LCOV - code coverage report
Current view: top level - source - GStreamerMSEMediaPlayerClient.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 94.5 % 656 620
Test Date: 2026-05-12 09:11:14 Functions: 98.5 % 133 131

            Line data    Source code
       1              : /*
       2              :  * Copyright (C) 2022 Sky UK
       3              :  *
       4              :  * This library is free software; you can redistribute it and/or
       5              :  * modify it under the terms of the GNU Lesser General Public
       6              :  * License as published by the Free Software Foundation;
       7              :  * version 2.1 of the License.
       8              :  *
       9              :  * This library is distributed in the hope that it will be useful,
      10              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12              :  * Lesser General Public License for more details.
      13              :  *
      14              :  * You should have received a copy of the GNU Lesser General Public
      15              :  * License along with this library; if not, write to the Free Software
      16              :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
      17              :  */
      18              : 
      19              : #include "GStreamerMSEMediaPlayerClient.h"
      20              : #include "Constants.h"
      21              : #include "GstreamerCatLog.h"
      22              : #include "RialtoGStreamerMSEBaseSink.h"
      23              : #include "RialtoGStreamerMSEBaseSinkPrivate.h"
      24              : #include "RialtoGStreamerMSEVideoSink.h"
      25              : 
      26              : #include <algorithm>
      27              : #include <chrono>
      28              : #include <thread>
      29              : 
      30              : namespace
      31              : {
      32              : // The start time of segment might differ from the first sample which is injected.
      33              : // That difference should not be bigger than 1 video / audio frame.
      34              : // 1 second is probably erring on the side of caution, but should not have side effect.
      35              : const int64_t segmentStartMaximumDiff = 1000000000;
      36              : const int32_t UNKNOWN_STREAMS_NUMBER = -1;
      37              : 
      38            0 : const char *toString(const firebolt::rialto::PlaybackError &error)
      39              : {
      40            0 :     switch (error)
      41              :     {
      42            0 :     case firebolt::rialto::PlaybackError::DECRYPTION:
      43            0 :         return "DECRYPTION";
      44            0 :     case firebolt::rialto::PlaybackError::UNKNOWN:
      45            0 :         return "UNKNOWN";
      46              :     }
      47            0 :     return "UNKNOWN";
      48              : }
      49            0 : const char *toString(const firebolt::rialto::MediaSourceType &src)
      50              : {
      51            0 :     switch (src)
      52              :     {
      53            0 :     case firebolt::rialto::MediaSourceType::AUDIO:
      54            0 :         return "AUDIO";
      55            0 :     case firebolt::rialto::MediaSourceType::VIDEO:
      56            0 :         return "VIDEO";
      57            0 :     case firebolt::rialto::MediaSourceType::SUBTITLE:
      58            0 :         return "SUBTITLE";
      59            0 :     case firebolt::rialto::MediaSourceType::UNKNOWN:
      60            0 :         return "UNKNOWN";
      61              :     }
      62            0 :     return "UNKNOWN";
      63              : }
      64              : } // namespace
      65              : #define GST_CAT_DEFAULT rialtoGStreamerCat
      66          281 : GStreamerMSEMediaPlayerClient::GStreamerMSEMediaPlayerClient(
      67              :     const std::shared_ptr<IMessageQueueFactory> &messageQueueFactory,
      68              :     const std::shared_ptr<firebolt::rialto::client::MediaPlayerClientBackendInterface> &MediaPlayerClientBackend,
      69          281 :     const uint32_t maxVideoWidth, const uint32_t maxVideoHeight, bool isLive)
      70          281 :     : m_backendQueue{messageQueueFactory->createMessageQueue()}, m_messageQueueFactory{messageQueueFactory},
      71          281 :       m_clientBackend(MediaPlayerClientBackend), m_duration(0), m_audioStreams{UNKNOWN_STREAMS_NUMBER},
      72          281 :       m_videoStreams{UNKNOWN_STREAMS_NUMBER}, m_subtitleStreams{UNKNOWN_STREAMS_NUMBER},
      73          281 :       m_videoRectangle{0, 0, 1920, 1080}, m_streamingStopped(false),
      74          281 :       m_maxWidth(maxVideoWidth == 0 ? DEFAULT_MAX_VIDEO_WIDTH : maxVideoWidth),
      75          843 :       m_maxHeight(maxVideoHeight == 0 ? DEFAULT_MAX_VIDEO_HEIGHT : maxVideoHeight), m_isLive{isLive}
      76              : {
      77          281 :     m_backendQueue->start();
      78              : }
      79              : 
      80          281 : GStreamerMSEMediaPlayerClient::~GStreamerMSEMediaPlayerClient()
      81              : {
      82          281 :     stopStreaming();
      83              : }
      84              : 
      85          439 : void GStreamerMSEMediaPlayerClient::stopStreaming()
      86              : {
      87          439 :     if (!m_streamingStopped)
      88              :     {
      89          281 :         m_backendQueue->stop();
      90              : 
      91          345 :         for (auto &source : m_attachedSources)
      92              :         {
      93           64 :             source.second.m_bufferPuller->stop();
      94              :         }
      95              : 
      96          281 :         m_streamingStopped = true;
      97              :     }
      98          439 : }
      99              : 
     100              : // Deletes client backend -> this deletes mediapipeline object
     101          162 : void GStreamerMSEMediaPlayerClient::destroyClientBackend()
     102              : {
     103          162 :     m_clientBackend.reset();
     104              : }
     105              : 
     106            1 : void GStreamerMSEMediaPlayerClient::notifyDuration(int64_t duration)
     107              : {
     108            1 :     m_backendQueue->postMessage(std::make_shared<SetDurationMessage>(duration, m_duration));
     109              : }
     110              : 
     111            1 : void GStreamerMSEMediaPlayerClient::notifyPosition(int64_t position)
     112              : {
     113            1 :     m_backendQueue->postMessage(std::make_shared<SetPositionMessage>(position, m_attachedSources));
     114              : }
     115              : 
     116              : void GStreamerMSEMediaPlayerClient::notifyNativeSize(uint32_t width, uint32_t height, double aspect) {}
     117              : 
     118              : void GStreamerMSEMediaPlayerClient::notifyNetworkState(firebolt::rialto::NetworkState state) {}
     119              : 
     120           59 : void GStreamerMSEMediaPlayerClient::notifyPlaybackState(firebolt::rialto::PlaybackState state)
     121              : {
     122           59 :     m_backendQueue->postMessage(std::make_shared<PlaybackStateMessage>(state, this));
     123              : }
     124              : 
     125              : void GStreamerMSEMediaPlayerClient::notifyVideoData(bool hasData) {}
     126              : 
     127              : void GStreamerMSEMediaPlayerClient::notifyAudioData(bool hasData) {}
     128              : 
     129           10 : void GStreamerMSEMediaPlayerClient::notifyNeedMediaData(
     130              :     int32_t sourceId, size_t frameCount, uint32_t needDataRequestId,
     131              :     const std::shared_ptr<firebolt::rialto::MediaPlayerShmInfo> & /*shmInfo*/)
     132              : {
     133           10 :     m_backendQueue->postMessage(std::make_shared<NeedDataMessage>(sourceId, frameCount, needDataRequestId, this));
     134              : 
     135           10 :     return;
     136              : }
     137              : 
     138              : void GStreamerMSEMediaPlayerClient::notifyCancelNeedMediaData(int sourceId) {}
     139              : 
     140            5 : void GStreamerMSEMediaPlayerClient::notifyQos(int32_t sourceId, const firebolt::rialto::QosInfo &qosInfo)
     141              : {
     142            5 :     m_backendQueue->postMessage(std::make_shared<QosMessage>(sourceId, qosInfo, this));
     143              : }
     144              : 
     145            2 : void GStreamerMSEMediaPlayerClient::notifyBufferUnderflow(int32_t sourceId)
     146              : {
     147            2 :     m_backendQueue->postMessage(std::make_shared<BufferUnderflowMessage>(sourceId, this));
     148              : }
     149              : 
     150            5 : void GStreamerMSEMediaPlayerClient::notifyPlaybackError(int32_t sourceId, firebolt::rialto::PlaybackError error)
     151              : {
     152            5 :     m_backendQueue->postMessage(std::make_shared<PlaybackErrorMessage>(sourceId, error, this));
     153              : }
     154              : 
     155            7 : void GStreamerMSEMediaPlayerClient::notifySourceFlushed(int32_t sourceId)
     156              : {
     157            7 :     m_backendQueue->postMessage(std::make_shared<SourceFlushedMessage>(sourceId, this));
     158              : }
     159              : 
     160            7 : void GStreamerMSEMediaPlayerClient::notifyPlaybackInfo(const firebolt::rialto::PlaybackInfo &playbackInfo)
     161              : {
     162            7 :     std::unique_lock lock{m_playbackInfoMutex};
     163            7 :     m_playbackInfo = playbackInfo;
     164              : }
     165              : 
     166            6 : int64_t GStreamerMSEMediaPlayerClient::getPosition(int32_t sourceId)
     167              : {
     168            6 :     std::unique_lock lock{m_playbackInfoMutex};
     169            6 :     return m_playbackInfo.currentPosition;
     170              : }
     171              : 
     172            4 : bool GStreamerMSEMediaPlayerClient::getDuration(int64_t &duration)
     173              : {
     174            4 :     if (!m_clientBackend)
     175              :     {
     176            1 :         return false;
     177              :     }
     178              : 
     179            3 :     bool status{false};
     180            6 :     m_backendQueue->callInEventLoop([&]() { status = m_clientBackend->getDuration(duration); });
     181            3 :     return status;
     182              : }
     183              : 
     184            5 : bool GStreamerMSEMediaPlayerClient::setImmediateOutput(int32_t sourceId, bool immediateOutput)
     185              : {
     186            5 :     if (!m_clientBackend)
     187              :     {
     188            1 :         return false;
     189              :     }
     190              : 
     191            4 :     bool status{false};
     192            8 :     m_backendQueue->callInEventLoop([&]() { status = m_clientBackend->setImmediateOutput(sourceId, immediateOutput); });
     193            4 :     return status;
     194              : }
     195              : 
     196            4 : bool GStreamerMSEMediaPlayerClient::getImmediateOutput(int32_t sourceId, bool &immediateOutput)
     197              : {
     198            4 :     if (!m_clientBackend)
     199              :     {
     200            1 :         return false;
     201              :     }
     202              : 
     203            3 :     bool status{false};
     204            6 :     m_backendQueue->callInEventLoop([&]() { status = m_clientBackend->getImmediateOutput(sourceId, immediateOutput); });
     205            3 :     return status;
     206              : }
     207              : 
     208            1 : bool GStreamerMSEMediaPlayerClient::getStats(int32_t sourceId, uint64_t &renderedFrames, uint64_t &droppedFrames)
     209              : {
     210            1 :     if (!m_clientBackend)
     211              :     {
     212            0 :         return false;
     213              :     }
     214              : 
     215            1 :     bool status{false};
     216            1 :     m_backendQueue->callInEventLoop([&]()
     217            1 :                                     { status = m_clientBackend->getStats(sourceId, renderedFrames, droppedFrames); });
     218            1 :     return status;
     219              : }
     220              : 
     221          166 : bool GStreamerMSEMediaPlayerClient::createBackend()
     222              : {
     223          166 :     bool result = false;
     224          332 :     m_backendQueue->callInEventLoop(
     225          166 :         [&]()
     226              :         {
     227          166 :             if (!m_clientBackend)
     228              :             {
     229            1 :                 GST_ERROR("Client backend is NULL");
     230            1 :                 result = false;
     231            1 :                 return;
     232              :             }
     233          165 :             m_clientBackend->createMediaPlayerBackend(shared_from_this(), m_maxWidth, m_maxHeight);
     234              : 
     235          165 :             if (m_clientBackend->isMediaPlayerBackendCreated())
     236              :             {
     237          160 :                 std::string utf8url = "mse://1";
     238          160 :                 firebolt::rialto::MediaType mediaType = firebolt::rialto::MediaType::MSE;
     239          480 :                 if (!m_clientBackend->load(mediaType, "", utf8url, m_isLive))
     240              :                 {
     241            1 :                     GST_ERROR("Could not load RialtoClient");
     242            1 :                     return;
     243              :                 }
     244          159 :                 result = true;
     245          160 :             }
     246              :             else
     247              :             {
     248            5 :                 GST_ERROR("Media player backend could not be created");
     249              :             }
     250              :         });
     251              : 
     252          166 :     return result;
     253              : }
     254              : 
     255           23 : StateChangeResult GStreamerMSEMediaPlayerClient::play(int32_t sourceId)
     256              : {
     257           23 :     StateChangeResult result = StateChangeResult::NOT_ATTACHED;
     258           46 :     m_backendQueue->callInEventLoop(
     259           23 :         [&]()
     260              :         {
     261           23 :             auto sourceIt = m_attachedSources.find(sourceId);
     262           23 :             if (sourceIt == m_attachedSources.end())
     263              :             {
     264            1 :                 GST_ERROR("Cannot play - there's no attached source with id %d", sourceId);
     265            1 :                 result = StateChangeResult::NOT_ATTACHED;
     266            4 :                 return;
     267              :             }
     268              : 
     269           22 :             if (m_serverPlaybackState == firebolt::rialto::PlaybackState::PLAYING ||
     270           20 :                 (m_serverPlaybackState == firebolt::rialto::PlaybackState::END_OF_STREAM && wasPlayingBeforeEos))
     271              :             {
     272            2 :                 GST_INFO("Server is already playing");
     273            2 :                 sourceIt->second.m_state = ClientState::PLAYING;
     274              : 
     275            6 :                 if (checkIfAllAttachedSourcesInStates({ClientState::PLAYING}))
     276              :                 {
     277            1 :                     m_clientState = ClientState::PLAYING;
     278              :                 }
     279              : 
     280            2 :                 result = StateChangeResult::SUCCESS_SYNC;
     281            2 :                 return;
     282              :             }
     283              : 
     284           20 :             sourceIt->second.m_state = ClientState::AWAITING_PLAYING;
     285              : 
     286           20 :             if (m_clientState == ClientState::PAUSED)
     287              :             {
     288              :                 // If one source is AWAITING_PLAYING, the other source can still be PLAYING.
     289              :                 // This happends when we are switching out audio.
     290           48 :                 if (checkIfAllAttachedSourcesInStates({ClientState::AWAITING_PLAYING, ClientState::PLAYING}))
     291              :                 {
     292           11 :                     GST_INFO("Sending play command");
     293           11 :                     bool async{true};
     294           11 :                     m_clientBackend->play(async);
     295           11 :                     m_clientState = ClientState::AWAITING_PLAYING;
     296           11 :                     if (!async)
     297              :                     {
     298              :                         // Synchronous playing state change. Finish procedure for other sources and return SUCCESS_SYNC
     299            1 :                         result = StateChangeResult::SUCCESS_SYNC;
     300            2 :                         m_backendQueue->postMessage(
     301            2 :                             std::make_shared<PlaybackStateMessage>(firebolt::rialto::PlaybackState::PLAYING, this));
     302            1 :                         return;
     303              :                     }
     304              :                 }
     305              :                 else
     306              :                 {
     307            5 :                     GST_DEBUG("Not all sources are ready to play");
     308              :                 }
     309              :             }
     310              :             else
     311              :             {
     312            4 :                 GST_WARNING("Not in PAUSED state in client state %u state; server playback state: %u",
     313              :                             static_cast<uint32_t>(m_clientState), static_cast<uint32_t>(m_serverPlaybackState));
     314              :             }
     315              : 
     316           19 :             result = StateChangeResult::SUCCESS_ASYNC;
     317           19 :             sourceIt->second.m_delegate->postAsyncStart();
     318              :         });
     319              : 
     320           23 :     return result;
     321              : }
     322              : 
     323          325 : StateChangeResult GStreamerMSEMediaPlayerClient::pause(int32_t sourceId)
     324              : {
     325          325 :     StateChangeResult result = StateChangeResult::NOT_ATTACHED;
     326          650 :     m_backendQueue->callInEventLoop(
     327          325 :         [&]()
     328              :         {
     329          325 :             auto sourceIt = m_attachedSources.find(sourceId);
     330          325 :             if (sourceIt == m_attachedSources.end())
     331              :             {
     332          152 :                 GST_WARNING("Cannot pause - there's no attached source with id %d", sourceId);
     333              : 
     334          152 :                 result = StateChangeResult::NOT_ATTACHED;
     335          152 :                 return;
     336              :             }
     337              : 
     338          173 :             if (m_serverPlaybackState == firebolt::rialto::PlaybackState::PAUSED &&
     339            4 :                 m_clientState != ClientState::AWAITING_PLAYING && m_clientState != ClientState::AWAITING_PAUSED)
     340              :             {
     341              :                 // if the server is already paused and we are not in async, we don't need to send pause command
     342            2 :                 GST_INFO("Server is already paused");
     343            2 :                 sourceIt->second.m_state = ClientState::PAUSED;
     344              : 
     345            6 :                 if (checkIfAllAttachedSourcesInStates({ClientState::PAUSED}))
     346              :                 {
     347            1 :                     m_clientState = ClientState::PAUSED;
     348              :                 }
     349              : 
     350            2 :                 result = StateChangeResult::SUCCESS_SYNC;
     351              :             }
     352              :             else
     353              :             {
     354          171 :                 sourceIt->second.m_state = ClientState::AWAITING_PAUSED;
     355              : 
     356          171 :                 bool shouldPause = false;
     357          171 :                 if (m_clientState == ClientState::READY)
     358              :                 {
     359          477 :                     if (checkIfAllAttachedSourcesInStates({ClientState::AWAITING_PAUSED}))
     360              :                     {
     361          150 :                         shouldPause = true;
     362              :                     }
     363              :                     else
     364              :                     {
     365            9 :                         GST_DEBUG("Not all attached sources are ready to pause");
     366              :                     }
     367              :                 }
     368           12 :                 else if (m_clientState == ClientState::AWAITING_PLAYING || m_clientState == ClientState::PLAYING)
     369              :                 {
     370            9 :                     shouldPause = true;
     371              :                 }
     372              :                 else
     373              :                 {
     374            3 :                     GST_DEBUG("Cannot pause in %u state", static_cast<uint32_t>(m_clientState));
     375              :                 }
     376              : 
     377          171 :                 if (shouldPause)
     378              :                 {
     379          159 :                     GST_INFO("Sending pause command in %u state", static_cast<uint32_t>(m_clientState));
     380          159 :                     m_clientBackend->pause();
     381          159 :                     m_clientState = ClientState::AWAITING_PAUSED;
     382              :                 }
     383              : 
     384          171 :                 result = StateChangeResult::SUCCESS_ASYNC;
     385          171 :                 sourceIt->second.m_delegate->postAsyncStart();
     386              :             }
     387              :         });
     388              : 
     389          325 :     return result;
     390              : }
     391              : 
     392          159 : void GStreamerMSEMediaPlayerClient::stop()
     393              : {
     394          318 :     m_backendQueue->callInEventLoop([&]() { m_clientBackend->stop(); });
     395          159 : }
     396              : 
     397            4 : void GStreamerMSEMediaPlayerClient::setPlaybackRate(double rate)
     398              : {
     399            8 :     m_backendQueue->callInEventLoop([&]() { m_clientBackend->setPlaybackRate(rate); });
     400            4 : }
     401              : 
     402           10 : void GStreamerMSEMediaPlayerClient::flush(int32_t sourceId, bool resetTime)
     403              : {
     404           10 :     m_flushAndDataSynchronizer.notifyFlushStarted(sourceId);
     405           20 :     m_backendQueue->callInEventLoop(
     406           10 :         [&]()
     407              :         {
     408           10 :             wasPlayingBeforeEos = false;
     409           10 :             bool async{true};
     410           10 :             auto sourceIt = m_attachedSources.find(sourceId);
     411           10 :             if (sourceIt == m_attachedSources.end())
     412              :             {
     413            2 :                 GST_ERROR("Cannot flush - there's no attached source with id %d", sourceId);
     414            3 :                 return;
     415              :             }
     416            8 :             if (!m_clientBackend->flush(sourceId, resetTime, async))
     417              :             {
     418            1 :                 GST_ERROR("Flush operation failed for source with id %d", sourceId);
     419            1 :                 return;
     420              :             }
     421            7 :             sourceIt->second.m_isFlushing = true;
     422              : 
     423            7 :             if (async)
     424              :             {
     425            7 :                 GST_INFO("Flush request sent for async source %d. Sink will lose state now", sourceId);
     426            7 :                 sourceIt->second.m_delegate->lostState();
     427              : 
     428            7 :                 sourceIt->second.m_state = ClientState::AWAITING_PAUSED;
     429            7 :                 if (m_clientState == ClientState::PLAYING)
     430              :                 {
     431            0 :                     m_clientState = ClientState::AWAITING_PLAYING;
     432              :                 }
     433            7 :                 else if (m_clientState == ClientState::PAUSED)
     434              :                 {
     435            3 :                     m_clientState = ClientState::AWAITING_PAUSED;
     436              :                 }
     437              :             }
     438              :         });
     439           10 : }
     440              : 
     441            9 : void GStreamerMSEMediaPlayerClient::setSourcePosition(int32_t sourceId, int64_t position, bool resetTime,
     442              :                                                       double appliedRate, uint64_t stopPosition)
     443              : {
     444           18 :     m_backendQueue->callInEventLoop(
     445            9 :         [&]()
     446              :         {
     447            9 :             auto sourceIt = m_attachedSources.find(sourceId);
     448            9 :             if (sourceIt == m_attachedSources.end())
     449              :             {
     450            1 :                 GST_ERROR("Cannot Set Source Position - there's no attached source with id %d", sourceId);
     451            2 :                 return;
     452              :             }
     453            8 :             if (!m_clientBackend->setSourcePosition(sourceId, position, resetTime, appliedRate, stopPosition))
     454              :             {
     455            1 :                 GST_ERROR("Set Source Position operation failed for source with id %d", sourceId);
     456            1 :                 return;
     457              :             }
     458            7 :             sourceIt->second.m_position = position;
     459              :         });
     460            9 : }
     461              : 
     462            1 : void GStreamerMSEMediaPlayerClient::setSubtitleOffset(int32_t sourceId, int64_t position)
     463              : {
     464            2 :     m_backendQueue->callInEventLoop(
     465            1 :         [&]()
     466              :         {
     467            1 :             auto sourceIt = m_attachedSources.find(sourceId);
     468            1 :             if (sourceIt == m_attachedSources.end())
     469              :             {
     470            0 :                 GST_ERROR("Cannot Set Subtitle Offset - there's no attached source with id %d", sourceId);
     471            0 :                 return;
     472              :             }
     473            1 :             if (!m_clientBackend->setSubtitleOffset(sourceId, position))
     474              :             {
     475            0 :                 GST_ERROR("Set Subtitle Offset operation failed for source with id %d", sourceId);
     476            0 :                 return;
     477              :             }
     478              :         });
     479            1 : }
     480              : 
     481            4 : void GStreamerMSEMediaPlayerClient::processAudioGap(int64_t position, uint32_t duration, int64_t discontinuityGap,
     482              :                                                     bool audioAac)
     483              : {
     484            8 :     m_backendQueue->callInEventLoop(
     485            4 :         [&]()
     486              :         {
     487            4 :             if (!m_clientBackend->processAudioGap(position, duration, discontinuityGap, audioAac))
     488              :             {
     489            1 :                 GST_ERROR("Process Audio Gap operation failed");
     490            1 :                 return;
     491              :             }
     492              :         });
     493            4 : }
     494              : 
     495          208 : bool GStreamerMSEMediaPlayerClient::attachSource(std::unique_ptr<firebolt::rialto::IMediaPipeline::MediaSource> &source,
     496              :                                                  RialtoMSEBaseSink *rialtoSink,
     497              :                                                  const std::shared_ptr<IPullModePlaybackDelegate> &delegate)
     498              : {
     499          208 :     if (source->getType() != firebolt::rialto::MediaSourceType::AUDIO &&
     500          220 :         source->getType() != firebolt::rialto::MediaSourceType::VIDEO &&
     501           12 :         source->getType() != firebolt::rialto::MediaSourceType::SUBTITLE)
     502              :     {
     503            1 :         GST_WARNING_OBJECT(rialtoSink, "Invalid source type %u", static_cast<uint32_t>(source->getType()));
     504            1 :         return false;
     505              :     }
     506              : 
     507          207 :     bool result = false;
     508          414 :     m_backendQueue->callInEventLoop(
     509          207 :         [&]()
     510              :         {
     511          207 :             result = m_clientBackend->attachSource(source);
     512              : 
     513          207 :             if (result)
     514              :             {
     515          206 :                 std::shared_ptr<BufferParser> bufferParser;
     516          206 :                 if (source->getType() == firebolt::rialto::MediaSourceType::AUDIO)
     517              :                 {
     518          153 :                     bufferParser = std::make_shared<AudioBufferParser>();
     519              :                 }
     520           53 :                 else if (source->getType() == firebolt::rialto::MediaSourceType::VIDEO)
     521              :                 {
     522           42 :                     bufferParser = std::make_shared<VideoBufferParser>();
     523              :                 }
     524           11 :                 else if (source->getType() == firebolt::rialto::MediaSourceType::SUBTITLE)
     525              :                 {
     526           11 :                     bufferParser = std::make_shared<SubtitleBufferParser>();
     527              :                 }
     528              : 
     529          206 :                 std::shared_ptr<BufferPuller> bufferPuller = std::make_shared<BufferPuller>(m_messageQueueFactory,
     530            0 :                                                                                             GST_ELEMENT_CAST(rialtoSink),
     531          206 :                                                                                             bufferParser, delegate);
     532              : 
     533          206 :                 if (m_attachedSources.find(source->getId()) == m_attachedSources.end())
     534              :                 {
     535          206 :                     m_attachedSources.emplace(source->getId(),
     536          412 :                                               AttachedSource(rialtoSink, bufferPuller, delegate, source->getType()));
     537          206 :                     delegate->setSourceId(source->getId());
     538          206 :                     m_flushAndDataSynchronizer.addSource(source->getId());
     539          206 :                     bufferPuller->start();
     540              :                 }
     541              :             }
     542              : 
     543          207 :             sendAllSourcesAttachedIfPossibleInternal();
     544          207 :         });
     545              : 
     546          207 :     return result;
     547              : }
     548              : 
     549            4 : void GStreamerMSEMediaPlayerClient::sendAllSourcesAttachedIfPossible()
     550              : {
     551            8 :     m_backendQueue->callInEventLoop([&]() { sendAllSourcesAttachedIfPossibleInternal(); });
     552            4 : }
     553              : 
     554          211 : void GStreamerMSEMediaPlayerClient::sendAllSourcesAttachedIfPossibleInternal()
     555              : {
     556          211 :     if (!m_wasAllSourcesAttachedSent && areAllStreamsAttached())
     557              :     {
     558              :         // RialtoServer doesn't support dynamic source attachment.
     559              :         // It means that when we notify that all sources were attached, we cannot add any more sources in the current session
     560          156 :         GST_INFO("All sources attached");
     561          156 :         m_clientBackend->allSourcesAttached();
     562          156 :         m_wasAllSourcesAttachedSent = true;
     563          156 :         m_clientState = ClientState::READY;
     564              : 
     565              :         // In playbin3 streams, confirmation about number of available sources comes after attaching the source,
     566              :         // so we need to check if all sources are ready to pause
     567          468 :         if (checkIfAllAttachedSourcesInStates({ClientState::AWAITING_PAUSED}))
     568              :         {
     569            1 :             GST_INFO("Sending pause command, because all attached sources are ready to pause");
     570            1 :             m_clientBackend->pause();
     571            1 :             m_clientState = ClientState::AWAITING_PAUSED;
     572              :         }
     573              :     }
     574          211 : }
     575              : 
     576          153 : void GStreamerMSEMediaPlayerClient::removeSource(int32_t sourceId)
     577              : {
     578          306 :     m_backendQueue->callInEventLoop(
     579          153 :         [&]()
     580              :         {
     581          153 :             if (!m_clientBackend->removeSource(sourceId))
     582              :             {
     583            1 :                 GST_WARNING("Remove source %d failed", sourceId);
     584              :             }
     585          153 :             m_attachedSources.erase(sourceId);
     586          153 :             m_flushAndDataSynchronizer.removeSource(sourceId);
     587          153 :         });
     588              : }
     589              : 
     590           60 : void GStreamerMSEMediaPlayerClient::handlePlaybackStateChange(firebolt::rialto::PlaybackState state)
     591              : {
     592           60 :     GST_DEBUG("Received state change to state %u", static_cast<uint32_t>(state));
     593          120 :     m_backendQueue->callInEventLoop(
     594           60 :         [&]()
     595              :         {
     596           60 :             const auto kPreviousState{m_serverPlaybackState};
     597           60 :             m_serverPlaybackState = state;
     598           60 :             switch (state)
     599              :             {
     600           53 :             case firebolt::rialto::PlaybackState::PAUSED:
     601              :             case firebolt::rialto::PlaybackState::PLAYING:
     602              :             {
     603           53 :                 wasPlayingBeforeEos = false;
     604           53 :                 if (state == firebolt::rialto::PlaybackState::PAUSED && m_clientState == ClientState::AWAITING_PAUSED)
     605              :                 {
     606           38 :                     m_clientState = ClientState::PAUSED;
     607              :                 }
     608           15 :                 else if (state == firebolt::rialto::PlaybackState::PLAYING &&
     609           13 :                          m_clientState == ClientState::AWAITING_PLAYING)
     610              :                 {
     611            9 :                     m_clientState = ClientState::PLAYING;
     612              :                 }
     613            6 :                 else if (state == firebolt::rialto::PlaybackState::PLAYING &&
     614            4 :                          m_clientState == ClientState::AWAITING_PAUSED)
     615              :                 {
     616            1 :                     GST_WARNING("Outdated Playback State change to PLAYING received. Discarding...");
     617            1 :                     break;
     618              :                 }
     619              : 
     620          117 :                 for (auto &source : m_attachedSources)
     621              :                 {
     622           65 :                     if (state == firebolt::rialto::PlaybackState::PAUSED &&
     623           48 :                         source.second.m_state == ClientState::AWAITING_PAUSED)
     624              :                     {
     625           45 :                         source.second.m_state = ClientState::PAUSED;
     626              :                     }
     627           20 :                     else if (state == firebolt::rialto::PlaybackState::PLAYING &&
     628           17 :                              source.second.m_state == ClientState::AWAITING_PLAYING)
     629              :                     {
     630           12 :                         source.second.m_state = ClientState::PLAYING;
     631              :                     }
     632           65 :                     source.second.m_delegate->handleStateChanged(state);
     633              :                 }
     634              : 
     635           52 :                 break;
     636              :             }
     637            4 :             case firebolt::rialto::PlaybackState::END_OF_STREAM:
     638              :             {
     639            4 :                 if (!wasPlayingBeforeEos && firebolt::rialto::PlaybackState::PLAYING == kPreviousState)
     640              :                 {
     641            2 :                     wasPlayingBeforeEos = true;
     642              :                 }
     643            8 :                 for (const auto &source : m_attachedSources)
     644              :                 {
     645            4 :                     source.second.m_delegate->handleEos();
     646              :                 }
     647              :             }
     648            4 :             break;
     649            1 :             case firebolt::rialto::PlaybackState::SEEK_DONE:
     650              :             {
     651            1 :                 GST_WARNING("firebolt::rialto::PlaybackState::SEEK_DONE notification not supported");
     652            1 :                 break;
     653              :             }
     654            1 :             case firebolt::rialto::PlaybackState::FAILURE:
     655              :             {
     656            1 :                 wasPlayingBeforeEos = false;
     657            2 :                 for (const auto &source : m_attachedSources)
     658              :                 {
     659            3 :                     source.second.m_delegate->handleError("Rialto server playback failed");
     660              :                 }
     661            2 :                 for (auto &source : m_attachedSources)
     662              :                 {
     663            1 :                     source.second.m_position = 0;
     664              :                 }
     665              :                 {
     666            1 :                     std::unique_lock lock{m_playbackInfoMutex};
     667            1 :                     m_playbackInfo.currentPosition = 0;
     668              :                 }
     669              : 
     670            1 :                 break;
     671              :             }
     672              :             break;
     673            1 :             default:
     674            1 :                 break;
     675              :             }
     676           60 :         });
     677              : }
     678              : 
     679            7 : void GStreamerMSEMediaPlayerClient::handleSourceFlushed(int32_t sourceId)
     680              : {
     681           14 :     m_backendQueue->callInEventLoop(
     682            7 :         [&]()
     683              :         {
     684            7 :             auto sourceIt = m_attachedSources.find(sourceId);
     685            7 :             if (sourceIt == m_attachedSources.end())
     686              :             {
     687            1 :                 GST_ERROR("Cannot finish flush - there's no attached source with id %d", sourceId);
     688            2 :                 return;
     689              :             }
     690            6 :             if (!sourceIt->second.m_isFlushing)
     691              :             {
     692            1 :                 GST_ERROR("Cannot finish flush - source with id %d is not flushing!", sourceId);
     693            1 :                 return;
     694              :             }
     695            5 :             sourceIt->second.m_isFlushing = false;
     696            5 :             sourceIt->second.m_delegate->handleFlushCompleted();
     697            5 :             m_flushAndDataSynchronizer.notifyFlushCompleted(sourceId);
     698              :         });
     699            7 : }
     700              : 
     701            7 : void GStreamerMSEMediaPlayerClient::setVideoRectangle(const std::string &rectangleString)
     702              : {
     703           14 :     m_backendQueue->callInEventLoop(
     704            7 :         [&]()
     705              :         {
     706            7 :             if (!m_clientBackend || !m_clientBackend->isMediaPlayerBackendCreated())
     707              :             {
     708            1 :                 GST_WARNING("Missing RialtoClient backend - can't set video window now");
     709            3 :                 return;
     710              :             }
     711              : 
     712            6 :             if (rectangleString.empty())
     713              :             {
     714            1 :                 GST_WARNING("Empty video rectangle string");
     715            1 :                 return;
     716              :             }
     717              : 
     718            5 :             Rectangle rect = {0, 0, 0, 0};
     719            5 :             if (sscanf(rectangleString.c_str(), "%u,%u,%u,%u", &rect.x, &rect.y, &rect.width, &rect.height) != 4)
     720              :             {
     721            1 :                 GST_WARNING("Invalid video rectangle values");
     722            1 :                 return;
     723              :             }
     724              : 
     725            4 :             m_clientBackend->setVideoWindow(rect.x, rect.y, rect.width, rect.height);
     726            4 :             m_videoRectangle = rect;
     727              :         });
     728            7 : }
     729              : 
     730            4 : std::string GStreamerMSEMediaPlayerClient::getVideoRectangle()
     731              : {
     732              :     char rectangle[64];
     733            8 :     m_backendQueue->callInEventLoop(
     734            8 :         [&]()
     735              :         {
     736            4 :             sprintf(rectangle, "%u,%u,%u,%u", m_videoRectangle.x, m_videoRectangle.y, m_videoRectangle.width,
     737              :                     m_videoRectangle.height);
     738            4 :         });
     739              : 
     740            8 :     return std::string(rectangle);
     741              : }
     742              : 
     743            4 : bool GStreamerMSEMediaPlayerClient::renderFrame(int32_t sourceId)
     744              : {
     745            4 :     bool result = false;
     746            8 :     m_backendQueue->callInEventLoop(
     747            4 :         [&]()
     748              :         {
     749            4 :             result = m_clientBackend->renderFrame();
     750            4 :             if (result)
     751              :             {
     752              :                 // RialtoServer's video sink should drop PAUSED state due to skipping prerolled buffer in PAUSED state
     753            3 :                 auto sourceIt = m_attachedSources.find(sourceId);
     754            3 :                 if (sourceIt != m_attachedSources.end())
     755              :                 {
     756            3 :                     sourceIt->second.m_delegate->lostState();
     757              :                 }
     758              :             }
     759            4 :         });
     760            4 :     return result;
     761              : }
     762              : 
     763            6 : void GStreamerMSEMediaPlayerClient::setVolume(double targetVolume, uint32_t volumeDuration,
     764              :                                               firebolt::rialto::EaseType easeType)
     765              : {
     766           12 :     m_backendQueue->callInEventLoop(
     767            6 :         [&]()
     768              :         {
     769            6 :             m_clientBackend->setVolume(targetVolume, volumeDuration, easeType);
     770            6 :             std::unique_lock lock{m_playbackInfoMutex};
     771            6 :             m_playbackInfo.volume = targetVolume;
     772            6 :         });
     773              : }
     774              : 
     775            3 : bool GStreamerMSEMediaPlayerClient::getVolume(double &volume)
     776              : {
     777            3 :     std::unique_lock lock{m_playbackInfoMutex};
     778            3 :     volume = m_playbackInfo.volume;
     779            3 :     return true;
     780              : }
     781              : 
     782            7 : void GStreamerMSEMediaPlayerClient::setMute(bool mute, int32_t sourceId)
     783              : {
     784           14 :     m_backendQueue->callInEventLoop([&]() { m_clientBackend->setMute(mute, sourceId); });
     785            7 : }
     786              : 
     787            3 : bool GStreamerMSEMediaPlayerClient::getMute(int sourceId)
     788              : {
     789            3 :     bool mute{false};
     790            6 :     m_backendQueue->callInEventLoop([&]() { m_clientBackend->getMute(mute, sourceId); });
     791              : 
     792            3 :     return mute;
     793              : }
     794              : 
     795            3 : void GStreamerMSEMediaPlayerClient::setTextTrackIdentifier(const std::string &textTrackIdentifier)
     796              : {
     797            6 :     m_backendQueue->callInEventLoop([&]() { m_clientBackend->setTextTrackIdentifier(textTrackIdentifier); });
     798            3 : }
     799              : 
     800            2 : std::string GStreamerMSEMediaPlayerClient::getTextTrackIdentifier()
     801              : {
     802            2 :     std::string getTextTrackIdentifier;
     803            4 :     m_backendQueue->callInEventLoop([&]() { m_clientBackend->getTextTrackIdentifier(getTextTrackIdentifier); });
     804            2 :     return getTextTrackIdentifier;
     805              : }
     806              : 
     807            6 : bool GStreamerMSEMediaPlayerClient::setLowLatency(bool lowLatency)
     808              : {
     809            6 :     if (!m_clientBackend)
     810              :     {
     811            1 :         return false;
     812              :     }
     813              : 
     814            5 :     bool status{false};
     815           10 :     m_backendQueue->callInEventLoop([&]() { status = m_clientBackend->setLowLatency(lowLatency); });
     816            5 :     return status;
     817              : }
     818              : 
     819            6 : bool GStreamerMSEMediaPlayerClient::setSync(bool sync)
     820              : {
     821            6 :     if (!m_clientBackend)
     822              :     {
     823            1 :         return false;
     824              :     }
     825              : 
     826            5 :     bool status{false};
     827           10 :     m_backendQueue->callInEventLoop([&]() { status = m_clientBackend->setSync(sync); });
     828            5 :     return status;
     829              : }
     830              : 
     831            4 : bool GStreamerMSEMediaPlayerClient::getSync(bool &sync)
     832              : {
     833            4 :     if (!m_clientBackend)
     834              :     {
     835            1 :         return false;
     836              :     }
     837              : 
     838            3 :     bool status{false};
     839            6 :     m_backendQueue->callInEventLoop([&]() { status = m_clientBackend->getSync(sync); });
     840            3 :     return status;
     841              : }
     842              : 
     843            6 : bool GStreamerMSEMediaPlayerClient::setSyncOff(bool syncOff)
     844              : {
     845            6 :     if (!m_clientBackend)
     846              :     {
     847            1 :         return false;
     848              :     }
     849              : 
     850            5 :     bool status{false};
     851           10 :     m_backendQueue->callInEventLoop([&]() { status = m_clientBackend->setSyncOff(syncOff); });
     852            5 :     return status;
     853              : }
     854              : 
     855           10 : bool GStreamerMSEMediaPlayerClient::setStreamSyncMode(int32_t sourceId, int32_t streamSyncMode)
     856              : {
     857           10 :     if (!m_clientBackend)
     858              :     {
     859            1 :         return false;
     860              :     }
     861              : 
     862            9 :     bool status{false};
     863           18 :     m_backendQueue->callInEventLoop([&]() { status = m_clientBackend->setStreamSyncMode(sourceId, streamSyncMode); });
     864            9 :     return status;
     865              : }
     866              : 
     867            4 : bool GStreamerMSEMediaPlayerClient::getStreamSyncMode(int32_t &streamSyncMode)
     868              : {
     869            4 :     if (!m_clientBackend)
     870              :     {
     871            1 :         return false;
     872              :     }
     873              : 
     874            3 :     bool status{false};
     875            6 :     m_backendQueue->callInEventLoop([&]() { status = m_clientBackend->getStreamSyncMode(streamSyncMode); });
     876            3 :     return status;
     877              : }
     878              : 
     879           44 : ClientState GStreamerMSEMediaPlayerClient::getClientState()
     880              : {
     881           44 :     ClientState state{ClientState::IDLE};
     882           44 :     m_backendQueue->callInEventLoop([&]() { state = m_clientState; });
     883           44 :     return state;
     884              : }
     885              : 
     886          173 : void GStreamerMSEMediaPlayerClient::handleStreamCollection(int32_t audioStreams, int32_t videoStreams,
     887              :                                                            int32_t subtitleStreams)
     888              : {
     889          346 :     m_backendQueue->callInEventLoop(
     890          173 :         [&]()
     891              :         {
     892          173 :             if (m_audioStreams == UNKNOWN_STREAMS_NUMBER)
     893          170 :                 m_audioStreams = audioStreams;
     894          173 :             if (m_videoStreams == UNKNOWN_STREAMS_NUMBER)
     895          169 :                 m_videoStreams = videoStreams;
     896          173 :             if (m_subtitleStreams == UNKNOWN_STREAMS_NUMBER)
     897          169 :                 m_subtitleStreams = subtitleStreams;
     898              : 
     899          173 :             GST_INFO("Updated number of streams. New streams' numbers; video=%d, audio=%d, text=%d", m_videoStreams,
     900              :                      m_audioStreams, m_subtitleStreams);
     901          173 :         });
     902              : }
     903              : 
     904            3 : void GStreamerMSEMediaPlayerClient::setBufferingLimit(uint32_t limitBufferingMs)
     905              : {
     906            3 :     if (!m_clientBackend)
     907              :     {
     908            0 :         return;
     909              :     }
     910            6 :     m_backendQueue->callInEventLoop([&]() { m_clientBackend->setBufferingLimit(limitBufferingMs); });
     911              : }
     912              : 
     913            2 : uint32_t GStreamerMSEMediaPlayerClient::getBufferingLimit()
     914              : {
     915            2 :     if (!m_clientBackend)
     916              :     {
     917            0 :         return kDefaultBufferingLimit;
     918              :     }
     919              : 
     920            2 :     uint32_t result{kDefaultBufferingLimit};
     921            4 :     m_backendQueue->callInEventLoop([&]() { m_clientBackend->getBufferingLimit(result); });
     922            2 :     return result;
     923              : }
     924              : 
     925            3 : void GStreamerMSEMediaPlayerClient::setUseBuffering(bool useBuffering)
     926              : {
     927            3 :     if (!m_clientBackend)
     928              :     {
     929            0 :         return;
     930              :     }
     931            6 :     m_backendQueue->callInEventLoop([&]() { m_clientBackend->setUseBuffering(useBuffering); });
     932              : }
     933              : 
     934            2 : bool GStreamerMSEMediaPlayerClient::getUseBuffering()
     935              : {
     936            2 :     if (!m_clientBackend)
     937              :     {
     938            0 :         return kDefaultUseBuffering;
     939              :     }
     940              : 
     941            2 :     bool result{kDefaultUseBuffering};
     942            4 :     m_backendQueue->callInEventLoop([&]() { m_clientBackend->getUseBuffering(result); });
     943            2 :     return result;
     944              : }
     945              : 
     946            3 : bool GStreamerMSEMediaPlayerClient::switchSource(const std::unique_ptr<firebolt::rialto::IMediaPipeline::MediaSource> &source)
     947              : {
     948            3 :     bool result = false;
     949            6 :     m_backendQueue->callInEventLoop([&]() { result = m_clientBackend->switchSource(source); });
     950              : 
     951            3 :     return result;
     952              : }
     953              : 
     954           36 : IFlushAndDataSynchronizer &GStreamerMSEMediaPlayerClient::getFlushAndDataSynchronizer()
     955              : {
     956           36 :     return m_flushAndDataSynchronizer;
     957              : }
     958              : 
     959          335 : bool GStreamerMSEMediaPlayerClient::checkIfAllAttachedSourcesInStates(const std::vector<ClientState> &states)
     960              : {
     961          670 :     return std::all_of(m_attachedSources.begin(), m_attachedSources.end(), [states](const auto &source)
     962         1020 :                        { return std::find(states.begin(), states.end(), source.second.m_state) != states.end(); });
     963              : }
     964              : 
     965          210 : bool GStreamerMSEMediaPlayerClient::areAllStreamsAttached()
     966              : {
     967          210 :     int32_t attachedVideoSources = 0;
     968          210 :     int32_t attachedAudioSources = 0;
     969          210 :     int32_t attachedSubtitleSources = 0;
     970          431 :     for (auto &source : m_attachedSources)
     971              :     {
     972          221 :         if (source.second.getType() == firebolt::rialto::MediaSourceType::VIDEO)
     973              :         {
     974           42 :             attachedVideoSources++;
     975              :         }
     976          179 :         else if (source.second.getType() == firebolt::rialto::MediaSourceType::AUDIO)
     977              :         {
     978          168 :             attachedAudioSources++;
     979              :         }
     980           11 :         else if (source.second.getType() == firebolt::rialto::MediaSourceType::SUBTITLE)
     981              :         {
     982           11 :             attachedSubtitleSources++;
     983              :         }
     984              :     }
     985              : 
     986          366 :     return attachedVideoSources == m_videoStreams && attachedAudioSources == m_audioStreams &&
     987          366 :            attachedSubtitleSources == m_subtitleStreams;
     988              : }
     989              : 
     990           10 : bool GStreamerMSEMediaPlayerClient::requestPullBuffer(int streamId, size_t frameCount, unsigned int needDataRequestId)
     991              : {
     992           10 :     bool result = false;
     993           20 :     m_backendQueue->callInEventLoop(
     994           10 :         [&]()
     995              :         {
     996           10 :             auto sourceIt = m_attachedSources.find(streamId);
     997           10 :             if (sourceIt == m_attachedSources.end())
     998              :             {
     999            1 :                 GST_ERROR("There's no attached source with id %d", streamId);
    1000              : 
    1001            1 :                 result = false;
    1002            1 :                 return;
    1003              :             }
    1004            9 :             result = sourceIt->second.m_bufferPuller->requestPullBuffer(streamId, frameCount, needDataRequestId, this);
    1005              :         });
    1006              : 
    1007           10 :     return result;
    1008              : }
    1009              : 
    1010            5 : bool GStreamerMSEMediaPlayerClient::handleQos(int sourceId, firebolt::rialto::QosInfo qosInfo)
    1011              : {
    1012            5 :     bool result = false;
    1013           10 :     m_backendQueue->callInEventLoop(
    1014            5 :         [&]()
    1015              :         {
    1016            5 :             auto sourceIt = m_attachedSources.find(sourceId);
    1017            5 :             if (sourceIt == m_attachedSources.end())
    1018              :             {
    1019            1 :                 result = false;
    1020            1 :                 return;
    1021              :             }
    1022            4 :             sourceIt->second.m_delegate->handleQos(qosInfo.processed, qosInfo.dropped);
    1023            4 :             result = true;
    1024              :         });
    1025              : 
    1026            5 :     return result;
    1027              : }
    1028              : 
    1029            2 : bool GStreamerMSEMediaPlayerClient::handleBufferUnderflow(int sourceId)
    1030              : {
    1031            2 :     bool result = false;
    1032            4 :     m_backendQueue->callInEventLoop(
    1033            2 :         [&]()
    1034              :         {
    1035            2 :             auto sourceIt = m_attachedSources.find(sourceId);
    1036            2 :             if (sourceIt == m_attachedSources.end())
    1037              :             {
    1038            1 :                 result = false;
    1039            1 :                 return;
    1040              :             }
    1041              : 
    1042            1 :             rialto_mse_base_handle_rialto_server_sent_buffer_underflow(sourceIt->second.m_rialtoSink);
    1043              : 
    1044            1 :             result = true;
    1045              :         });
    1046              : 
    1047            2 :     return result;
    1048              : }
    1049              : 
    1050            5 : bool GStreamerMSEMediaPlayerClient::handlePlaybackError(int sourceId, firebolt::rialto::PlaybackError error)
    1051              : {
    1052            5 :     bool result = false;
    1053           10 :     m_backendQueue->callInEventLoop(
    1054            5 :         [&]()
    1055              :         {
    1056            5 :             auto sourceIt = m_attachedSources.find(sourceId);
    1057            5 :             if (sourceIt == m_attachedSources.end())
    1058              :             {
    1059            1 :                 result = false;
    1060            1 :                 return;
    1061              :             }
    1062              : 
    1063              :             // Even though rialto has only reported a non-fatal error, still fail the pipeline from rialto-gstreamer
    1064            4 :             GST_ERROR("Received Playback error '%s', posting error on %s sink", toString(error),
    1065              :                       toString(sourceIt->second.getType()));
    1066            4 :             if (firebolt::rialto::PlaybackError::DECRYPTION == error)
    1067              :             {
    1068            6 :                 sourceIt->second.m_delegate->handleError("Rialto dropped a frame that failed to decrypt",
    1069              :                                                          GST_STREAM_ERROR_DECRYPT);
    1070              :             }
    1071              :             else
    1072              :             {
    1073            6 :                 sourceIt->second.m_delegate->handleError("Rialto server playback failed");
    1074              :             }
    1075              : 
    1076            4 :             result = true;
    1077              :         });
    1078              : 
    1079            5 :     return result;
    1080              : }
    1081              : 
    1082            4 : firebolt::rialto::AddSegmentStatus GStreamerMSEMediaPlayerClient::addSegment(
    1083              :     unsigned int needDataRequestId, const std::unique_ptr<firebolt::rialto::IMediaPipeline::MediaSegment> &mediaSegment)
    1084              : {
    1085              :     // rialto client's addSegment call is MT safe, so it's ok to call it from the Puller's thread
    1086            4 :     return m_clientBackend->addSegment(needDataRequestId, mediaSegment);
    1087              : }
    1088              : 
    1089          206 : BufferPuller::BufferPuller(const std::shared_ptr<IMessageQueueFactory> &messageQueueFactory, GstElement *rialtoSink,
    1090              :                            const std::shared_ptr<BufferParser> &bufferParser,
    1091          206 :                            const std::shared_ptr<IPullModePlaybackDelegate> &delegate)
    1092          206 :     : m_queue{messageQueueFactory->createMessageQueue()}, m_rialtoSink(rialtoSink), m_bufferParser(bufferParser),
    1093          206 :       m_delegate{delegate}
    1094              : {
    1095              : }
    1096              : 
    1097          206 : void BufferPuller::start()
    1098              : {
    1099          206 :     m_queue->start();
    1100              : }
    1101              : 
    1102           64 : void BufferPuller::stop()
    1103              : {
    1104           64 :     m_queue->stop();
    1105              : }
    1106              : 
    1107            9 : bool BufferPuller::requestPullBuffer(int sourceId, size_t frameCount, unsigned int needDataRequestId,
    1108              :                                      GStreamerMSEMediaPlayerClient *player)
    1109              : {
    1110           27 :     return m_queue->postMessage(std::make_shared<PullBufferMessage>(sourceId, frameCount, needDataRequestId, m_rialtoSink,
    1111           27 :                                                                     m_bufferParser, *m_queue, player, m_delegate));
    1112              : }
    1113              : 
    1114           10 : HaveDataMessage::HaveDataMessage(firebolt::rialto::MediaSourceStatus status, int sourceId,
    1115           10 :                                  unsigned int needDataRequestId, GStreamerMSEMediaPlayerClient *player)
    1116           10 :     : m_status(status), m_sourceId(sourceId), m_needDataRequestId(needDataRequestId), m_player(player)
    1117              : {
    1118              : }
    1119              : 
    1120           10 : void HaveDataMessage::handle()
    1121              : {
    1122           10 :     if (m_player->m_attachedSources.find(m_sourceId) == m_player->m_attachedSources.end())
    1123              :     {
    1124            1 :         GST_WARNING("Source id %d is invalid", m_sourceId);
    1125            1 :         return;
    1126              :     }
    1127              : 
    1128            9 :     m_player->m_clientBackend->haveData(m_status, m_needDataRequestId);
    1129              : }
    1130              : 
    1131            9 : PullBufferMessage::PullBufferMessage(int sourceId, size_t frameCount, unsigned int needDataRequestId,
    1132              :                                      GstElement *rialtoSink, const std::shared_ptr<BufferParser> &bufferParser,
    1133              :                                      IMessageQueue &pullerQueue, GStreamerMSEMediaPlayerClient *player,
    1134            9 :                                      const std::shared_ptr<IPullModePlaybackDelegate> &delegate)
    1135            9 :     : m_sourceId(sourceId), m_frameCount(frameCount), m_needDataRequestId(needDataRequestId), m_rialtoSink(rialtoSink),
    1136            9 :       m_bufferParser(bufferParser), m_pullerQueue(pullerQueue), m_player(player), m_delegate{delegate}
    1137              : {
    1138              : }
    1139              : 
    1140            8 : void PullBufferMessage::handle()
    1141              : {
    1142            8 :     bool isEos = false;
    1143            8 :     unsigned int addedSegments = 0;
    1144              : 
    1145           10 :     for (unsigned int frame = 0; frame < m_frameCount; ++frame)
    1146              :     {
    1147            8 :         if (!m_delegate->isReadyToSendData())
    1148              :         {
    1149            2 :             GST_INFO_OBJECT(m_rialtoSink, "Not ready to send data - segment or eos not received yet");
    1150            6 :             break;
    1151              :         }
    1152            6 :         GstRefSample sample = m_delegate->getFrontSample();
    1153            6 :         if (!sample)
    1154              :         {
    1155            3 :             if (m_delegate->isEos())
    1156              :             {
    1157            1 :                 isEos = true;
    1158              :             }
    1159              :             else
    1160              :             {
    1161              :                 // it's not a critical issue. It might be caused by receiving too many need data requests.
    1162            2 :                 GST_INFO_OBJECT(m_rialtoSink, "Could not get a sample");
    1163              :             }
    1164            3 :             break;
    1165              :         }
    1166              : 
    1167              :         // we pass GstMapInfo's pointers on data buffers to RialtoClient
    1168              :         // so we need to hold it until RialtoClient copies them to shm
    1169            3 :         GstBuffer *buffer = sample.getBuffer();
    1170              :         GstMapInfo map;
    1171            3 :         if (!gst_buffer_map(buffer, &map, GST_MAP_READ))
    1172              :         {
    1173            0 :             GST_ERROR_OBJECT(m_rialtoSink, "Could not map buffer");
    1174            0 :             m_delegate->popSample();
    1175            0 :             continue;
    1176              :         }
    1177              : 
    1178              :         std::unique_ptr<firebolt::rialto::IMediaPipeline::MediaSegment> mseData =
    1179            3 :             m_bufferParser->parseBuffer(sample, buffer, map, m_sourceId);
    1180            3 :         if (!mseData)
    1181              :         {
    1182            0 :             GST_ERROR_OBJECT(m_rialtoSink, "No data returned from the parser");
    1183            0 :             gst_buffer_unmap(buffer, &map);
    1184            0 :             m_delegate->popSample();
    1185            0 :             continue;
    1186              :         }
    1187              : 
    1188            3 :         firebolt::rialto::AddSegmentStatus addSegmentStatus = m_player->addSegment(m_needDataRequestId, mseData);
    1189            3 :         if (addSegmentStatus == firebolt::rialto::AddSegmentStatus::NO_SPACE)
    1190              :         {
    1191            1 :             gst_buffer_unmap(buffer, &map);
    1192            1 :             GST_INFO_OBJECT(m_rialtoSink, "There's no space to add sample");
    1193            1 :             break;
    1194              :         }
    1195              : 
    1196            2 :         gst_buffer_unmap(buffer, &map);
    1197            2 :         m_delegate->popSample();
    1198            2 :         addedSegments++;
    1199            7 :     }
    1200              : 
    1201            8 :     firebolt::rialto::MediaSourceStatus status = firebolt::rialto::MediaSourceStatus::OK;
    1202            8 :     if (isEos)
    1203              :     {
    1204            1 :         status = firebolt::rialto::MediaSourceStatus::EOS;
    1205              :     }
    1206            7 :     else if (addedSegments == 0)
    1207              :     {
    1208            5 :         status = firebolt::rialto::MediaSourceStatus::NO_AVAILABLE_SAMPLES;
    1209              :     }
    1210              : 
    1211            8 :     if (firebolt::rialto::MediaSourceStatus::OK == status || firebolt::rialto::MediaSourceStatus::EOS == status)
    1212              :     {
    1213            3 :         m_player->getFlushAndDataSynchronizer().notifyDataPushed(m_sourceId);
    1214              :     }
    1215              : 
    1216           16 :     m_player->m_backendQueue->postMessage(
    1217           16 :         std::make_shared<HaveDataMessage>(status, m_sourceId, m_needDataRequestId, m_player));
    1218            8 : }
    1219              : 
    1220           10 : NeedDataMessage::NeedDataMessage(int sourceId, size_t frameCount, unsigned int needDataRequestId,
    1221           10 :                                  GStreamerMSEMediaPlayerClient *player)
    1222           10 :     : m_sourceId(sourceId), m_frameCount(frameCount), m_needDataRequestId(needDataRequestId), m_player(player)
    1223              : {
    1224              : }
    1225              : 
    1226           10 : void NeedDataMessage::handle()
    1227              : {
    1228           10 :     if (!m_player->requestPullBuffer(m_sourceId, m_frameCount, m_needDataRequestId))
    1229              :     {
    1230            2 :         GST_ERROR("Failed to pull buffer for sourceId=%d and NeedDataRequestId %u", m_sourceId, m_needDataRequestId);
    1231            4 :         m_player->m_backendQueue->postMessage(
    1232            2 :             std::make_shared<HaveDataMessage>(firebolt::rialto::MediaSourceStatus::ERROR, m_sourceId,
    1233            2 :                                               m_needDataRequestId, m_player));
    1234              :     }
    1235           10 : }
    1236              : 
    1237           60 : PlaybackStateMessage::PlaybackStateMessage(firebolt::rialto::PlaybackState state, GStreamerMSEMediaPlayerClient *player)
    1238           60 :     : m_state(state), m_player(player)
    1239              : {
    1240              : }
    1241              : 
    1242           60 : void PlaybackStateMessage::handle()
    1243              : {
    1244           60 :     m_player->handlePlaybackStateChange(m_state);
    1245              : }
    1246              : 
    1247            5 : QosMessage::QosMessage(int sourceId, firebolt::rialto::QosInfo qosInfo, GStreamerMSEMediaPlayerClient *player)
    1248            5 :     : m_sourceId(sourceId), m_qosInfo(qosInfo), m_player(player)
    1249              : {
    1250              : }
    1251              : 
    1252            5 : void QosMessage::handle()
    1253              : {
    1254            5 :     if (!m_player->handleQos(m_sourceId, m_qosInfo))
    1255              :     {
    1256            1 :         GST_ERROR("Failed to handle qos for sourceId=%d", m_sourceId);
    1257              :     }
    1258            5 : }
    1259              : 
    1260            2 : BufferUnderflowMessage::BufferUnderflowMessage(int sourceId, GStreamerMSEMediaPlayerClient *player)
    1261            2 :     : m_sourceId(sourceId), m_player(player)
    1262              : {
    1263              : }
    1264              : 
    1265            2 : void BufferUnderflowMessage::handle()
    1266              : {
    1267            2 :     if (!m_player->handleBufferUnderflow(m_sourceId))
    1268              :     {
    1269            1 :         GST_ERROR("Failed to handle buffer underflow for sourceId=%d", m_sourceId);
    1270              :     }
    1271            2 : }
    1272              : 
    1273            5 : PlaybackErrorMessage::PlaybackErrorMessage(int sourceId, firebolt::rialto::PlaybackError error,
    1274            5 :                                            GStreamerMSEMediaPlayerClient *player)
    1275            5 :     : m_sourceId(sourceId), m_error(error), m_player(player)
    1276              : {
    1277              : }
    1278              : 
    1279            5 : void PlaybackErrorMessage::handle()
    1280              : {
    1281            5 :     if (!m_player->handlePlaybackError(m_sourceId, m_error))
    1282              :     {
    1283            1 :         GST_ERROR("Failed to handle playback error for sourceId=%d, error %s", m_sourceId, toString(m_error));
    1284              :     }
    1285            5 : }
    1286              : 
    1287            1 : SetPositionMessage::SetPositionMessage(int64_t newPosition, std::unordered_map<int32_t, AttachedSource> &attachedSources)
    1288            1 :     : m_newPosition(newPosition), m_attachedSources(attachedSources)
    1289              : {
    1290              : }
    1291              : 
    1292            1 : void SetPositionMessage::handle()
    1293              : {
    1294            2 :     for (auto &source : m_attachedSources)
    1295              :     {
    1296            1 :         source.second.setPosition(m_newPosition);
    1297              :     }
    1298              : }
    1299              : 
    1300            1 : SetDurationMessage::SetDurationMessage(int64_t newDuration, int64_t &targetDuration)
    1301            1 :     : m_newDuration(newDuration), m_targetDuration(targetDuration)
    1302              : {
    1303              : }
    1304              : 
    1305            1 : void SetDurationMessage::handle()
    1306              : {
    1307            1 :     m_targetDuration = m_newDuration;
    1308              : }
    1309              : 
    1310            7 : SourceFlushedMessage::SourceFlushedMessage(int32_t sourceId, GStreamerMSEMediaPlayerClient *player)
    1311            7 :     : m_sourceId{sourceId}, m_player{player}
    1312              : {
    1313              : }
    1314              : 
    1315            7 : void SourceFlushedMessage::handle()
    1316              : {
    1317            7 :     m_player->handleSourceFlushed(m_sourceId);
    1318              : }
        

Generated by: LCOV version 2.0-1