fix(audio): avoid overfilling backend audio buffer#6594
Open
banteg wants to merge 2 commits into
Open
Conversation
the audio producer is woken once per Graph_ProcessGfxCommands call and pushes a single ~1680-sample burst sized for the current R_UPDATE_RATE. two layered issues caused crackling on macos over hdmi: - DesiredBuffered = 1680 was exactly one producer burst, so any video frame jitter emptied the device buffer between wakes -- audible as clicks. bump it to 4096 (~128 ms at 32 khz). - on the file-select screen R_UPDATE_RATE is 1, which expects the producer to wake at ~60 hz. when the user's display rate is 20 fps the producer only wakes 20 times/s and structurally underproduces by 3x, no reservoir size can cover that. fix by running additional audio engine ticks within the same outer call until the reservoir is back at desired (capped at 6 iterations). each tick advances internal audio time by num_samples / sample_rate and the consumer drains them at the same rate, so audio still plays at normal speed. also bumps the libultraship submodule to fix-coreaudio-crackling, which replaces the locked ring buffer in the coreaudio backend with a lock-free spsc ring (eliminating the priority-inversion path) and fixes the wrap-equality + whole-chunk-drop bugs that produced clicks even on the built-in speaker path. verified on hdmi: underflow count over a 65 s session dropped from 1023 to 13 (only at startup), buffer level stays in the 3000-5500 frame range, never empties.
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
This completes the CoreAudio crackling fix from the Shipwright side.
The companion libultraship PR fixes the backend ring buffer itself:
Kenix3/libultraship#1098
This PR fixes the producer side in Shipwright: before generating another audio-engine buffer, the audio thread now checks whether the backend can accept the smallest next burst. If the backend ring is already too full, it skips that wake instead of producing PCM that the backend would have to reject or truncate.
Why
The adaptive producer loop added headroom for frame jitter by running extra audio ticks until the reservoir reaches
DesiredBuffered. That solves underproduction, but it can also briefly outrun the backend consumer. On CoreAudio, overfilling the backend ring exposed audible crackles, dropouts, and repeats because already-generated PCM could be dropped at the backend boundary.Keeping the producer from generating a chunk that cannot fit preserves audio continuity. The libultraship PR also preserves chunk boundaries defensively, but the app-side producer guard is what avoids advancing the audio engine when there is no room to enqueue the result.
Testing
soh/soh/OTRGlobals.cppand relinkingbuild-cmake/soh/soh-macos.Build Artifacts