Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(usb): Prepare embassy-usb for USB Audio, and add USB Audio Class 1.0 (playback only) #3212

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

elagil
Copy link
Contributor

@elagil elagil commented Jul 26, 2024

Hello,

I implemented a UAC 1.0 device, but this required some extensions and fixes to the implementation of embassy-usb.
Some changes are taken from or inspired by #2736.

Here is an example of where this is in use (still rough): https://github.com/blus-audio/firmware-rs
The feedback endpoint is not yet in use.

Features:

  • Added usage type and synchronization type settings for endpoints. This is only relevant for isochronous endpoints.
  • Added extra_fields that can be appended to an endpoint descriptor. This is required for UAC (e.g. bRefresh and bSynchAddress fields for UAC1.0)
  • Added functionality for allocating endpoints and writing their descriptors separately. This is required, because in UAC1.0, the synch endpoint must follow the audio streaming endpoint, but the descriptor of the latter must contain the endpoint index of the former. So I allocate the endpoints first, then write the descriptors with the information about the endpoints. Find an implementation of that approach here: https://github.com/blus-audio/firmware-rs/blob/main/firmware/src/uac1/mod.rs#L223

Fixes:

  • Set correct even/odd frame bit for isochronous endpoints. Otherwise, half of the packets are lost.
  • Consistent naming of register setters

@kalkyl
Copy link
Contributor

kalkyl commented Jul 26, 2024

Awesome!
Run cargo +nightly fmt to fix CI

Do you have a basic usage example to include?

@elagil
Copy link
Contributor Author

elagil commented Jul 26, 2024

Thanks! I just fixed formatting.

I could add an example for the STM32H7, because I can test that.
In my case, I stream USB->SAI->DAC.

However, such an example would still be a bit useless without explicit feedback. There will be jumps in the audio due to the rate discrepancies of SAI output and USB input. Measuring the value that has to be provided over the feedback endpoint is hardware dependent.

I will try to make something useful.

@elagil
Copy link
Contributor Author

elagil commented Jul 26, 2024

I guess I have to do this first, in order to create an example: embassy-rs/stm32-data#509

Maybe some details for the reasoning:
The fix allows v2 timers to trigger on the USB_SOF signal, which will be used for measuring the feedback value.
The feedback value expresses, how many samples were consumed by the audio device between two USB_SOF interrupts. It thus relates the rate of sample consumption to the rate at which input samples are provided. The feedback value is sent to the host, in order for it to adjust the rate at which it sends samples. It can be thought of as a control loop, where the USB audio device is the sensor.

@elagil elagil changed the title feat(usb): Prepare embassy-usb for USB Audio feat(usb): Prepare embassy-usb for USB Audio, and add USB Audio Class 1.0 (playback only) Jul 29, 2024
@elagil elagil marked this pull request as draft July 29, 2024 15:25
@elagil elagil force-pushed the feat_usb_prepare_for_uac branch 2 times, most recently from 1190b76 to 42905b2 Compare August 24, 2024 17:58
@elagil elagil marked this pull request as ready for review August 24, 2024 17:58
@elagil
Copy link
Contributor Author

elagil commented Aug 24, 2024

This should now be ready for review. You can go through the commits one-by-one:

  • Preparation of embassy-usb for USB audio
  • Implementation of UAC1
  • An example, based on STM32F4

The class is meant to be extended by more "applications" in the future. I implemented only a "speaker" application, where the device receives audio from the host. It has the following features:

  • Volume control
  • Mute control
  • Selectable sample rate
  • Selectable sample width
  • Implementation of the sample rate feedback mechanism (see example for details)
  • Separate streaming, control, and feedback instances

Disclaimer: I did not test the example on the STM32F4 platform, because I don't have that hardware. I only tested on my STM32H723, which does not exist as an example platform, and I feel like it makes more sense to use the more common F4.

Can someone please test it? For example, print the measured feedback value (in the usb_feedback_task) and received sample lengths (in the audio_receiver_task). Ideally, stream over SAI and play some music ;)

@elagil
Copy link
Contributor Author

elagil commented Sep 5, 2024

ISO endpoint support itself in the USB drivers was split off to #3314.

Therefore, this depends on the other PR and does not build without it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants