Port GStreamer src/sink to 0.11
[sipe-libnice.git] / gst / gstnicesrc.c
blob321a97c0b0683b7f09e807cdb130f11ac2227492
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 GstStaticPadTemplate gst_nice_src_src_template =
90 GST_STATIC_PAD_TEMPLATE (
91 "src",
92 GST_PAD_SRC,
93 GST_PAD_ALWAYS,
94 GST_STATIC_CAPS_ANY);
96 G_DEFINE_TYPE (GstNiceSrc, gst_nice_src, GST_TYPE_BASE_SRC);
98 enum
100 PROP_AGENT = 1,
101 PROP_STREAM,
102 PROP_COMPONENT
106 static void
107 gst_nice_src_class_init (GstNiceSrcClass *klass)
109 GstBaseSrcClass *gstbasesrc_class;
110 GstElementClass *gstelement_class;
111 GObjectClass *gobject_class;
113 GST_DEBUG_CATEGORY_INIT (nicesrc_debug, "nicesrc",
114 0, "libnice source");
116 gstbasesrc_class = (GstBaseSrcClass *) klass;
117 gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_nice_src_create);
118 gstbasesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_nice_src_unlock);
119 gstbasesrc_class->unlock_stop = GST_DEBUG_FUNCPTR (gst_nice_src_unlock_stop);
121 gobject_class = (GObjectClass *) klass;
122 gobject_class->set_property = gst_nice_src_set_property;
123 gobject_class->get_property = gst_nice_src_get_property;
124 gobject_class->dispose = gst_nice_src_dispose;
126 gstelement_class = (GstElementClass *) klass;
127 gstelement_class->change_state = gst_nice_src_change_state;
129 gst_element_class_add_pad_template (gstelement_class,
130 gst_static_pad_template_get (&gst_nice_src_src_template));
131 gst_element_class_set_metadata (gstelement_class,
132 "ICE source",
133 "Source",
134 "Interactive UDP connectivity establishment",
135 "Dafydd Harries <dafydd.harries@collabora.co.uk>");
137 g_object_class_install_property (gobject_class, PROP_AGENT,
138 g_param_spec_object (
139 "agent",
140 "Agent",
141 "The NiceAgent this source is bound to",
142 NICE_TYPE_AGENT,
143 G_PARAM_READWRITE));
145 g_object_class_install_property (gobject_class, PROP_STREAM,
146 g_param_spec_uint (
147 "stream",
148 "Stream ID",
149 "The ID of the stream to read from",
151 G_MAXUINT,
153 G_PARAM_READWRITE));
155 g_object_class_install_property (gobject_class, PROP_COMPONENT,
156 g_param_spec_uint (
157 "component",
158 "Component ID",
159 "The ID of the component to read from",
161 G_MAXUINT,
163 G_PARAM_READWRITE));
166 static void
167 gst_nice_src_init (GstNiceSrc *src)
169 gst_base_src_set_live (GST_BASE_SRC (src), TRUE);
170 gst_base_src_set_format (GST_BASE_SRC (src), GST_FORMAT_TIME);
171 gst_base_src_set_do_timestamp (GST_BASE_SRC (src), TRUE);
172 src->agent = NULL;
173 src->stream_id = 0;
174 src->component_id = 0;
175 src->mainctx = g_main_context_new ();
176 src->mainloop = g_main_loop_new (src->mainctx, FALSE);
177 src->unlocked = FALSE;
178 src->idle_source = NULL;
179 src->outbufs = g_queue_new ();
182 static void
183 gst_nice_src_read_callback (NiceAgent *agent,
184 guint stream_id,
185 guint component_id,
186 guint len,
187 gchar *buf,
188 gpointer data)
190 GstBaseSrc *basesrc = GST_BASE_SRC (data);
191 GstNiceSrc *nicesrc = GST_NICE_SRC (basesrc);
192 GstBuffer *buffer = NULL;
193 GstMapInfo info;
195 GST_LOG_OBJECT (agent, "Got buffer, getting out of the main loop");
197 buffer = gst_buffer_new_allocate (NULL, len, 1);
198 gst_buffer_map (buffer, &info, GST_MAP_WRITE);
199 memcpy (info.data, buf, len);
200 gst_buffer_unmap (buffer, &info);
201 g_queue_push_tail (nicesrc->outbufs, buffer);
203 g_main_loop_quit (nicesrc->mainloop);
206 static gboolean
207 gst_nice_src_unlock_idler (gpointer data)
209 GstNiceSrc *nicesrc = GST_NICE_SRC (data);
211 GST_OBJECT_LOCK (nicesrc);
212 if (nicesrc->unlocked)
213 g_main_loop_quit (nicesrc->mainloop);
215 if (nicesrc->idle_source) {
216 g_source_destroy (nicesrc->idle_source);
217 g_source_unref (nicesrc->idle_source);
218 nicesrc->idle_source = NULL;
220 GST_OBJECT_UNLOCK (nicesrc);
222 return FALSE;
225 static gboolean
226 gst_nice_src_unlock (GstBaseSrc *src)
228 GstNiceSrc *nicesrc = GST_NICE_SRC (src);
230 GST_OBJECT_LOCK (src);
231 nicesrc->unlocked = TRUE;
233 g_main_loop_quit (nicesrc->mainloop);
235 if (!nicesrc->idle_source) {
236 nicesrc->idle_source = g_idle_source_new ();
237 g_source_set_priority (nicesrc->idle_source, G_PRIORITY_HIGH);
238 g_source_set_callback (nicesrc->idle_source, gst_nice_src_unlock_idler, src, NULL);
239 g_source_attach (nicesrc->idle_source, g_main_loop_get_context (nicesrc->mainloop));
241 GST_OBJECT_UNLOCK (src);
243 return TRUE;
246 static gboolean
247 gst_nice_src_unlock_stop (GstBaseSrc *src)
249 GstNiceSrc *nicesrc = GST_NICE_SRC (src);
251 GST_OBJECT_LOCK (src);
252 nicesrc->unlocked = FALSE;
253 if (nicesrc->idle_source) {
254 g_source_destroy (nicesrc->idle_source);
255 g_source_unref(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->offset = offset;
276 GST_OBJECT_LOCK (basesrc);
277 if (nicesrc->unlocked) {
278 GST_OBJECT_UNLOCK (basesrc);
279 return GST_FLOW_WRONG_STATE;
281 GST_OBJECT_UNLOCK (basesrc);
283 if (g_queue_is_empty (nicesrc->outbufs))
284 g_main_loop_run (nicesrc->mainloop);
286 *buffer = g_queue_pop_head (nicesrc->outbufs);
287 if (*buffer != NULL) {
288 GST_LOG_OBJECT (nicesrc, "Got buffer, pushing");
289 return GST_FLOW_OK;
290 } else {
291 GST_LOG_OBJECT (nicesrc, "Got interrupting, returning wrong-state");
292 return GST_FLOW_WRONG_STATE;
297 static void
298 gst_nice_src_dispose (GObject *object)
300 GstNiceSrc *src = GST_NICE_SRC (object);
302 if (src->agent)
303 g_object_unref (src->agent);
304 src->agent = NULL;
306 if (src->mainloop)
307 g_main_loop_unref (src->mainloop);
308 src->mainloop = NULL;
310 if (src->mainctx)
311 g_main_context_unref (src->mainctx);
312 src->mainctx = NULL;
314 if (src->outbufs)
315 g_queue_free (src->outbufs);
316 src->outbufs = NULL;
318 G_OBJECT_CLASS (gst_nice_src_parent_class)->dispose (object);
321 static void
322 gst_nice_src_set_property (
323 GObject *object,
324 guint prop_id,
325 const GValue *value,
326 GParamSpec *pspec)
328 GstNiceSrc *src = GST_NICE_SRC (object);
330 switch (prop_id)
332 case PROP_AGENT:
333 if (src->agent)
334 GST_ERROR_OBJECT (object,
335 "Changing the agent on a nice src not allowed");
336 else
337 src->agent = g_value_dup_object (value);
338 break;
340 case PROP_STREAM:
341 src->stream_id = g_value_get_uint (value);
342 break;
344 case PROP_COMPONENT:
345 src->component_id = g_value_get_uint (value);
346 break;
348 default:
349 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
350 break;
354 static void
355 gst_nice_src_get_property (
356 GObject *object,
357 guint prop_id,
358 GValue *value,
359 GParamSpec *pspec)
361 GstNiceSrc *src = GST_NICE_SRC (object);
363 switch (prop_id)
365 case PROP_AGENT:
366 g_value_set_object (value, src->agent);
367 break;
369 case PROP_STREAM:
370 g_value_set_uint (value, src->stream_id);
371 break;
373 case PROP_COMPONENT:
374 g_value_set_uint (value, src->component_id);
375 break;
377 default:
378 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
379 break;
383 static GstStateChangeReturn
384 gst_nice_src_change_state (GstElement * element, GstStateChange transition)
386 GstNiceSrc *src;
387 GstStateChangeReturn ret;
389 src = GST_NICE_SRC (element);
391 switch (transition) {
392 case GST_STATE_CHANGE_NULL_TO_READY:
393 if (src->agent == NULL || src->stream_id == 0 || src->component_id == 0)
395 GST_ERROR_OBJECT (element,
396 "Trying to start Nice source without an agent set");
397 return GST_STATE_CHANGE_FAILURE;
399 else
401 nice_agent_attach_recv (src->agent, src->stream_id, src->component_id,
402 src->mainctx, gst_nice_src_read_callback, (gpointer) src);
404 break;
405 case GST_STATE_CHANGE_READY_TO_NULL:
406 nice_agent_attach_recv (src->agent, src->stream_id, src->component_id,
407 src->mainctx, NULL, NULL);
408 break;
409 default:
410 break;
413 ret = GST_ELEMENT_CLASS (gst_nice_src_parent_class)->change_state (element,
414 transition);
416 return ret;