Rate offset and jitter concealment for streaming audio
at +-2ppm, we'd win or lose a single sample any 45 seconds – my pragmatic approach here would be ignoring the problem, which, of course, has extremely low latency :)

But yes, especially if the producer is a bit slower than the consumer, you'll have a problem in the long run.

Now, there's no easy solution to this – first of all, your receiver needs to be able to see that problem at all.


But let's assume it does – simply by counting (recovered?) clock phases of the receive signal and comparing to its own clock cycles (this gets easier for serial audio data buses, e.g. I2S, because there's many bits per sample, so your bit clock is higher, so the counting offset gets visible much faster, but only if the transmitter continously clocks the bus).
If that can't work for technical reasons (non-continuous bursting of audio data, bus clock is decoupled from ADC clock, no access to recovered clock, etc), the only way I could think of would be the one of keeping track of buffer levels – I assume your receiver does have one, albeit small, buffer between its digital input and the ADC, because otherwise, the ADC would have to run directly off the bus clock, right?


You could observe the buffer "fillage" or clock offset, low pass filter and or caclulate a derivative of that info, define upper and lower boundaries, and simply drop a whole sample if you've got a next-to-critical source-faster-than-sink mismatch, or add a zero sample in the opposite case.

Of course, the "right" way to do this would be resampling – but from your question it seemed to me you're more interested in latency than in accuracy; you use the same frequency offset info as gotten from either bus/clock shift or buffer fillage to drive your own arbitrary resampler:


For example, what's pretty popular among these parts (PC-style computer based SDR), is a resampler based on MMSE-combined filters. They're not overly long.
The next more elegant thing is the Polyphase filterbank arbitrary resampler: again, filterbank with different filters, this time actually used just for a rational interpolator/decimator, but followed by logic that "combines" the output of the next lower rational resampler "branch" with the next higher linearly to get the wanted real resampling ratio. Advantage is that with a big filterbank, your error gets pretty small at reasonable CPU cost, and latency is bound by the length of the rational resampler bank filter - which typically won't be hundreds of samples long :)