Skip to content

Commit 0641dd8

Browse files
author
Dextinfire
committed
Merge pull request #472 from egyzol/detect-device-change
Detect audio device changes crossplatform
2 parents d6b310f + 0637c25 commit 0641dd8

18 files changed

Lines changed: 171 additions & 1 deletion

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,6 +1003,7 @@ if (EMSCRIPTEN)
10031003
string(REPLACE "-O2" "" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
10041004
string(REPLACE "-O2" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
10051005
string(REPLACE "-O2" "" CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}")
1006+
add_definitions(-DIMPACTO_OPENAL_HAVE_ALEXT)
10061007
else ()
10071008
find_package(SDL2 CONFIG REQUIRED)
10081009
find_package(ZLIB REQUIRED)
@@ -1028,6 +1029,7 @@ else ()
10281029
drm_nouveau
10291030
nx
10301031
)
1032+
add_definitions(-DIMPACTO_OPENAL_HAVE_ALEXT)
10311033
else ()
10321034
find_package(Ogg CONFIG REQUIRED)
10331035
find_package(Vorbis CONFIG REQUIRED)

src/audio/audiobackend.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,13 @@ class AudioBackend {
99
public:
1010
virtual bool Init() { return true; };
1111

12+
virtual bool Reinit() { return true; };
13+
1214
virtual void Shutdown() {};
15+
16+
virtual bool DidDeviceChanged() { return false; };
17+
18+
virtual bool ReopenSupported() { return false; }
1319
};
1420

1521
} // namespace Audio

src/audio/audiochannel.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ class AudioChannel {
2525
virtual void Stop(float fadeOutDuration) = 0;
2626
virtual void Pause() = 0;
2727
virtual void Resume() = 0;
28+
virtual void Reinit() = 0;
2829

2930
virtual void Update(float dt) = 0;
3031
virtual float PositionInSeconds() const = 0;
@@ -82,6 +83,8 @@ class EmptyAudioChannel : public AudioChannel {
8283
if (State == ACS_Paused) State = ACS_Playing;
8384
}
8485

86+
void Reinit() override {}
87+
8588
void Update(float dt) override {}
8689

8790
float PositionInSeconds() const override { return 0; }

src/audio/audiosystem.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,22 @@ void AudioInit() {
190190
IsInit = true;
191191
}
192192

193+
void AudioReinit() {
194+
if (Backend->Reinit()) {
195+
ImpLog(LogLevel::Info, LogChannel::Audio, "Reinitializing audio system\n");
196+
if (Backend->ReopenSupported()) return;
197+
}
198+
199+
for (int i = AC_SE0; i <= AC_SE2; i++) Channels[i]->Reinit();
200+
for (int i = AC_VOICE0; i <= AC_REV; i++) Channels[i]->Reinit();
201+
for (int i = AC_BGM0; i <= AC_BGM2; i++) Channels[i]->Reinit();
202+
203+
Channels[AC_SSE0]->Reinit();
204+
Channels[AC_SSE1]->Reinit();
205+
Channels[AC_SSE2]->Reinit();
206+
Channels[AC_SSE3]->Reinit();
207+
}
208+
193209
void AudioSubtitlesStart(AudioChannel* channel) {
194210
using Profile::Subtitle::SubtitleMappings;
195211
std::optional<Subtitle::SubtitlePlayer> player;

src/audio/audiosystem.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ namespace Audio {
1414
void AudioInit();
1515
void AudioUpdate(float dt);
1616
void AudioShutdown();
17+
void AudioReinit();
1718

1819
void AudioSubtitlesStart(AudioChannel* channel);
1920
void AudioSubtitlesUpdate();

src/audio/ffmpegaudioplayer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ class FFmpegAudioPlayer {
1919
virtual void InitConvertContext(AVCodecContext* codecCtx) {};
2020
virtual void FillAudioBuffers() {};
2121
virtual void Process() {};
22+
virtual void Reinit() {};
2223

2324
virtual void Stop() {};
2425
virtual void Unload() {};

src/audio/openal/audiobackend.cpp

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,19 @@ namespace OpenAL {
88

99
static ALCdevice* AlcDevice = 0;
1010
static ALCcontext* AlcContext = 0;
11+
static bool IsReopenSupported = false;
12+
#if ALC_SOFT_system_events
13+
static LPALCEVENTCALLBACKSOFT EventCallBackFunc = 0;
14+
static LPALCEVENTCONTROLSOFT EventControlFunc = 0;
15+
#endif
16+
#if ALC_SOFT_reopen_device
17+
static LPALCREOPENDEVICESOFT ReopenSoftFunc = 0;
18+
#endif
19+
void AL_APIENTRY DefaultDeviceChangedEventCallback(
20+
ALCenum eventType, ALCenum deviceType, ALCdevice* device, ALCsizei length,
21+
const ALCchar* message, void* userParam) {
22+
*(bool*)userParam = true;
23+
}
1124

1225
bool AudioBackend::Init() {
1326
AlcDevice = alcOpenDevice(NULL);
@@ -16,10 +29,41 @@ bool AudioBackend::Init() {
1629
"Could not create OpenAL device\n");
1730
return false;
1831
}
32+
AlcContext = alcCreateContext(AlcDevice, NULL);
33+
if (!AlcContext || !alcMakeContextCurrent(AlcContext)) {
34+
ImpLog(LogLevel::Fatal, LogChannel::Audio,
35+
"Failed to create OpenAL context\n");
36+
alcCloseDevice(AlcDevice);
37+
return false;
38+
}
1939
if (alIsExtensionPresent("AL_EXT_float32") == AL_FALSE) {
2040
ImpLog(LogLevel::Error, LogChannel::Audio,
2141
"No floating-point audio support, some decoders may fail\n");
2242
}
43+
InitAlextFunctions();
44+
return true;
45+
}
46+
47+
bool AudioBackend::Reinit() {
48+
DeviceChanged = false;
49+
#if ALC_SOFT_reopen_device
50+
if (IsReopenSupported) {
51+
if (ReopenSoftFunc) {
52+
return ReopenSoftFunc(AlcDevice, NULL, NULL);
53+
} else {
54+
ImpLog(LogLevel::Error, LogChannel::Audio,
55+
"Reopen support is present but function was not found falling "
56+
"back to manual reopen\n");
57+
}
58+
}
59+
#endif
60+
Shutdown();
61+
AlcDevice = alcOpenDevice(NULL);
62+
if (!AlcDevice) {
63+
ImpLog(LogLevel::Fatal, LogChannel::Audio,
64+
"Could not create OpenAL device\n");
65+
return false;
66+
}
2367
AlcContext = alcCreateContext(AlcDevice, NULL);
2468
if (!AlcContext || !alcMakeContextCurrent(AlcContext)) {
2569
ImpLog(LogLevel::Fatal, LogChannel::Audio,
@@ -35,6 +79,49 @@ void AudioBackend::Shutdown() {
3579
if (AlcDevice) alcCloseDevice(AlcDevice);
3680
}
3781

82+
bool AudioBackend::DidDeviceChanged() { return DeviceChanged; }
83+
84+
bool AudioBackend::ReopenSupported() {
85+
#if ALC_SOFT_reopen_device
86+
return IsReopenSupported && ReopenSoftFunc && EventControlFunc &&
87+
EventCallBackFunc;
88+
#else
89+
return false;
90+
#endif
91+
}
92+
93+
void AudioBackend::InitAlextFunctions() {
94+
#if ALC_SOFT_system_events
95+
if (alcIsExtensionPresent(AlcDevice, "ALC_SOFT_system_events") == AL_TRUE) {
96+
EventControlFunc = (LPALCEVENTCONTROLSOFT)alcGetProcAddress(
97+
AlcDevice, "alcEventControlSOFT");
98+
if (EventControlFunc) {
99+
const ALCenum eventType{ALC_EVENT_TYPE_DEFAULT_DEVICE_CHANGED_SOFT};
100+
EventControlFunc(1, &eventType, AL_TRUE);
101+
}
102+
103+
EventCallBackFunc = (LPALCEVENTCALLBACKSOFT)alcGetProcAddress(
104+
AlcDevice, "alcEventCallbackSOFT");
105+
if (EventCallBackFunc) {
106+
EventCallBackFunc((ALCEVENTPROCTYPESOFT)DefaultDeviceChangedEventCallback,
107+
&DeviceChanged);
108+
}
109+
#if ALC_SOFT_reopen_device
110+
if (alcIsExtensionPresent(AlcDevice, "ALC_SOFT_reopen_device") ==
111+
AL_FALSE) {
112+
ImpLog(LogLevel::Error, LogChannel::Audio,
113+
"No device reopen support,will be done manually\n");
114+
} else {
115+
IsReopenSupported = true;
116+
ReopenSoftFunc = (LPALCREOPENDEVICESOFT)alcGetProcAddress(
117+
AlcDevice, "alcReopenDeviceSOFT");
118+
if (!ReopenSoftFunc) IsReopenSupported = false;
119+
}
120+
#endif
121+
}
122+
#endif
123+
}
124+
38125
}; // namespace OpenAL
39126
}; // namespace Audio
40127
}; // namespace Impacto

src/audio/openal/audiobackend.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,20 @@ namespace Audio {
88
namespace OpenAL {
99

1010
class AudioBackend : public Audio::AudioBackend {
11+
private:
12+
bool DeviceChanged = false;
13+
void InitAlextFunctions();
14+
1115
public:
1216
bool Init() override;
1317

18+
bool Reinit() override;
19+
1420
void Shutdown() override;
21+
22+
bool DidDeviceChanged() override;
23+
24+
bool ReopenSupported() override;
1525
};
1626

1727
} // namespace OpenAL

src/audio/openal/ffmpegaudioplayer.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,18 @@ void FFmpegAudioPlayer::Init() {
3737
alGenBuffers(AudioBufferCount, BufferIds);
3838
}
3939

40+
void FFmpegAudioPlayer::Reinit() {
41+
alGenSources(1, &ALSource);
42+
alSourcef(ALSource, AL_PITCH, 1);
43+
alSourcef(ALSource, AL_GAIN, 1);
44+
alSource3f(ALSource, AL_POSITION, 0, 0, 0);
45+
alSource3f(ALSource, AL_VELOCITY, 0, 0, 0);
46+
alSourcei(ALSource, AL_LOOPING, AL_FALSE);
47+
48+
alGenBuffers(AudioBufferCount, BufferIds);
49+
First = true;
50+
}
51+
4052
void FFmpegAudioPlayer::InitConvertContext(AVCodecContext* codecCtx) {
4153
AVChannelLayout stereoFormat;
4254
av_channel_layout_default(&stereoFormat, 2);
@@ -126,6 +138,7 @@ void FFmpegAudioPlayer::Process() {
126138
alGetSourcei(ALSource, AL_BUFFERS_PROCESSED, &FreeBufferCount);
127139
if (First) {
128140
FreeBufferCount = AudioBufferCount;
141+
FirstFreeBuffer = 0;
129142
}
130143

131144
int currentlyPlayingBuffer =

src/audio/openal/ffmpegaudioplayer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class FFmpegAudioPlayer : public Audio::FFmpegAudioPlayer {
1818
void InitConvertContext(AVCodecContext* codecCtx) override;
1919
void FillAudioBuffers() override;
2020
void Process() override;
21+
void Reinit() override;
2122

2223
void Stop() override;
2324
void Unload() override;

0 commit comments

Comments
 (0)