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
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.
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.
43 #include "gstnicesrc.h"
45 GST_DEBUG_CATEGORY_STATIC (nicesrc_debug);
46 #define GST_CAT_DEFAULT nicesrc_debug
49 #define BUFFER_SIZE (65536)
61 gst_nice_src_unlock_stop (
65 gst_nice_src_set_property (
72 gst_nice_src_get_property (
80 gst_nice_src_dispose (GObject *object);
82 static GstStateChangeReturn
83 gst_nice_src_change_state (
85 GstStateChange transition);
87 static GstStaticPadTemplate gst_nice_src_src_template =
88 GST_STATIC_PAD_TEMPLATE (
94 G_DEFINE_TYPE (GstNiceSrc, gst_nice_src, GST_TYPE_PUSH_SRC);
105 gst_nice_src_class_init (GstNiceSrcClass *klass)
107 GstPushSrcClass *gstpushsrc_class;
108 GstBaseSrcClass *gstbasesrc_class;
109 GstElementClass *gstelement_class;
110 GObjectClass *gobject_class;
112 GST_DEBUG_CATEGORY_INIT (nicesrc_debug, "nicesrc",
113 0, "libnice source");
115 gstpushsrc_class = (GstPushSrcClass *) klass;
116 gstpushsrc_class->create = GST_DEBUG_FUNCPTR (gst_nice_src_create);
118 gstbasesrc_class = (GstBaseSrcClass *) klass;
119 gstbasesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_nice_src_unlock);
120 gstbasesrc_class->unlock_stop = GST_DEBUG_FUNCPTR (gst_nice_src_unlock_stop);
122 gobject_class = (GObjectClass *) klass;
123 gobject_class->set_property = gst_nice_src_set_property;
124 gobject_class->get_property = gst_nice_src_get_property;
125 gobject_class->dispose = gst_nice_src_dispose;
127 gstelement_class = (GstElementClass *) klass;
128 gstelement_class->change_state = gst_nice_src_change_state;
130 gst_element_class_add_pad_template (gstelement_class,
131 gst_static_pad_template_get (&gst_nice_src_src_template));
132 #if GST_CHECK_VERSION (1,0,0)
133 gst_element_class_set_metadata (gstelement_class,
135 gst_element_class_set_details_simple (gstelement_class,
139 "Interactive UDP connectivity establishment",
140 "Dafydd Harries <dafydd.harries@collabora.co.uk>");
142 g_object_class_install_property (gobject_class, PROP_AGENT,
143 g_param_spec_object (
146 "The NiceAgent this source is bound to",
150 g_object_class_install_property (gobject_class, PROP_STREAM,
154 "The ID of the stream to read from",
160 g_object_class_install_property (gobject_class, PROP_COMPONENT,
164 "The ID of the component to read from",
172 gst_nice_src_init (GstNiceSrc *src)
174 gst_base_src_set_live (GST_BASE_SRC (src), TRUE);
175 gst_base_src_set_format (GST_BASE_SRC (src), GST_FORMAT_TIME);
176 gst_base_src_set_do_timestamp (GST_BASE_SRC (src), TRUE);
179 src->component_id = 0;
180 src->mainctx = g_main_context_new ();
181 src->mainloop = g_main_loop_new (src->mainctx, FALSE);
182 src->unlocked = FALSE;
183 src->idle_source = NULL;
184 src->outbufs = g_queue_new ();
188 gst_nice_src_read_callback (NiceAgent *agent,
195 GstBaseSrc *basesrc = GST_BASE_SRC (data);
196 GstNiceSrc *nicesrc = GST_NICE_SRC (basesrc);
197 GstBuffer *buffer = NULL;
199 GST_LOG_OBJECT (agent, "Got buffer, getting out of the main loop");
201 #if GST_CHECK_VERSION (1,0,0)
202 buffer = gst_buffer_new_allocate (NULL, len, NULL);
203 gst_buffer_fill (buffer, 0, buf, len);
205 buffer = gst_buffer_new_and_alloc (len);
206 memcpy (GST_BUFFER_DATA (buffer), buf, len);
208 GST_OBJECT_LOCK (nicesrc);
209 g_queue_push_tail (nicesrc->outbufs, buffer);
210 g_main_loop_quit (nicesrc->mainloop);
211 GST_OBJECT_UNLOCK (nicesrc);
215 gst_nice_src_unlock_idler (gpointer data)
217 GstNiceSrc *nicesrc = GST_NICE_SRC (data);
219 GST_OBJECT_LOCK (nicesrc);
220 if (nicesrc->unlocked)
221 g_main_loop_quit (nicesrc->mainloop);
223 if (nicesrc->idle_source) {
224 g_source_destroy (nicesrc->idle_source);
225 g_source_unref (nicesrc->idle_source);
226 nicesrc->idle_source = NULL;
228 GST_OBJECT_UNLOCK (nicesrc);
234 gst_nice_src_unlock (GstBaseSrc *src)
236 GstNiceSrc *nicesrc = GST_NICE_SRC (src);
238 GST_OBJECT_LOCK (src);
239 nicesrc->unlocked = TRUE;
241 g_main_loop_quit (nicesrc->mainloop);
243 if (!nicesrc->idle_source) {
244 nicesrc->idle_source = g_idle_source_new ();
245 g_source_set_priority (nicesrc->idle_source, G_PRIORITY_HIGH);
246 g_source_set_callback (nicesrc->idle_source, gst_nice_src_unlock_idler, src, NULL);
247 g_source_attach (nicesrc->idle_source, g_main_loop_get_context (nicesrc->mainloop));
249 GST_OBJECT_UNLOCK (src);
255 gst_nice_src_unlock_stop (GstBaseSrc *src)
257 GstNiceSrc *nicesrc = GST_NICE_SRC (src);
259 GST_OBJECT_LOCK (src);
260 nicesrc->unlocked = FALSE;
261 if (nicesrc->idle_source) {
262 g_source_destroy (nicesrc->idle_source);
263 g_source_unref(nicesrc->idle_source);
265 nicesrc->idle_source = NULL;
266 GST_OBJECT_UNLOCK (src);
272 gst_nice_src_create (
276 GstNiceSrc *nicesrc = GST_NICE_SRC (basesrc);
278 GST_LOG_OBJECT (nicesrc, "create called");
280 GST_OBJECT_LOCK (basesrc);
281 if (nicesrc->unlocked) {
282 GST_OBJECT_UNLOCK (basesrc);
283 #if GST_CHECK_VERSION (1,0,0)
284 return GST_FLOW_FLUSHING;
286 return GST_FLOW_WRONG_STATE;
289 if (g_queue_is_empty (nicesrc->outbufs)) {
290 GST_OBJECT_UNLOCK (basesrc);
291 g_main_loop_run (nicesrc->mainloop);
292 GST_OBJECT_LOCK (basesrc);
295 *buffer = g_queue_pop_head (nicesrc->outbufs);
296 GST_OBJECT_UNLOCK (basesrc);
298 if (*buffer != NULL) {
299 GST_LOG_OBJECT (nicesrc, "Got buffer, pushing");
302 GST_LOG_OBJECT (nicesrc, "Got interrupting, returning wrong-state");
303 #if GST_CHECK_VERSION (1,0,0)
304 return GST_FLOW_FLUSHING;
306 return GST_FLOW_WRONG_STATE;
313 gst_nice_src_dispose (GObject *object)
315 GstNiceSrc *src = GST_NICE_SRC (object);
318 g_object_unref (src->agent);
322 g_main_loop_unref (src->mainloop);
323 src->mainloop = NULL;
326 g_main_context_unref (src->mainctx);
330 g_queue_free_full (src->outbufs, (GDestroyNotify) gst_buffer_unref);
334 if (src->idle_source) {
335 g_source_destroy (src->idle_source);
336 g_source_unref(src->idle_source);
338 src->idle_source = NULL;
340 G_OBJECT_CLASS (gst_nice_src_parent_class)->dispose (object);
344 gst_nice_src_set_property (
350 GstNiceSrc *src = GST_NICE_SRC (object);
356 GST_ERROR_OBJECT (object,
357 "Changing the agent on a nice src not allowed");
359 src->agent = g_value_dup_object (value);
363 src->stream_id = g_value_get_uint (value);
367 src->component_id = g_value_get_uint (value);
371 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
377 gst_nice_src_get_property (
383 GstNiceSrc *src = GST_NICE_SRC (object);
388 g_value_set_object (value, src->agent);
392 g_value_set_uint (value, src->stream_id);
396 g_value_set_uint (value, src->component_id);
400 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
405 static GstStateChangeReturn
406 gst_nice_src_change_state (GstElement * element, GstStateChange transition)
409 GstStateChangeReturn ret;
411 src = GST_NICE_SRC (element);
413 switch (transition) {
414 case GST_STATE_CHANGE_NULL_TO_READY:
415 if (src->agent == NULL)
417 GST_ERROR_OBJECT (element,
418 "Trying to start Nice source without an agent set");
419 return GST_STATE_CHANGE_FAILURE;
421 else if (src->stream_id == 0)
423 GST_ERROR_OBJECT (element,
424 "Trying to start Nice source without a stream set");
425 return GST_STATE_CHANGE_FAILURE;
427 else if (src->component_id == 0)
429 GST_ERROR_OBJECT (element,
430 "Trying to start Nice source without a component set");
431 return GST_STATE_CHANGE_FAILURE;
434 case GST_STATE_CHANGE_PAUSED_TO_READY:
435 nice_agent_attach_recv (src->agent, src->stream_id, src->component_id,
436 src->mainctx, NULL, NULL);
437 GST_OBJECT_LOCK (src);
438 g_list_free_full (src->outbufs->head, (GDestroyNotify) gst_buffer_unref);
439 g_queue_init (src->outbufs);
440 GST_OBJECT_UNLOCK (src);
442 case GST_STATE_CHANGE_READY_TO_PAUSED:
443 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
444 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
445 case GST_STATE_CHANGE_READY_TO_NULL:
450 ret = GST_ELEMENT_CLASS (gst_nice_src_parent_class)->change_state (element,
453 switch (transition) {
454 case GST_STATE_CHANGE_READY_TO_PAUSED:
455 nice_agent_attach_recv (src->agent, src->stream_id, src->component_id,
456 src->mainctx, gst_nice_src_read_callback, (gpointer) src);
458 case GST_STATE_CHANGE_NULL_TO_READY:
459 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
460 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
461 case GST_STATE_CHANGE_PAUSED_TO_READY:
462 case GST_STATE_CHANGE_READY_TO_NULL: