Convert CoreAudio AudioObjectID to IOUSB LocationID

Is there a recommended way on macOS 26 Tahoe to take a CoreAudio AudioObjectID and use it to lookup the underlying USB LocationID?

I previously used AudioObjectID to query the corresponding DeviceUID with kAudioDevicePropertyDeviceUID. Then I queried for the IOService matching kIOAudioEngineClassName with property kIOAudioEngineGlobalUniqueIDKey matching DeviceUID, and I loaded kUSBDevicePropertyLocationID from the result.

This fails on macOS 26, because the IO Registry for the device has an entry for usbaudiod rather than AppleUSBAudioEngine, and usbaudiod does not include a kIOAudioEngineGlobalUniqueIDKey property (or any other property to map it to a CoreAudio DeviceUID).

My use-case here is a piece of audio recording software that allows configuring a set of supported audio devices via USB HID prior to recording. I present the user with a list of CoreAudio devices to use, but without a way to lookup the underlying USB LocationID, I cannot guarantee that the configured device matches the selected device (e.g. if the user plugged in two identical microphones).

Answered by Engineer in 859601022

The examples in the code example below are for reference purposes only.

IOAudioFamily.kext and IOAudioFamily support

macOS Tahoe no longer implements the USB Audio class using an IOAudioFamily based kext. USB Audio class devices are now supported within a driver functioning in user space. This change has implications for 3rd party developers who provide additional support for their devices. It is common for some devices to provide additional, non-class, USB interfaces for control and configuration of proprietary parameters and these parameters are generally made available to end users via custom applications provided by the 3rd party vendor.

To access these advanced parameters an application developer may need to associate an instance of a Core Audio device AudioObjectID, created and published by the Apple USB Audio class driver, with the underlying USB device available through one of the IOUSBHostFamily API's.

AppleUSBAudio.kext (IOAudioFamily) is no longer in use:

The following IOServices published by AppleUSBAudio.kext are no longer created:
-AppleUSBAudioEngine
-AppleUSBAudioDevice
-AppleUSBAudioStream
 

Any properties previously published by those services in the IORegistry will no longer be available.

Applications that have depended on AppleUSBAudio.kext/IOAudioFamily services will need to be updated.

The example below is mostly written mostly in Swift for convenience. There is nothing specific to Swift or Swift frameworks and this example can be implemented with Objective C or C API's without much effort.

Notes on matching

It is possible to match on IOUSBHostDevice services by VID/PID. This is what the USB Audio class driver does. Because the USB Audio class driver also matches on these services, there is a delay in publishing Core Audio audio devices, and this delay may cause a race if your application is looking for both the service and a Core Audio device. We suggest implementors listen for CoreAudio audio device notifications for discovery, after which you can you build upon the examples below to get the IOUSBHostDevice service. Discovering devices through the CoreAudio eliminates that race.

Which method the application chooses for discovering devices is beyond the scope of this example.

Core audio device properties of interest

There are 2 Core Audio properties that the Apple USB class driver sets that are useful for associating IOUSBHostDevice services:

kAudioDevicePropertyDeviceUID

The Core Audio property kAudioDevicePropertyDeviceUID is set from the USB Audio class driver(s) as: "AppleUSBAudioEngine:\(manufacturerName):\(usbDevice.deviceName):\(serialNumberOrLocation):\(interfacesString)" The serialNumberOrLocation component of the deviceUID is one of the 2 properties set on the IOUSBHostDevice service: -iSerialNumber -locationID

kAudioDevicePropertyModelUID

The Core Audio property kAudioDevicePropertyDeviceUID is set from the USB Audio class driver(s) as: "BoxName::0xVID:0xPID" - Both VID/PID are 16 bits Hex

Accepted Answer

The examples in the code example below are for reference purposes only.

IOAudioFamily.kext and IOAudioFamily support

macOS Tahoe no longer implements the USB Audio class using an IOAudioFamily based kext. USB Audio class devices are now supported within a driver functioning in user space. This change has implications for 3rd party developers who provide additional support for their devices. It is common for some devices to provide additional, non-class, USB interfaces for control and configuration of proprietary parameters and these parameters are generally made available to end users via custom applications provided by the 3rd party vendor.

To access these advanced parameters an application developer may need to associate an instance of a Core Audio device AudioObjectID, created and published by the Apple USB Audio class driver, with the underlying USB device available through one of the IOUSBHostFamily API's.

AppleUSBAudio.kext (IOAudioFamily) is no longer in use:

The following IOServices published by AppleUSBAudio.kext are no longer created:
-AppleUSBAudioEngine
-AppleUSBAudioDevice
-AppleUSBAudioStream
 

Any properties previously published by those services in the IORegistry will no longer be available.

Applications that have depended on AppleUSBAudio.kext/IOAudioFamily services will need to be updated.

The example below is mostly written mostly in Swift for convenience. There is nothing specific to Swift or Swift frameworks and this example can be implemented with Objective C or C API's without much effort.

Notes on matching

It is possible to match on IOUSBHostDevice services by VID/PID. This is what the USB Audio class driver does. Because the USB Audio class driver also matches on these services, there is a delay in publishing Core Audio audio devices, and this delay may cause a race if your application is looking for both the service and a Core Audio device. We suggest implementors listen for CoreAudio audio device notifications for discovery, after which you can you build upon the examples below to get the IOUSBHostDevice service. Discovering devices through the CoreAudio eliminates that race.

Which method the application chooses for discovering devices is beyond the scope of this example.

Core audio device properties of interest

There are 2 Core Audio properties that the Apple USB class driver sets that are useful for associating IOUSBHostDevice services:

kAudioDevicePropertyDeviceUID

The Core Audio property kAudioDevicePropertyDeviceUID is set from the USB Audio class driver(s) as: "AppleUSBAudioEngine:\(manufacturerName):\(usbDevice.deviceName):\(serialNumberOrLocation):\(interfacesString)" The serialNumberOrLocation component of the deviceUID is one of the 2 properties set on the IOUSBHostDevice service: -iSerialNumber -locationID

kAudioDevicePropertyModelUID

The Core Audio property kAudioDevicePropertyDeviceUID is set from the USB Audio class driver(s) as: "BoxName::0xVID:0xPID" - Both VID/PID are 16 bits Hex

Thank you! I ultimately settled on parsing the deviceUID to achieve this association.

Convert CoreAudio AudioObjectID to IOUSB LocationID
 
 
Q