AudioQueueStart fails with -16981 from background process on iOS 7 - ios

In my iOS app on all previous versions of the OS, we record audio occasionally, then sleep for a while, then record again, and cycle for ever (sleep is to maintain battery). This worked fine up to iOS 7, even when the app was in background. Now, when the app is in the background the call to AudioQueueStart fails to start recording with an error: -16981. I can't seem to find this error code in the documentation or on the Web, and if I turn it into an NSError, it says "The operation couldn’t be completed. (OSStatus error -16981.)", which isn't all that helpful.
I have a theory that Apple are closing a hole here; the idea being; why would you want to start recording from a background process, unless you are spying? Well, with the users consent (signed and paid for!), that's exactly what we are doing.
So; can anyone confirm or deny that this is expected, or what I might be able to do about it. It's a bit of a killer for our app. I have filed it as a bug with Apple, and will try to report progress here.
UPDATE: 3rd October 2013
Although the previous answer seemed to work for this for a while; it has stopped working now with -12985, which is because another app has turned on audio. This is of course why I need to use the mixing flag.
UPDATE:
iOS 7.0.3 (and later) seem to have fixed this issue completely.

After playing with different audio session properties, I found that -16981 error takes place when kAudioSessionProperty_OverrideCategoryMixWithOthers is enabled (TRUE). As soon, as I set it to '0', AudioQueueStart() executes successfully. So, before starting the audio session try:
UInt32 allowMixing = 0;
status = AudioSessionSetProperty (
kAudioSessionProperty_OverrideCategoryMixWithOthers,
sizeof (allowMixing),
&allowMixing);
Clearly, this is behavior change in iOS 7. As it was mentioned before, the documentation does not list -16981 error code.

Related

AVAudioSession setPreferredSampleRate not working on iPhone 11 and above

I have a legacy video streaming library that seems to be broken on iPhone 11 (and above) devices. After digging into the problem it seems that the code that is initiating the AVAudioSession is failing due to the call to AVAudioSession.sharedInstance.setPreferredSampleRate(44100) not changing the actual sample rate and keeping it at 48000Hz.
Has anyone else faced this? I know that the method says preferred and it is not guaranteed that it will change the audio sample rate, but it was working on all previous devices.

iOS App running on iOS 13 is resetting each time the user goes into background for at least 30sec

It is not really a question but I wanted to write it down here so other people facing the problem could find the solution.
Since the release of iOS 13, some of our users were contacting us telling that our app was resetting each time they go into background for a medium amount of time (approximatively 30sec).
Of course, absolutely no clue of the behavior, nothing on Crashlytics etc. We were able to reproduce on a QA device but unable to reproduce on a debugger attached device.
So obviously we used the Console to monitor what's going on and we noticed that a weird message was being sent after approx. 25sec after our app was put into background:
default 10:14:01.658579+0100 XXX RunningBoardServices Received process assertions expiration warning!
default 10:14:01.659214+0100 XXX RunningBoardServices Notifying client of imminent expiration of assertion
default 10:14:01.659568+0100 XXX RunningBoardServices Expiration notification complete
If you were fast enough to relaunch the app, everything just worked fine, but if you left the app inactive for another 5sec (approx.) and then relaunched it, then the app was resetting (appDidFinishLaunching...).
...
...
We dug deeper and deeper without finding anything... until we decided to update some of our external libraries through Cocoapods, and guess what? we found our guilty guy: GoogleDataTransport from the Firebase suite!
We were using the 1.1.3 version and updating to the 3.0.1 fixed the issue. I guess they were doing some "bad" stuff in the background...
That's it guys. I hope it will help some others!
Cheers.
EDIT:
From this page (Firebase release notes) https://firebase.google.com/support/release-notes/ios#6.11.0, you can read:
Fixed race condition that prevented upload from completing while app was in the background.
Version 6.10.0 - October 8, 2019
From what I understand, maybe Firebase was not notifying iOS that the upload they were doing in the background was completed. It could explain why iOS 13 kills an app in this case.
🤷‍♂️
EDIT 2:
Apple apparently released an iOS update (13.2.2) which is supposed to solve these background issues: https://twitter.com/engadget/status/1192512171252551682?s=12.
Fixes an issue that could cause apps to quit unexpectedly when running in the background
We tested it using an old app which does not include our previous fix and unfortunately the problem is still present...
The crash was due to a background task leak. In my application, some SDKs don't use the background task correctly. Because it was killed by the watchdog, debugging will not appear, you can print beginBackgroundTask and endBackgroundTask during debugging. If there is a mismatch, a leak occurs.
I wrote a category to hook background task related methods to avoid leaking being killed by watchdog:https://github.com/ruanjx/MPIBackgroundTaskProtection
More information about background task:https://medium.com/swlh/handling-background-tasks-in-ios-13-67f717d94b3d

Any Core MIDI call causes app to become unresponsive

I've come across an issue with Core MIDI across a couple of iOS apps I work on, and another app I downloaded from the App Store.
What appears to be happening is the Core MIDI server crashes. After this happens, any interaction with Core MIDI functions or properties makes the calling app unresponsive. The following line is in AppDelegate's didFinishLaunchingWithOptions::
[MIDINetworkSession defaultSession].enabled = YES;
Execution stops at this point, causing a forever hang when debugging or a #8badf00d crash otherwise.
This happens even if the Core MIDI function should return an OSStatus - the return value never comes back:
OSStatus s = MIDIObjectGetStringProperty(ref, kMIDIPropertyDisplayName, (CFStringRef*)&string);
This call (which is in the PGMidi library) also hangs, with s not being returned. The only way to fix the issue is to restart the device.
The Core MIDI server becoming unresponsive seems related to running multiple Network Sessions from a connected Mac, but I haven't been able to pinpoint a way to replicate reliably. As well as my own apps (which use the MIKMIDI library), I have experienced unresponsive behaviour with midimittr, downloaded from the App Store.
Of course, I have no control over whether the Core MIDI Server becomes unresponsive. But is there a way to check the status of the MIDI server before making calls that may make my app unresponsive?
Update: 2019-05-10
I've found that I can get the iOS Core MIDI server into this unresponsive state by following these steps:
Set up a Network MIDI session on a Mac in Audio/MIDI Setup.
In iOS app, connect to that Network MIDI session.
Let Mac go to sleep naturally (invoking sleep from the Apple Menu doesn't appear to trigger the issue).
Once the Mac has gone to sleep do something in iOS app that will call Core MIDI.
So it's like the iOS Core MIDI server has lost connection to the Mac's MIDI network, but continues to try and execute.
Update: 2019-05-17
Apple responded to my bug report (#50657978) saying it is a duplicate of another report (#49583498) and will be closed. At the very least they are aware of the bug.
Update: 2019-07-17
This Core MIDI hang state can also be entered more quickly (for debugging purposes) by connecting the Core MIDI network via Audio Music Setup, then backgrounding your app and switching on Airplane mode on the iOS device.
SEE BELOW FOR LATEST UPDATE AND FINAL SOLUTION
I've managed to come up with a partial solution to this problem. (Alas, as the root cause seems embedded in Apple's code a complete solution is not possible.)
In my AppDelegate I now run a routine which can detect whether calls to Core MIDI will time out:
func enableMIDINetworkSession() {
let midiNetworkGroup = DispatchGroup()
midiNetworkGroup.enter()
DispatchQueue.global(qos: .background).async {
MIDINetworkSession.default().isEnabled = true
midiNetworkGroup.leave()
}
// If `midiNetworkGroup.leave()` is not reached in the closure above, then the result below will be `.timeOut`
let midiNetworkTimeoutResult = midiNetworkGroup.wait(timeout: DispatchTime.now() + 10.0)
switch midiNetworkTimeoutResult {
case .timedOut:
{ ... } // Calls to Core MIDI will cause app to hang. Handle as required. Note: app will crash anyway at some point in the future.
case .success:
break // All good, continue as before
}
}
A thing to note here: if you intend to display an alert in the case that midiNetworkTimeoutResult == .timeOut then keep in mind that any calls to Core MIDI that occur straight after this may cause the alert to not be presented (as the main queue will be blocked).
Update: 2019-07-17
It's important to mention with the solution above that if you end up in the .timedOut case above, the app will crash at some point in the future anyway, as it catches up with the MIDINetworkSession.default().isEnabled call.
The gap before the crash is around 5 minutes, so there's enough time to display an alert and advise the user to restart their device.
Update: 2019-08-14
Recommended solution
It appears that this issue has been resolved by Apple in iOS 12.4. The solution then would be to advise your users to update to iOS 12.4 or later.
(Also, this issue seems only to affect iOS 12.2 and 12.3 versions.)

Is there a way to stop an app from closing if it stalls on splash screen?

I've been testing an app for iOS in Xamarin Studio, however whenever I reach a breakpoint or an exception is thrown and I stay there for a few seconds without pushing the continue execution button, the debugging session will close as the app will close on my device. This is due to the process mentioned here, as it is occurring during the splash screen, and if the app pauses too long there, it will close the app because it failed to scene-create. I was wondering if it is possible to disable this when debugging with breakpoints, because I would like to look at the data flow through variables and such.
As matt guessed, it is a Xamarin issue. The response to my inquiry to Xamarin was this,
Xamarin does not currently use a native debugger, thus watchdog is not
disabled. They are looking into alternatives, but for now a potential
workaround is to not do anything until you've returned from the
FinishedLaunching method (i.e. start your launch code in a timer event
for instance), and debug that instead.
Update: the status on this bug is "fixed for the next major release." as of 12/29/15

AudioQueueDispose crashes in IOS 6, works fine in IOS 5

I'm streaming music from SoundCloud, using their streaming APIs, which in turn uses Apple's AudioToolbox framework. You can find the git repository here.
The app was streaming fine using ios 5 and below. Now with ios 6 I'm getting EXC_BAD_ACCESS anytime an AudioQueue is disposed via AudioQueueDispose. I've tried commenting out this line; sure enough it doesn't crash anymore, but obviously my audio streams keep playing and never get dealloc'd.
I'm not really sure what could be causing this. Is this a bug that needs to be reported with Apple? Or some new feature in ios 6 that inadvertently causes the audioQueue to be referenced somewhere after it has been disposed? Has anyone noticed behavior like this?
AudioQueueDispose will work in iOS6 devices without fail. You have to pass true as second parameter for AudioQueueDispose. Then its asynchronously stop the queue. But the problem is same thing is not working in iOS 6.1 devices. Can anybody help me for this issue.Thanks for advance.

Resources