5b61a0ccf2ab7daeacec744d5d2b77699b7c2c12
[platform/core/api/mediatransporter.git] / src / MediaTransporterReceiverSrt.cpp
1 /**
2  * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "MediaTransporterBase.h"
18 #include "MediaTransporterException.h"
19 #include "MediaTransporterReceiverSrt.h"
20 #include "MediaTransporterGst.h"
21 #include "MediaTransporterLog.h"
22 #include "MediaTransporterUtil.h"
23 #include <cassert>
24
25 using namespace tizen_media_transporter;
26 using namespace tizen_media_transporter::param::srt;
27
28 static const std::map<std::string, mtprConnectionStatsProp> __receiverProp = {
29         { "packets-received", MTPR_CONNECTION_STATS_PROP_PACKET_RECEIVED },
30         { "packets-received-lost", MTPR_CONNECTION_STATS_PROP_PACKET_RECEIVED_LOST },
31         { "packets-received-rate-mbps", MTPR_CONNECTION_STATS_PROP_RECEIVED_RATE_MBPS },
32         { "negotiated-latency-ms", MTPR_CONNECTION_STATS_PROP_NEGOTIATED_LATENCY_MS },
33         { "bandwidth-mbps", MTPR_CONNECTION_STATS_PROP_BANDWIDTH_MPBS },
34         { "rtt-ms", MTPR_CONNECTION_STATS_PROP_RTT_MS },
35         { "bytes-received-total", MTPR_CONNECTION_STATS_PROP_BYTES_RECEIVED_TOTAL }};
36
37 MediaTransporterReceiverSrt::MediaTransporterReceiverSrt()
38 {
39         LOG_DEBUG("ctor: %p", this);
40 }
41
42 MediaTransporterReceiverSrt::~MediaTransporterReceiverSrt()
43 {
44         LOG_DEBUG("dtor: %p", this);
45 }
46
47 void MediaTransporterReceiverSrt::_demuxNoMorePadsCallback(GstElement *demux, gpointer userData)
48 {
49         MediaTransporterReceiverSrt* srt = static_cast<MediaTransporterReceiverSrt*>(userData);
50         std::string dotName = std::string { GST_ELEMENT_NAME(srt->_gst.pipeline) } + ".complete";
51         gst::_generateDot(srt->_gst.pipeline, dotName);
52
53         _noMoreStreamCallback(userData);
54 }
55
56 void MediaTransporterReceiverSrt::_demuxPadAddedCallback(GstElement *demux, GstPad *new_pad, gpointer userData)
57 {
58         if (GST_PAD_DIRECTION(new_pad) != GST_PAD_SRC)
59                 return;
60
61         std::string mediaType = gst::_getMimeTypeFromPad(new_pad);
62
63         if (!_isSupportedMediaType(mediaType))
64                 return;
65
66         LOG_INFO("new_pad[%s] media_type[%s]", GST_PAD_NAME(new_pad), mediaType.c_str());
67
68         auto srt = static_cast<MediaTransporterReceiverSrt*>(userData);
69         assert(srt);
70
71         bool isAudio = _isAudioMediaType(mediaType);
72         if (srt->_audioCallback._callback && isAudio)
73                 srt->_buildForwardingElements(demux, new_pad, G_CALLBACK(_encodedAudioStreamCallback));
74         else if (srt->_videoCallback._callback && !isAudio)
75                 srt->_buildForwardingElements(demux, new_pad, G_CALLBACK(_encodedVideoStreamCallback));
76         else
77                 srt->_buildRenderingElements(demux, new_pad, isAudio);
78
79         _streamAddedCallback(new_pad, userData);
80 }
81
82 void MediaTransporterReceiverSrt::buildPipeline()
83 {
84         GstElement* src = NULL;
85         GstElement* queue = NULL;
86         GstElement* tsdemux = NULL;
87
88         MTPR_FENTER();
89
90         /* create mux to sink */
91         try {
92                 if (_senderAddress.empty())
93                         throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "address is empty");
94
95                 src = gst::_createElement(gst::DEFAULT_ELEMENT_SRTSRC);
96                 g_object_set(G_OBJECT(src),
97                         "uri", util::addProtocolPrefix(_senderAddress, "srt").c_str(),
98                         "latency", 10,
99                         NULL);
100
101                 if (_connectionParam.mode != MTPR_CONNECTION_SRT_MODE_NONE)
102                         g_object_set(G_OBJECT(src),
103                                 "mode", static_cast<int>(_connectionParam.mode), NULL);
104
105                 if (_connectionParam.pbKeyLen != MTPR_CONNECTION_SRT_NO_KEY)
106                         g_object_set(G_OBJECT(src),
107                                 "pbkeylen", static_cast<int>(_connectionParam.pbKeyLen), NULL);
108
109                 if (!_connectionParam.passPhrase.empty())
110                         g_object_set(G_OBJECT(src),
111                                 "passphrase", _connectionParam.passPhrase.c_str(), NULL);
112
113                 if (!_connectionParam.streamId.empty())
114                         g_object_set(G_OBJECT(src),
115                                 "streamid", _connectionParam.streamId.c_str(), NULL);
116
117                 queue = gst::_createElement(gst::DEFAULT_ELEMENT_QUEUE);
118
119                 tsdemux = gst::_createElement(gst::DEFAULT_ELEMENT_TSDEMUX);
120                 g_object_set(G_OBJECT(tsdemux), "latency", 0, NULL);
121
122                 gst_bin_add_many(GST_BIN(_gst.pipeline), src, queue, tsdemux, NULL);
123
124                 if (!gst_element_link_many (src, queue, tsdemux, NULL))
125                         throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "failed to link elements");
126
127                 gst::_connectAndAppendSignal(&_gst.signals, G_OBJECT(tsdemux), "pad-added", G_CALLBACK(_demuxPadAddedCallback), this);
128                 gst::_connectAndAppendSignal(&_gst.signals, G_OBJECT(tsdemux), "no-more-pads", G_CALLBACK(_demuxNoMorePadsCallback), this);
129                 LOG_INFO("linked mux and sink");
130                 _srtSrc = src;
131         } catch (const MediaTransporterException& e) {
132                 LOG_ERROR("%s", e.what());
133
134                 gst::_disconnectSignal(&_gst.signals, G_OBJECT(tsdemux));
135
136                 gst::_destroyElementFromParent(src);
137                 gst::_destroyElementFromParent(queue);
138                 gst::_destroyElementFromParent(tsdemux);
139
140                 throw;
141         }
142 }
143
144 void MediaTransporterReceiverSrt::startPipeline()
145 {
146         gst::_setPipelineState(_gst.pipeline, GST_STATE_PLAYING,
147                                                         MediaTransporterIni::get().general().timeout);
148 }
149
150 void MediaTransporterReceiverSrt::stopPipeline()
151 {
152         gst::_setPipelineState(_gst.pipeline, GST_STATE_NULL,
153                                                         MediaTransporterIni::get().general().timeout);
154         _srtSrc = NULL;
155 }
156
157 void MediaTransporterReceiverSrt::setConnection(std::string name, std::string val)
158 {
159         setConnectionParam(name, val, &_connectionParam);
160 }
161
162 std::string MediaTransporterReceiverSrt::getConnection(std::string name)
163 {
164         return getConnectionParam(_connectionParam, name);
165 }
166
167 void MediaTransporterReceiverSrt::setSenderAddress(std::string address)
168 {
169         _senderAddress = address;
170 }
171
172 gboolean MediaTransporterReceiverSrt::_statsForeachCb(GQuark fieldId, const GValue* val, gpointer userData)
173 {
174         auto callback = static_cast<IInvokable*>(userData);
175         std::string fieldName = g_quark_to_string(fieldId);
176
177         if (!callback ||
178                 !callback->invoke(fieldName, val, __receiverProp)) {
179                 LOG_WARNING("stop calling stats callback");
180                 return FALSE;
181         }
182
183         return TRUE;
184 }
185
186 void MediaTransporterReceiverSrt::foreachConnectionStats(InvokablePtr callback)
187 {
188         GstStructure* structure = nullptr;
189
190         g_object_get(_srtSrc, "stats", &structure, NULL);
191
192         gchar* str = gst_structure_to_string(structure);
193         SECURE_LOG_DEBUG("RECEIVER >>> stats : %s", str);
194         g_free(str);
195
196         gst_structure_foreach(structure, _statsForeachCb, callback.get());
197 }