[e2e] Packet transmission timer

John Lazzaro lazzaro at CS.Berkeley.EDU
Fri Jul 6 11:53:23 PDT 2001


> Jeevandra <jeevandra at swift.ee.umist.ac.uk> writes
>
> or less. But most OSs are not able to provide that of a high timer
> resolution. I am only able to obtain at most a 10ms granularity.

There's a trick that works under Linux that comes out of the audio
world, and so it only works if there is a soundcard in your machine
and you have the OSS or ALSA drivers installed, that lets you do 
significantly better than 10ms. 

The way these audio API's work, at start time you have the option
of creating a small pool of "fragment" buffers -- 4 buffers of 64
bytes each, for example. For 44100Hz mono 16 bit audio, a fragment
holds 0.725ms of sound, and the 4 fragments together hold about 3ms
of sound. 

Once you've created the fragment pool, you can write() to the sound
card device, and either one of two things happen:

-- There's a fragment free in the pool. If so, the data you write
is copied to the fragment, which is then taken out of the pool and
queued for playback to the soundcard, and the write() returns 
immediately.

-- There's no fragments left in the pool -- because you've done a
bunch of write() calls in succession, and so the playback queue
is filled with all the fragments. In this case, the write() blocks,
until the sound driver is finished playing out the lead fragment
in the queue (which takes 0.725ms), and then unblocks. 

Given this behavior, you can write a simple "dummy" audio app, 
that sets up a fragment pool at the start of the fragment, and
then does a set of quick write()'s to use up all the fragments
(in our example 4). It then does a 5th write, which in effect 
will act as a 0.725ms timer. In this scenareo, everything else
in your program is carefully designed to be non-blocking. Audio
apps that do low-latency work under Linux (for example, music
synthesis programs that are controlled by a MIDI keyboard) use
this technique to get acceptably low latency. A few things to
note:

-- This is most reliable when you use real-time POSIX scheduling,
and run the process in SCHED_FIFO.                            

-- This is different than just calling a function like nanosleep(),
because the process is really blocking during that 0.725ms -- 
you can run a program like this under X just fine, and maintain
full cursor and window control, whereas running a SCHED_FIFO 
process with nanosleep() calls for timing and no other blocking
would lock the mouse and keyboard until the process ended. 

-- You can query the soundcard using ioctl()'s to track the 
total number of fragments written during the lifetime of the
program. You can use this a clock, and you can double check
the number against the gettimeofday() clock to catch any 
catastrophes that led to an overrun, and compensate accordingly.


The success of this technqiue ultimately lies in the ability of
the kernel to deliver good SCHED_FIFO scheduling performance --
to quickly note when the soundcard driver unblocks, and hand
control back to the SCHED_FIFO process. There's a relatively
short list of "things not to do" if you want this to work 
reliably under Linux -- and if you're willing to install the
special "low-latency kernel patches", the list gets even shorter.

There's a community devoted to these sorts of techniques:

http://www.linuxdj.com/audio/lad/resources.php3

for more details on how to make this actually work for you.

-------------------------------------------------------------------------
John Lazzaro -- Research Specialist -- CS Division -- EECS -- UC Berkeley
lazzaro [at] cs [dot] berkeley [dot] edu     www.cs.berkeley.edu/~lazzaro
-------------------------------------------------------------------------



More information about the end2end-interest mailing list