Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
24 changes: 17 additions & 7 deletions aampgstplayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -842,12 +842,14 @@ void AAMPGstPlayer::EndOfStreamReached(AampMediaType type)
*/
void AAMPGstPlayer::Stop(bool keepLastFrame)
{
aamp->SyncBegin();
AAMPLOG_MIL("entering AAMPGstPlayer_Stop keepLastFrame %d", keepLastFrame);
StopMonitorAvTimer();
playerInstance->Stop(keepLastFrame);

aamp->seiTimecode.assign("");
AAMPLOG_MIL("exiting AAMPGstPlayer_Stop");
aamp->SyncEnd();
}


Expand Down Expand Up @@ -928,21 +930,29 @@ long long AAMPGstPlayer::GetPositionMilliseconds(void)
*/
bool AAMPGstPlayer::Pause( bool pause, bool forceStopGstreamerPreBuffering )
{
aamp->SyncBegin(); /* Obtains a mutex lock */
bool res = false;

AAMPLOG_MIL("entering AAMPGstPlayer_Pause - pause(%d) stop-pre-buffering(%d)", pause, forceStopGstreamerPreBuffering);
aamp->SyncBegin(); /* Obtains a mutex lock */

bool res = this->playerInstance->Pause(pause, forceStopGstreamerPreBuffering);
if(res)
if (!playerInstance)
{
AAMPLOG_WARN("AAMPGstPlayer_Pause called but playerInstance is null");
}
else
{
if(!aamp->IsGstreamerSubsEnabled())
aamp->PauseSubtitleParser(pause);
AAMPLOG_MIL("entering AAMPGstPlayer_Pause - pause(%d) stop-pre-buffering(%d)", pause, forceStopGstreamerPreBuffering);

res = this->playerInstance->Pause(pause, forceStopGstreamerPreBuffering);
if(res)
{
if(!aamp->IsGstreamerSubsEnabled())
aamp->PauseSubtitleParser(pause);
}
}

aamp->SyncEnd(); /* Releases the mutex */

return res;
//return retValue;
}

/**
Expand Down
8 changes: 8 additions & 0 deletions test/utests/fakes/FakePrivateInstanceAAMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -951,10 +951,18 @@ void PrivateInstanceAAMP::StopTrackInjection(AampMediaType type)

void PrivateInstanceAAMP::SyncBegin(void)
{
if (g_mockPrivateInstanceAAMP != nullptr)
{
g_mockPrivateInstanceAAMP->SyncBegin();
}
}

void PrivateInstanceAAMP::SyncEnd(void)
{
if (g_mockPrivateInstanceAAMP != nullptr)
{
g_mockPrivateInstanceAAMP->SyncEnd();
}
}

void PrivateInstanceAAMP::UpdateCullingState(double culledSecs)
Expand Down
2 changes: 2 additions & 0 deletions test/utests/mocks/MockPrivateInstanceAAMP.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ class MockPrivateInstanceAAMP
MOCK_METHOD(bool, IsLiveStream, ());
MOCK_METHOD(void, Individualization, (const std::string &payload));
MOCK_METHOD(void, UpdateUseSinglePipeline, ());
MOCK_METHOD(void, SyncBegin, ());
MOCK_METHOD(void, SyncEnd, ());
};

extern MockPrivateInstanceAAMP *g_mockPrivateInstanceAAMP;
Expand Down
46 changes: 46 additions & 0 deletions test/utests/tests/AampGstPlayer/FunctionalTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -640,4 +640,50 @@ TEST_F(AAMPGstPlayerTests, MonitorAV )
DestroyAMPGstPlayer();
}

TEST_F(AAMPGstPlayerTests, Pause_NullPlayerInstance)
{
// Setup
ConstructAMPGstPlayer();

// Simulate playerInstance being null (as could happen during a race with Stop)
InterfacePlayerRDK *savedPlayerInstance = mAAMPGstPlayer->playerInstance;
mAAMPGstPlayer->playerInstance = nullptr;

// Expect SyncBegin/SyncEnd to be called even when playerInstance is null
EXPECT_CALL(*g_mockPrivateInstanceAAMP, SyncBegin()).Times(2);
EXPECT_CALL(*g_mockPrivateInstanceAAMP, SyncEnd()).Times(2);

// Code under test - should return false without crashing
bool result = mAAMPGstPlayer->Pause(true, false);
EXPECT_FALSE(result);

result = mAAMPGstPlayer->Pause(false, false);
EXPECT_FALSE(result);

// Restore playerInstance for proper cleanup
mAAMPGstPlayer->playerInstance = savedPlayerInstance;

// Tidy Up
DestroyAMPGstPlayer();
}

TEST_F(AAMPGstPlayerTests, Stop_WithPipeline)
{
// Setup
ConstructAMPGstPlayer();
SetupPipeline(&tbl[0]);

// Expect SyncBegin/SyncEnd to be called during Stop
EXPECT_CALL(*g_mockPrivateInstanceAAMP, SyncBegin()).Times(1);
EXPECT_CALL(*g_mockPrivateInstanceAAMP, SyncEnd()).Times(1);

// Code under test - Stop should execute with SyncBegin/SyncEnd without issues
mAAMPGstPlayer->Stop(false);

// After Stop, playerInstance->Stop() should have been called (pipeline torn down)
// The DestroyAMPGstPlayer expectations for pipeline teardown are no longer needed
isPipelineSetup = false;

// Tidy Up
DestroyAMPGstPlayer();
}
Loading