SendPlayerStateAsync must not overwrite the applied static delay - #170
Merged
Conversation
Two defects on the same parameter, both found while checking why a server-side
sync app concluded the SDK player could not take a measured delay.
The staticDelayMs parameter defaulted to 0.0, so the two-argument call - the form
MIGRATION-5.4.0.md documents for a volume change - reported static_delay_ms: 0.
The spec requires the server to merge each client/state, "retaining the last value
of any field that is absent", so a present value overwrites: one volume change
after a server-set 250 ms delay wiped it back to 0. Omitting an unchanged field is
safe; sending a wrong one is destructive.
A supplied value was reported but never applied or persisted. Playback kept using
the old delay while the server was told the new one, so group calibration and
scheduling disagreed, and because nothing was persisted the next reconnect
reported the old value again - the measurement evaporated silently. The spec both
permits a client-initiated update ("clients may update static_delay_ms ... when
audio output changes") and requires it be persisted ("clients must persist
static_delay_ms locally across reboots and server reconnections"), so a
report-only path is not a legitimate update.
The parameter becomes double? = null. Null leaves the delay untouched; a value
applies it to the clock synchronizer, persists it through IStaticDelayStore, and
reports it. The reported delay is now always the applied one, never the argument.
Verified by probing the real message sequence, not by inspection. Discrimination:
reverting the report line fails 2 of 5, removing the apply-and-persist block fails
3 of 5. Suite 756 green, clean Release build on both TFMs.
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.
Found while diagnosing why a server-side sync app concluded an SDK player could not accept a measured delay. Two defects on one parameter.
1. The
0.0default overwrote a server-set delayProbed against a real message sequence rather than read off the signature:
The spec is explicit about why this is destructive rather than merely redundant:
Omitting an unchanged field is safe — the server retains it. Sending
0is an overwrite the server is obliged to honour. And the two-argument call is the formMIGRATION-5.4.0.mddocuments for a volume change, so the first volume nudge after any calibration wiped it.2. A supplied delay was reported but never applied or persisted
The server calibrated against a delay playback was not using, nothing was written to
IStaticDelayStore, and the next reconnect reported 250 again — the measurement evaporated with no error anywhere.The spec both permits and constrains this:
A client-initiated update is legitimate; one that does not persist is not an update. So a report-only parameter had no valid meaning.
The change
nullleaves the delay untouched. A value applies it to the clock synchronizer, persists it viaIStaticDelayStore, and reports it — the same three steps the inboundset_static_delayhandler already performed. The reported delay is now always the applied one, never the argument, so the two paths cannot diverge again.Composes with #169: a negative delay still schedules audio later and still never reaches the wire.
Verification
dotnet build -c Release --no-incremental: 0 errors, both library TFMs.OmittedDelay_ChangesNothingAndPersistsNothingis the positive control in both directions: it catches a supplied delay being ignored and an omitted one wrongly writing through.Not a bug: the advertisement location
The app's original symptom is app-side. Per spec,
player@v1_support.supported_commandsis "subset of: 'volume', 'mute'" and theclient/stateplayer one is "subset of: 'set_static_delay'" — soset_static_delaycan only ever be advertised viaclient/state, for any conformant client. A server reading onlyclient/helloconcludes no player supports it. Documented in the NuGet README alongside the note that a player's initialclient/stateis deferred until clock sync converges.