media icon indicating copy to clipboard operation
media copied to clipboard

CastPlayer: Scrubbing (Seeking) is Non-Responsive for Live Stream

Open FilipKastrupGP opened this issue 2 months ago • 2 comments

Version

Media3 1.8.0

More version details

When casting the a live HLS live stream (with a large window), seeking (scrubbing) within the timeline does not work. Observation: In the demo-cast app, the scrub bar is simply disabled, so we cant reproduce. In our project, the receiver does not respond to any scrubbing attempts. Debugging indicates the seek command is never sent to the cast receiver.

This led us to implement a custom logic using CastTimelineTracker to enable seeking.

Devices that reproduce the issue

Any

Devices that do not reproduce the issue

No response

Reproducible in the demo app?

No

Reproduction steps

Ensure that seeking is supported by the cast-receiver. addSupportedMediaCommands(ALL_BASIC_MEDIA)

Cast the stream to the chromecast device. Once playback begins, attempt to scrub (seek) backward or forward in the timeline.

Expected result

When scrubbing in a timeline it should be received by the chromecast device.

Actual result

Scrubbing actions do not result in a seek; the command appears to not be sent to the receiver (in our app).

Media

Stream details: ~30-minute window, 6-second segments, audio only

Bug Report

  • [ ] You will email the zip file produced by adb bugreport to [email protected] after filing this issue.

FilipKastrupGP avatar Oct 30 '25 19:10 FilipKastrupGP

Note. To make the live audio hls scrubable on the cast receiver (my chrome-cast guy said) we added this:

playbackConfig.shakaConfig = {
    manifest: {
        // In Shaka player, we cannot seek inside HLS. Google has implemented this by cutting the buffer short. By specifying a window override, we can allow seeking in all of the buffer
        availabilityWindowOverride: 1800,
        hls: {
            // The duration of the segments and the date time are not totally in sync, so we need to disable this check, otherwise the playback will start looping after playing 2-3 segments
            ignoreManifestProgramDateTime: true
        }
    },
    streaming: {
        rebufferingGoal: 18,
        bufferingGoal: 18,
        bufferBehind: 30,
    }
}

FilipKastrupGP avatar Oct 31 '25 10:10 FilipKastrupGP

Ensure that seeking is supported by the cast-receiver. addSupportedMediaCommands(ALL_BASIC_MEDIA)

I'm pretty sure (Remote)CastPlayer can still remove the seek command(s) if it doesn't think the content it's playing is seekable. This is tested here:

https://github.com/androidx/media/blob/bfe5930f7f29c6492d60e3d01a90abd3c138b615/libraries/cast/src/test/java/androidx/media3/cast/CastPlayerTest.java#L1506-L1526

I suspect that if you call isCommandAvailable(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM) before you call seekTo it will return false.

This would also explain why the demo app disables the scrubber bar (because the command is unavailable):

In the demo-cast app, the scrub bar is simply disabled, so we cant reproduce.


So I think this issue is more about "why doesn't CastPlayer think the content is seekable?"

The command is added/removed by this code:

https://github.com/androidx/media/blob/bfe5930f7f29c6492d60e3d01a90abd3c138b615/libraries/common/src/main/java/androidx/media3/common/util/Util.java#L3685

Which depends on Player.isCurrentMediaItemSeekable(), which is implemented by BasePlayer (superclass of (Remote)CastPlayer) here:

https://github.com/androidx/media/blob/bfe5930f7f29c6492d60e3d01a90abd3c138b615/libraries/common/src/main/java/androidx/media3/common/BasePlayer.java#L380-L384

Which leads to the CastTimeline implementation of isSeekable, which leads here: https://github.com/androidx/media/blob/bfe5930f7f29c6492d60e3d01a90abd3c138b615/libraries/cast/src/main/java/androidx/media3/cast/CastTimeline.java#L164

"seekable" and "dynamic" are not the same concept - but it looks like cast has assumed a dynamic timeline is unseekable since 2017: https://github.com/androidx/media/commit/aafdd2267abd6c9191ef66e9cf109cc24e159e30


Assigning to @AquilesCanta to take a deeper look.

icbaker avatar Nov 03 '25 12:11 icbaker

I guess this effectively makes this a feature request?

After tinkering with the code, I found I can retrieve somewhat usable data using RemoteMediaClient.getApproximateLiveSeekableRangeStart(), RemoteMediaClient.getApproximateLiveSeekableRangeEnd(), and RemoteMediaClient.getApproximateStreamPosition(). However, these values are offsets relative to the start of the stream session rather than absolute timestamps.

If I need the actual "Wall Clock" time of the content currently playing, my best option right now is to estimate it by comparing getApproximateLiveSeekableRangeEnd() against the device's current system time.

The issue is that this calculation almost always results in a slight mismatch compared to the time displayed on the Cast Receiver, presumably because the Receiver derives its time directly from the HLS timecodes.

Is there a way to retrieve this precise wall-clock time directly from the client, or would exposing that require a new feature?

FilipKastrupGP avatar Dec 16 '25 08:12 FilipKastrupGP