Use a Queue in gstnicesrc to avoid multiple read_callbacks overwriting the out buffer
[sipe-libnice.git] / gst / gstnicesrc.c
blobe8c4d0a1c42be1bf75dfc28f611a0e48ead40c33
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->mainctx = g_main_context_new ();
184 src->mainloop = g_main_loop_new (src->mainctx, FALSE);
185 src->unlocked = FALSE;
186 src->idle_source = NULL;
187 src->outbufs = g_queue_new ();
190 static void
191 gst_nice_src_read_callback (NiceAgent *agent,
192 guint stream_id,
193 guint component_id,
194 guint len,
195 gchar *buf,
196 gpointer data)
198 GstBaseSrc *basesrc = GST_BASE_SRC (data);
199 GstNiceSrc *nicesrc = GST_NICE_SRC (basesrc);
200 GstBuffer *buffer = NULL;
202 GST_LOG_OBJECT (agent, "Got buffer, getting out of the main loop");
204 nicesrc->flow_ret = gst_pad_alloc_buffer (basesrc->srcpad, nicesrc->offset,
205 len, GST_PAD_CAPS (basesrc->srcpad), &buffer);
206 if (nicesrc->flow_ret == GST_FLOW_OK) {
207 memcpy (buffer->data, buf, len);
208 buffer->size = len;
209 g_queue_push_tail (nicesrc->outbufs, buffer);
212 g_main_loop_quit (nicesrc->mainloop);
215 static gboolean
216 gst_nice_src_unlock_idler (gpointer data)
218 GstNiceSrc *nicesrc = GST_NICE_SRC (data);
220 GST_OBJECT_LOCK (nicesrc);
221 if (nicesrc->unlocked)
222 g_main_loop_quit (nicesrc->mainloop);
224 if (nicesrc->idle_source) {
225 g_source_destroy (nicesrc->idle_source);
226 g_source_unref (nicesrc->idle_source);
227 nicesrc->idle_source = NULL;
229 GST_OBJECT_UNLOCK (nicesrc);
231 return FALSE;
234 static gboolean
235 gst_nice_src_unlock (GstBaseSrc *src)
237 GstNiceSrc *nicesrc = GST_NICE_SRC (src);
239 GST_OBJECT_LOCK (src);
240 nicesrc->unlocked = TRUE;
242 g_main_loop_quit (nicesrc->mainloop);
244 if (!nicesrc->idle_source) {
245 nicesrc->idle_source = g_idle_source_new ();
246 g_source_set_priority (nicesrc->idle_source, G_PRIORITY_HIGH);
247 g_source_set_callback (nicesrc->idle_source, gst_nice_src_unlock_idler, src, NULL);
248 g_source_attach (nicesrc->idle_source, g_main_loop_get_context (nicesrc->mainloop));
250 GST_OBJECT_UNLOCK (src);
252 return TRUE;
255 static gboolean
256 gst_nice_src_unlock_stop (GstBaseSrc *src)
258 GstNiceSrc *nicesrc = GST_NICE_SRC (src);
260 GST_OBJECT_LOCK (src);
261 nicesrc->unlocked = FALSE;
262 if (nicesrc->idle_source) {
263 g_source_destroy (nicesrc->idle_source);
264 g_source_unref(nicesrc->idle_source);
266 nicesrc->idle_source = NULL;
267 GST_OBJECT_UNLOCK (src);
269 return TRUE;
272 static GstFlowReturn
273 gst_nice_src_create (
274 GstBaseSrc *basesrc,
275 guint64 offset,
276 guint length,
277 GstBuffer **buffer)
279 GstNiceSrc *nicesrc = GST_NICE_SRC (basesrc);
281 GST_LOG_OBJECT (nicesrc, "create called");
283 nicesrc->offset = offset;
285 GST_OBJECT_LOCK (basesrc);
286 if (nicesrc->unlocked) {
287 GST_OBJECT_UNLOCK (basesrc);
288 return GST_FLOW_WRONG_STATE;
290 GST_OBJECT_UNLOCK (basesrc);
292 if (g_queue_is_empty (nicesrc->outbufs))
293 g_main_loop_run (nicesrc->mainloop);
295 *buffer = g_queue_pop_head (nicesrc->outbufs);
296 if (*buffer != NULL) {
297 GST_LOG_OBJECT (nicesrc, "Got buffer, pushing");
298 return nicesrc->flow_ret;
299 } else {
300 GST_LOG_OBJECT (nicesrc, "Got interrupting, returning wrong-state");
301 return GST_FLOW_WRONG_STATE;
306 static void
307 gst_nice_src_dispose (GObject *object)
309 GstNiceSrc *src = GST_NICE_SRC (object);
311 if (src->agent)
312 g_object_unref (src->agent);
313 src->agent = NULL;
315 if (src->mainloop)
316 g_main_loop_unref (src->mainloop);
317 src->mainloop = NULL;
319 if (src->mainctx)
320 g_main_context_unref (src->mainctx);
321 src->mainctx = NULL;
323 if (src->outbufs)
324 g_queue_free (src->outbufs);
325 src->outbufs = NULL;
327 GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
330 static void
331 gst_nice_src_set_property (
332 GObject *object,
333 guint prop_id,
334 const GValue *value,
335 GParamSpec *pspec)
337 GstNiceSrc *src = GST_NICE_SRC (object);
339 switch (prop_id)
341 case PROP_AGENT:
342 if (src->agent)
343 GST_ERROR_OBJECT (object,
344 "Changing the agent on a nice src not allowed");
345 else
346 src->agent = g_value_dup_object (value);
347 break;
349 case PROP_STREAM:
350 src->stream_id = g_value_get_uint (value);
351 break;
353 case PROP_COMPONENT:
354 src->component_id = g_value_get_uint (value);
355 break;
357 default:
358 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
359 break;
363 static void
364 gst_nice_src_get_property (
365 GObject *object,
366 guint prop_id,
367 GValue *value,
368 GParamSpec *pspec)
370 GstNiceSrc *src = GST_NICE_SRC (object);
372 switch (prop_id)
374 case PROP_AGENT:
375 g_value_set_object (value, src->agent);
376 break;
378 case PROP_STREAM:
379 g_value_set_uint (value, src->stream_id);
380 break;
382 case PROP_COMPONENT:
383 g_value_set_uint (value, src->component_id);
384 break;
386 default:
387 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
388 break;
392 static GstStateChangeReturn
393 gst_nice_src_change_state (GstElement * element, GstStateChange transition)
395 GstNiceSrc *src;
396 GstStateChangeReturn ret;
398 src = GST_NICE_SRC (element);
400 switch (transition) {
401 case GST_STATE_CHANGE_NULL_TO_READY:
402 if (src->agent == NULL || src->stream_id == 0 || src->component_id == 0)
404 GST_ERROR_OBJECT (element,
405 "Trying to start Nice source without an agent set");
406 return GST_STATE_CHANGE_FAILURE;
408 else
410 nice_agent_attach_recv (src->agent, src->stream_id, src->component_id,
411 src->mainctx, gst_nice_src_read_callback, (gpointer) src);
413 break;
414 case GST_STATE_CHANGE_READY_TO_NULL:
415 nice_agent_attach_recv (src->agent, src->stream_id, src->component_id,
416 src->mainctx, NULL, NULL);
417 break;
418 default:
419 break;
422 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
424 return ret;