Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get notifications when the headphones are plugged in/out? Mac

I'd like to get notified when headphones are plugged in or out in the headphone jack.
I've searched around for this on stackoverflow but I can't seem to find what I'm looking for for the Mac, I can only find for iOS.
So, do you have any ideas on how to perform this? What I want to do with this is: when headphones are plugged out I want to programmatically pause iTunes (iOS-like feature).
Thank you!

like image 710
Pedro Vieira Avatar asked Jan 23 '13 15:01

Pedro Vieira


People also ask

Do notifications go through headphones?

On Android, open Settings and then choose Connected devices. Tap the cog icon next to your earbuds, then select Google Assistant and Spoken notifications. Turn on the corresponding toggle switch, then choose the apps you want to hear from through your earbuds using the list underneath.

How do I use speakers when my headphones are plugged in on my Mac?

On your Mac, choose Apple menu > System Preferences, click Sound , then click Output. Select the device you want to use in the list of sound output devices. ), USB speakers, and AirPlay devices. For any device plugged into the computer's sound port, choose Headphones.

Why isn't my Mac detecting my headphones?

Make sure the headset is connected with your Mac. Choose Apple menu > System Preferences, then click Bluetooth . Check to see if your headset is in the list of devices. If your headset isn't in the list, try connecting with it again.


1 Answers

You can observe changes using the CoreAudio framework.

Both headphones and the speakers are data sources on the same audio output device (of type built-in). One of both will be on the audio device based on headphones being plugged in or not.

To get notifications you listen to changes of the active datasource on the built-in output device.

1. Get the built-in output device

To keep this short we'll use the default output device. In most cases this is the built-in output device. In real-life applications you'll want to loop all available devices to find it, because the default device could be set to a different audio device (soundflower or airplay for example).

AudioDeviceID defaultDevice = 0;
UInt32 defaultSize = sizeof(AudioDeviceID);

const AudioObjectPropertyAddress defaultAddr = {
    kAudioHardwarePropertyDefaultOutputDevice,
    kAudioObjectPropertyScopeGlobal,
    kAudioObjectPropertyElementMaster
};

AudioObjectGetPropertyData(kAudioObjectSystemObject, &defaultAddr, 0, NULL, &defaultSize, &defaultDevice); 

2. Read its current data source

The current datasource on a device is identified by an ID of type UInt32.

AudioObjectPropertyAddress sourceAddr;
sourceAddr.mSelector = kAudioDevicePropertyDataSource;
sourceAddr.mScope = kAudioDevicePropertyScopeOutput;
sourceAddr.mElement = kAudioObjectPropertyElementMaster;

UInt32 dataSourceId = 0;
UInt32 dataSourceIdSize = sizeof(UInt32);
AudioObjectGetPropertyData(defaultDevice, &sourceAddr, 0, NULL, &dataSourceIdSize, &dataSourceId);

3. Observe for changes to the data source

AudioObjectAddPropertyListenerBlock(_defaultDevice, &sourceAddr, dispatch_get_current_queue(), ^(UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses) {
    // move to step 2. to read the updated value
});

Determine the data source type

When you have the data source id as UInt32 you can query the audio object for properties using a value transformer. For example to get the source name as string use kAudioDevicePropertyDataSourceNameForIDCFString. This will result in the string "Internal Speaker" or "Headphones". However this might differ based on user locale.

An easier way is to compare the data source id directly:

if (dataSourceId == 'ispk') {
    // Recognized as internal speakers
} else if (dataSourceId == 'hdpn') {
    // Recognized as headphones
}

However I couldn't find any constants defined for these values, so this is kind of undocumented.

like image 69
Joris Kluivers Avatar answered Oct 12 '22 11:10

Joris Kluivers