Repository navigation
Conversation
… it (sonn-audio#390) `paused` calls `pausePlayback` unconditionally. Nothing called `resumePlayback` — the Soloist input never has, though DLNA and AirPlay both do and the port has always had it. A pause does not go through `finishTrack`, the only thing that nulls `runner.stream`. So on a resume the uri has not moved and the stream is alive, which is exactly the case 661824e leaves alone, and the branch returns having done nothing. The room stays paused while Soloist plays on: the app shows the bar moving, the position keeps arriving, and nothing sounds until a track change happens to take another path. Sent on every `playing` rather than tracked separately, because `audioManager.resumePlayback` returns early on a session already playing — the runner needs no second copy of the zone's state. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vo1g71NXgnEdsdjmVhPWTx
…unced (sonn-audio#390) The `!runner.stream` adopt added in 661824e is level-triggered where the other two are edge-triggered: it stays true for as long as adoption takes, adoption awaits `waitForSpec` before it assigns the stream, and the app keeps saying `playing` throughout. So one takeover can start several adoptions. Not harmless, because `takeStream()` destroys the stream it replaces — the second adoption tears down the one the first has just handed to the zone. `device_changed` and `track_changed` never had this exposure. The body moves to `adoptConnectPlaybackInner` so the flag stays a try/finally rather than something threaded through every early return. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vo1g71NXgnEdsdjmVhPWTx
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.
Closes #390. Against current
dev(1dfec51), and only the two things from #383 that 661824e did not carry — that commit's own half (adopt when the stream is gone, and teardown forgetting the track) is untouched here.1. A room the app pauses is never resumed
pausedcallspausePlaybackunconditionally. Nothing callsresumePlayback— the Soloist input never has, though DLNA and AirPlay both do and the port has always had it.A pause does not go through
finishTrack, which is the only thing that nullsrunner.stream. So on a resume the uri has not moved and the stream is alive, which is precisely the case 661824e leaves alone, and the branch returns having done nothing. The room stays paused in core while Soloist plays on: the app shows the bar moving, the position keeps arriving, nothing sounds until a track change happens to take another path.Measured on 4.0.0-beta.21 carrying 661824e as a dist patch, on the zone that found #383:
With this commit the same sequence reads
paused 42→playing 49, card back toRUNNING.Sent on every
playingrather than tracked separately:audioManager.resumePlaybackreturns early on a session that is already playing, so the runner does not need a second copy of the zone's state to know when to send it.2. The adopt is level-triggered and nothing guards it
!runner.streamstays true for as long as adoption takes, adoption awaitswaitForSpecbefore it assigns the stream, andplayingkeeps arriving throughout — so one takeover can start several adoptions.That is not harmless, because
takeStream()destroys the stream it replaces:The second adoption tears down the stream the first has just handed to the zone.
device_changedandtrack_changedare edge-triggered and never had this exposure; the condition added in 661824e does. A flag for the duration is enough, and the body moved toadoptConnectPlaybackInnerso that stays atry/finallyrather than a flag threaded through every early return.Tests
Three added to
tests/soloistBackend.test.ts, beside the ones from 661824e, and the sharedwithConnectRunnergained a controller that counts resumes:playing, because a playing session ignores it;adoptConnectPlayback, since the guard lives inside it, so it has a second small harness.All 20 in the file pass with both commits, and the three new ones fail on unmodified
dev. The first commit alone is green on its own 19, so the two can be taken separately.playing the track that is already sounding is left alonestill passes throughout — it asserts nothing is adopted, which remains true.Typecheck, eslint and dependency-cruiser are clean.
npm testas a whole I cannot run to the end here (that is the arm64 segfault from #384, fixed ondevin 3a8bc12 but not in the beta.21 tree I build against), so the file was run through a standalone runner.