miniaudio: bound the OpenSL ES buffer-queue drain - #19
Merged
Conversation
ma_device_drain__opensl() spins in an unbounded for(;;)/ma_sleep(10) loop until the buffer queue reports empty, with no timeout and no iteration cap. If the OpenSL callback thread stops servicing the queue -- audioserver hiccup, route change, device disconnect -- the count never reaches zero and ma_device_stop() never returns (alnitak#333). Since the audio device is stopped on every idle timeout to release the audioserver AudioMix partial wakelock, that is an unrecoverable hang on a routine path. miniaudio itself disabled the equivalent stop inside ma_device_uninit() for the same reason; see its "can result in a deadlock" comment there. The queue can only legitimately hold `periods` buffers of `periodSizeInFrames`, so the wait is capped at twice that duration, clamped to [200ms, 1000ms]. Bailing out is safe: both callers in ma_device_stop__opensl() immediately follow the drain with SetPlayState(SL_PLAYSTATE_STOPPED) and Clear() on the same queue, so the worst case is discarding a few milliseconds of tail audio that Clear() was going to discard anyway. This is a local patch to vendored miniaudio 0.11.25, marked with a greppable banner. It should be carried across miniaudio updates, and is worth reporting upstream: the loop is unbounded for every OpenSL user. Verified without an NDK (the backend is __ANDROID__-only) by exercising the added arithmetic against the real ma_device struct (4096x3@48k -> 512ms, 512x3@48k -> 200ms floor, 8192x4@44k -> 1000ms ceiling, 0x0@0 -> no divide by zero, UINT32_MAX x8 -> no 32-bit overflow), compiling the patched function verbatim against OpenSL stubs under C99 and C89 with -Wall -Wextra, and running a stalled-queue harness: the unpatched function loops forever (killed at 5s), the patched one returns after ~520ms matching the bound. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Colton127
force-pushed
the
fix/opensl-drain-timeout
branch
from
July 26, 2026 23:24
99bfa3b to
08d7f79
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Upstream miniaudio waits indefinitely for the OpenSL ES buffer queue to report empty. If the callback queue stalls,
ma_device_stop()can block indefinitely; flutter_soloud now calls device stop routinely for idle stopping.Approach
deviceTypeargument for queue, timing, and draining-flag selection, so duplex devices drain capture and playback independently.GetState()and ends the drain attempt on failure without inspecting queue state.Verification
git diff --checkflutter pub getflutter analyze(passed; six informational lints reported in existing example tests)flutter test(passed)cd example && flutter build apk --debugwas attempted, but the build could not proceed because the example configures NDK 27.0.12077973 while dependencyjnirequires NDK 28.2.13676358. No Android/NDK compile result is claimed.Maintenance note
The
flutter_soloud local patchmarkers must be preserved when updating vendored miniaudio.