What is the correct way to calculate audio delay?


#1

My app plays audio and records it back, and I want to compinsate for this round trip delay. To figure out the delay, I played a sound on the left channel, recorded it on the right channel, exported the stereo wave file and looked at the difference between channels. It was 1238 samples.

I'm comparing that to the values I get from AudioIODevice::getInputLatencyInSamples() and AudioIODevice::getOutputLatencyInSamples() which both give me 1068.

From that I assume the round trip delay is 2136, which seems a lot higher than the 1238 the driver is reporting. That's a difference of about 20 ms. Or is the output delay the time from when the driver recieves the data to the time the block is finished playing? Therefore the time between giving the driver a block and the block starts playing is actually AudioIODevice::getOutputLatencyInSamples()  - blockSize?

Is there something wrong in my assumptions or are driver delays not that accurate? 

 


#2

I played a sound on the left channel, recorded it on the right channel, exported the stereo wave file and looked at the difference between channels.

..or you can just use the juce demo's latency detector to measure this!

Different devices will be better or worse at reporting latency. Most ASIO devices will be almost exactly correct. DirectSound and Android will be almost completely useless. CoreAudio will generally be ok-ish, but will depend on the device.. In each case I've done my best to make it return as good a guess as possible, but it's rarely possible to get it perfect.


#3

On iOS, the getOutputLatencyInSamples() and getInputLatencyInSamples() just return 0 and there is a comments that says // xxx. I'm assuming you never got around to implementing them. They should be:

    int getOutputLatencyInSamples() override
    {
        Float32 outLatency = 0;
        getSessionProperty(kAudioSessionProperty_CurrentHardwareOutputLatency, outLatency);
      
        return roundDoubleToInt(outLatency * getCurrentSampleRate());
    }
    
    int getInputLatencyInSamples() override
    {
        Float32 inLatency = 0;
        getSessionProperty(kAudioSessionProperty_CurrentHardwareInputLatency, inLatency);
    
        return roundDoubleToInt(inLatency * getCurrentSampleRate());
    }

#4

Ah, thanks! TBH I didn't realise that those function weren't finished, I'll sort that out..