mediaserviced dies when disconnected bluetooth headset after setting it as the preferred input multiple times

Number:rdar://FB8921592 Date Originated:2020-11-29
Status:Open Resolved:
Product:iOS Product Version:iOS 13 and 14
Classification:System Bug Reproducible:Always
## The Problem

When setting the preferred input on AVAudioSession to a bluetooth headset multiple times and then disconnecting the bluetooth headset while receiving I/O data from it (via AVCaptureSession or AVAudioEngine), AVAudioSessionMediaServicesWereLostNotification will be fired consistently. This kills all media related work in my application.

The use case is a broadcasting application that allows the user explicit control over what audio input device they are using. In this scenario, if the user starts with bluetooth headphones connected, swaps to the built-mic mic, swaps back to the bluetooth headset, and then turns the bluetooth device off, it will cause mediaserviced to die.

## Repro Steps

In a new example application:

1. Set your AVAudioSession category to record with the allowBluetooth option.
2. Set your AVAudioSession to active.
3. Grab a reference to both the built-in port and bluetooth port via AVAudioSession.availablePorts.
4. Set the preferred input to the bluetooth headset, then back to the built-in port, then the bluetooth headset again. You can do this serially without any delay in between. You can also trigger the swap via a button press with significant delay, it doesn't matter as long as you swap the preferred input multiple times and end on the bluetooth port.
5. Start monitoring port I/O with either AVCaptureSession (AVCaptureAudioDataOutputSampleBufferDelegate) or AVAudioEngine (installTap).
6. Disconnect the bluetooth headset by powering it off.
7. AVAudioSession.mediaServicesWereLostNotification will be fired.

This reproduces on the following headsets of mine:
Bose QuietComfort 35 II
Sony WH-1000XM3
TaoTonics TT-BH07

This reproduces on the following iOS devices of mine:
iPhone 7 on iOS 14.2
iPhone Xr on iOS 14.0.1
iPad Air 2 on iOs 13.7

## What I Expected to Happen

I would accept a couple different results from this that are not mediaserviced dying.

1. Automatically set AVAudioSession.preferredInput to nil and resort to the next best input port.
2. Notify the user via an AVAudioSession notification that the device has disconnected and let them handle changing the port.
3. Notify the AVAudioEngine or AVCaptureSession instances that something went wrong and stop sampling the input.

## What Happened

mediaserviced crashes, and all media related work in my application stops.

There is an example repo that reproduces the issue here -


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!