Conversation
LateStart_WithDeclaredOutputLatency_StaysOnSchedule named a property of the general case while measuring a single start. RunDriftFreeSession builds one TimedAudioBuffer and starts playback once, so nothing in the harness observes what repeated starts do - the name was true of start one and said nothing about start five. Renamed to LateStart_PreservesTheOutputLatencyPreRoll, which is the claim the assertion supports: the SkipStaleAudio re-derivation runs ScheduledLocalTimeFor a second time against a head cursor that has already moved, and does not lose or double-count the pre-roll. The distinction turned out to matter. A capture rig running this player and the C++ CLI into one timebase measured the .NET side displacing at every stream restart and never recovering: mean ~24ms per restart, 95% of it at the restart rather than between them (overall -350.3 ms/hour against a mean within-interval slope of -16.5 ms/hour), cumulative and permanent - -525ms over 22 restarts, monotonic across 19 of 19 bins. Two C++ instances under identical conditions were also perturbed at restarts but with no consistent direction, 4 of 10 negative, so they random-walk and stay bounded. That control is what makes it a defect rather than restart noise. So a test asserting late starts stay on schedule would have been read as covering exactly the case that is broken, which is worse than having no test there at all. The remark now records the gap and what closing it needs - repeated starts against one timebase, asserting displacement after N restarts is not N times worse than after one - and notes it belongs to the SDK's shared startup path, since it reproduces on Linux/OpenAL. Not asserted anywhere, because it is not established: why each restart displaces. The absorbed startup baseline sits near-constant at -23ms but does not predict the per-restart step (r = -0.113 over 23 pairs, 7 of them positive, steps ranging +29 to -111ms). The aggregate agreement between the two figures is two means coinciding, not a mechanism.
The stale-audio assertion holds for every case including startLateMicros: 0, so SkipStaleAudio runs on every start here - declaring an output latency pre-rolls the schedule past the grace window, and the harness cannot construct an ordinary start at all. That is worth stating next to the coverage gap, because the rare path is the only one modelled. In the measured run the branch ran once in 29 starts; the other 28 stayed inside the grace window, and those are what the -525ms accumulated across. The stale branch does explain the outsized residuals -88.9ms on that single start against -21.9 to -23.7ms on ordinary ones - but a larger absorption is a difference in what gets absorbed, not in what accumulates. So the displacement is something an ordinary stream start does, and this file cannot reach an ordinary stream start. Recorded rather than fixed: making the harness model one means a start inside the grace window with the pre-roll declared, which is a different harness rather than another case.
The remark had started tracking an investigation rather than describing the test, and had already needed one correction: it said the player displaces at every stream restart, which turned out to be restart-kind dependent. Seeking barely registers; stopping and restarting is what displaces. Restructured so what stays is what can be re-checked from this file - the harness starts playback once, and SkipStaleAudio runs on every case including startLateMicros: 0, so it cannot construct an ordinary start. Both are properties of the harness, not of the code under test, and neither depends on anyone's measurements. Kept two external facts because they decide whether a reproducer works at all: it is the stop/start cycle rather than seeking, and it reproduces on Linux/OpenAL so it is the shared SDK startup path. The rest of the diagnosis now points at sendspin-dotnet#272 instead of being restated here. Four candidate mechanisms have looked settled and then failed a disconfirming check - the resampler ratio, the absorbed baseline, the stale-start branch, the restart count - and a comment that cannot be re-run is the wrong place to keep score. Also recorded the corroboration on AbsorbedStartupBaseline_IsNotMisalignment, which is now the best-supported claim in the file: three hardware measurements from different directions agree that the absorbed value stays put while the displacement varies. Measurements rather than mechanisms, so they are worth writing down.
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.
Correcting an overclaim I merged in #88, before it gets read as coverage.
The defect
LateStart_WithDeclaredOutputLatency_StaysOnSchedulenamed a property of the general case while measuring a single start.RunDriftFreeSessionbuilds oneTimedAudioBufferand starts playback once, so nothing in the harness observes what repeated starts do. The name was true of start one and silent about start five.Renamed to
LateStart_PreservesTheOutputLatencyPreRoll— the claim the assertion actually supports:SkipStaleAudio's re-derivation runsScheduledLocalTimeFora second time against a head cursor that has already moved, and does not lose or double-count the pre-roll. That is worth pinning. It is just not the same statement.Why it matters
A capture rig running this player and the C++ CLI into one timebase — both in one MA sync group, each to its own null sink, both captured by a single ffmpeg process — measured the .NET side displacing at every stream restart and never recovering.
95% of the displacement happens at the restarts themselves. The control is what makes this a defect rather than restart noise: two C++ instances under identical conditions were also perturbed at each restart, but with no consistent direction — 4 of 10 negative, mean +6.4 ms — so they random-walk and stay bounded, while the .NET leg moved the same way 16 times out of 22.
A test asserting "late starts stay on schedule" would have been read as covering precisely the case that is broken. That is worse than having no test there, which is the whole reason #87 exists.
What the remark now records
The gap, and what closing it needs: repeated starts against one timebase, asserting that displacement after N restarts is not N times worse than after one. It belongs to the SDK's shared startup path rather than to this repository — it reproduces on Linux/OpenAL, so it is not WASAPI and not windowsSpin.
Deliberately not asserted
Why each restart displaces. The absorbed startup baseline is near-constant at −23 ms but does not predict the per-restart step: r = −0.113 over 23 pairs, 7 of them positive, steps ranging +29 to −111 ms. The aggregate agreement between "−23.9 ms mean displacement" and "−23 ms mean baseline" is two means coinciding, not a mechanism — I relayed it as one earlier and that was wrong.
AbsorbedStartupBaseline_IsNotMisalignmentis untouched and stands: it asserts the absorbed baseline is not a measure of misalignment, which the per-event pairing independently confirms from real audio.Testing
dotnet test -c Releaseon Windows: 219 passed, 0 failed.Credit for the measurements and the C++/C++ control to the Linux capture rig; the analysis of what the test does and does not cover is from reading the harness.