SDL_LockAudio on MacOS

I know this has been discussed before, but I was curious if a resolution
was ever reached.

I’m going to summarize here, please correct me if any of this is wrong:

Basically, SDL_LockAudio() is a no-op on MacOS 9, since there’re no mutexes.
However, the audio callback runs in a hardware interrupt, which means that
there are still potential (and actual) race conditions when the hardware
interrupt preempts the application.

There is no way to delay the interrupt from firing, so at best we could
just hope to feed silence to the audio chip if we set up a flag in SDL
that says the audio is “locked”. Preventing the interrupt from firing at
all during locked periods would be equally as bad. There isn’t a way to
catch up if we miss an interrupt, so in either case, we just have to deal
with skipping/popping/etc.

This seems pretty bleak. Is there some obvious solution I’m missing
(“upgrade to OS X” doesn’t count), because I can’t see a good way to
make this work, consider how dependent most code (SDL_mixer included) is
on SDL_LockAudio().

Alternately, what recommendations are there for designing SDL audio
applications that don’t rely on SDL_LockAudio() (if this is a better
tactic…)?

Thanks,
–ryan.

This seems pretty bleak. Is there some obvious solution I’m missing
(“upgrade to OS X” doesn’t count), because I can’t see a good way to
make this work, consider how dependent most code (SDL_mixer included) is
on SDL_LockAudio().

Yep, as far as I know that’s the situation.

Alternately, what recommendations are there for designing SDL audio
applications that don’t rely on SDL_LockAudio() (if this is a better
tactic…)?

The only think that I can think of offhand is to have a pointer to the
"mixing data" which you atomically switch when you want to modify what
data the mixing callback uses.

Any mac guys with great ideas? :slight_smile:

See ya,
-Sam Lantinga, Software Engineer, Blizzard Entertainment

This seems pretty bleak. Is there some obvious solution I’m missing
(“upgrade to OS X” doesn’t count), because I can’t see a good way to
make this work, consider how dependent most code (SDL_mixer included)
is
on SDL_LockAudio().

Yep, as far as I know that’s the situation.

Alternately, what recommendations are there for designing SDL audio
applications that don’t rely on SDL_LockAudio() (if this is a better
tactic…)?

The only think that I can think of offhand is to have a pointer to the
"mixing data" which you atomically switch when you want to modify what
data the mixing callback uses.

Any mac guys with great ideas? :slight_smile:

Before I go into an idea, perhaps some things to note and rambling to
gather my thoughts and understand the issues involved.

  • The audio callback could interrupt the user program at any time.

  • The audio callback cannot be interrupted by the user process.

  • The audio callback (basically) performs 3 tasks.

    1. Queue the buffer that was previously mixed in the last callback
      for playback.
    2. Call the SDL mix function on the buffer that was just consumed.
    3. Queue a command to invoke the callback again when the buffer in
      first step is consumed.
  • By this setup, the mix function cannot touch a buffer that is
    currently being played.

The primary use for SDL_LockAudio() seems to be that you want to avoid a
race condition when modifying something that will be used later in the
mix callback, which can be accomplished by temporarily disabling the
callback, making the change, then enabling the callback.

So, can we do this? :wink:

One approach uses a global variable audio_is_locked. If the low-level
callback is triggered and audio_is_locked is true, the callback does
step 1 and does not do steps 2 and 3.

This will only work if we have atomic test-and-set. Thankfully,
DriverServicesLib can do this, believe it or not. The procedure I
propose is as follows:

The callback would do an atomic test on audio_is_locked right before
step 2. If locked, the callback would abort.

SDL_LockAudio() would do an atomic set on audio_is_locked to true.

SDL_UnLockAudio() would set audio_is_locked to false, and would do step
2 + 3 only if
necessary. For this last part we need an additional global variable to
determine if the callback ever
reached step 2 and aborted.

I think this will work. Who wants to code it? :wink:

In the process we can throw out the SndPlayDoubleBuffer() code, which
this can’t be implemented for anyhow.

-DOn Tuesday, March 26, 2002, at 07:57 PM, Sam Lantinga wrote:

  • The audio callback (basically) performs 3 tasks.
    1. Queue the buffer that was previously mixed in the last callback
      [snip]
      So, can we do this? :wink:

It’s pretty clever…I can’t think of a reason why it couldn’t work.

–ryan.

Nothing Mac specific, but in Kobo Deluxe, I’m using a simple lock-free
FIFO to pass “commands” from the application to the audio callback. All
mixing is done in the callback, and of course, you don’t ever pass
references to structures that are “in flux”. (It’s actually possible to
get the engine to do that right now, with some abuse. Will be fixed
eventually… Code should be able to take some abuse! :wink:

In short:

"Don't touch anything directly! Tell the engine to do it."

Dead simple and very effective.

I’m quite sure the current engine won’t work on Mac OS Classic for other
reasons (*), but the FIFO itself is pretty well tested in various
environments and on different CPU types, and seems to work just about
everywhere.

http://olofson.net/mixed.html

(Look for "sfifo".)

(*) This is due to an unimplemented feature in the FX plugin API,
resulting in memory allocation being done in the engine context.
Sucks regardless of platform, so it’ll be fixed the next time
I’m hacking around in that area…

//David Olofson — Programmer, Reologica Instruments AB

.- M A I A -------------------------------------------------.
| Multimedia Application Integration Architecture |
| A Free/Open Source Plugin API for Professional Multimedia |
----------------------------> http://www.linuxdj.com/maia -' .- David Olofson -------------------------------------------. | Audio Hacker - Open Source Advocate - Singer - Songwriter |-------------------------------------> http://olofson.net -'On Wednesday 27 March 2002 01:57, Sam Lantinga wrote:

This seems pretty bleak. Is there some obvious solution I’m missing
(“upgrade to OS X” doesn’t count), because I can’t see a good way to
make this work, consider how dependent most code (SDL_mixer included)
is on SDL_LockAudio().

Yep, as far as I know that’s the situation.

Alternately, what recommendations are there for designing SDL audio
applications that don’t rely on SDL_LockAudio() (if this is a better
tactic…)?

The only think that I can think of offhand is to have a pointer to the
"mixing data" which you atomically switch when you want to modify what
data the mixing callback uses.

Any mac guys with great ideas? :slight_smile:

In short:

“Don’t touch anything directly! Tell the engine to do it.”

Dead simple and very effective.

Unfortunately this doesn’t work very well on MacOS Classic because
you can’t move the heap during interrupt time. I suppose you can
implement your own memory buffer pool though…

-Sam Lantinga, Software Engineer, Blizzard Entertainment

In short:

"Don't touch anything directly! Tell the engine to do it."

Dead simple and very effective.

Unfortunately this doesn’t work very well on MacOS Classic because
you can’t move the heap during interrupt time.

Right - and you can’t really do that on any other OS either, without a
drastically increased risk of drop-outs. (Maybe it doesn’t make all that
much of a difference on anything but BeOS and Linux/lowlatency,
though…?)

I suppose you can
implement your own memory buffer pool though…

Sure - but what would it be used for? A properly designed audio engine
won’t do any dynamic memory allocation in the “real time” context anyway.
(Which effectively means that a few versions of my engine are broken,
because I’ve been lazy. :slight_smile:

//David Olofson — Programmer, Reologica Instruments AB

.- M A I A -------------------------------------------------.
| Multimedia Application Integration Architecture |
| A Free/Open Source Plugin API for Professional Multimedia |
----------------------------> http://www.linuxdj.com/maia -' .- David Olofson -------------------------------------------. | Audio Hacker - Open Source Advocate - Singer - Songwriter |-------------------------------------> http://olofson.net -'On Wednesday 27 March 2002 06:19, Sam Lantinga wrote: