Background audio killed when a background URLSession finishes

Short version, in case it saves someone the trip I just took: if your app plays audio AND uses a background URLSession with sessionSendsLaunchEvents = true, playback can be killed mid-episode the moment you call the handleEventsForBackgroundURLSession completion handler, but only in a process that was launched into the background and never went foreground. There is no crash log and no jetsam event: applicationWillTerminate simply fires. To users it looks exactly like the app crashed while playing, which is how it was reported to me, and why I wasted a while looking for a crash that did not exist.

My setup:

  • podcast app, audio background mode
  • a background URLSession (sessionSendsLaunchEvents = true, isDiscretionary = false) used only to refresh RSS feeds
  • those feed downloads are started from a BGAppRefreshTask

What happens:

  1. iOS launches the app into the background to run a BGAppRefreshTask. The scene connects unattached; the process never becomes foreground.
  2. The task starts a batch of feed downloads on the background session. They outlive the ~10 s refresh window and finish about two minutes later.
  3. Meanwhile the user presses Play on their AirPods. Playback starts, inside that same never-foreground process.
  4. The downloads finish. iOS calls handleEventsForBackgroundURLSession. I store the handler and invoke it on the main thread from urlSessionDidFinishEvents, as documented.
  5. ~1 ms later applicationWillTerminate fires and the audio stops.

At that moment the app is playing audio: AVAudioSession active, category .playback, and -[UIApplication backgroundTimeRemaining] returning greatestFiniteMagnitude. A sysdiagnose shows audiomxd holding a MediaPlayback isPlayingProcessAssertion for the process, taken 27 s earlier, invalidated only as part of the teardown, and CMSessionMgr logging "pid ... is now Terminated. Background entitlement: YES" while IsPlayingOutput:YES.

The tell, and the thing that took me longest to spot: if the process HAS been foreground at some point in its life, calling the identical completion handler on the identical session does not kill it, and playback carries on. Across a full day of logs, "has this process ever been foreground" is the only variable that predicts the kill. The audio background mode is not the problem, the app happily played for ~6 minutes as a never-foreground process on another occasion, and died only at the completion-handler call.

Half of this is documented behaviour: the system takes a power assertion when it resumes you for the session, and calling the completion handler releases it. What I did not expect is that the audio assertion does not take over at that point.

My workaround so far is sessionSendsLaunchEvents = false on the feed session. RSS refreshes are not urgent: the transfers still run in the background, and the system hands the results to me at the next launch, where my refresh task parses them. I'm still verifying if this works as expected.

So, questions for anyone who has been here:

  • Has anyone else with an audio app hit this? I have a hunch it shows up in the wild as unexplained "the app crashed while playing" reports, particularly for podcast and audiobook apps that refresh content in the background, because there is no crash log to point at.
  • If you combine background audio with a background URLSession, how do you handle it? Do you avoid launch events entirely, or split urgent from non-urgent transfers across separate sessions?
  • Is there a better pattern than turning launch events off for transfers that genuinely are not urgent?

Filed as FB23789310 with a sysdiagnose and a timestamped log excerpt. If you have seen this too, a dupe would help.

Answered by DTS Engineer in 897905022

I don’t have much to say here other than:

  • Well, that's weird.
  • Thanks for filing FB23789310.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I don’t have much to say here other than:

  • Well, that's weird.
  • Thanks for filing FB23789310.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Background audio killed when a background URLSession finishes
 
 
Q