usbaudio: convert to asynchronous operation

Add feedback not based on samples used, but on buffers filled - idea
being we can do "PID" (someone who has actually implemented Real PID
could probably rewrite the calculation) based on how many buffers
we have filled versus the ideal buffer filled level (16).

Feedback is based on a historical average of the last two feedback
intervals.

This feedback math is done as fixed-point math to keep floats out of core. Note that a couple division operations needed to be strategically staged to avoid overflow or truncation.

Floats are still used for debug screen printout.

Also fixed a typo in the definition of usb_audio_control_request()

Host:
Linux: works
MacOS: works
Windows: Feedback does not work! It appears that Windows may not
         support asynchronous devices at all. Playback may "work",
         but results will vary as the number of buffers filled will
         drift over time.

Change-Id: I027feb16705e6e46c1144b1d08920b53de42cb26
This commit is contained in:
Dana Conrad 2025-10-08 00:37:33 +00:00
parent 9ce66e088e
commit 7c4293af64
5 changed files with 439 additions and 65 deletions

View file

@ -21,6 +21,14 @@
#include "usb_ch9.h"
/* NOTE
*
* This is USBAudio 1.0. USBAudio 2.0 is notably _not backwards compatible!_
* USBAudio 1.0 over _USB_ 2.0 is perfectly valid!
*
* Relevant specifications are USB 2.0 and USB Audio Class 1.0.
*/
/*
* usb_audio_request_endpoints():
*
@ -178,6 +186,28 @@ int usb_audio_get_main_intf(void);
*/
int usb_audio_get_alt_intf(void);
/*
* usb_audio_get_samplesperframe():
*
* Return the samples per frame over the last two feedback cycles
* This is the samples sent to the mixer.
*
* This is returned in floating point 16.16 type. To convert to float,
* do ((double)result / (1<<16))
*/
int32_t usb_audio_get_samplesperframe(void);
/*
* usb_audio_get_samplesperframe():
*
* Return the samples per frame over the last two feedback cycles
* This is the samples received from USB.
*
* This is returned in floating point 16.16 type. To convert to float,
* do ((double)result / (1<<16))
*/
int32_t usb_audio_get_samples_rx_perframe(void);
/*
* usb_audio_get_out_ep():
*
@ -199,6 +229,25 @@ unsigned int usb_audio_get_in_ep(void);
*/
int usb_audio_get_prebuffering(void);
/*
* usb_audio_get_prebuffering_avg():
*
* Return the average number of buffers filled ahead of playback
* over the last two feedback cycles
*
* This is returned in floating point 16.16 type. To convert to float,
* do ((double)result / (1<<16))
*/
int32_t usb_audio_get_prebuffering_avg(void);
/*
* usb_audio_get_prebuffering_maxmin():
*
* Return the max or min number of buffers filled ahead of playback
* over the last feedback cycle
*/
int usb_audio_get_prebuffering_maxmin(bool max);
/*
* usb_audio_get_underflow():
*
@ -213,6 +262,13 @@ bool usb_audio_get_underflow(void);
*/
bool usb_audio_get_overflow(void);
/*
* usb_audio_get_frames_dropped():
*
* Return the number of frames which have been dropped during playback
*/
int usb_audio_get_frames_dropped(void);
/*
* usb_audio_get_cur_volume():
*