1 /* GStreamer
2 * Copyright (C) 2017 Matthew Waters <matthew@centricular.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
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 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #endif
23
24 #include "transportstream.h"
25 #include "transportsendbin.h"
26 #include "transportreceivebin.h"
27 #include "gstwebrtcice.h"
28 #include "gstwebrtcbin.h"
29 #include "utils.h"
30 #include "gst/webrtc/webrtc-priv.h"
31
32 #define transport_stream_parent_class parent_class
33 G_DEFINE_TYPE (TransportStream, transport_stream, GST_TYPE_OBJECT);
34
35 enum
36 {
37 PROP_0,
38 PROP_WEBRTC,
39 PROP_SESSION_ID,
40 PROP_DTLS_CLIENT,
41 };
42
43 GstCaps *
transport_stream_get_caps_for_pt(TransportStream * stream,guint pt)44 transport_stream_get_caps_for_pt (TransportStream * stream, guint pt)
45 {
46 guint i, len;
47
48 len = stream->ptmap->len;
49 for (i = 0; i < len; i++) {
50 PtMapItem *item = &g_array_index (stream->ptmap, PtMapItem, i);
51 if (item->pt == pt)
52 return item->caps;
53 }
54 return NULL;
55 }
56
57 int
transport_stream_get_pt(TransportStream * stream,const gchar * encoding_name,guint media_idx)58 transport_stream_get_pt (TransportStream * stream, const gchar * encoding_name,
59 guint media_idx)
60 {
61 guint i;
62 gint ret = 0;
63
64 for (i = 0; i < stream->ptmap->len; i++) {
65 PtMapItem *item = &g_array_index (stream->ptmap, PtMapItem, i);
66
67 if (media_idx != -1 && media_idx != item->media_idx)
68 continue;
69
70 if (!gst_caps_is_empty (item->caps)) {
71 GstStructure *s = gst_caps_get_structure (item->caps, 0);
72 if (!g_strcmp0 (gst_structure_get_string (s, "encoding-name"),
73 encoding_name)) {
74 ret = item->pt;
75 break;
76 }
77 }
78 }
79
80 return ret;
81 }
82
83 int *
transport_stream_get_all_pt(TransportStream * stream,const gchar * encoding_name,gsize * pt_len)84 transport_stream_get_all_pt (TransportStream * stream,
85 const gchar * encoding_name, gsize * pt_len)
86 {
87 guint i;
88 gsize ret_i = 0;
89 gsize ret_size = 8;
90 int *ret = NULL;
91
92 for (i = 0; i < stream->ptmap->len; i++) {
93 PtMapItem *item = &g_array_index (stream->ptmap, PtMapItem, i);
94 if (!gst_caps_is_empty (item->caps)) {
95 GstStructure *s = gst_caps_get_structure (item->caps, 0);
96 if (!g_strcmp0 (gst_structure_get_string (s, "encoding-name"),
97 encoding_name)) {
98 if (!ret)
99 ret = g_new0 (int, ret_size);
100 if (ret_i >= ret_size) {
101 ret_size *= 2;
102 ret = g_realloc_n (ret, ret_size, sizeof (int));
103 }
104 ret[ret_i++] = item->pt;
105 }
106 }
107 }
108
109 *pt_len = ret_i;
110 return ret;
111 }
112
113 static void
transport_stream_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)114 transport_stream_set_property (GObject * object, guint prop_id,
115 const GValue * value, GParamSpec * pspec)
116 {
117 TransportStream *stream = TRANSPORT_STREAM (object);
118
119 switch (prop_id) {
120 case PROP_WEBRTC:
121 gst_object_set_parent (GST_OBJECT (stream), g_value_get_object (value));
122 break;
123 }
124
125 GST_OBJECT_LOCK (stream);
126 switch (prop_id) {
127 case PROP_WEBRTC:
128 break;
129 case PROP_SESSION_ID:
130 stream->session_id = g_value_get_uint (value);
131 break;
132 case PROP_DTLS_CLIENT:
133 stream->dtls_client = g_value_get_boolean (value);
134 break;
135 default:
136 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
137 break;
138 }
139 GST_OBJECT_UNLOCK (stream);
140 }
141
142 static void
transport_stream_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)143 transport_stream_get_property (GObject * object, guint prop_id,
144 GValue * value, GParamSpec * pspec)
145 {
146 TransportStream *stream = TRANSPORT_STREAM (object);
147
148 GST_OBJECT_LOCK (stream);
149 switch (prop_id) {
150 case PROP_SESSION_ID:
151 g_value_set_uint (value, stream->session_id);
152 break;
153 case PROP_DTLS_CLIENT:
154 g_value_set_boolean (value, stream->dtls_client);
155 break;
156 default:
157 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
158 break;
159 }
160 GST_OBJECT_UNLOCK (stream);
161 }
162
163 static void
transport_stream_dispose(GObject * object)164 transport_stream_dispose (GObject * object)
165 {
166 TransportStream *stream = TRANSPORT_STREAM (object);
167
168 if (stream->send_bin)
169 gst_object_unref (stream->send_bin);
170 stream->send_bin = NULL;
171
172 if (stream->receive_bin)
173 gst_object_unref (stream->receive_bin);
174 stream->receive_bin = NULL;
175
176 if (stream->transport)
177 gst_object_unref (stream->transport);
178 stream->transport = NULL;
179
180 if (stream->rtxsend)
181 gst_object_unref (stream->rtxsend);
182 stream->rtxsend = NULL;
183
184 if (stream->rtxreceive)
185 gst_object_unref (stream->rtxreceive);
186 stream->rtxreceive = NULL;
187
188 GST_OBJECT_PARENT (object) = NULL;
189
190 G_OBJECT_CLASS (parent_class)->dispose (object);
191 }
192
193 static void
transport_stream_finalize(GObject * object)194 transport_stream_finalize (GObject * object)
195 {
196 TransportStream *stream = TRANSPORT_STREAM (object);
197
198 g_array_free (stream->ptmap, TRUE);
199 g_ptr_array_free (stream->remote_ssrcmap, TRUE);
200
201 G_OBJECT_CLASS (parent_class)->finalize (object);
202 }
203
204 static void
transport_stream_constructed(GObject * object)205 transport_stream_constructed (GObject * object)
206 {
207 TransportStream *stream = TRANSPORT_STREAM (object);
208 GstWebRTCBin *webrtc;
209 GstWebRTCICETransport *ice_trans;
210
211 stream->transport = gst_webrtc_dtls_transport_new (stream->session_id);
212
213 webrtc = GST_WEBRTC_BIN (gst_object_get_parent (GST_OBJECT (object)));
214
215 g_object_bind_property (stream->transport, "client", stream, "dtls-client",
216 G_BINDING_BIDIRECTIONAL);
217
218 /* Need to go full Java and have a transport manager?
219 * Or make the caller set the ICE transport up? */
220
221 stream->stream = _find_ice_stream_for_session (webrtc, stream->session_id);
222 if (stream->stream == NULL) {
223 stream->stream = gst_webrtc_ice_add_stream (webrtc->priv->ice,
224 stream->session_id);
225 _add_ice_stream_item (webrtc, stream->session_id, stream->stream);
226 }
227 ice_trans =
228 gst_webrtc_ice_find_transport (webrtc->priv->ice, stream->stream,
229 GST_WEBRTC_ICE_COMPONENT_RTP);
230 gst_webrtc_dtls_transport_set_transport (stream->transport, ice_trans);
231 gst_object_unref (ice_trans);
232
233 stream->send_bin = g_object_new (transport_send_bin_get_type (), "stream",
234 stream, NULL);
235 gst_object_ref_sink (stream->send_bin);
236 stream->receive_bin = g_object_new (transport_receive_bin_get_type (),
237 "stream", stream, NULL);
238 gst_object_ref_sink (stream->receive_bin);
239
240 gst_object_unref (webrtc);
241
242 G_OBJECT_CLASS (parent_class)->constructed (object);
243 }
244
245 static void
transport_stream_class_init(TransportStreamClass * klass)246 transport_stream_class_init (TransportStreamClass * klass)
247 {
248 GObjectClass *gobject_class = (GObjectClass *) klass;
249
250 gobject_class->constructed = transport_stream_constructed;
251 gobject_class->get_property = transport_stream_get_property;
252 gobject_class->set_property = transport_stream_set_property;
253 gobject_class->dispose = transport_stream_dispose;
254 gobject_class->finalize = transport_stream_finalize;
255
256 /* some acrobatics are required to set the parent before _constructed()
257 * has been called */
258 g_object_class_install_property (gobject_class,
259 PROP_WEBRTC,
260 g_param_spec_object ("webrtc", "Parent webrtcbin",
261 "Parent webrtcbin",
262 GST_TYPE_WEBRTC_BIN,
263 G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
264
265 g_object_class_install_property (gobject_class,
266 PROP_SESSION_ID,
267 g_param_spec_uint ("session-id", "Session ID",
268 "Session ID used for this transport",
269 0, G_MAXUINT, 0,
270 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
271
272 g_object_class_install_property (gobject_class,
273 PROP_DTLS_CLIENT,
274 g_param_spec_boolean ("dtls-client", "DTLS client",
275 "Whether we take the client role in DTLS negotiation",
276 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
277 }
278
279 static void
clear_ptmap_item(PtMapItem * item)280 clear_ptmap_item (PtMapItem * item)
281 {
282 if (item->caps)
283 gst_caps_unref (item->caps);
284 }
285
286 SsrcMapItem *
ssrcmap_item_new(guint32 ssrc,guint media_idx)287 ssrcmap_item_new (guint32 ssrc, guint media_idx)
288 {
289 SsrcMapItem *ssrc_item = g_slice_new (SsrcMapItem);
290
291 ssrc_item->media_idx = media_idx;
292 ssrc_item->ssrc = ssrc;
293 g_weak_ref_init (&ssrc_item->rtpjitterbuffer, NULL);
294
295 return ssrc_item;
296 }
297
298 static void
ssrcmap_item_free(SsrcMapItem * item)299 ssrcmap_item_free (SsrcMapItem * item)
300 {
301 g_weak_ref_clear (&item->rtpjitterbuffer);
302 g_slice_free (SsrcMapItem, item);
303 }
304
305 static void
transport_stream_init(TransportStream * stream)306 transport_stream_init (TransportStream * stream)
307 {
308 stream->ptmap = g_array_new (FALSE, TRUE, sizeof (PtMapItem));
309 g_array_set_clear_func (stream->ptmap, (GDestroyNotify) clear_ptmap_item);
310 stream->remote_ssrcmap = g_ptr_array_new_with_free_func (
311 (GDestroyNotify) ssrcmap_item_free);
312 }
313
314 TransportStream *
transport_stream_new(GstWebRTCBin * webrtc,guint session_id)315 transport_stream_new (GstWebRTCBin * webrtc, guint session_id)
316 {
317 TransportStream *stream;
318
319 stream = g_object_new (transport_stream_get_type (), "webrtc", webrtc,
320 "session-id", session_id, NULL);
321
322 return stream;
323 }
324