From df6bcde70f603b23bd83016eae269488a99fba3d Mon Sep 17 00:00:00 2001 From: srikanthreddybijjam-comcast Date: Wed, 6 May 2026 11:06:13 +0530 Subject: [PATCH 1/2] VPAAMP-28: Merge MonitorLatency and RateCorrectionWorkerThread Reason for change: Merged the new flow Test Procedure: Refer jira ticket VPAAMP-28 Priority: P2 Signed-off-by: srikanthreddybijjam-comcast --- AampConfig.cpp | 1 - AampConfig.h | 1 - AampLatencyMonitor.cpp | 6 +- AampLatencyMonitor.h | 6 + aampgstplayer.cpp | 8 - fragmentcollector_hls.cpp | 4 +- fragmentcollector_mpd.cpp | 3 +- main_aamp.cpp | 10 +- priv_aamp.cpp | 280 +++--------------- priv_aamp.h | 46 +-- streamabstraction.cpp | 12 +- test/utests/fakes/FakeAampLatencyMonitor.cpp | 1 + test/utests/fakes/FakePrivateInstanceAAMP.cpp | 24 +- test/utests/mocks/MockPrivateInstanceAAMP.h | 2 + .../tests/PrivAampTests/PrivAampTests.cpp | 42 +-- .../PauseOnPlaybackTests.cpp | 7 +- .../FunctionalTests.cpp | 3 + .../subtitleTests.cpp | 1 + 18 files changed, 96 insertions(+), 361 deletions(-) diff --git a/AampConfig.cpp b/AampConfig.cpp index a91b7d88f0..db34c809ea 100644 --- a/AampConfig.cpp +++ b/AampConfig.cpp @@ -457,7 +457,6 @@ static const ConfigLookupEntryInt mConfigLookupTableInt[AAMPCONFIG_INT_COUNT+CON {0,"timeBasedBufferSeconds",eAAMPConfig_TimeBasedBufferSeconds,true,eCONFIG_RANGE_PLAYBACK_OFFSET}, {DEFAULT_MAX_DOWNLOAD_BUFFER,"maxDownloadBuffer",eAAMPConfig_MaxDownloadBuffer,true,eCONFIG_RANGE_PLAYBACK_OFFSET}, {DEFAULT_TELEMETRY_REPORT_INTERVAL,"telemetryInterval",eAAMPConfig_TelemetryInterval,true}, - {0,"rateCorrectionDelay", eAAMPConfig_RateCorrectionDelay,true}, {-1,"harvestDuration",eAAMPConfig_HarvestDuration,false,eCONFIG_RANGE_HARVEST_DURATION}, {DEFAULT_SUBTITLE_CLOCK_SYNC_INTERVAL_S,"subtitleClockSyncInterval",eAAMPConfig_SubtitleClockSyncInterval,true}, {eABSOLUTE_PROGRESS_WITHOUT_AVAILABILITY_START,"preferredAbsoluteReporting",eAAMPConfig_PreferredAbsoluteProgressReporting,true, eCONFIG_RANGE_ABSOLUTE_REPORTING}, diff --git a/AampConfig.h b/AampConfig.h index 7e3fb7eb25..18c50f148e 100644 --- a/AampConfig.h +++ b/AampConfig.h @@ -309,7 +309,6 @@ typedef enum eAAMPConfig_TimeBasedBufferSeconds, eAAMPConfig_MaxDownloadBuffer, /**< Max download buffer in seconds, this can be used to limit player download job scheduling for DASH*/ eAAMPConfig_TelemetryInterval, /**< time interval for the telemetry reporting*/ - eAAMPConfig_RateCorrectionDelay, /**< Delay Rate Correction upon discontinuity in seconds */ eAAMPConfig_HarvestDuration, /**< Harvest duration time */ eAAMPConfig_SubtitleClockSyncInterval, /**< time interval for synchronizing subtitle clock */ eAAMPConfig_PreferredAbsoluteProgressReporting, /**< Preferred settings for absolute progress reporting**/ diff --git a/AampLatencyMonitor.cpp b/AampLatencyMonitor.cpp index 09882f95dc..c53c599304 100644 --- a/AampLatencyMonitor.cpp +++ b/AampLatencyMonitor.cpp @@ -196,7 +196,11 @@ void AampLatencyMonitor::EnableRateCorrection(bool enabled) } mCorrectionEnabled.store(enabled); - // Wake the worker so it can immediately reset the rate if needed. + if (!enabled) + { + // Reset rate to normal immediately, before the worker thread wakes up. + ResetToNormalRate(); + } { std::lock_guard lock(mSleepMutex); mWakeupSignalled = true; diff --git a/AampLatencyMonitor.h b/AampLatencyMonitor.h index 4280273aaf..912c5808fb 100644 --- a/AampLatencyMonitor.h +++ b/AampLatencyMonitor.h @@ -185,6 +185,12 @@ class AampLatencyMonitor */ void EnableRateCorrection(bool enabled); + /** + * @brief Returns true if rate correction is currently enabled. + * Thread-safe (atomic load). + */ + bool IsRateCorrectionEnabled() const { return mCorrectionEnabled.load(); } + /** * @brief Returns the playback rate most recently applied by this monitor. * diff --git a/aampgstplayer.cpp b/aampgstplayer.cpp index 9512db260b..4dff8a982a 100644 --- a/aampgstplayer.cpp +++ b/aampgstplayer.cpp @@ -950,12 +950,6 @@ void AAMPGstPlayer::FlushTrack(AampMediaType type,double pos) double audioDelta = aamp->mAudioDelta; double subDelta = aamp->mSubtitleDelta; double rate = playerInstance->FlushTrack(mediaType, pos, audioDelta, subDelta); - - if(aamp->mCorrectionRate != rate) - { - AAMPLOG_MIL("Reset Rate Correction to 1"); - aamp->mCorrectionRate = rate; - } } /** @@ -1076,8 +1070,6 @@ void AAMPGstPlayer::Flush(double position, int rate, bool shouldTearDown) //reset buffer control states prior to gstreamer flush so that the first needs_data event is caught privateContext->mBufferControl[i].flush(); } - - aamp->mCorrectionRate = (double)AAMP_NORMAL_PLAY_RATE; } } diff --git a/fragmentcollector_hls.cpp b/fragmentcollector_hls.cpp index ac46c04aad..1b77062b01 100644 --- a/fragmentcollector_hls.cpp +++ b/fragmentcollector_hls.cpp @@ -4023,7 +4023,6 @@ AAMPStatusType StreamAbstractionAAMP_HLS::Init(TuneType tuneType) video->playTarget = 0; subtitle->playTarget = 0; aamp->NotifyOnEnteringLive(); - aamp->mDisableRateCorrection = false; } else if (((eTUNETYPE_SEEK == tuneType) || (eTUNETYPE_RETUNE == tuneType) || (eTUNETYPE_NEW_SEEK == tuneType)) && (this->rate > 0)) { @@ -4049,7 +4048,6 @@ AAMPStatusType StreamAbstractionAAMP_HLS::Init(TuneType tuneType) aamp->NotifyOnEnteringLive(); } AAMPLOG_INFO("StreamAbstractionAAMP_HLS: Live latency correction is enabled due to the seek (rate=%f) to live window!!", this->rate); - aamp->mDisableRateCorrection = false; } else { @@ -7020,7 +7018,7 @@ void StreamAbstractionAAMP_HLS::RefreshTrack(AampMediaType type) } track->AbortWaitForCachedAndFreeFragment(true); aamp->StopTrackInjection(type); - aamp->mDisableRateCorrection = true; + aamp->EnableLatencyMonitor(false); if(aamp->IsLive() && !track->seamlessAudioSwitchInProgress) { // Abort ongoing wait for playlist refresh, so the track change can be processed immediately. diff --git a/fragmentcollector_mpd.cpp b/fragmentcollector_mpd.cpp index 546ce142aa..1046e19121 100644 --- a/fragmentcollector_mpd.cpp +++ b/fragmentcollector_mpd.cpp @@ -3696,7 +3696,6 @@ AAMPStatusType StreamAbstractionAAMP_MPD::Init(TuneType tuneType) notifyEnteringLive = true; } AAMPLOG_INFO("StreamAbstractionAAMP_MPD: Live latency correction is enabled due to the seek (rate=%f) to live window!!", currentRate); - aamp->mDisableRateCorrection = false; } if (mLowLatencyMode && !liveAdjust) @@ -6532,7 +6531,7 @@ void StreamAbstractionAAMP_MPD::RefreshTrack(AampMediaType type) } track->AbortWaitForCachedAndFreeFragment(true); aamp->StopTrackInjection(type); - aamp->mDisableRateCorrection = true; + aamp->EnableLatencyMonitor(false); } } diff --git a/main_aamp.cpp b/main_aamp.cpp index e92290c0db..fdd15d5497 100755 --- a/main_aamp.cpp +++ b/main_aamp.cpp @@ -949,14 +949,8 @@ void PlayerInstanceAAMP::SetRateInternal(float rate,int overshootcorrection) } aamp->mSinkPaused = true; - if(aamp->GetLLDashServiceData()->lowLatencyMode) - { - // PAUSED to PLAY without tune, LLD rate correction is disabled to keep position - AAMPLOG_INFO("LL-Dash speed correction disabled after Pause"); - aamp->EnableLatencyMonitor(false); - } - AAMPLOG_INFO("StreamAbstractionAAMP_MPD: Live latency correction is disabled due to the Pause operation!!"); - aamp->mDisableRateCorrection = true; + AAMPLOG_INFO("Latency correction is disabled due to the Pause operation!!"); + aamp->EnableLatencyMonitor(false); } } else diff --git a/priv_aamp.cpp b/priv_aamp.cpp index 031c73f392..3f57fe3da6 100644 --- a/priv_aamp.cpp +++ b/priv_aamp.cpp @@ -1681,12 +1681,6 @@ PrivateInstanceAAMP::PrivateInstanceAAMP(AampConfig *config) : mReportProgressPo , vDynamicDrmData() , midFragmentSeekCache(false) , mLiveOffsetDrift(AAMP_DEFAULT_LIVE_OFFSET_DRIFT) - , mDisableRateCorrection (false) - , mRateCorrectionThread () - , mRateCorrectionWait() - , mRateCorrectionTimeoutLock() - , mAbortRateCorrection (false) - , mCorrectionRate(AAMP_NORMAL_PLAY_RATE) , mPreviousAudioType (FORMAT_INVALID) , mTsbRecordingId() , mthumbIndexValue(-1) @@ -1805,8 +1799,6 @@ PrivateInstanceAAMP::PrivateInstanceAAMP(AampConfig *config) : mReportProgressPo , mMPDStichOption(OPT_1_FULL_MANIFEST_TUNE),mMPDStichRefreshUrl("") , mTsbType("none") , mTsbDepthMs(0) - , mDiscStartTime(0) - , mRateCorrectionDelay(false) , mDownloadDelay(0) , curlhost{} , mWaitForDiscoToComplete() @@ -2305,7 +2297,7 @@ void PrivateInstanceAAMP::NotifyPauseOnStartPlayback(void) mpStreamAbstractionAAMP->NotifyPlaybackPaused(true); } AAMPLOG_INFO("Live latency correction is disabled after Pause"); - mDisableRateCorrection = true; + EnableLatencyMonitor(false); mSinkPaused = true; } @@ -2365,211 +2357,6 @@ void PrivateInstanceAAMP::SyncEnd(void) mLock.unlock(); } -/** - * @brief Abort wait for playlist download - */ -void PrivateInstanceAAMP::WakeupLatencyCheck() -{ - mRateCorrectionWait.notify_one(); -} - -/** - * @brief Wait until timeout is reached or interrupted - */ -void PrivateInstanceAAMP::TimedWaitForLatencyCheck(int timeInMs) -{ - if(timeInMs > 0 && DownloadsAreEnabled()) - { - std::unique_lock lock(mRateCorrectionTimeoutLock); - if(mRateCorrectionWait.wait_for(lock, std::chrono::milliseconds(timeInMs)) == std::cv_status::timeout) - { - AAMPLOG_TRACE(" Timeout exceeded Rate Correction Thread : %d", timeInMs); // make it trace - } - else - { - mAbortRateCorrection = true; - AAMPLOG_INFO(" Aborted Rate Correction Thread"); // TRACE - } - } -} - -/** - * @brief The helper function which perform tuning - * Common tune operations used on Tune, Seek, SetRate etc - */ -void PrivateInstanceAAMP::StopRateCorrectionWorkerThread(void) -{ - if (mRateCorrectionThread.joinable()) - { - try - { - mAbortRateCorrection = true; - WakeupLatencyCheck(); - mRateCorrectionThread.join(); - mCorrectionRate = AAMP_NORMAL_PLAY_RATE; - } - catch (exception& exp) - { - AAMPLOG_ERR("Rate Correction Thread Failed to Stop : %s ", exp.what()); - } - } -} -/** - * @brief The helper function which perform tuning - * Common tune operations used on Tune, Seek, SetRate etc - */ -void PrivateInstanceAAMP::StartRateCorrectionWorkerThread(void) -{ - try - { - bool newTune = IsNewTune(); - bool enabled = ISCONFIGSET_PRIV(eAAMPConfig_EnableLiveLatencyRateCorrection); - /** Spawn the rate Correction thread if it is live, new tune, thread not started yet, and rate correction enabled **/ - if(IsLive() && newTune && !mRateCorrectionThread.joinable() && enabled ) - { - mAbortRateCorrection = false; - mRateCorrectionThread = std::thread(&PrivateInstanceAAMP::RateCorrectionWorkerThread, this); - AAMPLOG_INFO("Rate Correction Thread started [%zx]", GetPrintableThreadID(mRateCorrectionThread)); //Print Id - KC - } - } - catch (exception& exp) - { - AAMPLOG_ERR("Rate Correction Thread Failed to start : %s ", exp.what()); - } -} - -/** - * @brief Rate correction API call in thread to avoid the time delay for setting rate - * This is single sleeping thread ; only wake up whenever it needed - */ -void PrivateInstanceAAMP::RateCorrectionWorkerThread(void) -{ - if(ISCONFIGSET_PRIV(eAAMPConfig_EnableLiveLatencyRateCorrection)) - { - int latencyMonitorInterval = GETCONFIGVALUE_PRIV(eAAMPConfig_LatencyMonitorIntervalMs); - double normalPlaybackRate = GETCONFIGVALUE_PRIV(eAAMPConfig_NormalLatencyCorrectionPlaybackRate); - double maxPlaybackRate = GETCONFIGVALUE_PRIV(eAAMPConfig_MaxLatencyCorrectionPlaybackRate); - double minPlaybackRate = GETCONFIGVALUE_PRIV(eAAMPConfig_MinLatencyCorrectionPlaybackRate); - int disableRateCorrectionTimeInSeconds = GETCONFIGVALUE_PRIV(eAAMPConfig_RateCorrectionDelay); - int latencyMonitorDelay = GETCONFIGVALUE_PRIV(eAAMPConfig_LatencyMonitorDelayMs); - AAMPLOG_TRACE("latencyMonitorDelay %d latencyMonitorInterval=%d", latencyMonitorDelay,latencyMonitorInterval ); - double latencyMonitorScheduleTimeMs = latencyMonitorDelay - latencyMonitorInterval; - //To handle latencyMonitorDelay < latencyMonitorInterval case - if( latencyMonitorScheduleTimeMs < 0) - { // clamp! - AAMPLOG_INFO("unexpected latencyMonitorScheduleTime(%lf) ms", latencyMonitorScheduleTimeMs ); - latencyMonitorScheduleTimeMs = 500; //TimedWaitForLatencyCheck here is 500 ms - } - while(!mAbortRateCorrection) - { - mCorrectionRate = rate; /**< To align with main playback rate start with rate*/ - double rateRequired = normalPlaybackRate; /**< Can be vary for debug*/ - TimedWaitForLatencyCheck(latencyMonitorScheduleTimeMs); - while(DownloadsAreEnabled()) - { - interruptibleMsSleep(latencyMonitorInterval); - AAMPPlayerState state = GetState(); - if (!mAbortRateCorrection &&!mDisableRateCorrection && DownloadsAreEnabled() && state == eSTATE_PLAYING) - { - double bufferedDuration = 0.0; - { - std::lock_guard guard(mStreamLock); - if (mpStreamAbstractionAAMP) - { - bufferedDuration = mpStreamAbstractionAAMP->GetBufferedVideoDurationSec(); - } - } - //If the player detect an empty period switch, it will set the buffer duration as -1 even though the player has content from previous period. - //In this case, player should not increase the playback speed to catchup the latency. - //So Setting isEnoughBuffer true by default and the value will update accordingly if only buffer duration is greater than -1. - bool isEnoughBuffer = true; - if(bufferedDuration > -1.0) - { - isEnoughBuffer = bufferedDuration > (mLiveOffset / 2); - } - double latency = static_cast(GetCurrentLatencyMs()) / 1000.0; // in seconds - AAMPLOG_INFO("Current latency is %.02lf current playback rate is %.02lf maxLiveOffset is %.02lf sec, target LiveOffset is %.02lf sec, minLiveOffset is %.02lf sec AvailableBuffer = %.02lf", - latency, mCorrectionRate, (mLiveOffset + mLiveOffsetDrift ), mLiveOffset, (mLiveOffset - mLiveOffsetDrift), bufferedDuration ); - if ((latency > (mLiveOffset + mLiveOffsetDrift)) && isEnoughBuffer) - { - rateRequired = maxPlaybackRate; - } - else if (latency < (mLiveOffset - mLiveOffsetDrift)) - { - rateRequired = minPlaybackRate; - } - else if (((latency <= mLiveOffset) && mCorrectionRate == maxPlaybackRate) || - ((latency >= mLiveOffset) && mCorrectionRate == minPlaybackRate) || - ((mCorrectionRate == maxPlaybackRate) && !isEnoughBuffer)) - { - rateRequired = normalPlaybackRate; - } - - if (disableRateCorrectionTimeInSeconds > 0 && mDiscStartTime > 0 && true == mRateCorrectionDelay) - { - int deltaTime = (int)(NOW_STEADY_TS_SECS- mDiscStartTime); - - AAMPLOG_INFO("mDiscStartTime %ld currenttime=%" PRId64 " delta=%d disableRateCorrectionTimeInSeconds=%d", - mDiscStartTime, NOW_STEADY_TS_SECS, deltaTime, disableRateCorrectionTimeInSeconds); - - if ( deltaTime > disableRateCorrectionTimeInSeconds ) - { - mRateCorrectionDelay = false; - mDiscStartTime = 0; - AAMPLOG_WARN("Rate correction is enabled after discontinuity processing"); - } - else - { - AAMPLOG_INFO("Rate correction is still disabled because still in discontinuity processing %ld", mDiscStartTime); - } - } - - StreamSink *sink = AampStreamSinkManager::GetInstance().GetStreamSink(this); - if (sink) - { - if( !mRateCorrectionDelay && (mCorrectionRate != rateRequired) && !mDiscontinuityTuneOperationInProgress) - { - if (sink->SetPlayBackRate(rateRequired)) - { - mCorrectionRate = rateRequired; - UpdateVideoEndMetrics(rateRequired); - SendAnomalyEvent(ANOMALY_WARNING, "Rate changed to:%f", rateRequired); - AAMPLOG_WARN("Rate Changed to : %f Live latency : %lf", rateRequired, latency); - profiler.IncrementChangeCount(Count_RateCorrection); - } - } - } - } - else - { - if (mDisableRateCorrection && DownloadsAreEnabled() && (rate == AAMP_NORMAL_PLAY_RATE && mCorrectionRate != normalPlaybackRate)) - { - //Rate correction stopping from correction rate so reset to normal - StreamSink *sink = AampStreamSinkManager::GetInstance().GetStreamSink(this); - if (sink) - { - if (sink->SetPlayBackRate(normalPlaybackRate)) - { - mCorrectionRate = normalPlaybackRate; - AAMPLOG_WARN("Rate Changed to : %f", mCorrectionRate); - } - else - { - AAMPLOG_WARN("Failed to reset the playback rate!!"); - } - } - } - } - } - } - } - else - { - AAMPLOG_WARN("Rate Correction Ignored Due to Rate Correction disabled from config; EnableLiveLatencyRateCorrection [%d]", - ISCONFIGSET_PRIV(eAAMPConfig_EnableLiveLatencyRateCorrection)); - } -} - /** * @brief API returns true is live stream and playing at the live point */ @@ -2752,14 +2539,10 @@ void PrivateInstanceAAMP::MonitorProgress(bool sync, bool beginningOfStream) // This is trickplay or slow motion currentRate = rate; } - else if(mAampLLDashServiceData.lowLatencyMode) + else if(mAampLLDashServiceData.lowLatencyMode || ISCONFIGSET_PRIV(eAAMPConfig_EnableLiveLatencyRateCorrection)) { currentRate = mLatencyMonitor->GetCurrentRate(); } - else if (!mAampLLDashServiceData.lowLatencyMode && ISCONFIGSET_PRIV(eAAMPConfig_EnableLiveLatencyRateCorrection) ) - { - currentRate = mCorrectionRate; - } else { currentRate = rate; @@ -3818,17 +3601,10 @@ bool PrivateInstanceAAMP::ProcessPendingDiscontinuity() mpStreamAbstractionAAMP->ResetESChangeStatus(); mpStreamAbstractionAAMP->ReSetPipelineFlushStatus(); - bool isRateCorrectionEnabled = ISCONFIGSET_PRIV(eAAMPConfig_EnableLiveLatencyRateCorrection); - int disableRateCorrectionTimeInSeconds = GETCONFIGVALUE_PRIV(eAAMPConfig_RateCorrectionDelay); - if( disableRateCorrectionTimeInSeconds > 0 && isRateCorrectionEnabled ) - { - mRateCorrectionDelay = true; - mDiscStartTime = NOW_STEADY_TS_SECS; - AAMPLOG_WARN("Rate correction is disabled on discontinuity processing : %ld", mDiscStartTime); - } - else + bool WasRateCorrectionEnabled = mLatencyMonitor->IsRateCorrectionEnabled(); + if(WasRateCorrectionEnabled) { - AAMPLOG_WARN("DisableRateCorrectionTimeInSeconds : %d isRateCorrectionEnabled : %d", disableRateCorrectionTimeInSeconds, isRateCorrectionEnabled); + EnableLatencyMonitor(false); } if(mDiscontinuityFound) @@ -3844,6 +3620,13 @@ bool PrivateInstanceAAMP::ProcessPendingDiscontinuity() sink->Stream(); } mIsTrackIdMismatch = false; + + // Discontinuity processing is complete; re-enable rate correction only if + // it was active before, filtering out unwanted latency correction wake-ups. + if (WasRateCorrectionEnabled) + { + EnableLatencyMonitor(true); + } } else { @@ -6039,7 +5822,6 @@ void PrivateInstanceAAMP::TuneHelper(TuneType tuneType, bool seekWhilePaused) { /** Enabled rate Correction by default, seek case and live added later point **/ AAMPLOG_INFO("Live latency correction is disabled for seek by default!!"); - mDisableRateCorrection = true; //Logging should be deactivated if the buffer exceeds the minimum buffer size or if seeking occurs if(mIsLoggingNeeded && mConfig->GetConfigOwner(eAAMPConfig_InfoLogging) == AAMP_DEFAULT_SETTING) { @@ -6048,10 +5830,6 @@ void PrivateInstanceAAMP::TuneHelper(TuneType tuneType, bool seekWhilePaused) mIsLoggingNeeded = false; } } - else - { - mDisableRateCorrection = false; - } if (tuneType == eTUNETYPE_SEEK || tuneType == eTUNETYPE_SEEKTOLIVE || tuneType == eTUNETYPE_SEEKTOEND) { @@ -6086,6 +5864,17 @@ void PrivateInstanceAAMP::TuneHelper(TuneType tuneType, bool seekWhilePaused) TeardownStream(newTune|| (eTUNETYPE_RETUNE == tuneType)); + // After teardown, apply the intended latency monitor state for this tune type. + // TeardownStream always disables it; re-enable here for non-seek operations. + if((eTUNETYPE_SEEK == tuneType) || (eTUNETYPE_NEW_SEEK == tuneType)) + { + EnableLatencyMonitor(false); + } + else + { + EnableLatencyMonitor(true); + } + if(SocUtils::ResetNewSegmentEvent()) { // Send new SEGMENT event only on all trickplay and trickplay -> play, not on pause -> play / seek while paused @@ -6413,13 +6202,8 @@ void PrivateInstanceAAMP::TuneHelper(TuneType tuneType, bool seekWhilePaused) mMediaFormat = eMEDIAFORMAT_HLS_MP4; } - if (ISCONFIGSET_PRIV(eAAMPConfig_EnableLiveLatencyRateCorrection)) - { - StartRateCorrectionWorkerThread(); - } - if (mMediaFormat == eMEDIAFORMAT_DASH && mAampLLDashServiceData.lowLatencyMode) + if (ISCONFIGSET_PRIV(eAAMPConfig_EnableLiveLatencyRateCorrection) || (mAampLLDashServiceData.lowLatencyMode && mMediaFormat == eMEDIAFORMAT_DASH)) { - // Start latency monitor for DASH Low Latency content. StartLatencyMonitor(); } @@ -8577,7 +8361,6 @@ void PrivateInstanceAAMP::Stop( bool sendStateChangeEvent ) DisableDownloads(); UnblockWaitForDiscontinuityProcessToComplete(); - StopRateCorrectionWorkerThread(); if(mTelemetryInterval > 0) { double bufferedDuration = 0.0; @@ -8708,7 +8491,6 @@ void PrivateInstanceAAMP::Stop( bool sendStateChangeEvent ) SetPauseOnStartPlayback(false); mSeekOperationInProgress = false; mTrickplayInProgress = false; - mDisableRateCorrection = false; mMaxLanguageCount = 0; // reset language count //mPreferredAudioTrack = AudioTrackInfo(); // reset mPreferredTextTrack = TextTrackInfo(); // reset @@ -13004,6 +12786,7 @@ void PrivateInstanceAAMP::SetPreferredLanguages(const char *languageList, const { seek_pos_seconds = GetPositionSeconds(); AAMPLOG_MIL("Retune to change the audio track at pos %fs", seek_pos_seconds); + bool wasAtLivePoint = IsAtLivePoint(); if (IsLocalAAMPTsb()) { mAampTsbLanguageChangeInProgress = true; @@ -13034,7 +12817,7 @@ void PrivateInstanceAAMP::SetPreferredLanguages(const char *languageList, const AAMPLOG_ERR("TSB Session Manager is NULL"); } } - else if(mDisableRateCorrection) + else if(!wasAtLivePoint) { TuneHelper(eTUNETYPE_SEEK); } @@ -15131,9 +14914,10 @@ void PrivateInstanceAAMP::StartLatencyMonitor() { bool lowLatencyCorrection = mAampLLDashServiceData.lowLatencyMode && ISCONFIGSET_PRIV(eAAMPConfig_EnableLowLatencyCorrection); + bool liveLatencyCorrection = ISCONFIGSET_PRIV(eAAMPConfig_EnableLiveLatencyRateCorrection); bool isAtLivePointWithNormalRate = IsAtLivePoint() && (rate == AAMP_NORMAL_PLAY_RATE); - if (IsLive() && lowLatencyCorrection && + if (IsLive() && (lowLatencyCorrection || liveLatencyCorrection) && isAtLivePointWithNormalRate && !mbPauseOnStartPlayback && !mPauseOnFirstVideoFrameDisp) { if (!mLatencyMonitor->IsRunning()) @@ -15149,6 +14933,14 @@ void PrivateInstanceAAMP::StartLatencyMonitor() } } +/** + * @brief Returns true if rate correction is currently enabled in the latency monitor. + */ +bool PrivateInstanceAAMP::IsLatencyMonitorEnabled() const +{ + return mLatencyMonitor->IsRateCorrectionEnabled(); +} + /** * @brief Stop the latency monitor */ diff --git a/priv_aamp.h b/priv_aamp.h index f0393970bd..9886c31cf9 100644 --- a/priv_aamp.h +++ b/priv_aamp.h @@ -883,7 +883,6 @@ class PrivateInstanceAAMP : public DrmCallbacks, public std::enable_shared_from_ std::recursive_mutex mLock; std::recursive_mutex mParallelPlaylistFetchLock; /**< mutex lock for parallel fetch */ - std::thread mRateCorrectionThread; /**< Rate correction thread Id **/ class StreamAbstractionAAMP *mpStreamAbstractionAAMP; /**< HLS or MPD collector */ class CDAIObject *mCdaiObject; /**< Client Side DAI Object */ @@ -1139,8 +1138,6 @@ class PrivateInstanceAAMP : public DrmCallbacks, public std::enable_shared_from_ in gst brcmaudiodecoder, default: True */ std::string mSessionToken; /**< Field to set session token for player */ bool midFragmentSeekCache; /**< To find if cache is updated when seeked to mid fragment boundary */ - bool mDisableRateCorrection; /**< Disable live latency correction when user pause or seek the playback **/ - bool mAbortRateCorrection; /**< Flag to abort rate correction thread **/ bool mAutoResumeTaskPending; std::string mTsbRecordingId; /**< Recording ID of current TSB */ @@ -1156,8 +1153,6 @@ class PrivateInstanceAAMP : public DrmCallbacks, public std::enable_shared_from_ double mProgressReportAvailabilityOffset; /**< Offset time for progress reporting from availability start */ double mAbsoluteEndPosition; /**< Live Edge position for absolute reporting */ AampConfig *mConfig; - long mDiscStartTime; /**< start time of discontinuity */ - bool mRateCorrectionDelay; /**ResumeTrackInjection((AampMediaType)eMEDIATYPE_AUDIO); NotifyCachedAudioFragmentAvailable(); loadNewAudio = false; - aamp->mDisableRateCorrection = false; + // Re-enable latency rate correction after audio track switch completes. + if (aamp->IsLive() && !aamp->IsLatencyMonitorEnabled()) + { + aamp->EnableLatencyMonitor(true); + } } if (loadNewSubtitle && (eTRACK_SUBTITLE == type) && !isInitSegment) { @@ -535,7 +539,11 @@ void MediaTrack::UpdateTSAfterFetchStats(CachedFragment* cachedFragment, bool is aamp->ResumeTrackInjection((AampMediaType)eMEDIATYPE_SUBTITLE); NotifyCachedSubtitleFragmentAvailable(); loadNewSubtitle = false; - aamp->mDisableRateCorrection = false; + // Re-enable latency rate correction after subtitle track switch completes. + if (aamp->IsLive() && !aamp->IsLatencyMonitorEnabled()) + { + aamp->EnableLatencyMonitor(true); + } } if (!isInitSegment) { diff --git a/test/utests/fakes/FakeAampLatencyMonitor.cpp b/test/utests/fakes/FakeAampLatencyMonitor.cpp index 2cd718cffb..341e3f162a 100644 --- a/test/utests/fakes/FakeAampLatencyMonitor.cpp +++ b/test/utests/fakes/FakeAampLatencyMonitor.cpp @@ -57,6 +57,7 @@ void AampLatencyMonitor::Stop() void AampLatencyMonitor::EnableRateCorrection(bool enabled) { + mCorrectionEnabled.store(enabled); } double AampLatencyMonitor::GetCurrentRate() const diff --git a/test/utests/fakes/FakePrivateInstanceAAMP.cpp b/test/utests/fakes/FakePrivateInstanceAAMP.cpp index 1d60204833..f4eb523c14 100644 --- a/test/utests/fakes/FakePrivateInstanceAAMP.cpp +++ b/test/utests/fakes/FakePrivateInstanceAAMP.cpp @@ -72,7 +72,6 @@ PrivateInstanceAAMP::PrivateInstanceAAMP(AampConfig *config) : mDrmInitData(), mPreferredTextTrack(), midFragmentSeekCache(false), - mDisableRateCorrection (false), mthumbIndexValue(-1), mMPDPeriodsInfo(), mProfileCappedStatus(false), @@ -1718,14 +1717,6 @@ void PrivateInstanceAAMP::UpdateLocalAAMPTsbInjection() } } -void PrivateInstanceAAMP::TimedWaitForLatencyCheck(int timeInMs) -{ -} - -void PrivateInstanceAAMP::WakeupLatencyCheck() -{ -} - void PrivateInstanceAAMP::IncreaseGSTBufferSize() { } @@ -1913,4 +1904,17 @@ bool PrivateInstanceAAMP::CheckForChunkEarlyAbort(CurlCallbackContext *context) void PrivateInstanceAAMP::EnableLatencyMonitor(bool enabled) { -} \ No newline at end of file + if (g_mockPrivateInstanceAAMP != nullptr) + { + g_mockPrivateInstanceAAMP->EnableLatencyMonitor(enabled); + } +} + +bool PrivateInstanceAAMP::IsLatencyMonitorEnabled() const +{ + if (g_mockPrivateInstanceAAMP != nullptr) + { + return g_mockPrivateInstanceAAMP->IsLatencyMonitorEnabled(); + } + return true; // default: rate correction enabled +} diff --git a/test/utests/mocks/MockPrivateInstanceAAMP.h b/test/utests/mocks/MockPrivateInstanceAAMP.h index 4b86c57ef7..3468f970e2 100644 --- a/test/utests/mocks/MockPrivateInstanceAAMP.h +++ b/test/utests/mocks/MockPrivateInstanceAAMP.h @@ -101,6 +101,8 @@ class MockPrivateInstanceAAMP MOCK_METHOD(long, GetCurrentLatencyMs, ()); MOCK_METHOD(double, GetBufferedDurationSecs, ()); MOCK_METHOD(bool, IsAdPlaying, ()); + MOCK_METHOD(void, EnableLatencyMonitor, (bool enabled)); + MOCK_METHOD(bool, IsLatencyMonitorEnabled, (), (const)); MOCK_METHOD(void, UpdateVideoEndMetrics, (double adjustedRate)); MOCK_METHOD(void, NotifyReservationComplete, (const std::string& reservationId)); MOCK_METHOD(void, LoadIDX, (ProfilerBucketType bucketType, std::string fragmentUrl, std::string& effectiveUrl, std::vector& fragment, unsigned int curlInstance, const char *range, int& http_code, double *downloadTime, AampMediaType mediaType, int *fogError)); diff --git a/test/utests/tests/PrivAampTests/PrivAampTests.cpp b/test/utests/tests/PrivAampTests/PrivAampTests.cpp index c0b03af46d..dd9a625dc8 100644 --- a/test/utests/tests/PrivAampTests/PrivAampTests.cpp +++ b/test/utests/tests/PrivAampTests/PrivAampTests.cpp @@ -1399,42 +1399,6 @@ TEST_F(PrivAampTests,GetVideoPTSTest) EXPECT_EQ(videoPTS,0); } -TEST_F(PrivAampTests,WakeupLatencyCheckTest) -{ - p_aamp->WakeupLatencyCheck(); -} -TEST_F(PrivAampTests,TimedWaitForLatencyCheckTest) -{ - int timeInMs = 10; - p_aamp->TimedWaitForLatencyCheck(timeInMs); - - // below are stress level test case - p_aamp->TimedWaitForLatencyCheck(0); - p_aamp->TimedWaitForLatencyCheck(100); - p_aamp->TimedWaitForLatencyCheck(500); - p_aamp->TimedWaitForLatencyCheck(-10); - p_aamp->TimedWaitForLatencyCheck(-12355); - p_aamp->TimedWaitForLatencyCheck(1235); - - EXPECT_FALSE(p_aamp->mAbortRateCorrection); -} - -TEST_F(PrivAampTests,StopRateCorrectionWorkerThreadTest) -{ - p_aamp->StartRateCorrectionWorkerThread(); - EXPECT_FALSE(p_aamp->mAbortRateCorrection); - - p_aamp->StopRateCorrectionWorkerThread(); - EXPECT_FALSE(p_aamp->mAbortRateCorrection); -} - -TEST_F(PrivAampTests,RateCorrectionWorkerThreadTest1) -{ - p_aamp->RateCorrectionWorkerThread(); - - EXPECT_NE(p_aamp->mCorrectionRate,0); - EXPECT_FALSE(p_aamp->mDisableRateCorrection); -} TEST_F(PrivAampTests,MonitorProgressTest1) { @@ -2716,11 +2680,11 @@ TEST_F(PrivAampTests, TuneHelperTest) TuneType tuneType=eTUNETYPE_SEEK; p_aamp->mEncryptedPeriodFound = true; p_aamp->mPipelineIsClear = true; - EXPECT_FALSE(p_aamp->mDisableRateCorrection); + EXPECT_TRUE(p_aamp->IsLatencyMonitorEnabled()); tuneType=eTUNETYPE_SEEKTOEND; p_aamp->TuneHelper(tuneType,true); - EXPECT_FALSE(p_aamp->mDisableRateCorrection); + EXPECT_TRUE(p_aamp->IsLatencyMonitorEnabled()); } TEST_F(PrivAampTests, TuneHelperTest_1) @@ -2730,7 +2694,7 @@ TEST_F(PrivAampTests, TuneHelperTest_1) tuneType=eTUNETYPE_NEW_NORMAL; p_aamp->TuneHelper(tuneType,true); - EXPECT_FALSE(p_aamp->mDisableRateCorrection); + EXPECT_TRUE(p_aamp->IsLatencyMonitorEnabled()); } TEST_F(PrivAampTests, TuneHelperTest_2) diff --git a/test/utests/tests/PrivateInstanceAAMP/PauseOnPlaybackTests.cpp b/test/utests/tests/PrivateInstanceAAMP/PauseOnPlaybackTests.cpp index 5f35768fe6..4af4304334 100644 --- a/test/utests/tests/PrivateInstanceAAMP/PauseOnPlaybackTests.cpp +++ b/test/utests/tests/PrivateInstanceAAMP/PauseOnPlaybackTests.cpp @@ -165,7 +165,6 @@ TEST_F(PauseOnPlaybackTests, SetPauseOnStartPlayback_NoSink) TEST_F(PauseOnPlaybackTests, NotifyPauseOnStartPlayback_NotActive) { mPrivateInstanceAAMP->mbDownloadsBlocked = false; - mPrivateInstanceAAMP->mDisableRateCorrection = false; mPrivateInstanceAAMP->SetLowLatencyMode(); @@ -175,7 +174,7 @@ TEST_F(PauseOnPlaybackTests, NotifyPauseOnStartPlayback_NotActive) EXPECT_FALSE(mPrivateInstanceAAMP->Test_PauseOnStartPlayback()); EXPECT_FALSE(mPrivateInstanceAAMP->mbDownloadsBlocked); - EXPECT_FALSE(mPrivateInstanceAAMP->mDisableRateCorrection); + EXPECT_TRUE(mPrivateInstanceAAMP->IsLatencyMonitorEnabled()); } // Testing calling NotifyPauseOnStartPlayback when Pause On Playback active @@ -183,7 +182,7 @@ TEST_F(PauseOnPlaybackTests, NotifyPauseOnStartPlayback_NotActive) TEST_F(PauseOnPlaybackTests, NotifyFirstFrameReceived_Success) { mPrivateInstanceAAMP->mbDownloadsBlocked = false; - mPrivateInstanceAAMP->mDisableRateCorrection = false; + EXPECT_TRUE(mPrivateInstanceAAMP->IsLatencyMonitorEnabled()); mPrivateInstanceAAMP->SetPauseOnStartPlayback(true); @@ -197,6 +196,6 @@ TEST_F(PauseOnPlaybackTests, NotifyFirstFrameReceived_Success) EXPECT_FALSE(mPrivateInstanceAAMP->Test_PauseOnStartPlayback()); EXPECT_TRUE(mPrivateInstanceAAMP->mbDownloadsBlocked); - EXPECT_TRUE(mPrivateInstanceAAMP->mDisableRateCorrection); + EXPECT_FALSE(mPrivateInstanceAAMP->IsLatencyMonitorEnabled()); } diff --git a/test/utests/tests/StreamAbstractionAAMP_MPD/FunctionalTests.cpp b/test/utests/tests/StreamAbstractionAAMP_MPD/FunctionalTests.cpp index f69220ab7d..b9c436bfc2 100644 --- a/test/utests/tests/StreamAbstractionAAMP_MPD/FunctionalTests.cpp +++ b/test/utests/tests/StreamAbstractionAAMP_MPD/FunctionalTests.cpp @@ -380,6 +380,9 @@ R"( EXPECT_CALL(*g_mockPrivateInstanceAAMP, GetLLDashChunkMode()).WillRepeatedly(Return(false)); + EXPECT_CALL(*g_mockPrivateInstanceAAMP, EnableLatencyMonitor(true)) + .Times(AnyNumber()); + EXPECT_CALL(*g_mockAampMPDDownloader, GetManifest (_, _, _)) .WillOnce(WithoutArgs(Invoke(this, &FunctionalTestsBase::GetManifestForMPDDownloader))); diff --git a/test/utests/tests/StreamAbstractionAAMP_MPD/subtitleTests.cpp b/test/utests/tests/StreamAbstractionAAMP_MPD/subtitleTests.cpp index 73a759d5d6..8e5d262c06 100644 --- a/test/utests/tests/StreamAbstractionAAMP_MPD/subtitleTests.cpp +++ b/test/utests/tests/StreamAbstractionAAMP_MPD/subtitleTests.cpp @@ -472,6 +472,7 @@ TEST_F(SubtitleTrackTests, RefreshTrack) EXPECT_NE(track, nullptr); MediaStreamContext *pMediaStreamContext = static_cast(track); EXPECT_EQ(pMediaStreamContext->refreshSubtitles,false); + EXPECT_CALL(*g_mockPrivateInstanceAAMP, EnableLatencyMonitor(false)).Times(1); CallRefreshTrack(eMEDIATYPE_SUBTITLE); EXPECT_EQ(pMediaStreamContext->refreshSubtitles,true); } From 37b5165d32d0c919042ee9e7155d8414c45dedfc Mon Sep 17 00:00:00 2001 From: srikanthreddybijjam-comcast Date: Thu, 14 May 2026 14:07:39 +0530 Subject: [PATCH 2/2] VPAAMP-28: Merge MonitorLatency and RateCorrectionWorkerThread Reason for change: Merged the new flow Test Procedure: Refer jira ticket VPAAMP-28 Priority: P2 Signed-off-by: srikanthreddybijjam-comcast --- AampLatencyMonitor.cpp | 5 ----- StreamAbstractionAAMP.h | 7 +++++++ fragmentcollector_hls.cpp | 6 ++++-- fragmentcollector_mpd.cpp | 3 +++ priv_aamp.cpp | 18 +++++++++++++----- priv_aamp.h | 5 +++++ streamabstraction.cpp | 10 +++++----- test/utests/fakes/FakeAampLatencyMonitor.cpp | 1 - test/utests/fakes/FakePrivateInstanceAAMP.cpp | 11 ++++++++++- test/utests/mocks/MockPrivateInstanceAAMP.h | 1 + 10 files changed, 48 insertions(+), 19 deletions(-) diff --git a/AampLatencyMonitor.cpp b/AampLatencyMonitor.cpp index c53c599304..4473245190 100644 --- a/AampLatencyMonitor.cpp +++ b/AampLatencyMonitor.cpp @@ -196,11 +196,6 @@ void AampLatencyMonitor::EnableRateCorrection(bool enabled) } mCorrectionEnabled.store(enabled); - if (!enabled) - { - // Reset rate to normal immediately, before the worker thread wakes up. - ResetToNormalRate(); - } { std::lock_guard lock(mSleepMutex); mWakeupSignalled = true; diff --git a/StreamAbstractionAAMP.h b/StreamAbstractionAAMP.h index dde1666cf2..b0d4ef89f8 100644 --- a/StreamAbstractionAAMP.h +++ b/StreamAbstractionAAMP.h @@ -606,6 +606,12 @@ class MediaTrack * @brief To Load New subtitle on seamless subtitle switch */ void LoadNewSubtitle(bool val); + /** + * @brief Save latency monitor enabled state before an audio/subtitle track switch. + * Used by RefreshTrack to record whether rate correction was active, + * so UpdateTSAfterFetchStats can restore it only when appropriate. + */ + void SaveLatencyMonitorStateBeforeSwitch(bool val) { mLatencyMonitorEnabledBeforeSwitch = val; } /** * @brief To set Track's Fetch and Inject duration after playlist update @@ -824,6 +830,7 @@ class MediaTrack bool abortInject; /**< Abort inject operations if flag is set*/ std::mutex audioMutex; /**< protection of audio track reconfiguration */ bool loadNewAudio; /**< Flag to indicate new audio loading started on seamless audio switch */ + bool mLatencyMonitorEnabledBeforeSwitch; /**< Saved latency monitor state before audio/subtitle track switch; used to restore only if it was active prior to the switch */ std::mutex subtitleMutex; bool loadNewSubtitle; int fragmentChunkIdxToInject; /**< Write position */ diff --git a/fragmentcollector_hls.cpp b/fragmentcollector_hls.cpp index 1b77062b01..baea8634f1 100644 --- a/fragmentcollector_hls.cpp +++ b/fragmentcollector_hls.cpp @@ -4022,7 +4022,7 @@ AAMPStatusType StreamAbstractionAAMP_HLS::Init(TuneType tuneType) audio->playTarget = 0; video->playTarget = 0; subtitle->playTarget = 0; - aamp->NotifyOnEnteringLive(); + aamp->NotifyOnEnteringLive();//NotifyOnEnteringLive invokes Init and the Latency correction will be applied in the next step when its at LivePoint. } else if (((eTUNETYPE_SEEK == tuneType) || (eTUNETYPE_RETUNE == tuneType) || (eTUNETYPE_NEW_SEEK == tuneType)) && (this->rate > 0)) { @@ -4045,7 +4045,7 @@ AAMPStatusType StreamAbstractionAAMP_HLS::Init(TuneType tuneType) subtitle->playTarget = 0; if (eTUNETYPE_SEEK == tuneType) { - aamp->NotifyOnEnteringLive(); + aamp->NotifyOnEnteringLive();//NotifyOnEnteringLive invokes Init and the Latency correction will be applied in the next step when its at LivePoint. } AAMPLOG_INFO("StreamAbstractionAAMP_HLS: Live latency correction is enabled due to the seek (rate=%f) to live window!!", this->rate); } @@ -7018,6 +7018,8 @@ void StreamAbstractionAAMP_HLS::RefreshTrack(AampMediaType type) } track->AbortWaitForCachedAndFreeFragment(true); aamp->StopTrackInjection(type); + // Save the latency monitor state before disabling - it will be restored after the switch only if it was active prior + track->SaveLatencyMonitorStateBeforeSwitch(aamp->IsLatencyMonitorRunning() && aamp->IsLatencyMonitorEnabled()); aamp->EnableLatencyMonitor(false); if(aamp->IsLive() && !track->seamlessAudioSwitchInProgress) { diff --git a/fragmentcollector_mpd.cpp b/fragmentcollector_mpd.cpp index 1046e19121..364cc2b1c3 100644 --- a/fragmentcollector_mpd.cpp +++ b/fragmentcollector_mpd.cpp @@ -3695,6 +3695,7 @@ AAMPStatusType StreamAbstractionAAMP_MPD::Init(TuneType tuneType) { notifyEnteringLive = true; } + //Live Latency correction is handled by live adjust. AAMPLOG_INFO("StreamAbstractionAAMP_MPD: Live latency correction is enabled due to the seek (rate=%f) to live window!!", currentRate); } @@ -6531,6 +6532,8 @@ void StreamAbstractionAAMP_MPD::RefreshTrack(AampMediaType type) } track->AbortWaitForCachedAndFreeFragment(true); aamp->StopTrackInjection(type); + // Save the latency monitor state before disabling - it will be restored after the switch only if it was active prior + track->SaveLatencyMonitorStateBeforeSwitch(aamp->IsLatencyMonitorRunning() && aamp->IsLatencyMonitorEnabled()); aamp->EnableLatencyMonitor(false); } } diff --git a/priv_aamp.cpp b/priv_aamp.cpp index 3f57fe3da6..2d9b1e9387 100644 --- a/priv_aamp.cpp +++ b/priv_aamp.cpp @@ -3601,8 +3601,8 @@ bool PrivateInstanceAAMP::ProcessPendingDiscontinuity() mpStreamAbstractionAAMP->ResetESChangeStatus(); mpStreamAbstractionAAMP->ReSetPipelineFlushStatus(); - bool WasRateCorrectionEnabled = mLatencyMonitor->IsRateCorrectionEnabled(); - if(WasRateCorrectionEnabled) + bool wasRateCorrectionEnabled = mLatencyMonitor->IsRateCorrectionEnabled(); + if(wasRateCorrectionEnabled) { EnableLatencyMonitor(false); } @@ -3623,7 +3623,7 @@ bool PrivateInstanceAAMP::ProcessPendingDiscontinuity() // Discontinuity processing is complete; re-enable rate correction only if // it was active before, filtering out unwanted latency correction wake-ups. - if (WasRateCorrectionEnabled) + if (wasRateCorrectionEnabled) { EnableLatencyMonitor(true); } @@ -5864,8 +5864,8 @@ void PrivateInstanceAAMP::TuneHelper(TuneType tuneType, bool seekWhilePaused) TeardownStream(newTune|| (eTUNETYPE_RETUNE == tuneType)); - // After teardown, apply the intended latency monitor state for this tune type. - // TeardownStream always disables it; re-enable here for non-seek operations. + // Disable monitor for SEEK (default); re-enable for all other tune types. + // StartLatencyMonitor() below will re-enable if the seek lands at the live edge. if((eTUNETYPE_SEEK == tuneType) || (eTUNETYPE_NEW_SEEK == tuneType)) { EnableLatencyMonitor(false); @@ -14941,6 +14941,14 @@ bool PrivateInstanceAAMP::IsLatencyMonitorEnabled() const return mLatencyMonitor->IsRateCorrectionEnabled(); } +/** + * @brief Returns true if the latency monitor worker thread is running. + */ +bool PrivateInstanceAAMP::IsLatencyMonitorRunning() const +{ + return mLatencyMonitor->IsRunning(); +} + /** * @brief Stop the latency monitor */ diff --git a/priv_aamp.h b/priv_aamp.h index 9886c31cf9..ef5d47707f 100644 --- a/priv_aamp.h +++ b/priv_aamp.h @@ -4020,6 +4020,11 @@ class PrivateInstanceAAMP : public DrmCallbacks, public std::enable_shared_from_ */ bool IsLatencyMonitorEnabled() const; + /** + * @brief Returns true if the latency monitor worker thread is running + */ + bool IsLatencyMonitorRunning() const; + /** * @brief Check if an ad is currently playing * @return true if an ad is playing, false otherwise diff --git a/streamabstraction.cpp b/streamabstraction.cpp index d7f25d0d60..3e9aaf305f 100644 --- a/streamabstraction.cpp +++ b/streamabstraction.cpp @@ -520,8 +520,8 @@ void MediaTrack::UpdateTSAfterFetchStats(CachedFragment* cachedFragment, bool is aamp->ResumeTrackInjection((AampMediaType)eMEDIATYPE_AUDIO); NotifyCachedAudioFragmentAvailable(); loadNewAudio = false; - // Re-enable latency rate correction after audio track switch completes. - if (aamp->IsLive() && !aamp->IsLatencyMonitorEnabled()) + // Re-enable latency rate correction after audio track switch only if it was previously enabled. + if (mLatencyMonitorEnabledBeforeSwitch) { aamp->EnableLatencyMonitor(true); } @@ -539,8 +539,8 @@ void MediaTrack::UpdateTSAfterFetchStats(CachedFragment* cachedFragment, bool is aamp->ResumeTrackInjection((AampMediaType)eMEDIATYPE_SUBTITLE); NotifyCachedSubtitleFragmentAvailable(); loadNewSubtitle = false; - // Re-enable latency rate correction after subtitle track switch completes. - if (aamp->IsLive() && !aamp->IsLatencyMonitorEnabled()) + // Re-enable latency rate correction after subtitle track switch only if it was previously enabled. + if (mLatencyMonitorEnabledBeforeSwitch) { aamp->EnableLatencyMonitor(true); } @@ -1920,7 +1920,7 @@ MediaTrack::MediaTrack(TrackType type, PrivateInstanceAAMP* aamp, const char* na mutex(), abortInject(false), mSubtitleParser(), refreshSubtitles(false), refreshAudio(false), mCachedFragmentChunks{}, fragmentChunkFetched(), fragmentChunkInjected(), maxCachedFragmentChunksPerTrack(0), - noMDATCount(0), loadNewAudio(false), audioFragmentCached(), audioMutex(), loadNewSubtitle(false), subtitleFragmentCached(), subtitleMutex(), + noMDATCount(0), loadNewAudio(false), mLatencyMonitorEnabledBeforeSwitch(false), audioFragmentCached(), audioMutex(), loadNewSubtitle(false), subtitleFragmentCached(), subtitleMutex(), abortPlaylistDownloader(true), plDownloadWait() ,dwnldMutex(), playlistDownloaderThread(NULL), mManifestUpdateCounter(0) ,mManifestUpdateWait(),prevDownloadStartTime(-1) diff --git a/test/utests/fakes/FakeAampLatencyMonitor.cpp b/test/utests/fakes/FakeAampLatencyMonitor.cpp index 341e3f162a..2cd718cffb 100644 --- a/test/utests/fakes/FakeAampLatencyMonitor.cpp +++ b/test/utests/fakes/FakeAampLatencyMonitor.cpp @@ -57,7 +57,6 @@ void AampLatencyMonitor::Stop() void AampLatencyMonitor::EnableRateCorrection(bool enabled) { - mCorrectionEnabled.store(enabled); } double AampLatencyMonitor::GetCurrentRate() const diff --git a/test/utests/fakes/FakePrivateInstanceAAMP.cpp b/test/utests/fakes/FakePrivateInstanceAAMP.cpp index f4eb523c14..35d1d334dc 100644 --- a/test/utests/fakes/FakePrivateInstanceAAMP.cpp +++ b/test/utests/fakes/FakePrivateInstanceAAMP.cpp @@ -1916,5 +1916,14 @@ bool PrivateInstanceAAMP::IsLatencyMonitorEnabled() const { return g_mockPrivateInstanceAAMP->IsLatencyMonitorEnabled(); } - return true; // default: rate correction enabled + return true; +} + +bool PrivateInstanceAAMP::IsLatencyMonitorRunning() const +{ + if (g_mockPrivateInstanceAAMP != nullptr) + { + return g_mockPrivateInstanceAAMP->IsLatencyMonitorRunning(); + } + return true; } diff --git a/test/utests/mocks/MockPrivateInstanceAAMP.h b/test/utests/mocks/MockPrivateInstanceAAMP.h index 3468f970e2..d9087fd986 100644 --- a/test/utests/mocks/MockPrivateInstanceAAMP.h +++ b/test/utests/mocks/MockPrivateInstanceAAMP.h @@ -103,6 +103,7 @@ class MockPrivateInstanceAAMP MOCK_METHOD(bool, IsAdPlaying, ()); MOCK_METHOD(void, EnableLatencyMonitor, (bool enabled)); MOCK_METHOD(bool, IsLatencyMonitorEnabled, (), (const)); + MOCK_METHOD(bool, IsLatencyMonitorRunning, (), (const)); MOCK_METHOD(void, UpdateVideoEndMetrics, (double adjustedRate)); MOCK_METHOD(void, NotifyReservationComplete, (const std::string& reservationId)); MOCK_METHOD(void, LoadIDX, (ProfilerBucketType bucketType, std::string fragmentUrl, std::string& effectiveUrl, std::vector& fragment, unsigned int curlInstance, const char *range, int& http_code, double *downloadTime, AampMediaType mediaType, int *fogError));