From alsa-devel-owner@alsa.jcu.cz  Fri Feb  5 22:29:36 1999
Received: from entry.jcu.cz (IDENT:perex@entry.jcu.cz [160.217.1.111])
	by marvin.jcu.cz (8.9.1a/8.9.1) with SMTP id WAA27858;
	Fri, 5 Feb 1999 22:27:27 +0100
Date: Fri, 5 Feb 1999 22:27:27 +0100 (CET)
From: Jaroslav Kysela <perex@jcu.cz>
To: Paul Barton-Davis <pbd@op.net>
cc: alsa-devel@alsa.jcu.cz
Subject: proposal of PCM API changes [Re: latency..]
In-Reply-To: <199902042337.SAA11881@renoir.op.net>
Message-ID: <Pine.LNX.3.96.990205211016.464C-100000@entry.jcu.cz>
MIME-Version: 1.0
Content-Type: TEXT/PLAIN; charset=US-ASCII
Reply-To: alsa-devel@alsa.jcu.cz
Sender: alsa-devel-owner@alsa.jcu.cz
Precedence: list

On Thu, 4 Feb 1999, Paul Barton-Davis wrote:

> >I'm thinking about adding 'prepare' ioctls for playback and record to let
> >an application control this behaviour. I'm also thinking about 
> >synchronized playback and record, but only if the hardware allows it
> >(something or same thing like TRIGGER in OSS PCM API). Any comments?
> 
> I'm just working on the guts of my new implementation of Csound, and
> its turning out that the TRIGGER functionality in OSS seems pretty vital.
> In order to get timing to work correctly, I write 2 fragments-worth of
> data to the PCM buffer before starting its playback operation.  If the
> card starts up as soon as I fill the first fragment, I can't
> reasonably synchronize things so that I'm always writing into the
> fragment 2 beyond where the hardware is currently reading.
> 
> So I think that the TRIGGER ioctl is very, very useful.

You can do perfect timing using ALSA's timestamps, but I know, why an
application program must do it if we can bother driver programmers?
Or you can use playback pause / write initial playback data / playback
enable sequence (already implemented and it's same thing as OSS's
trigger does).

OK - to real life. The ALSA's TRIGGER will be absolutely different than
OSS's one. The trigger ioctl will enable start at same time playback
and/or recording from one or more PCM devices installed in the system if
(and only if) the hardware will support it.

Algorithm:

* initialize playback and recording directions
* determine which devices can be triggered
* pause all playback directions used
* write necessary bytes to playback ring buffers in kernel
  - in this case these bytes will be real delay between playback and
    recording!!
* trigger required devices

Underruns/overruns:

* it's an application thing how this will be handled inside
  - the best thing is stoping all directions and telling the user that
    something is wrong

Hardware which cannot be supported (full duplex - playback & recording):

  - S3 SonicVibes (different PLLs)
  - GUS Classic (GF1 chip)
    - I'm not sure here if recording direction uses another clock than
      synthesizer part of chip.. It needs some testing.

The hardware which can be supported, but we can miss some precision (I
think only one sample between playback and recording):

  - SoundBlaster 16
    - It isn't possible trigger playback & recording with one out
      instruction.
  - ES 18xx
    - ...dtto...

Fully supported hardware:

  - CS4231+
  - Ensoniq AudioPCI

Enhanced hardware:

  - Ensoniq AudioPCI
    - we can trigger both playback directions + recording at same time!!!

Issues with nonsupported hardware:

  - implementing prepare ioctls (to reduce delay from manual trigger
    by application)
  - timestamps could be used for sample insert/removal

> Another feature of the OSS API that I would be nice to see improved
> (and this may already be done - I haven't checked) is support for

This feature exists from the begin!!! I'm not sure if you read API
documentation for ALSA's PCM API. You can set both low and high
watermarks. Maybe you are speaking about another thing.

> defining when select() returns. Right now, OSS requires you to mmap()
> the buffer to get select() to return on fragment boundaries. Although
> I'm a big fan of mmap(), I see no reason to have to use it to force
> select() to work this way. I would like to do something like:
> 
> 	 ioctl (fd, SNDCTL_DSP_SELECT_ON_FRAGMENT_BOUNDARY, 0);
> 
> 	 while (select (....)) {
> 	       /* now we know that the hardware recently
> 	          crossed a fragment boundary, so we
> 		  can overwrite the previous
> 		  fragment and/or write-ahead a future
> 		  fragment.
> 		*/

I know how is used mmaped() access in OSS. ALSA have this algorithm:

 - I need wakeup when at least two fragments are free and when
   at maximum five fragments are used.
 - Standard select() loop..

OK. I see that you are working with partly filled fragments (in another
words you can fill the fragment which is being played - correct?).

At this time ALSA doesn't allow use the fragment which is being played,
but I'm looking for adding this feature to ALSA. It can improve the
latency and greatly reduce interrupts, but only in special cases when
an application takes all available CPU time or when it does own timing
(maybe good for RTlinux?).

As you said before in your example, select() returns control to the
application only if one fragment is played, thus application must
prepare/write one whole fragment at least.

I still didn't think that mmaped() access is best. The driver can control
overruns / underruns / write-ahead more exactly than the user level
application.

FEEDBACK, please...

							Jaroslav

-----
Jaroslav Kysela <perex@jcu.cz>
Academic Computer Centre, University of South Bohemia
Branisovska 31, C. Budejovice, CZ-370 05 Czech Republic




