Skip to content
Open
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 42 additions & 5 deletions priv_aamp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2723,11 +2723,48 @@ void PrivateInstanceAAMP::MonitorProgress(bool sync, bool beginningOfStream)
}
else
{
// For HLS Live, calculate latency based on live edge; round to nearest ms
latency = static_cast<long>(std::lround(end - reportFormattedCurrPos));
if(latency < 0)
{ // this should never happen!
AAMPLOG_ERR("HLS negative live latency = %ldms, end = %lfms, reportFormattedCurrPos = %lfms", latency, end, reportFormattedCurrPos);
if(mProgramDateTime > 0.0)
{
// For HLS Live with EXT-X-PROGRAM-DATE-TIME: calculate latency as the
// difference between the current wall-clock time and the absolute wall-clock
// time at the player's current playback position.
// mProgramDateTime is the current playlist-window start in epoch seconds.
// reportFormattedCurrPos is the player's position in ms, measured from the
// same window start (i.e. relative to culledSeconds). Adding them together
// gives the epoch-based wall-clock time of the current playback position,
// and subtracting from nowMs yields the true live latency.
// This avoids the sawtooth fluctuation caused by the live edge advancing
// in discrete segment-sized steps on each manifest refresh.
long long nowMs = aamp_GetCurrentTimeMS();
// playbackOffsetFromWindowStartMs: how far into the current playlist
// window the player is. start is culledSeconds*1000 (in ms), already
// offset-adjusted by GetFormatPositionOffsetInMSecs(). Clamp to >= 0
// to guard against transient position-behind-start edge cases.
double playbackOffsetFromWindowStartMs = reportFormattedCurrPos - (culledSeconds*1000.0);
if (playbackOffsetFromWindowStartMs < 0.0)
{
playbackOffsetFromWindowStartMs = 0.0;
}
long long pdtAtCurrentPosMs = static_cast<long long>(
(mProgramDateTime * 1000.0) + playbackOffsetFromWindowStartMs);
Copy link
Copy Markdown
Contributor Author

@psiva01 psiva01 May 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback and #1412 (comment)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in cd37ddd. Changed playbackOffsetFromWindowStartMs from reportFormattedCurrPos - (culledSeconds*1000.0) (mixed coordinate spaces) to position - (culledSeconds * 1000.0) — both in the same raw (unadjusted) space. Using position directly (rather than reportFormattedCurrPos - start) also avoids the edge case where start is reset to -1 for TSB-less linear streams. Also updated the block comment and downgraded the log from WARN to INFO.

latency = static_cast<long>(nowMs - pdtAtCurrentPosMs);
AAMPLOG_WARN("HLS PDT latency = %ldms, nowMs = %lldms, mProgramDateTime = %.3fs, "
"start = %.3fms, culledSeconds = %.3fms, reportFormattedCurrPos = %.3fms, playbackOffsetFromWindowStartMs = %.3fms",
latency, nowMs, mProgramDateTime, start, culledSeconds*1000.0, reportFormattedCurrPos, playbackOffsetFromWindowStartMs);
if(latency < 0)
{ // this should never happen!
AAMPLOG_ERR("HLS PDT-based negative live latency = %ldms, nowMs = %lldms, pdtAtCurrentPosMs = %lldms", latency, nowMs, pdtAtCurrentPosMs);
}
}
else
{
// Fallback for HLS streams without EXT-X-PROGRAM-DATE-TIME:
// calculate latency based on live edge; round to nearest ms.
latency = static_cast<long>(std::lround(end - reportFormattedCurrPos));
if(latency < 0)
{ // this should never happen!
AAMPLOG_ERR("HLS negative live latency = %ldms, end = %lfms, reportFormattedCurrPos = %lfms", latency, end, reportFormattedCurrPos);
}
}
}
SetCurrentLatencyMs(latency);
Expand Down
Loading