Secure UpdateMusicStream/PlayMusicStream/UpdateAudioStream;

This change is twofold:
* Add locks to UpdateMusicStream/UpdateAudioStream (second one needed separation)
* Remove unnecessary hack to restart music - inlining the statements resulted in a no-op

Especially the second part made it easier to ensure thread-safety overall
This commit is contained in:
Christian Haas 2024-04-09 09:50:31 +02:00
parent 637805ff1f
commit 5bf19a7d9c

View File

@ -444,6 +444,11 @@ void SetAudioBufferPan(AudioBuffer *buffer, float pan);
void TrackAudioBuffer(AudioBuffer *buffer); void TrackAudioBuffer(AudioBuffer *buffer);
void UntrackAudioBuffer(AudioBuffer *buffer); void UntrackAudioBuffer(AudioBuffer *buffer);
//----------------------------------------------------------------------------------
// AudioStream management functions declaration
//----------------------------------------------------------------------------------
void UpdateAudioStreamInLockedState(AudioStream stream, const void *data, int frameCount);
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module Functions Definition - Audio Device initialization and Closing // Module Functions Definition - Audio Device initialization and Closing
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -1770,19 +1775,10 @@ void UnloadMusicStream(Music music)
} }
} }
// Start music playing (open stream) // Start music playing (open stream) from beginning
void PlayMusicStream(Music music) void PlayMusicStream(Music music)
{ {
if (music.stream.buffer != NULL) PlayAudioStream(music.stream);
{
// For music streams, we need to make sure we maintain the frame cursor position
// This is a hack for this section of code in UpdateMusicStream()
// NOTE: In case window is minimized, music stream is stopped, just make sure to
// play again on window restore: if (IsMusicStreamPlaying(music)) PlayMusicStream(music);
ma_uint32 frameCursorPos = music.stream.buffer->frameCursorPos;
PlayAudioStream(music.stream); // WARNING: This resets the cursor position.
music.stream.buffer->frameCursorPos = frameCursorPos;
}
} }
// Pause music playing // Pause music playing
@ -1874,6 +1870,8 @@ void UpdateMusicStream(Music music)
{ {
if (music.stream.buffer == NULL) return; if (music.stream.buffer == NULL) return;
ma_mutex_lock(&AUDIO.System.lock);
unsigned int subBufferSizeInFrames = music.stream.buffer->sizeInFrames/2; unsigned int subBufferSizeInFrames = music.stream.buffer->sizeInFrames/2;
// On first call of this function we lazily pre-allocated a temp buffer to read audio files/memory data in // On first call of this function we lazily pre-allocated a temp buffer to read audio files/memory data in
@ -2009,7 +2007,7 @@ void UpdateMusicStream(Music music)
default: break; default: break;
} }
UpdateAudioStream(music.stream, AUDIO.System.pcmBuffer, framesToStream); UpdateAudioStreamInLockedState(music.stream, AUDIO.System.pcmBuffer, framesToStream);
music.stream.buffer->framesProcessed = music.stream.buffer->framesProcessed%music.frameCount; music.stream.buffer->framesProcessed = music.stream.buffer->framesProcessed%music.frameCount;
@ -2017,6 +2015,7 @@ void UpdateMusicStream(Music music)
{ {
if (!music.looping) if (!music.looping)
{ {
ma_mutex_unlock(&AUDIO.System.lock);
// Streaming is ending, we filled latest frames from input // Streaming is ending, we filled latest frames from input
StopMusicStream(music); StopMusicStream(music);
return; return;
@ -2024,9 +2023,7 @@ void UpdateMusicStream(Music music)
} }
} }
// NOTE: In case window is minimized, music stream is stopped, ma_mutex_unlock(&AUDIO.System.lock);
// just make sure to play again on window restore
if (IsMusicStreamPlaying(music)) PlayMusicStream(music);
} }
// Check if any music is playing // Check if any music is playing
@ -2150,6 +2147,13 @@ void UnloadAudioStream(AudioStream stream)
// NOTE 1: Only updates one buffer of the stream source: dequeue -> update -> queue // NOTE 1: Only updates one buffer of the stream source: dequeue -> update -> queue
// NOTE 2: To dequeue a buffer it needs to be processed: IsAudioStreamProcessed() // NOTE 2: To dequeue a buffer it needs to be processed: IsAudioStreamProcessed()
void UpdateAudioStream(AudioStream stream, const void *data, int frameCount) void UpdateAudioStream(AudioStream stream, const void *data, int frameCount)
{
ma_mutex_lock(&AUDIO.System.lock);
UpdateAudioStreamInLockedState(stream, data, frameCount);
ma_mutex_unlock(&AUDIO.System.lock);
}
void UpdateAudioStreamInLockedState(AudioStream stream, const void *data, int frameCount)
{ {
if (stream.buffer != NULL) if (stream.buffer != NULL)
{ {