Fix music never playing - game speed nearly doubled (task #49)
Channel::isPlaying answered FALSE for a channel System::playSound had just
handed out with a success code. The guest polled it, concluded the track
had finished, and started the next one - forever. Each cycle reopened the
OBB asset filesystem ON THE GLThread, stalling frames directly.
Found from a user observation ("треки меняются очень быстро в меню паузы"),
then measured: a different track roughly every 1.5s, picked
non-sequentially (DEAD SARA, DEAD SARA, GREEN DAY, SKRILLEX, GREEN DAY,
CROSSES, ICONA POP, JOY FORMIDABLE), so not a walk through playlists.sb but
a fresh selection each time.
Now tracks the channels playSound hands out and reports those as playing
until Channel::stop drops them, so normal transitions still work. A
one-time log states plainly that there is no audio backend and playback is
simulated, instead of leaving that only in a comment.
Measured on the Pixel 6a with the race's own clock, same method both times:
game time vs wall clock 7.69x -> 3.99x
useAssetsFileSystem 1.00/s -> 0.00/s (in-race, fully stopped)
faults 0 -> 0
27s of wall time advanced the race timer 18.82 -> 25.58 (6.76s); the two
sub-intervals gave 4.18x and 3.81x.
Third instance today of one failure shape: a shim reporting SUCCESS while
handing back an empty or negative value. See AndroidBitmap_lockPixels
(task #41) and the synthetic-swap premise (task #47).
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
#include "fmod_shims.h"
|
||||
#include <cstring>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -256,9 +258,37 @@ uint32_t Shim_System_getSoftwareFormat(GuestEngine& eng, uint32_t, uint32_t out1
|
||||
}
|
||||
uint32_t Shim_System_setSoftwareFormat(GuestEngine&, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t) { return kFmodOk; }
|
||||
uint32_t Shim_System_set3DSpeakerPosition(GuestEngine&, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t) { return kFmodOk; }
|
||||
// FIX (2026-09-19, task #49). Channels handed out by System::playSound and
|
||||
// not yet stopped. Without this the music never played: playSound reported
|
||||
// success and returned a fake channel, then Channel::isPlaying answered
|
||||
// FALSE for it, so the game concluded the track had finished and immediately
|
||||
// started the next one - forever. Measured in the pause menu: a different
|
||||
// track roughly every 1.5s, picked non-sequentially (DEAD SARA, DEAD SARA,
|
||||
// GREEN DAY, SKRILLEX, GREEN DAY, CROSSES, ICONA POP, JOY FORMIDABLE), so
|
||||
// not a walk through playlists.sb but a fresh selection each time.
|
||||
//
|
||||
// Third instance today of the same failure shape - a shim reporting SUCCESS
|
||||
// while handing back an empty/negative value (see AndroidBitmap_lockPixels
|
||||
// in gles_shim.cpp, task #41). Hence the log below: this engine has no audio
|
||||
// backend, so playback here is simulated, and that fact belongs in the log
|
||||
// rather than only in a comment.
|
||||
std::set<uint32_t> g_playingChannels;
|
||||
std::mutex g_playingChannelsMutex;
|
||||
|
||||
uint32_t Shim_System_playSound(GuestEngine& eng, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t sp) {
|
||||
uint32_t out = eng.ReadIncomingArg(4, 0, 0, 0, 0, sp); // 5th total arg (this,channelid,sound,paused,+channel**)
|
||||
OutPtr(eng, out, FakeHandle(eng));
|
||||
GuestAddr channel = FakeHandle(eng);
|
||||
OutPtr(eng, out, channel);
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(g_playingChannelsMutex);
|
||||
g_playingChannels.insert(channel);
|
||||
}
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [] {
|
||||
Log("fmod_shims: no audio backend - System::playSound will report channels as PLAYING until "
|
||||
"the guest stops them. Sound is silent by design; without this the guest sees every track "
|
||||
"finish instantly and thrashes through the playlist (task #49).");
|
||||
});
|
||||
return kFmodOk;
|
||||
}
|
||||
uint32_t Shim_System_setOutput(GuestEngine&, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t) { return kFmodOk; }
|
||||
@@ -266,14 +296,29 @@ uint32_t Shim_System_setOutput(GuestEngine&, uint32_t, uint32_t, uint32_t, uint3
|
||||
// ---- Channel ----
|
||||
uint32_t Shim_Channel_setCallback(GuestEngine&, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t) { return kFmodOk; }
|
||||
uint32_t Shim_Channel_setPriority(GuestEngine&, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t) { return kFmodOk; }
|
||||
uint32_t Shim_Channel_stop(GuestEngine&, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t) { return kFmodOk; }
|
||||
uint32_t Shim_Channel_stop(GuestEngine&, uint32_t r0, uint32_t, uint32_t, uint32_t, uint32_t) {
|
||||
// r0 is `this`. Dropping it here is what lets the guest end a track on its
|
||||
// own terms - the next isPlaying() then honestly answers false, so normal
|
||||
// transitions (race ends, menu change) still work.
|
||||
std::lock_guard<std::mutex> lock(g_playingChannelsMutex);
|
||||
g_playingChannels.erase(r0);
|
||||
return kFmodOk;
|
||||
}
|
||||
uint32_t Shim_Channel_setMute(GuestEngine&, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t) { return kFmodOk; }
|
||||
uint32_t Shim_Channel_getPaused(GuestEngine& eng, uint32_t, uint32_t out, uint32_t, uint32_t, uint32_t) {
|
||||
OutBool(eng, out, false);
|
||||
return kFmodOk;
|
||||
}
|
||||
uint32_t Shim_Channel_isPlaying(GuestEngine& eng, uint32_t, uint32_t out, uint32_t, uint32_t, uint32_t) {
|
||||
OutBool(eng, out, false);
|
||||
uint32_t Shim_Channel_isPlaying(GuestEngine& eng, uint32_t r0, uint32_t out, uint32_t, uint32_t, uint32_t) {
|
||||
// See g_playingChannels' comment. Answering "playing" only for channels we
|
||||
// actually handed out - rather than a blanket true - keeps a stale or
|
||||
// never-started channel honest.
|
||||
bool playing;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(g_playingChannelsMutex);
|
||||
playing = g_playingChannels.count(r0) != 0;
|
||||
}
|
||||
OutBool(eng, out, playing);
|
||||
return kFmodOk;
|
||||
}
|
||||
uint32_t Shim_Channel_setPaused(GuestEngine&, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t) { return kFmodOk; }
|
||||
|
||||
Reference in New Issue
Block a user