iosswiftcore-audio

How to update AudioUnitSetProperty with URL argument for iOS 26?


My app can play Standard MIDI Files with an AVAudioUnitMIDIInstrument. I've been setting a sound font like this, where soundfontURL is a Swift URL object:

AudioUnitSetProperty(audioUnit, kMusicDeviceProperty_SoundBankURL, kAudioUnitScope_Global, AudioUnitElement(0), &soundfontURL, UInt32(MemoryLayout.size(ofValue: soundfontURL)))

In iOS 26, this crashes with the following backtrace:

Crashed: com.apple.main-thread
SIGABRT ABORT 0x00000002424200cc
0   libsystem_kernel.dylib  __pthread_kill + 8
1   libsystem_pthread.dylib pthread_kill + 268
2   libsystem_c.dylib   abort + 124
3   libswiftCore.dylib  <redacted> + 142
4   libswiftCore.dylib  <redacted> + 30
5   libswiftCore.dylib  <redacted> + 142
6   CoreFoundation  <redacted> + 1472
7   CoreFoundation  _CF_forwarding_prep_0 + 96
8   CoreFoundation  CFURLGetFileSystemRepresentation + 196
9   libEmbeddedSystemAUs.dylib  AccessURLAsset(__CFURL const*, int)
10  libEmbeddedSystemAUs.dylib  MIDISynth::SetProperty(unsigned int, unsigned int, unsigned int, void const*, unsigned int)
11  libEmbeddedSystemAUs.dylib  ausdk::AUBase::DispatchSetProperty(unsigned int, unsigned int, unsigned int, void const*, unsigned int)
12  libEmbeddedSystemAUs.dylib  ausdk::AUMethodSetProperty(void*, unsigned int, unsigned int, unsigned int, void const*, unsigned int)

Xcode shows the following warning on this line of code:

Forming 'UnsafeRawPointer' to a variable of type 'URL'; this is likely incorrect because 'URL' may contain an object reference.

So I tried to convert the URL object to an UnsafeRawPointer explicitly rather than passing it as a reference as described in the Apple documentation, and came up with this:

if let urlData = String.toData(soundfontURL.absoluteString) {
    urlData.withUnsafeBytes { (u8Ptr: UnsafePointer<UInt8>) in
        let urlPointer = UnsafeRawPointer(u8Ptr)
        AudioUnitSetProperty(audioUnit, kMusicDeviceProperty_SoundBankURL, kAudioUnitScope_Global, AudioUnitElement(0), urlPointer, UInt32(MemoryLayout.size(ofValue: urlPointer)))
    }
}

But the same line of code is still crashing, so I don't know if this isn't the right solution to the problem, or if it isn't even the right problem.

Does anyone know how to correctly pass a URL argument in the AudioUnitSetProperty in iOS 26?

By the way, the soundfontURL does point to a valid file and the code was working on iOS 18.


Solution

  • I suspect the function is expecting a pointer to a CFURLRef, but you are giving it a pointer to a Swift URL. It should work if you cast it to CFURL in Swift first,

    withUnsafePointer(to: soundfontURL as CFURL) { ptr in
        AudioUnitSetProperty(..., ptr, UInt32(MemoryLayout.size(ofValue: ptr)))
    }
    

    withUnsafePointer basically does the same thing as using the & prefix on a variable. The only difference is that the former doesn't produce the warning. See here for a more detailed explanation.


    Based on my investigation, what changed in iOS 26 is that the Swift URL no longer automatically becomes CFURL/NSURL when it goes to the Objective-C side. Instead, it is now a Foundation._SwiftURL.

    For example, if you call this from Swift:

    void somethingTakingURL(const void * url) {
        CFStringRef s = CFURLGetString(*(CFURLRef *)url);
    }
    
    withUnsafePointer(to:  URL(string: "https://google.com")!) {
        somethingTakingURL($0)
    }
    

    It will produce an error

    Unrecognized selector -[Foundation._SwiftURL relativeString]