PortAudio Latency |
This page discusses the issues of audio latency for PortAudio . It offers suggestions on how to lower latency to improve the responsiveness of applications.
What is Latency?By Phil Burk, Copyright 2002 Phil Burk and Ross Bencina
PortAudio and Latency
Macintosh
Unix
WIndows
Consider the example of pressing a key on the ASCII keyboard to play a note. There are several stages in this process which each contribute their own latency. First the operating system must respond to the keypress. Then the audio signal generated must work its way through the PortAudio buffers. Then it must work its way through the audio card hardware. Then it must go through the audio amplifier which is very quick and then travel through the air. Sound travels at abous one foot per millisecond through air so placing speakers across the room can add 5-20 msec of delay.
The reverse process occurs when recording or responding to audio input. If you are processing audio, for example if you implement a software guitar fuzz box, then you have both the audio input and audio output latencies added together.
The audio buffers are used to prevent glitches in the audio stream. The user software writes audio into the output buffers. That audio is read by the low level audio driver or by DMA and sent to the DAC. If the computer gets busy doing something like reading the disk or redrawing the screen, then it may not have time to fill the audio buffer. The audio hardware then runs out of audio data, which causes a glitch. By using a large enough buffer we can ensure that there is always enough audio data for the audio hardware to play. But if the buffer is too large then the latency is high and the system feels sluggish. If you play notes on the keyboard then the "instrument" will feel unresponsive. So you want the buffers to be as small as possible without glitching.
The latency in milliseconds due to this buffering is:
latency_msec = 1000 * numBuffers * framesPerBuffer / framesPerSecondThis is not the total latency, as we have seen, but it is the part we can control.
If you call Pa_OpenStream() with numBuffers equal to zero, then PortAudio will select a conservative number that will prevent audio glitches. If you still get glitches, then you can pass a larger value for numBuffers until the glitching stops. if you try to pass a numBuffers value that is too small, then PortAudio will use its own idea of the minimum value.
PortAudio decides on the minimum number of buffers in a conservative way based on the frameRate, operating system and other variables. You can query the value that PortAudio will use by calling:
int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate );On some systems you can override the PortAudio minimum if you know your system can handle a lower value. You do this by setting an environment variable called PA_MIN_LATENCY_MSEC which is read by PortAudio when it starts up. This is supported on the PortAudio implementations for Windows MME, Windows DirectSound, and Unix OSS.
For Mac OS X the latency is very low because Apple Core Audio is so well written. You can set the PA_MIN_LATENCY_MSEC variable using:
setenv PA_MIN_LATENCY_MSEC 4
The underlying audio API also makes a lot of difference. If the audio device has its own DirectSound driver then DirectSound can often provide better latency than WMME. But if a real DirectSound driver is not available for your device then it is emulated using WMME and the latency can be very high. That's where I saw the 400 millisecond latency. The ASIO implementation is generally very good and will give the lowest latency if available.
You can set the PA_MIN_LATENCY_MSEC variable to 50, for example, by entering in MS-DOS:
set PA_MIN_LATENCY_MSEC=50If you enter this in a DOS window then you must run the PortAudio program from that same window for the variable to have an effect. You can add that line to your C:\AUTOEXEC.BAT file and reboot if you want it to affect any PortAudio based program.
For Windows XP, you can set environment variables as follows: