Невозможно установить Bluetooth-гарнитуру в качестве устройства вывода по умолчанию в OS X с помощью API CoreAudio.
У меня возникли трудности с программной настройкой моей Bluetooth-гарнитуры (Apple Airpods) в качестве устройства вывода звука по умолчанию на моей OSX. Я попытался использовать API CoreAudio, чтобы установить устройство по умолчанию, но, похоже, оно не работает.
В своей программе записи звука я создаю совокупное аудиоустройство, включающее в себя гарнитуру Bluetooth и устройство «черная дыра». Программа правильно запоминает имя устройства Bluetooth-гарнитуры и получает из этого имени AudioDeviceID. После записи программа удаляет созданное совокупное аудиоустройство, а затем пытается установить устройство гарнитуры Bluetooth в качестве устройства вывода по умолчанию с помощью AudioObjectSetPropertyData(). Однако, несмотря на то, что функция возвращает успешный результат (noErr), устройство не устанавливается по умолчанию.
Прежде чем прекратить запись, я еще раз проверяю, совпадает ли устройство вывода по умолчанию с предыдущим. Если отображается по-другому, я пытаюсь установить его еще раз. Однако он снова возвращает успех, но еще не устанавливает его по умолчанию.
Я не уверен, является ли это проблемой реализации функции или сама функция не работает. Если у кого-то есть предложения или кто-то сталкивался с подобной проблемой, буду очень признателен за любую помощь или совет.
#include <CoreAudio/AudioHardware.h>
#include <CoreAudio/AudioServerPlugIn.h>
OSStatus SetDefaultOutputDeviceFromName(const char *_name = nullptr)
{
OSStatus err = noErr;
if(_name != nullptr)
{
std::string log_ = "[Destroy Aggregate Device]: Selected loopback device name: " + std::string(_name) + "\n";
synchronized_logger_function(log_);
AudioDeviceID deviceID = findDeviceIDFromDeviceName(_name);
if(deviceID == kAudioObjectUnknown) {
std::cerr << "Error in getting Device Id from name\n";
}
else
{
AudioObjectPropertyAddress defaultDeviceAOPA;
defaultDeviceAOPA.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
defaultDeviceAOPA.mScope = kAudioObjectPropertyScopeGlobal;
defaultDeviceAOPA.mElement = kAudioObjectPropertyElementMain;
err = AudioObjectSetPropertyData(kAudioObjectSystemObject, &defaultDeviceAOPA, 0, NULL, sizeof(AudioDeviceID), &deviceID);
// pause again to give the changes time to take effect
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
if (err)
{
// printf("[Remove Aggregate Device]: Error setting default output device: %d\n", err);
}
else
{
// printf("[Create Aggregate Device]: Previous device set as default output device.\n");
}
}
// MA_ASSERT(deviceID != kAudioObjectUnknown);
}
return noErr;
}
OSStatus DestroyAggregateDevice(AudioDeviceID inDeviceToDestroy, const char *_name = nullptr)
{
OSStatus osErr = noErr;
//-----------------------
// Start by getting the base audio hardware plugin
//-----------------------
// UInt32 outSize;
// Boolean outWritable;
// osErr = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyPlugInForBundleID, &outSize, &outWritable);
// if (osErr != noErr) return osErr;
AudioObjectPropertyAddress propertyAddress = {
kAudioHardwarePropertyPlugInForBundleID,
kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMain};
UInt32 outSize = 0;
// Boolean writable = false;
OSStatus err = AudioObjectGetPropertyDataSize(
kAudioObjectSystemObject,
&propertyAddress,
0,
NULL,
&outSize);
if (err != noErr)
{
// Handle error
synchronized_logger_function(std::string("[Destroy aggregate device]: Error occured in removing aggregate device\n"));
}
AudioValueTranslation pluginAVT;
CFStringRef inBundleRef = CFSTR("com.apple.audio.CoreAudio");
AudioObjectID pluginID;
pluginAVT.mInputData = &inBundleRef;
pluginAVT.mInputDataSize = sizeof(inBundleRef);
pluginAVT.mOutputData = &pluginID;
pluginAVT.mOutputDataSize = sizeof(pluginID);
osErr = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &outSize, &pluginAVT);
// osErr = AudioHardwareGetProperty(kAudioHardwarePropertyPlugInForBundleID, &outSize, &pluginAVT);
if (osErr != noErr)
return osErr;
//-----------------------
// Feed the AudioDeviceID to the plugin, to destroy the aggregate device
//-----------------------
AudioObjectPropertyAddress pluginAOPA;
pluginAOPA.mSelector = kAudioPlugInDestroyAggregateDevice;
pluginAOPA.mScope = kAudioObjectPropertyScopeGlobal;
pluginAOPA.mElement = kAudioObjectPropertyElementMain;
UInt32 outDataSize;
osErr = AudioObjectGetPropertyDataSize(pluginID, &pluginAOPA, 0, NULL, &outDataSize);
if (osErr != noErr)
{
return osErr;
}
osErr = AudioObjectGetPropertyData(pluginID, &pluginAOPA, 0, NULL, &outDataSize, &inDeviceToDestroy);
if (osErr != noErr)
{
return osErr;
}
// pause again to give the changes time to take effect
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
SetDefaultOutputDeviceFromName(_name);
return noErr;
}