2 * Copyright (C) 2017 Matthew Waters <matthew@centricular.com>
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.
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.
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.
24 #include "nicestream.h"
25 #include "nicetransport.h"
27 #define GST_CAT_DEFAULT gst_webrtc_nice_stream_debug
28 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
36 struct _GstWebRTCNiceStreamPrivate
40 gboolean gathering_started;
41 gulong candidate_gathering_done_id;
45 #define gst_webrtc_nice_stream_parent_class parent_class
46 G_DEFINE_TYPE_WITH_CODE (GstWebRTCNiceStream, gst_webrtc_nice_stream,
47 GST_TYPE_WEBRTC_ICE_STREAM, G_ADD_PRIVATE (GstWebRTCNiceStream)
48 GST_DEBUG_CATEGORY_INIT (gst_webrtc_nice_stream_debug,
49 "webrtcnicestream", 0, "webrtcnicestream"););
52 gst_webrtc_nice_stream_set_property (GObject * object, guint prop_id,
53 const GValue * value, GParamSpec * pspec)
55 GstWebRTCNiceStream *stream = GST_WEBRTC_NICE_STREAM (object);
59 g_weak_ref_set (&stream->priv->ice_weak, g_value_get_object (value));
62 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
68 gst_webrtc_nice_stream_get_property (GObject * object, guint prop_id,
69 GValue * value, GParamSpec * pspec)
71 GstWebRTCNiceStream *stream = GST_WEBRTC_NICE_STREAM (object);
75 g_value_take_object (value, g_weak_ref_get (&stream->priv->ice_weak));
78 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
84 gst_webrtc_nice_stream_finalize (GObject * object)
86 GstWebRTCNiceStream *stream = GST_WEBRTC_NICE_STREAM (object);
87 GstWebRTCNice *ice = g_weak_ref_get (&stream->priv->ice_weak);
91 g_object_get (ice, "agent", &agent, NULL);
93 if (stream->priv->candidate_gathering_done_id != 0) {
94 g_signal_handler_disconnect (agent,
95 stream->priv->candidate_gathering_done_id);
98 g_object_unref (agent);
99 gst_object_unref (ice);
102 g_list_free (stream->priv->transports);
103 stream->priv->transports = NULL;
105 g_weak_ref_clear (&stream->priv->ice_weak);
107 G_OBJECT_CLASS (parent_class)->finalize (object);
111 _on_candidate_gathering_done (NiceAgent * agent, guint stream_id,
114 GstWebRTCNiceStream *ice = g_weak_ref_get (ice_weak);
120 if (stream_id != GST_WEBRTC_ICE_STREAM (ice)->stream_id)
123 GST_DEBUG_OBJECT (ice, "%u gathering done", stream_id);
125 ice->priv->gathered = TRUE;
127 for (l = ice->priv->transports; l; l = l->next) {
128 GstWebRTCICETransport *ice = l->data;
130 gst_webrtc_ice_transport_gathering_state_change (ice,
131 GST_WEBRTC_ICE_GATHERING_STATE_COMPLETE);
135 gst_object_unref (ice);
138 static GstWebRTCICETransport *
139 gst_webrtc_nice_stream_find_transport (GstWebRTCICEStream * stream,
140 GstWebRTCICEComponent component)
142 GstWebRTCICEComponent trans_comp;
143 GstWebRTCICETransport *ret;
145 GstWebRTCNiceStream *nice_stream = GST_WEBRTC_NICE_STREAM (stream);
147 for (l = nice_stream->priv->transports; l; l = l->next) {
148 GstWebRTCICETransport *trans = l->data;
149 g_object_get (trans, "component", &trans_comp, NULL);
151 if (component == trans_comp)
152 return gst_object_ref (trans);
156 GST_WEBRTC_ICE_TRANSPORT (gst_webrtc_nice_transport_new (nice_stream,
158 nice_stream->priv->transports =
159 g_list_prepend (nice_stream->priv->transports, ret);
165 weak_new (GstWebRTCNiceStream * stream)
167 GWeakRef *weak = g_new0 (GWeakRef, 1);
168 g_weak_ref_init (weak, stream);
173 weak_free (GWeakRef * weak)
175 g_weak_ref_clear (weak);
180 gst_webrtc_nice_stream_constructed (GObject * object)
182 GstWebRTCNiceStream *stream;
186 G_OBJECT_CLASS (parent_class)->constructed (object);
188 stream = GST_WEBRTC_NICE_STREAM (object);
189 ice = g_weak_ref_get (&stream->priv->ice_weak);
192 g_assert (ice != NULL);
193 g_object_get (ice, "agent", &agent, NULL);
194 stream->priv->candidate_gathering_done_id = g_signal_connect_data (agent,
195 "candidate-gathering-done", G_CALLBACK (_on_candidate_gathering_done),
196 weak_new (stream), (GClosureNotify) weak_free, (GConnectFlags) 0);
198 g_object_unref (agent);
199 gst_object_unref (ice);
203 gst_webrtc_nice_stream_gather_candidates (GstWebRTCICEStream * stream)
209 GstWebRTCNiceStream *nice_stream = GST_WEBRTC_NICE_STREAM (stream);
211 GST_DEBUG_OBJECT (nice_stream, "start gathering candidates");
213 if (nice_stream->priv->gathered)
216 for (l = nice_stream->priv->transports; l; l = l->next) {
217 GstWebRTCICETransport *trans = l->data;
219 gst_webrtc_ice_transport_gathering_state_change (trans,
220 GST_WEBRTC_ICE_GATHERING_STATE_GATHERING);
223 ice = GST_WEBRTC_ICE (g_weak_ref_get (&nice_stream->priv->ice_weak));
224 g_assert (ice != NULL);
226 g_object_get (ice, "agent", &agent, NULL);
228 if (!nice_stream->priv->gathering_started) {
229 if (ice->min_rtp_port != 0 || ice->max_rtp_port != 65535) {
230 if (ice->min_rtp_port > ice->max_rtp_port) {
231 GST_ERROR_OBJECT (ice,
232 "invalid port range: min-rtp-port %d must be <= max-rtp-port %d",
233 ice->min_rtp_port, ice->max_rtp_port);
238 nice_agent_set_port_range (agent, stream->stream_id,
239 NICE_COMPONENT_TYPE_RTP, ice->min_rtp_port, ice->max_rtp_port);
241 /* mark as gathering started to prevent changing ports again */
242 nice_stream->priv->gathering_started = TRUE;
245 if (!nice_agent_gather_candidates (agent, stream->stream_id)) {
250 for (l = nice_stream->priv->transports; l; l = l->next) {
251 GstWebRTCNiceTransport *trans = l->data;
253 gst_webrtc_nice_transport_update_buffer_size (trans);
258 g_object_unref (agent);
260 gst_object_unref (ice);
266 gst_webrtc_nice_stream_class_init (GstWebRTCNiceStreamClass * klass)
268 GObjectClass *gobject_class = (GObjectClass *) klass;
269 GstWebRTCICEStreamClass *gst_webrtc_ice_stream_class =
270 GST_WEBRTC_ICE_STREAM_CLASS (klass);
272 gst_webrtc_ice_stream_class->find_transport =
273 gst_webrtc_nice_stream_find_transport;
274 gst_webrtc_ice_stream_class->gather_candidates =
275 gst_webrtc_nice_stream_gather_candidates;
277 gobject_class->constructed = gst_webrtc_nice_stream_constructed;
278 gobject_class->get_property = gst_webrtc_nice_stream_get_property;
279 gobject_class->set_property = gst_webrtc_nice_stream_set_property;
280 gobject_class->finalize = gst_webrtc_nice_stream_finalize;
282 g_object_class_install_property (gobject_class,
284 g_param_spec_object ("ice",
285 "ICE", "ICE agent associated with this stream",
287 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
291 gst_webrtc_nice_stream_init (GstWebRTCNiceStream * stream)
293 stream->priv = gst_webrtc_nice_stream_get_instance_private (stream);
295 g_weak_ref_init (&stream->priv->ice_weak, NULL);
298 GstWebRTCNiceStream *
299 gst_webrtc_nice_stream_new (GstWebRTCICE * ice, guint stream_id)
301 return g_object_new (GST_TYPE_WEBRTC_NICE_STREAM, "ice", ice,
302 "stream-id", stream_id, NULL);