[Portaudio] PA latency; StepMania use

Ross Bencina rbencina@iprimus.com.au
Mon, 18 Nov 2002 14:38:45 +1100

Hi Glenn

 "Glenn Maynard" <g_paud@zewt.org> wrote:
> I've tried a test implementation using PA.  It initializes 16 streams at
> start, and when a sound is played uses the first unused stream.  For the
> most part, it works fine.

That sounds like an extremely bad way to proceed. Primarily becase PortAudio
doesn't guarantee that you can open multiple streams using the same device.
It might work with DirectSound but it won't work with many other PortAudio
implementations. Also, there is no guarantee that stream start up time will
be low-latency, or delay free because we can't know what the driver will do.

There may be Audio APIs which support low-latency sample playback - I know
DirectSound allows you to cache samples in soundcard ram for lowest
latency - but PortAudio is primarily a streaming audio API. The best way to
get consistently low latency with lots of different sounds playing is to
keep a single stream open and active and output silence when you don't have
any audio playing. With V19 you can retrieve stream latency values and
buffer timings and use these to generate sound ahead of time (when possible)
so that it's perfectly syncronised with your graphics.

> So, another vote for a toggle for prebuffering audio vs. silence;
> I'd recommend prebuffering audio be the default, since most apps
> probably won't have the high-load-callback problem.

I think many uses of PortAudio would have the high-load problem, but I could
be wrong. Either way, pre-buffering vs. silence is on the proposals list and
it will be available in V19.

> Here's an unresolved problem:
> I need to stop streams when they're finished, so they can be recycled.
> Pa_AbortStream isn't (and can't be) reliable, so I can't be calling it in
> the main thread; it'll cause framerate glitches.  It's probably safe
> enough to thread off all sound calls, which would prevent that, but it'd
> stlil cause timing glitches on sounds, if we needed to start playing a new
> sound while the sound thread was blocking in Pa_AbortStream.  Is it safe
> to move Pa_StopStream/Pa_AbortStream into a thread, if I don't make any
> other PA calls on that stream until it finishes?

It's definitely safe if you don't make any other calls to PA at all (on any
stream.) Beyond that we make no guarantees.

I think this problem is another reason why your approach is a bad fit for
PortAudio. I think you should build some infrastructure on top of PortAudio
(a sample scheduler for example) to support your application. One way to
avoid glitches is to treat the PortAudio callback as a separate thread, and
use lock-free  FIFOs (ie non-blocking) to communicate with it. This is
typically how music applications work.

> I suppose what this really wants is a nonblocking Pa_StopStream, so I can
> tell PA to stop it in the background then actually mark the stream
> once it's really stopped, but that might be difficult to implement at the
> driver level.

Yes, difficult to implement at the driver level. But relatively easy for you
to implement on top of PortAudio.

If you need more help with this let me know, I have a few ideas about how to
implement something. Perhaps we can build something that can be included in
the PortAudio distribution as an example.

Best wishes,