diff --git a/media/server/gstplayer/include/GstGenericPlayer.h b/media/server/gstplayer/include/GstGenericPlayer.h index 8ea963d8d..496927cb5 100644 --- a/media/server/gstplayer/include/GstGenericPlayer.h +++ b/media/server/gstplayer/include/GstGenericPlayer.h @@ -194,6 +194,7 @@ class GstGenericPlayer : public IGstGenericPlayer, public IGstGenericPlayerPriva bool reattachSource(const std::unique_ptr &source) override; bool hasSourceType(const MediaSourceType &mediaSourceType) const override; GstElement *getSink(const MediaSourceType &mediaSourceType) const override; + GstElement *getDecoder(const MediaSourceType &mediaSourceType) override; void setSourceFlushed(const MediaSourceType &mediaSourceType) override; bool isAsync(const MediaSourceType &mediaSourceType) const; void notifyPlaybackInfo() override; @@ -297,15 +298,6 @@ class GstGenericPlayer : public IGstGenericPlayer, public IGstGenericPlayerPriva */ GstElement *getSinkChildIfAutoAudioSink(GstElement *sink) const; - /** - * @brief Gets the decoder element for source type. - * - * @param[in] mediaSourceType : the source type to obtain the decoder for - * - * @retval The decoder, NULL if not found - */ - GstElement *getDecoder(const MediaSourceType &mediaSourceType); - /** * @brief Gets the parser element for source type. * diff --git a/media/server/gstplayer/include/IGstGenericPlayerPrivate.h b/media/server/gstplayer/include/IGstGenericPlayerPrivate.h index 9b6d54af0..0b05b3ef2 100644 --- a/media/server/gstplayer/include/IGstGenericPlayerPrivate.h +++ b/media/server/gstplayer/include/IGstGenericPlayerPrivate.h @@ -288,6 +288,15 @@ class IGstGenericPlayerPrivate */ virtual GstElement *getSink(const MediaSourceType &mediaSourceType) const = 0; + /** + * @brief Gets the decoder element for source type. + * + * @param[in] mediaSourceType : the source type to obtain the decoder for + * + * @retval The decoder, NULL if not found. Please call getObjectUnref() if it's non-null + */ + virtual GstElement *getDecoder(const MediaSourceType &mediaSourceType) = 0; + /** * @brief Pushes GstSample if playback position has changed or new segment needs to be sent. * diff --git a/media/server/gstplayer/include/tasks/IGenericPlayerTaskFactory.h b/media/server/gstplayer/include/tasks/IGenericPlayerTaskFactory.h index 54b8fc621..5d318dc46 100644 --- a/media/server/gstplayer/include/tasks/IGenericPlayerTaskFactory.h +++ b/media/server/gstplayer/include/tasks/IGenericPlayerTaskFactory.h @@ -202,11 +202,14 @@ class IGenericPlayerTaskFactory * @brief Creates a SetPlaybackRate task. * * @param[in] context : The GstGenericPlayer context + * @param[in] player : The GstGenericPlayer instance * @param[in] rate : The new playback rate. * * @retval the new SetPlaybackRate task instance. */ - virtual std::unique_ptr createSetPlaybackRate(GenericPlayerContext &context, double rate) const = 0; + virtual std::unique_ptr createSetPlaybackRate(GenericPlayerContext &context, + IGstGenericPlayerPrivate &player, + double rate) const = 0; /** * @brief Creates a SetPosition task. diff --git a/media/server/gstplayer/include/tasks/generic/GenericPlayerTaskFactory.h b/media/server/gstplayer/include/tasks/generic/GenericPlayerTaskFactory.h index 79e31838b..abad4efcf 100644 --- a/media/server/gstplayer/include/tasks/generic/GenericPlayerTaskFactory.h +++ b/media/server/gstplayer/include/tasks/generic/GenericPlayerTaskFactory.h @@ -69,7 +69,8 @@ class GenericPlayerTaskFactory : public IGenericPlayerTaskFactory IGstGenericPlayerPrivate &player) const override; std::unique_ptr createCheckAudioUnderflow(GenericPlayerContext &context, IGstGenericPlayerPrivate &player) const override; - std::unique_ptr createSetPlaybackRate(GenericPlayerContext &context, double rate) const override; + std::unique_ptr createSetPlaybackRate(GenericPlayerContext &context, IGstGenericPlayerPrivate &player, + double rate) const override; std::unique_ptr createSetPosition(GenericPlayerContext &context, IGstGenericPlayerPrivate &player, std::int64_t position) const override; std::unique_ptr createSetupElement(GenericPlayerContext &context, IGstGenericPlayerPrivate &player, diff --git a/media/server/gstplayer/include/tasks/generic/SetPlaybackRate.h b/media/server/gstplayer/include/tasks/generic/SetPlaybackRate.h index 8adbddcf7..cdbefd04c 100644 --- a/media/server/gstplayer/include/tasks/generic/SetPlaybackRate.h +++ b/media/server/gstplayer/include/tasks/generic/SetPlaybackRate.h @@ -22,6 +22,7 @@ #include "GenericPlayerContext.h" #include "IGlibWrapper.h" +#include "IGstGenericPlayerPrivate.h" #include "IGstWrapper.h" #include "IPlayerTask.h" #include @@ -31,13 +32,15 @@ namespace firebolt::rialto::server::tasks::generic class SetPlaybackRate : public IPlayerTask { public: - SetPlaybackRate(GenericPlayerContext &context, std::shared_ptr gstWrapper, + SetPlaybackRate(GenericPlayerContext &context, IGstGenericPlayerPrivate &player, + std::shared_ptr gstWrapper, std::shared_ptr glibWrapper, double rate); ~SetPlaybackRate() override; void execute() const override; private: GenericPlayerContext &m_context; + IGstGenericPlayerPrivate &m_player; std::shared_ptr m_gstWrapper; std::shared_ptr m_glibWrapper; double m_rate; diff --git a/media/server/gstplayer/source/GstGenericPlayer.cpp b/media/server/gstplayer/source/GstGenericPlayer.cpp index 56030d04d..3cb5520bf 100644 --- a/media/server/gstplayer/source/GstGenericPlayer.cpp +++ b/media/server/gstplayer/source/GstGenericPlayer.cpp @@ -389,7 +389,7 @@ void GstGenericPlayer::setPlaybackRate(double rate) { if (m_workerThread) { - m_workerThread->enqueueTask(m_taskFactory->createSetPlaybackRate(m_context, rate)); + m_workerThread->enqueueTask(m_taskFactory->createSetPlaybackRate(m_context, *this, rate)); } } diff --git a/media/server/gstplayer/source/tasks/generic/GenericPlayerTaskFactory.cpp b/media/server/gstplayer/source/tasks/generic/GenericPlayerTaskFactory.cpp index a7886a335..39a773da0 100644 --- a/media/server/gstplayer/source/tasks/generic/GenericPlayerTaskFactory.cpp +++ b/media/server/gstplayer/source/tasks/generic/GenericPlayerTaskFactory.cpp @@ -160,9 +160,10 @@ std::unique_ptr GenericPlayerTaskFactory::createCheckAudioUnderflow } std::unique_ptr GenericPlayerTaskFactory::createSetPlaybackRate(GenericPlayerContext &context, + IGstGenericPlayerPrivate &player, double rate) const { - return std::make_unique(context, m_gstWrapper, m_glibWrapper, rate); + return std::make_unique(context, player, m_gstWrapper, m_glibWrapper, rate); } std::unique_ptr GenericPlayerTaskFactory::createSetPosition(GenericPlayerContext &context, diff --git a/media/server/gstplayer/source/tasks/generic/SetPlaybackRate.cpp b/media/server/gstplayer/source/tasks/generic/SetPlaybackRate.cpp index f5f8f609c..a73b60a90 100644 --- a/media/server/gstplayer/source/tasks/generic/SetPlaybackRate.cpp +++ b/media/server/gstplayer/source/tasks/generic/SetPlaybackRate.cpp @@ -26,14 +26,16 @@ namespace { const char kCustomInstantRateChangeEventName[] = "custom-instant-rate-change"; +constexpr double DEFAULT_INITIAL_RATE_CORRECTION_SPEED = 1.000001; } // namespace namespace firebolt::rialto::server::tasks::generic { SetPlaybackRate::SetPlaybackRate(GenericPlayerContext &context, + IGstGenericPlayerPrivate &player, std::shared_ptr gstWrapper, std::shared_ptr glibWrapper, double rate) - : m_context{context}, m_gstWrapper{gstWrapper}, m_glibWrapper{glibWrapper}, m_rate{rate} + : m_context{context}, m_player{player}, m_gstWrapper{gstWrapper}, m_glibWrapper{glibWrapper}, m_rate{rate} { RIALTO_SERVER_LOG_DEBUG("Constructing SetPlaybackRate"); } @@ -46,23 +48,38 @@ SetPlaybackRate::~SetPlaybackRate() void SetPlaybackRate::execute() const { RIALTO_SERVER_LOG_DEBUG("Executing SetPlaybackRate"); - if (m_context.playbackRate == m_rate) + double rate{m_rate}; + if (rate == DEFAULT_INITIAL_RATE_CORRECTION_SPEED) { - RIALTO_SERVER_LOG_DEBUG("No need to change playback rate - it is already %lf", m_rate); + GstElement *decoder{m_player.getDecoder(firebolt::rialto::MediaSourceType::AUDIO)}; + if (!decoder || !m_glibWrapper->gStrHasPrefix(GST_ELEMENT_NAME(decoder), "brcm")) + { + rate = 1.0f; + } + + if (decoder) + { + m_gstWrapper->gstObjectUnref(decoder); + } + } + + if (m_context.playbackRate == rate) + { + RIALTO_SERVER_LOG_DEBUG("No need to change playback rate - it is already %lf", rate); return; } if (!m_context.pipeline) { - RIALTO_SERVER_LOG_INFO("Postponing set playback rate to %lf. Pipeline is NULL", m_rate); - m_context.pendingPlaybackRate = m_rate; + RIALTO_SERVER_LOG_INFO("Postponing set playback rate to %lf. Pipeline is NULL", rate); + m_context.pendingPlaybackRate = rate; return; } if (GST_STATE(m_context.pipeline) < GST_STATE_PLAYING) { - RIALTO_SERVER_LOG_INFO("Postponing set playback rate to %lf. Pipeline state is below PLAYING", m_rate); - m_context.pendingPlaybackRate = m_rate; + RIALTO_SERVER_LOG_INFO("Postponing set playback rate to %lf. Pipeline state is below PLAYING", rate); + m_context.pendingPlaybackRate = rate; return; } m_context.pendingPlaybackRate = kNoPendingPlaybackRate; @@ -74,7 +91,7 @@ void SetPlaybackRate::execute() const { GstSegment *segment{m_gstWrapper->gstSegmentNew()}; m_gstWrapper->gstSegmentInit(segment, GST_FORMAT_TIME); - segment->rate = m_rate; + segment->rate = rate; segment->start = GST_CLOCK_TIME_NONE; segment->position = GST_CLOCK_TIME_NONE; success = m_gstWrapper->gstPadSendEvent(GST_BASE_SINK_PAD(audioSink), m_gstWrapper->gstEventNewSegment(segment)); @@ -84,7 +101,7 @@ void SetPlaybackRate::execute() const else { GstStructure *structure{ - m_gstWrapper->gstStructureNew(kCustomInstantRateChangeEventName, "rate", G_TYPE_DOUBLE, m_rate, NULL)}; + m_gstWrapper->gstStructureNew(kCustomInstantRateChangeEventName, "rate", G_TYPE_DOUBLE, rate, NULL)}; success = m_gstWrapper->gstElementSendEvent(m_context.pipeline, m_gstWrapper->gstEventNewCustom(GST_EVENT_CUSTOM_DOWNSTREAM_OOB, structure)); @@ -93,8 +110,8 @@ void SetPlaybackRate::execute() const if (success) { - RIALTO_SERVER_LOG_MIL("Playback rate set to: %lf", m_rate); - m_context.playbackRate = m_rate; + RIALTO_SERVER_LOG_MIL("Playback rate set to: %lf", rate); + m_context.playbackRate = rate; } if (audioSink) diff --git a/tests/unittests/media/server/gstplayer/genericPlayer/GstGenericPlayerTest.cpp b/tests/unittests/media/server/gstplayer/genericPlayer/GstGenericPlayerTest.cpp index 108b0e423..8c74e5351 100644 --- a/tests/unittests/media/server/gstplayer/genericPlayer/GstGenericPlayerTest.cpp +++ b/tests/unittests/media/server/gstplayer/genericPlayer/GstGenericPlayerTest.cpp @@ -235,7 +235,8 @@ TEST_F(GstGenericPlayerTest, shouldSetPlaybackRate) double playbackRate{1.5}; std::unique_ptr task{std::make_unique>()}; EXPECT_CALL(dynamic_cast &>(*task), execute()); - EXPECT_CALL(m_taskFactoryMock, createSetPlaybackRate(_, playbackRate)).WillOnce(Return(ByMove(std::move(task)))); + EXPECT_CALL(m_taskFactoryMock, createSetPlaybackRate(_, _, playbackRate)) + .WillOnce(Return(ByMove(std::move(task)))); m_sut->setPlaybackRate(playbackRate); } diff --git a/tests/unittests/media/server/gstplayer/genericPlayer/common/GenericTasksTestsBase.cpp b/tests/unittests/media/server/gstplayer/genericPlayer/common/GenericTasksTestsBase.cpp index 6d9c80666..22d4cd728 100644 --- a/tests/unittests/media/server/gstplayer/genericPlayer/common/GenericTasksTestsBase.cpp +++ b/tests/unittests/media/server/gstplayer/genericPlayer/common/GenericTasksTestsBase.cpp @@ -2822,7 +2822,8 @@ void GenericTasksTestsBase::shouldNotifyNeedVideoDataFailure() void GenericTasksTestsBase::triggerSetPlaybackRate() { - firebolt::rialto::server::tasks::generic::SetPlaybackRate task{testContext->m_context, testContext->m_gstWrapper, + firebolt::rialto::server::tasks::generic::SetPlaybackRate task{testContext->m_context, testContext->m_gstPlayer, + testContext->m_gstWrapper, testContext->m_glibWrapper, kRate}; task.execute(); } diff --git a/tests/unittests/media/server/gstplayer/genericPlayer/tasksTests/GenericPlayerTaskFactoryTest.cpp b/tests/unittests/media/server/gstplayer/genericPlayer/tasksTests/GenericPlayerTaskFactoryTest.cpp index d25627cda..1953e45ba 100644 --- a/tests/unittests/media/server/gstplayer/genericPlayer/tasksTests/GenericPlayerTaskFactoryTest.cpp +++ b/tests/unittests/media/server/gstplayer/genericPlayer/tasksTests/GenericPlayerTaskFactoryTest.cpp @@ -298,7 +298,7 @@ TEST_F(GenericPlayerTaskFactoryTest, ShouldCreateUnderflow) TEST_F(GenericPlayerTaskFactoryTest, ShouldCreateSetPlaybackRate) { - auto task = m_sut.createSetPlaybackRate(m_context, 1.25); + auto task = m_sut.createSetPlaybackRate(m_context, m_gstPlayer, 1.25); EXPECT_NE(task, nullptr); EXPECT_NO_THROW(dynamic_cast(*task)); } diff --git a/tests/unittests/media/server/mocks/gstplayer/GenericPlayerTaskFactoryMock.h b/tests/unittests/media/server/mocks/gstplayer/GenericPlayerTaskFactoryMock.h index b3fca43e0..48b75c16f 100644 --- a/tests/unittests/media/server/mocks/gstplayer/GenericPlayerTaskFactoryMock.h +++ b/tests/unittests/media/server/mocks/gstplayer/GenericPlayerTaskFactoryMock.h @@ -66,8 +66,8 @@ class GenericPlayerTaskFactoryMock : public IGenericPlayerTaskFactory (GenericPlayerContext & context, IGstGenericPlayerPrivate &player), (const, override)); MOCK_METHOD(std::unique_ptr, createCheckAudioUnderflow, (GenericPlayerContext & context, IGstGenericPlayerPrivate &player), (const, override)); - MOCK_METHOD(std::unique_ptr, createSetPlaybackRate, (GenericPlayerContext & context, double rate), - (const, override)); + MOCK_METHOD(std::unique_ptr, createSetPlaybackRate, + (GenericPlayerContext & context, IGstGenericPlayerPrivate &player, double rate), (const, override)); MOCK_METHOD(std::unique_ptr, createSetPosition, (GenericPlayerContext & context, IGstGenericPlayerPrivate &player, std::int64_t position), (const, override)); diff --git a/tests/unittests/media/server/mocks/gstplayer/GstGenericPlayerPrivateMock.h b/tests/unittests/media/server/mocks/gstplayer/GstGenericPlayerPrivateMock.h index d0b018a87..360c9b610 100644 --- a/tests/unittests/media/server/mocks/gstplayer/GstGenericPlayerPrivateMock.h +++ b/tests/unittests/media/server/mocks/gstplayer/GstGenericPlayerPrivateMock.h @@ -71,6 +71,7 @@ class GstGenericPlayerPrivateMock : public IGstGenericPlayerPrivate MOCK_METHOD(void, removeAutoVideoSinkChild, (GObject * object), (override)); MOCK_METHOD(void, removeAutoAudioSinkChild, (GObject * object), (override)); MOCK_METHOD(GstElement *, getSink, (const MediaSourceType &mediaSourceType), (const, override)); + MOCK_METHOD(GstElement *, getDecoder, (const MediaSourceType &mediaSourceType), (override)); MOCK_METHOD(void, addAudioClippingToBuffer, (GstBuffer * buffer, uint64_t clippingStart, uint64_t clippingEnd), (const, override));