LCOV - code coverage report
Current view: top level - source - PullModeAudioPlaybackDelegate.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 97.5 % 403 393
Test Date: 2026-06-10 12:08:30 Functions: 100.0 % 8 8

            Line data    Source code
       1              : /*
       2              :  * Copyright (C) 2025 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 "PullModeAudioPlaybackDelegate.h"
      20              : #include "GStreamerMSEUtils.h"
      21              : #include "GstreamerCatLog.h"
      22              : #include <gst/audio/audio.h>
      23              : #include <gst/gst.h>
      24              : #include <gst/pbutils/pbutils.h>
      25              : 
      26              : #define GST_CAT_DEFAULT rialtoGStreamerCat
      27              : 
      28              : namespace
      29              : {
      30            3 : firebolt::rialto::EaseType convertCharToEaseType(char easeTypeChar)
      31              : {
      32            3 :     switch (easeTypeChar)
      33              :     {
      34            1 :     case 'L':
      35            1 :         return firebolt::rialto::EaseType::EASE_LINEAR;
      36            1 :     case 'I':
      37            1 :         return firebolt::rialto::EaseType::EASE_IN_CUBIC;
      38            1 :     case 'O':
      39            1 :         return firebolt::rialto::EaseType::EASE_OUT_CUBIC;
      40            0 :     default:
      41            0 :         return firebolt::rialto::EaseType::EASE_LINEAR;
      42              :     }
      43              : }
      44              : } // namespace
      45              : 
      46          203 : PullModeAudioPlaybackDelegate::PullModeAudioPlaybackDelegate(GstElement *sink) : PullModePlaybackDelegate(sink)
      47              : {
      48          203 :     m_mediaSourceType = firebolt::rialto::MediaSourceType::AUDIO;
      49              : }
      50              : 
      51          650 : GstStateChangeReturn PullModeAudioPlaybackDelegate::changeState(GstStateChange transition)
      52              : {
      53          650 :     switch (transition)
      54              :     {
      55          115 :     case GST_STATE_CHANGE_READY_TO_PAUSED:
      56              :     {
      57          115 :         if (!attachToMediaClientAndSetStreamsNumber())
      58              :         {
      59            2 :             return GST_STATE_CHANGE_FAILURE;
      60              :         }
      61              : 
      62          113 :         std::shared_ptr<GStreamerMSEMediaPlayerClient> client = m_mediaPlayerManager.getMediaPlayerClient();
      63          113 :         if (!client)
      64              :         {
      65            0 :             GST_ERROR_OBJECT(m_sink, "MediaPlayerClient is nullptr");
      66            0 :             return GST_STATE_CHANGE_FAILURE;
      67              :         }
      68          113 :         if (m_isVolumeQueued)
      69              :         {
      70            1 :             client->setVolume(m_targetVolume, kDefaultVolumeDuration, kDefaultEaseType);
      71            1 :             m_isVolumeQueued = false;
      72              :         }
      73          113 :         if (m_isAudioFadeQueued)
      74              :         {
      75              :             AudioFadeConfig audioFadeConfig;
      76              :             {
      77            1 :                 std::lock_guard<std::mutex> lock(m_audioFadeConfigMutex);
      78            1 :                 audioFadeConfig = m_audioFadeConfig;
      79              :             }
      80            1 :             client->setVolume(audioFadeConfig.volume, audioFadeConfig.duration, audioFadeConfig.easeType);
      81            1 :             m_isAudioFadeQueued = false;
      82              :         }
      83          113 :         break;
      84              :     }
      85          535 :     default:
      86          535 :         break;
      87              :     }
      88          648 :     return PullModePlaybackDelegate::changeState(transition);
      89              : }
      90              : 
      91          158 : gboolean PullModeAudioPlaybackDelegate::handleEvent(GstPad *pad, GstObject *parent, GstEvent *event)
      92              : {
      93          158 :     switch (GST_EVENT_TYPE(event))
      94              :     {
      95          109 :     case GST_EVENT_CAPS:
      96              :     {
      97          109 :         GstCaps *caps{nullptr};
      98          109 :         gst_event_parse_caps(event, &caps);
      99          109 :         if (m_sourceAttached)
     100              :         {
     101            2 :             GST_INFO_OBJECT(m_sink, "Source already attached. Skip calling attachSource");
     102            2 :             break;
     103              :         }
     104              : 
     105          107 :         GST_INFO_OBJECT(m_sink, "Attaching AUDIO source with caps %" GST_PTR_FORMAT, caps);
     106              : 
     107          107 :         std::unique_ptr<firebolt::rialto::IMediaPipeline::MediaSource> asource = createMediaSource(caps);
     108          107 :         if (asource)
     109              :         {
     110          106 :             std::shared_ptr<GStreamerMSEMediaPlayerClient> client = m_mediaPlayerManager.getMediaPlayerClient();
     111          211 :             if ((!client) || (!client->attachSource(asource, RIALTO_MSE_BASE_SINK(m_sink),
     112          211 :                                                     PullModePlaybackDelegate::shared_from_this())))
     113              :             {
     114            1 :                 GST_ERROR_OBJECT(m_sink, "Failed to attach AUDIO source");
     115              :             }
     116              :             else
     117              :             {
     118          105 :                 m_sourceAttached = true;
     119              : 
     120          105 :                 if (m_isMuteQueued)
     121              :                 {
     122            1 :                     client->setMute(m_mute, m_sourceId);
     123            1 :                     m_isMuteQueued = false;
     124              :                 }
     125          105 :                 if (m_isLowLatencyQueued)
     126              :                 {
     127            2 :                     if (!client->setLowLatency(m_lowLatency))
     128              :                     {
     129            1 :                         GST_ERROR_OBJECT(m_sink, "Could not set queued low-latency");
     130              :                     }
     131            2 :                     m_isLowLatencyQueued = false;
     132              :                 }
     133          105 :                 if (m_isSyncQueued)
     134              :                 {
     135            2 :                     if (!client->setSync(m_sync))
     136              :                     {
     137            1 :                         GST_ERROR_OBJECT(m_sink, "Could not set queued sync");
     138              :                     }
     139            2 :                     m_isSyncQueued = false;
     140              :                 }
     141          105 :                 if (m_isSyncOffQueued)
     142              :                 {
     143            2 :                     if (!client->setSyncOff(m_syncOff))
     144              :                     {
     145            1 :                         GST_ERROR_OBJECT(m_sink, "Could not set queued sync-off");
     146              :                     }
     147            2 :                     m_isSyncOffQueued = false;
     148              :                 }
     149          105 :                 if (m_isStreamSyncModeQueued)
     150              :                 {
     151            2 :                     if (!client->setStreamSyncMode(m_sourceId, m_streamSyncMode))
     152              :                     {
     153            1 :                         GST_ERROR_OBJECT(m_sink, "Could not set queued stream-sync-mode");
     154              :                     }
     155            2 :                     m_isStreamSyncModeQueued = false;
     156              :                 }
     157          105 :                 if (m_isBufferingLimitQueued)
     158              :                 {
     159            1 :                     client->setBufferingLimit(m_bufferingLimit);
     160            1 :                     m_isBufferingLimitQueued = false;
     161              :                 }
     162          105 :                 if (m_isUseBufferingQueued)
     163              :                 {
     164            1 :                     client->setUseBuffering(m_useBuffering);
     165            1 :                     m_isUseBufferingQueued = false;
     166              :                 }
     167              :                 // check if READY -> PAUSED was requested before source was attached
     168          105 :                 if (GST_STATE_NEXT(m_sink) == GST_STATE_PAUSED)
     169              :                 {
     170          105 :                     client->pause(m_sourceId);
     171              :                 }
     172              :             }
     173          106 :         }
     174              :         else
     175              :         {
     176            1 :             GST_ERROR_OBJECT(m_sink, "Failed to create AUDIO source");
     177              :         }
     178          107 :         break;
     179              :     }
     180            6 :     case GST_EVENT_CUSTOM_DOWNSTREAM:
     181              :     case GST_EVENT_CUSTOM_DOWNSTREAM_OOB:
     182              :     {
     183            6 :         if (gst_event_has_name(event, "switch-source"))
     184              :         {
     185            4 :             GST_DEBUG_OBJECT(m_sink, "Switch source event received");
     186            4 :             const GstStructure *structure{gst_event_get_structure(event)};
     187            4 :             const GValue *value = gst_structure_get_value(structure, "caps");
     188            4 :             if (!value)
     189              :             {
     190            1 :                 GST_ERROR_OBJECT(m_sink, "Caps not available in switch-source event");
     191            2 :                 break;
     192              :             }
     193            3 :             const GstCaps *caps = gst_value_get_caps(value);
     194            3 :             GstCaps *mutableCaps = gst_caps_copy(caps);
     195            3 :             std::unique_ptr<firebolt::rialto::IMediaPipeline::MediaSource> asource = createMediaSource(mutableCaps);
     196            3 :             gst_caps_unref(mutableCaps);
     197            3 :             if (!asource)
     198              :             {
     199            1 :                 GST_ERROR_OBJECT(m_sink, "Not able to parse caps");
     200            1 :                 break;
     201              :             }
     202            2 :             std::shared_ptr<GStreamerMSEMediaPlayerClient> client = m_mediaPlayerManager.getMediaPlayerClient();
     203            2 :             if ((!client) || (!client->switchSource(asource)))
     204              :             {
     205            1 :                 GST_ERROR_OBJECT(m_sink, "Failed to switch AUDIO source");
     206              :             }
     207            3 :         }
     208            4 :         break;
     209              :     }
     210           43 :     default:
     211           43 :         break;
     212              :     }
     213          158 :     return PullModePlaybackDelegate::handleEvent(pad, parent, event);
     214              : }
     215              : 
     216           34 : void PullModeAudioPlaybackDelegate::getProperty(const Property &type, GValue *value)
     217              : {
     218           34 :     std::shared_ptr<GStreamerMSEMediaPlayerClient> client{m_mediaPlayerManager.getMediaPlayerClient()};
     219              : 
     220           34 :     switch (type)
     221              :     {
     222            3 :     case IPlaybackDelegate::Property::Volume:
     223              :     {
     224            3 :         double volume{1.0};
     225            3 :         if (client)
     226              :         {
     227            1 :             if (client->getCachedVolume(volume))
     228            1 :                 m_targetVolume = volume;
     229              :             else
     230            0 :                 volume = m_targetVolume; // Use last known volume
     231              :         }
     232              :         else
     233              :         {
     234            2 :             volume = m_targetVolume;
     235              :         }
     236            3 :         g_value_set_double(value, volume);
     237            3 :         break;
     238              :     }
     239            3 :     case IPlaybackDelegate::Property::Mute:
     240              :     {
     241            3 :         if (!client)
     242              :         {
     243            2 :             g_value_set_boolean(value, m_mute);
     244            2 :             return;
     245              :         }
     246            1 :         g_value_set_boolean(value, client->getMute(m_sourceId));
     247            1 :         break;
     248              :     }
     249            4 :     case IPlaybackDelegate::Property::Sync:
     250              :     {
     251            4 :         if (!client)
     252              :         {
     253            2 :             g_value_set_boolean(value, m_sync);
     254            2 :             return;
     255              :         }
     256              : 
     257            2 :         bool sync{kDefaultSync};
     258            2 :         if (!client->getSync(sync))
     259              :         {
     260            1 :             GST_ERROR_OBJECT(m_sink, "Could not get sync");
     261              :         }
     262            2 :         g_value_set_boolean(value, sync);
     263            2 :         break;
     264              :     }
     265            4 :     case IPlaybackDelegate::Property::StreamSyncMode:
     266              :     {
     267            4 :         if (!client)
     268              :         {
     269            2 :             g_value_set_int(value, m_streamSyncMode);
     270            2 :             return;
     271              :         }
     272              : 
     273            2 :         int32_t streamSyncMode{kDefaultStreamSyncMode};
     274            2 :         if (!client->getStreamSyncMode(streamSyncMode))
     275              :         {
     276            1 :             GST_ERROR_OBJECT(m_sink, "Could not get stream-sync-mode");
     277              :         }
     278            2 :         g_value_set_int(value, streamSyncMode);
     279            2 :         break;
     280              :     }
     281            2 :     case IPlaybackDelegate::Property::FadeVolume:
     282              :     {
     283            2 :         double volume{};
     284            2 :         if (!client || !client->getVolume(volume))
     285              :         {
     286            1 :             g_value_set_uint(value, kDefaultFadeVolume);
     287            1 :             return;
     288              :         }
     289            1 :         g_value_set_uint(value, static_cast<uint32_t>(volume * 100.0));
     290            1 :         break;
     291              :     }
     292            3 :     case IPlaybackDelegate::Property::LimitBufferingMs:
     293              :     {
     294            3 :         if (!client)
     295              :         {
     296            2 :             g_value_set_uint(value, m_bufferingLimit);
     297            2 :             return;
     298              :         }
     299            1 :         g_value_set_uint(value, client->getBufferingLimit());
     300            1 :         break;
     301              :     }
     302            3 :     case IPlaybackDelegate::Property::UseBuffering:
     303              :     {
     304            3 :         if (!client)
     305              :         {
     306            2 :             g_value_set_boolean(value, m_useBuffering);
     307            2 :             return;
     308              :         }
     309            1 :         g_value_set_boolean(value, client->getUseBuffering());
     310            1 :         break;
     311              :     }
     312            1 :     case IPlaybackDelegate::Property::Async:
     313              :     {
     314              :         // Rialto MSE Audio sink is always async
     315            1 :         g_value_set_boolean(value, TRUE);
     316            1 :         break;
     317              :     }
     318           11 :     default:
     319              :     {
     320           11 :         PullModePlaybackDelegate::getProperty(type, value);
     321           11 :         break;
     322              :     }
     323              :     }
     324           34 : }
     325              : 
     326          281 : void PullModeAudioPlaybackDelegate::setProperty(const Property &type, const GValue *value)
     327              : {
     328          281 :     std::shared_ptr<GStreamerMSEMediaPlayerClient> client = m_mediaPlayerManager.getMediaPlayerClient();
     329              : 
     330          281 :     switch (type)
     331              :     {
     332            3 :     case IPlaybackDelegate::Property::Volume:
     333              :     {
     334            3 :         m_targetVolume = g_value_get_double(value);
     335            3 :         if (!client || !m_sourceAttached)
     336              :         {
     337            2 :             GST_DEBUG_OBJECT(m_sink, "Enqueue volume setting");
     338            2 :             m_isVolumeQueued = true;
     339            2 :             return;
     340              :         }
     341            1 :         client->setVolume(m_targetVolume, kDefaultVolumeDuration, kDefaultEaseType);
     342            1 :         break;
     343              :     }
     344            3 :     case IPlaybackDelegate::Property::Mute:
     345              :     {
     346            3 :         m_mute = g_value_get_boolean(value);
     347            3 :         if (!client || !m_sourceAttached)
     348              :         {
     349            2 :             GST_DEBUG_OBJECT(m_sink, "Enqueue mute setting");
     350            2 :             m_isMuteQueued = true;
     351            2 :             return;
     352              :         }
     353            1 :         client->setMute(m_mute, m_sourceId);
     354            1 :         break;
     355              :     }
     356            2 :     case IPlaybackDelegate::Property::Gap:
     357              :     {
     358            2 :         gint64 position{0}, discontinuityGap{0};
     359            2 :         guint duration{0};
     360            2 :         gboolean audioAac{FALSE};
     361              : 
     362            2 :         GstStructure *gapData = GST_STRUCTURE_CAST(g_value_get_boxed(value));
     363            2 :         if (!gst_structure_get_int64(gapData, "position", &position))
     364              :         {
     365            1 :             GST_WARNING_OBJECT(m_sink, "Set gap: position is missing!");
     366              :         }
     367            2 :         if (!gst_structure_get_uint(gapData, "duration", &duration))
     368              :         {
     369            1 :             GST_WARNING_OBJECT(m_sink, "Set gap: duration is missing!");
     370              :         }
     371            2 :         if (!gst_structure_get_int64(gapData, "discontinuity-gap", &discontinuityGap))
     372              :         {
     373            1 :             GST_WARNING_OBJECT(m_sink, "Set gap: discontinuity gap is missing!");
     374              :         }
     375            2 :         if (!gst_structure_get_boolean(gapData, "audio-aac", &audioAac))
     376              :         {
     377            1 :             GST_WARNING_OBJECT(m_sink, "Set gap: audio aac is missing!");
     378              :         }
     379              : 
     380            2 :         GST_DEBUG_OBJECT(m_sink, "Processing audio gap.");
     381            2 :         client->processAudioGap(position, duration, discontinuityGap, audioAac);
     382            2 :         break;
     383              :     }
     384            5 :     case IPlaybackDelegate::Property::LowLatency:
     385              :     {
     386            5 :         m_lowLatency = g_value_get_boolean(value);
     387            5 :         if (!client)
     388              :         {
     389            3 :             GST_DEBUG_OBJECT(m_sink, "Enqueue low latency setting");
     390            3 :             m_isLowLatencyQueued = true;
     391            3 :             return;
     392              :         }
     393              : 
     394            2 :         if (!client->setLowLatency(m_lowLatency))
     395              :         {
     396            1 :             GST_ERROR_OBJECT(m_sink, "Could not set low-latency");
     397              :         }
     398            2 :         break;
     399              :     }
     400            5 :     case IPlaybackDelegate::Property::Sync:
     401              :     {
     402            5 :         m_sync = g_value_get_boolean(value);
     403            5 :         if (!client)
     404              :         {
     405            3 :             GST_DEBUG_OBJECT(m_sink, "Enqueue sync setting");
     406            3 :             m_isSyncQueued = true;
     407            3 :             return;
     408              :         }
     409              : 
     410            2 :         if (!client->setSync(m_sync))
     411              :         {
     412            1 :             GST_ERROR_OBJECT(m_sink, "Could not set sync");
     413              :         }
     414            2 :         break;
     415              :     }
     416            5 :     case IPlaybackDelegate::Property::SyncOff:
     417              :     {
     418            5 :         m_syncOff = g_value_get_boolean(value);
     419            5 :         if (!client)
     420              :         {
     421            3 :             GST_DEBUG_OBJECT(m_sink, "Enqueue sync off setting");
     422            3 :             m_isSyncOffQueued = true;
     423            3 :             return;
     424              :         }
     425              : 
     426            2 :         if (!client->setSyncOff(m_syncOff))
     427              :         {
     428            1 :             GST_ERROR_OBJECT(m_sink, "Could not set sync-off");
     429              :         }
     430            2 :         break;
     431              :     }
     432            5 :     case IPlaybackDelegate::Property::StreamSyncMode:
     433              :     {
     434            5 :         m_streamSyncMode = g_value_get_int(value);
     435            5 :         if (!client || !m_sourceAttached)
     436              :         {
     437            3 :             GST_DEBUG_OBJECT(m_sink, "Enqueue stream sync mode setting");
     438            3 :             m_isStreamSyncModeQueued = true;
     439            3 :             return;
     440              :         }
     441              : 
     442            2 :         if (!client->setStreamSyncMode(m_sourceId, m_streamSyncMode))
     443              :         {
     444            1 :             GST_ERROR_OBJECT(m_sink, "Could not set stream-sync-mode");
     445              :         }
     446            2 :         break;
     447              :     }
     448            4 :     case IPlaybackDelegate::Property::AudioFade:
     449              :     {
     450            4 :         const gchar *audioFadeStr = g_value_get_string(value);
     451              : 
     452            4 :         uint32_t fadeVolume = static_cast<uint32_t>(kDefaultVolume * 100);
     453            4 :         uint32_t duration = kDefaultVolumeDuration;
     454            4 :         char easeTypeChar = 'L';
     455              : 
     456            4 :         int parsedItems = sscanf(audioFadeStr, "%u,%u,%c", &fadeVolume, &duration, &easeTypeChar);
     457              : 
     458            4 :         if (parsedItems == 0)
     459              :         {
     460            1 :             GST_ERROR_OBJECT(m_sink, "Failed to parse any values from audio fade string: %s.", audioFadeStr);
     461            2 :             return;
     462              :         }
     463            3 :         else if (parsedItems == 1 || parsedItems == 2)
     464              :         {
     465            1 :             GST_WARNING_OBJECT(m_sink, "Partially parsed audio fade string: %s. Continuing with values: fadeVolume=%u, duration=%u, easeTypeChar=%c",
     466              :                                audioFadeStr, fadeVolume, duration, easeTypeChar);
     467              :         }
     468              : 
     469            3 :         if (fadeVolume > 100)
     470              :         {
     471            0 :             GST_WARNING_OBJECT(m_sink, "Fade volume is greater than 100. Setting it to 100.");
     472            0 :             fadeVolume = 100;
     473              :         }
     474            3 :         double volume = fadeVolume / 100.0;
     475              : 
     476            3 :         firebolt::rialto::EaseType easeType = convertCharToEaseType(easeTypeChar);
     477              : 
     478              :         {
     479            3 :             std::lock_guard<std::mutex> lock(m_audioFadeConfigMutex);
     480            3 :             m_audioFadeConfig.volume = volume;
     481            3 :             m_audioFadeConfig.duration = duration;
     482            3 :             m_audioFadeConfig.easeType = easeType;
     483              :         }
     484              : 
     485            3 :         if (!client)
     486              :         {
     487            1 :             GST_DEBUG_OBJECT(m_sink, "Enqueue audio fade setting");
     488            1 :             m_isAudioFadeQueued = true;
     489            1 :             return;
     490              :         }
     491              : 
     492            2 :         client->setVolume(volume, duration, easeType);
     493            2 :         break;
     494              :     }
     495            3 :     case IPlaybackDelegate::Property::LimitBufferingMs:
     496              :     {
     497            3 :         m_bufferingLimit = g_value_get_uint(value);
     498            3 :         if (!client)
     499              :         {
     500            2 :             GST_DEBUG_OBJECT(m_sink, "Enqueue buffering limit setting");
     501            2 :             m_isBufferingLimitQueued = true;
     502            2 :             return;
     503              :         }
     504              : 
     505            1 :         client->setBufferingLimit(m_bufferingLimit);
     506            1 :         break;
     507              :     }
     508            3 :     case IPlaybackDelegate::Property::UseBuffering:
     509              :     {
     510            3 :         m_useBuffering = g_value_get_boolean(value);
     511            3 :         if (!client)
     512              :         {
     513            2 :             GST_DEBUG_OBJECT(m_sink, "Enqueue use buffering setting");
     514            2 :             m_isUseBufferingQueued = true;
     515            2 :             return;
     516              :         }
     517              : 
     518            1 :         client->setUseBuffering(m_useBuffering);
     519            1 :         break;
     520              :     }
     521            1 :     case IPlaybackDelegate::Property::Async:
     522              :     {
     523            1 :         if (FALSE == g_value_get_boolean(value))
     524              :         {
     525            1 :             GST_WARNING_OBJECT(m_sink, "Cannot set ASYNC to false - not supported");
     526              :         }
     527            1 :         break;
     528              :     }
     529          242 :     default:
     530              :     {
     531          242 :         PullModePlaybackDelegate::setProperty(type, value);
     532          242 :         break;
     533              :     }
     534              :     }
     535          281 : }
     536              : 
     537            1 : void PullModeAudioPlaybackDelegate::handleQos(uint64_t processed, uint64_t dropped) const
     538              : {
     539            1 :     GstBus *bus = gst_element_get_bus(m_sink);
     540              :     /* Hardcode isLive to FALSE and set invalid timestamps */
     541            1 :     GstMessage *message = gst_message_new_qos(GST_OBJECT(m_sink), FALSE, GST_CLOCK_TIME_NONE, GST_CLOCK_TIME_NONE,
     542              :                                               GST_CLOCK_TIME_NONE, GST_CLOCK_TIME_NONE);
     543            1 :     gst_message_set_qos_stats(message, GST_FORMAT_DEFAULT, processed, dropped);
     544            1 :     gst_bus_post(bus, message);
     545            1 :     gst_object_unref(bus);
     546              : }
     547              : 
     548              : std::unique_ptr<firebolt::rialto::IMediaPipeline::MediaSource>
     549          110 : PullModeAudioPlaybackDelegate::createMediaSource(GstCaps *caps) const
     550              : {
     551          110 :     GstStructure *structure = gst_caps_get_structure(caps, 0);
     552          110 :     const gchar *structName = gst_structure_get_name(structure);
     553              : 
     554          110 :     firebolt::rialto::AudioConfig audioConfig{};
     555          110 :     firebolt::rialto::SegmentAlignment alignment{get_segment_alignment(structure)};
     556          110 :     std::shared_ptr<firebolt::rialto::CodecData> codecData{get_codec_data(structure)};
     557          110 :     firebolt::rialto::StreamFormat format{get_stream_format(structure)};
     558              : 
     559          110 :     if (structName)
     560              :     {
     561          109 :         std::string mimeType{};
     562          116 :         if (g_str_has_prefix(structName, "audio/mpeg") || g_str_has_prefix(structName, "audio/x-eac3") ||
     563            7 :             g_str_has_prefix(structName, "audio/x-ac3"))
     564              :         {
     565          103 :             gint sample_rate{0};
     566          103 :             gint number_of_channels{0};
     567          103 :             gst_structure_get_int(structure, "rate", &sample_rate);
     568          103 :             gst_structure_get_int(structure, "channels", &number_of_channels);
     569              : 
     570          206 :             audioConfig = firebolt::rialto::AudioConfig{static_cast<uint32_t>(number_of_channels),
     571          103 :                                                         static_cast<uint32_t>(sample_rate),
     572          103 :                                                         {}};
     573              : 
     574          103 :             if (g_str_has_prefix(structName, "audio/mpeg"))
     575              :             {
     576          101 :                 gint mpegversion{0};
     577          101 :                 gint layer{0};
     578          101 :                 gst_structure_get_int(structure, "mpegversion", &mpegversion);
     579          101 :                 gst_structure_get_int(structure, "layer", &layer);
     580          101 :                 if (1 == mpegversion && 3 == layer)
     581              :                 {
     582            1 :                     mimeType = "audio/mp3";
     583              :                 }
     584              :                 else
     585              :                 {
     586          100 :                     mimeType = "audio/mp4";
     587              :                 }
     588              :             }
     589              :             else
     590              :             {
     591            2 :                 mimeType = "audio/x-eac3";
     592              :             }
     593              :         }
     594            6 :         else if (g_str_has_prefix(structName, "audio/x-opus"))
     595              :         {
     596            3 :             mimeType = "audio/x-opus";
     597            3 :             guint32 sampleRate{48000};
     598            3 :             guint8 numberOfChannels{}, streams{}, stereoStreams{}, channelMappingFamily{};
     599            3 :             guint8 channelMapping[256]{};
     600            3 :             if (gst_codec_utils_opus_parse_caps(caps, &sampleRate, &numberOfChannels, &channelMappingFamily, &streams,
     601              :                                                 &stereoStreams, channelMapping))
     602              :             {
     603            2 :                 std::vector<std::vector<uint8_t>> streamHeaderVec;
     604            2 :                 const GValue *streamheader = gst_structure_get_value(structure, "streamheader");
     605            2 :                 if (streamheader)
     606              :                 {
     607            2 :                     for (guint i = 0; i < gst_value_array_get_size(streamheader); ++i)
     608              :                     {
     609            1 :                         const GValue *headerValue = gst_value_array_get_value(streamheader, i);
     610            1 :                         GstBuffer *headerBuffer = gst_value_get_buffer(headerValue);
     611            1 :                         if (headerBuffer)
     612              :                         {
     613            1 :                             GstMappedBuffer mappedBuf(headerBuffer, GST_MAP_READ);
     614            1 :                             if (mappedBuf)
     615              :                             {
     616            1 :                                 streamHeaderVec.push_back(
     617            3 :                                     std::vector<std::uint8_t>(mappedBuf.data(), mappedBuf.data() + mappedBuf.size()));
     618              :                             }
     619            1 :                         }
     620              :                     }
     621              :                 }
     622            2 :                 if (streamHeaderVec.size() > 0)
     623              :                 {
     624            1 :                     audioConfig = firebolt::rialto::AudioConfig{numberOfChannels, sampleRate, streamHeaderVec[0]};
     625              :                 }
     626              :                 else
     627              :                 {
     628            1 :                     guint16 preSkip{0};
     629            1 :                     gint16 gain{0};
     630              : 
     631            1 :                     GstBuffer *idHeader{};
     632            1 :                     idHeader = gst_codec_utils_opus_create_header(sampleRate, numberOfChannels, channelMappingFamily,
     633              :                                                                   streams, stereoStreams, channelMapping, preSkip, gain);
     634            1 :                     std::vector<uint8_t> codecSpecificConfig{};
     635            1 :                     GstMapInfo lsMap{};
     636            1 :                     if (gst_buffer_map(idHeader, &lsMap, GST_MAP_READ))
     637              :                     {
     638            1 :                         codecSpecificConfig.assign(lsMap.data, lsMap.data + lsMap.size);
     639            1 :                         gst_buffer_unmap(idHeader, &lsMap);
     640              :                     }
     641              :                     else
     642              :                     {
     643            0 :                         GST_ERROR_OBJECT(m_sink, "Failed to read opus header details from a GstBuffer!");
     644              :                     }
     645            1 :                     gst_buffer_unref(idHeader);
     646              : 
     647            1 :                     audioConfig = firebolt::rialto::AudioConfig{numberOfChannels, sampleRate, codecSpecificConfig};
     648              :                 }
     649            2 :             }
     650              :             else
     651              :             {
     652            1 :                 GST_ERROR("Failed to parse opus caps!");
     653            1 :                 return nullptr;
     654              :             }
     655              :         }
     656            3 :         else if (g_str_has_prefix(structName, "audio/b-wav") || g_str_has_prefix(structName, "audio/x-raw"))
     657              :         {
     658            2 :             gint sampleRate{0};
     659            2 :             gint numberOfChannels{0};
     660            2 :             std::optional<uint64_t> channelMask;
     661            2 :             gst_structure_get_int(structure, "rate", &sampleRate);
     662            2 :             gst_structure_get_int(structure, "channels", &numberOfChannels);
     663              :             std::optional<firebolt::rialto::Layout> layout =
     664            2 :                 rialto_mse_sink_convert_layout(gst_structure_get_string(structure, "layout"));
     665              :             std::optional<firebolt::rialto::Format> rialtoFormat =
     666            2 :                 rialto_mse_sink_convert_format(gst_structure_get_string(structure, "format"));
     667            2 :             const GValue *channelMaskValue = gst_structure_get_value(structure, "channel-mask");
     668            2 :             if (channelMaskValue)
     669              :             {
     670            2 :                 channelMask = gst_value_get_bitmask(channelMaskValue);
     671              :             }
     672              : 
     673            2 :             if (g_str_has_prefix(structName, "audio/b-wav"))
     674              :             {
     675            1 :                 mimeType = "audio/b-wav";
     676              :             }
     677              :             else
     678              :             {
     679            1 :                 mimeType = "audio/x-raw";
     680              :             }
     681              : 
     682            4 :             audioConfig = firebolt::rialto::AudioConfig{static_cast<uint32_t>(numberOfChannels),
     683            2 :                                                         static_cast<uint32_t>(sampleRate),
     684              :                                                         {},
     685              :                                                         rialtoFormat,
     686              :                                                         layout,
     687            2 :                                                         channelMask};
     688              :         }
     689            1 :         else if (g_str_has_prefix(structName, "audio/x-flac"))
     690              :         {
     691            1 :             mimeType = "audio/x-flac";
     692            1 :             gint sampleRate{0};
     693            1 :             gint numberOfChannels{0};
     694            1 :             gst_structure_get_int(structure, "rate", &sampleRate);
     695            1 :             gst_structure_get_int(structure, "channels", &numberOfChannels);
     696            1 :             std::vector<std::vector<uint8_t>> streamHeaderVec;
     697            1 :             const GValue *streamheader = gst_structure_get_value(structure, "streamheader");
     698            1 :             if (streamheader)
     699              :             {
     700            2 :                 for (guint i = 0; i < gst_value_array_get_size(streamheader); ++i)
     701              :                 {
     702            1 :                     const GValue *headerValue = gst_value_array_get_value(streamheader, i);
     703            1 :                     GstBuffer *headerBuffer = gst_value_get_buffer(headerValue);
     704            1 :                     if (headerBuffer)
     705              :                     {
     706            1 :                         GstMappedBuffer mappedBuf(headerBuffer, GST_MAP_READ);
     707            1 :                         if (mappedBuf)
     708              :                         {
     709            1 :                             streamHeaderVec.push_back(
     710            3 :                                 std::vector<std::uint8_t>(mappedBuf.data(), mappedBuf.data() + mappedBuf.size()));
     711              :                         }
     712            1 :                     }
     713              :                 }
     714              :             }
     715            1 :             std::optional<bool> framed;
     716            1 :             gboolean framedValue{FALSE};
     717            1 :             if (gst_structure_get_boolean(structure, "framed", &framedValue))
     718              :             {
     719            1 :                 framed = framedValue;
     720              :             }
     721              : 
     722            2 :             audioConfig = firebolt::rialto::AudioConfig{static_cast<uint32_t>(numberOfChannels),
     723            1 :                                                         static_cast<uint32_t>(sampleRate),
     724              :                                                         {},
     725              :                                                         std::nullopt,
     726              :                                                         std::nullopt,
     727              :                                                         std::nullopt,
     728              :                                                         streamHeaderVec,
     729            1 :                                                         framed};
     730              :         }
     731              :         else
     732              :         {
     733            0 :             GST_INFO_OBJECT(m_sink, "%s audio media source created", structName);
     734            0 :             mimeType = structName;
     735              :         }
     736              : 
     737          216 :         return std::make_unique<firebolt::rialto::IMediaPipeline::MediaSourceAudio>(mimeType, m_hasDrm, audioConfig,
     738          108 :                                                                                     alignment, format, codecData);
     739          109 :     }
     740              : 
     741            1 :     GST_ERROR_OBJECT(m_sink, "Empty caps' structure name! Failed to set mime type for audio media source.");
     742            1 :     return nullptr;
     743          110 : }
        

Generated by: LCOV version 2.0-1