Fixed SDL_mixer patch

Here’s the (hopefully) correct patch to fix SDL_mixer’s LockAudio
behaviour.

I’ve also added some comments to SDL_mixer.h about not locking audio in
various effect callbacks, etc.

–ryan.

-------------- next part --------------
diff -u -r1.15 SDL_mixer.h
— SDL_mixer.h 2002/01/14 19:35:45 1.15
+++ SDL_mixer.h 2002/03/31 02:39:42
@@ -141,15 +141,19 @@
extern DECLSPEC void Mix_HookMusic(void (*mix_func)
(void *udata, Uint8 *stream, int len), void *arg);

-/* Add your own callback when the music has finished playing.

  • /
    +/
    Add your own callback when the music has finished playing. */
    extern DECLSPEC void Mix_HookMusicFinished(void (*music_finished)(void));

/* Get a pointer to the user data for the current music hook */
extern DECLSPEC void *Mix_GetMusicHookData(void);

-/* Add your own callback when a channel has finished playing. NULL

    • to disable callback.
      +/*
    • Add your own callback when a channel has finished playing. NULL
    • to disable callback. The callback may be called from the mixer’s audio
    • callback or it could be called as a result of Mix_HaltChannel(), etc.
    • do not call SDL_LockAudio() from this callback; you will either be
    • inside the audio callback, or SDL_mixer will explicitly lock the audio
    • before calling your callback.
      */
      extern DECLSPEC void Mix_ChannelFinished(void (*channel_finished)(int channel));

@@ -172,6 +176,8 @@

  • down the mixing pipeline, through any other effect functions, then finally
  • to be mixed with the rest of the channels and music for the final output
  • stream.
    • DO NOT EVER call SDL_LockAudio() from your callback function!
      */
      typedef void (*Mix_EffectFunc_t)(int chan, void *stream, int len, void *udata);

@@ -181,6 +187,8 @@

  • plays out normally, or if you call Mix_HaltChannel(), implicitly stop
  • a channel via Mix_AllocateChannels(), or unregister a callback while
  • it’s still playing.
    • DO NOT EVER call SDL_LockAudio() from your callback function!
      */
      typedef void (*Mix_EffectDone_t)(int chan, void *udata);

@@ -226,11 +234,13 @@

  • through Mix_SetPostMix() runs, and then the stream goes to the audio
  • device.*
    • DO NOT EVER call SDL_LockAudio() from your callback function!
    • returns zero if error (no such channel), nonzero if added.
    • Error messages can be retrieved from Mix_GetError().
      */
      extern DECLSPEC int Mix_RegisterEffect(int chan, Mix_EffectFunc_t f,
  •   								Mix_EffectDone_t d, void *arg);
    
  •   			Mix_EffectDone_t d, void *arg);
    

/* You may not need to call this explicitly, unless you need to stop an
diff -u -r1.35 mixer.c
— mixer.c 2002/03/24 02:06:12 1.35
+++ mixer.c 2002/03/31 02:39:44
@@ -40,7 +40,6 @@
#define FORM 0x4d524f46 /* “FORM” */

static int audio_opened = 0;

static SDL_AudioSpec mixer;
static SDL_mutex *mixer_lock;

@@ -101,15 +100,28 @@
return(&linked_mixver);
}

+static int _Mix_remove_all_effects(int channel, effect_info **e);

/* rcg06122001 Cleanup effect callbacks. */
-static void Mix_ChannelDonePlaying(int channel)
+static void _Mix_channel_done_playing(int channel, int lockaudio)
{

  • if (lockaudio) {
  •   SDL_LockAudio();
    
  • }
  • if (channel_done_callback) {
    channel_done_callback(channel);
    }
  • Mix_UnregisterAllEffects(channel);
  • /*
  •     * Call internal function directly, to avoid locking audio from
    
  •     *   inside audio callback.
    
  •     */
    
  • _Mix_remove_all_effects(channel, &mix_channel[channel].effects);
  • if (lockaudio) {
  •   SDL_UnlockAudio();
    
  • }
    }

@@ -223,7 +235,7 @@

			/* rcg06072001 Alert app if channel is done playing. */
			if (!mix_channel[i].playing) {
  •   			Mix_ChannelDonePlaying(i);
    
  •   			_Mix_channel_done_playing(i, 0);
      		}
      	}
      }
    

@@ -622,7 +634,7 @@
if ( which >= 0 ) {
Uint32 sdl_ticks = SDL_GetTicks();
if (Mix_Playing(which))

  •   		Mix_ChannelDonePlaying(which);
    
  •   		_Mix_channel_done_playing(which, 1);
      	mix_channel[which].samples = chunk->abuf;
      	mix_channel[which].playing = chunk->alen;
      	mix_channel[which].looping = loops;
    

@@ -688,7 +700,7 @@
if ( which >= 0 ) {
Uint32 sdl_ticks = SDL_GetTicks();
if (Mix_Playing(which))

  •   		Mix_ChannelDonePlaying(which);
    
  •   		_Mix_channel_done_playing(which, 1);
      	mix_channel[which].samples = chunk->abuf;
      	mix_channel[which].playing = chunk->alen;
      	mix_channel[which].looping = loops;
    

@@ -758,7 +770,7 @@
} else {
SDL_mutexP(mixer_lock);
if (mix_channel[which].playing) {

  •   	Mix_ChannelDonePlaying(which);
    
  •   	_Mix_channel_done_playing(which, 1);
      mix_channel[which].playing = 0;
      }
      mix_channel[which].expire = 0;
    

@@ -1043,8 +1055,9 @@

  • as Mix_SetPanning().
    */

+/* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
static int _Mix_register_effect(effect_info **e, Mix_EffectFunc_t f,

  •   									Mix_EffectDone_t d, void *arg)
    
  •   		Mix_EffectDone_t d, void *arg)
    

{
effect_info *new_e = malloc(sizeof (effect_info));

@@ -1068,8 +1081,6 @@
new_e->udata = arg;
new_e->next = NULL;

  • SDL_LockAudio();

  • /* add new effect to end of linked list… */
    if (*e == NULL) {
    *e = new_e;
    @@ -1084,11 +1095,11 @@
    }
    }

  • SDL_UnlockAudio();
    return(1);
    }

+/* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
static int _Mix_remove_effect(int channel, effect_info **e, Mix_EffectFunc_t f)
{
effect_info *cur;
@@ -1100,7 +1111,6 @@
return(0);
}

  • SDL_LockAudio();
    for (cur = *e; cur != NULL; cur = cur->next) {
    if (cur->callback == f) {
    next = cur->next;
    @@ -1114,18 +1124,17 @@
    } else {
    prev->next = next;
    }

  •   	SDL_UnlockAudio();
      	return(1);
      }
      prev = cur;
    

    }

  • SDL_UnlockAudio();
    Mix_SetError(“No such effect registered”);
    return(0);
    }

+/* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
static int _Mix_remove_all_effects(int channel, effect_info **e)
{
effect_info *cur;
@@ -1136,7 +1145,6 @@
return(0);
}

  • SDL_LockAudio();
    for (cur = *e; cur != NULL; cur = next) {
    next = cur->next;
    if (cur->done_callback != NULL) {
    @@ -1145,16 +1153,16 @@
    free(cur);
    }
    *e = NULL;

  • SDL_UnlockAudio();

    return(1);
    }

int Mix_RegisterEffect(int channel, Mix_EffectFunc_t f,

  •   				Mix_EffectDone_t d, void *arg)
    
  •   	Mix_EffectDone_t d, void *arg)
    

{
effect_info **e = NULL;

  • int retval;

    if (channel == MIX_CHANNEL_POST) {
    e = &posteffects;
    @@ -1166,13 +1174,17 @@
    e = &mix_channel[channel].effects;
    }

  • return(_Mix_register_effect(e, f, d, arg));
  • SDL_LockAudio();
  • retval = _Mix_register_effect(e, f, d, arg);
  • SDL_UnlockAudio();
  • return(retval);
    }

int Mix_UnregisterEffect(int channel, Mix_EffectFunc_t f)
{
effect_info **e = NULL;

  • int retval;

    if (channel == MIX_CHANNEL_POST) {
    e = &posteffects;
    @@ -1183,13 +1195,18 @@
    }
    e = &mix_channel[channel].effects;
    }

  • return(_Mix_remove_effect(channel, e, f));
  • SDL_LockAudio();
  • retval = _Mix_remove_effect(channel, e, f);
  • SDL_UnlockAudio();
  • return(retval);
    }

int Mix_UnregisterAllEffects(int channel)
{
effect_info **e = NULL;

  • int retval;

    if (channel == MIX_CHANNEL_POST) {
    e = &posteffects;
    @@ -1201,7 +1218,10 @@
    e = &mix_channel[channel].effects;
    }

  • return(_Mix_remove_all_effects(channel, e));
  • SDL_LockAudio();
  • retval = _Mix_remove_all_effects(channel, e);
  • SDL_UnlockAudio();
  • return(retval);
    }

/* end of mixer.c … */