Browse Source

🐞 Duplicate sounds: Fix data race

This fixes a data race by deleting the sound exactly when it finishes
playing.

Previously, a data race could happen in
`CleanupFinishedDuplicateSounds`, where the sound would be destroyed
while Aulib was reading from its buffer.
pull/1835/head
Gleb Mazovetskiy 5 years ago
parent
commit
559229dea1
  1. 1
      Source/effects.cpp
  2. 28
      Source/sound.cpp
  3. 1
      Source/sound.h
  4. 1
      Source/sound_stubs.cpp
  5. 5
      Source/utils/soundsample.h

1
Source/effects.cpp

@ -1295,7 +1295,6 @@ void sound_update()
}
stream_update();
CleanupFinishedDuplicateSounds();
}
void effects_cleanup_sfx()

28
Source/sound.cpp

@ -6,6 +6,7 @@
#include "sound.h"
#include <cstdint>
#include <list>
#include <memory>
#include <aulib.h>
@ -19,6 +20,7 @@
#include "storm/storm_sdl_rw.h"
#include "storm/storm.h"
#include "utils/log.hpp"
#include "utils/sdl_mutex.h"
#include "utils/stdcompat/optional.hpp"
#include "utils/stdcompat/shared_ptr_array.hpp"
#include "utils/stubs.h"
@ -65,13 +67,24 @@ void CleanupMusic()
#endif
}
std::vector<std::unique_ptr<SoundSample>> duplicateSounds;
std::list<std::unique_ptr<SoundSample>> duplicateSounds;
SDLMutexUniquePtr duplicateSoundsMutex;
SoundSample *DuplicateSound(const SoundSample &sound) {
auto duplicate = std::make_unique<SoundSample>();
if (duplicate->DuplicateFrom(sound) != 0)
return nullptr;
auto *result = duplicate.get();
duplicateSounds.push_back(std::move(duplicate));
{
SDLMutexLockGuard lock(duplicateSoundsMutex.get());
duplicateSounds.push_back(std::move(duplicate));
auto it = duplicateSounds.end();
--it;
result->SetFinishCallback([it](Aulib::Stream &stream) {
SDLMutexLockGuard lock(duplicateSoundsMutex.get());
duplicateSounds.erase(it);
});
}
return result;
}
@ -120,15 +133,6 @@ void ClearDuplicateSounds() {
duplicateSounds.clear();
}
void CleanupFinishedDuplicateSounds()
{
duplicateSounds.erase(
std::remove_if(duplicateSounds.begin(), duplicateSounds.end(), [](const auto &sound) {
return !sound->IsPlaying();
}),
duplicateSounds.end());
}
void snd_play_snd(TSnd *pSnd, int lVolume, int lPan)
{
DWORD tc;
@ -211,12 +215,14 @@ void snd_init()
LogVerbose(LogCategory::Audio, "Aulib sampleRate={} channels={} frameSize={} format={:#x}",
Aulib::sampleRate(), Aulib::channelCount(), Aulib::frameSize(), Aulib::sampleFormat());
duplicateSoundsMutex = SDLMutexUniquePtr { SDL_CreateMutex() };
gbSndInited = true;
}
void snd_deinit() {
if (gbSndInited) {
Aulib::quit();
duplicateSoundsMutex = nullptr;
}
gbSndInited = false;

1
Source/sound.h

@ -48,7 +48,6 @@ struct TSnd {
extern bool gbSndInited;
void ClearDuplicateSounds();
void CleanupFinishedDuplicateSounds();
void snd_stop_snd(TSnd *pSnd);
void snd_play_snd(TSnd *pSnd, int lVolume, int lPan);
std::unique_ptr<TSnd> sound_file_load(const char *path, bool stream = false);

1
Source/sound_stubs.cpp

@ -11,7 +11,6 @@ bool gbSoundOn;
// AllowShortFunctionsOnASingleLine: None
// clang-format off
void ClearDuplicateSounds() { }
void CleanupFinishedDuplicateSounds() { }
void snd_stop_snd(TSnd *pSnd) { }
void snd_play_snd(TSnd *pSnd, int lVolume, int lPan) { }
std::unique_ptr<TSnd> sound_file_load(const char *path, bool stream) { return nullptr; }

5
Source/utils/soundsample.h

@ -23,6 +23,11 @@ public:
void Stop();
int SetChunkStream(std::string filePath);
void SetFinishCallback(Aulib::Stream::Callback &&callback)
{
stream_->setFinishCallback(std::forward<Aulib::Stream::Callback>(callback));
}
/**
* @brief Sets the sample's WAV, FLAC, or Ogg/Vorbis data.
* @param fileData Buffer containing the data

Loading…
Cancel
Save