• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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