diff --git a/priv_aamp.cpp b/priv_aamp.cpp index 174fdd362..555bcc521 100644 --- a/priv_aamp.cpp +++ b/priv_aamp.cpp @@ -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(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 playlist-window start in epoch seconds. + // position is the player's current position in raw ms (from stream start). + // culledSeconds*1000 is the window start in the same raw coordinate space. + // Adding the offset to mProgramDateTime gives the epoch time of the + // current playback position; subtracting from nowMs yields true 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 (in ms) the player is into + // the current playlist window. Both position and culledSeconds*1000 are + // in the same raw (unadjusted) coordinate space, so no offset skew. + // Clamp to >= 0 to guard against transient position-behind-start cases. + double playbackOffsetFromWindowStartMs = position - (culledSeconds * 1000.0); + if (playbackOffsetFromWindowStartMs < 0.0) + { + playbackOffsetFromWindowStartMs = 0.0; + } + long long pdtAtCurrentPosMs = static_cast( + (mProgramDateTime * 1000.0) + playbackOffsetFromWindowStartMs); + latency = static_cast(nowMs - pdtAtCurrentPosMs); + AAMPLOG_INFO("HLS PDT latency = %ldms, nowMs = %lldms, mProgramDateTime = %.3fs, " + "position = %.3fms, culledSeconds = %.3fms, playbackOffsetFromWindowStartMs = %.3fms", + latency, nowMs, mProgramDateTime, position, culledSeconds*1000.0, 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(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);