Skip to content

Add session recovery with automatic playback resume#1690

Open
Arneball wants to merge 1 commit intolibrespot-org:devfrom
Arneball:session-fix
Open

Add session recovery with automatic playback resume#1690
Arneball wants to merge 1 commit intolibrespot-org:devfrom
Arneball:session-fix

Conversation

@Arneball
Copy link
Copy Markdown
Contributor

When the TCP connection to Spotify access points drops due to network instability, the keep-alive timeout fires after ~80s and invalidates the session. The old spirc shuts down and a new Session + Spirc is created. However, three things went wrong:

  1. Session ID mismatch: The new Session generated a fresh random UUID, so Spotify could not match it to the previous playback session. The automatic transfer in handle_connection_id_update failed because the cluster session_id did not match the new session_id.

  2. Volume reset: ConnectConfig.initial_volume was set once at startup and reused on every reconnection. The new SpircTask initialized the mixer to this stale value instead of the users current volume, causing a jarring volume jump on reconnect.

  3. Playback not resuming: The transfer state from Spotify always has is_paused=true after a disconnect, since the device went offline. handle_transfer used this to set start_playing=false, so the track loaded paused even though the user was actively listening.

Fixes:

  • Preserve session_id across reconnections for automatic transfer
  • Preserve mixer volume on reconnect, only override after first connect
  • Track user play intent via shared Arc was_playing flag
  • Add force_play parameter to handle_transfer for reconnection resume
  • Add shutdown reason strings to session.shutdown for debugging
  • Fast-fail audio key requests when session is invalid
  • Use RwLock in player for session hot-swap

Testing librespot session recovery via iptables

1. Find the AP connection

ss -tnp | grep librearmv7 | grep 4070

Example output:

ESTAB 0 0  192.168.0.14:57572  34.158.1.133:4070  users:(("librearmv7",pid=3429,fd=17))

Note the destination IP (34.158.1.133) and source port (57572).

2. Block the connection

sudo iptables -A OUTPUT -d <IP> -p tcp --sport <SPORT> --dport 4070 -j DROP
sudo iptables -A INPUT -s <IP> -p tcp --dport <SPORT> --sport 4070 -j DROP

Using the example values:

sudo iptables -A OUTPUT -d 34.158.1.133 -p tcp --sport 57572 --dport 4070 -j DROP
sudo iptables -A INPUT -s 34.158.1.133 -p tcp --dport 57572 --sport 4070 -j DROP

Blocking the specific source port is important — it kills the existing connection while allowing librespot to establish a new one on a different port.

3. Wait for reconnection

The keep-alive timeout fires after ~80 seconds. After that, the session is invalidated and librespot creates a new session + spirc. The audio buffer may sustain playback for another 1-2 minutes before the reconnection completes.

Monitor with:

tail -f /tmp/librespot.log

Look for:

  • Shutdown: Invalidating session: keep-alive timeout
  • Preserved session_id across reconnection
  • start_playing=true (if music was playing)

4. Clean up iptables rules

sudo iptables -F

@Arneball Arneball force-pushed the session-fix branch 3 times, most recently from 772e90f to ed7ccba Compare February 26, 2026 12:44
When the TCP connection to Spotify access points drops due to network
instability, the keep-alive timeout fires after ~80s and invalidates
the session. The old spirc shuts down and a new Session + Spirc is
created. However, three things went wrong:

1. Session ID mismatch: The new Session generated a fresh random UUID,
   so Spotify could not match it to the previous playback session. The
   automatic transfer in handle_connection_id_update failed because
   the cluster session_id did not match the new session_id.

2. Volume reset: ConnectConfig.initial_volume was set once at startup
   and reused on every reconnection. The new SpircTask initialized the
   mixer to this stale value instead of the users current volume,
   causing a jarring volume jump on reconnect.

3. Playback not resuming: The transfer state from Spotify always has
   is_paused=true after a disconnect, since the device went offline.
   handle_transfer used this to set start_playing=false, so the track
   loaded paused even though the user was actively listening.

Fixes:
- Preserve session_id across reconnections for automatic transfer
- Preserve mixer volume on reconnect, only override after first connect
- Track user play intent via shared Arc<AtomicBool> was_playing flag
- Add force_play parameter to handle_transfer for reconnection resume
- Add shutdown reason strings to session.shutdown for debugging
- Fast-fail audio key requests when session is invalid
- Use RwLock<Session> in player for session hot-swap
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant