LCOV - code coverage report
Current view: top level - source - RialtoGStreamerMSEBaseSink.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 86.2 % 152 131
Test Date: 2025-10-17 10:59:19 Functions: 100.0 % 17 17

            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              : #define USE_GLIB 1
      20              : 
      21              : #include <cstring>
      22              : #include <limits>
      23              : 
      24              : #include <gst/gst.h>
      25              : 
      26              : #include "ControlBackend.h"
      27              : #include "GStreamerUtils.h"
      28              : #include "IClientLogControl.h"
      29              : #include "IMediaPipeline.h"
      30              : #include "LogToGstHandler.h"
      31              : #include "RialtoGStreamerMSEBaseSink.h"
      32              : #include "RialtoGStreamerMSEBaseSinkPrivate.h"
      33              : 
      34              : GST_DEBUG_CATEGORY_STATIC(RialtoMSEBaseSinkDebug);
      35              : #define GST_CAT_DEFAULT RialtoMSEBaseSinkDebug
      36              : 
      37              : #define rialto_mse_base_sink_parent_class parent_class
      38         4128 : G_DEFINE_TYPE_WITH_CODE(RialtoMSEBaseSink, rialto_mse_base_sink, GST_TYPE_ELEMENT,
      39              :                         G_ADD_PRIVATE(RialtoMSEBaseSink)
      40              :                             GST_DEBUG_CATEGORY_INIT(RialtoMSEBaseSinkDebug, "rialtomsebasesink", 0,
      41              :                                                     "rialto mse base sink"));
      42              : 
      43              : enum
      44              : {
      45              :     PROP_0,
      46              :     PROP_IS_SINGLE_PATH_STREAM,
      47              :     PROP_N_STREAMS,
      48              :     PROP_HAS_DRM,
      49              :     PROP_STATS,
      50              :     PROP_LAST
      51              : };
      52              : 
      53              : enum
      54              : {
      55              :     SIGNAL_UNDERFLOW,
      56              :     SIGNAL_LAST
      57              : };
      58              : 
      59              : static guint g_signals[SIGNAL_LAST] = {0};
      60              : 
      61          291 : void rialto_mse_base_sink_initialise_delegate(RialtoMSEBaseSink *sink, const std::shared_ptr<IPlaybackDelegate> &delegate)
      62              : {
      63          291 :     std::unique_lock lock{sink->priv->m_sinkMutex};
      64          291 :     sink->priv->m_delegate = delegate;
      65              : 
      66          293 :     for (auto &[type, value] : sink->priv->m_queuedProperties)
      67              :     {
      68            2 :         delegate->setProperty(type, &value);
      69            2 :         g_value_unset(&value);
      70              :     }
      71          291 :     sink->priv->m_queuedProperties.clear();
      72              : }
      73              : 
      74         1746 : static std::shared_ptr<IPlaybackDelegate> rialto_mse_base_sink_get_delegate(RialtoMSEBaseSink *sink)
      75              : {
      76         1746 :     std::unique_lock lock{sink->priv->m_sinkMutex};
      77         1746 :     if (!sink->priv->m_delegate)
      78              :     {
      79            3 :         GST_ERROR_OBJECT(sink, "Sink delegate not initialized");
      80              :     }
      81         3492 :     return sink->priv->m_delegate;
      82         1746 : }
      83              : 
      84           45 : static gboolean rialto_mse_base_sink_send_event(GstElement *element, GstEvent *event)
      85              : {
      86           45 :     if (auto delegate = rialto_mse_base_sink_get_delegate(RIALTO_MSE_BASE_SINK(element)))
      87              :     {
      88           45 :         return delegate->handleSendEvent(event);
      89              :     }
      90            0 :     return FALSE;
      91              : }
      92              : 
      93          211 : gboolean rialto_mse_base_sink_event(GstPad *pad, GstObject *parent, GstEvent *event)
      94              : {
      95          211 :     if (auto delegate = rialto_mse_base_sink_get_delegate(RIALTO_MSE_BASE_SINK(parent)))
      96              :     {
      97          211 :         return delegate->handleEvent(pad, parent, event);
      98              :     }
      99            0 :     return FALSE;
     100              : }
     101              : 
     102           33 : GstFlowReturn rialto_mse_base_sink_chain(GstPad *pad, GstObject *parent, GstBuffer *buf)
     103              : {
     104           33 :     if (auto delegate = rialto_mse_base_sink_get_delegate(RIALTO_MSE_BASE_SINK(parent)))
     105              :     {
     106           33 :         return delegate->handleBuffer(buf);
     107              :     }
     108            0 :     return GST_FLOW_ERROR;
     109              : }
     110              : 
     111           38 : static gboolean rialto_mse_base_sink_query(GstElement *element, GstQuery *query)
     112              : {
     113           38 :     RialtoMSEBaseSink *sink = RIALTO_MSE_BASE_SINK(element);
     114           38 :     if (auto delegate = rialto_mse_base_sink_get_delegate(sink))
     115              :     {
     116           38 :         std::optional<gboolean> result{delegate->handleQuery(query)};
     117           38 :         if (result.has_value())
     118              :         {
     119            8 :             return result.value();
     120              :         }
     121           30 :         GstElement *parent = GST_ELEMENT(&sink->parent);
     122           30 :         return GST_ELEMENT_CLASS(parent_class)->query(parent, query);
     123           38 :     }
     124            0 :     return FALSE;
     125              : }
     126              : 
     127          942 : static GstStateChangeReturn rialto_mse_base_sink_change_state(GstElement *element, GstStateChange transition)
     128              : {
     129          942 :     RialtoMSEBaseSink *sink = RIALTO_MSE_BASE_SINK(element);
     130          942 :     if (auto delegate = rialto_mse_base_sink_get_delegate(sink))
     131              :     {
     132          941 :         GstStateChangeReturn status = delegate->changeState(transition);
     133          941 :         if (GST_STATE_CHANGE_FAILURE != status)
     134              :         {
     135          934 :             if (GST_STATE_CHANGE_READY_TO_NULL == transition)
     136              :             {
     137          285 :                 sink->priv->m_delegate.reset();
     138              :             }
     139          934 :             GstStateChangeReturn result = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
     140          934 :             if (G_UNLIKELY(result == GST_STATE_CHANGE_FAILURE))
     141              :             {
     142            0 :                 GST_WARNING_OBJECT(sink, "State change failed");
     143            0 :                 return result;
     144              :             }
     145          934 :             else if (result == GST_STATE_CHANGE_ASYNC)
     146              :             {
     147            0 :                 return GST_STATE_CHANGE_ASYNC;
     148              :             }
     149              :         }
     150          941 :         return status;
     151          942 :     }
     152            1 :     return GST_STATE_CHANGE_FAILURE;
     153              : }
     154              : 
     155           54 : void rialto_mse_base_sink_handle_get_property(RialtoMSEBaseSink *sink, const IPlaybackDelegate::Property &property,
     156              :                                               GValue *value)
     157              : {
     158           54 :     if (auto delegate = rialto_mse_base_sink_get_delegate(sink))
     159              :     {
     160           54 :         delegate->getProperty(property, value);
     161              :     }
     162              :     else // Copy queued value if present
     163              :     {
     164            0 :         std::unique_lock lock{sink->priv->m_sinkMutex};
     165            0 :         if (sink->priv->m_queuedProperties.find(property) != sink->priv->m_queuedProperties.end())
     166              :         {
     167            0 :             g_value_copy(&sink->priv->m_queuedProperties[property], value);
     168              :         }
     169           54 :     }
     170              : }
     171              : 
     172          423 : void rialto_mse_base_sink_handle_set_property(RialtoMSEBaseSink *sink, const IPlaybackDelegate::Property &property,
     173              :                                               const GValue *value)
     174              : {
     175          423 :     if (auto delegate = rialto_mse_base_sink_get_delegate(sink))
     176              :     {
     177          421 :         delegate->setProperty(property, value);
     178              :     }
     179              :     else
     180              :     {
     181            2 :         std::unique_lock lock{sink->priv->m_sinkMutex};
     182            2 :         sink->priv->m_queuedProperties[property] = G_VALUE_INIT;
     183            2 :         g_value_init(&(sink->priv->m_queuedProperties[property]), G_VALUE_TYPE(value));
     184            2 :         g_value_copy(value, &(sink->priv->m_queuedProperties[property]));
     185          425 :     }
     186          423 : }
     187              : 
     188            5 : static void rialto_mse_base_sink_get_property(GObject *object, guint propId, GValue *value, GParamSpec *pspec)
     189              : {
     190            5 :     switch (propId)
     191              :     {
     192            1 :     case PROP_IS_SINGLE_PATH_STREAM:
     193              :         // Set default value if it can't be acquired
     194            1 :         g_value_set_boolean(value, FALSE);
     195            1 :         rialto_mse_base_sink_handle_get_property(RIALTO_MSE_BASE_SINK(object),
     196            1 :                                                  IPlaybackDelegate::Property::IsSinglePathStream, value);
     197            1 :         break;
     198            1 :     case PROP_N_STREAMS:
     199              :         // Set default value if it can't be acquired
     200            1 :         g_value_set_int(value, 1);
     201            1 :         rialto_mse_base_sink_handle_get_property(RIALTO_MSE_BASE_SINK(object),
     202            1 :                                                  IPlaybackDelegate::Property::NumberOfStreams, value);
     203            1 :         break;
     204            1 :     case PROP_HAS_DRM:
     205              :         // Set default value if it can't be acquired
     206            1 :         g_value_set_boolean(value, TRUE);
     207            1 :         rialto_mse_base_sink_handle_get_property(RIALTO_MSE_BASE_SINK(object), IPlaybackDelegate::Property::HasDrm,
     208              :                                                  value);
     209            1 :         break;
     210            2 :     case PROP_STATS:
     211            2 :         rialto_mse_base_sink_handle_get_property(RIALTO_MSE_BASE_SINK(object), IPlaybackDelegate::Property::Stats, value);
     212            2 :         break;
     213            0 :     default:
     214            0 :         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
     215            0 :         break;
     216              :     }
     217            5 : }
     218              : 
     219          347 : static void rialto_mse_base_sink_set_property(GObject *object, guint propId, const GValue *value, GParamSpec *pspec)
     220              : {
     221          347 :     switch (propId)
     222              :     {
     223          173 :     case PROP_IS_SINGLE_PATH_STREAM:
     224          173 :         rialto_mse_base_sink_handle_set_property(RIALTO_MSE_BASE_SINK(object),
     225          173 :                                                  IPlaybackDelegate::Property::IsSinglePathStream, value);
     226          173 :         break;
     227          173 :     case PROP_N_STREAMS:
     228          173 :         rialto_mse_base_sink_handle_set_property(RIALTO_MSE_BASE_SINK(object),
     229          173 :                                                  IPlaybackDelegate::Property::NumberOfStreams, value);
     230          173 :         break;
     231            1 :     case PROP_HAS_DRM:
     232            1 :         rialto_mse_base_sink_handle_set_property(RIALTO_MSE_BASE_SINK(object), IPlaybackDelegate::Property::HasDrm,
     233              :                                                  value);
     234            1 :         break;
     235            0 :     default:
     236            0 :         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
     237            0 :         break;
     238              :     }
     239          347 : }
     240              : 
     241            1 : void rialto_mse_base_handle_rialto_server_sent_buffer_underflow(RialtoMSEBaseSink *sink)
     242              : {
     243            1 :     GST_WARNING_OBJECT(sink, "Sending underflow signal");
     244              :     // send 2 last parameters just to be compatible with RDK's buffer-underflow-callback signal signature
     245            1 :     g_signal_emit(G_OBJECT(sink), g_signals[SIGNAL_UNDERFLOW], 0, 0, nullptr);
     246              : }
     247              : 
     248          291 : bool rialto_mse_base_sink_initialise_sinkpad(RialtoMSEBaseSink *sink)
     249              : {
     250              :     GstPadTemplate *pad_template =
     251          291 :         gst_element_class_get_pad_template(GST_ELEMENT_CLASS(G_OBJECT_GET_CLASS(sink)), "sink");
     252          291 :     if (!pad_template)
     253              :     {
     254            0 :         GST_ERROR_OBJECT(sink, "Could not find sink pad template");
     255            0 :         return false;
     256              :     }
     257              : 
     258          291 :     GstPad *sinkPad = gst_pad_new_from_template(pad_template, "sink");
     259          291 :     if (!sinkPad)
     260              :     {
     261            0 :         GST_ERROR_OBJECT(sink, "Could not create sinkpad");
     262            0 :         return false;
     263              :     }
     264              : 
     265          291 :     gst_element_add_pad(GST_ELEMENT_CAST(sink), sinkPad);
     266          291 :     sink->priv->m_sinkPad = sinkPad;
     267              : 
     268          291 :     return true;
     269              : }
     270              : 
     271          291 : static void rialto_mse_base_sink_init(RialtoMSEBaseSink *sink)
     272              : {
     273          291 :     GST_INFO_OBJECT(sink, "Init: %" GST_PTR_FORMAT, sink);
     274          291 :     sink->priv = static_cast<RialtoMSEBaseSinkPrivate *>(rialto_mse_base_sink_get_instance_private(sink));
     275          291 :     new (sink->priv) RialtoMSEBaseSinkPrivate();
     276              : 
     277          291 :     GST_OBJECT_FLAG_SET(sink, GST_ELEMENT_FLAG_SINK);
     278              : }
     279              : 
     280          291 : static void rialto_mse_base_sink_finalize(GObject *object)
     281              : {
     282          291 :     RialtoMSEBaseSink *sink = RIALTO_MSE_BASE_SINK(object);
     283          291 :     RialtoMSEBaseSinkPrivate *priv = sink->priv;
     284          291 :     GST_INFO_OBJECT(sink, "Finalize: %" GST_PTR_FORMAT " %" GST_PTR_FORMAT, sink, priv);
     285              : 
     286          291 :     priv->~RialtoMSEBaseSinkPrivate();
     287          291 :     GST_CALL_PARENT(G_OBJECT_CLASS, finalize, (object));
     288              : }
     289              : 
     290            1 : static void rialto_mse_base_sink_class_init(RialtoMSEBaseSinkClass *klass)
     291              : {
     292              :     std::shared_ptr<firebolt::rialto::IClientLogHandler> logToGstHandler =
     293            1 :         std::make_shared<firebolt::rialto::LogToGstHandler>();
     294            1 :     if (!firebolt::rialto::IClientLogControlFactory::createFactory()->createClientLogControl().registerLogHandler(logToGstHandler,
     295              :                                                                                                                   true))
     296              :     {
     297            0 :         GST_ERROR("Unable to preRegister log handler");
     298              :     }
     299              : 
     300            1 :     GObjectClass *gobjectClass = G_OBJECT_CLASS(klass);
     301            1 :     GstElementClass *elementClass = GST_ELEMENT_CLASS(klass);
     302              : 
     303            1 :     gst_element_class_set_metadata(elementClass, "Rialto MSE base sink", "Generic", "A sink for Rialto", "Sky");
     304              : 
     305            1 :     gobjectClass->finalize = rialto_mse_base_sink_finalize;
     306            1 :     gobjectClass->get_property = rialto_mse_base_sink_get_property;
     307            1 :     gobjectClass->set_property = rialto_mse_base_sink_set_property;
     308            1 :     elementClass->query = rialto_mse_base_sink_query;
     309            1 :     elementClass->send_event = rialto_mse_base_sink_send_event;
     310            1 :     elementClass->change_state = rialto_mse_base_sink_change_state;
     311              : 
     312            1 :     g_signals[SIGNAL_UNDERFLOW] = g_signal_new("buffer-underflow-callback", G_TYPE_FROM_CLASS(klass),
     313              :                                                (GSignalFlags)(G_SIGNAL_RUN_LAST), 0, nullptr, nullptr,
     314              :                                                g_cclosure_marshal_VOID__UINT_POINTER, G_TYPE_NONE, 2, G_TYPE_UINT,
     315              :                                                G_TYPE_POINTER);
     316              : 
     317            1 :     g_object_class_install_property(gobjectClass, PROP_IS_SINGLE_PATH_STREAM,
     318              :                                     g_param_spec_boolean("single-path-stream", "single path stream",
     319              :                                                          "is single path stream", FALSE, GParamFlags(G_PARAM_READWRITE)));
     320              : 
     321            1 :     g_object_class_install_property(gobjectClass, PROP_N_STREAMS,
     322              :                                     g_param_spec_int("streams-number", "streams number", "streams number", 1, G_MAXINT,
     323              :                                                      1, GParamFlags(G_PARAM_READWRITE)));
     324              : 
     325            1 :     g_object_class_install_property(gobjectClass, PROP_HAS_DRM,
     326              :                                     g_param_spec_boolean("has-drm", "has drm", "has drm", TRUE,
     327              :                                                          GParamFlags(G_PARAM_READWRITE)));
     328            1 :     g_object_class_install_property(gobjectClass, PROP_STATS,
     329              :                                     g_param_spec_pointer("stats", NULL, "pointer to a gst_structure",
     330              :                                                          GParamFlags(G_PARAM_READABLE)));
     331              : }
        

Generated by: LCOV version 2.0-1