Circle 7a81e1b4: USB audio accepts an asynchronous feedback value only between 7/8 and 3/2 of the nominal rate, as Linux snd-usb-audio does, and keeps the nominal rate otherwise. Without it a device whose first feedback reads 0 stops Circle on the m_nChunkSizeBytes assertion. diff --git a/include/circle/usb/usbaudiostreaming.h b/include/circle/usb/usbaudiostreaming.h index d4c7131..30d6e85 100644 --- a/include/circle/usb/usbaudiostreaming.h +++ b/include/circle/usb/usbaudiostreaming.h @@ -161,6 +161,7 @@ private: volatile boolean m_bSyncEPActive; DMA_BUFFER (u32, m_SyncEPBuffer, 1); unsigned m_nSyncAccu; + u32 m_nFeedbackNominal; // frames per packet at the nominal rate, Q16.16 u8 m_uchClockSourceID; u8 m_uchSelectorUnitID; diff --git a/lib/usb/usbaudiostreaming.cpp b/lib/usb/usbaudiostreaming.cpp index f48056e..40bc0fb 100644 --- a/lib/usb/usbaudiostreaming.cpp +++ b/lib/usb/usbaudiostreaming.cpp @@ -127,6 +127,7 @@ CUSBAudioStreamingDevice::CUSBAudioStreamingDevice (CUSBFunction *pFunction) m_nPacketsPerChunk (0), m_bSyncEPActive (FALSE), m_nSyncAccu (0), + m_nFeedbackNominal (0), m_uchClockSourceID (USB_AUDIO_UNDEFINED_UNIT_ID), m_uchSelectorUnitID (USB_AUDIO_UNDEFINED_UNIT_ID), From ("uaudio") @@ -720,6 +721,8 @@ boolean CUSBAudioStreamingDevice::Setup (unsigned nSampleRate) m_nChunkSizeBytes = nSampleRate * nFrameSize / nUSBFrameRate; + m_nFeedbackNominal = (u32) (((u64) nSampleRate << 16) / nUSBFrameRate); + // round up to a multiple of frame size m_nChunkSizeBytes += nFrameSize-1; m_nChunkSizeBytes /= nFrameSize; @@ -1066,6 +1069,18 @@ void CUSBAudioStreamingDevice::SyncCompletionHandler (CUSBRequest *pURB, void *p assert (pThis->m_bSyncEPActive); + // Some devices send 0 or a value far from the nominal rate before their clock runs, and a + // chunk size derived from it would be 0 or overflow the TX buffers. As the Linux driver + // does, accept only values between 7/8 and 3/2 of the nominal rate. + if (bOK) + { + u32 nValue = bFormat10_14 ? (pThis->m_SyncEPBuffer[0] & 0xFFFFFF) << 2 + : pThis->m_SyncEPBuffer[0]; + u32 nNominal = pThis->m_nFeedbackNominal; + bOK = nValue >= nNominal - nNominal / 8 + && nValue <= nNominal + nNominal / 2; + } + if (bOK) { if (bFormat10_14)