OS X下使用CoreAudio API无法将蓝牙耳机设为默认输出设备
macOS下CoreAudio设置AirPods为默认输出设备失败问题
问题背景
在录音程序中创建了包含AirPods蓝牙耳机和Blackhole设备的聚合音频设备,录制完成后删除该聚合设备,随后调用AudioObjectSetPropertyData()尝试将AirPods设为默认输出设备。尽管函数返回noErr成功状态,但设备并未实际成为默认输出设备;退出录音前再次检查并重试设置,依然返回成功但无实际效果。
已知条件:程序能正确记录AirPods设备名称,并通过名称获取到对应的AudioDeviceID。
相关代码
#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 //----------------------- AudioObjectPropertyAddress propertyAddress = { kAudioHardwarePropertyPlugInForBundleID, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMain}; UInt32 outSize = 0; 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); 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; }
排查与解决建议
1. 延长系统状态同步等待时间
销毁聚合设备后,系统音频服务可能仍在处理状态变更,立即设置默认设备可能被后续操作覆盖。建议将CFRunLoopRunInMode的超时时间从0.1秒调整至0.5-1秒,确保系统完成聚合设备的清理工作。
2. 添加设置后验证逻辑
在调用AudioObjectSetPropertyData后,立即读取当前默认设备ID进行验证,确认设置是否真的生效,若未生效则重试:
// 在SetDefaultOutputDeviceFromName函数的设置操作后添加 AudioDeviceID currentDefault; UInt32 size = sizeof(AudioDeviceID); err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &defaultDeviceAOPA, 0, NULL, &size, ¤tDefault); if (err == noErr && currentDefault != deviceID) { synchronized_logger_function("Default device verification failed, retrying...\n"); err = AudioObjectSetPropertyData(kAudioObjectSystemObject, &defaultDeviceAOPA, 0, NULL, sizeof(AudioDeviceID), &deviceID); }
3. 检查辅助功能权限
macOS Ventura及以上版本中,音频设备设置可能需要程序拥有「辅助功能」权限。前往「系统设置-隐私与安全性-辅助功能」,确认当前程序已被授权,若未授权则手动添加后重新测试。
4. 确认AirPods设备状态
AirPods可能处于连接不稳定状态(如重新连接中),导致设置默认设备失败。设置前可通过kAudioDevicePropertyDeviceIsRunning属性检查设备是否处于活跃可用状态。
5. 监听音频设备属性变化
通过注册kAudioHardwarePropertyDefaultOutputDevice的属性监听器,确认聚合设备完全销毁后,再执行默认设备设置操作,避免状态冲突。
内容的提问来源于stack exchange,提问作者V K
相关产品推荐
相关产品推荐

