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 "icestream.h"
25 #include "nicetransport.h"
26
27 #define GST_CAT_DEFAULT gst_webrtc_ice_stream_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_ICE,
40 PROP_STREAM_ID,
41 };
42
43 //static guint gst_webrtc_ice_stream_signals[LAST_SIGNAL] = { 0 };
44
45 struct _GstWebRTCICEStreamPrivate
46 {
47 gboolean gathered;
48 GList *transports;
49 gboolean gathering_started;
50 };
51
52 #define gst_webrtc_ice_stream_parent_class parent_class
53 G_DEFINE_TYPE_WITH_CODE (GstWebRTCICEStream, gst_webrtc_ice_stream,
54 GST_TYPE_OBJECT, G_ADD_PRIVATE (GstWebRTCICEStream)
55 GST_DEBUG_CATEGORY_INIT (gst_webrtc_ice_stream_debug,
56 "webrtcicestream", 0, "webrtcicestream"););
57
58 static void
gst_webrtc_ice_stream_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)59 gst_webrtc_ice_stream_set_property (GObject * object, guint prop_id,
60 const GValue * value, GParamSpec * pspec)
61 {
62 GstWebRTCICEStream *stream = GST_WEBRTC_ICE_STREAM (object);
63
64 switch (prop_id) {
65 case PROP_ICE:
66 /* XXX: weak-ref this? */
67 stream->ice = g_value_get_object (value);
68 break;
69 case PROP_STREAM_ID:
70 stream->stream_id = g_value_get_uint (value);
71 break;
72 default:
73 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
74 break;
75 }
76 }
77
78 static void
gst_webrtc_ice_stream_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)79 gst_webrtc_ice_stream_get_property (GObject * object, guint prop_id,
80 GValue * value, GParamSpec * pspec)
81 {
82 GstWebRTCICEStream *stream = GST_WEBRTC_ICE_STREAM (object);
83
84 switch (prop_id) {
85 case PROP_ICE:
86 g_value_set_object (value, stream->ice);
87 break;
88 case PROP_STREAM_ID:
89 g_value_set_uint (value, stream->stream_id);
90 break;
91 default:
92 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
93 break;
94 }
95 }
96
97 static void
gst_webrtc_ice_stream_finalize(GObject * object)98 gst_webrtc_ice_stream_finalize (GObject * object)
99 {
100 GstWebRTCICEStream *stream = GST_WEBRTC_ICE_STREAM (object);
101
102 g_list_free (stream->priv->transports);
103 stream->priv->transports = NULL;
104
105 G_OBJECT_CLASS (parent_class)->finalize (object);
106 }
107
108 static void
_on_candidate_gathering_done(NiceAgent * agent,guint stream_id,GstWebRTCICEStream * ice)109 _on_candidate_gathering_done (NiceAgent * agent, guint stream_id,
110 GstWebRTCICEStream * ice)
111 {
112 GList *l;
113
114 if (stream_id != ice->stream_id)
115 return;
116
117 GST_DEBUG_OBJECT (ice, "%u gathering done", stream_id);
118
119 ice->priv->gathered = TRUE;
120
121 for (l = ice->priv->transports; l; l = l->next) {
122 GstWebRTCICETransport *ice = l->data;
123
124 gst_webrtc_ice_transport_gathering_state_change (ice,
125 GST_WEBRTC_ICE_GATHERING_STATE_COMPLETE);
126 }
127 }
128
129 GstWebRTCICETransport *
gst_webrtc_ice_stream_find_transport(GstWebRTCICEStream * stream,GstWebRTCICEComponent component)130 gst_webrtc_ice_stream_find_transport (GstWebRTCICEStream * stream,
131 GstWebRTCICEComponent component)
132 {
133 GstWebRTCICEComponent trans_comp;
134 GstWebRTCICETransport *ret;
135 GList *l;
136
137 g_return_val_if_fail (GST_IS_WEBRTC_ICE_STREAM (stream), NULL);
138
139 for (l = stream->priv->transports; l; l = l->next) {
140 GstWebRTCICETransport *trans = l->data;
141 g_object_get (trans, "component", &trans_comp, NULL);
142
143 if (component == trans_comp)
144 return gst_object_ref (trans);
145 }
146
147 ret =
148 GST_WEBRTC_ICE_TRANSPORT (gst_webrtc_nice_transport_new (stream,
149 component));
150 stream->priv->transports = g_list_prepend (stream->priv->transports, ret);
151
152 return ret;
153 }
154
155 static void
gst_webrtc_ice_stream_constructed(GObject * object)156 gst_webrtc_ice_stream_constructed (GObject * object)
157 {
158 GstWebRTCICEStream *stream = GST_WEBRTC_ICE_STREAM (object);
159 NiceAgent *agent;
160
161 g_object_get (stream->ice, "agent", &agent, NULL);
162 g_signal_connect (agent, "candidate-gathering-done",
163 G_CALLBACK (_on_candidate_gathering_done), stream);
164
165 g_object_unref (agent);
166
167 G_OBJECT_CLASS (parent_class)->constructed (object);
168 }
169
170 gboolean
gst_webrtc_ice_stream_gather_candidates(GstWebRTCICEStream * stream)171 gst_webrtc_ice_stream_gather_candidates (GstWebRTCICEStream * stream)
172 {
173 NiceAgent *agent;
174 GList *l;
175
176 g_return_val_if_fail (GST_IS_WEBRTC_ICE_STREAM (stream), FALSE);
177
178 GST_DEBUG_OBJECT (stream, "start gathering candidates");
179
180 if (stream->priv->gathered)
181 return TRUE;
182
183 for (l = stream->priv->transports; l; l = l->next) {
184 GstWebRTCICETransport *trans = l->data;
185
186 gst_webrtc_ice_transport_gathering_state_change (trans,
187 GST_WEBRTC_ICE_GATHERING_STATE_GATHERING);
188 }
189
190 g_object_get (stream->ice, "agent", &agent, NULL);
191
192 if (!stream->priv->gathering_started) {
193 if (stream->ice->min_rtp_port != 0 || stream->ice->max_rtp_port != 65535) {
194 if (stream->ice->min_rtp_port > stream->ice->max_rtp_port) {
195 GST_ERROR_OBJECT (stream->ice,
196 "invalid port range: min-rtp-port %d must be <= max-rtp-port %d",
197 stream->ice->min_rtp_port, stream->ice->max_rtp_port);
198 return FALSE;
199 }
200
201 nice_agent_set_port_range (agent, stream->stream_id,
202 NICE_COMPONENT_TYPE_RTP, stream->ice->min_rtp_port,
203 stream->ice->max_rtp_port);
204 }
205 /* mark as gathering started to prevent changing ports again */
206 stream->priv->gathering_started = TRUE;
207 }
208
209 if (!nice_agent_gather_candidates (agent, stream->stream_id)) {
210 g_object_unref (agent);
211 return FALSE;
212 }
213
214 for (l = stream->priv->transports; l; l = l->next) {
215 GstWebRTCNiceTransport *trans = l->data;
216
217 gst_webrtc_nice_transport_update_buffer_size (trans);
218 }
219
220 g_object_unref (agent);
221 return TRUE;
222 }
223
224 static void
gst_webrtc_ice_stream_class_init(GstWebRTCICEStreamClass * klass)225 gst_webrtc_ice_stream_class_init (GstWebRTCICEStreamClass * klass)
226 {
227 GObjectClass *gobject_class = (GObjectClass *) klass;
228
229 gobject_class->constructed = gst_webrtc_ice_stream_constructed;
230 gobject_class->get_property = gst_webrtc_ice_stream_get_property;
231 gobject_class->set_property = gst_webrtc_ice_stream_set_property;
232 gobject_class->finalize = gst_webrtc_ice_stream_finalize;
233
234 g_object_class_install_property (gobject_class,
235 PROP_ICE,
236 g_param_spec_object ("ice",
237 "ICE", "ICE agent associated with this stream",
238 GST_TYPE_WEBRTC_ICE,
239 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
240
241 g_object_class_install_property (gobject_class,
242 PROP_STREAM_ID,
243 g_param_spec_uint ("stream-id",
244 "ICE stream id", "ICE stream id associated with this stream",
245 0, G_MAXUINT, 0,
246 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
247 }
248
249 static void
gst_webrtc_ice_stream_init(GstWebRTCICEStream * ice)250 gst_webrtc_ice_stream_init (GstWebRTCICEStream * ice)
251 {
252 ice->priv = gst_webrtc_ice_stream_get_instance_private (ice);
253 }
254
255 GstWebRTCICEStream *
gst_webrtc_ice_stream_new(GstWebRTCICE * ice,guint stream_id)256 gst_webrtc_ice_stream_new (GstWebRTCICE * ice, guint stream_id)
257 {
258 return g_object_new (GST_TYPE_WEBRTC_ICE_STREAM, "ice", ice,
259 "stream-id", stream_id, NULL);
260 }
261