Add stereo support to usb_audio - #11102
Conversation
|
Thanks for working on this! I will test out mono speaker, and try to resolve the issues with microphone. |
|
@mikeysklar Thanks for your work here. I'll make sure to follow your guidelines closely. |
|
@mikeysklar I've updated my code accordingly, and it's looking good. There are still some bugs within this PR which prevents it from being ready to merge at this time. |
|
As an aside, Linus Torvalds appears to have some success with stereo headset operation on his RP2350 guitar pedal: https://github.com/torvalds/GuitarPedal/blob/main/Software/usb-device.c |
fix for usb_audio mono, descriptors, and endpoints
|
I've been writing a guide this week for building a HIL farm. This PR looked like a good way to test the farm's ability. Built 50a1195 for all 8 boards, all build clean. Stereo looks great on RP2040 and RP2350. Sent 1 kHz into left and 3 kHz into right, recorded back on the host:
18000 in, 18000 out. Mono arrives identical on both channels, L==R on 100% of frames. Same through synthio with notes alternating hard left and right. One finding on nRF52840. The combined
The code comment already calls this unsupported on nRF52, but it might be closer than it looks. Tiny separate thing, the docstring example passes The farm, for reference. Eight boards on switchable USB hubs, built and flashed one at a time from the same tree. Versions below are read back off each board's
* Out of curiosity I forced |
The combined microphone+speaker case allocated two sequential endpoint numbers in all cases. On ports that pin isochronous transfers to a dedicated endpoint number (USB_AUDIO_ISO_EP_NUM, currently nRF52) those numbers are not ISO-capable, so the device enumerated with correct descriptors but the stream never opened and no data was transferred. The nRF52 constraint is the endpoint number, not the direction: the USBD has a separate ISOIN and ISOOUT on endpoint 8, and TinyUSB splits the ISO buffer (ISOSPLIT = HalfIN) when both are open. Use the dedicated number for both directions on those ports, and do not consume sequential endpoint numbers, matching what the single-direction branches already do. Sequential-allocation ports are unaffected. Tested on Feather nRF52840 Express: microphone+speaker now enumerates on 0x08/0x88 and streams in both directions at once, verified by recording and playing simultaneously. Metro RP2040 unchanged on 0x06/0x87 with identical capture results.
|
Had a look at that nRF52840 headset case and it turns out to be a small fix, so I opened relic-se#2 against your branch. Both directions can share endpoint 8. The constraint there is the endpoint number, not the direction, and TinyUSB splits the ISO buffer when ISOIN and ISOOUT are both open. |
Support usb_audio headset on ports with a dedicated ISO endpoint (nRF52840)
|
Thank you for your extensive testing and subsequent fix, @mikeysklar . I don't have an nRF52840 board to test this myself, but I trust your review. It seems that we've limited this functionality to RP2xxx and nRF52840, but it would be interesting to see it extended to other platforms in the future, namely ESP32-S3 and M4/M7 as you've suggested.
As listed in the notes of the original description, this PR removes that argument. Good catch with those docstrings. I've updated them to remove that argument. But tbh, I'm still on the fence as to whether or not to include this argument. 😆 |
|
Retested at I'd leave out the bit setting argument. It implies a bit setting other than 16-bit can be set (which it cannot be today). So no changes needed on that. I'll look into getting ESP32-S3 going. |
|
Spent some time on ESP32-S3 today and it looks promising, but I would not hold this PR for it. It enumerates as a proper UAC2 device with a valid stereo descriptor and the isochronous endpoint opens, but getting audio actually flowing looks like it will need both tinyusb and CircuitPython patches, none of it in This one looks done.
|
Updates USB Audio device descriptors to assume stereo operation. Mono operation (
channel_count=1) is still supported although the device will enumerate as stereo.Example Code
boot.py
code.py
Notes
bits_per_sampleargument is removed fromusb_audio.enable(...)since it is always assumed to be 16. (open to input here)For operation on most devices,Only uses 2 endpoints when in mono or stereo bidirectional mode which is consistent with previous operation.usb_hid(and potentiallyusb_midi) will need to be disabled to avoid reaching the limit of USB endpoint pairs when operating in bidirectional mode.In Progress
Mono output throughusb_microphoneresults in random noise.Mono input throughusb_speakerresults in distorted audio.Bidirectional operation is somewhat functional, but an issue with the device descriptor is causing distortion withusb_speaker. Stereousb_microphoneoperates correctly.For interest: @FoamyGuy