300a3d03737d1e373acb88a4f4ba87fb1733d9aa
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / gst-libs / gst / webrtc / nice / nicetransport.c
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 "nicestream.h"
25 #include "nicetransport.h"
26
27 #define GST_CAT_DEFAULT gst_webrtc_nice_transport_debug
28 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
29
30 enum
31 {
32   SIGNAL_0,
33   LAST_SIGNAL,
34 };
35
36 enum
37 {
38   PROP_0,
39   PROP_STREAM,
40   PROP_SEND_BUFFER_SIZE,
41   PROP_RECEIVE_BUFFER_SIZE
42 };
43
44 //static guint gst_webrtc_nice_transport_signals[LAST_SIGNAL] = { 0 };
45
46 struct _GstWebRTCNiceTransportPrivate
47 {
48   gboolean running;
49
50   gint send_buffer_size;
51   gint receive_buffer_size;
52   gulong on_new_selected_pair_id;
53   gulong on_component_state_changed_id;
54 };
55
56 #define gst_webrtc_nice_transport_parent_class parent_class
57 G_DEFINE_TYPE_WITH_CODE (GstWebRTCNiceTransport, gst_webrtc_nice_transport,
58     GST_TYPE_WEBRTC_ICE_TRANSPORT, G_ADD_PRIVATE (GstWebRTCNiceTransport)
59     GST_DEBUG_CATEGORY_INIT (gst_webrtc_nice_transport_debug,
60         "webrtcnicetransport", 0, "webrtcnicetransport");
61     );
62
63 static NiceComponentType
64 _gst_component_to_nice (GstWebRTCICEComponent component)
65 {
66   switch (component) {
67     case GST_WEBRTC_ICE_COMPONENT_RTP:
68       return NICE_COMPONENT_TYPE_RTP;
69     case GST_WEBRTC_ICE_COMPONENT_RTCP:
70       return NICE_COMPONENT_TYPE_RTCP;
71     default:
72       g_assert_not_reached ();
73       return 0;
74   }
75 }
76
77 static GstWebRTCICEComponent
78 _nice_component_to_gst (NiceComponentType component)
79 {
80   switch (component) {
81     case NICE_COMPONENT_TYPE_RTP:
82       return GST_WEBRTC_ICE_COMPONENT_RTP;
83     case NICE_COMPONENT_TYPE_RTCP:
84       return GST_WEBRTC_ICE_COMPONENT_RTCP;
85     default:
86       g_assert_not_reached ();
87       return 0;
88   }
89 }
90
91 static GstWebRTCICEConnectionState
92 _nice_component_state_to_gst (NiceComponentState state)
93 {
94   switch (state) {
95     case NICE_COMPONENT_STATE_DISCONNECTED:
96       return GST_WEBRTC_ICE_CONNECTION_STATE_DISCONNECTED;
97     case NICE_COMPONENT_STATE_GATHERING:
98       return GST_WEBRTC_ICE_CONNECTION_STATE_NEW;
99     case NICE_COMPONENT_STATE_CONNECTING:
100       return GST_WEBRTC_ICE_CONNECTION_STATE_CHECKING;
101     case NICE_COMPONENT_STATE_CONNECTED:
102       return GST_WEBRTC_ICE_CONNECTION_STATE_CONNECTED;
103     case NICE_COMPONENT_STATE_READY:
104       return GST_WEBRTC_ICE_CONNECTION_STATE_COMPLETED;
105     case NICE_COMPONENT_STATE_FAILED:
106       return GST_WEBRTC_ICE_CONNECTION_STATE_FAILED;
107     default:
108       g_assert_not_reached ();
109       return 0;
110   }
111 }
112
113 static void
114 gst_webrtc_nice_transport_set_property (GObject * object, guint prop_id,
115     const GValue * value, GParamSpec * pspec)
116 {
117   GstWebRTCNiceTransport *nice = GST_WEBRTC_NICE_TRANSPORT (object);
118
119   switch (prop_id) {
120     case PROP_STREAM:
121       if (nice->stream)
122         gst_object_unref (nice->stream);
123       nice->stream = g_value_dup_object (value);
124       break;
125     case PROP_SEND_BUFFER_SIZE:
126       nice->priv->send_buffer_size = g_value_get_int (value);
127       gst_webrtc_nice_transport_update_buffer_size (nice);
128       break;
129     case PROP_RECEIVE_BUFFER_SIZE:
130       nice->priv->receive_buffer_size = g_value_get_int (value);
131       gst_webrtc_nice_transport_update_buffer_size (nice);
132       break;
133     default:
134       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
135       break;
136   }
137 }
138
139 static void
140 gst_webrtc_nice_transport_get_property (GObject * object, guint prop_id,
141     GValue * value, GParamSpec * pspec)
142 {
143   GstWebRTCNiceTransport *nice = GST_WEBRTC_NICE_TRANSPORT (object);
144
145   switch (prop_id) {
146     case PROP_STREAM:
147       g_value_set_object (value, nice->stream);
148       break;
149     case PROP_SEND_BUFFER_SIZE:
150       g_value_set_int (value, nice->priv->send_buffer_size);
151       break;
152     case PROP_RECEIVE_BUFFER_SIZE:
153       g_value_set_int (value, nice->priv->receive_buffer_size);
154       break;
155     default:
156       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
157       break;
158   }
159 }
160
161 static void
162 gst_webrtc_nice_transport_finalize (GObject * object)
163 {
164   GstWebRTCNiceTransport *nice = GST_WEBRTC_NICE_TRANSPORT (object);
165   NiceAgent *agent;
166   GstWebRTCNice *webrtc_ice;
167
168   GWeakRef ice_weak;
169   g_object_get (GST_WEBRTC_NICE_STREAM (nice->stream), "ice", &ice_weak, NULL);
170   webrtc_ice = g_weak_ref_get (&ice_weak);
171
172   if (webrtc_ice) {
173     g_object_get (webrtc_ice, "agent", &agent, NULL);
174
175     if (nice->priv->on_component_state_changed_id != 0) {
176       g_signal_handler_disconnect (agent,
177           nice->priv->on_component_state_changed_id);
178     }
179
180     if (nice->priv->on_new_selected_pair_id != 0) {
181       g_signal_handler_disconnect (agent, nice->priv->on_new_selected_pair_id);
182     }
183
184     g_object_unref (agent);
185     gst_object_unref (webrtc_ice);
186   }
187
188   gst_object_unref (nice->stream);
189
190   G_OBJECT_CLASS (parent_class)->finalize (object);
191 }
192
193 void
194 gst_webrtc_nice_transport_update_buffer_size (GstWebRTCNiceTransport * nice)
195 {
196   NiceAgent *agent = NULL;
197   GPtrArray *sockets;
198   guint i;
199   GstWebRTCNice *webrtc_ice;
200
201   GWeakRef ice_weak;
202   g_object_get (GST_WEBRTC_NICE_STREAM (nice->stream), "ice", &ice_weak, NULL);
203   webrtc_ice = g_weak_ref_get (&ice_weak);
204
205   g_assert (webrtc_ice != NULL);
206
207   g_object_get (webrtc_ice, "agent", &agent, NULL);
208   g_assert (agent != NULL);
209
210   sockets =
211       nice_agent_get_sockets (agent,
212       GST_WEBRTC_ICE_STREAM (nice->stream)->stream_id, 1);
213   if (sockets == NULL) {
214     g_object_unref (agent);
215     gst_object_unref (webrtc_ice);
216     return;
217   }
218
219   for (i = 0; i < sockets->len; i++) {
220     GSocket *gsocket = g_ptr_array_index (sockets, i);
221 #ifdef SO_SNDBUF
222     if (nice->priv->send_buffer_size != 0) {
223       GError *gerror = NULL;
224       if (!g_socket_set_option (gsocket, SOL_SOCKET, SO_SNDBUF,
225               nice->priv->send_buffer_size, &gerror))
226         GST_WARNING_OBJECT (nice, "Could not set send buffer size : %s",
227             gerror->message);
228       g_clear_error (&gerror);
229     }
230 #endif
231 #ifdef SO_RCVBUF
232     if (nice->priv->receive_buffer_size != 0) {
233       GError *gerror = NULL;
234       if (!g_socket_set_option (gsocket, SOL_SOCKET, SO_RCVBUF,
235               nice->priv->receive_buffer_size, &gerror))
236         GST_WARNING_OBJECT (nice, "Could not set send receive size : %s",
237             gerror->message);
238       g_clear_error (&gerror);
239     }
240 #endif
241   }
242   g_ptr_array_unref (sockets);
243   g_object_unref (agent);
244   gst_object_unref (webrtc_ice);
245 }
246
247
248 static void
249 _on_new_selected_pair (NiceAgent * agent, guint stream_id,
250     NiceComponentType component, NiceCandidate * lcandidate,
251     NiceCandidate * rcandidate, GWeakRef * nice_weak)
252 {
253   GstWebRTCNiceTransport *nice = g_weak_ref_get (nice_weak);
254   GstWebRTCICETransport *ice;
255   GstWebRTCICEComponent comp = _nice_component_to_gst (component);
256   guint our_stream_id;
257
258   if (!nice)
259     return;
260
261   ice = GST_WEBRTC_ICE_TRANSPORT (nice);
262
263   g_object_get (nice->stream, "stream-id", &our_stream_id, NULL);
264
265   if (stream_id != our_stream_id)
266     goto cleanup;
267   if (comp != ice->component)
268     goto cleanup;
269
270   gst_webrtc_ice_transport_selected_pair_change (ice);
271
272 cleanup:
273   gst_object_unref (nice);
274 }
275
276 static void
277 _on_component_state_changed (NiceAgent * agent, guint stream_id,
278     NiceComponentType component, NiceComponentState state, GWeakRef * nice_weak)
279 {
280   GstWebRTCNiceTransport *nice = g_weak_ref_get (nice_weak);
281   GstWebRTCICETransport *ice;
282   GstWebRTCICEComponent comp = _nice_component_to_gst (component);
283   guint our_stream_id;
284
285   if (!nice)
286     return;
287
288   ice = GST_WEBRTC_ICE_TRANSPORT (nice);
289
290   g_object_get (nice->stream, "stream-id", &our_stream_id, NULL);
291
292   if (stream_id != our_stream_id)
293     goto cleanup;
294   if (comp != ice->component)
295     goto cleanup;
296
297   GST_DEBUG_OBJECT (ice, "%u %u %s", stream_id, component,
298       nice_component_state_to_string (state));
299
300   gst_webrtc_ice_transport_connection_state_change (ice,
301       _nice_component_state_to_gst (state));
302
303 cleanup:
304   gst_object_unref (nice);
305 }
306
307 static GWeakRef *
308 weak_new (GstWebRTCNiceTransport * nice)
309 {
310   GWeakRef *weak = g_new0 (GWeakRef, 1);
311   g_weak_ref_init (weak, nice);
312   return weak;
313 }
314
315 static void
316 weak_free (GWeakRef * weak)
317 {
318   g_weak_ref_clear (weak);
319   g_free (weak);
320 }
321
322 static void
323 gst_webrtc_nice_transport_constructed (GObject * object)
324 {
325   GstWebRTCNiceTransport *nice = GST_WEBRTC_NICE_TRANSPORT (object);
326   GstWebRTCICETransport *ice = GST_WEBRTC_ICE_TRANSPORT (object);
327   NiceComponentType component = _gst_component_to_nice (ice->component);
328   gboolean controlling_mode;
329   guint our_stream_id;
330   NiceAgent *agent;
331   GstWebRTCNice *webrtc_ice;
332
333   GWeakRef ice_weak;
334   g_object_get (GST_WEBRTC_NICE_STREAM (nice->stream), "ice", &ice_weak, NULL);
335   webrtc_ice = g_weak_ref_get (&ice_weak);
336
337   g_assert (webrtc_ice != NULL);
338   g_object_get (nice->stream, "stream-id", &our_stream_id, NULL);
339   g_object_get (webrtc_ice, "agent", &agent, NULL);
340
341   g_object_get (agent, "controlling-mode", &controlling_mode, NULL);
342   ice->role =
343       controlling_mode ? GST_WEBRTC_ICE_ROLE_CONTROLLING :
344       GST_WEBRTC_ICE_ROLE_CONTROLLED;
345
346   nice->priv->on_component_state_changed_id = g_signal_connect_data (agent,
347       "component-state-changed", G_CALLBACK (_on_component_state_changed),
348       weak_new (nice), (GClosureNotify) weak_free, (GConnectFlags) 0);
349   nice->priv->on_new_selected_pair_id = g_signal_connect_data (agent,
350       "new-selected-pair-full", G_CALLBACK (_on_new_selected_pair),
351       weak_new (nice), (GClosureNotify) weak_free, (GConnectFlags) 0);
352
353   ice->src = gst_element_factory_make ("nicesrc", NULL);
354   if (ice->src) {
355     g_object_set (ice->src, "agent", agent, "stream", our_stream_id,
356         "component", component, NULL);
357   }
358   ice->sink = gst_element_factory_make ("nicesink", NULL);
359   if (ice->sink) {
360     g_object_set (ice->sink, "agent", agent, "stream", our_stream_id,
361         "component", component, "async", FALSE, "enable-last-sample", FALSE,
362         "sync", FALSE, NULL);
363   }
364
365   g_object_unref (agent);
366   gst_object_unref (webrtc_ice);
367
368   G_OBJECT_CLASS (parent_class)->constructed (object);
369 }
370
371 static void
372 gst_webrtc_nice_transport_class_init (GstWebRTCNiceTransportClass * klass)
373 {
374   GObjectClass *gobject_class = (GObjectClass *) klass;
375
376   gobject_class->constructed = gst_webrtc_nice_transport_constructed;
377   gobject_class->get_property = gst_webrtc_nice_transport_get_property;
378   gobject_class->set_property = gst_webrtc_nice_transport_set_property;
379   gobject_class->finalize = gst_webrtc_nice_transport_finalize;
380
381   g_object_class_install_property (gobject_class,
382       PROP_STREAM,
383       g_param_spec_object ("stream",
384           "WebRTC ICE Stream", "ICE stream associated with this transport",
385           GST_TYPE_WEBRTC_NICE_STREAM,
386           G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
387
388   /**
389    * GstWebRTCNiceTransport:send-buffer-size:
390    *
391    * Size of the kernel send buffer in bytes, 0=default
392    *
393    * Since: 1.20
394    */
395
396   g_object_class_install_property (G_OBJECT_CLASS (klass),
397       PROP_SEND_BUFFER_SIZE, g_param_spec_int ("send-buffer-size",
398           "Send Buffer Size",
399           "Size of the kernel send buffer in bytes, 0=default", 0, G_MAXINT, 0,
400           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
401
402   /**
403    * GstWebRTCNiceTransport:receive-buffer-size:
404    *
405    * Size of the kernel receive buffer in bytes, 0=default
406    *
407    * Since: 1.20
408    */
409
410   g_object_class_install_property (G_OBJECT_CLASS (klass),
411       PROP_RECEIVE_BUFFER_SIZE, g_param_spec_int ("receive-buffer-size",
412           "Receive Buffer Size",
413           "Size of the kernel receive buffer in bytes, 0=default", 0, G_MAXINT,
414           0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
415 }
416
417 static void
418 gst_webrtc_nice_transport_init (GstWebRTCNiceTransport * nice)
419 {
420   nice->priv = gst_webrtc_nice_transport_get_instance_private (nice);
421 }
422
423 GstWebRTCNiceTransport *
424 gst_webrtc_nice_transport_new (GstWebRTCNiceStream * stream,
425     GstWebRTCICEComponent component)
426 {
427   return g_object_new (GST_TYPE_WEBRTC_NICE_TRANSPORT, "stream", stream,
428       "component", component, NULL);
429 }