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 "nicetransport.h"
25 #include "icestream.h"
26
27 #include <gio/gnetworking.h>
28
29 #define GST_CAT_DEFAULT gst_webrtc_nice_transport_debug
30 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
31
32 enum
33 {
34 SIGNAL_0,
35 LAST_SIGNAL,
36 };
37
38 enum
39 {
40 PROP_0,
41 PROP_STREAM,
42 PROP_SEND_BUFFER_SIZE,
43 PROP_RECEIVE_BUFFER_SIZE
44 };
45
46 //static guint gst_webrtc_nice_transport_signals[LAST_SIGNAL] = { 0 };
47
48 struct _GstWebRTCNiceTransportPrivate
49 {
50 gboolean running;
51
52 gint send_buffer_size;
53 gint receive_buffer_size;
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
_gst_component_to_nice(GstWebRTCICEComponent component)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
_nice_component_to_gst(NiceComponentType component)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
_nice_component_state_to_gst(NiceComponentState state)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
gst_webrtc_nice_transport_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)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
gst_webrtc_nice_transport_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)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
gst_webrtc_nice_transport_finalize(GObject * object)162 gst_webrtc_nice_transport_finalize (GObject * object)
163 {
164 GstWebRTCNiceTransport *nice = GST_WEBRTC_NICE_TRANSPORT (object);
165
166 gst_object_unref (nice->stream);
167
168 G_OBJECT_CLASS (parent_class)->finalize (object);
169 }
170
171 void
gst_webrtc_nice_transport_update_buffer_size(GstWebRTCNiceTransport * nice)172 gst_webrtc_nice_transport_update_buffer_size (GstWebRTCNiceTransport * nice)
173 {
174 NiceAgent *agent = NULL;
175 GPtrArray *sockets;
176 guint i;
177
178 g_object_get (nice->stream->ice, "agent", &agent, NULL);
179 g_assert (agent != NULL);
180
181 sockets = nice_agent_get_sockets (agent, nice->stream->stream_id, 1);
182 if (sockets == NULL) {
183 g_object_unref (agent);
184 return;
185 }
186
187 for (i = 0; i < sockets->len; i++) {
188 GSocket *gsocket = g_ptr_array_index (sockets, i);
189 #ifdef SO_SNDBUF
190 if (nice->priv->send_buffer_size != 0) {
191 GError *gerror = NULL;
192 if (!g_socket_set_option (gsocket, SOL_SOCKET, SO_SNDBUF,
193 nice->priv->send_buffer_size, &gerror))
194 GST_WARNING_OBJECT (nice, "Could not set send buffer size : %s",
195 gerror->message);
196 g_clear_error (&gerror);
197 }
198 #endif
199 #ifdef SO_RCVBUF
200 if (nice->priv->receive_buffer_size != 0) {
201 GError *gerror = NULL;
202 if (!g_socket_set_option (gsocket, SOL_SOCKET, SO_RCVBUF,
203 nice->priv->receive_buffer_size, &gerror))
204 GST_WARNING_OBJECT (nice, "Could not set send receive size : %s",
205 gerror->message);
206 g_clear_error (&gerror);
207 }
208 #endif
209 }
210 g_ptr_array_unref (sockets);
211 g_object_unref (agent);
212 }
213
214
215 static void
_on_new_selected_pair(NiceAgent * agent,guint stream_id,NiceComponentType component,NiceCandidate * lcandidate,NiceCandidate * rcandidate,GstWebRTCNiceTransport * nice)216 _on_new_selected_pair (NiceAgent * agent, guint stream_id,
217 NiceComponentType component, NiceCandidate * lcandidate,
218 NiceCandidate * rcandidate, GstWebRTCNiceTransport * nice)
219 {
220 GstWebRTCICETransport *ice = GST_WEBRTC_ICE_TRANSPORT (nice);
221 GstWebRTCICEComponent comp = _nice_component_to_gst (component);
222 guint our_stream_id;
223
224 g_object_get (nice->stream, "stream-id", &our_stream_id, NULL);
225
226 if (stream_id != our_stream_id)
227 return;
228 if (comp != ice->component)
229 return;
230
231 gst_webrtc_ice_transport_selected_pair_change (ice);
232 }
233
234 static void
_on_component_state_changed(NiceAgent * agent,guint stream_id,NiceComponentType component,NiceComponentState state,GstWebRTCNiceTransport * nice)235 _on_component_state_changed (NiceAgent * agent, guint stream_id,
236 NiceComponentType component, NiceComponentState state,
237 GstWebRTCNiceTransport * nice)
238 {
239 GstWebRTCICETransport *ice = GST_WEBRTC_ICE_TRANSPORT (nice);
240 GstWebRTCICEComponent comp = _nice_component_to_gst (component);
241 guint our_stream_id;
242
243 g_object_get (nice->stream, "stream-id", &our_stream_id, NULL);
244
245 if (stream_id != our_stream_id)
246 return;
247 if (comp != ice->component)
248 return;
249
250 GST_DEBUG_OBJECT (ice, "%u %u %s", stream_id, component,
251 nice_component_state_to_string (state));
252
253 gst_webrtc_ice_transport_connection_state_change (ice,
254 _nice_component_state_to_gst (state));
255 }
256
257 static void
gst_webrtc_nice_transport_constructed(GObject * object)258 gst_webrtc_nice_transport_constructed (GObject * object)
259 {
260 GstWebRTCNiceTransport *nice = GST_WEBRTC_NICE_TRANSPORT (object);
261 GstWebRTCICETransport *ice = GST_WEBRTC_ICE_TRANSPORT (object);
262 NiceComponentType component = _gst_component_to_nice (ice->component);
263 gboolean controlling_mode;
264 guint our_stream_id;
265 NiceAgent *agent;
266
267 g_object_get (nice->stream, "stream-id", &our_stream_id, NULL);
268 g_object_get (nice->stream->ice, "agent", &agent, NULL);
269
270 g_object_get (agent, "controlling-mode", &controlling_mode, NULL);
271 ice->role =
272 controlling_mode ? GST_WEBRTC_ICE_ROLE_CONTROLLING :
273 GST_WEBRTC_ICE_ROLE_CONTROLLED;
274
275 g_signal_connect (agent, "component-state-changed",
276 G_CALLBACK (_on_component_state_changed), nice);
277 g_signal_connect (agent, "new-selected-pair-full",
278 G_CALLBACK (_on_new_selected_pair), nice);
279
280 ice->src = gst_element_factory_make ("nicesrc", NULL);
281 if (ice->src) {
282 g_object_set (ice->src, "agent", agent, "stream", our_stream_id,
283 "component", component, NULL);
284 }
285 ice->sink = gst_element_factory_make ("nicesink", NULL);
286 if (ice->sink) {
287 g_object_set (ice->sink, "agent", agent, "stream", our_stream_id,
288 "component", component, "async", FALSE, "enable-last-sample", FALSE,
289 "sync", FALSE, NULL);
290 }
291
292 g_object_unref (agent);
293
294 G_OBJECT_CLASS (parent_class)->constructed (object);
295 }
296
297 static void
gst_webrtc_nice_transport_class_init(GstWebRTCNiceTransportClass * klass)298 gst_webrtc_nice_transport_class_init (GstWebRTCNiceTransportClass * klass)
299 {
300 GObjectClass *gobject_class = (GObjectClass *) klass;
301
302 gobject_class->constructed = gst_webrtc_nice_transport_constructed;
303 gobject_class->get_property = gst_webrtc_nice_transport_get_property;
304 gobject_class->set_property = gst_webrtc_nice_transport_set_property;
305 gobject_class->finalize = gst_webrtc_nice_transport_finalize;
306
307 g_object_class_install_property (gobject_class,
308 PROP_STREAM,
309 g_param_spec_object ("stream",
310 "WebRTC ICE Stream", "ICE stream associated with this transport",
311 GST_TYPE_WEBRTC_ICE_STREAM,
312 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
313
314 /**
315 * GstWebRTCNiceTransport:send-buffer-size:
316 *
317 * Size of the kernel send buffer in bytes, 0=default
318 *
319 * Since: 1.20
320 */
321
322 g_object_class_install_property (G_OBJECT_CLASS (klass),
323 PROP_SEND_BUFFER_SIZE, g_param_spec_int ("send-buffer-size",
324 "Send Buffer Size",
325 "Size of the kernel send buffer in bytes, 0=default", 0, G_MAXINT, 0,
326 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
327
328 /**
329 * GstWebRTCNiceTransport:receive-buffer-size:
330 *
331 * Size of the kernel receive buffer in bytes, 0=default
332 *
333 * Since: 1.20
334 */
335
336 g_object_class_install_property (G_OBJECT_CLASS (klass),
337 PROP_RECEIVE_BUFFER_SIZE, g_param_spec_int ("receive-buffer-size",
338 "Receive Buffer Size",
339 "Size of the kernel receive buffer in bytes, 0=default", 0, G_MAXINT,
340 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
341 }
342
343 static void
gst_webrtc_nice_transport_init(GstWebRTCNiceTransport * nice)344 gst_webrtc_nice_transport_init (GstWebRTCNiceTransport * nice)
345 {
346 nice->priv = gst_webrtc_nice_transport_get_instance_private (nice);
347 }
348
349 GstWebRTCNiceTransport *
gst_webrtc_nice_transport_new(GstWebRTCICEStream * stream,GstWebRTCICEComponent component)350 gst_webrtc_nice_transport_new (GstWebRTCICEStream * stream,
351 GstWebRTCICEComponent component)
352 {
353 return g_object_new (GST_TYPE_WEBRTC_NICE_TRANSPORT, "stream", stream,
354 "component", component, NULL);
355 }
356