USB interface for multi channel outputs, not just stereo

Have you actually selected 8-channel USB in the Tools menu?

1747775132485.png


If you don't, the AudioInputUSBOct and AudioOutputUSBOct classes are not defined (because they wouldn't work), and that's the error message you'd get.
 
I was able to successfully compile.
The issue was I hadn't set the USB Type to "Audio".

I am able to use audacity and stream audio on the first two channels as Audacity only supports stereo playback. Rest of the 6 channels are still silent.

I am looking for an audio tool or audacity plugin that lets to stream 8 channel audio. Any recommendations?
 
Hey @alex6679,
Yes, I did test it on my Mac.
Even with just Stereo playback with Audacity on Mac.
The channels go Mute after about 5s of playback.Same for more than 8 channel play back as well.

On Windows it works perfectly.
 
Hi, it looks like the same issue that's occurring on Weiweiweiwear's Mac. A plausible explanation is that it's related to the feedback the Teensy sends to the USB host:
  • This would explain why the problem doesn't occur on all Macs—it depends on the clock difference between the USB host and the Teensy.
  • It would also explain why it takes a few seconds before the Mac mutes the signal. Initially, the Teensy sends the default feedback and requests samples at 44.1kHz. If the Mac's clock is significantly slower, the Teensy gradually increases the sample request rate to avoid a buffer underflow. Eventually (e.g., after about 5 seconds), the feedback reaches a value that the Mac rejects, and from that point on, the Mac sends only a muted signal.
I’ve created this branch of my usb interface where the Teensy always sends only the default feedback to the USB host. @fan_2021, could you please try this branch and see if the problem still occurs?
 
Apologies if this isn't the place to ask.

I have a Teensy 4.1 and a couple of BOOST-DAC8568 dev boards and I was wanting to use this setup for Linux USB audio but I need it to support DC-coupled operation so I can also output control voltages from a DAW. I don't need to use DAC8568, happy to use something more suitable but I would want at least eight DC-coupled channels, is this possible?

Thanks.
 
Hi, it looks like the same issue that's occurring on Weiweiweiwear's Mac. A plausible explanation is that it's related to the feedback the Teensy sends to the USB host:
  • This would explain why the problem doesn't occur on all Macs—it depends on the clock difference between the USB host and the Teensy.
  • It would also explain why it takes a few seconds before the Mac mutes the signal. Initially, the Teensy sends the default feedback and requests samples at 44.1kHz. If the Mac's clock is significantly slower, the Teensy gradually increases the sample request rate to avoid a buffer underflow. Eventually (e.g., after about 5 seconds), the feedback reaches a value that the Mac rejects, and from that point on, the Mac sends only a muted signal.
I’ve created this branch of my usb interface where the Teensy always sends only the default feedback to the USB host. @fan_2021, could you please try this branch and see if the problem still occurs?
Hey Alex,

first of all a big thanks to you and all the other people who put so much effort into this ecosystem! Since I also have the problem on my Mac that audio output is muted after ~5s, I did some tests and catched the logs.

I used your main_usbInput.ino example, just modified to use the ADA1966A via TDM as output. Then I caught the system usb logs using
Bash:
sudo log stream --predicate 'eventMessage contains "USB"' --info

Directly after starting the playback, everything looked fine:
Code:
2025-07-28 08:49:01.400178+0200 0xcbbb     Default     0x0                  195    0    coreaudiod: (CoreAudio) HALS_IOContext_Legacy_Impl.cpp:1368   HALS_IOContext_Legacy_Impl::IOWorkLoopInit: 428 AppleUSBAudioEngine:Teensyduino:Teensy MIDI_Audio:Audio-2/442B:3,4 (AppleUSBAudioEngine:Teensyduino:Teensy MIDI_Audio:Audio-2/442B:3,4): starting
2025-07-28 08:49:01.401842+0200 0xc9b1     Default     0x0                  195    0    coreaudiod: (CoreAudio)   HALB_PowerAssertion.cpp:115    HALB_PowerAssertion::Take: taking power assertion ID 34818 of type 'PreventUserIdleSystemSleep' with name: 'com.apple.audio.AppleUSBAudioEngine:Teensyduino:Teensy MIDI_Audio:Audio-2/442B:3,4.context.preventuseridlesleep' on behalf of 3099
2025-07-28 08:49:01.414859+0200 0xc9b1     Default     0x0                  195    0    coreaudiod: (libAudioStatistics.dylib) [com.apple.coreaudio:carc]      CAReportingClient.mm:702   Sending message { message="{
    "device_is_aggregate" = 0;
    "duration_us" = 12173;
    "hal_chat_flavor" = default;
    "input_avail_phys_formats" = "{ [16/44100/2 lpcm] }";
    "input_avail_virt_formats" = "{ [32/44100/2 lpcm] }";
    "input_bits_per_channel" = 32;
    "input_bytes_per_frame" = 8;
    "input_bytes_per_packet" = 8;
    "input_channels_per_frame" = 2;
    "input_device_latency_list" = 45;
    "input_device_source_list" = Unknown;
    "input_device_start_duration_us_list" = 7226;
    "input_device_transport_list" = USB;
    "input_device_uid_list" = "AppleUSBAudioEngine:Teensyduino:Teensy MIDI_Audio:Audio-2/:3,4";
    "input_format_id" = lpcm;
    "input_frames_per_packet" = 1;
    "input_num_tap_streams" = 0;
    "input_scalar_volume" = "1.000000";
    "io_buffer_size" = 512;
    message = StartHardware;
    "output_avail_phys_formats" = "{ [16/44100/2 lpcm] }";
    "output_avail_virt_formats" = "{ [32/44100/2 lpcm] }";
    "output_bits_per_channel" = 32;
    "output_bytes_p", reporters="<decode: missing data>" }
2025-07-28 08:49:01.445706+0200 0x500d     Default     0x0                  3099   0    Music: (AudioSession) [com.apple.coreaudio:as_client]   AVAudioSession_MacOS.mm:2356  --> setPlayState Started Output {AppleUSBAudioEngine:Teensyduino:Teensy MIDI_Audio:Audio-2/442B:3,4, 0xa}
2025-07-28 08:49:01.445768+0200 0x500d     Info        0x0                  3099   0    Music: (AudioSession) [com.apple.coreaudio:as_client]   AVAudioSession_MacOS.mm:2379  Devices are same: =0. Previous: {(
)}. Current: {(
    "AppleUSBAudioEngine:Teensyduino:Teensy MIDI_Audio:Audio-2/442B:3,4"
)}

After 5s, I get messages like
Code:
2025-07-28 08:49:05.910096+0200 0xa3d      Default     0x0                  195    0    coreaudiod: (libAudioStatistics.dylib) [com.apple.coreaudio:carc]      CAReportingClient.mm:702   Sending message { message="{
    "HAL_client_IO_duration" = 60375;
    HostApplicationDisplayID = "com.apple.Music";
    "anchor_sample_time" = 583;
    cause = Unknown;
    "cause_set" = 0;
    deadline = 197191;
    "input_device_source_list" = Unknown;
    "input_device_transport_list" = USB;
    "input_device_uid_list" = "AppleUSBAudioEngine:Teensyduino:Teensy MIDI_Audio:Audio-2/:3,4";
    "io_buffer_size" = 512;
    "io_cycle" = 382;
    "io_cycle_budget" = 23242625;
    "io_cycle_usage" = 1;
    "io_frame_counter" = 382;
    "io_page_faults" = 0;
    "io_page_faults_duration" = 0;
    "is_prewarming" = 0;
    "is_recovering" = 0;
    "issue_type" = overload;
    lateness = "-1014";
    "multi_cycle_io_page_faults" = 0;
    "multi_cycle_io_page_faults_duration" = 0;
    "num_continuous_nonzero_io_cycles" = 372;
    "num_continuous_silent_io_cycles" = 0;
    "other_active_clients" = "[  ]";
    "other_page_faults" = 0;
    "output_device_source_list" = Unknown;
    "output_device_transport_", reporters="<decode: missing data>" }

This message is repeated with every cycle until audio is finally muted:
Code:
2025-07-28 08:49:06.427846+0200 0xa3d      Default     0x0                  195    0    coreaudiod: (libAudioStatistics.dylib) [com.apple.coreaudio:carc]      CAReportingClient.mm:702   Sending message { message="{
    "HAL_client_IO_duration" = 54500;
    HostApplicationDisplayID = "com.apple.Music";
    "anchor_sample_time" = 218683;
    cause = Unknown;
    "cause_set" = 0;
    deadline = 220219;
    "input_device_source_list" = Unknown;
    "input_device_transport_list" = USB;
    "input_device_uid_list" = "AppleUSBAudioEngine:Teensyduino:Teensy MIDI_Audio:Audio-2/:3,4";
    "io_buffer_size" = 512;
    "io_cycle" = 1;
    "io_cycle_budget" = 23242625;
    "io_cycle_usage" = 1;
    "io_frame_counter" = 1;
    "io_page_faults" = 0;
    "io_page_faults_duration" = 0;
    "is_prewarming" = 0;
    "is_recovering" = 0;
    "issue_type" = overload;
    lateness = "-1017";
    "multi_cycle_io_page_faults" = 0;
    "multi_cycle_io_page_faults_duration" = 0;
    "num_continuous_nonzero_io_cycles" = 416;
    "num_continuous_silent_io_cycles" = 0;
    "other_active_clients" = "[  ]";
    "other_page_faults" = 0;
    "output_device_source_list" = Unknown;
    "output_device_transport_l", reporters="<decode: missing data>" }
2025-07-28 08:49:06.432005+0200 0xa3d      Default     0x0                  195    0    coreaudiod: (libAudioStatistics.dylib) [com.apple.coreaudio:carc]      CAReportingClient.mm:702   Sending message { message="{
    "HAL_client_IO_duration" = 39375;
    HostApplicationDisplayID = "com.apple.Music";
    "anchor_sample_time" = 219207;
    cause = Unknown;
    "cause_set" = 0;
    deadline = 220743;
    "input_device_source_list" = Unknown;
    "input_device_transport_list" = USB;
    "input_device_uid_list" = "AppleUSBAudioEngine:Teensyduino:Teensy MIDI_Audio:Audio-2/:3,4";
    "io_buffer_size" = 512;
    "io_cycle" = 1;
    "io_cycle_budget" = 23242625;
    "io_cycle_usage" = 1;
    "io_frame_counter" = 1;
    "io_page_faults" = 0;
    "io_page_faults_duration" = 0;
    "is_prewarming" = 0;
    "is_recovering" = 0;
    "issue_type" = overload;
    lateness = "-1018";
    "multi_cycle_io_page_faults" = 0;
    "multi_cycle_io_page_faults_duration" = 0;
    "num_continuous_nonzero_io_cycles" = 0;
    "num_continuous_silent_io_cycles" = 1;
    "other_active_clients" = "[  ]";
    "other_page_faults" = 0;
    "output_device_source_list" = Unknown;
    "output_device_transport_lis", reporters="<decode: missing data>" }

"num_continuous_nonzero_io_cycles" is then incremented in every following cycle.

The overload issue tells me that there are some kinds of timing problems. But I'm struggling with deeper understanding. Using your default_feedback branch did not change this behavior.

I would be happy to help improving the library with some debugging, but since I'm not so much into usb audio, I don't quite know where to start.

My system:
MacBook Pro M2 Pro (Sonoma 14.6.1)
Arduino IDE 2.3.2
Teensyduino 1.59.0
 
Just out of interest, does it make any difference if you add an AudioOutputI2S object to the code? It doesn't have to do anything besides exist, which will make the audio system update happen at a more precise interval rather than relying on an intervalTimer which has dubious accuracy.

Edit: never mind, I see that the sample code already has one in it...
 
Just out of interest, does it make any difference if you add an AudioOutputI2S object to the code? It doesn't have to do anything besides exist, which will make the audio system update happen at a more precise interval rather than relying on an intervalTimer which has dubious accuracy.

Edit: never mind, I see that the sample code already has one in it...
I tried both with and without I2S output. When I leave the I2S output from the example in the code, I don't get any audio output at all. But I did not expect this to work because the documentation for AudioOutputTDM says
The I2S hardware is used by TDM, so TDM objects may not be used together with I2S, SPDIF or PT8211.
So usually I comment out the I2S output.

In both cases, I catch the same usb logs, as posted above. I also just noticed that "num_continuous_nonzero_io_cycles" is incremented as long as audio is playing. As soon as I pause the audio playback, it switches to incrementing "num_continuous_silent_io_cycles". So this change does not appear to have something to do with our problem.
 
Thank you very much for your test and the log output!
I'll have a closer look at the log output next weekend. If you have some time, could you maybe also test the usb output example 'main_usbOutput.ino' and again have a look at the log output? I am just curious if the problem is only related to the usb input or if it also occurs at the usb ouput.
 
Thanks for your suggestion. I tried the 'main_usbOutput.ino' and it works perfectly. I could record all 8 tracks for about 1 min without any problems. No problematic logs on the console.

I will try to gather some additional information and let you know about my progress before the weekend.
 
This is interesting. With the script main_usbOutput.ino, did you also try playing some audio on the Mac? With that script incoming audio is just discarded. If the "overload" issue doesn't appear in the log and everything looks fine on the Mac, then we might have a clue as to which part of the Teensy code is causing the problem.
 
Good news! Playing audio not only works without errors with the main_usbOutput.ino, but also with main_usbInput.ino, as soon as I add an additional line
Code:
AudioOutputUSB usb2;
after
Code:
AudioInputUSB usb1;

From that point, I could again modify the original example to use my ADAU1966A with TDM output and I can confirm that all 8 tracks get through the teensy without any problems or overload logs. So the difference seems to be made by initializing an additional AudioOutputUSB, even if it's not needed.
 
Wow! This are great news! Thank you for your help. I'll have a look at the code and try to spot the missing initialization that causes the problem.
 
I think the problem is caused by the following code:
C++:
// Called from the USB interrupt when ready to transmit another
// isochronous packet.  If we place data into the transmit buffer,
// the return is the number of bytes.  Otherwise, return 0 means
// no data to transmit
unsigned int usb_audio_transmit_callback(void)
{   
    if(!USBAudioOutInterface::running){
        return 0;
    }
If there is no AudioOutputUSB, then USBAudioOutInterface::running if false and the Teensy only sends empty packages to the host. I changed the code now, so that the Teensy sends a quiet signal if the USBAudioOutInterface::running is not running:
C++:
// Called from the USB interrupt when ready to transmit another
// isochronous packet.
// the return is the number of bytes to transmit
unsigned int usb_audio_transmit_callback(void)
{   
    //compute the number of samples we want to transmit (at 44.1kHz and a bInterval of 1ms that is either 44 or 45 samples)
    uint32_t target = getTransmissionTarget();
    if(!USBAudioOutInterface::running){
        //Some hosts (Linux, Windows) would tolerate zero length data packages.
        //However, sometimes there are troubles with MacOs.
        //So we better always send the expected number of samples.
        const uint32_t numBytes =target*noTransmittedChannels*AUDIO_SUBSLOT_SIZE;
        uint8_t *data = usb_audio_transmit_buffer;
        memset(data, 0, numBytes);
        return target * noTransmittedChannels*AUDIO_SUBSLOT_SIZE;
    }
I tested it and on Windows it doesn't make a noticable difference.
I also asked Chatgpt, if it thinks that this was the problem. Here is its answer:

What your new test tells us​


When the Teensy operates playback-only it still presents a USB IN streaming endpoint to macOS, but that endpoint returns zero-length isochronous packets every micro-frame.
When you turned on full-duplex (the Teensy now sends real audio frames back to the host) the overloads vanished.


That points to a very specific failure mode that others have run into:


ConditionWhat Core Audio expectsWhat the Teensy does in “receive-only” modeResult
Streaming interface advertises an IN endpointA constant stream of packets whose size matches the nominal frame count (or, at worst, short packets with valid “silent” samples)Repeated 0-byte packetsCore Audio thread blocks waiting for data → HAL_client_IO_duration skyrockets → “overload” reset

macOS isn’t demanding non-silent audio, but it does require correctly-sized packets as long as the IN endpoint is active. Repeated zero-length packets keep the USB transfer alive but starve the audio engine, and Apple’s driver reports a sustained “overload” exactly like the one in your logs Apple Developer. Intel even documents a related xHCI erratum: a host controller may hang if a USB-audio device “sends zero-length data packets” Steinberg Forums.

The USB-Audio spec allows an isochronous IN endpoint to reply with ZLPs when no data is ready Stack OverflowDaniel S. Gruss, but Core Audio’s class driver clearly doesn’t cope well when the packets never regain their nominal size.

Why you didn’t see the problem on Android or Windows​


  • Android’s ALSA/USB stack requests data in larger chunks and quietly injects silence when it gets a 0-length ISO IN transfer.
  • Windows’ UAC2 driver seems to tolerate a run of ZLPs, although Microsoft’s own docs still flag variable-size packets as a corner case Apple Developer.

macOS’s class driver, however, assumes that if an IN endpoint is active it will deliver time-stamped audio frames of the advertised size. When that assumption is violated the driver stalls for tens of milliseconds, Core Audio blows its 11 ms deadline, and Console shows exactly the overload pattern you captured.
 
So it's a known quirk of the macOs driver.
Funny thing: When Weiweiweiwear and I tried to solve the issue, I also made a version of the audio interface at which I mixed the code from the current Teensy audio main branch with my current implementation:
  • All UAC1 related stuff (e.g. descriptors... ) were taken from the current Teensy audio main branch.
  • The content of usb_audio.cpp (e.g. feedback computation) was taken from my implementation.
With this implementation the issue was also solved. It seems like the macOs UAC1 driver has no problem with this empty packages.
Anyway, I already commited the change to the main branch. @SonicSignals_Workshop, could you test whether the issue is resolved on your end? Specifically, does main_usbInput.ino now work without needing to add an AudioInputUSB instance?
 
Finding this thread convinced me to get my first Teensy. I have been well rewarded!

I have tested on these machines, using the 2 channel USB setup, with a pair of i2S microphones, (ICS43434):
- Mac OS 10.15 - iMac, 3.4 GHz Quad-Core Intel Core i5 - success
- Mac OS 12.5 - Macbook Pro, 2.2 GHz Quad-Code Intel Core i7 - success
- Linux, Raspberry Pi OS 64bit Lite (Linux kernel 5.18.19), RaspberryPi Model 3A,

I can't tell you how pleased I am to get this working on the Raspberry Pi (I've been struggling to get multi channel audio to work on the Pi while keeping it physically light). I'm going to get myself 6 more i2S mics so I can test the full 8 channels.
 
That's great to hear! Thanks for helping us grow the set of successfully tested USB hosts. Wishing you lots of success with your projects.
 
Back
Top