Detecting if Headphones are Plugged in
Implementing the Selective Muting feature took a bit longer then I expected. I found many posts on mailing lists asking the question of how to detect if something is plugged into the headphones jack, but no complete answer. So here’s how you do it.
Use the CoreAudio.framework, specifically CoreAudio/CoreAudio.h Unfortunately the documentation is a bit confusing at times, but it’s still very complete.
HALLab (/Developer/Examples/CoreAudio/HAL/HALLab/) is the most complex bit of relevant CoreAudio sample code, and when built it’s a pretty useful utility for poking-around with to boot.
A word of caution, do not use the promising-looking AudioDevice Property kAudioDevicePropertyJackIsConnected it does not work on all systems.
Whenever something is plugged into the headphones jack, CoreAudio changes the data source for the output device, from internal speakers to headphones. Use AudioDeviceGetProperty(outputDeviceID, 0, 0, kAudioDevicePropertyDataSource, &size, &dataSource); to examine the 32-bit ID of the data source, which is best thought of as a 4 character code. If dataSource is 'ispk', sound is played through internal speakers, if it is 'hdpn', sound is playing through the headphones jack. I’m not sure what happens if you have speakers plugged in that use a different output source, like USB, FireWire, or optical out.
If you want to be notified when something is plugged/unplugged in the headphones jack, listen for a kAudioDevicePropertyDataSource change to the output audio device. Here is the code I use to test if a computer is using it’s internal speakers:
//Returns YES if the default sound output device
//is using external speakers to play sound.
- (BOOL) usingInternalSpeakers
{
AudioDeviceID deviceID;
UInt32 size = sizeof(deviceID);
OSStatus err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultSystemOutputDevice, &size, &deviceID);
NSCAssert((err == noErr), @”AudioHardwareGetProperty failed to get the kAudioHardwarePropertyDefaultSystemOutputDevice property”);
//To be notified when something is plugged/unplugged into the headphones jack
//listen for a kAudioDevicePropertyDataSource or kAudioDevicePropertyDataSources notification on deviceID
//Check if headphones are plugged in right now:
UInt32 dataSource;
size = sizeof(dataSource);
err = AudioDeviceGetProperty(deviceID, 0, 0, kAudioDevicePropertyDataSource, &size, &dataSource);
NSCAssert((err == noErr), @”AudioDeviceGetProperty failed to get the kAudioDevicePropertyDataSource property”);
//’ispk’ => internal speakers
//’hdpn’ => headphones
return dataSource == ‘ispk’;
}