Re: [linux-audio-dev] Producer/consumer threads and syncing

New Message Reply About this list Date view Thread view Subject view Author view Other groups

Subject: Re: [linux-audio-dev] Producer/consumer threads and syncing
From: Joakim G. (jocke_AT_gleipnir.com)
Date: Mon Apr 22 2002 - 01:11:49 EEST


Paul Davis wrote:
>
> >Context: Linux/OSS
> >
> >I have two threads (play_thread and output_thread). The output_thread
> >write sample chunks of 1024 bytes (from RAM) into a circular (jitter)
> >buffer (of length 8). The play_thread plays sample chunks from the
> >same circular buffer.
> >
> >The question is: How do I keep these two threads in sync?
>
> well, i'm not totally sure, but definitely not anything like the way
> you are doing. you cannot use a non-audio timing source to sync to a
> timing source unless you want to do a lot of ugly code to resync them
> as they drift (possibly in two directions over a given period of time).

I see.
 
> >If I let the play_thread play samples as fast as it can, blocking on
> >the write(2) system call, it gets _slightly_ to little data to run in
> >lock step with the output thread. Hmm.
>
> Yet another audio programmer sadly tied into the write(2) system call :)
>
> >I tried to delay the play_thread using the same 127712 period as the
> >output_thread, i.e. pseudo code follows:
> >
> >suspend.tv_sec = 0;
> >suspend.tv_usec = 127712;
>
> It seems that you are not aware that Linux (and POSIX OS's in general)
> do not provide timing of this kind of resolution. You just can't do
> this without (at the very least) a kernel patch, and even then, it
> still won't provide correct sync without drift correction.

Aha. I should have guessed. Do you know what kind of timing resolution
I can except from a vanilla Linux kernel?

> Instead, what you do is to use pthread_cond_signal() from the
> play_thread to notify the output_thread that it needs to do some
> work. Simply keep track of the relative position of the read/write
> pointers for the ringbuffer, and when the gap is too large, tell the
> output thread to deliver more data into it.

I actually fiddled with a conditional variable as you describe and it
did the job ok. The problem was that I wanted to stream audio via udp
between separate machines.

Just for fun I tried to write a chat server which read udp audio
streams coming from N machines. The mixing server created N mixing
threads, one for each machine in the chat. Each mixing thread mixed
together all incoming audio data expect from the machine it intended
to send the mixed audio stream back to (to avoid echo effects).

All strictly unicast.

Each mixing thread used a combination of gettimeofday/usleep to keep
the sync for incoming/outgoing audio streams. This is a no-brainer
approach I suppose.

I could dig into rtp/rtcp I guess but I just wanted to play a little
with the basics behind realtime audio streaming. I have some homework
to do it seems.

> I don't want to sound like a (broken record|skipping CD), but why
> don't you consider using JACK as the framework for what you are doing?
> You can forget about the mechanics of audio I/O and focus instead on
> ways to do useful work, which in your case might be interesting work
> for the rest of us too. Under JACK, your play thread will get called
> periodically to deliver and/or process "nframes" of audio data. You'll
> still have to work out the synchronization between that and the thread
> thats writing data into the shared ringbuffer, but you'll be able to
> forget about write(2), usleep(2) etc. You'll also be able to send data
> to other JACK-aware applications.
>
> http://jackit.sf.net/

I will take a close look. Thanks.

Cheers
/Jocke


New Message Reply About this list Date view Thread view Subject view Author view Other groups

This archive was generated by hypermail 2b28 : Mon Apr 22 2002 - 01:05:50 EEST