LCOV - code coverage report
Current view: top level - source - RialtoGStreamerMSEAudioSink.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 97.3 % 148 144
Test Date: 2025-08-04 11:40:41 Functions: 100.0 % 6 6

            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              : #include <mutex>
      19              : 
      20              : #include <gst/audio/audio.h>
      21              : #include <gst/gst.h>
      22              : 
      23              : #include "GStreamerMSEUtils.h"
      24              : #include "IMediaPipelineCapabilities.h"
      25              : #include "PullModeAudioPlaybackDelegate.h"
      26              : #include "RialtoGStreamerMSEAudioSink.h"
      27              : #include "RialtoGStreamerMSEBaseSinkPrivate.h"
      28              : 
      29              : using namespace firebolt::rialto::client;
      30              : 
      31              : GST_DEBUG_CATEGORY_STATIC(RialtoMSEAudioSinkDebug);
      32              : #define GST_CAT_DEFAULT RialtoMSEAudioSinkDebug
      33              : 
      34              : #define rialto_mse_audio_sink_parent_class parent_class
      35          591 : G_DEFINE_TYPE_WITH_CODE(RialtoMSEAudioSink, rialto_mse_audio_sink, RIALTO_TYPE_MSE_BASE_SINK,
      36              :                         G_IMPLEMENT_INTERFACE(GST_TYPE_STREAM_VOLUME, NULL)
      37              :                             GST_DEBUG_CATEGORY_INIT(RialtoMSEAudioSinkDebug, "rialtomseaudiosink", 0,
      38              :                                                     "rialto mse audio sink"));
      39              : 
      40              : enum
      41              : {
      42              :     PROP_0,
      43              :     PROP_VOLUME,
      44              :     PROP_MUTE,
      45              :     PROP_GAP,
      46              :     PROP_LOW_LATENCY,
      47              :     PROP_SYNC,
      48              :     PROP_SYNC_OFF,
      49              :     PROP_STREAM_SYNC_MODE,
      50              :     PROP_AUDIO_FADE,
      51              :     PROP_FADE_VOLUME,
      52              :     PROP_LIMIT_BUFFERING_MS,
      53              :     PROP_USE_BUFFERING,
      54              :     PROP_ASYNC,
      55              :     PROP_LAST
      56              : };
      57              : 
      58          588 : static GstStateChangeReturn rialto_mse_audio_sink_change_state(GstElement *element, GstStateChange transition)
      59              : {
      60          588 :     RialtoMSEAudioSink *sink = RIALTO_MSE_AUDIO_SINK(element);
      61          588 :     if (GST_STATE_CHANGE_NULL_TO_READY == transition)
      62              :     {
      63          185 :         GST_INFO_OBJECT(sink, "RialtoMSEAudioSink state change to READY. Initializing delegate");
      64          185 :         rialto_mse_base_sink_initialise_delegate(RIALTO_MSE_BASE_SINK(sink),
      65          370 :                                                  std::make_shared<PullModeAudioPlaybackDelegate>(element));
      66              :     }
      67              : 
      68          588 :     GstStateChangeReturn result = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
      69          588 :     if (G_UNLIKELY(result == GST_STATE_CHANGE_FAILURE))
      70              :     {
      71            2 :         GST_WARNING_OBJECT(sink, "State change failed");
      72            2 :         return result;
      73              :     }
      74              : 
      75          586 :     return result;
      76              : }
      77              : 
      78           26 : static void rialto_mse_audio_sink_get_property(GObject *object, guint propId, GValue *value, GParamSpec *pspec)
      79              : {
      80           26 :     switch (propId)
      81              :     {
      82            5 :     case PROP_VOLUME:
      83              :     {
      84            5 :         g_value_set_double(value, kDefaultVolume);
      85            5 :         rialto_mse_base_sink_handle_get_property(RIALTO_MSE_BASE_SINK(object), IPlaybackDelegate::Property::Volume,
      86              :                                                  value);
      87            5 :         break;
      88              :     }
      89            3 :     case PROP_MUTE:
      90              :     {
      91            3 :         g_value_set_boolean(value, kDefaultMute);
      92            3 :         rialto_mse_base_sink_handle_get_property(RIALTO_MSE_BASE_SINK(object), IPlaybackDelegate::Property::Mute, value);
      93            3 :         break;
      94              :     }
      95            4 :     case PROP_SYNC:
      96              :     {
      97            4 :         g_value_set_boolean(value, kDefaultSync);
      98            4 :         rialto_mse_base_sink_handle_get_property(RIALTO_MSE_BASE_SINK(object), IPlaybackDelegate::Property::Sync, value);
      99            4 :         break;
     100              :     }
     101            4 :     case PROP_STREAM_SYNC_MODE:
     102              :     {
     103            4 :         g_value_set_int(value, kDefaultStreamSyncMode);
     104            4 :         rialto_mse_base_sink_handle_get_property(RIALTO_MSE_BASE_SINK(object),
     105            4 :                                                  IPlaybackDelegate::Property::StreamSyncMode, value);
     106            4 :         break;
     107              :     }
     108            2 :     case PROP_FADE_VOLUME:
     109              :     {
     110            2 :         g_value_set_uint(value, kDefaultFadeVolume);
     111            2 :         rialto_mse_base_sink_handle_get_property(RIALTO_MSE_BASE_SINK(object), IPlaybackDelegate::Property::FadeVolume,
     112              :                                                  value);
     113            2 :         break;
     114              :     }
     115            3 :     case PROP_LIMIT_BUFFERING_MS:
     116              :     {
     117            3 :         g_value_set_uint(value, kDefaultBufferingLimit);
     118            3 :         rialto_mse_base_sink_handle_get_property(RIALTO_MSE_BASE_SINK(object),
     119            3 :                                                  IPlaybackDelegate::Property::LimitBufferingMs, value);
     120            3 :         break;
     121              :     }
     122            3 :     case PROP_USE_BUFFERING:
     123              :     {
     124            3 :         g_value_set_boolean(value, kDefaultUseBuffering);
     125            3 :         rialto_mse_base_sink_handle_get_property(RIALTO_MSE_BASE_SINK(object),
     126            3 :                                                  IPlaybackDelegate::Property::UseBuffering, value);
     127            3 :         break;
     128              :     }
     129            1 :     case PROP_ASYNC:
     130              :     {
     131            1 :         g_value_set_boolean(value, TRUE);
     132            1 :         rialto_mse_base_sink_handle_get_property(RIALTO_MSE_BASE_SINK(object), IPlaybackDelegate::Property::Async, value);
     133            1 :         break;
     134              :     }
     135            1 :     default:
     136              :     {
     137            1 :         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
     138            1 :         break;
     139              :     }
     140              :     }
     141           26 : }
     142              : 
     143           40 : static void rialto_mse_audio_sink_set_property(GObject *object, guint propId, const GValue *value, GParamSpec *pspec)
     144              : {
     145           40 :     switch (propId)
     146              :     {
     147            3 :     case PROP_VOLUME:
     148              :     {
     149            3 :         rialto_mse_base_sink_handle_set_property(RIALTO_MSE_BASE_SINK(object), IPlaybackDelegate::Property::Volume,
     150              :                                                  value);
     151            3 :         break;
     152              :     }
     153            3 :     case PROP_MUTE:
     154              :     {
     155            3 :         rialto_mse_base_sink_handle_set_property(RIALTO_MSE_BASE_SINK(object), IPlaybackDelegate::Property::Mute, value);
     156            3 :         break;
     157              :     }
     158            2 :     case PROP_GAP:
     159              :     {
     160            2 :         rialto_mse_base_sink_handle_set_property(RIALTO_MSE_BASE_SINK(object), IPlaybackDelegate::Property::Gap, value);
     161            2 :         break;
     162              :     }
     163            5 :     case PROP_LOW_LATENCY:
     164              :     {
     165            5 :         rialto_mse_base_sink_handle_set_property(RIALTO_MSE_BASE_SINK(object), IPlaybackDelegate::Property::LowLatency,
     166              :                                                  value);
     167            5 :         break;
     168              :     }
     169            5 :     case PROP_SYNC:
     170              :     {
     171            5 :         rialto_mse_base_sink_handle_set_property(RIALTO_MSE_BASE_SINK(object), IPlaybackDelegate::Property::Sync, value);
     172            5 :         break;
     173              :     }
     174            5 :     case PROP_SYNC_OFF:
     175              :     {
     176            5 :         rialto_mse_base_sink_handle_set_property(RIALTO_MSE_BASE_SINK(object), IPlaybackDelegate::Property::SyncOff,
     177              :                                                  value);
     178            5 :         break;
     179              :     }
     180            5 :     case PROP_STREAM_SYNC_MODE:
     181              :     {
     182            5 :         rialto_mse_base_sink_handle_set_property(RIALTO_MSE_BASE_SINK(object),
     183            5 :                                                  IPlaybackDelegate::Property::StreamSyncMode, value);
     184            5 :         break;
     185              :     }
     186            4 :     case PROP_AUDIO_FADE:
     187              :     {
     188            4 :         rialto_mse_base_sink_handle_set_property(RIALTO_MSE_BASE_SINK(object), IPlaybackDelegate::Property::AudioFade,
     189              :                                                  value);
     190            4 :         break;
     191              :     }
     192            3 :     case PROP_LIMIT_BUFFERING_MS:
     193              :     {
     194            3 :         rialto_mse_base_sink_handle_set_property(RIALTO_MSE_BASE_SINK(object),
     195            3 :                                                  IPlaybackDelegate::Property::LimitBufferingMs, value);
     196            3 :         break;
     197              :     }
     198            3 :     case PROP_USE_BUFFERING:
     199              :     {
     200            3 :         rialto_mse_base_sink_handle_set_property(RIALTO_MSE_BASE_SINK(object),
     201            3 :                                                  IPlaybackDelegate::Property::UseBuffering, value);
     202            3 :         break;
     203              :     }
     204            1 :     case PROP_ASYNC:
     205              :     {
     206            1 :         rialto_mse_base_sink_handle_set_property(RIALTO_MSE_BASE_SINK(object), IPlaybackDelegate::Property::Async, value);
     207            1 :         break;
     208              :     }
     209            1 :     default:
     210              :     {
     211            1 :         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
     212            1 :         break;
     213              :     }
     214              :     }
     215           40 : }
     216              : 
     217          188 : static void rialto_mse_audio_sink_init(RialtoMSEAudioSink *sink)
     218              : {
     219          188 :     RialtoMSEBaseSinkPrivate *priv = sink->parent.priv;
     220              : 
     221          188 :     if (!rialto_mse_base_sink_initialise_sinkpad(RIALTO_MSE_BASE_SINK(sink)))
     222              :     {
     223            0 :         GST_ERROR_OBJECT(sink, "Failed to initialise AUDIO sink. Sink pad initialisation failed.");
     224            0 :         return;
     225              :     }
     226              : 
     227          188 :     gst_pad_set_chain_function(priv->m_sinkPad, rialto_mse_base_sink_chain);
     228          188 :     gst_pad_set_event_function(priv->m_sinkPad, rialto_mse_base_sink_event);
     229              : }
     230              : 
     231            1 : static void rialto_mse_audio_sink_class_init(RialtoMSEAudioSinkClass *klass)
     232              : {
     233            1 :     GObjectClass *gobjectClass = G_OBJECT_CLASS(klass);
     234            1 :     GstElementClass *elementClass = GST_ELEMENT_CLASS(klass);
     235            1 :     gobjectClass->get_property = rialto_mse_audio_sink_get_property;
     236            1 :     gobjectClass->set_property = rialto_mse_audio_sink_set_property;
     237            1 :     elementClass->change_state = rialto_mse_audio_sink_change_state;
     238              : 
     239            1 :     g_object_class_install_property(gobjectClass, PROP_VOLUME,
     240              :                                     g_param_spec_double("volume", "Volume", "Volume of this stream", 0, 1.0,
     241              :                                                         kDefaultVolume,
     242              :                                                         GParamFlags(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
     243              : 
     244            1 :     g_object_class_install_property(gobjectClass, PROP_MUTE,
     245              :                                     g_param_spec_boolean("mute", "Mute", "Mute status of this stream", kDefaultMute,
     246              :                                                          GParamFlags(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
     247              : 
     248            1 :     g_object_class_install_property(gobjectClass, PROP_GAP,
     249              :                                     g_param_spec_boxed("gap", "Gap", "Audio Gap", GST_TYPE_STRUCTURE,
     250              :                                                        (GParamFlags)(G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)));
     251              : 
     252            1 :     g_object_class_install_property(gobjectClass, PROP_USE_BUFFERING,
     253              :                                     g_param_spec_boolean("use-buffering",
     254              :                                                          "Use buffering", "Emit GST_MESSAGE_BUFFERING based on low-/high-percent thresholds",
     255              :                                                          kDefaultUseBuffering, G_PARAM_READWRITE));
     256            1 :     g_object_class_install_property(gobjectClass, PROP_ASYNC,
     257              :                                     g_param_spec_boolean("async", "Async", "Asynchronous mode", FALSE, G_PARAM_READWRITE));
     258              : 
     259              :     std::unique_ptr<firebolt::rialto::IMediaPipelineCapabilities> mediaPlayerCapabilities =
     260            1 :         firebolt::rialto::IMediaPipelineCapabilitiesFactory::createFactory()->createMediaPipelineCapabilities();
     261            1 :     if (mediaPlayerCapabilities)
     262              :     {
     263              :         std::vector<std::string> supportedMimeTypes =
     264            1 :             mediaPlayerCapabilities->getSupportedMimeTypes(firebolt::rialto::MediaSourceType::AUDIO);
     265              : 
     266            1 :         rialto_mse_sink_setup_supported_caps(elementClass, supportedMimeTypes);
     267              : 
     268            2 :         const std::string kLowLatencyPropertyName{"low-latency"};
     269            2 :         const std::string kSyncPropertyName{"sync"};
     270            2 :         const std::string kSyncOffPropertyName{"sync-off"};
     271            2 :         const std::string kStreamSyncModePropertyName{"stream-sync-mode"};
     272            2 :         const std::string kAudioFadePropertyName{"audio-fade"};
     273            2 :         const std::string kFadeVolumePropertyName{"fade-volume"};
     274            1 :         const std::string kBufferingLimitPropertyName{"limit-buffering-ms"};
     275              :         const std::vector<std::string> kPropertyNamesToSearch{kLowLatencyPropertyName,     kSyncPropertyName,
     276              :                                                               kSyncOffPropertyName,        kStreamSyncModePropertyName,
     277              :                                                               kBufferingLimitPropertyName, kAudioFadePropertyName,
     278            9 :                                                               kFadeVolumePropertyName};
     279              :         std::vector<std::string> supportedProperties{
     280            1 :             mediaPlayerCapabilities->getSupportedProperties(firebolt::rialto::MediaSourceType::AUDIO,
     281            1 :                                                             kPropertyNamesToSearch)};
     282              : 
     283            8 :         for (auto it = supportedProperties.begin(); it != supportedProperties.end(); ++it)
     284              :         {
     285            7 :             if (kLowLatencyPropertyName == *it)
     286              :             {
     287            1 :                 g_object_class_install_property(gobjectClass, PROP_LOW_LATENCY,
     288              :                                                 g_param_spec_boolean(kLowLatencyPropertyName.c_str(),
     289              :                                                                      "low latency", "Turn on low latency mode, for use with gaming (no audio decoding, no a/v sync)",
     290              :                                                                      kDefaultLowLatency, GParamFlags(G_PARAM_WRITABLE)));
     291              :             }
     292            6 :             else if (kSyncPropertyName == *it)
     293              :             {
     294            1 :                 g_object_class_install_property(gobjectClass, PROP_SYNC,
     295              :                                                 g_param_spec_boolean(kSyncPropertyName.c_str(), "sync", "Clock sync",
     296              :                                                                      kDefaultSync, GParamFlags(G_PARAM_READWRITE)));
     297              :             }
     298            5 :             else if (kSyncOffPropertyName == *it)
     299              :             {
     300            1 :                 g_object_class_install_property(gobjectClass, PROP_SYNC_OFF,
     301              :                                                 g_param_spec_boolean(kSyncOffPropertyName.c_str(),
     302              :                                                                      "sync off", "Turn on free running audio. Must be set before pipeline is PLAYING state.",
     303              :                                                                      kDefaultSyncOff, GParamFlags(G_PARAM_WRITABLE)));
     304              :             }
     305            4 :             else if (kStreamSyncModePropertyName == *it)
     306              :             {
     307            1 :                 g_object_class_install_property(gobjectClass, PROP_STREAM_SYNC_MODE,
     308              :                                                 g_param_spec_int(kStreamSyncModePropertyName.c_str(),
     309              :                                                                  "stream sync mode", "1 - Frame to decode frame will immediately proceed next frame sync, 0 - Frame decoded with no frame sync",
     310              :                                                                  0, G_MAXINT, kDefaultStreamSyncMode,
     311              :                                                                  GParamFlags(G_PARAM_READWRITE)));
     312              :             }
     313            3 :             else if (kAudioFadePropertyName == *it)
     314              :             {
     315            1 :                 g_object_class_install_property(gobjectClass, PROP_AUDIO_FADE,
     316              :                                                 g_param_spec_string(kAudioFadePropertyName.c_str(),
     317              :                                                                     "audio fade", "Start audio fade (vol[0-100],duration ms,easetype[(L)inear,Cubic(I)n,Cubic(O)ut])",
     318              :                                                                     kDefaultAudioFade, GParamFlags(G_PARAM_WRITABLE)));
     319              :             }
     320            2 :             else if (kFadeVolumePropertyName == *it)
     321              :             {
     322            1 :                 g_object_class_install_property(gobjectClass, PROP_FADE_VOLUME,
     323              :                                                 g_param_spec_uint(kFadeVolumePropertyName.c_str(), "fade volume",
     324              :                                                                   "Get current fade volume", 0, 100, kDefaultFadeVolume,
     325              :                                                                   G_PARAM_READABLE));
     326              :             }
     327            1 :             else if (kBufferingLimitPropertyName == *it)
     328              :             {
     329            1 :                 constexpr uint32_t kMaxValue{20000};
     330            1 :                 g_object_class_install_property(gobjectClass, PROP_LIMIT_BUFFERING_MS,
     331              :                                                 g_param_spec_uint("limit-buffering-ms",
     332              :                                                                   "limit buffering ms", "Set millisecond threshold used if limit_buffering is set. Changing this value does not enable/disable limit_buffering",
     333              :                                                                   0, kMaxValue, kDefaultBufferingLimit,
     334              :                                                                   G_PARAM_READWRITE));
     335              :             }
     336              :             else
     337              :             {
     338            0 :                 GST_ERROR("Unexpected property %s returned from rialto", it->c_str());
     339              :             }
     340              :         }
     341            1 :     }
     342              :     else
     343              :     {
     344            0 :         GST_ERROR("Failed to get supported mime types for AUDIO");
     345              :     }
     346              : 
     347            1 :     gst_element_class_set_details_simple(elementClass, "Rialto Audio Sink", "Decoder/Audio/Sink/Audio",
     348              :                                          "Communicates with Rialto Server", "Sky");
     349            2 : }
        

Generated by: LCOV version 2.0-1