diff --git a/fragmentcollector_mpd.cpp b/fragmentcollector_mpd.cpp index 546ce142a..1462bafca 100644 --- a/fragmentcollector_mpd.cpp +++ b/fragmentcollector_mpd.cpp @@ -1929,17 +1929,18 @@ bool StreamAbstractionAAMP_MPD::HandleSeekEOSAndPeriodTransition(double remainin { bool switchToNextPeriod = false; - // Check whether any track hit EOS during the seek. Any enabled track reaching EOS - // is sufficient to trigger a period transition: DASH spec requires all tracks in a - // period to end at the same presentation time, so this is safe for well-formed content. - // The mPlayRate and remainingSeek guards (comment 2 & 3) prevent false positives: + // Check whether any *enabled* track hit EOS during the seek. Only enabled tracks + // participate in period transition: a disabled track (e.g. an audio track deselected + // mid-playback, or a subtitle track the app has not activated) cannot reliably signal + // a period boundary and must not drive a forward switch on its own. + // The mPlayRate and remainingSeek guards prevent false positives: // - mPlayRate >= AAMP_RATE_PAUSE: for reverse playback (mPlayRate < 0), EOS means // beginning-of-period, not end-of-period, so we must not advance to the next period. - // - remainingSeek >= 0: a negative remainder also indicates the seek overshot backward + // - remainingSeek >= 0: a negative remainder indicates the seek overshot backward // rather than forward, so no forward period transition is appropriate. for (int i = 0; i < mNumberOfTracks; i++) { - if (mMediaStreamContext[i] != NULL && mMediaStreamContext[i]->eos && (mPlayRate >= AAMP_RATE_PAUSE) && remainingSeek >= 0) + if (mMediaStreamContext[i] != NULL && mMediaStreamContext[i]->enabled && mMediaStreamContext[i]->eos && (mPlayRate >= AAMP_RATE_PAUSE) && remainingSeek >= 0) { switchToNextPeriod = true; break; diff --git a/test/utests/tests/StreamAbstractionAAMP_MPD/FetcherLoopTests.cpp b/test/utests/tests/StreamAbstractionAAMP_MPD/FetcherLoopTests.cpp index a242cfdf2..942a07116 100644 --- a/test/utests/tests/StreamAbstractionAAMP_MPD/FetcherLoopTests.cpp +++ b/test/utests/tests/StreamAbstractionAAMP_MPD/FetcherLoopTests.cpp @@ -165,6 +165,25 @@ class FetcherLoopTests : public ::testing::Test { mIsFogTSB = value; } + + bool InvokeHandleSeekEOSAndPeriodTransition(double remainingSeek, bool skipToEnd) + { + return HandleSeekEOSAndPeriodTransition(remainingSeek, skipToEnd); + } + + int GetNumberOfTracks() const + { + return mNumberOfTracks; + } + + MediaStreamContext* GetMediaStreamContextAt(int idx) + { + if ((idx < 0) || (idx >= mNumberOfTracks)) + { + return nullptr; + } + return mMediaStreamContext[idx]; + } }; PrivateInstanceAAMP *mPrivateInstanceAAMP; @@ -2642,3 +2661,43 @@ INSTANTIATE_TEST_SUITE_P( BasicFetcherLoopMPDTests, AdvancedFetcherLoopTests, ::testing::ValuesIn(testCases)); + +/** + * @brief VPAAMP-342: HandleSeekEOSAndPeriodTransition must not trigger a forward period + * transition when EOS is reported only on disabled tracks. + * + * Scenario: after init at period 0, mark all initialized non-NULL tracks disabled and set + * their eos flags. Call HandleSeekEOSAndPeriodTransition with a non-negative remainingSeek. + * Expected (post-fix): no period transition occurs (returns false, period index unchanged). + * Pre-fix behaviour: the enabled check was absent, so eos on any non-NULL track drove + * a transition even if that track was not active. + */ +TEST_F(FetcherLoopTests, HandleSeekEOS_DisabledTrack_NoPeriodTransition) +{ + AAMPStatusType status; + + EXPECT_CALL(*g_mockMediaStreamContext, CacheFragment(_, _, _, _, _, true, _, _, _)) + .WillRepeatedly(Return(true)); + + status = InitializeMPD(mVodManifest); + EXPECT_EQ(status, eAAMPSTATUS_OK); + + // Mark all initialized tracks as disabled with eos set so that, without the enabled + // guard, every non-NULL context would independently fire the period-transition path. + for (int i = 0; i < mTestableStreamAbstractionAAMP_MPD->GetNumberOfTracks(); i++) + { + MediaStreamContext *ctx = mTestableStreamAbstractionAAMP_MPD->GetMediaStreamContextAt(i); + if (ctx) + { + ctx->enabled = false; + ctx->eos = true; + } + } + + int periodBefore = mTestableStreamAbstractionAAMP_MPD->GetCurrentPeriodIdx(); + bool transitioned = mTestableStreamAbstractionAAMP_MPD->InvokeHandleSeekEOSAndPeriodTransition(0.0, false); + + // Disabled tracks must not trigger a forward period transition. + EXPECT_FALSE(transitioned); + EXPECT_EQ(mTestableStreamAbstractionAAMP_MPD->GetCurrentPeriodIdx(), periodBefore); +}