From afc59caf36c83decaf7978497559063879eddd49 Mon Sep 17 00:00:00 2001 From: Dave Lacey Date: Mon, 4 Apr 2011 16:52:42 +0100 Subject: [PATCH] Made prefill levels vary with sample rate and usb speed --- module_usb_aud_shared/usb_buffer/decouple.xc | 84 +++++++++++++++++--- 1 file changed, 75 insertions(+), 9 deletions(-) diff --git a/module_usb_aud_shared/usb_buffer/decouple.xc b/module_usb_aud_shared/usb_buffer/decouple.xc index 9e9640d0..21c59931 100644 --- a/module_usb_aud_shared/usb_buffer/decouple.xc +++ b/module_usb_aud_shared/usb_buffer/decouple.xc @@ -58,11 +58,8 @@ inline void XUD_Change_ReadyIn_Buffer(XUD_ep e, unsigned bufferPtr, int len) #define BUFF_SIZE_OUT MAX(4 * CLASS_TWO_PACKET_SIZE * NUM_USB_CHAN_OUT, 4 * CLASS_ONE_PACKET_SIZE * MAX_CLASS_ONE_CHAN) #define BUFF_SIZE_IN MAX(4 * CLASS_TWO_PACKET_SIZE * NUM_USB_CHAN_IN, 4 * CLASS_ONE_PACKET_SIZE * MAX_CLASS_ONE_CHAN) #define MAX_USB_AUD_PACKET_SIZE 1028 -//#define OUT_BUFFER_PREFILL (2*4*BUFF_SIZE_OUT/3) -//#define OUT_BUFFER_PREFILL MAX(CLASS_ONE_PACKET_SIZE*3+4,CLASS_TWO_PACKET_SIZE*4+4)*2 -//#define IN_BUFFER_PREFILL MAX(CLASS_ONE_PACKET_SIZE*3+4,CLASS_TWO_PACKET_SIZE*4+4)*2 -#define OUT_BUFFER_PREFILL (MAX(MAX_CLASS_ONE_CHAN*CLASS_ONE_PACKET_SIZE*3+4,NUM_USB_CHAN_OUT*CLASS_TWO_PACKET_SIZE*4+4)*1) -#define IN_BUFFER_PREFILL (MAX(CLASS_ONE_PACKET_SIZE*3+4,CLASS_TWO_PACKET_SIZE*4+4)*2) +#define NUM_PACKETS_PREFILL (1) + //#pragma xta command "add exclusion out_underflow" //#pragma xta command "add exclusion freq_change" //#pragma xta command "add exclusion print_err"is_as @@ -93,6 +90,9 @@ unsigned audioBuffIn[BUFF_SIZE_IN + (MAX_DEVICE_AUD_PACKET_SIZE>>2) + 4]; unsigned inZeroBuff[(MAX_DEVICE_AUD_PACKET_SIZE>>2)+4]; +unsigned g_in_buffer_prefill = 0; +unsigned g_out_buffer_prefill = 0; + unsigned ledVal = 1; unsigned dir = 0; @@ -139,6 +139,42 @@ void led(chanend ?c_led) void GetADCCounts(unsigned samFreq, int &min, int &mid, int &max); + + +/* This function sets the prefill levels for the in and out buffers, + it needs to be changed for a different sample rate or number of channels. + The amount set here is what determines the latency of the buffering. +*/ +static void set_prefills(unsigned int sampFreq) { + int min,mid,max; + int usb_speed; + unsigned prefill; + int bytes_per_sample; + int num_channels; + int frame; + int packet_size; + GET_SHARED_GLOBAL(usb_speed, g_curUsbSpeed); + + frame = usb_speed == XUD_SPEED_HS ? 8000 : 1000; + packet_size = ((((sampFreq+frame-1)/frame))+3); + + + bytes_per_sample = usb_speed == XUD_SPEED_HS ? 4 : 3; + + GET_SHARED_GLOBAL(num_channels, g_numUsbChanOut); + prefill = ((packet_size * num_channels * bytes_per_sample + 4) * NUM_PACKETS_PREFILL); + SET_SHARED_GLOBAL(g_out_buffer_prefill, prefill); + + GET_SHARED_GLOBAL(num_channels, g_numUsbChanIn); + prefill = ((packet_size * num_channels * bytes_per_sample + 4) * NUM_PACKETS_PREFILL); + SET_SHARED_GLOBAL(g_in_buffer_prefill, prefill); + return; +} + + + + + static inline void swap(xc_ptr &a, xc_ptr &b) { xc_ptr tmp; @@ -283,6 +319,15 @@ void handle_audio_request(chanend c_mix_out, chanend ?c_led) if (space_left > (BUFF_SIZE_IN*4/2)) { inOverflow = 0; + // When we come out of overflow we clear the buffer and + // go into underflow and do a prefill again - this is to + // get a low latency and to ensure consistency between + // coming out of underflow or overflow + inUnderflow = 1; + SET_SHARED_GLOBAL(g_aud_to_host_rdptr, + aud_to_host_fifo_start); + SET_SHARED_GLOBAL(g_aud_to_host_wrptr, + aud_to_host_fifo_start); } } else @@ -370,6 +415,7 @@ void handle_audio_request(chanend c_mix_out, chanend ?c_led) if(outUnderflow) { + unsigned prefill; #pragma xta endpoint "out_underflow" /* We're still pre-buffering, send out 0 samps */ for(int i = 0; i < NUM_USB_CHAN_OUT; i++) @@ -384,8 +430,9 @@ void handle_audio_request(chanend c_mix_out, chanend ?c_led) outSamps += BUFF_SIZE_OUT*4; } + GET_SHARED_GLOBAL(prefill, g_out_buffer_prefill); /* If we have a decent number of samples, come out of underflow cond */ - if (outSamps >= (OUT_BUFFER_PREFILL)) + if (outSamps >= prefill) { outUnderflow = 0; } @@ -799,6 +846,8 @@ void decouple(chanend c_mix_out, } #endif + set_prefills(sampFreq); + while(1) { if (!isnull(c_clk_int)) @@ -854,13 +903,14 @@ void decouple(chanend c_mix_out, SET_SHARED_GLOBAL(g_aud_from_host_rdptr, aud_from_host_fifo_start); SET_SHARED_GLOBAL(g_aud_from_host_wrptr, aud_from_host_fifo_start); SET_SHARED_GLOBAL(aud_data_remaining_to_device, 0); - /* Wait for handshake back and pass back up */ chkct(c_mix_out, XS1_CT_END); SET_SHARED_GLOBAL(g_freqChange, 0); asm("outct res[%0],%1"::"r"(buffer_aud_ctl_chan),"r"(XS1_CT_END)); + set_prefills(sampFreq); + ENABLE_INTERRUPTS(); speedRem = 0; @@ -883,6 +933,7 @@ void decouple(chanend c_mix_out, SET_SHARED_GLOBAL(g_aud_to_host_buffer, g_aud_to_host_zeros); SET_SHARED_GLOBAL(g_freqChange, 0); + set_prefills(sampFreq); ENABLE_INTERRUPTS(); } } @@ -959,9 +1010,22 @@ void decouple(chanend c_mix_out, if (space_left >= (BUFF_SIZE_OUT*4/2)) { /* Come out of OUT overflow state */ - outOverflow = 0; + DISABLE_INTERRUPTS(); + outOverflow = 0; + // When we come out of overflow we clear the buffer and + // go into underflow and do a prefill again - this is to + // get a low latency and to ensure consistency between + // coming out of underflow or overflow + outUnderflow = 1; + SET_SHARED_GLOBAL(g_aud_from_host_rdptr, + aud_from_host_fifo_start); + SET_SHARED_GLOBAL(g_aud_from_host_wrptr, + aud_from_host_fifo_start); + SET_SHARED_GLOBAL(aud_data_remaining_to_device, 0); + SET_SHARED_GLOBAL(g_aud_from_host_buffer, aud_from_host_wrptr); XUD_SetReady(aud_from_host_usb_ep, 1); + ENABLE_INTERRUPTS(); #ifdef DEBUG_LEDS led(c_led); #endif @@ -988,6 +1052,7 @@ void decouple(chanend c_mix_out, int aud_to_host_wrptr; int aud_to_host_rdptr; int fill_level; + unsigned prefill; GET_SHARED_GLOBAL(aud_to_host_wrptr, g_aud_to_host_wrptr); GET_SHARED_GLOBAL(aud_to_host_rdptr, g_aud_to_host_rdptr); @@ -997,7 +1062,8 @@ void decouple(chanend c_mix_out, if (fill_level < 0) fill_level += BUFF_SIZE_IN*4; - if (fill_level >= IN_BUFFER_PREFILL) + GET_SHARED_GLOBAL(prefill, g_in_buffer_prefill); + if (fill_level >= prefill) { inUnderflow = 0; SET_SHARED_GLOBAL(g_aud_to_host_buffer, aud_to_host_rdptr);