I have the following code to (re)start AVAudioEngine
wired up to AVAudioEngineConfigurationChangeNotification
:
do {
try self.engine.start()
} catch {
DDLogError("could not start sound engine")
self.soundEnabled = false
return
}
self.engine is defined as
private let engine = AVAudioEngine()
However, I frequently receive crash reports via Crashlytics saying
Fatal Exception: com.apple.coreaudio.avfaudio error 561015905
on the line containing the try self.engine.start()
.
561015905 is AVAudioSessionErrorCodeCannotStartPlaying
and from what I understand, this should be a NSError
error code, not an exception, which should be caught by my blank catch
in the code above. Still, the app just seems to crash at that point. What am I missing?
I know there are situations where the app wakes up in the background where this error can occur and I would be fine with that, as long as I can somehow catch it happening, as I thought I could with do/catch
.
Xcode Version 9.2 (9C40b) + Swift 4 : I know this question is a little old, however, I was having the same crashing issues with audioEngine.start()
even though in a do/try/catch and also receiving the following from Crashalytics:
Fatal Exception: com.apple.coreaudio.avfaudio error 561015905
S1LENT WARRIOR's sleep(1) "hack" worked in some cases, but not all (specifically with AVAudioEngineConfigurationChangeNotification selector).
Finally, I used Obj-C exception handling to really catch the error so no crash occurs, from this very useful post by freytag (big thanks!):
Catching NSException in Swift
Now, after implementing the ObjC .h and .m files and the bridging header, I do:
do {
try ObjC.catchException {
try! self.audioEngine.start()
}
}
catch {
print("An error occurred: \(error)")
}
You can test this by screwing up the engine initialization (eg don't .attach or .connect anything) and no crash... only:
2018-01-06 10:01:48.890801+0700 XXXXXX[16389:3367770] [avae] AVAEInternal.h:70:_AVAE_Check: required condition is false: [AVAudioEngineGraph.mm:1209:Initialize: (inputNode != nullptr || outputNode != nullptr)] An error occurred: Error Domain=com.apple.coreaudio.avfaudio Code=0 "(null)"
Make sure you check the audioEngine is running before using it, something like:
func play(soundName: String) {
if !audioEngine.isRunning {
return
}
// play sound
}
OK, so you get no sound but it is a "graceful fail".
Seems ridiculous that in Swift you can't properly catch an exception, and ok if you're going to make some exceptions not catchable then at least provide a method to test first, something like audioEngine.areYouConfiguredProperly()
. Oh hang on there is this method (in Obj-C) [AVAudioEngine startAndReturnError:]
but someone decided to wrap it with the startEngine()
function and do away with all useful functionality... doh.
I encountered the same error when handling AVAudioSessionInterruption
notification.
In my case, the error was arising when i tried to start AVAudioEngine
after the interruption ended.
After detailed testing and debugging for a while, i noticed the app wasn't crashing if i introduce a debugger breakpoint
before audioEngine.prepare()
or audioEngine.start()
.
So i added sleep(1)
before audioEngine.start()
and my app stopped crashing!
I know its not a very elegant solution but still hope this may help someone else!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With