gst/: Make ChildProxy threadsafe and fix mem leaks.
[glsdk/gstreamer0-10.git] / gst / gstchildproxy.c
1 /* GStreamer
2  * Copyright (C) 2005 Stefan Kost <ensonic@users.sf.net>
3  *
4  * gstchildproxy.c: interface for multi child elements
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21 /**
22  * SECTION:gstchildproxy
23  * @short_description: Interface for multi child elements.
24  * @see_also: #GstBin
25  *
26  * This interface abstracts handling of property sets for child elements.
27  * Imagine elements such as mixers or polyphonic generators. They all have
28  * multiple #GstPads or some kind of voice objects. The element acts as a parent
29  * for those child objects. Each child has the same properties.
30  *
31  * By implementing this interface the child properties can be accessed from the
32  * parent element by using gst_child_proxy_get() and gst_child_proxy_set().
33  *
34  * Property names are written as "child-name::property-name". The whole naming
35  * scheme is recursive. Thus "child1::child2::property" is valid too, if
36  * "child1" also implements the #GstChildProxy interface.
37  */
39 #include "gst_private.h"
41 #include "gstchildproxy.h"
42 #include "gstmarshal.h"
43 #include <gobject/gvaluecollector.h>
45 /* signals */
46 enum
47 {
48   CHILD_ADDED,
49   CHILD_REMOVED,
50   LAST_SIGNAL
51 };
53 static guint signals[LAST_SIGNAL] = { 0 };
55 /**
56  * gst_child_proxy_get_child_by_name:
57  * @parent: the parent object to get the child from
58  * @name: the childs name
59  *
60  * Looks up a child element by the given name.
61  *
62  * Implementors can use #GstObject together with gst_object_get_name() 
63  *
64  * Returns: the child object or %NULL if not found. Unref after usage.
65  *
66  * MT safe.
67  */
68 GstObject *
69 gst_child_proxy_get_child_by_name (GstChildProxy * parent, const gchar * name)
70 {
71   guint count, i;
72   GstObject *object, *result;
73   gchar *object_name;
75   g_return_val_if_fail (GST_IS_CHILD_PROXY (parent), NULL);
76   g_return_val_if_fail (name != NULL, NULL);
78   result = NULL;
80   count = gst_child_proxy_get_children_count (parent);
81   for (i = 0; i < count; i++) {
82     gboolean eq;
84     if (!(object = gst_child_proxy_get_child_by_index (parent, i)))
85       continue;
87     object_name = gst_object_get_name (object);
88     if (object_name == NULL) {
89       g_warning ("child %u of parent %s has no name", i,
90           GST_OBJECT_NAME (parent));
91       goto next;
92     }
93     eq = g_str_equal (object_name, name);
94     g_free (object_name);
96     if (eq) {
97       result = object;
98       break;
99     }
100   next:
101     gst_object_unref (object);
102   }
103   return result;
106 /**
107  * gst_child_proxy_get_child_by_index:
108  * @parent: the parent object to get the child from
109  * @index: the childs position in the child list
110  *
111  * Fetches a child by its number.
112  *
113  * Returns: the child object or %NULL if not found (index too high). Unref
114  * after usage.
115  *
116  * MT safe.
117  */
118 GstObject *
119 gst_child_proxy_get_child_by_index (GstChildProxy * parent, guint index)
121   g_return_val_if_fail (GST_IS_CHILD_PROXY (parent), NULL);
123   return (GST_CHILD_PROXY_GET_INTERFACE (parent)->get_child_by_index (parent,
124           index));
127 /**
128  * gst_child_proxy_get_children_count:
129  * @parent: the parent object
130  *
131  * Gets the number of child objects this parent contains.
132  *
133  * Returns: the number of child objects
134  *
135  * MT safe.
136  */
137 guint
138 gst_child_proxy_get_children_count (GstChildProxy * parent)
140   g_return_val_if_fail (GST_IS_CHILD_PROXY (parent), 0);
142   return (GST_CHILD_PROXY_GET_INTERFACE (parent)->get_children_count (parent));
145 /**
146  * gst_child_proxy_lookup:
147  * @object: object to lookup the property in
148  * @name: name of the property to look up
149  * @target: pointer to a #GstObject that takes the real object to set property on
150  * @pspec: pointer to take the #GParamSpec describing the property
151  *
152  * Looks up which object and #GParamSpec would be effected by the given @name.
153  *
154  * Returns: TRUE if @target and @pspec could be found. FALSE otherwise. In that 
155  * case the values for @pspec and @target are not modified. Unref @target after
156  * usage.
157  *
158  * MT safe.
159  */
160 gboolean
161 gst_child_proxy_lookup (GstObject * object, const gchar * name,
162     GstObject ** target, GParamSpec ** pspec)
164   gboolean res = FALSE;
165   gchar **names, **current;
167   g_return_val_if_fail (GST_IS_OBJECT (object), FALSE);
168   g_return_val_if_fail (name != NULL, FALSE);
170   gst_object_ref (object);
172   current = names = g_strsplit (name, "::", -1);
173   while (current[1]) {
174     GstObject *next;
176     if (!GST_IS_CHILD_PROXY (object)) {
177       GST_INFO
178           ("object %s is not a parent, so you cannot request a child by name %s",
179           GST_OBJECT_NAME (object), current[0]);
180       break;
181     }
182     next = gst_child_proxy_get_child_by_name (GST_CHILD_PROXY (object),
183         current[0]);
184     if (!next) {
185       GST_INFO ("no such object %s", current[0]);
186       break;
187     }
188     gst_object_unref (object);
189     object = next;
190     current++;
191   };
192   if (current[1] == NULL) {
193     GParamSpec *spec =
194         g_object_class_find_property (G_OBJECT_GET_CLASS (object), current[0]);
195     if (spec == NULL) {
196       GST_INFO ("no param spec named %s", current[0]);
197     } else {
198       if (pspec)
199         *pspec = spec;
200       if (target) {
201         gst_object_ref (object);
202         *target = object;
203       }
204       res = TRUE;
205     }
206   }
207   gst_object_unref (object);
208   g_strfreev (names);
209   return res;
212 /**
213  * gst_child_proxy_get_property:
214  * @object: object to query
215  * @name: name of the property
216  * @value: an uninitialized #GValue that should take the result. 
217  *
218  * Gets a single property using the GstChildProxy mechanism.
219  * You are responsible for for freeing it by calling g_value_unset()
220  */
221 void
222 gst_child_proxy_get_property (GstObject * object, const gchar * name,
223     GValue * value)
225   GParamSpec *pspec;
226   GstObject *target;
228   g_return_if_fail (GST_IS_OBJECT (object));
229   g_return_if_fail (name != NULL);
230   g_return_if_fail (!G_IS_VALUE (value));
232   if (!gst_child_proxy_lookup (object, name, &target, &pspec))
233     goto not_found;
235   g_object_get_property (G_OBJECT (target), pspec->name, value);
236   gst_object_unref (target);
238   return;
240 not_found:
241   {
242     g_warning ("cannot get property %s from object %s", name,
243         GST_OBJECT_NAME (object));
244     return;
245   }
248 /**
249  * gst_child_proxy_get_valist:
250  * @object: the object to query
251  * @first_property_name: name of the first property to get
252  * @var_args: return location for the first property, followed optionally by more name/return location pairs, followed by NULL
253  *
254  * Gets properties of the parent object and its children.
255  */
256 void
257 gst_child_proxy_get_valist (GstObject * object,
258     const gchar * first_property_name, va_list var_args)
260   const gchar *name;
261   gchar *error = NULL;
262   GValue value = { 0, };
264   g_return_if_fail (G_IS_OBJECT (object));
266   name = first_property_name;
268   /* iterate over pairs */
269   while (name) {
270     gst_child_proxy_get_property (object, name, &value);
271     G_VALUE_LCOPY (&value, var_args, 0, &error);
272     if (error) {
273       g_warning ("error copying value: %s", error);
274       return;
275     }
276     g_value_unset (&value);
277     name = va_arg (var_args, gchar *);
278   }
281 /**
282  * gst_child_proxy_get:
283  * @object: the parent object
284  * @first_property_name: name of the first property to get
285  * @...: return location for the first property, followed optionally by more name/return location pairs, followed by NULL
286  *
287  * Gets properties of the parent object and its children.
288  */
289 void
290 gst_child_proxy_get (GstObject * object, const gchar * first_property_name, ...)
292   va_list var_args;
294   g_return_if_fail (GST_IS_OBJECT (object));
296   va_start (var_args, first_property_name);
297   gst_child_proxy_get_valist (object, first_property_name, var_args);
298   va_end (var_args);
301 /**
302  * gst_child_proxy_set_property:
303  * @object: the parent object
304  * @name: name of the property to set
305  * @value: new #GValue for the property
306  *
307  * Sets a single property using the GstChildProxy mechanism.
308  */
309 void
310 gst_child_proxy_set_property (GstObject * object, const gchar * name,
311     const GValue * value)
313   GParamSpec *pspec;
314   GstObject *target;
316   g_return_if_fail (GST_IS_OBJECT (object));
317   g_return_if_fail (name != NULL);
318   g_return_if_fail (!G_IS_VALUE (value));
320   if (!gst_child_proxy_lookup (object, name, &target, &pspec))
321     goto not_found;
323   g_object_set_property (G_OBJECT (target), pspec->name, value);
324   gst_object_unref (target);
325   return;
327 not_found:
328   {
329     g_warning ("cannot set property %s on object %s", name,
330         GST_OBJECT_NAME (object));
331     return;
332   }
335 /**
336  * gst_child_proxy_set_valist:
337  * @object: the parent object
338  * @first_property_name: name of the first property to set
339  * @var_args: value for the first property, followed optionally by more name/value pairs, followed by NULL
340  *
341  * Sets properties of the parent object and its children.
342  */
343 void
344 gst_child_proxy_set_valist (GstObject * object,
345     const gchar * first_property_name, va_list var_args)
347   const gchar *name;
348   gchar *error = NULL;
349   GValue value = { 0, };
351   g_return_if_fail (G_IS_OBJECT (object));
353   name = first_property_name;
355   /* iterate over pairs */
356   while (name) {
357     GParamSpec *pspec;
358     GstObject *target;
360     if (!gst_child_proxy_lookup (object, name, &target, &pspec)) {
361       g_warning ("no such property %s in object %s", name,
362           GST_OBJECT_NAME (object));
363       continue;
364     }
365     g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
366     G_VALUE_COLLECT (&value, var_args, G_VALUE_NOCOPY_CONTENTS, &error);
367     if (error) {
368       g_warning ("error copying value: %s", error);
369       gst_object_unref (target);
370       return;
371     }
372     g_object_set_property (G_OBJECT (target), pspec->name, &value);
373     gst_object_unref (target);
375     g_value_unset (&value);
376     name = va_arg (var_args, gchar *);
377   }
380 /**
381  * gst_child_proxy_set:
382  * @object: the parent object
383  * @first_property_name: name of the first property to set
384  * @...: value for the first property, followed optionally by more name/value pairs, followed by NULL
385  *
386  * Sets properties of the parent object and its children.
387  */
388 void
389 gst_child_proxy_set (GstObject * object, const gchar * first_property_name, ...)
391   va_list var_args;
393   g_return_if_fail (GST_IS_OBJECT (object));
395   va_start (var_args, first_property_name);
396   gst_child_proxy_set_valist (object, first_property_name, var_args);
397   va_end (var_args);
400 /**
401  * gst_child_proxy_child_added:
402  * @object: the parent object
403  * @child: the newly added child
404  * 
405  * Emits the "child-added" signal.
406  */
407 void
408 gst_child_proxy_child_added (GstObject * object, GstObject * child)
410   g_signal_emit (G_OBJECT (object), signals[CHILD_ADDED], 0, child);
413 /**
414  * gst_child_proxy_child_removed:
415  * @object: the parent object
416  * @child: the newly added child
417  * 
418  * Emits the "child-removed" signal.
419  */
420 void
421 gst_child_proxy_child_removed (GstObject * object, GstObject * child)
423   g_signal_emit (G_OBJECT (object), signals[CHILD_REMOVED], 0, child);
426 /* gobject methods */
428 static void
429 gst_child_proxy_base_init (gpointer g_class)
431   static gboolean initialized = FALSE;
433   if (!initialized) {
434     /* create interface signals and properties here. */
435     signals[CHILD_ADDED] =
436         g_signal_new ("child-added", G_TYPE_FROM_CLASS (g_class),
437         G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GstChildProxyInterface,
438             child_added), NULL, NULL, gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
439         G_TYPE_OBJECT);
441     signals[CHILD_REMOVED] =
442         g_signal_new ("child-removed", G_TYPE_FROM_CLASS (g_class),
443         G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GstChildProxyInterface,
444             child_removed), NULL, NULL, gst_marshal_VOID__OBJECT, G_TYPE_NONE,
445         1, G_TYPE_OBJECT);
447     initialized = TRUE;
448   }
451 GType
452 gst_child_proxy_get_type (void)
454   static GType type = 0;
456   if (type == 0) {
457     static const GTypeInfo info = {
458       sizeof (GstChildProxyInterface),
459       gst_child_proxy_base_init,        /* base_init */
460       NULL,                     /* base_finalize */
461       NULL,                     /* class_init */
462       NULL,                     /* class_finalize */
463       NULL,                     /* class_data */
464       0,
465       0,                        /* n_preallocs */
466       NULL                      /* instance_init */
467     };
468     type = g_type_register_static (G_TYPE_INTERFACE, "GstChildProxy", &info, 0);
470     g_type_interface_add_prerequisite (type, GST_TYPE_OBJECT);
471   }
472   return type;