Track decouple fill level instead of (incorrect) buffer space left

This commit is contained in:
Daniel Pieczko
2022-09-27 15:16:47 +01:00
parent ff6547b75c
commit 30cb913519

View File

@@ -100,7 +100,6 @@ XUD_ep aud_to_host_usb_ep = 0;
/* Shared global audio buffering variables */ /* Shared global audio buffering variables */
unsigned g_aud_from_host_buffer; unsigned g_aud_from_host_buffer;
unsigned g_aud_to_host_buffer;
unsigned g_aud_to_host_flag = 0; unsigned g_aud_to_host_flag = 0;
int buffer_aud_ctl_chan = 0; int buffer_aud_ctl_chan = 0;
unsigned g_aud_from_host_flag = 0; unsigned g_aud_from_host_flag = 0;
@@ -126,7 +125,7 @@ xc_ptr aud_to_host_fifo_end;
xc_ptr g_aud_to_host_wrptr; xc_ptr g_aud_to_host_wrptr;
xc_ptr g_aud_to_host_dptr; xc_ptr g_aud_to_host_dptr;
xc_ptr g_aud_to_host_rdptr; xc_ptr g_aud_to_host_rdptr;
xc_ptr g_aud_to_host_zeros; int g_aud_to_host_fill_level;
int aud_data_remaining_to_device = 0; int aud_data_remaining_to_device = 0;
@@ -150,7 +149,6 @@ unsigned packData = 0;
#pragma unsafe arrays #pragma unsafe arrays
void handle_audio_request(chanend c_mix_out) void handle_audio_request(chanend c_mix_out)
{ {
int space_left;
#if(defined XUA_USB_DESCRIPTOR_OVERWRITE_RATE_RES) #if(defined XUA_USB_DESCRIPTOR_OVERWRITE_RATE_RES)
#error #error
g_curSubSlot_Out = get_usb_to_device_bit_res() >> 3; g_curSubSlot_Out = get_usb_to_device_bit_res() >> 3;
@@ -323,6 +321,9 @@ __builtin_unreachable();
#endif #endif
{ {
int dPtr;
GET_SHARED_GLOBAL(dPtr, g_aud_to_host_dptr);
/* Store samples from mixer into sample buffer */ /* Store samples from mixer into sample buffer */
switch(g_curSubSlot_In) switch(g_curSubSlot_In)
{ {
@@ -349,8 +350,8 @@ __builtin_unreachable();
sample = sample << 3; sample = sample << 3;
#endif #endif
#endif #endif
write_short_via_xc_ptr(g_aud_to_host_dptr, sample>>16); write_short_via_xc_ptr(dPtr, sample>>16);
g_aud_to_host_dptr+=2; dPtr+=2;
} }
break; break;
@@ -359,7 +360,6 @@ __builtin_unreachable();
#if (STREAM_FORMAT_INPUT_SUBSLOT_4_USED == 0) #if (STREAM_FORMAT_INPUT_SUBSLOT_4_USED == 0)
__builtin_unreachable(); __builtin_unreachable();
#endif #endif
unsigned ptr = g_aud_to_host_dptr;
for(int i = 0; i < g_numUsbChan_In; i++) for(int i = 0; i < g_numUsbChan_In; i++)
{ {
@@ -382,13 +382,10 @@ __builtin_unreachable();
#endif #endif
#endif #endif
/* Write into fifo */ /* Write into fifo */
write_via_xc_ptr(ptr, sample); write_via_xc_ptr(dPtr, sample);
ptr+=4; dPtr+=4;
} }
/* Update global pointer */
g_aud_to_host_dptr = ptr;
break; break;
} }
@@ -417,21 +414,21 @@ __builtin_unreachable();
break; break;
case 1: case 1:
packData = (packData >> 8) | ((sample & 0xff00)<<16); packData = (packData >> 8) | ((sample & 0xff00)<<16);
write_via_xc_ptr(g_aud_to_host_dptr, packData); write_via_xc_ptr(dPtr, packData);
g_aud_to_host_dptr+=4; dPtr+=4;
write_via_xc_ptr(g_aud_to_host_dptr, sample>>16); write_via_xc_ptr(dPtr, sample>>16);
packData = sample; packData = sample;
break; break;
case 2: case 2:
packData = (packData>>16) | ((sample & 0xffff00) << 8); packData = (packData>>16) | ((sample & 0xffff00) << 8);
write_via_xc_ptr(g_aud_to_host_dptr, packData); write_via_xc_ptr(dPtr, packData);
g_aud_to_host_dptr+=4; dPtr+=4;
packData = sample; packData = sample;
break; break;
case 3: case 3:
packData = (packData >> 24) | (sample & 0xffffff00); packData = (packData >> 24) | (sample & 0xffffff00);
write_via_xc_ptr(g_aud_to_host_dptr, packData); write_via_xc_ptr(dPtr, packData);
g_aud_to_host_dptr+=4; dPtr+=4;
break; break;
} }
packState++; packState++;
@@ -443,6 +440,8 @@ __builtin_unreachable();
break; break;
} }
SET_SHARED_GLOBAL(g_aud_to_host_dptr, dPtr);
/* Input any remaining channels - past this thread we always operate on max channel count */ /* Input any remaining channels - past this thread we always operate on max channel count */
for(int i = 0; i < NUM_USB_CHAN_IN - g_numUsbChan_In; i++) for(int i = 0; i < NUM_USB_CHAN_IN - g_numUsbChan_In; i++)
{ {
@@ -457,27 +456,35 @@ __builtin_unreachable();
/* Total samps to write could start at 0 (i.e. no MCLK) so need to check for < 0) */ /* Total samps to write could start at 0 (i.e. no MCLK) so need to check for < 0) */
if (sampsToWrite <= 0) if (sampsToWrite <= 0)
{ {
int speed; int speed, wrPtr;
packState = 0; packState = 0;
/* Write last packet length into FIFO */ /* Write last packet length into FIFO */
int datasize = totalSampsToWrite * g_curSubSlot_In * g_numUsbChan_In; int datasize = totalSampsToWrite * g_curSubSlot_In * g_numUsbChan_In;
write_via_xc_ptr(g_aud_to_host_wrptr, datasize); GET_SHARED_GLOBAL(wrPtr, g_aud_to_host_wrptr);
write_via_xc_ptr(wrPtr, datasize);
/* Round up to nearest word - note, not needed for slotsize == 4! */ /* Round up to nearest word - note, not needed for slotsize == 4! */
datasize = (datasize+3) & (~0x3); datasize = (datasize+3) & (~0x3);
assert(datasize >= 0);
assert(datasize <= g_maxPacketSize);
/* Move wr ptr on by old packet length */ /* Move wr ptr on by old packet length */
g_aud_to_host_wrptr += 4+datasize; wrPtr += 4+datasize;
int fillLevel;
GET_SHARED_GLOBAL(fillLevel, g_aud_to_host_fill_level);
fillLevel += 4+datasize;
assert(fillLevel <= BUFF_SIZE_IN);
/* Do wrap */ /* Do wrap */
if (g_aud_to_host_wrptr >= aud_to_host_fifo_end) if (wrPtr >= aud_to_host_fifo_end)
{ {
g_aud_to_host_wrptr = aud_to_host_fifo_start; wrPtr = aud_to_host_fifo_start;
} }
g_aud_to_host_dptr = g_aud_to_host_wrptr + 4; SET_SHARED_GLOBAL(g_aud_to_host_wrptr, wrPtr);
SET_SHARED_GLOBAL(g_aud_to_host_dptr, wrPtr + 4);
/* Now calculate new packet length... /* Now calculate new packet length...
* First get feedback val (ideally this would be syncronised) * First get feedback val (ideally this would be syncronised)
@@ -497,18 +504,10 @@ __builtin_unreachable();
totalSampsToWrite = 0; totalSampsToWrite = 0;
} }
/* Calc slots left in fifo */ /* Must allow space for at least one sample per channel, as these are written at the beginning of
space_left = g_aud_to_host_rdptr - g_aud_to_host_wrptr; * the interrupt handler even if totalSampsToWrite is zero (will be overwritten by a later packet). */
int spaceRequired = MAX(totalSampsToWrite, 1) * g_numUsbChan_In * g_curSubSlot_In + 4;
/* Mod and special case */ if (spaceRequired > BUFF_SIZE_IN - fillLevel)
if ((space_left <= 0) && (g_aud_to_host_rdptr == aud_to_host_fifo_start))
{
space_left = aud_to_host_fifo_end - g_aud_to_host_wrptr;
}
assert(space_left > 0 && msg("space_left expected to be positive"));
if((space_left < (totalSampsToWrite * g_numUsbChan_In * (unsigned) g_curSubSlot_In + 4)))
{ {
/* In pipe has filled its buffer - we need to overflow /* In pipe has filled its buffer - we need to overflow
* Accept the packet, and throw away the oldest in the buffer */ * Accept the packet, and throw away the oldest in the buffer */
@@ -518,36 +517,40 @@ __builtin_unreachable();
int min, mid, max; int min, mid, max;
GetADCCounts(sampFreq, min, mid, max); GetADCCounts(sampFreq, min, mid, max);
const int max_pkt_size = ((max * g_curSubSlot_In * g_numUsbChan_In + 3) & ~0x3) + 4; const int max_pkt_size = ((max * g_curSubSlot_In * g_numUsbChan_In + 3) & ~0x3) + 4;
int rdPtr;
GET_SHARED_GLOBAL(rdPtr, g_aud_to_host_rdptr);
/* Keep throwing away packets until buffer contains two packets */ /* Keep throwing away packets until buffer contains two packets */
do do
{ {
unsigned rdPtr; int wrPtr;
GET_SHARED_GLOBAL(wrPtr, g_aud_to_host_wrptr);
/* Read length of packet in buffer at read pointer */ /* Read length of packet in buffer at read pointer */
int datalength; int datalength;
GET_SHARED_GLOBAL(rdPtr, g_aud_to_host_rdptr);
asm volatile("ldw %0, %1[0]":"=r"(datalength):"r"(rdPtr)); asm volatile("ldw %0, %1[0]":"=r"(datalength):"r"(rdPtr));
/* Round up datalength */ /* Round up datalength */
datalength = ((datalength+3) & ~0x3) + 4; datalength = ((datalength+3) & ~0x3) + 4;
assert(datalength >= 4);
assert(fillLevel >= datalength);
/* Move read pointer on by length */ /* Move read pointer on by length */
fillLevel -= datalength;
rdPtr += datalength; rdPtr += datalength;
if (rdPtr >= aud_to_host_fifo_end) if (rdPtr >= aud_to_host_fifo_end)
{ {
rdPtr = aud_to_host_fifo_start; rdPtr = aud_to_host_fifo_start;
} }
space_left += datalength;
SET_SHARED_GLOBAL(g_aud_to_host_rdptr, rdPtr);
assert(rdPtr < aud_to_host_fifo_end && msg("rdPtr must be within buffer")); assert(rdPtr < aud_to_host_fifo_end && msg("rdPtr must be within buffer"));
} while(space_left < (BUFF_SIZE_IN - 2 * max_pkt_size)); } while (fillLevel > 2 * max_pkt_size);
SET_SHARED_GLOBAL(g_aud_to_host_rdptr, rdPtr);
} }
SET_SHARED_GLOBAL(g_aud_to_host_fill_level, fillLevel);
sampsToWrite = totalSampsToWrite; sampsToWrite = totalSampsToWrite;
} }
} }
@@ -587,9 +590,10 @@ __builtin_unreachable();
} }
/* Mark Endpoint (IN) ready with an appropriately sized zero buffer */ /* Mark Endpoint (IN) ready with an appropriately sized zero buffer */
static inline void SetupZerosSendBuffer(XUD_ep aud_to_host_usb_ep, unsigned sampFreq, unsigned slotSize) static inline void SetupZerosSendBuffer(XUD_ep aud_to_host_usb_ep, unsigned sampFreq, unsigned slotSize,
xc_ptr aud_to_host_zeros)
{ {
int min, mid, max, p; int min, mid, max;
GetADCCounts(sampFreq, min, mid, max); GetADCCounts(sampFreq, min, mid, max);
/* Set IN stream packet size to something sensible. We expect the buffer to /* Set IN stream packet size to something sensible. We expect the buffer to
@@ -599,7 +603,7 @@ static inline void SetupZerosSendBuffer(XUD_ep aud_to_host_usb_ep, unsigned samp
mid *= g_numUsbChan_In * slotSize; mid *= g_numUsbChan_In * slotSize;
asm volatile("stw %0, %1[0]"::"r"(mid),"r"(g_aud_to_host_zeros)); asm volatile("stw %0, %1[0]"::"r"(mid),"r"(aud_to_host_zeros));
#if XUA_DEBUG_BUFFER #if XUA_DEBUG_BUFFER
printstr("SetupZerosSendBuffer\n"); printstr("SetupZerosSendBuffer\n");
@@ -614,11 +618,7 @@ static inline void SetupZerosSendBuffer(XUD_ep aud_to_host_usb_ep, unsigned samp
/* Mark EP ready with the zero buffer. Note this will simply update the packet size /* Mark EP ready with the zero buffer. Note this will simply update the packet size
* if it is already ready */ * if it is already ready */
/* g_aud_to_host_buffer is already set to g_aud_to_host_zeros */ XUD_SetReady_InPtr(aud_to_host_usb_ep, aud_to_host_zeros+4, mid);
GET_SHARED_GLOBAL(p, g_aud_to_host_buffer);
XUD_SetReady_InPtr(aud_to_host_usb_ep, p+4, mid);
} }
#pragma unsafe arrays #pragma unsafe arrays
@@ -653,18 +653,20 @@ void XUA_Buffer_Decouple(chanend c_mix_out
t = array_to_xc_ptr(audioBuffIn); t = array_to_xc_ptr(audioBuffIn);
int aud_to_host_buffer;
aud_to_host_fifo_start = t; aud_to_host_fifo_start = t;
aud_to_host_fifo_end = aud_to_host_fifo_start + BUFF_SIZE_IN; aud_to_host_fifo_end = aud_to_host_fifo_start + BUFF_SIZE_IN;
g_aud_to_host_wrptr = aud_to_host_fifo_start; SET_SHARED_GLOBAL(g_aud_to_host_wrptr, aud_to_host_fifo_start);
g_aud_to_host_rdptr = aud_to_host_fifo_start; SET_SHARED_GLOBAL(g_aud_to_host_rdptr, aud_to_host_fifo_start);
g_aud_to_host_dptr = aud_to_host_fifo_start + 4; SET_SHARED_GLOBAL(g_aud_to_host_dptr, aud_to_host_fifo_start + 4);
SET_SHARED_GLOBAL(g_aud_to_host_fill_level, 0);
/* Setup pointer to In stream 0 buffer. Note, length will be innited to 0 /* Setup pointer to In stream 0 buffer. Note, length will be innited to 0
* However, this should be over-written on first stream start (assuming host * However, this should be over-written on first stream start (assuming host
properly sends a SetInterface() before streaming. In any case we will send properly sends a SetInterface() before streaming. In any case we will send
0 length packets, which is reasonable behaviour */ 0 length packets, which is reasonable behaviour */
t = array_to_xc_ptr(inZeroBuff); t = array_to_xc_ptr(inZeroBuff);
g_aud_to_host_zeros = t; xc_ptr aud_to_host_zeros = t;
/* Init vol mult tables */ /* Init vol mult tables */
#if !defined(OUT_VOLUME_IN_MIXER) && (OUTPUT_VOLUME_CONTROL == 1) #if !defined(OUT_VOLUME_IN_MIXER) && (OUTPUT_VOLUME_CONTROL == 1)
@@ -716,8 +718,7 @@ void XUA_Buffer_Decouple(chanend c_mix_out
#if (AUDIO_CLASS == 1) #if (AUDIO_CLASS == 1)
/* For UAC1 we know we only run at FS */ /* For UAC1 we know we only run at FS */
/* Set buffer back to zeros buffer */ /* Set buffer back to zeros buffer */
SET_SHARED_GLOBAL(g_aud_to_host_buffer, g_aud_to_host_zeros); SetupZerosSendBuffer(aud_to_host_usb_ep, sampFreq, g_curSubSlot_In, aud_to_host_zeros);
SetupZerosSendBuffer(aud_to_host_usb_ep, sampFreq, g_curSubSlot_In);
#endif #endif
#endif #endif
@@ -755,12 +756,13 @@ void XUA_Buffer_Decouple(chanend c_mix_out
SET_SHARED_GLOBAL(g_aud_to_host_rdptr, aud_to_host_fifo_start); 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); SET_SHARED_GLOBAL(g_aud_to_host_wrptr, aud_to_host_fifo_start);
SET_SHARED_GLOBAL(g_aud_to_host_dptr,aud_to_host_fifo_start+4); SET_SHARED_GLOBAL(g_aud_to_host_dptr,aud_to_host_fifo_start+4);
SET_SHARED_GLOBAL(g_aud_to_host_fill_level, 0);
/* Set buffer to send back to zeros buffer */ /* Set buffer to send back to zeros buffer */
SET_SHARED_GLOBAL(g_aud_to_host_buffer, g_aud_to_host_zeros); aud_to_host_buffer = aud_to_host_zeros;
/* Update size of zeros buffer (and sampsToWrite) */ /* Update size of zeros buffer (and sampsToWrite) */
SetupZerosSendBuffer(aud_to_host_usb_ep, sampFreq, g_curSubSlot_In); SetupZerosSendBuffer(aud_to_host_usb_ep, sampFreq, g_curSubSlot_In, aud_to_host_zeros);
/* Reset OUT buffer state */ /* Reset OUT buffer state */
outUnderflow = 1; outUnderflow = 1;
@@ -809,12 +811,13 @@ void XUA_Buffer_Decouple(chanend c_mix_out
SET_SHARED_GLOBAL(g_aud_to_host_rdptr, aud_to_host_fifo_start); 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); SET_SHARED_GLOBAL(g_aud_to_host_wrptr,aud_to_host_fifo_start);
SET_SHARED_GLOBAL(g_aud_to_host_dptr,aud_to_host_fifo_start+4); SET_SHARED_GLOBAL(g_aud_to_host_dptr,aud_to_host_fifo_start+4);
SET_SHARED_GLOBAL(g_aud_to_host_fill_level, 0);
/* Set buffer back to zeros buffer */ /* Set buffer back to zeros buffer */
SET_SHARED_GLOBAL(g_aud_to_host_buffer, g_aud_to_host_zeros); aud_to_host_buffer = aud_to_host_zeros;
/* Update size of zeros buffer (and sampsToWrite) */ /* Update size of zeros buffer (and sampsToWrite) */
SetupZerosSendBuffer(aud_to_host_usb_ep, sampFreq, g_curSubSlot_In); SetupZerosSendBuffer(aud_to_host_usb_ep, sampFreq, g_curSubSlot_In, aud_to_host_zeros);
GET_SHARED_GLOBAL(usbSpeed, g_curUsbSpeed); GET_SHARED_GLOBAL(usbSpeed, g_curUsbSpeed);
if (usbSpeed == XUD_SPEED_HS) if (usbSpeed == XUD_SPEED_HS)
@@ -977,28 +980,26 @@ void XUA_Buffer_Decouple(chanend c_mix_out
/* Reset flag */ /* Reset flag */
SET_SHARED_GLOBAL(g_aud_to_host_flag, 0); SET_SHARED_GLOBAL(g_aud_to_host_flag, 0);
DISABLE_INTERRUPTS();
if (inUnderflow) if (inUnderflow)
{ {
int aud_to_host_wrptr; int fillLevel;
int aud_to_host_rdptr; GET_SHARED_GLOBAL(fillLevel, g_aud_to_host_fill_level);
int fill_level; assert(fillLevel >= 0);
GET_SHARED_GLOBAL(aud_to_host_wrptr, g_aud_to_host_wrptr); assert(fillLevel <= BUFF_SIZE_IN);
GET_SHARED_GLOBAL(aud_to_host_rdptr, g_aud_to_host_rdptr);
/* Check if we have come out of underflow */ /* Check if we have come out of underflow */
fill_level = aud_to_host_wrptr - aud_to_host_rdptr; if (fillLevel >= IN_BUFFER_PREFILL)
if (fill_level < 0)
fill_level += BUFF_SIZE_IN;
if (fill_level >= IN_BUFFER_PREFILL)
{ {
int aud_to_host_rdptr;
GET_SHARED_GLOBAL(aud_to_host_rdptr, g_aud_to_host_rdptr);
inUnderflow = 0; inUnderflow = 0;
SET_SHARED_GLOBAL(g_aud_to_host_buffer, aud_to_host_rdptr); aud_to_host_buffer = aud_to_host_rdptr;
} }
else else
{ {
SET_SHARED_GLOBAL(g_aud_to_host_buffer, g_aud_to_host_zeros); aud_to_host_buffer = aud_to_host_zeros;
} }
} }
else else
@@ -1007,37 +1008,49 @@ void XUA_Buffer_Decouple(chanend c_mix_out
int datalength; int datalength;
int aud_to_host_wrptr; int aud_to_host_wrptr;
int aud_to_host_rdptr; int aud_to_host_rdptr;
int fillLevel;
GET_SHARED_GLOBAL(aud_to_host_wrptr, g_aud_to_host_wrptr); GET_SHARED_GLOBAL(aud_to_host_wrptr, g_aud_to_host_wrptr);
GET_SHARED_GLOBAL(aud_to_host_rdptr, g_aud_to_host_rdptr); GET_SHARED_GLOBAL(aud_to_host_rdptr, g_aud_to_host_rdptr);
GET_SHARED_GLOBAL(fillLevel, g_aud_to_host_fill_level);
/* Read datalength and round to nearest word */ /* Read datalength and round to nearest word */
read_via_xc_ptr(datalength, aud_to_host_rdptr); read_via_xc_ptr(datalength, aud_to_host_rdptr);
aud_to_host_rdptr = aud_to_host_rdptr + ((datalength+3)&~0x3) + 4; datalength = ((datalength + 3) & ~0x3) + 4;
assert(datalength >= 4);
assert(fillLevel >= datalength);
aud_to_host_rdptr += datalength;
fillLevel -= datalength;
if (aud_to_host_rdptr >= aud_to_host_fifo_end) if (aud_to_host_rdptr >= aud_to_host_fifo_end)
{ {
aud_to_host_rdptr = aud_to_host_fifo_start; aud_to_host_rdptr = aud_to_host_fifo_start;
} }
SET_SHARED_GLOBAL(g_aud_to_host_rdptr, aud_to_host_rdptr); SET_SHARED_GLOBAL(g_aud_to_host_rdptr, aud_to_host_rdptr);
SET_SHARED_GLOBAL(g_aud_to_host_fill_level, fillLevel);
/* Check for read pointer hitting write pointer - underflow */ /* Check for read pointer hitting write pointer - underflow */
if (aud_to_host_rdptr != aud_to_host_wrptr) if (fillLevel != 0)
{ {
SET_SHARED_GLOBAL(g_aud_to_host_buffer, aud_to_host_rdptr); aud_to_host_buffer = aud_to_host_rdptr;
} }
else else
{ {
assert(aud_to_host_rdptr == aud_to_host_wrptr);
inUnderflow = 1; inUnderflow = 1;
SET_SHARED_GLOBAL(g_aud_to_host_buffer, g_aud_to_host_zeros); aud_to_host_buffer = aud_to_host_zeros;
} }
} }
/* Request to send packet */ /* Request to send packet */
{ {
int p, len; int len;
GET_SHARED_GLOBAL(p, g_aud_to_host_buffer); asm volatile("ldw %0, %1[0]":"=r"(len):"r"(aud_to_host_buffer));
asm volatile("ldw %0, %1[0]":"=r"(len):"r"(p)); XUD_SetReady_InPtr(aud_to_host_usb_ep, aud_to_host_buffer+4, len);
XUD_SetReady_InPtr(aud_to_host_usb_ep, p+4, len);
} }
ENABLE_INTERRUPTS();
continue; continue;
} }
} }