Skip to content

Seeking/resume fails immediately (end of file or error on socket) on a remote (R-capability) transcoded stream #1663

Description

@NikolajChristensen

Describe the bug

Seeking (or resuming after a pause, which appears to use the same code path) on a track whose custom-convert.conf profile combines the R (remote URL) and T (seek-to-start-time) capabilities reliably fails, even though every intermediate step is provably correct.

The transcoded stream (ffmpeg fed a remote HLS URL, R-only, no T) plays perfectly from the start. Adding T and seeking mid-playback causes Slim::Player::Source::_readNextChunk to report end of file or error on socket roughly 1 second after the seek-triggered reopen - even though the exact command LMS constructs (confirmed via the Tokenized command: log line) decodes the entire rest of the file with zero errors when run directly, outside LMS.

With multiple players synced together, this repeats indefinitely (seek → ~1s of audio → reopen at ~the same position → repeat). With a single, unsynced player, it stops instead of looping - but the same "end of file or error on socket" / immediate-reopen pattern is the underlying cause in both cases.

I want to be upfront that I can't rule out something specific to my own profile/handler causing this, but every piece I could independently verify came back correct - see the sequence of log lines below - which is what made me suspect the bug is in LMS's own pipe-reading/seek-reopen logic for an R-capability stream rather than in my own code.

To Reproduce

  1. A custom protocol handler for a remote (isRemote => 1, canDirectStream => 0) HLS stream, resolved to a .m3u8 URL and handed to ffmpeg via a custom-convert.conf profile declaring RT:{START=-ss %s} (mirroring the built-in flac/faad profiles' T:{START=--skip=%t} pattern), plus a getSeekData($client, $song, $newtime) implementation returning { timeOffset => $newtime }.
  2. Start playback of a track using that profile - it plays normally from the beginning.
  3. A few seconds/minutes in, seek to a new position (or pause, wait, then resume).
  4. Observe server.log (with the built-in player.source category raised to INFO, to see the Tokenized command: line):
    • Slim::Player::Song::open correctly logs Adding seekdata { timeOffset => <N> } and seek=true time=<N> canSeek=2
    • The Tokenized command: line correctly includes -ss <N> at the right position
    • Within ~1 second, Slim::Player::Source::_readNextChunk logs end of file or error on socket, song pos: <bytes>
    • Several Slim::Player::StreamingController::_Invalid lines follow (event ... received while in invalid state ...)
  5. Confirm the same command run directly (outside LMS) works correctly for the full remaining duration:
    ffmpeg -loglevel warning -nostdin -ss <N> -reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 10 \
      -i "<the exact resolved HLS URL from the Tokenized command line>" \
      -vn -c:a flac -compression_level 0 -f flac -y out.flac
    
    This decodes cleanly to completion with no errors in every case I tried.

I hit this in a small open-source plugin I wrote (source, including the exact custom-convert.conf profile and protocol handler: https://github.com/NikolajChristensen/lyrion-drlive - see the README's Troubleshooting section, "Seeking and pause/resume on TVA", for the full write-up of what I tried across several versions). The specific content is a Danish public broadcaster's on-demand HLS stream, which is geo-restricted to Denmark/EU, so I can't hand you a URL that works everywhere - but the failure pattern doesn't look content-specific, and I'd expect it to reproduce with any R+T profile seeking into a remote HLS VOD asset. Happy to help reproduce against a different, non-geo-restricted source if that's useful, or to pull further log detail from my own server.

Expected behavior

Seeking (and resuming after a pause) on a remotely-transcoded (R-capability) stream should restart the transcoder at the requested offset and continue playing normally, the same way it does for a locally-transcoded (non-R) T-capable profile.

Screenshots

N/A (audio-only issue, no visual component beyond the progress bar and playback state).

System Information (please complete the following information):

  • OS on which you're running LMS: Debian/Ubuntu-based Linux
  • Hardware: x86_64
  • Web skin used: Default
  • Browser: N/A (reproduced via a Squeezebox2-family hardware player)
  • LMS Version: 9.1.1
  • Player(s) involved: Squeezebox2-family hardware, both a single unsynced player and a 4-player sync group
  • ffmpeg 5.1.9 (Debian package)

Additional context

Relevant server.log excerpt (player MAC redacted), plugin.drlive at DEBUG and the built-in player.source at INFO:

Slim::Player::StreamingController::jumpToTime
Slim::Player::Song::open (371) Adding seekdata { timeOffset => 259.52 }
Slim::Player::Song::open (395) seek=true time=259.52 canSeek=2
Slim::Player::TranscodingHelper::tokenizeConvertCommand2 (668) Using command for conversion: "/bin/ffmpeg" -loglevel error -nostdin -ss 259.52 -reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 10 -i "https://<redacted HLS URL>" -vn -c:a flac -compression_level 0 -f flac - & |
Slim::Player::Song::open (586) Tokenized command: "/bin/ffmpeg" -loglevel error -nostdin -ss 259.52 -reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 10 -i "https://<redacted HLS URL>" -vn -c:a flac -compression_level 0 -f flac - & |
...
Slim::Player::Source::_readNextChunk (379) end of file or error on socket, song pos: 2440298
Slim::Player::Source::_readNextChunk (384) <player>: mark end of stream
Slim::Player::StreamingController::_setStreamingState (2439) new streaming state STREAMOUT
...
Slim::Player::StreamingController::_Invalid (325) <player>: event ReadyToStream received while in invalid state WAITING_TO_SYNC-STREAMOUT
Slim::Player::StreamingController::_Invalid (325) <player>: event BufferReady received while in invalid state PLAYING-IDLE

I also came across DEVELOPERS.md's "Issue of 'Volatile' Redirection" section while investigating, which describes LMS closing the connection on pause and needing to re-resolve on resume - a related but distinct scenario (that one is about a redirected URL going stale; this one reproduces on a stable, unredirected URL that decodes perfectly when fetched again immediately after the failure). Mentioning it in case the two share a root cause in the same area of Slim::Player::Song/Slim::Player::Source.

Happy to provide the full plugin source, a longer log excerpt, or test further against my own server - just let me know what would help.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions