Skip to content

Commit c7d9937

Browse files
committed
android: fix a bug in music handling,
- remove service_provider member from MusicManager, it is not needed - android handle a few special events
1 parent d4b5c64 commit c7d9937

File tree

4 files changed

+88
-18
lines changed

4 files changed

+88
-18
lines changed

src/executables/game/application.cpp

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,11 @@ void Application::handle_event(const SDL_Event& event) {
119119
m_is_running = false;
120120
}
121121

122+
// special event for android and IOS
123+
if (event.type == SDL_APP_TERMINATING) {
124+
m_is_running = false;
125+
}
126+
122127
auto handled = false;
123128

124129
for (const auto& scene : std::ranges::views::reverse(m_scene_stack)) {
@@ -301,7 +306,6 @@ void Application::initialize() {
301306
: 0s;
302307
auto start_execution_time = std::chrono::steady_clock::now();
303308

304-
305309
bool finished_loading = false;
306310

307311
// this is a duplicate of below in some cases, but it's just for the loading screen and can't be factored out easily
@@ -324,6 +328,15 @@ void Application::initialize() {
324328
if (event.type == SDL_QUIT) {
325329
m_is_running = false;
326330
}
331+
332+
// special event for android and IOS
333+
if (event.type == SDL_APP_TERMINATING) {
334+
m_is_running = false;
335+
}
336+
}
337+
338+
if (not m_is_running) {
339+
break;
327340
}
328341

329342
loading_screen.update();
@@ -355,12 +368,12 @@ void Application::initialize() {
355368

356369
const auto duration = std::chrono::milliseconds(SDL_GetTicks64() - start_time);
357370

358-
// we can reach this via SDL_QUIT or (not console::inMainLoop())
359-
if (not finished_loading) {
371+
// we can reach this via SDL_QUIT, SDL_APP_TERMINATING or (not console::inMainLoop())
372+
if (not finished_loading or not m_is_running) {
360373

361374
spdlog::debug("Aborted loading after {}", duration);
362375

363-
// just exit immediately, without cleaning up, since than we would have to cancel the loading thread somehow, which is way rto complicated, let the OS clean up our mess we create her xD
376+
// just exit immediately, without cleaning up, since than we would have to cancel the loading thread somehow, which is way to complicated, let the OS clean up our mess we created here xD
364377

365378
utils::exit(0);
366379
}

src/input/input.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,38 @@ input::InputManager::InputManager(const std::shared_ptr<Window>& window) {
151151
break;
152152
}
153153
break;
154+
//TODO(Totto): handle those types correctly, to e.g. pause the game automatically on background enter
155+
case SDL_APP_TERMINATING:
156+
/* Terminate the app.
157+
Shut everything down before returning from this function.
158+
*/
159+
return true;
160+
case SDL_APP_LOWMEMORY:
161+
/* You will get this when your app is paused and iOS wants more memory.
162+
Release as much memory as possible.
163+
*/
164+
return true;
165+
case SDL_APP_WILLENTERBACKGROUND:
166+
/* Prepare your app to go into the background. Stop loops, etc.
167+
This gets called when the user hits the home button, or gets a call.
168+
*/
169+
return true;
170+
case SDL_APP_DIDENTERBACKGROUND:
171+
/* This will get called if the user accepted whatever sent your app to the background.
172+
If the user got a phone call and canceled it, you'll instead get an SDL_APP_DID_ENTER_FOREGROUND event and restart your loops.
173+
When you get this, you have 5 seconds to save all your state or the app will be terminated.
174+
Your app is NOT active at this point.
175+
*/
176+
return true;
177+
case SDL_APP_WILLENTERFOREGROUND:
178+
/* This call happens when your app is coming back to the foreground.
179+
Restore all your state here.
180+
*/
181+
return true;
182+
case SDL_APP_DIDENTERFOREGROUND:
183+
154184
default:
185+
155186
break;
156187
}
157188

src/manager/music_manager.cpp

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@ MusicManager::MusicManager(ServiceProvider* service_provider, u8 channel_size)
1919
m_queued_music{ nullptr },
2020
m_channel_size{ channel_size },
2121
m_chunk_map{ std::unordered_map<std::string, Mix_Chunk*>{} },
22-
m_service_provider{ service_provider },
23-
m_volume{ m_service_provider->command_line_arguments().silent ? std::nullopt : std::optional{ 1.0F } } {
22+
m_volume{ service_provider->command_line_arguments().silent ? std::nullopt : std::optional{ 1.0F } } {
2423
if (s_instance != nullptr) {
25-
spdlog::error("it's not allowed to create more than one MusicManager instance");
24+
spdlog::error(
25+
"it's not allowed to create more than one MusicManager instance: {} != {}",
26+
static_cast<void*>(s_instance), static_cast<void*>(this)
27+
);
2628
return;
2729
}
2830

@@ -37,13 +39,21 @@ MusicManager::MusicManager(ServiceProvider* service_provider, u8 channel_size)
3739
throw helper::InitializationError{ fmt::format("Failed to initialize any audio codec: {}", SDL_GetError()) };
3840
}
3941

40-
// see: https://wiki.libsdl.org/SDL2_mixer/Mix_AllocateChannels
41-
auto allocated_channels = Mix_AllocateChannels(channel_size);
42-
if (allocated_channels != channel_size) {
43-
throw helper::InitializationError{ fmt::format(
44-
"Failed to initialize the requested channels, requested {} but only got {}: {}", channel_size,
45-
allocated_channels, SDL_GetError()
46-
) };
42+
// retrieve allocated channels
43+
auto allocated_channels = Mix_AllocateChannels(-1);
44+
45+
spdlog::debug("SDL_MIX: allocated_channels = {}", allocated_channels);
46+
47+
if (allocated_channels == 0) {
48+
49+
// see: https://wiki.libsdl.org/SDL2_mixer/Mix_AllocateChannels
50+
auto newly_allocated_channels = Mix_AllocateChannels(channel_size);
51+
if (newly_allocated_channels != channel_size) {
52+
throw helper::InitializationError{ fmt::format(
53+
"Failed to initialize the requested channels, requested {} but only got {}: {}", channel_size,
54+
newly_allocated_channels, SDL_GetError()
55+
) };
56+
}
4757
}
4858

4959
// 2 here means STEREO, note that channels above means tracks, e.g. simultaneous playing source that are mixed,
@@ -66,7 +76,10 @@ MusicManager::~MusicManager() noexcept {
6676
}
6777

6878
// stop sounds and free loaded data
69-
Mix_HaltChannel(-1);
79+
int result = Mix_HaltChannel(-1);
80+
if (result != 0) {
81+
spdlog::warn("Mix_HaltChannel failed with error: {}", SDL_GetError());
82+
}
7083

7184
if (m_music != nullptr) {
7285
Mix_FreeMusic(m_music);
@@ -79,8 +92,11 @@ MusicManager::~MusicManager() noexcept {
7992
for (const auto& [_, value] : m_chunk_map) {
8093
Mix_FreeChunk(value);
8194
}
95+
8296
Mix_CloseAudio();
8397
Mix_Quit();
98+
99+
s_instance = nullptr;
84100
}
85101

86102
std::optional<std::string> MusicManager::load_and_play_music(const std::filesystem::path& location, const usize delay) {
@@ -141,7 +157,11 @@ std::optional<std::string> MusicManager::load_and_play_music(const std::filesyst
141157
m_queued_music = music;
142158
m_delay = delay;
143159
Mix_HookMusicFinished([]() {
144-
assert(s_instance != nullptr and "there must be a MusicManager instance");
160+
// this can happen on e.g. android, where if we exit the application, we don't close the window, so its reused, but the music manager is destroyed, but the hook is called later xD
161+
/* if (s_instance == nullptr) {
162+
return;
163+
} */
164+
145165
s_instance->hook_music_finished();
146166
});
147167

@@ -232,7 +252,10 @@ void MusicManager::hook_music_finished() {
232252

233253
[[nodiscard]] bool MusicManager::validate_instance() {
234254
if (s_instance != this) {
235-
spdlog::error("this MusicManager instance is not the instance that is used globally");
255+
spdlog::error(
256+
"this MusicManager instance is not the instance that is used globally: {} != {}",
257+
static_cast<void*>(s_instance), static_cast<void*>(this)
258+
);
236259
return false;
237260
}
238261
return true;

src/manager/music_manager.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,19 @@ struct MusicManager final {
3030
std::unordered_map<std::string, Mix_Chunk*> m_chunk_map;
3131
static constexpr unsigned fade_ms = 500;
3232
usize m_delay = MusicManager::fade_ms;
33-
ServiceProvider* m_service_provider;
33+
3434
std::optional<double> m_volume;
3535
std::unordered_map<std::string, VolumeChangeFunction> m_volume_listeners;
3636

3737
public:
3838
explicit MusicManager(ServiceProvider* service_provider, u8 channel_size = 2);
39+
3940
MusicManager(const MusicManager&) = delete;
4041
MusicManager& operator=(const MusicManager&) = delete;
42+
4143
MusicManager(const MusicManager&&) = delete;
4244
MusicManager& operator=(MusicManager&&) = delete;
45+
4346
~MusicManager() noexcept;
4447

4548
std::optional<std::string>

0 commit comments

Comments
 (0)