added a parameter to S_StopChannel to trigger a mutex lock, this fixes
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Sun, 2 Mar 2008 12:06:55 +0000 (12:06 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Sun, 2 Mar 2008 12:06:55 +0000 (12:06 +0000)
crashes in the SDL audio callback when S_StopChannel clears fields while
they are being used in the mixer (this mostly crashed on level changes),
the mutex lock itself is done simply by calling SndSys_LockRenderBuffer

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@8176 d7cf8633-e32d-0410-b094-e92efae38249

cd_shared.c
dpvsimpledecode.c
snd_main.c
snd_mix.c
snd_null.c
sound.h

index 5eeadae..0f5a3ad 100644 (file)
@@ -171,7 +171,7 @@ void CDAudio_Play_byName (const char *trackname, qboolean looping)
                        Con_Print("Could not load BGM track.\n");
                        return;
                }
-       
+
                if (!cdValid)
                {
                        CDAudio_GetAudioDiskInfo();
@@ -214,7 +214,7 @@ void CDAudio_Stop (void)
 
        if (faketrack != -1)
        {
-               S_StopChannel (faketrack);
+               S_StopChannel (faketrack, true);
                faketrack = -1;
        }
        else if (cdPlaying && (CDAudio_SysStop() == -1))
index 7519c3f..6cbc44e 100644 (file)
@@ -369,7 +369,7 @@ void *dpvsimpledecode_open(char *filename, char **errorstring)
                                                        if (s->videopixels != NULL)
                                                        {
                                                                size_t namelen;
-                                                               
+
                                                                namelen = strlen(filename) + 10;
                                                                wavename = (char *)Z_Malloc(namelen);
                                                                if (wavename)
@@ -424,7 +424,7 @@ void dpvsimpledecode_close(void *stream)
        if (s->videopixels)
                Z_Free(s->videopixels);
        if (s->sndchan != -1)
-               S_StopChannel (s->sndchan);
+               S_StopChannel (s->sndchan, true);
        if (s->framedatablocks)
                hz_bitstream_read_blocks_free(s->framedatablocks);
        if (s->bitstream)
index 84e2469..251a859 100644 (file)
@@ -896,7 +896,7 @@ void S_FreeSfx (sfx_t *sfx, qboolean force)
        // Stop all channels using this sfx
        for (i = 0; i < total_channels; i++)
                if (channels[i].sfx == sfx)
-                       S_StopChannel (i);
+                       S_StopChannel (i, true);
 
        // Free it
        if (sfx->fetcher != NULL && sfx->fetcher->free != NULL)
@@ -1082,7 +1082,7 @@ channel_t *SND_PickChannel(int entnum, int entchannel)
                        if (ch->entnum == entnum && (ch->entchannel == entchannel || entchannel == -1) )
                        {
                                // always override sound from same entity
-                               S_StopChannel (ch_idx);
+                               S_StopChannel (ch_idx, true);
                                return &channels[ch_idx];
                        }
                }
@@ -1196,9 +1196,10 @@ void SND_Spatialize(channel_t *ch, qboolean isstatic)
 void S_PlaySfxOnChannel (sfx_t *sfx, channel_t *target_chan, unsigned int flags, vec3_t origin, float fvol, float attenuation, qboolean isstatic)
 {
        // Initialize the channel
+       // We MUST set sfx LAST because otherwise we could crash a threaded mixer
+       // (otherwise we'd have to call SndSys_LockRenderBuffer here)
        memset (target_chan, 0, sizeof (*target_chan));
        VectorCopy (origin, target_chan->origin);
-       target_chan->sfx = sfx;
        target_chan->flags = flags;
        target_chan->pos = 0; // start of the sound
 
@@ -1215,7 +1216,12 @@ void S_PlaySfxOnChannel (sfx_t *sfx, channel_t *target_chan, unsigned int flags,
        // Lock the SFX during play
        S_LockSfx (sfx);
 
-       // and finally, apply the volume
+       // finally, set the sfx pointer, so the channel becomes valid for playback
+       // and will be noticed by the mixer
+       target_chan->sfx = sfx;
+
+       // we have to set the channel volume AFTER the sfx because the function
+       // needs it for replaygain support
        S_SetChannelVolume(target_chan - channels, fvol);
 }
 
@@ -1260,7 +1266,7 @@ int S_StartSound (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float f
        return (target_chan - channels);
 }
 
-void S_StopChannel (unsigned int channel_ind)
+void S_StopChannel (unsigned int channel_ind, qboolean lockmutex)
 {
        channel_t *ch;
 
@@ -1272,6 +1278,12 @@ void S_StopChannel (unsigned int channel_ind)
        {
                sfx_t *sfx = ch->sfx;
 
+               // we have to lock an audio mutex to prevent crashes if an audio mixer
+               // thread is currently mixing this channel
+               // the SndSys_LockRenderBuffer function uses such a mutex in
+               // threaded sound backends
+               if (lockmutex)
+                       SndSys_LockRenderBuffer();
                if (sfx->fetcher != NULL)
                {
                        snd_fetcher_endsb_t fetcher_endsb = sfx->fetcher->endsb;
@@ -1284,6 +1296,8 @@ void S_StopChannel (unsigned int channel_ind)
 
                ch->fetcher_data = NULL;
                ch->sfx = NULL;
+               if (lockmutex)
+                       SndSys_UnlockRenderBuffer();
        }
 }
 
@@ -1313,7 +1327,7 @@ void S_StopSound(int entnum, int entchannel)
        for (i = 0; i < MAX_DYNAMIC_CHANNELS; i++)
                if (channels[i].entnum == entnum && channels[i].entchannel == entchannel)
                {
-                       S_StopChannel (i);
+                       S_StopChannel (i, true);
                        return;
                }
 }
@@ -1331,7 +1345,7 @@ void S_StopAllSounds (void)
        CDAudio_Stop();
 
        for (i = 0; i < total_channels; i++)
-               S_StopChannel (i);
+               S_StopChannel (i, true);
 
        total_channels = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS;   // no statics
        memset(channels, 0, MAX_CHANNELS * sizeof(channel_t));
index d7a6255..2fa5878 100644 (file)
--- a/snd_mix.c
+++ b/snd_mix.c
@@ -513,7 +513,7 @@ void S_MixToBuffer(void *stream, unsigned int bufferframes)
                                                ch->pos = 0;
                                        else
                                        {
-                                               S_StopChannel (ch - channels);
+                                               S_StopChannel (ch - channels, false);
                                                break;
                                        }
                                }
index 22a606d..1ed1cc8 100755 (executable)
@@ -62,7 +62,7 @@ int S_StartSound (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float f
        return -1;
 }
 
-void S_StopChannel (unsigned int channel_ind)
+void S_StopChannel (unsigned int channel_ind, qboolean lockmutex)
 {
 }
 
diff --git a/sound.h b/sound.h
index 1889b87..2496170 100644 (file)
--- a/sound.h
+++ b/sound.h
@@ -79,7 +79,7 @@ void S_StopSound (int entnum, int entchannel);
 void S_StopAllSounds (void);
 void S_PauseGameSounds (qboolean toggle);
 
-void S_StopChannel (unsigned int channel_ind);
+void S_StopChannel (unsigned int channel_ind, qboolean lockmutex);
 qboolean S_SetChannelFlag (unsigned int ch_ind, unsigned int flag, qboolean value);
 void S_SetChannelVolume (unsigned int ch_ind, float fvol);