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

Generated by: LCOV version 2.0-1