我需要确定任意CoreAduio AudioDevice与哪个物理USB设备(通过VID/PID/SerialNumber)相关。CoreAudio允许查询各种设备属性,如传输类型(在我的情况下是USB), UID(跨会话和机器的唯一)和一些配置字符串。
IOKit和CoreAudio的音频部分都有音频设备的表示,但我不清楚如何弥合两者之间的差距。(似乎我应该能够查询AudioDevice的IOAudioDevice…)
我发现了苹果CoreAudio工程师的以下帖子,描述了如何从AudioDeviceID
中获得IOUSBDeviceInterface
:
两者之间没有直接的映射关系。但最好的方法是是:
- 从HAL
获取设备的UID字符串- 创建一个查找IOAudioEngine对象的匹配字典
- 遍历匹配服务,直到找到UID属性与您从HAL
获得的匹配的服务。- 从这里走到iregistry找到您正在寻找的USB对象
代码应该是这样的:
#include <IOKit/IOKitLib.h>
#include <IOKit/audio/IOAudioDefines.h>
#include <IOKit/usb/USB.h>
AudioDeviceID deviceID = ...
// get device UID for AudioDevice ID
AudioObjectPropertyAddress address = {kAudioDevicePropertyDeviceUID, kAudioObjectPropertyScopeOutput, 0};
UInt32 size = sizeof(CFStringRef);
CFStringRef uid = NULL;
OSStatus err = AudioObjectGetPropertyData(deviceID, &address, 0, NULL, &size, &uid);
NSNumber *vid, *pid;
// find matching IOAudioEngine object
io_iterator_t it;
if (IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceMatching(kIOAudioEngineClassName), &it) == KERN_SUCCESS) {
io_service_t service;
while ((service = IOIteratorNext(it)) != 0) {
CFStringRef uniqueID = IORegistryEntryCreateCFProperty(service, CFSTR(kIOAudioEngineGlobalUniqueIDKey), kCFAllocatorDefault, 0);
if (uniqueID && CFEqual(uniqueID, uid)) {
vid = CFBridgingRelease(IORegistryEntryCreateCFProperty(service, CFSTR(kUSBVendorID), kCFAllocatorDefault, 0));
pid = CFBridgingRelease(IORegistryEntryCreateCFProperty(service, CFSTR(kUSBProductID), kCFAllocatorDefault, 0));
}
CFRelease(uniqueID);
if (vid || pid) break;
}
IOObjectRelease(it);
}