Always clamp 'frames_needed' to the allowed mix/max range in the mixer

This fixes tripping the check_casts at the start of `MIXER_MixData` when
putting your laptop to sleep on macOS when audio playback is active.
Probably it fixes all sorts of other weird edge cases.

This is a medium-term solution to ensure safety until the mixer code is
thorougly refactored. Triggering and/or understanding all the special
cases when the 'frames_needed' under/overshoot can happen is rather
tricky with the current code.
This commit is contained in:
John Novak 2023-09-07 09:22:46 +10:00 committed by John Novak
parent dfc3d0a5a3
commit a25af54d53

View file

@ -221,6 +221,16 @@ static struct mixer_t mixer = {};
alignas(sizeof(float)) uint8_t MixTemp[MixerBufferLength] = {};
// TODO Once the mixer code is thorougly refactored, revisit whether this is
// still necessary (i.e., we might be able to be more precise with our
// 'frames_needed' calculation so we never under or overshoot).
static int clamp_frames_needed(const int frames_needed)
{
return clamp(frames_needed,
mixer.min_frames_needed.load(),
mixer.max_frames_needed.load());
}
uint16_t MIXER_GetPreBufferMs()
{
assert(mixer.prebuffer_ms > 0);
@ -897,7 +907,8 @@ void MixerChannel::Mix(const uint16_t frames_requested)
return;
}
frames_needed = frames_requested;
frames_needed = clamp_frames_needed(frames_requested);
while (frames_needed > frames_done) {
auto frames_remaining = frames_needed - frames_done;
frames_remaining *= freq_add;
@ -2105,7 +2116,11 @@ static void MIXER_Mix()
MIXER_MixData(mixer.frames_needed);
mixer.tick_counter += mixer.tick_add;
mixer.frames_needed += mixer.tick_counter >> TickShift;
const auto frames_needed = mixer.frames_needed +
(mixer.tick_counter >> TickShift);
mixer.frames_needed = clamp_frames_needed(frames_needed);
mixer.tick_counter &= TickMask;
MIXER_UnlockAudioDevice();
@ -2137,7 +2152,7 @@ static void MIXER_Mix_NoSound()
/* Set values for next tick */
mixer.tick_counter += mixer.tick_add;
mixer.frames_needed = (mixer.tick_counter >> TickShift);
mixer.frames_needed = clamp_frames_needed(mixer.tick_counter >> TickShift);
mixer.tick_counter &= TickMask;
mixer.frames_done = 0;
@ -2267,7 +2282,9 @@ static void SDLCALL MIXER_CallBack([[maybe_unused]] void* userdata,
}
mixer.frames_done -= reduce_frames;
mixer.frames_needed -= reduce_frames;
const auto frames_needed = mixer.frames_needed - reduce_frames;
mixer.frames_needed = clamp_frames_needed(frames_needed);
pos = mixer.pos;
mixer.pos = check_cast<work_index_t>((mixer.pos + reduce_frames) &
@ -2888,7 +2905,7 @@ void MIXER_Init(Section* sec)
mixer.pos = 0;
mixer.frames_done = 0;
mixer.frames_needed = mixer.min_frames_needed + 1;
mixer.frames_needed = clamp_frames_needed(mixer.min_frames_needed + 1);
mixer.min_frames_needed = 0;
mixer.max_frames_needed = mixer.blocksize * 2 + 2 * prebuffer_frames;