Skip to content

Native streaming recovery reconnects but leaves playback paused after a mid-song session drop #372

Description

@LargeModGames

Describe the bug

When the librespot session drops mid-song, native streaming recovery reconnects successfully and reloads the current track, but playback is never resumed. The track sits loaded and paused, and the user sees music silently stop with no error. Pressing play resumes normally, so the recovered player is healthy. It just never gets told to play.

To Reproduce

  1. Play a track via native streaming.
  2. Interrupt the connection to the Spotify access point mid-song (a network blip is enough; in my case it followed a period of degraded throughput).
  3. Observe recovery run in the logs: new session authenticates, track reloads.
  4. Playback stays paused.

Expected behavior

If playback was active when the session dropped, recovery should restore the playing state once the new player is up, so a transient network blip doesn't silently end listening.

Logs (identifiers and track metadata redacted)

[20:32:33][librespot_audio::fetch::receive][WARN] Throughput 6 kbps lower than minimum 8, setting to minimum
...
[20:38:47][librespot_core::session][ERROR] Connection to server closed.
[20:38:47][librespot_connect::spirc][WARN] unexpected shutdown
[20:38:47][librespot_connect::state::context][WARN] couldn't load context info because: context is not available. type: Default
[20:38:47][spotatui::infra::player::events][INFO] attempting native streaming recovery
[20:38:47][spotatui::infra::player::streaming][INFO] Using cached streaming credentials
[20:38:47][spotatui::infra::player::streaming][INFO] Initializing Spirc with device_id=<redacted>
[20:38:47][librespot_core::session][INFO] Connecting to AP "<redacted>"
[20:38:47][librespot_core::session][INFO] Authenticated as '<redacted>' !
[20:38:47][spotatui::infra::player::streaming][INFO] Streaming connection established!
[20:38:47][spotatui::infra::player::events][INFO] spawning native player event handler
[20:38:51][librespot_core::dealer][WARN] Websocket connection failed: WebSocket protocol error: Remote sent after having closed
[20:38:51][librespot_core::dealer][WARN] Wasn't able to reply to dealer request: channel closed
[20:38:51][librespot_playback::player][INFO] Loading <track> with Spotify URI <redacted>
[20:38:52][librespot_playback::player][INFO] <track> (<duration> ms) loaded
[20:38:52][librespot_connect::spirc][INFO] active device is <redacted> with session <redacted>

Nothing follows. Recovery completed in under a second and then playback simply stayed paused.

Root cause

Recovery ends by calling app.replay_pending_start_playback() in handle_streaming_recovery (src/infra/player/events.rs:119). That only replays a pending_start_playback request, which per its own doc comment (src/core/app.rs:1348-1352) is "a StartPlayback request parked while no usable backend exists", meaning a press the user made while the backend was down.

A mid-song disconnect parks nothing, because the user never pressed anything. So there is no pending request to replay, and the recovered player is left idle on a loaded track. The pre-disconnect playing state isn't captured anywhere in the recovery path.

Suggested fix

Capture whether playback was active at the moment of the drop and, if so, issue a play against the recovered player after replay_pending_start_playback(), guarding against a double-play when a pending request already exists. Restoring the playback position is likely wanted here too. Worth confirming whether the reload resumes from the drop point or from the track start.

Desktop

  • OS: Windows 11
  • Terminal: PowerShell
  • Version: reproduced on a local build of feature/repeat-shuffle-other-sources (2ee8cf6), but this is not branch-specific. src/infra/player/events.rs is identical to main on that branch, and the branch does not touch pending_start_playback, so released builds (0.40.2) are affected the same way. Line numbers above refer to main.

Additional context

Two network-side signals bracket the drop: degraded throughput roughly 6 minutes earlier (Throughput 6 kbps lower than minimum 8), and a dealer websocket failure right after the reconnect. This looks like a flaky connection rather than anything wrong in-app. The app's reconnect handling is working, the resume is what's missing.

Related to #72 ("Freezing when a song is paused for too long"), but distinct. In #72 the session dies during a long idle pause and resume produces a playing indicator with no audio. Here the session dies mid-playback, recovery genuinely succeeds, and the track is simply never played. Both are cases of the librespot session's lifetime drifting out of sync with the app's playback state, and a general session-state reconciliation pass would likely cover both.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingrustRust programming language related

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions