I need to to determine which physical USB device (via VID/PID/SerialNumber) an arbitrary CoreAduio AudioDevice relates to. CoreAudio allows to query various device proprerties such as transport type (USB in my case), a UID (unique across sessions and machines), and a few configuration strings.
Both the audio portion of IOKit and CoreAudio have a representation for audio devices but it's not clear to me how to bridge the gap between the two. (Seems like I should be able to query AudioDevice for it's IOAudioDevice...)
I found the following post from an Apple CoreAudio engineer describing how to get the IOUSBDeviceInterface from an AudioDeviceID:
There is no direct mapping between the two. But the best way to do it would be:
- get the UID string for the device from the HAL
- Make a matching dictionary that searches for IOAudioEngine objects
- Iterate through the matching services until you find the one with the UID property that matches what you got from the HAL
- Walk the IORegistry from here to find the USB object you are looking for
This is what the code would look like:
#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);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With