Re: [linux-audio-dev] LAAGA - main components

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

Subject: Re: [linux-audio-dev] LAAGA - main components
From: Jim Peters (jim_AT_aguazul.demon.co.uk)
Date: Tue May 01 2001 - 12:35:55 EEST


Paul Davis wrote:
> >I can't see a problem with that. If we have a circular SHM buffers
> >for data moving to/from the critical process, then the critical
> >process will never have to block.
>
> how does any process, critical or otherwise, know *when* to write/read ?

The critical process is completely governed by the hardware - that is
the only thing it should block on. The critical process gets a chunk
of input audio, processes all its plugins, and outputs a chunk of
audio. (This is the main loop of a full-duplex app, isn't it ?). The
reading/writing data from/to shared memory buffers happens as these
plugins are processed.

For an external app writing to a shared memory buffer, it keeps
writing data to the buffer until it is full, and then blocks (somehow,
see below). When it wakes there should be some more space to fill.
Let's say the buffer has enough room for 100ms of sound. The app will
be at most 100ms ahead of real-time, but depending on other CPU
activity, it may get behind, but hopefully not as much as 100ms behind
or else we're in trouble.

The timing of each part is governed by the most time-critical thing it
hangs off. The critical process hangs off the hardware, and external
apps hang off the critical process. Each allows itself a fixed
latency according to how well it reckons it can keep up with what it's
hanging off.

> >some other event, then the app will have to give the time-critical
> >plugin a sample-clock time at which to release the buffer contents.
>
> and how will it do that? especially when you write:

Can we agree that the critical process can keep a count of the time in
sample-clock ticks ? If so, then in shared memory we can have this
structure:

  struct {
    int start_time;
    char start_time_valid;
  };

Most of the time `start_time_valid' is 0. If a plugin sees
`start_time_valid' non-zero, then it looks at the sample-clock time,
and if it isn't going to reach `start_time' in the next chunk, it just
outputs silence. After that point it starts outputting from the
shared memory buffer as normal (with some padding to get the time
exact). Once the app has seen that everything's started okay, it can
clear `start_time_valid'. Only the app is permitted to modify this
structure or else we risk race conditions.

This would need to be extended to also allow the output to be stopped
precisely, but I think that with care this is do-able.

> >I can see how SHM can work smoothly without need for semaphores and
>
> you can't sleep on a bit in shm.
>
> :::
>
> and the estimated sleep method cannot work, because the kernel offers
> no way to sleep for less than 1 timer tick, which is 10ms by default
> (i.e. 99% of all x86 linux systems). yes, i know that RT_FIFO threads
> will busy-wait, for smaller time periods on SMP systems but that
> doesn't count as "sleeping" in my book.

The only time we'd need to sleep is in the app where it is waiting for
a shared memory buffer to empty a little (for output) or fill a little
(for input). If, from what you say, all methods that involve a system
call risk blocking the critical process, and we can't reduce this risk
by moving all these calls to the end of the main loop (after writing
the output sound), then this leaves only the estimated sleep method.

If the minimum sleep is 10ms in the worst case, then this just means
that external apps had better allow themselves 20ms latency at least.
If they need better than that, then they'd better load a plugin into
the critical process.

Does this sound fair ?

The other way might to modify the kernel to permit sleeping on a bit
in shared memory ! Hmmm. Basically, what we want is at the end of
the critical process main loop, when it is once again blocking on the
audio input and the process context changes, at that point we want to
wake up all the processes that may be waiting on the shared memory
buffers. Ideally this would be with a single system call (or less).
Looking at the possibilities, kill(2) looks possible, as you can send
a signal to a whole process group. Alternatively we could create a
device that accepts a byte input (from a write(2) call), and releases
every process that is sleeping on it at that moment.

If even that single system call at the end of the critical process
main loop is still too much of a risk, then we're down to a choice of
kernel mods or 20ms+ delays for external "less-critical" apps, unless
someone can think of some other way.

Jim

-- 
 Jim Peters         /             __   |  \              Aguazul
                   /   /| /| )| /| / )||   \
 jim_AT_aguazul.      \  (_|(_|(_|(_| )(_|I   /        www.aguazul.
  demon.co.uk       \    ._)     _/       /          demon.co.uk


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

This archive was generated by hypermail 2b28 : Tue May 01 2001 - 13:34:56 EEST