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
Con_Print("Could not load BGM track.\n");
return;
}
Con_Print("Could not load BGM track.\n");
return;
}
if (!cdValid)
{
CDAudio_GetAudioDiskInfo();
if (!cdValid)
{
CDAudio_GetAudioDiskInfo();
- S_StopChannel (faketrack);
+ S_StopChannel (faketrack, true);
faketrack = -1;
}
else if (cdPlaying && (CDAudio_SysStop() == -1))
faketrack = -1;
}
else if (cdPlaying && (CDAudio_SysStop() == -1))
if (s->videopixels != NULL)
{
size_t namelen;
if (s->videopixels != NULL)
{
size_t namelen;
namelen = strlen(filename) + 10;
wavename = (char *)Z_Malloc(namelen);
if (wavename)
namelen = strlen(filename) + 10;
wavename = (char *)Z_Malloc(namelen);
if (wavename)
if (s->videopixels)
Z_Free(s->videopixels);
if (s->sndchan != -1)
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)
if (s->framedatablocks)
hz_bitstream_read_blocks_free(s->framedatablocks);
if (s->bitstream)
// Stop all channels using this sfx
for (i = 0; i < total_channels; i++)
if (channels[i].sfx == sfx)
// Stop all channels using this sfx
for (i = 0; i < total_channels; i++)
if (channels[i].sfx == sfx)
+ S_StopChannel (i, true);
// Free it
if (sfx->fetcher != NULL && sfx->fetcher->free != NULL)
// Free it
if (sfx->fetcher != NULL && sfx->fetcher->free != NULL)
if (ch->entnum == entnum && (ch->entchannel == entchannel || entchannel == -1) )
{
// always override sound from same entity
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];
}
}
return &channels[ch_idx];
}
}
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
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);
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
target_chan->flags = flags;
target_chan->pos = 0; // start of the sound
// Lock the SFX during play
S_LockSfx (sfx);
// 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);
}
S_SetChannelVolume(target_chan - channels, fvol);
}
return (target_chan - channels);
}
return (target_chan - channels);
}
-void S_StopChannel (unsigned int channel_ind)
+void S_StopChannel (unsigned int channel_ind, qboolean lockmutex)
+ // 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;
if (sfx->fetcher != NULL)
{
snd_fetcher_endsb_t fetcher_endsb = sfx->fetcher->endsb;
ch->fetcher_data = NULL;
ch->sfx = NULL;
ch->fetcher_data = NULL;
ch->sfx = NULL;
+ if (lockmutex)
+ SndSys_UnlockRenderBuffer();
for (i = 0; i < MAX_DYNAMIC_CHANNELS; i++)
if (channels[i].entnum == entnum && channels[i].entchannel == entchannel)
{
for (i = 0; i < MAX_DYNAMIC_CHANNELS; i++)
if (channels[i].entnum == entnum && channels[i].entchannel == entchannel)
{
+ S_StopChannel (i, true);
CDAudio_Stop();
for (i = 0; i < total_channels; i++)
CDAudio_Stop();
for (i = 0; i < total_channels; i++)
+ S_StopChannel (i, true);
total_channels = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS; // no statics
memset(channels, 0, MAX_CHANNELS * sizeof(channel_t));
total_channels = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS; // no statics
memset(channels, 0, MAX_CHANNELS * sizeof(channel_t));
- S_StopChannel (ch - channels);
+ S_StopChannel (ch - channels, false);
-void S_StopChannel (unsigned int channel_ind)
+void S_StopChannel (unsigned int channel_ind, qboolean lockmutex)
void S_StopAllSounds (void);
void S_PauseGameSounds (qboolean toggle);
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);
qboolean S_SetChannelFlag (unsigned int ch_ind, unsigned int flag, qboolean value);
void S_SetChannelVolume (unsigned int ch_ind, float fvol);