webrtcbin: an element that handles the transport aspects of webrtc connections
[platform/upstream/gst-plugins-bad.git] / ext / webrtc / 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 "nicetransport.h"
25 #include "icestream.h"
26
27 #define GST_CAT_DEFAULT gst_webrtc_nice_transport_debug
28 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
29
30 #define gst_webrtc_nice_transport_parent_class parent_class
31 G_DEFINE_TYPE_WITH_CODE (GstWebRTCNiceTransport, gst_webrtc_nice_transport,
32     GST_TYPE_WEBRTC_ICE_TRANSPORT,
33     GST_DEBUG_CATEGORY_INIT (gst_webrtc_nice_transport_debug,
34         "webrtcnicetransport", 0, "webrtcnicetransport");
35     );
36
37 enum
38 {
39   SIGNAL_0,
40   LAST_SIGNAL,
41 };
42
43 enum
44 {
45   PROP_0,
46   PROP_STREAM,
47 };
48
49 //static guint gst_webrtc_nice_transport_signals[LAST_SIGNAL] = { 0 };
50
51 struct _GstWebRTCNiceTransportPrivate
52 {
53   gboolean running;
54 };
55
56 static NiceComponentType
57 _gst_component_to_nice (GstWebRTCICEComponent component)
58 {
59   switch (component) {
60     case GST_WEBRTC_ICE_COMPONENT_RTP:
61       return NICE_COMPONENT_TYPE_RTP;
62     case GST_WEBRTC_ICE_COMPONENT_RTCP:
63       return NICE_COMPONENT_TYPE_RTCP;
64     default:
65       g_assert_not_reached ();
66       return 0;
67   }
68 }
69
70 static GstWebRTCICEComponent
71 _nice_component_to_gst (NiceComponentType component)
72 {
73   switch (component) {
74     case NICE_COMPONENT_TYPE_RTP:
75       return GST_WEBRTC_ICE_COMPONENT_RTP;
76     case NICE_COMPONENT_TYPE_RTCP:
77       return GST_WEBRTC_ICE_COMPONENT_RTCP;
78     default:
79       g_assert_not_reached ();
80       return 0;
81   }
82 }
83
84 static GstWebRTCICEConnectionState
85 _nice_component_state_to_gst (NiceComponentState state)
86 {
87   switch (state) {
88     case NICE_COMPONENT_STATE_DISCONNECTED:
89       return GST_WEBRTC_ICE_CONNECTION_STATE_DISCONNECTED;
90     case NICE_COMPONENT_STATE_GATHERING:
91       return GST_WEBRTC_ICE_CONNECTION_STATE_NEW;
92     case NICE_COMPONENT_STATE_CONNECTING:
93       return GST_WEBRTC_ICE_CONNECTION_STATE_CHECKING;
94     case NICE_COMPONENT_STATE_CONNECTED:
95       return GST_WEBRTC_ICE_CONNECTION_STATE_CONNECTED;
96     case NICE_COMPONENT_STATE_READY:
97       return GST_WEBRTC_ICE_CONNECTION_STATE_COMPLETED;
98     case NICE_COMPONENT_STATE_FAILED:
99       return GST_WEBRTC_ICE_CONNECTION_STATE_FAILED;
100     default:
101       g_assert_not_reached ();
102       return 0;
103   }
104 }
105
106 static void
107 gst_webrtc_nice_transport_set_property (GObject * object, guint prop_id,
108     const GValue * value, GParamSpec * pspec)
109 {
110   GstWebRTCNiceTransport *nice = GST_WEBRTC_NICE_TRANSPORT (object);
111
112   switch (prop_id) {
113     case PROP_STREAM:
114       if (nice->stream)
115         gst_object_unref (nice->stream);
116       nice->stream = g_value_dup_object (value);
117       break;
118     default:
119       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
120       break;
121   }
122 }
123
124 static void
125 gst_webrtc_nice_transport_get_property (GObject * object, guint prop_id,
126     GValue * value, GParamSpec * pspec)
127 {
128   GstWebRTCNiceTransport *nice = GST_WEBRTC_NICE_TRANSPORT (object);
129
130   switch (prop_id) {
131     case PROP_STREAM:
132       g_value_set_object (value, nice->stream);
133       break;
134     default:
135       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
136       break;
137   }
138 }
139
140 static void
141 gst_webrtc_nice_transport_finalize (GObject * object)
142 {
143   GstWebRTCNiceTransport *nice = GST_WEBRTC_NICE_TRANSPORT (object);
144
145   gst_object_unref (nice->stream);
146
147   G_OBJECT_CLASS (parent_class)->finalize (object);
148 }
149
150 static void
151 _on_new_selected_pair (NiceAgent * agent, guint stream_id,
152     NiceComponentType component, NiceCandidate * lcandidate,
153     NiceCandidate * rcandidate, GstWebRTCNiceTransport * nice)
154 {
155   GstWebRTCICETransport *ice = GST_WEBRTC_ICE_TRANSPORT (nice);
156   GstWebRTCICEComponent comp = _nice_component_to_gst (component);
157   guint our_stream_id;
158
159   g_object_get (nice->stream, "stream-id", &our_stream_id, NULL);
160
161   if (stream_id != our_stream_id)
162     return;
163   if (comp != ice->component)
164     return;
165
166   gst_webrtc_ice_transport_selected_pair_change (ice);
167 }
168
169 static void
170 _on_component_state_changed (NiceAgent * agent, guint stream_id,
171     NiceComponentType component, NiceComponentState state,
172     GstWebRTCNiceTransport * nice)
173 {
174   GstWebRTCICETransport *ice = GST_WEBRTC_ICE_TRANSPORT (nice);
175   GstWebRTCICEComponent comp = _nice_component_to_gst (component);
176   guint our_stream_id;
177
178   g_object_get (nice->stream, "stream-id", &our_stream_id, NULL);
179
180   if (stream_id != our_stream_id)
181     return;
182   if (comp != ice->component)
183     return;
184
185   GST_DEBUG_OBJECT (ice, "%u %u %s", stream_id, component,
186       nice_component_state_to_string (state));
187
188   gst_webrtc_ice_transport_connection_state_change (ice,
189       _nice_component_state_to_gst (state));
190 }
191
192 static void
193 gst_webrtc_nice_transport_constructed (GObject * object)
194 {
195   GstWebRTCNiceTransport *nice = GST_WEBRTC_NICE_TRANSPORT (object);
196   GstWebRTCICETransport *ice = GST_WEBRTC_ICE_TRANSPORT (object);
197   NiceComponentType component = _gst_component_to_nice (ice->component);
198   gboolean controlling_mode;
199   guint our_stream_id;
200   NiceAgent *agent;
201
202   g_object_get (nice->stream, "stream-id", &our_stream_id, NULL);
203   g_object_get (nice->stream->ice, "agent", &agent, NULL);
204
205   g_object_get (agent, "controlling-mode", &controlling_mode, NULL);
206   ice->role =
207       controlling_mode ? GST_WEBRTC_ICE_ROLE_CONTROLLING :
208       GST_WEBRTC_ICE_ROLE_CONTROLLED;
209
210   g_signal_connect (agent, "component-state-changed",
211       G_CALLBACK (_on_component_state_changed), nice);
212   g_signal_connect (agent, "new-selected-pair-full",
213       G_CALLBACK (_on_new_selected_pair), nice);
214
215   ice->src = gst_element_factory_make ("nicesrc", NULL);
216   if (ice->src) {
217     g_object_set (ice->src, "agent", agent, "stream", our_stream_id,
218         "component", component, NULL);
219   }
220   ice->sink = gst_element_factory_make ("nicesink", NULL);
221   if (ice->sink) {
222     g_object_set (ice->sink, "agent", agent, "stream", our_stream_id,
223         "component", component, "async", FALSE, "enable-last-sample", FALSE,
224         NULL);
225     if (ice->component == GST_WEBRTC_ICE_COMPONENT_RTCP)
226       g_object_set (ice->sink, "sync", FALSE, NULL);
227   }
228
229   g_object_unref (agent);
230
231   G_OBJECT_CLASS (parent_class)->constructed (object);
232 }
233
234 static void
235 gst_webrtc_nice_transport_class_init (GstWebRTCNiceTransportClass * klass)
236 {
237   GObjectClass *gobject_class = (GObjectClass *) klass;
238
239   g_type_class_add_private (klass, sizeof (GstWebRTCNiceTransportPrivate));
240
241   gobject_class->constructed = gst_webrtc_nice_transport_constructed;
242   gobject_class->get_property = gst_webrtc_nice_transport_get_property;
243   gobject_class->set_property = gst_webrtc_nice_transport_set_property;
244   gobject_class->finalize = gst_webrtc_nice_transport_finalize;
245
246   g_object_class_install_property (gobject_class,
247       PROP_STREAM,
248       g_param_spec_object ("stream",
249           "WebRTC ICE Stream", "ICE stream associated with this transport",
250           GST_TYPE_WEBRTC_ICE_STREAM,
251           G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
252 }
253
254 static void
255 gst_webrtc_nice_transport_init (GstWebRTCNiceTransport * nice)
256 {
257   nice->priv =
258       G_TYPE_INSTANCE_GET_PRIVATE ((nice), GST_TYPE_WEBRTC_NICE_TRANSPORT,
259       GstWebRTCNiceTransportPrivate);
260 }
261
262 GstWebRTCNiceTransport *
263 gst_webrtc_nice_transport_new (GstWebRTCICEStream * stream,
264     GstWebRTCICEComponent component)
265 {
266   return g_object_new (GST_TYPE_WEBRTC_NICE_TRANSPORT, "stream", stream,
267       "component", component, NULL);
268 }