oups, this caused non-msn calls to fail
[sipe-libnice.git] / gst / gstnicesrc.c
blob37aabbfdd40b6e23ffaac9a2f515458977c99ae6
1 /*
2 * This file is part of the Nice GLib ICE library.
4 * (C) 2006, 2007 Collabora Ltd.
5 * Contact: Dafydd Harries
6 * (C) 2006, 2007 Nokia Corporation. All rights reserved.
7 * Contact: Kai Vehmanen
9 * The contents of this file are subject to the Mozilla Public License Version
10 * 1.1 (the "License"); you may not use this file except in compliance with
11 * the License. You may obtain a copy of the License at
12 * http://www.mozilla.org/MPL/
14 * Software distributed under the License is distributed on an "AS IS" basis,
15 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
16 * for the specific language governing rights and limitations under the
17 * License.
19 * The Original Code is the Nice GLib ICE library.
21 * The Initial Developers of the Original Code are Collabora Ltd and Nokia
22 * Corporation. All Rights Reserved.
24 * Contributors:
25 * Dafydd Harries, Collabora Ltd.
27 * Alternatively, the contents of this file may be used under the terms of the
28 * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
29 * case the provisions of LGPL are applicable instead of those above. If you
30 * wish to allow use of your version of this file only under the terms of the
31 * LGPL and not to allow others to use your version of this file under the
32 * MPL, indicate your decision by deleting the provisions above and replace
33 * them with the notice and other provisions required by the LGPL. If you do
34 * not delete the provisions above, a recipient may use your version of this
35 * file under either the MPL or the LGPL.
37 #ifdef HAVE_CONFIG_H
38 # include "config.h"
39 #endif
41 #include <string.h>
43 #include "gstnicesrc.h"
45 GST_DEBUG_CATEGORY_STATIC (nicesrc_debug);
46 #define GST_CAT_DEFAULT nicesrc_debug
49 #define BUFFER_SIZE (65536)
51 static GstFlowReturn
52 gst_nice_src_create (
53 GstBaseSrc *basesrc,
54 guint64 offset,
55 guint length,
56 GstBuffer **buffer);
58 static gboolean
59 gst_nice_src_unlock (
60 GstBaseSrc *basesrc);
62 static gboolean
63 gst_nice_src_unlock_stop (
64 GstBaseSrc *basesrc);
66 static void
67 gst_nice_src_set_property (
68 GObject *object,
69 guint prop_id,
70 const GValue *value,
71 GParamSpec *pspec);
73 static void
74 gst_nice_src_get_property (
75 GObject *object,
76 guint prop_id,
77 GValue *value,
78 GParamSpec *pspec);
81 static void
82 gst_nice_src_dispose (GObject *object);
84 static GstStateChangeReturn
85 gst_nice_src_change_state (
86 GstElement * element,
87 GstStateChange transition);
89 static const GstElementDetails gst_nice_src_details =
90 GST_ELEMENT_DETAILS (
91 "ICE source",
92 "Source",
93 "Interactive UDP connectivity establishment",
94 "Dafydd Harries <dafydd.harries@collabora.co.uk>");
96 static GstStaticPadTemplate gst_nice_src_src_template =
97 GST_STATIC_PAD_TEMPLATE (
98 "src",
99 GST_PAD_SRC,
100 GST_PAD_ALWAYS,
101 GST_STATIC_CAPS_ANY);
103 GST_BOILERPLATE (GstNiceSrc, gst_nice_src, GstBaseSrc, GST_TYPE_BASE_SRC);
105 enum
107 PROP_AGENT = 1,
108 PROP_STREAM,
109 PROP_COMPONENT
112 static void
113 gst_nice_src_base_init (gpointer g_class)
115 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
117 gst_element_class_add_pad_template (element_class,
118 gst_static_pad_template_get (&gst_nice_src_src_template));
119 gst_element_class_set_details (element_class, &gst_nice_src_details);
122 static void
123 gst_nice_src_class_init (GstNiceSrcClass *klass)
125 GstBaseSrcClass *gstbasesrc_class;
126 GstElementClass *gstelement_class;
127 GObjectClass *gobject_class;
129 GST_DEBUG_CATEGORY_INIT (nicesrc_debug, "nicesrc",
130 0, "libnice source");
132 gstbasesrc_class = (GstBaseSrcClass *) klass;
133 gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_nice_src_create);
134 gstbasesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_nice_src_unlock);
135 gstbasesrc_class->unlock_stop = GST_DEBUG_FUNCPTR (gst_nice_src_unlock_stop);
137 gobject_class = (GObjectClass *) klass;
138 gobject_class->set_property = gst_nice_src_set_property;
139 gobject_class->get_property = gst_nice_src_get_property;
140 gobject_class->dispose = gst_nice_src_dispose;
142 gstelement_class = (GstElementClass *) klass;
143 gstelement_class->change_state = gst_nice_src_change_state;
145 g_object_class_install_property (gobject_class, PROP_AGENT,
146 g_param_spec_object (
147 "agent",
148 "Agent",
149 "The NiceAgent this source is bound to",
150 NICE_TYPE_AGENT,
151 G_PARAM_READWRITE));
153 g_object_class_install_property (gobject_class, PROP_STREAM,
154 g_param_spec_uint (
155 "stream",
156 "Stream ID",
157 "The ID of the stream to read from",
159 G_MAXUINT,
161 G_PARAM_READWRITE));
163 g_object_class_install_property (gobject_class, PROP_COMPONENT,
164 g_param_spec_uint (
165 "component",
166 "Component ID",
167 "The ID of the component to read from",
169 G_MAXUINT,
171 G_PARAM_READWRITE));
174 static void
175 gst_nice_src_init (GstNiceSrc *src, GstNiceSrcClass *g_class)
177 gst_base_src_set_live (GST_BASE_SRC (src), TRUE);
178 gst_base_src_set_format (GST_BASE_SRC (src), GST_FORMAT_TIME);
179 gst_base_src_set_do_timestamp (GST_BASE_SRC (src), TRUE);
180 src->agent = NULL;
181 src->stream_id = 0;
182 src->component_id = 0;
183 src->mainloop = g_main_loop_new (g_main_context_new (), FALSE);
184 src->unlocked = FALSE;
185 src->idle_source = NULL;
188 static void
189 gst_nice_src_read_callback (NiceAgent *agent,
190 guint stream_id,
191 guint component_id,
192 guint len,
193 gchar *buf,
194 gpointer data)
196 GstBaseSrc *basesrc = GST_BASE_SRC (data);
197 GstNiceSrc *nicesrc = GST_NICE_SRC (basesrc);
199 GST_LOG_OBJECT (agent, "Got buffer, getting out of the main loop");
201 nicesrc->flow_ret = gst_pad_alloc_buffer (basesrc->srcpad, nicesrc->offset,
202 len, GST_PAD_CAPS (basesrc->srcpad), &nicesrc->outbuf);
203 if (nicesrc->flow_ret == GST_FLOW_OK) {
204 memcpy (nicesrc->outbuf->data, buf, len);
205 nicesrc->outbuf->size = len;
208 g_main_loop_quit (nicesrc->mainloop);
211 static gboolean
212 gst_nice_src_unlock_idler (gpointer data)
214 GstNiceSrc *nicesrc = GST_NICE_SRC (data);
216 GST_OBJECT_LOCK (nicesrc);
217 if (nicesrc->unlocked)
218 g_main_loop_quit (nicesrc->mainloop);
220 if (nicesrc->idle_source) {
221 g_source_unref (nicesrc->idle_source);
222 nicesrc->idle_source = NULL;
224 GST_OBJECT_UNLOCK (nicesrc);
226 return FALSE;
229 static gboolean
230 gst_nice_src_unlock (GstBaseSrc *src)
232 GstNiceSrc *nicesrc = GST_NICE_SRC (src);
234 GST_OBJECT_LOCK (src);
235 nicesrc->unlocked = TRUE;
237 g_main_loop_quit (nicesrc->mainloop);
239 nicesrc->idle_source = g_idle_source_new ();
240 g_source_set_priority (nicesrc->idle_source, G_PRIORITY_HIGH);
241 g_source_set_callback (nicesrc->idle_source, gst_nice_src_unlock_idler, src, NULL);
242 g_source_attach (nicesrc->idle_source, g_main_loop_get_context (nicesrc->mainloop));
243 GST_OBJECT_UNLOCK (src);
245 return TRUE;
248 static gboolean
249 gst_nice_src_unlock_stop (GstBaseSrc *src)
251 GstNiceSrc *nicesrc = GST_NICE_SRC (src);
253 GST_OBJECT_LOCK (src);
254 nicesrc->unlocked = FALSE;
255 if (nicesrc->idle_source)
256 g_source_destroy (nicesrc->idle_source);
257 nicesrc->idle_source = NULL;
258 GST_OBJECT_UNLOCK (src);
260 return TRUE;
263 static GstFlowReturn
264 gst_nice_src_create (
265 GstBaseSrc *basesrc,
266 guint64 offset,
267 guint length,
268 GstBuffer **buffer)
270 GstNiceSrc *nicesrc = GST_NICE_SRC (basesrc);
272 GST_LOG_OBJECT (nicesrc, "create called");
274 nicesrc->outbuf = NULL;
275 nicesrc->offset = offset;
277 GST_OBJECT_LOCK (basesrc);
278 if (nicesrc->unlocked) {
279 GST_OBJECT_UNLOCK (basesrc);
280 return GST_FLOW_WRONG_STATE;
282 GST_OBJECT_UNLOCK (basesrc);
284 g_main_loop_run (nicesrc->mainloop);
286 if (nicesrc->outbuf) {
287 GST_LOG_OBJECT (nicesrc, "Got buffer, pushing");
289 *buffer = nicesrc->outbuf;
290 return nicesrc->flow_ret;
291 } else {
292 GST_LOG_OBJECT (nicesrc, "Got interrupting, returning wrong-state");
293 return GST_FLOW_WRONG_STATE;
298 static void
299 gst_nice_src_dispose (GObject *object)
301 GstNiceSrc *src = GST_NICE_SRC (object);
303 if (src->agent)
304 g_object_unref (src->agent);
305 src->agent = NULL;
307 if (src->mainloop)
308 g_main_loop_unref (src->mainloop);
309 src->mainloop = NULL;
311 GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
314 static void
315 gst_nice_src_set_property (
316 GObject *object,
317 guint prop_id,
318 const GValue *value,
319 GParamSpec *pspec)
321 GstNiceSrc *src = GST_NICE_SRC (object);
323 switch (prop_id)
325 case PROP_AGENT:
326 if (src->agent)
327 GST_ERROR_OBJECT (object,
328 "Changing the agent on a nice src not allowed");
329 else
330 src->agent = g_value_dup_object (value);
331 break;
333 case PROP_STREAM:
334 src->stream_id = g_value_get_uint (value);
335 break;
337 case PROP_COMPONENT:
338 src->component_id = g_value_get_uint (value);
339 break;
341 default:
342 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
343 break;
347 static void
348 gst_nice_src_get_property (
349 GObject *object,
350 guint prop_id,
351 GValue *value,
352 GParamSpec *pspec)
354 GstNiceSrc *src = GST_NICE_SRC (object);
356 switch (prop_id)
358 case PROP_AGENT:
359 g_value_set_object (value, src->agent);
360 break;
362 case PROP_STREAM:
363 g_value_set_uint (value, src->stream_id);
364 break;
366 case PROP_COMPONENT:
367 g_value_set_uint (value, src->component_id);
368 break;
370 default:
371 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
372 break;
376 static GstStateChangeReturn
377 gst_nice_src_change_state (GstElement * element, GstStateChange transition)
379 GstNiceSrc *src;
380 GstStateChangeReturn ret;
382 src = GST_NICE_SRC (element);
384 switch (transition) {
385 case GST_STATE_CHANGE_NULL_TO_READY:
386 if (src->agent == NULL || src->stream_id == 0 || src->component_id == 0)
388 GST_ERROR_OBJECT (element,
389 "Trying to start Nice source without an agent set");
390 return GST_STATE_CHANGE_FAILURE;
392 else
394 nice_agent_attach_recv (src->agent, src->stream_id, src->component_id,
395 g_main_loop_get_context (src->mainloop),
396 gst_nice_src_read_callback, (gpointer) src);
398 break;
399 case GST_STATE_CHANGE_READY_TO_NULL:
400 nice_agent_attach_recv (src->agent, src->stream_id, src->component_id,
401 g_main_loop_get_context (src->mainloop), NULL, NULL);
402 break;
403 default:
404 break;
407 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
409 return ret;