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

Generated by: LCOV version 2.0-1