Как получать уведомления, когда наушники подключены/выключены? макинтош

Я хотел бы получить уведомление, когда наушники подключены или вставлены в гнездо для наушников.
Я искал для этого в stackoverflow, но я не могу найти то, что я ищу для Mac, я могу найти только для iOS.
Итак, есть ли у вас какие-либо идеи о том, как это сделать? Что я хочу сделать с этим: когда наушники подключены, я хочу программно приостановить iTunes (iOS-подобная функция).
Спасибо!

Ответ 1

Вы можете наблюдать изменения, используя структуру CoreAudio.

Оба наушника и динамики являются источниками данных на одном и том же устройстве вывода звука (типа встроенного). Один из них будет подключен к аудиоустройству на основе подключенных или отключенных наушников.

Чтобы получать уведомления, вы слушаете изменения активного источника данных на встроенном устройстве вывода.

1. Получить встроенное устройство вывода

Чтобы сохранить это, мы будем использовать устройство вывода по умолчанию. В большинстве случаев это встроенное устройство вывода. В реальных приложениях вы захотите закодировать все доступные устройства, чтобы найти его, потому что устройство по умолчанию может быть настроено на другое аудиоустройство (например, soundflower или airplay).

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

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

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

2. Прочтите текущий источник данных

Текущий источник данных на устройстве идентифицируется идентификатором типа 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. Наблюдайте за изменениями в источнике данных

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

Определите тип источника данных

Когда у вас есть идентификатор источника данных как UInt32, вы можете запросить аудио объект для свойств с помощью трансформатора значения. Например, чтобы получить имя источника в качестве строки, используйте kAudioDevicePropertyDataSourceNameForIDCFString. Это приведет к появлению строки "Внутренний динамик" или "Наушники". Однако это может различаться в зависимости от пользовательской локали.

Более простой способ - напрямую сравнить исходный код источника данных:

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

Однако я не мог найти никаких констант, определенных для этих значений, поэтому это недостоверно.