• 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 "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