diff --git a/AampStreamSinkManager.cpp b/AampStreamSinkManager.cpp index ca9354bb54..0f5023f118 100644 --- a/AampStreamSinkManager.cpp +++ b/AampStreamSinkManager.cpp @@ -497,7 +497,7 @@ void AampStreamSinkManager::SetActive(PrivateInstanceAAMP *aamp, double position mGstPlayer->ChangeAamp(aamp, mInactiveGstPlayersMap[aamp]->GetID3MetadataHandler()); aamp->mIsFlushOperationInProgress = true; - mGstPlayer->Flush(position, aamp->rate, true); + mGstPlayer->Flush(position, aamp->rate, true,false); aamp->mIsFlushOperationInProgress = false; mGstPlayer->SetSubtitleMute(aamp->subtitles_muted); if(!aamp->IsTuneCompleted() && aamp->IsPlayEnabled() && (mPipelineMode == ePIPELINEMODE_SINGLE)) diff --git a/StreamSink.h b/StreamSink.h index 80ae915e42..2951699021 100644 --- a/StreamSink.h +++ b/StreamSink.h @@ -133,9 +133,14 @@ class StreamSink * @param[in] position - playback position * @param[in] rate - Speed * @param[in] shouldTearDown - if pipeline is not in a valid state, tear down pipeline + * @param[in] keepPausedSeek - true only when this Flush is part of an explicit seek-with-keepPaused + * request. Must NOT be inferred from the pipeline's incidental paused + * state (which can be true for unrelated reasons such as buffering or + * fragment caching), since that conflation can permanently block later + * PLAYING transitions when no explicit resume ever arrives. * @return void */ - virtual void Flush(double position = 0, int rate = AAMP_NORMAL_PLAY_RATE, bool shouldTearDown = true){} + virtual void Flush(double position = 0, int rate = AAMP_NORMAL_PLAY_RATE, bool shouldTearDown = true, bool keepPausedSeek = false){} /** * @brief Flush the audio playbin diff --git a/aampgstplayer.cpp b/aampgstplayer.cpp index 9957537a79..32a3f24a5e 100644 --- a/aampgstplayer.cpp +++ b/aampgstplayer.cpp @@ -1124,7 +1124,7 @@ void AAMPGstPlayer::SetAudioVolume(int volume) /** * @brief Flush cached GstBuffers and set seek position & rate */ -void AAMPGstPlayer::Flush(double position, int rate, bool shouldTearDown) +void AAMPGstPlayer::Flush(double position, int rate, bool shouldTearDown, bool keepPausedSeek) { if(ISCONFIGSET(eAAMPConfig_SuppressDecode)) { @@ -1136,7 +1136,7 @@ void AAMPGstPlayer::Flush(double position, int rate, bool shouldTearDown) { isAppSeek = true; } - bool ret = playerInstance->Flush(position, rate, shouldTearDown, isAppSeek); + bool ret = playerInstance->Flush(position, rate, shouldTearDown, isAppSeek, keepPausedSeek); if(ret) { for (int i = 0; i < AAMP_TRACK_COUNT; i++) @@ -1269,7 +1269,7 @@ void AAMPGstPlayer::SeekStreamSink(double position, double rate) // shouldTearDown is set to false, because in case of a new tune pipeline // might not be in a playing/paused state which causes Flush() to destroy // pipeline. This has to be avoided. - Flush(position, rate, false); + Flush(position, rate, false, false); } diff --git a/aampgstplayer.h b/aampgstplayer.h index 426297cc1f..86d390b59e 100644 --- a/aampgstplayer.h +++ b/aampgstplayer.h @@ -167,8 +167,9 @@ class AAMPGstPlayer : public StreamSink * @param[in] position playback seek position * @param[in] rate playback rate * @param[in] shouldTearDown flag indicates if pipeline should be destroyed if in invalid state + * @param[in] keepPausedSeek true only for an explicit seek-with-keepPaused request */ - void Flush(double position, int rate, bool shouldTearDown) override; + void Flush(double position, int rate, bool shouldTearDown, bool keepPausedSeek) override; /** * @fn Pause * @param[in] pause flag to pause/play the pipeline diff --git a/main_aamp.cpp b/main_aamp.cpp index 1e0223ad00..fc6e19b654 100755 --- a/main_aamp.cpp +++ b/main_aamp.cpp @@ -917,8 +917,32 @@ void PlayerInstanceAAMP::SetRateInternal(float rate,int overshootcorrection) { retValue = sink->Pause(false, false); } - // required since buffers are already cached in paused state - aamp->NotifyFirstBufferProcessed(sink ? sink->GetVideoRectangle() : std::string()); + if (sink && !retValue) + { + // Pipeline resume did not complete (async PAUSED->PLAYING wedged by a + // rapid trickplay->seek->resume race - seen on both VOD and FOG-TSB linear). + // Recover by re-seeking to the current position: the same mechanism the + // local-TSB resume path uses. Works uniformly for VOD, FOG-TSB & local TSB. + AAMPLOG_WARN("SetRateInternal: pipeline resume failed (GstState timeout); recovering via re-seek"); + aamp->SetState(eSTATE_SEEKING); + aamp->seek_pos_seconds = aamp->GetPositionSeconds(); + aamp->rate = AAMP_NORMAL_PLAY_RATE; + aamp->mSinkPaused = false; + { + std::lock_guard lock(aamp->GetStreamLock()); + aamp->TuneHelper(eTUNETYPE_SEEK, false); + } + + // Skip common notification (like local-TSB path): state -> PLAYING + // via NotifyFirstBufferProcessed once fragments arrive. + retValue = false; + aamp->NotifySpeedChanged(aamp->rate, false); + } + else + { + // required since buffers are already cached in paused state + aamp->NotifyFirstBufferProcessed(sink ? sink->GetVideoRectangle() : std::string()); + } } } aamp->mSinkPaused = false; diff --git a/middleware/InterfacePlayerRDK.cpp b/middleware/InterfacePlayerRDK.cpp index fb29e69038..bd90c9eab1 100644 --- a/middleware/InterfacePlayerRDK.cpp +++ b/middleware/InterfacePlayerRDK.cpp @@ -1565,7 +1565,7 @@ bool InterfacePlayerRDK::IsUsingRialtoSink() /** * @brief Flush cached GstBuffers and set seek position & rate */ -bool InterfacePlayerRDK::Flush(double position, int rate, bool shouldTearDown, bool isAppSeek) +bool InterfacePlayerRDK::Flush(double position, int rate, bool shouldTearDown, bool isAppSeek, bool keepPausedSeek) { GstState aud_current; GstState aud_pending; diff --git a/middleware/InterfacePlayerRDK.h b/middleware/InterfacePlayerRDK.h index ba5a090828..515ccb7877 100644 --- a/middleware/InterfacePlayerRDK.h +++ b/middleware/InterfacePlayerRDK.h @@ -717,7 +717,7 @@ class InterfacePlayerRDK * @param[in] GstState The desired GStreamer pipeline state. * @param[in] gstMediaFormat The media format for the pipeline. */ - bool Flush(double position, int rate, bool shouldTearDown, bool isAppSeek); + bool Flush(double position, int rate, bool shouldTearDown, bool isAppSeek, bool keepPausedSeek); /** * @fn TimerAdd * @param[in] funcPtr function to execute on timer expiry diff --git a/priv_aamp.cpp b/priv_aamp.cpp index 057a52b5fb..4612a6eaa9 100644 --- a/priv_aamp.cpp +++ b/priv_aamp.cpp @@ -6503,7 +6503,7 @@ void PrivateInstanceAAMP::TuneHelper(TuneType tuneType, bool seekWhilePaused) // shouldTearDown is set to false, because in case of a new tune pipeline // might not be in a playing/paused state which causes Flush() to destroy // pipeline. This has to be avoided. - sink->Flush(flushPosition, rate, false); + sink->Flush(flushPosition, rate, false, seekWhilePaused); } }