Thanks for being a part of WWDC25!

How did we do? We’d love to know your thoughts on this year’s conference. Take the survey here

Does USB Audio in macOS support 12 channels with 16bit PCM samples?

I have a custom USB Audio Class 2 (UAC2) compatible device. When I connect this custom device to a MacBook with a configuration of up to 10 channels (16-bit), everything seems to work fine. However, when I increase the channel count to 12, the MacBook does not recognize the 12 channels. It only shows the channel count as 0.

TN2274 is the only source where I found some information about Apple's Audio Class Drivers, but it doesn't mention any limitations regarding channel counts.

Could you let me know the current limitations of the Audio Class Drivers on the latest macOS versions? What configuration should I use to get 12 channels working?

P.S. I also found that a 12-channel, 8-bit configuration is detected by the MacBook, bit I want it to work with 16bits.

For more detail please check FB17098863

Answered by ssmith_c in 834507022

thanks for posting the descriptor.

Here's the descriptor of alternate interface 1 of interface 3, the audio streaming interface, when set to 12 channels of 8-bit-per-sample audio:

Endpoint 0x03 - Isochronous Output   
                Address:   0x03  (OUT)
                Attributes:   0x09  (Isochronous adaptive data endpoint)
                Max Packet Size:   0x024c  (588 x 1  transactions opportunities per microframe)
                Polling Interval:   4 (8 microframes (1 msecs) 

Your sampling rate is 48kHz, so 48 samples every millisecond. The polling interval is 1 millisecond (the actual number in the descriptor is 4, we're on USB 2.0 high speed here, so that means every 2^(4-1) or 8 micro-frames. Each sample is 1 bytes, and there are 12 channels. So in each frame, there are 12x48 or 576 bytes to transfer (nominally). Up to one additional sample frame (12 bytes) may be transferred in each interval to synchronize the device rate with the host rate, which is where the 588 bytes comes from.

In the 16 bits-per-channel case, the polling interval is the same - 1ms. But you need to transfer up to 1152+24 = 1176 bytes per interval. However, the maxPacketSize here is 1024 - the maximum allowed by the USB 2.0 Audio Specification.

One way to fix this is to change the descriptor to reduce the polling interval from every millisecond to twice every millisecond (the number '3' in the bInterval field, and change the wMaxPacketSize to 588.

Another possibility would be to ask for up to two transactions per micro frame - this is squeezed into bits 12 and 11 of bMaxPacketSize. However, the (now ancient) tech note TN2274 says "At this time, AppleUSBAudio supports at most one transaction per microframe".

See Table 9-13 and section 5.6.3 of the USB 2.0 Specification and Table 4-33 of the USB Audio Class Specification v2.0

You might be asking yourself why it "works on Linux", but does it really?

How custom is your custom device? Does it work on other platforms? I assume since it is an audio device, that it is using isochronous transfers. Does your device reserve enough isochronous bandwidth for 12 channels of 48kHz, 16 bit per sample audio?

Hi @ssmith_c ,

Thank very much for getting back on this question.

How custom is your custom device?
My custom device is an AOSP (Android) based device which supports UAC2 drivers. I am using the standard UAC2 drivers officially shipped with Android.

Does it work on other platforms?
My primary objective was to get the device working with macOS. In Linux enviroment the detection of 12 channels was working fine.

Does your device reserve enough isochronous bandwidth for 12 channels of 48kHz, 16 bit per sample audio?
Data rate for 12 channels 16bit PCM @ 48kHz is ˜9.2 Mbps. The USB 2.0 which I tested have a bandwidth of 480 Mbps.

My primary question is, what are the limitation of the UAC2 driver support in latest macOS devices and where can I get for infomation about it? Specially what is the minimum buffer size that apple devices support with UAC2 drivers.

I can't tell you anything about the audio drivers in macOS, sorry.

By "how custom" I meant "do you write the firmware". It doesn't really matter how much bandwidth is available on the bus. The device declares a number of different alternate interfaces in its USB descriptor, which ask the OS for a different amount of USB bandwidth. This enables multiple devices to occupy the same bus with predictable results. It is possible that there is something a bit odd about your device's USB descriptor. You could post it here. Use the usbdiagnose tool to fetch the descriptor (it is in /usb/bin)

Have you checked the system log to see if it is complaining about the device, either from the USB sub-system or from the Core Audio subsystem?

Since the log floods with irrelevant messages but you don't know what to look for until you've seen it, live filtering on predicates is not very useful. I would connect the device, then execute

log collect --last 1m

which will write the last 1 minute of log data to a file, which you can then peruse later, or export and examine with a text editor.

The tech note you referenced says "Snow Leopard (and later) is able to stream 10 channels of 32-bit audio at 192 kHz to and from a USB Audio 2.0 device" - bandwidth or system performance is unlikely to be your limitation.

There are USB audio mixers available for macOS with more than 12 channels at 192kHz and 16 bits. Have you compared your device's behavior with one of those?

Thank you very much for the inputs. I didn't know that there is a bandwidth limitation on different interfaces when there are multiple USB interfaces are sharing the same USB device.

Anyways the firmware in the custom device is not written by me. I only do USB gadget configuration changes to change the bit depth and channel count. The firmware is the standard Linux firmware that shipped with Android OSP.

By the way, I checked the usbdiagnose output for 8bit (working condition) and 16bit configs. The only noticeable difference is the Max Packet Size which is 558 (8bit case) and 1024 and 1023 (16bit case). I am not sure why it shows two values in two different places. I have attached the output as files for your reference.

On the log collect --last 1m the only meaning full error was from coreaudiod

HALS_PlugIn.cpp:834   HALS_PlugIn::HostInterface_PropertiesChanged: the object is not valid

Are there any other places which I can check to identify the issue real?

Accepted Answer

thanks for posting the descriptor.

Here's the descriptor of alternate interface 1 of interface 3, the audio streaming interface, when set to 12 channels of 8-bit-per-sample audio:

Endpoint 0x03 - Isochronous Output   
                Address:   0x03  (OUT)
                Attributes:   0x09  (Isochronous adaptive data endpoint)
                Max Packet Size:   0x024c  (588 x 1  transactions opportunities per microframe)
                Polling Interval:   4 (8 microframes (1 msecs) 

Your sampling rate is 48kHz, so 48 samples every millisecond. The polling interval is 1 millisecond (the actual number in the descriptor is 4, we're on USB 2.0 high speed here, so that means every 2^(4-1) or 8 micro-frames. Each sample is 1 bytes, and there are 12 channels. So in each frame, there are 12x48 or 576 bytes to transfer (nominally). Up to one additional sample frame (12 bytes) may be transferred in each interval to synchronize the device rate with the host rate, which is where the 588 bytes comes from.

In the 16 bits-per-channel case, the polling interval is the same - 1ms. But you need to transfer up to 1152+24 = 1176 bytes per interval. However, the maxPacketSize here is 1024 - the maximum allowed by the USB 2.0 Audio Specification.

One way to fix this is to change the descriptor to reduce the polling interval from every millisecond to twice every millisecond (the number '3' in the bInterval field, and change the wMaxPacketSize to 588.

Another possibility would be to ask for up to two transactions per micro frame - this is squeezed into bits 12 and 11 of bMaxPacketSize. However, the (now ancient) tech note TN2274 says "At this time, AppleUSBAudio supports at most one transaction per microframe".

See Table 9-13 and section 5.6.3 of the USB 2.0 Specification and Table 4-33 of the USB Audio Class Specification v2.0

You might be asking yourself why it "works on Linux", but does it really?

Thank you very much for the clarification. I was able to get a quick fix by reducing the sample rate to 32Khz which is sufficient for now.

Thanks a lot for finding the real root cause of my issue.

On the points of "works on Linux" the 12 channel is getting detected in Linux but playback was not working fine. I think I forgot to mention that point clearly before.

Does USB Audio in macOS support 12 channels with 16bit PCM samples?
 
 
Q