I need to change my audio depending on whether or not headphones are plugged in. I'm aware of kAudioSessionProperty_AudioInputAvailable, which will tell me if there's a microphone, but I'd like to test for any headphones, not just headphones with a built-in microphone. Is this possible?
Asked
Active
Viewed 1.6k times
14
-
1@Brad Larson The answer to that question didn't give me the information I need. My question specifies _headphones_, not microphone. I believe the accepted answer to the question you linked to describes how to detect if a microphone is plugged in. – morgancodes Sep 16 '10 at 17:47
-
Yes, I guess you're asking a refinement of that question where simply detecting the audio input isn't good enough. Perhaps some of the discussion around [this question](http://stackoverflow.com/questions/1238758/how-can-i-detect-if-headphones-are-connected-to-an-ipod-touch-g1) might be helpful as well. – Brad Larson Sep 16 '10 at 19:56
-
Thanks for pointing me to that question. – morgancodes Sep 16 '10 at 23:15
-
3Maybe, nearly two years on, you should accept the answer...? – JohnK May 14 '13 at 18:23
4 Answers
28
Here is a method of my own which is a slightly modified version of one found on this site : http://www.iphonedevsdk.com/forum/iphone-sdk-development/9982-play-record-same-time.html
- (BOOL)isHeadsetPluggedIn {
UInt32 routeSize = sizeof (CFStringRef);
CFStringRef route;
OSStatus error = AudioSessionGetProperty (kAudioSessionProperty_AudioRoute,
&routeSize,
&route);
/* Known values of route:
* "Headset"
* "Headphone"
* "Speaker"
* "SpeakerAndMicrophone"
* "HeadphonesAndMicrophone"
* "HeadsetInOut"
* "ReceiverAndMicrophone"
* "Lineout"
*/
if (!error && (route != NULL)) {
NSString* routeStr = (NSString*)route;
NSRange headphoneRange = [routeStr rangeOfString : @"Head"];
if (headphoneRange.location != NSNotFound) return YES;
}
return NO;
}

jptsetung
- 9,064
- 3
- 43
- 55
-
-
what doesn't work? doesn't compile? I use this piece of code in a game and it works for me. – jptsetung Dec 09 '11 at 17:36
-
-
What is the value of 'error' and 'route' with your earphones plugged? – jptsetung Dec 10 '11 at 04:32
-
Hi I've found that this works with the actual device but not the simulator. There is 0 error, and the route returns "Speaker". Any idea why? – lppier Dec 11 '12 at 02:36
-
3
-
how would I re write the OSStatus error variable for iOS7 audiosessiongetproperty is deprecated.. – 4GetFullOf Jan 22 '14 at 19:33
-
I think [this other answer](http://stackoverflow.com/a/21382748/1693173) is preferable because it uses constants defined by Apple on the port routing. – progrmr Mar 17 '16 at 06:06
12
Here's a solution based on rob mayoff's comment:
- (BOOL)isHeadsetPluggedIn
{
AVAudioSessionRouteDescription *route = [[AVAudioSession sharedInstance] currentRoute];
BOOL headphonesLocated = NO;
for( AVAudioSessionPortDescription *portDescription in route.outputs )
{
headphonesLocated |= ( [portDescription.portType isEqualToString:AVAudioSessionPortHeadphones] );
}
return headphonesLocated;
}
Simply link to the AVFoundation framework.

ekscrypto
- 3,718
- 1
- 24
- 38
3
Just a heads up for any future readers of this post.
Most of the AVToolbox methods have been deprecated with the release of iOS 7 without alternative so audio listeners are now largely redundancy

Anthony Main
- 6,039
- 12
- 64
- 89
1
I started with the code given above by jpsetung, but there were a few issues with it for my use case:
- No evidence of something called
kAudioSessionProperty_AudioRoute
in the docs - Leaks
route
- No audio session check
- String check for headphones instead of logical awareness of categories
- I was more interested in whether the iPhone was using its speakers, with "headphones" meaning "anything other than speakers". I feel that leaving out options like "bluetooth", "airplay", or "lineout" was dangerous.
This implementation broadens the check to allow for any type of specified output:
BOOL isAudioRouteAvailable(CFStringRef routeType)
{
/*
As of iOS 5:
kAudioSessionOutputRoute_LineOut;
kAudioSessionOutputRoute_Headphones;
kAudioSessionOutputRoute_BluetoothHFP;
kAudioSessionOutputRoute_BluetoothA2DP;
kAudioSessionOutputRoute_BuiltInReceiver;
kAudioSessionOutputRoute_BuiltInSpeaker;
kAudioSessionOutputRoute_USBAudio;
kAudioSessionOutputRoute_HDMI;
kAudioSessionOutputRoute_AirPlay;
*/
//Prep
BOOL foundRoute = NO;
CFDictionaryRef description = NULL;
//Session
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
AudioSessionInitialize(NULL, NULL, NULL, NULL);
});
//Property
UInt32 propertySize;
AudioSessionGetPropertySize(kAudioSessionProperty_AudioRouteDescription, &propertySize);
OSStatus error = AudioSessionGetProperty(kAudioSessionProperty_AudioRouteDescription, &propertySize, &description);
if ( !error && description ) {
CFArrayRef outputs = CFDictionaryGetValue(description, kAudioSession_AudioRouteKey_Outputs);
CFIndex count = CFArrayGetCount(outputs);
if ( outputs && count ) {
for (CFIndex i = 0; i < count; i++) {
CFDictionaryRef route = CFArrayGetValueAtIndex(outputs, i);
CFStringRef type = CFDictionaryGetValue(route, kAudioSession_AudioRouteKey_Type);
NSLog(@"Got audio route %@", type);
//Audio route type
if ( CFStringCompare(type, routeType, 0) == kCFCompareEqualTo ) {
foundRoute = YES;
break;
}
}
}
} else if ( error ) {
NSLog(@"Audio route error %ld", error);
}
//Cleanup
if ( description ) {
CFRelease(description);
}
//Done
return foundRoute;
}
Used like so:
if ( isAudioRouteAvailable(kAudioSessionOutputRoute_BuiltInSpeaker) ) {
//Do great things...
}

SG1
- 2,871
- 1
- 29
- 41
-
2Check out `-[AVAudioSession currentRoute]` for an Objective-C interface to this information as of iOS 6.0. – rob mayoff Jul 14 '13 at 06:10
-
Definitely a good note, but only if you are linking to AVFoundation (the code above is for AudioToolbox) – SG1 Sep 02 '13 at 17:26