Skip to content

Commit

Permalink
Fix #17297: Crash when switching language (#17370)
Browse files Browse the repository at this point in the history
* Refactor all uses of IAudioChannel and the audio mixer.
* Use shared_ptr to avoid dead pointers hanging about.
* Reload particular audio channels where necessary after object reload.
  • Loading branch information
IntelOrca committed Jun 27, 2022
1 parent 0d6a8af commit 585ebed
Show file tree
Hide file tree
Showing 32 changed files with 257 additions and 395 deletions.
15 changes: 13 additions & 2 deletions src/openrct2-ui/UiContext.cpp
Expand Up @@ -31,6 +31,7 @@
#include <openrct2/Context.h>
#include <openrct2/Input.h>
#include <openrct2/Version.h>
#include <openrct2/audio/AudioContext.h>
#include <openrct2/audio/AudioMixer.h>
#include <openrct2/config/Config.h>
#include <openrct2/core/String.hpp>
Expand Down Expand Up @@ -382,11 +383,11 @@ class UiContext final : public IUiContext
{
if (e.window.event == SDL_WINDOWEVENT_FOCUS_GAINED)
{
Mixer_SetVolume(1);
SetAudioVolume(1);
}
if (e.window.event == SDL_WINDOWEVENT_FOCUS_LOST)
{
Mixer_SetVolume(0);
SetAudioVolume(0);
}
}
break;
Expand Down Expand Up @@ -986,6 +987,16 @@ class UiContext final : public IUiContext

return ie;
}

void SetAudioVolume(float value)
{
auto audioContext = GetContext()->GetAudioContext();
auto mixer = audioContext->GetMixer();
if (mixer != nullptr)
{
mixer->SetVolume(value);
}
}
};

std::unique_ptr<IUiContext> OpenRCT2::Ui::CreateUiContext(const std::shared_ptr<IPlatformEnvironment>& env)
Expand Down
9 changes: 7 additions & 2 deletions src/openrct2-ui/audio/AudioChannel.cpp
Expand Up @@ -19,7 +19,7 @@

namespace OpenRCT2::Audio
{
template<typename AudioSource_ = SDLAudioSource> class AudioChannelImpl : public ISDLAudioChannel
template<typename AudioSource_ = SDLAudioSource> class AudioChannelImpl final : public ISDLAudioChannel
{
static_assert(std::is_base_of_v<IAudioSource, AudioSource_>);

Expand Down Expand Up @@ -185,7 +185,7 @@ namespace OpenRCT2::Audio
return _stopping;
}

void SetStopping(bool value) override
void SetStopping(bool value) final override
{
_stopping = value;
}
Expand Down Expand Up @@ -223,6 +223,11 @@ namespace OpenRCT2::Audio
_done = false;
}

void Stop() override
{
SetStopping(true);
}

void UpdateOldVolume() override
{
_oldvolume = _volume;
Expand Down
16 changes: 0 additions & 16 deletions src/openrct2-ui/audio/AudioContext.cpp
Expand Up @@ -128,19 +128,6 @@ namespace OpenRCT2::Audio
{
}

IAudioChannel* PlaySound(int32_t soundId, int32_t volume, int32_t pan) override
{
return nullptr;
}
IAudioChannel* PlaySoundAtLocation(int32_t soundId, int16_t x, int16_t y, int16_t z) override
{
return nullptr;
}
IAudioChannel* PlaySoundPanned(int32_t soundId, int32_t pan, int16_t x, int16_t y, int16_t z) override
{
return nullptr;
}

void ToggleAllSounds() override
{
}
Expand All @@ -157,9 +144,6 @@ namespace OpenRCT2::Audio
void StopCrowdSound() override
{
}
void StopWeatherSound() override
{
}
void StopRideMusic() override
{
}
Expand Down
21 changes: 5 additions & 16 deletions src/openrct2-ui/audio/AudioMixer.cpp
Expand Up @@ -51,10 +51,6 @@ void AudioMixer::Close()
{
// Free channels
Lock();
for (IAudioChannel* channel : _channels)
{
delete channel;
}
_channels.clear();
Unlock();

Expand All @@ -79,10 +75,10 @@ void AudioMixer::Unlock()
SDL_UnlockAudioDevice(_deviceId);
}

IAudioChannel* AudioMixer::Play(IAudioSource* source, int32_t loop, bool deleteondone)
std::shared_ptr<IAudioChannel> AudioMixer::Play(IAudioSource* source, int32_t loop, bool deleteondone)
{
Lock();
auto* channel = AudioChannel::Create();
auto channel = std::shared_ptr<ISDLAudioChannel>(AudioChannel::Create());
if (channel != nullptr)
{
channel->Play(source, loop);
Expand All @@ -93,13 +89,6 @@ IAudioChannel* AudioMixer::Play(IAudioSource* source, int32_t loop, bool deleteo
return channel;
}

void AudioMixer::Stop(IAudioChannel* channel)
{
Lock();
channel->SetStopping(true);
Unlock();
}

void AudioMixer::SetVolume(float volume)
{
_volume = volume;
Expand Down Expand Up @@ -146,12 +135,12 @@ void AudioMixer::GetNextAudioChunk(uint8_t* dst, size_t length)
auto it = _channels.begin();
while (it != _channels.end())
{
auto channel = *it;
auto& channel = *it;
auto channelSource = channel->GetSource();
auto channelSourceReleased = channelSource == nullptr || channelSource->IsReleased();
if (channelSourceReleased || (channel->IsDone() && channel->DeleteOnDone()) || channel->IsStopping())
{
delete channel;
channel->SetDone(true);
it = _channels.erase(it);
}
else
Expand All @@ -160,7 +149,7 @@ void AudioMixer::GetNextAudioChunk(uint8_t* dst, size_t length)
if ((group != MixerGroup::Sound || gConfigSound.sound_enabled) && gConfigSound.master_sound_enabled
&& gConfigSound.master_volume != 0)
{
MixChannel(channel, dst, length);
MixChannel(channel.get(), dst, length);
}
it++;
}
Expand Down
5 changes: 2 additions & 3 deletions src/openrct2-ui/audio/AudioMixer.h
Expand Up @@ -33,7 +33,7 @@ namespace OpenRCT2::Audio

SDL_AudioDeviceID _deviceId = 0;
AudioFormat _format = {};
std::list<ISDLAudioChannel*> _channels;
std::list<std::shared_ptr<ISDLAudioChannel>> _channels;
float _volume = 1.0f;
float _adjustSoundVolume = 0.0f;
float _adjustMusicVolume = 0.0f;
Expand All @@ -52,8 +52,7 @@ namespace OpenRCT2::Audio
void Close() override;
void Lock() override;
void Unlock() override;
IAudioChannel* Play(IAudioSource* source, int32_t loop, bool deleteondone) override;
void Stop(IAudioChannel* channel) override;
std::shared_ptr<IAudioChannel> Play(IAudioSource* source, int32_t loop, bool deleteondone) override;
void SetVolume(float volume) override;
SDLAudioSource* AddSource(std::unique_ptr<SDLAudioSource> source);

Expand Down
3 changes: 3 additions & 0 deletions src/openrct2-ui/audio/FlacAudioSource.cpp
Expand Up @@ -9,9 +9,12 @@

#include "SDLAudioSource.h"

#include <stdexcept>

#ifndef DISABLE_FLAC
# include <FLAC/all.h>
# include <SDL.h>
# include <cstring>
# include <vector>
#endif

Expand Down
1 change: 1 addition & 0 deletions src/openrct2-ui/audio/MemoryAudioSource.cpp
Expand Up @@ -15,6 +15,7 @@
#include <algorithm>
#include <openrct2/audio/AudioSource.h>
#include <openrct2/common.h>
#include <stdexcept>
#include <vector>

namespace OpenRCT2::Audio
Expand Down
2 changes: 2 additions & 0 deletions src/openrct2-ui/audio/OggAudioSource.cpp
Expand Up @@ -9,6 +9,8 @@

#include "SDLAudioSource.h"

#include <stdexcept>

#ifndef DISABLE_VORBIS
# include <SDL.h>
# include <optional>
Expand Down
11 changes: 11 additions & 0 deletions src/openrct2-ui/audio/SDLAudioSource.cpp
@@ -1,5 +1,16 @@
/*****************************************************************************
* Copyright (c) 2014-2022 OpenRCT2 developers
*
* For a complete list of all authors, please refer to contributors.md
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/

#include "SDLAudioSource.h"

#include <stdexcept>

using namespace OpenRCT2::Audio;

enum class AudioCodecKind
Expand Down
1 change: 1 addition & 0 deletions src/openrct2-ui/audio/WavAudioSource.cpp
Expand Up @@ -10,6 +10,7 @@
#include "SDLAudioSource.h"

#include <SDL.h>
#include <stdexcept>

namespace OpenRCT2::Audio
{
Expand Down
2 changes: 1 addition & 1 deletion src/openrct2-ui/libopenrct2ui.vcxproj
Expand Up @@ -232,4 +232,4 @@
</Lib>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>
</Project>
16 changes: 10 additions & 6 deletions src/openrct2-ui/windows/Options.cpp
Expand Up @@ -22,6 +22,7 @@
#include <openrct2-ui/windows/Window.h>
#include <openrct2/Context.h>
#include <openrct2/actions/ScenarioSetSettingAction.h>
#include <openrct2/audio/AudioContext.h>
#include <openrct2/audio/AudioMixer.h>
#include <openrct2/audio/audio.h>
#include <openrct2/config/Config.h>
Expand All @@ -44,6 +45,9 @@
#include <openrct2/ui/UiContext.h>
#include <openrct2/util/Util.h>

using namespace OpenRCT2;
using namespace OpenRCT2::Audio;

// clang-format off
enum WindowOptionsPage {
WINDOW_OPTIONS_PAGE_DISPLAY,
Expand Down Expand Up @@ -1384,17 +1388,17 @@ class OptionsWindow final : public Window
OpenRCT2::Audio::InitRideSounds(dropdownIndex);
if (dropdownIndex < OpenRCT2::Audio::GetDeviceCount())
{
auto audioContext = GetContext()->GetAudioContext();
if (dropdownIndex == 0)
{
Mixer_Init(nullptr);
gConfigSound.device = nullptr;
audioContext->SetOutputDevice("");
gConfigSound.device = "";
}
else
{
const char* devicename = OpenRCT2::Audio::GetDeviceName(dropdownIndex).c_str();
Mixer_Init(devicename);
SafeFree(gConfigSound.device);
gConfigSound.device = strndup(devicename, OpenRCT2::Audio::MaxDeviceNameSize);
const auto& deviceName = GetDeviceName(dropdownIndex);
audioContext->SetOutputDevice(deviceName);
gConfigSound.device = deviceName;
}
config_save_default();
OpenRCT2::Audio::PlayTitleMusic();
Expand Down
20 changes: 10 additions & 10 deletions src/openrct2/Intro.cpp
Expand Up @@ -10,11 +10,14 @@
#include "Intro.h"

#include "Context.h"
#include "audio/AudioChannel.h"
#include "audio/AudioMixer.h"
#include "audio/audio.h"
#include "drawing/Drawing.h"
#include "sprites.h"

using namespace OpenRCT2::Audio;

#define BACKROUND_COLOUR_DARK PALETTE_INDEX_10
#define BACKROUND_COLOUR_LOGO PALETTE_INDEX_245
#define BORDER_COLOUR_PUBLISHER PALETTE_INDEX_129
Expand All @@ -27,7 +30,7 @@ IntroState gIntroState;
// Used mainly for timing but also for Y coordinate and fading.
static int32_t _introStateCounter;

static void* _soundChannel = nullptr;
static std::shared_ptr<IAudioChannel> _soundChannel = nullptr;
static bool _chainLiftFinished;

static void screen_intro_process_mouse_input();
Expand Down Expand Up @@ -55,8 +58,7 @@ void intro_update()
_introStateCounter = -580;

// Play the chain lift sound
_soundChannel = Mixer_Play_Effect(
OpenRCT2::Audio::SoundId::LiftBM, MIXER_LOOP_INFINITE, MIXER_VOLUME_MAX, 0.5f, 1, true);
_soundChannel = CreateAudioChannel(SoundId::LiftBM, true);
_chainLiftFinished = false;
gIntroState = IntroState::PublisherScroll;
break;
Expand Down Expand Up @@ -89,13 +91,12 @@ void intro_update()
// Stop the chain lift sound
if (_soundChannel != nullptr)
{
Mixer_Stop_Channel(_soundChannel);
_soundChannel->Stop();
_soundChannel = nullptr;
}

// Play the track friction sound
_soundChannel = Mixer_Play_Effect(
OpenRCT2::Audio::SoundId::TrackFrictionBM, MIXER_LOOP_INFINITE, MIXER_VOLUME_MAX, 0.25f, 0.75, true);
_soundChannel = CreateAudioChannel(SoundId::TrackFrictionBM, true, MIXER_VOLUME_MAX, 0.25f, 0.75);
}

// Check if logo is off the screen...ish
Expand All @@ -104,13 +105,12 @@ void intro_update()
// Stop the track friction sound
if (_soundChannel != nullptr)
{
Mixer_Stop_Channel(_soundChannel);
_soundChannel->Stop();
_soundChannel = nullptr;
}

// Play long peep scream sound
_soundChannel = Mixer_Play_Effect(
OpenRCT2::Audio::SoundId::Scream1, MIXER_LOOP_NONE, MIXER_VOLUME_MAX, 0.5f, 1, false);
_soundChannel = CreateAudioChannel(SoundId::Scream1);

gIntroState = IntroState::LogoFadeIn;
_introStateCounter = 0;
Expand Down Expand Up @@ -148,7 +148,7 @@ void intro_update()
// Stop any playing sound
if (_soundChannel != nullptr)
{
Mixer_Stop_Channel(_soundChannel);
_soundChannel->Stop();
_soundChannel = nullptr;
}

Expand Down

0 comments on commit 585ebed

Please sign in to comment.