Skip to content

HLS: Player stuck in infinite buffering loop when #EXT-X-PROGRAM-DATE-TIME changes between playlist refreshes #3337

Description

@thathorizon

Version

Media3 1.10.1

More version details

Problem

Some HLS live streams have servers that change the #EXT-X-PROGRAM-DATE-TIME value between playlist refreshes. This causes ExoPlayer to compute a negative playback position (e.g., -35.96s) from which it never recovers. The player stays in READY state but at a negative position, unable to play any content.

Per RFC 8216, Section 4.3.2.6:

"Note that dates in Playlists can refer to when the content was produced (or to other times), which have no relation to the time of playback."

So this behavior from the server is allowed by the spec — it does not require PROGRAM-DATE-TIME to be consistent across playlist refreshes.

Manifest Example

The first media playlist response has PROGRAM-DATE-TIME set to one time. The second response (with overlapping segments) has it set to a different time, creating a ~36s discontinuity.

First response (seq=0):

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-DISCONTINUITY-SEQUENCE:0
#EXT-X-START:TIME-OFFSET=0
#EXT-X-PROGRAM-DATE-TIME:2026-07-16T09:20:26.281Z
#EXT-X-DISCONTINUITY
#EXTINF:0.185760,
l1_6a58a1d3ee8ac1baff0fc11e.aac
#EXT-X-DISCONTINUITY
#EXTINF:5.990748,
l0_6a58a262ee8ac1baff0fc136.aac
#EXTINF:5.990748,
l0_6a58a268ee8ac1baff0fc137.aac
#EXTINF:5.990748,
l0_6a58a26eee8ac1baff0fc138.aac
...

Second response (seq=2):

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:2
#EXT-X-DISCONTINUITY-SEQUENCE:2
#EXT-X-START:TIME-OFFSET=0
#EXT-X-PROGRAM-DATE-TIME:2026-07-16T09:21:08.047Z
#EXTINF:5.990748,
l0_6a58a268ee8ac1baff0fc137.aac
#EXTINF:5.990748,
l0_6a58a26eee8ac1baff0fc138.aac
...

The segment l0_6a58a268ee8ac1baff0fc137.aac appears in both playlists. In the first response, its implied time is ~09:20:32Z (09:20:26.281 + 0.186 + 5.991). In the second response, PROGRAM-DATE-TIME is 09:21:08.047Z — a ~36 second discontinuity for the same segment.

Player Behavior

eventTime=0.00   mediaPos=0.00   state=BUFFERING
eventTime=1.63   mediaPos=0.00   state=READY         <-- starts playing
eventTime=2.20   mediaPos=0.50   loading=false        <-- playing normally
eventTime=5.82   mediaPos=4.12   loading=true         <-- rebuffering after ~4s
eventTime=7.44   mediaPos=-36.03                       <-- POSITION JUMPS TO -36s
eventTime=7.51   mediaPos=-35.96 loading=false
eventTime=47.41  mediaPos=-37.99 loading=true          <-- stuck: loads every 6s, position ~-38
eventTime=53.39  mediaPos=-38.00 loading=true
eventTime=59.38  mediaPos=-38.01 loading=true
... (continues indefinitely, never recovers)

The player transitions from READY at position 4.12 to position -35.96 during a playlist refresh, then stays stuck at approximately -38s forever. No BehindLiveWindowException is thrown.

Where it happens

In DefaultHlsPlaylistTracker.getLoadedPlaylistStartTimeUs(), when the loaded playlist has hasProgramDateTime = true, the method unconditionally returns the server-provided startTimeUs:

if (loadedPlaylist.hasProgramDateTime) {
    return loadedPlaylist.startTimeUs;
}

For playlists without PROGRAM-DATE-TIME, the tracker already computes startTimeUs from overlapping segments in the previous playlist, which maintains timeline consistency. The issue is that this safe behavior is bypassed when PROGRAM-DATE-TIME is present.

Devices that reproduce the issue

Tested on Android emulator, API 35

Devices that do not reproduce the issue

No response

Reproducible in the demo app?

Yes

Reproduction steps

  1. Play an HLS live stream where #EXT-X-PROGRAM-DATE-TIME changes between playlist refreshes
  2. Wait for the first playlist refresh
  3. Observe the player position

Expected result

The player handles inconsistent PROGRAM-DATE-TIME values gracefully, maintains a positive playback position, and continues playing live content.

Actual result

After the first playlist refresh, the player position jumps from a positive value (e.g., 4.12s) to a negative value (e.g., -35.96s). The player stays stuck in this state indefinitely — it keeps loading segments but never recovers. No BehindLiveWindowException is thrown.

Media

Sorry, can not provide stream URL (private).

hls_manifests2.log
eventlog_full.txt

Bug Report

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions