8
votes

I'm trying to figure out how to detect which if any audio devices are connected on iphone/ipad/ipod. I know all about the audio route calls and route change callbacks but these don't tell me anything about what's attached. They only report where the audio is currently routing. I need to know, for instance, if headphones and/or bluetooth are still attached while audio is routed through the speakers. Or, for instance, if a user plugs in the headset while using bluetooth then decides to disconnect bluetooth, I need to know that the bluetooth is disconnected even as audio is still routing through headphones.

3
I have a similar issue in my app, my app is playing stream correctly but if I change audio output (unplugged headphone), it stop playing.. did u figureout how to detect when audio output is changed? - Jay Vachhani
Yes, detecting a route change is do via an AudioSessionPropertyListener callback. The property listener is then registered via the AudioSessionAddPropertyListener function. However that's not what I was trying to do above. In my app I need to detect which devices are connected to correctly display available routing options to the user. - Cliff

3 Answers

2
votes

Unfortunately, as of iOS11, it seems there's no API to reliably get the list of the output devices that are currently attached - as soon as the current route changes, you only see 1 device (currently routed) via AVAudioSession's currentRoute.outputs, even though multiple devices may still be attached.

However, for the input, and that includes Bluetooth devices with HFP profile, if the proper Audio Session mode is used (AVAudioSessionModeVoiceChat or AVAudioSessionModeVideoChat for example), one can get the list of the available input via AVAudioSession's availableInputs, and those inputs are listed there even when that device is not an active route - this is very useful when a user is doing a manual override via MPVolumeView from Bluetooth to the speaker, for example, and since HFP is a 2-way IO (has both input and output), you can judge whether output HFP Bluetooth is still available by looking at the inputs.

BOOL isBtInputAvailable = NO;
NSArray *inputs = [[AVAudioSession sharedInstance] availableInputs];
for (AVAudioSessionPortDescription* port in inputs) {
    if ([port.portType isEqualToString:AVAudioSessionPortBluetoothHFP]) {
        isBtInputAvailable = YES;
        break;
    }
}
1
votes

In case of iOS 5 you should use:

CFStringRef newRoute;
size = sizeof(CFStringRef);
XThrowIfError(AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &size, &newRoute), "couldn't get new audio route");
if (newRoute)
{
    CFShow(newRoute);
    if (CFStringCompare(newRoute, CFSTR("HeadsetInOut"), NULL) == kCFCompareEqualTo) // headset plugged in
          {
            colorLevels[0] = .3;                
            colorLevels[5] = .5;
          }
    else if (CFStringCompare(newRoute, CFSTR("SpeakerAndMicrophone"), NULL) == kCFCompareEqualTo)
}
0
votes

You can get from AudioSession properties a list of InputSources and OutputDestinations. Check out these Session Properties:

kAudioSessionProperty_InputSources
kAudioSessionProperty_OutputDestinations

And to query the details of each, you can use:

kAudioSessionProperty_InputSource
kAudioSessionProperty_OutputDestination