Repository navigation
fix: start an external-volume session from the real volume - #425
Merged
Merged
Conversation
Under external_volume a new session advertised 100% (MaxStateVolume) in its first state, and kept advertising it until the controlling application pushed its level. Every zeroconf takeover and every session restored after a logout opened that window; an idle restored session stayed at 100% until playback started. A phone that steps its volume buttons from what the device advertised sent 96% or 100% from there, and the speaker jumped to it. The app now holds the volume across sessions: every change, from the API or a Spotify client, sets it, and POST /player/volume is accepted while there is no session, including during login. Under external_volume a new session starts at that volume: the last one set in this process, else the saved one unless ignore_last_volume is set, else initial_volume. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Now that the app holds a volume across sessions and POST /player/volume is accepted without one, GET answers with the volume the next session starts from instead of 204. The conversion to the API's steps is shared by every path that reports or reads a volume in steps. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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.
Cause
With
external_volume, a new session's device state started atMaxStateVolume, and the initial-volume branch inhandleDealerMessageis skipped for external volume. So the session's first PutState (NEW_DEVICE) told Spotify the device was at 100%, until the controlling application pushed its level throughPOST /player/volume.That window opens on every zeroconf takeover and every session restored after a logout. The restored session is idle, so it can stay at 100% for a long time: the Web API's device list showed it at 100 while the real level was 37.
Spotify clients step their volume buttons from the level the device advertised. Reproduced with an Android phone (Spotify 9.1.92): after a takeover, a volume key pressed before the application's push landed sent a
SetVolumeCommandfor 96% (down) or 100% (up), and the speaker jumped there from 37%.POST /player/volumecouldn't close the window ahead of time either: without a session it answeredErrNoSession.Change
stateMu. Every change sets it, from the API or a Spotify client, andLastVolumeis still saved as before.POST /player/volumeis accepted while there is no session, in both no-session paths: the zeroconf branch, andanswerWithoutSessionduring login. It only updates that volume.GET /player/volumewithout a session answers with that volume, the one the next session starts from, instead of 204.external_volume, a new session starts at that volume, so its first PutState carries the real level. The order is: the last volume set while this process runs, else the saved one unlessignore_last_volumeis set, elseinitial_volume(capped atvolume_steps).external_volumenothing changes: the session still sets its own level once the dealer connects.Checked
TestSessionVolume: the precedence above.TestVolumeFromApi: absolute, relative and clamping.TestAnswerWithoutSessionTakesVolume: with no session,POST /player/volumeis kept and saved, andGET /player/volumereports it.TestInitStateVolume: the first state carries the held level under external volume, and 100% otherwise.gofmt, the daemon build andgo test -tags "test_unit test_integration" ./...pass.active. Volumes read from the decoded PutStates andSetVolumeCommands:NEW_DEVICEat 37%, and the phone sent 33%. Before this change it sent 96%.POST /player/volume25, then takeover: the session started at 25%.🤖 Generated with Claude Code