-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
UAC2 supports interrupt-endpoint for providing control-change notifications to the host #1702
Conversation
…ations to the host
345ad9c
to
f931983
Compare
src/class/audio/audio_device.h
Outdated
@@ -531,7 +541,33 @@ TU_ATTR_WEAK TU_ATTR_FAST_FUNC void tud_audio_feedback_interval_isr(uint8_t func | |||
|
|||
#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP | |||
|
|||
#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN | |||
#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP | |||
// UAC2 §9.6 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your PR !
Which UAC2 document are you using ? In my side Interrupt Data Message
is section 6.1 p129.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That seems to be a mis-paste from my other work on isochronous feedback (§9.6 in USB20 document).
I'll submit another PR soon with improvements for audio feedback which should reduce code size, and add (verified) support for FIFO-based feedback.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reference fixed
Also, to get this (and feedback) working on my STM32H7 board, I also had to use this patch (for enabling SOF interrupt): This is with the st/synopsys port. |
src/class/audio/audio_device.c
Outdated
while (p_desc < p_desc_end) | ||
{ | ||
// Find correct interface | ||
if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const * )p_desc)->bInterfaceNumber == 0 && ((tusb_desc_interface_t const * )p_desc)->bAlternateSetting == 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah sorry, this is leftover from when I initially hacked it together for my specific project. I'll generalise that soon.
Also, since there are several places where we sequentially search the descriptors for some specific descriptor, should I create a separate function for doing that, which takes a predicate as an argument?
It should reduce code-size a bit while not burning a significant amount of extra cycles as a result.
And the CPU overhead shouldn't matter much anyway since this is set-up stuff rather than "in the loop" stuff.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, since there are several places where we sequentially search the descriptors for some specific descriptor, should I create a separate function for doing that, which takes a predicate as an argument?
I think there is no need to do it now, later we can generalize them with a function like tu_desc_search()
if needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True, this number can be any interface number!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You may also skip that check since you already work on the descriptor corresponding to the right interrupt EP. Do we need to remember which INT EP corresponds to which interface? For sending messages via INT EP?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
Thanks a lot! Indeed the interrupt EP was not implemented correctly! Since you are the first one who needs it, i am glad you fix the issues! |
INT_CTR to INT refactor done |
Thanks a lot and sorry for the late reply! I have but a few questions on this:
|
The buffer within the tinyusb audio device structure was there already when I started this work - I have no idea if it's required or if we can bypass it. My board + build system are quite custom so I can't easily extract an example out or test an example project. Here's the relevant code though for using this feature. I have a buffer containing three pre-determined messages, which I send incrementally when the audio controls have changed (which can happen by user using physical controls, or me testing via serial interface, or by the USB host setting parameters via existing tinyusb functionality). usb.c (implementations of tinyusb event handlers and tinyusb basics)
usb_control_status.c (manages notifying host about control changes)
|
Almost forgot, relevant part of descriptor. Goes in control-interface part of descriptor, i.e. before any of the streaming interfaces/alternates. descriptor
|
Project-specific implementation details in my case: Basically - each thing that cares about the audio controls has a value in a
There's an array of observer flags ( Whenever a control value changes (i.e. This way, whenever anything changes audio parameters, all observers get to know about it whenever they next poll during their update, and they can handle it each their own way. Probably over-complicated for a basic demo, where you could probably just have a single boolean flag. |
Looks like your CI failure for the RP2040 build could be fixed in this PR #1716 |
@maxsimmonds1337 Info is here if you fancy building an example/demo. |
Perfect, thanks @battlesnake |
Has anyone got this working? I've attempted to reconcile these changes with the version of tinyusb used by Pico SDK, but at best nothing happens and at worst I can reliably crash my board. This happens when I attempt to adjust the volume from the host after calling There's an awful work in progress mess here: Gadgetoid/pico-tinyusb-i2s-speaker@84c127f This doesn't show my futile modifications to tinyusb, which mostly involve trying to set |
I can take a look later, but there are too much pending changes in UAC class not merged yet... |
Thank you!
😬 I guess I'm going to have some fixes to do in future! |
2c8bc03
to
2defcfd
Compare
2defcfd
to
6cf2798
Compare
@battlesnake @Gadgetoid Sorry for the extra long delay, finally I reviewed the changes and it's ready to merge:
|
Requires upstream changes to tinyusb, see here: hathach/tinyusb#1702
Requires upstream changes to tinyusb, see here: hathach/tinyusb#1702
Looks like three weeks since I bumped it, that's a fast turnaround IMO and it's hugely appreciated! (We'll pretend the PR isn't years old because something something glass houses and stones 😬) I have updated my code and replaced the tinyusb submodule in my local clone of pico-sdk. Everything works as I'd expect with our RP2040-based design. Including mute/unmute. Full changeset on my not-actually-a-headset-but-two-speakers codebase here: Gadgetoid/pico-tinyusb-i2s-speaker@6032314 Tested on RP2040, macOS (Ventura) and Linux (Raspberry Pi OS bookworm, 6.6.20+rpt-rpi-2712). 🥳 Thanks, both, for making audio on the Pico just that little bit slicker. |
Hooray! I can switch back to mainline for my audio projects, instead of using my fork :D This PR should hopefully bring in 2-way sync between device and host for control values. Sometime I'll try to add support to the Linux UAC2 driver for multi-band equaliser controls too, which it currently seems to totally lack. |
Relates to issue #1697
Describe the PR
UAC2 supports an interrupt endpoint to provide notifications to the host about control changes (e.g. mute button pressed on the device).
The interrupt endpoint lives in the control interface, and transmits 6-byte messages to notify the host about control values changing.
The host may then decide to issue a get-entity request via the control endpoint in order to read the new control value.
These interrupts can notify about changes to endpoints, interfaces, entities/controls, and also provide vendor-specific notifications.
The implementation of this functionality in TinyUSB was incomplete.
I have tested this on a custom board using STM32H7 and no RTOS.
On Linux, I see ALSAMIXER's UI controls on the host PC change, when I interact with the physical controls on the device.
I'm not too familiar with the coding style or architecture for TinyUSB, so please give suggestions on making this PR conform with the existing style.
This PR also includes the fix from #1698, where compilation was failing (when interrupt-endpoint enabled) due to a "section" attribute being applied to a member within a struct.
Additional context