Repository navigation
ASIO, CoreAudio: read the input before invoking the user callback - #492
Merged
garyscavone merged 1 commit intoOct 27, 2026
Merged
Conversation
RtApiAsio::callbackEvent and RtApiCore::callbackEvent invoked the user callback before copying the driver's input into stream_.userBuffer[1], so the callback always received the input of the previous cycle: one buffer of round-trip latency that getStreamLatency() does not report. The input block now runs before the callback, unchanged except that it carries the existing "don't bother draining input" rule as its own condition. The drain counter is still advanced after the output. With two CoreAudio devices nothing changes: the input device's IOProc only stores the input, and the output device's IOProc never reads it.
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.
Fixes #491.
RtApiAsio::callbackEventandRtApiCore::callbackEventinvoked the user callback before copying the driver's input intostream_.userBuffer[1], so the callback always received the previous cycle's input: one buffer of extra round-trip latency thatgetStreamLatency()does not report. The issue has the measurements (macOS/CoreAudio and Windows/ASIO, cross-checked with RTL Utility) and how it came up; the analysis and this patch were worked out with Claude and tested on real hardware.The change
In both functions the block that copies the input into
stream_.userBuffer[1]moves in front of the user callback. The block itself is unchanged except for its condition, which now carries the existing "don't bother draining input" rule (handle->drainCounter == 0) instead of agoto unlockafter the output. The drain counter is still advanced after the output, exactly as before.bufferSwitch(index)the input halfindexhas just been filled by the driver, so it can be read before the callback. Duplex and input-only streams both get the current input.stream_.deviceBufferis shared by the input and output conversion. They still run one after the other within one call, only in the other order.WASAPI, JACK, ALSA, PulseAudio, OSS and DirectSound are not touched.
The open #411 also edits the CoreAudio input copy block that this change moves. Whichever of the two lands second needs a mechanical rebase; I am happy to do it on this side.
Tested