Vincent Gable’s Blog

September 11, 2008

Detecting if Headphones are Plugged In

Filed under: MacOSX,Programming,Sample Code | , ,
― Vincent Gable on September 11, 2008

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 I do it.

Docs & Tools

Use the CoreAudio.framework, specifically CoreAudio/CoreAudio.h Unfortunately it’s a bit confusing sometimes, but the documentation is still very complete (if complex).

HALLab (/Developer/Examples/CoreAudio/HAL/HALLab/ if you have the developer tools installed) is the most complex bit of relevant CoreAudio sample code, and when built it’s a useful utility for poking-around with to boot.

How To Do It

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.

A word of caution, do not use the promising-looking AudioDevice Property kAudioDevicePropertyJackIsConnected it does not work on all systems (specifically it didn’t work in 10.4, and I have not tested it under Leopard).

Change Notifications

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:

Sample Code:


//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';
}

July 5, 2008

FourCharCode2NSString

Filed under: MacOSX,Objective-C,Programming,Sample Code,Usability | , , ,
― Vincent Gable on July 5, 2008

As I have written before, the best way to convert a FourCharCode to an NSString* for NSLog()ing is to use the NSFileTypeForHFSTypeCode() function. But for the life of me I can’t remember that name, even though I use it about once a month. It’s too long, and it has too little to do with what I’m using it for.

So I have added the line:
#define FourCharCode2NSString(err) NSFileTypeForHFSTypeCode(err)
To my prefix-files, because I can remember FourCharCode2NSString().

UPDATE: (2008-08-06) There is an even easier way.

Powered by WordPress