LCOV - code coverage report
Current view: top level - media/server/gstplayer/source/tasks/generic - SetupElement.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 100.0 % 99 99
Test Date: 2025-02-18 13:13:53 Functions: 100.0 % 9 9

            Line data    Source code
       1              : /*
       2              :  * If not stated otherwise in this file or this component's LICENSE file the
       3              :  * following copyright and licenses apply:
       4              :  *
       5              :  * Copyright 2022 Sky UK
       6              :  *
       7              :  * Licensed under the Apache License, Version 2.0 (the "License");
       8              :  * you may not use this file except in compliance with the License.
       9              :  * You may obtain a copy of the License at
      10              :  *
      11              :  * http://www.apache.org/licenses/LICENSE-2.0
      12              :  *
      13              :  * Unless required by applicable law or agreed to in writing, software
      14              :  * distributed under the License is distributed on an "AS IS" BASIS,
      15              :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      16              :  * See the License for the specific language governing permissions and
      17              :  * limitations under the License.
      18              :  */
      19              : 
      20              : #include "tasks/generic/SetupElement.h"
      21              : #include "GenericPlayerContext.h"
      22              : #include "IGlibWrapper.h"
      23              : #include "IGstGenericPlayerPrivate.h"
      24              : #include "IGstWrapper.h"
      25              : #include "RialtoServerLogging.h"
      26              : #include "Utils.h"
      27              : 
      28              : namespace
      29              : {
      30              : /**
      31              :  * @brief Callback for audio underflow event from sink. Called by the Gstreamer thread.
      32              :  *
      33              :  * @param[in] object     : the object that emitted the signal
      34              :  * @param[in] fifoDepth  : the fifo depth (may be 0)
      35              :  * @param[in] queueDepth : the queue depth (may be NULL)
      36              :  * @param[in] self       : The pointer to IGstGenericPlayerPrivate
      37              :  *
      38              :  * @retval true if the handling of the message is successful, false otherwise.
      39              :  */
      40            1 : void audioUnderflowCallback(GstElement *object, guint fifoDepth, gpointer queueDepth, gpointer self)
      41              : {
      42            1 :     firebolt::rialto::server::IGstGenericPlayerPrivate *player =
      43              :         static_cast<firebolt::rialto::server::IGstGenericPlayerPrivate *>(self);
      44            1 :     player->scheduleAudioUnderflow();
      45              : }
      46              : 
      47              : /**
      48              :  * @brief Callback for video underflow event from sink. Called by the Gstreamer thread.
      49              :  *
      50              :  * @param[in] object     : the object that emitted the signal
      51              :  * @param[in] fifoDepth  : the fifo depth (may be 0)
      52              :  * @param[in] queueDepth : the queue depth (may be NULL)
      53              :  * @param[in] self       : The pointer to IGstGenericPlayerPrivate
      54              :  *
      55              :  * @retval true if the handling of the message is successful, false otherwise.
      56              :  */
      57            1 : void videoUnderflowCallback(GstElement *object, guint fifoDepth, gpointer queueDepth, gpointer self)
      58              : {
      59            1 :     firebolt::rialto::server::IGstGenericPlayerPrivate *player =
      60              :         static_cast<firebolt::rialto::server::IGstGenericPlayerPrivate *>(self);
      61            1 :     player->scheduleVideoUnderflow();
      62              : }
      63              : 
      64              : /**
      65              :  * @brief Callback for a autovideosink when a child has been added to the sink.
      66              :  *
      67              :  * @param[in] obj        : the parent element (autovideosink)
      68              :  * @param[in] object     : the child element
      69              :  * @param[in] name       : the name of the child element
      70              :  * @param[in] self       : The pointer to IGstGenericPlayerPrivate
      71              :  */
      72            1 : void autoVideoSinkChildAddedCallback(GstChildProxy *obj, GObject *object, gchar *name, gpointer self)
      73              : {
      74            1 :     RIALTO_SERVER_LOG_DEBUG("AutoVideoSink added element %s", name);
      75            1 :     firebolt::rialto::server::IGstGenericPlayerPrivate *player =
      76              :         static_cast<firebolt::rialto::server::IGstGenericPlayerPrivate *>(self);
      77            1 :     player->addAutoVideoSinkChild(object);
      78              : }
      79              : 
      80              : /**
      81              :  * @brief Callback for a autoaudiosink when a child has been added to the sink.
      82              :  *
      83              :  * @param[in] obj        : the parent element (autoaudiosink)
      84              :  * @param[in] object     : the child element
      85              :  * @param[in] name       : the name of the child element
      86              :  * @param[in] self       : The pointer to IGstGenericPlayerPrivate
      87              :  */
      88            1 : void autoAudioSinkChildAddedCallback(GstChildProxy *obj, GObject *object, gchar *name, gpointer self)
      89              : {
      90            1 :     RIALTO_SERVER_LOG_DEBUG("AutoAudioSink added element %s", name);
      91            1 :     firebolt::rialto::server::IGstGenericPlayerPrivate *player =
      92              :         static_cast<firebolt::rialto::server::IGstGenericPlayerPrivate *>(self);
      93            1 :     player->addAutoAudioSinkChild(object);
      94              : }
      95              : 
      96              : /**
      97              :  * @brief Callback for a autovideosink when a child has been removed from the sink.
      98              :  *
      99              :  * @param[in] obj        : the parent element (autovideosink)
     100              :  * @param[in] object     : the child element
     101              :  * @param[in] name       : the name of the child element
     102              :  * @param[in] self       : The pointer to IGstGenericPlayerPrivate
     103              :  */
     104            1 : void autoVideoSinkChildRemovedCallback(GstChildProxy *obj, GObject *object, gchar *name, gpointer self)
     105              : {
     106            1 :     RIALTO_SERVER_LOG_DEBUG("AutoVideoSink removed element %s", name);
     107            1 :     firebolt::rialto::server::IGstGenericPlayerPrivate *player =
     108              :         static_cast<firebolt::rialto::server::IGstGenericPlayerPrivate *>(self);
     109            1 :     player->removeAutoVideoSinkChild(object);
     110              : }
     111              : 
     112              : /**
     113              :  * @brief Callback for a autoaudiosink when a child has been removed from the sink.
     114              :  *
     115              :  * @param[in] obj        : the parent element (autoaudiosink)
     116              :  * @param[in] object     : the child element
     117              :  * @param[in] name       : the name of the child element
     118              :  * @param[in] self       : The pointer to IGstGenericPlayerPrivate
     119              :  */
     120            1 : void autoAudioSinkChildRemovedCallback(GstChildProxy *obj, GObject *object, gchar *name, gpointer self)
     121              : {
     122            1 :     RIALTO_SERVER_LOG_DEBUG("AutoAudioSink removed element %s", name);
     123            1 :     firebolt::rialto::server::IGstGenericPlayerPrivate *player =
     124              :         static_cast<firebolt::rialto::server::IGstGenericPlayerPrivate *>(self);
     125            1 :     player->removeAutoAudioSinkChild(object);
     126              : }
     127              : } // namespace
     128              : 
     129              : namespace firebolt::rialto::server::tasks::generic
     130              : {
     131           28 : SetupElement::SetupElement(GenericPlayerContext &context,
     132              :                            std::shared_ptr<firebolt::rialto::wrappers::IGstWrapper> gstWrapper,
     133              :                            std::shared_ptr<firebolt::rialto::wrappers::IGlibWrapper> glibWrapper,
     134           28 :                            IGstGenericPlayerPrivate &player, GstElement *element)
     135           28 :     : m_context{context}, m_gstWrapper{gstWrapper}, m_glibWrapper{glibWrapper}, m_player{player}, m_element{element}
     136              : {
     137           28 :     RIALTO_SERVER_LOG_DEBUG("Constructing SetupElement");
     138              : }
     139              : 
     140           29 : SetupElement::~SetupElement()
     141              : {
     142           28 :     RIALTO_SERVER_LOG_DEBUG("SetupElement finished");
     143           29 : }
     144              : 
     145           27 : void SetupElement::execute() const
     146              : {
     147           27 :     RIALTO_SERVER_LOG_DEBUG("Executing SetupElement");
     148              : 
     149           27 :     const std::string kElementTypeName = m_glibWrapper->gTypeName(G_OBJECT_TYPE(m_element));
     150           27 :     if (kElementTypeName == "GstAutoVideoSink")
     151              :     {
     152              :         // Check and store child sink so we can set underlying properties
     153            5 :         m_glibWrapper->gSignalConnect(m_element, "child-added", G_CALLBACK(autoVideoSinkChildAddedCallback), &m_player);
     154            5 :         m_glibWrapper->gSignalConnect(m_element, "child-removed", G_CALLBACK(autoVideoSinkChildRemovedCallback),
     155            5 :                                       &m_player);
     156              : 
     157              :         // AutoVideoSink sets child before it is setup on the pipeline, so check for children here
     158            5 :         GstIterator *sinks = m_gstWrapper->gstBinIterateSinks(GST_BIN(m_element));
     159            5 :         if (sinks && sinks->size > 1)
     160              :         {
     161            1 :             RIALTO_SERVER_LOG_WARN("More than one child sink attached");
     162              :         }
     163              : 
     164            5 :         GValue elem = G_VALUE_INIT;
     165            5 :         if (m_gstWrapper->gstIteratorNext(sinks, &elem) == GST_ITERATOR_OK)
     166              :         {
     167            2 :             m_player.addAutoVideoSinkChild(G_OBJECT(m_glibWrapper->gValueGetObject(&elem)));
     168              :         }
     169            5 :         m_glibWrapper->gValueUnset(&elem);
     170              : 
     171            5 :         if (sinks)
     172            5 :             m_gstWrapper->gstIteratorFree(sinks);
     173              :     }
     174           22 :     else if (kElementTypeName == "GstAutoAudioSink")
     175              :     {
     176              :         // Check and store child sink so we can set underlying properties
     177            5 :         m_glibWrapper->gSignalConnect(m_element, "child-added", G_CALLBACK(autoAudioSinkChildAddedCallback), &m_player);
     178            5 :         m_glibWrapper->gSignalConnect(m_element, "child-removed", G_CALLBACK(autoAudioSinkChildRemovedCallback),
     179            5 :                                       &m_player);
     180              : 
     181              :         // AutoAudioSink sets child before it is setup on the pipeline, so check for children here
     182            5 :         GstIterator *sinks = m_gstWrapper->gstBinIterateSinks(GST_BIN(m_element));
     183            5 :         if (sinks && sinks->size > 1)
     184              :         {
     185            1 :             RIALTO_SERVER_LOG_WARN("More than one child sink attached");
     186              :         }
     187              : 
     188            5 :         GValue elem = G_VALUE_INIT;
     189            5 :         if (m_gstWrapper->gstIteratorNext(sinks, &elem) == GST_ITERATOR_OK)
     190              :         {
     191            2 :             m_player.addAutoAudioSinkChild(G_OBJECT(m_glibWrapper->gValueGetObject(&elem)));
     192              :         }
     193            5 :         m_glibWrapper->gValueUnset(&elem);
     194              : 
     195            5 :         if (sinks)
     196            5 :             m_gstWrapper->gstIteratorFree(sinks);
     197              :     }
     198              : 
     199           27 :     if (m_glibWrapper->gStrHasPrefix(GST_ELEMENT_NAME(m_element), "amlhalasink"))
     200              :     {
     201            2 :         if (m_context.streamInfo.find(MediaSourceType::VIDEO) != m_context.streamInfo.end())
     202              :         {
     203              :             // Wait for video so that the audio aligns at the starting point with timeout of 4000ms.
     204            1 :             m_glibWrapper->gObjectSet(m_element, "wait-video", TRUE, "a-wait-timeout", 4000, nullptr);
     205              :         }
     206              : 
     207              :         // Xrun occasionally pauses the underlying sink due to unstable playback, but the rest of the pipeline
     208              :         // remains in the playing state. This causes problems with the synchronization of gst element and rialto
     209              :         // ultimately hangs waiting for pipeline termination.
     210            2 :         m_glibWrapper->gObjectSet(m_element, "disable-xrun", TRUE, nullptr);
     211              :     }
     212           25 :     else if (m_glibWrapper->gStrHasPrefix(GST_ELEMENT_NAME(m_element), "brcmaudiosink"))
     213              :     {
     214            1 :         m_glibWrapper->gObjectSet(m_element, "async", TRUE, nullptr);
     215              :     }
     216           24 :     else if (m_glibWrapper->gStrHasPrefix(GST_ELEMENT_NAME(m_element), "rialtotexttracksink"))
     217              :     {
     218              :         // in cannot be set during construction, because playsink overwrites "sync" value of text-sink during setup
     219            1 :         m_glibWrapper->gObjectSet(m_element, "sync", FALSE, nullptr);
     220              :     }
     221              : 
     222           27 :     if (isVideoSink(*m_gstWrapper, m_element))
     223              :     {
     224            9 :         if (!m_context.pendingGeometry.empty())
     225              :         {
     226            1 :             m_player.setVideoSinkRectangle();
     227              :         }
     228            9 :         if (m_context.pendingImmediateOutputForVideo.has_value())
     229              :         {
     230            1 :             m_player.setImmediateOutput();
     231              :         }
     232            9 :         if (m_context.pendingRenderFrame)
     233              :         {
     234            1 :             m_player.setRenderFrame();
     235              :         }
     236              :     }
     237           18 :     else if (isVideoDecoder(*m_gstWrapper, m_element))
     238              :     {
     239            1 :         std::string underflowSignalName = getUnderflowSignalName(*m_glibWrapper, m_element);
     240            1 :         if (!underflowSignalName.empty())
     241              :         {
     242            2 :             m_glibWrapper->gSignalConnect(m_element, underflowSignalName.c_str(), G_CALLBACK(videoUnderflowCallback),
     243            1 :                                           &m_player);
     244              :         }
     245              :     }
     246           17 :     else if (isAudioDecoder(*m_gstWrapper, m_element))
     247              :     {
     248            5 :         std::string underflowSignalName = getUnderflowSignalName(*m_glibWrapper, m_element);
     249            5 :         if (!underflowSignalName.empty())
     250              :         {
     251           10 :             m_glibWrapper->gSignalConnect(m_element, underflowSignalName.c_str(), G_CALLBACK(audioUnderflowCallback),
     252            5 :                                           &m_player);
     253              :         }
     254              : 
     255            5 :         if (m_context.pendingSyncOff.has_value())
     256              :         {
     257            1 :             m_player.setSyncOff();
     258              :         }
     259            5 :         if (m_context.pendingStreamSyncMode.find(MediaSourceType::AUDIO) != m_context.pendingStreamSyncMode.end())
     260              :         {
     261            1 :             m_player.setStreamSyncMode(MediaSourceType::AUDIO);
     262              :         }
     263            5 :         if (m_context.pendingBufferingLimit.has_value())
     264              :         {
     265            1 :             m_player.setBufferingLimit();
     266              :         }
     267            5 :     }
     268           12 :     else if (isAudioSink(*m_gstWrapper, m_element))
     269              :     {
     270           10 :         if (m_context.pendingLowLatency.has_value())
     271              :         {
     272            1 :             m_player.setLowLatency();
     273              :         }
     274           10 :         if (m_context.pendingSync.has_value())
     275              :         {
     276            1 :             m_player.setSync();
     277              :         }
     278              :     }
     279            2 :     else if (isVideoParser(*m_gstWrapper, m_element))
     280              :     {
     281            1 :         if (m_context.pendingStreamSyncMode.find(MediaSourceType::VIDEO) != m_context.pendingStreamSyncMode.end())
     282              :         {
     283            1 :             m_player.setStreamSyncMode(MediaSourceType::VIDEO);
     284              :         }
     285              :     }
     286              : 
     287           27 :     m_gstWrapper->gstObjectUnref(m_element);
     288              : }
     289              : } // namespace firebolt::rialto::server::tasks::generic
        

Generated by: LCOV version 2.0-1