Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Finding the USB VID/PID associated with a CoreAudio device on OSX

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...)

like image 766
user2134761 Avatar asked Dec 31 '25 08:12

user2134761


1 Answers

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:

  1. get the UID string for the device from the HAL
  2. Make a matching dictionary that searches for IOAudioEngine objects
  3. Iterate through the matching services until you find the one with the UID property that matches what you got from the HAL
  4. 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);
}
like image 70
Frederik Avatar answered Jan 01 '26 22:01

Frederik