Bug when using multiple AVAudioUnitSampler instances

Hi there, I'm building an audio app for iOS and ran into a very weird bug when using multiple AVAudioUnitSampler instances to play different instruments at the same time. I narrowed down the repro to:

let sampler = AVAudioUnitSampler()
self.audioEngine.attach(sampler)
self.audioEngine.connect(sampler, to: self.audioEngine.mainMixerNode, format: nil)
try! sampler.loadInstrument(at: Bundle.main.url(forResource: "SteinwayPiano-v1", withExtension: "aupreset")!)

let sampler2 = AVAudioUnitSampler()
self.audioEngine.attach(sampler2)
self.audioEngine.connect(sampler2, to: self.audioEngine.mainMixerNode, format: nil)
try! sampler2.loadInstrument(at: Bundle.main.url(forResource: "Rhodes-v1", withExtension: "aupreset")!)

I get the following error on the console (real device and simulator):

2022-07-02 21:27:28.329147+0200 soundboard[23592:612358] [default]     ExtAudioFile.cpp:193  about to throw -42: open audio file
2022-07-02 21:27:28.329394+0200 soundboard[23592:612358] [default]      FileSample.cpp:52  about to throw -42: FileSample::LoadFromURL: ExtAudioFileOpenURL
2022-07-02 21:27:28.330206+0200 soundboard[23592:612358]     SampleManager.cpp:434  Failed to load sample 'Sounds/Rhodes/A_050__D3_4-ST.wav -- file:///Users/deermichel/Library/Developer/CoreSimulator/Devices/79ACB2AD-5155-4798-8E96-649964CB274E/data/Containers/Bundle/Application/A10C7802-3F4B-445D-A390-B6A84D8071EE/soundboard.app/': error -42
2022-07-02 21:27:28.330414+0200 soundboard[23592:612358] [default]     SampleManager.cpp:435  about to throw -42: Failed to load sample

Sometimes the app crashes after that, but most importantly, sampler2 won't work.

Now, if I only create one of the samplers, it works as expected. Also, if both samplers reference to the same aupreset, it works. Only if I try to load different samples, I end up in undefined behavior.

Adding a audioEngine.detach(sampler) before creating sampler2 doesn't solve the issue either - it will fail loading the samples with the same error. However, when deferring removal of sampler and creation of sampler2 a little bit, it magically starts working (though that's not what I want because I need both samplers simultaneously):

let sampler = AVAudioUnitSampler()
self.audioEngine.attach(sampler)
self.audioEngine.connect(sampler, to: self.audioEngine.mainMixerNode, format: nil)
try! sampler.loadInstrument(at: Bundle.main.url(forResource: "SteinwayPiano-v1", withExtension: "aupreset")!)

DispatchQueue.main.async {
  self.audioEngine.detach(sampler)
  let sampler2 = AVAudioUnitSampler()
  self.audioEngine.attach(sampler2)
  self.audioEngine.connect(sampler2, to: self.audioEngine.mainMixerNode, format: nil)
  try! sampler2.loadInstrument(at: Bundle.main.url(forResource: "Rhodes-v1", withExtension: "aupreset")!)
}

My samples are linked to the bundle as a folder alias - and I have a feeling that there is some exclusive lock... however I don't have the source code to debug the errors on the console further. Any help is appreciated, have a good one :)

  • Addendum: Loading samples from NSDocumentDirectory instead of the bundle results in the same behavior.

Add a Comment

Accepted Reply

Ok, it turned out that is was not a bug in AVAudioUnitSampler - running the same code on macOS gave some additional hints...

unable to obtain configuration from file:///Library/Preferences/com.apple.ViewBridge.plist due to Error Domain=NSCocoaErrorDomain Code=256 "(null)" UserInfo={NSFilePath=/Library/Preferences/com.apple.ViewBridge.plist, NSUnderlyingError=0x600003a9e610 {Error Domain=NSPOSIXErrorDomain Code=24 "Too many open files"}}

...with the second sampler, the app exceeded the soft limit for currently opened files per process (=256). The crashes afterwards were caused by failing file handles in other parts of the app. A workaround can be found at https://stackoverflow.com/a/62074374/1993349 ... done.

Replies

Ok, it turned out that is was not a bug in AVAudioUnitSampler - running the same code on macOS gave some additional hints...

unable to obtain configuration from file:///Library/Preferences/com.apple.ViewBridge.plist due to Error Domain=NSCocoaErrorDomain Code=256 "(null)" UserInfo={NSFilePath=/Library/Preferences/com.apple.ViewBridge.plist, NSUnderlyingError=0x600003a9e610 {Error Domain=NSPOSIXErrorDomain Code=24 "Too many open files"}}

...with the second sampler, the app exceeded the soft limit for currently opened files per process (=256). The crashes afterwards were caused by failing file handles in other parts of the app. A workaround can be found at https://stackoverflow.com/a/62074374/1993349 ... done.