I think part of the problem is that because "feedback_accumulator" is cumulative, it gets so out of whack that it never quite recovers. Perhaps resetting it at some point might help. I'm not sure where or how.
Still, after reading the USB Spec section 5.10.4.2 covering feedback, if I am interpreting the jargon correctly, I think a modified approach might be better.
Allow me to give my understanding of the process, and please correct me if I am wrong, followed by code suggestions. It's not prefect, but it does get rid of the stuttering.
USB says feedback is:
desired data rate (Ff) is, relative to the USB SOF frequency
So the number is based on the rate that SOF packets are received (approx 1 SOF every 1 ms) and not how far behind or ahead we are in terms of audio data received, although the two are related. But once you fall behind, it doesn't much matter how far behind because you can't make up lost packets.
Anyway, the formula is:
feedback = cpu_ticks_per_sof * usb_samples_per_sec / cpu_ticks_per_sec
Roughly, this number is 44.1 (sample rate of 44100 Hz). Because this is not a round number, we expect the computer to send back about 9 packets of 44 samples followed by 1 packet of 45, repeating this pattern.
That's my understanding. But that's hard to translate this into code.
Because of this, as a method for calculating feedback, I suggest we keep track of the rate at which the data is actually received and compare it to our desired rate of consumption based of F_CPU and MCLK_*. If too slow, add a little to feedback; if too fast, subtract a little bit. I keep track of the data rate by counting bytes and packets between requests for feedback.
Now, the code suggestions:
The first thing is to get the rate as close to 44100 Hz as possible by implementing @donturner's patch:
https://github.com/dturner/Audio/commit/77ee3c3c0548ede9cb92472532b7dbf4cbed7b1c, the relevant section for Teensy 3.2 is a change to output_i2s.cpp:
Code:
// MCLK needs to be 48e6 / 1088 * 256 = 11.29411765 MHz -> 44.117647 kHz sample rate
//
#if F_CPU == 96000000 || F_CPU == 48000000 || F_CPU == 24000000
// PLL is at 96 MHz in these modes
// patch from https://github.com/dturner/Audio/commit/77ee3c3c0548ede9cb92472532b7dbf4cbed7b1c
#define MCLK_MULT 147
#define MCLK_DIV 1250
//#define MCLK_MULT 2
//#define MCLK_DIV 17
Next, add some variables to keep track of data rates in usb_audio.cpp:
Code:
uint32_t usb_audio_sync_feedback DMABUFATTR;
+ uint32_t usb_aduio_sync_count;
+ uint32_t usb_aduio_sync_count_pkt;
+
uint8_t usb_audio_receive_setting=0;
In usb_audio_receive_callback(), add code to keep counts; these counts are reset by the feedback calculation code:
Code:
len >>= 2; // 1 sample = 4 bytes: 2 left, 2 right
data = (const uint32_t *)usb_audio_receive_buffer;
+ usb_aduio_sync_count += len;
+ usb_aduio_sync_count_pkt++;
+
count = AudioInputUSB::incoming_count;
left = AudioInputUSB::incoming_left;
right = AudioInputUSB::incoming_right;
Remove setting usb_audio_sync_feedback:
Code:
if (f) {
int diff = AUDIO_BLOCK_SAMPLES/2 - (int)c;
feedback_accumulator += diff / 3;
! // uint32_t feedback = (feedback_accumulator >> 8) + diff * 100;
#ifdef MACOSX_ADAPTIVE_LIMIT
if (feedback > 722698) feedback = 722698;
#endif
! // usb_audio_sync_feedback = feedback;
//if (diff > 0) {
//serial_print(".");
//} else if (diff < 0) {
Next, add to usb_dev.c, the variables we added in usb_audio.cpp:
Code:
extern uint32_t usb_aduio_sync_count;
extern uint32_t usb_aduio_sync_count_pkt;
And the heart of the calculation is performed when feedback is requested in usb_dev.c
Code:
b->addr = usb_audio_receive_buffer;
b->desc = (AUDIO_RX_SIZE << 16) | BDT_OWN;
} else if ((endpoint == AUDIO_SYNC_ENDPOINT-1) && (stat & 0x08)) {
+ // Send back how many samples the computer should send between every SOF packet (which is approx 1ms).
+ // Returned in 10.14 format (hence all the ">> 14" below).
+ // Formula is: cpu_ticks_per_sof * usb_samples_per_sec / cpu_ticks_per_sec
+ // In a perfect world, the answer is 44.1 packets per SOF cycle (or ~722534 in 10.14 format).
+ // But this is not the case because clocks never run precisely in sync.
+ const uint32_t usb_audio_sync_clock = 44100; // Actually: F_CPU * MCLK_MULT / MCLK_DIV / 256;
+ const uint32_t usb_audio_sync_clock_min = (usb_audio_sync_clock << 14) / 1000; // min samples per packet
+ const uint32_t usb_audio_sync_clock_max = ((usb_audio_sync_clock+5) << 14) / 1000; // max samples per packet
+
+ // Get the average number of samples per packet, should be approx 44.1 (in 10.14 format)
+ uint32_t avg_samples_per_packet = (usb_aduio_sync_count << 14) / usb_aduio_sync_count_pkt;
+ // Is it in the range of what we want?
+ if (avg_samples_per_packet < usb_audio_sync_clock_min) { // too low, adjust up
+ usb_audio_sync_feedback += 10;
+ if (usb_audio_sync_feedback > 722698) usb_audio_sync_feedback = 722698;
+ }
+ else if (avg_samples_per_packet > usb_audio_sync_clock_max) { // too high, adjust down
+ usb_audio_sync_feedback -= 10;
+ if (usb_audio_sync_feedback < 722370) usb_audio_sync_feedback = 722370;
+ }
+ usb_aduio_sync_count = usb_aduio_sync_count_pkt = 0; // reset the counts
+
b = (bdt_t *)((uint32_t)b ^ 8);
b->addr = &usb_audio_sync_feedback;
b->desc = (3 << 16) | BDT_OWN;
I hard code the value of "usb_audio_sync_clock" because I don't have access to MCLK_MULT & MCLK_DIV from here.