Version 0.0.10
[sipe-libnice.git] / gst / gstnicesrc.c
blobb86f096c7cfdd9ab4a8ecb65197afc2d47ba51b7
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;
189 static void
190 gst_nice_src_read_callback (NiceAgent *agent,
191 guint stream_id,
192 guint component_id,
193 guint len,
194 gchar *buf,
195 gpointer data)
197 GstBaseSrc *basesrc = GST_BASE_SRC (data);
198 GstNiceSrc *nicesrc = GST_NICE_SRC (basesrc);
200 GST_LOG_OBJECT (agent, "Got buffer, getting out of the main loop");
202 nicesrc->flow_ret = gst_pad_alloc_buffer (basesrc->srcpad, nicesrc->offset,
203 len, GST_PAD_CAPS (basesrc->srcpad), &nicesrc->outbuf);
204 if (nicesrc->flow_ret == GST_FLOW_OK) {
205 memcpy (nicesrc->outbuf->data, buf, len);
206 nicesrc->outbuf->size = len;
209 g_main_loop_quit (nicesrc->mainloop);
212 static gboolean
213 gst_nice_src_unlock_idler (gpointer data)
215 GstNiceSrc *nicesrc = GST_NICE_SRC (data);
217 GST_OBJECT_LOCK (nicesrc);
218 if (nicesrc->unlocked)
219 g_main_loop_quit (nicesrc->mainloop);
221 if (nicesrc->idle_source) {
222 g_source_destroy (nicesrc->idle_source);
223 g_source_unref (nicesrc->idle_source);
224 nicesrc->idle_source = NULL;
226 GST_OBJECT_UNLOCK (nicesrc);
228 return FALSE;
231 static gboolean
232 gst_nice_src_unlock (GstBaseSrc *src)
234 GstNiceSrc *nicesrc = GST_NICE_SRC (src);
236 GST_OBJECT_LOCK (src);
237 nicesrc->unlocked = TRUE;
239 g_main_loop_quit (nicesrc->mainloop);
241 if (!nicesrc->idle_source) {
242 nicesrc->idle_source = g_idle_source_new ();
243 g_source_set_priority (nicesrc->idle_source, G_PRIORITY_HIGH);
244 g_source_set_callback (nicesrc->idle_source, gst_nice_src_unlock_idler, src, NULL);
245 g_source_attach (nicesrc->idle_source, g_main_loop_get_context (nicesrc->mainloop));
247 GST_OBJECT_UNLOCK (src);
249 return TRUE;
252 static gboolean
253 gst_nice_src_unlock_stop (GstBaseSrc *src)
255 GstNiceSrc *nicesrc = GST_NICE_SRC (src);
257 GST_OBJECT_LOCK (src);
258 nicesrc->unlocked = FALSE;
259 if (nicesrc->idle_source) {
260 g_source_destroy (nicesrc->idle_source);
261 g_source_unref(nicesrc->idle_source);
263 nicesrc->idle_source = NULL;
264 GST_OBJECT_UNLOCK (src);
266 return TRUE;
269 static GstFlowReturn
270 gst_nice_src_create (
271 GstBaseSrc *basesrc,
272 guint64 offset,
273 guint length,
274 GstBuffer **buffer)
276 GstNiceSrc *nicesrc = GST_NICE_SRC (basesrc);
278 GST_LOG_OBJECT (nicesrc, "create called");
280 nicesrc->outbuf = NULL;
281 nicesrc->offset = offset;
283 GST_OBJECT_LOCK (basesrc);
284 if (nicesrc->unlocked) {
285 GST_OBJECT_UNLOCK (basesrc);
286 return GST_FLOW_WRONG_STATE;
288 GST_OBJECT_UNLOCK (basesrc);
290 g_main_loop_run (nicesrc->mainloop);
292 if (nicesrc->outbuf) {
293 GST_LOG_OBJECT (nicesrc, "Got buffer, pushing");
295 *buffer = nicesrc->outbuf;
296 return nicesrc->flow_ret;
297 } else {
298 GST_LOG_OBJECT (nicesrc, "Got interrupting, returning wrong-state");
299 return GST_FLOW_WRONG_STATE;
304 static void
305 gst_nice_src_dispose (GObject *object)
307 GstNiceSrc *src = GST_NICE_SRC (object);
309 if (src->agent)
310 g_object_unref (src->agent);
311 src->agent = NULL;
313 if (src->mainloop)
314 g_main_loop_unref (src->mainloop);
315 src->mainloop = NULL;
317 if (src->mainctx)
318 g_main_context_unref (src->mainctx);
319 src->mainctx = NULL;
321 GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
324 static void
325 gst_nice_src_set_property (
326 GObject *object,
327 guint prop_id,
328 const GValue *value,
329 GParamSpec *pspec)
331 GstNiceSrc *src = GST_NICE_SRC (object);
333 switch (prop_id)
335 case PROP_AGENT:
336 if (src->agent)
337 GST_ERROR_OBJECT (object,
338 "Changing the agent on a nice src not allowed");
339 else
340 src->agent = g_value_dup_object (value);
341 break;
343 case PROP_STREAM:
344 src->stream_id = g_value_get_uint (value);
345 break;
347 case PROP_COMPONENT:
348 src->component_id = g_value_get_uint (value);
349 break;
351 default:
352 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
353 break;
357 static void
358 gst_nice_src_get_property (
359 GObject *object,
360 guint prop_id,
361 GValue *value,
362 GParamSpec *pspec)
364 GstNiceSrc *src = GST_NICE_SRC (object);
366 switch (prop_id)
368 case PROP_AGENT:
369 g_value_set_object (value, src->agent);
370 break;
372 case PROP_STREAM:
373 g_value_set_uint (value, src->stream_id);
374 break;
376 case PROP_COMPONENT:
377 g_value_set_uint (value, src->component_id);
378 break;
380 default:
381 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
382 break;
386 static GstStateChangeReturn
387 gst_nice_src_change_state (GstElement * element, GstStateChange transition)
389 GstNiceSrc *src;
390 GstStateChangeReturn ret;
392 src = GST_NICE_SRC (element);
394 switch (transition) {
395 case GST_STATE_CHANGE_NULL_TO_READY:
396 if (src->agent == NULL || src->stream_id == 0 || src->component_id == 0)
398 GST_ERROR_OBJECT (element,
399 "Trying to start Nice source without an agent set");
400 return GST_STATE_CHANGE_FAILURE;
402 else
404 nice_agent_attach_recv (src->agent, src->stream_id, src->component_id,
405 src->mainctx, gst_nice_src_read_callback, (gpointer) src);
407 break;
408 case GST_STATE_CHANGE_READY_TO_NULL:
409 nice_agent_attach_recv (src->agent, src->stream_id, src->component_id,
410 src->mainctx, NULL, NULL);
411 break;
412 default:
413 break;
416 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
418 return ret;