[farsight2/master] Make the element addition notification thing into a GObject so that we can use regular signals
Olivier Crête
olivier.crete at collabora.co.uk
Tue Dec 23 15:21:19 PST 2008
---
docs/libs/farsight-libs-docs.sgml | 4 +-
docs/libs/farsight-libs-sections.txt | 26 +-
docs/libs/farsight-libs.types | 2 +
gst-libs/gst/farsight/Makefile.am | 4 +-
gst-libs/gst/farsight/fs-element-added-notifier.c | 452 +++++++++++++++++++++
gst-libs/gst/farsight/fs-element-added-notifier.h | 97 +++++
gst-libs/gst/farsight/fs-marshal.list | 1 +
gst-libs/gst/farsight/fs-utils.c | 411 -------------------
gst-libs/gst/farsight/fs-utils.h | 61 ---
tests/check/utils/binadded.c | 60 ++--
10 files changed, 605 insertions(+), 513 deletions(-)
create mode 100644 gst-libs/gst/farsight/fs-element-added-notifier.c
create mode 100644 gst-libs/gst/farsight/fs-element-added-notifier.h
delete mode 100644 gst-libs/gst/farsight/fs-utils.c
delete mode 100644 gst-libs/gst/farsight/fs-utils.h
diff --git a/docs/libs/farsight-libs-docs.sgml b/docs/libs/farsight-libs-docs.sgml
index ab78075..b90a162 100644
--- a/docs/libs/farsight-libs-docs.sgml
+++ b/docs/libs/farsight-libs-docs.sgml
@@ -21,8 +21,8 @@
<xi:include href="xml/fs-codec.xml"/>
</chapter>
<chapter>
- <title>Farsight Utility Functions</title>
- <xi:include href="xml/fs-utils.xml"/>
+ <title>Farsight Utility Functions and Objects</title>
+ <xi:include href="xml/fs-element-added-notifier.xml"/>
</chapter>
</part>
<part>
diff --git a/docs/libs/farsight-libs-sections.txt b/docs/libs/farsight-libs-sections.txt
index fe14249..ea5d955 100644
--- a/docs/libs/farsight-libs-sections.txt
+++ b/docs/libs/farsight-libs-sections.txt
@@ -78,7 +78,6 @@ FS_IS_CONFERENCE
FS_TYPE_CONFERENCE
fs_conference_get_type
FS_CONFERENCE_GET_IFACE
-FsConference
FsConferenceClass
fs_error_quark
</SECTION>
@@ -191,11 +190,11 @@ fs_stream_transmitter_get_type
<SECTION>
<FILE>fs-plugin</FILE>
<TITLE>FsPlugin</TITLE>
+FsPlugin
fs_plugin_create_valist
fs_plugin_create
FS_INIT_PLUGIN
<SUBSECTION Standard>
-FsPlugin
FsPluginClass
FS_IS_PLUGIN
FS_IS_PLUGIN_CLASS
@@ -208,10 +207,21 @@ fs_plugin_get_type
</SECTION>
<SECTION>
-<FILE>fs-utils</FILE>
-<TITLE>Utils</TITLE>
-FsElementAddedCallback
-fs_utils_add_recursive_element_added_notification
-fs_utils_remove_recursive_element_added_notification
-fs_utils_add_recursive_element_setter_from_keyfile
+<FILE>fs-element-added-notifier</FILE>
+<TITLE>FsElementAddedNotifier</TITLE>
+FsElementAddedNotifier
+fs_element_added_notifier_new
+fs_element_added_notifier_add
+fs_element_added_notifier_remove
+fs_element_added_notifier_set_properties_from_keyfile
+<SUBSECTION Standard>
+FsElementAddedNotifierClass
+FsElementAddedNotifierPrivate
+FS_ELEMENT_ADDED_NOTIFIER
+FS_ELEMENT_ADDED_NOTIFIER_CLASS
+FS_ELEMENT_ADDED_NOTIFIER_GET_CLASS
+FS_IS_ELEMENT_ADDED_NOTIFIER
+FS_IS_ELEMENT_ADDED_NOTIFIER_CLASS
+FS_TYPE_ELEMENT_ADDED_NOTIFIER
+fs_element_added_notifier_get_type
</SECTION>
diff --git a/docs/libs/farsight-libs.types b/docs/libs/farsight-libs.types
index e924ef2..e092b68 100644
--- a/docs/libs/farsight-libs.types
+++ b/docs/libs/farsight-libs.types
@@ -12,6 +12,7 @@
#include "../../gst-libs/gst/farsight/fs-base-conference.h"
#include "../../gst-libs/gst/farsight/fs-transmitter.h"
#include "../../gst-libs/gst/farsight/fs-stream-transmitter.h"
+#include "../../gst-libs/gst/farsight/fs-element-added-notifier.h"
fs_participant_get_type
fs_session_get_type
@@ -19,3 +20,4 @@ fs_stream_get_type
fs_base_conference_get_type
fs_transmitter_get_type
fs_stream_transmitter_get_type
+fs_element_added_notifier_get_type
diff --git a/gst-libs/gst/farsight/Makefile.am b/gst-libs/gst/farsight/Makefile.am
index f687cbb..e07d206 100644
--- a/gst-libs/gst/farsight/Makefile.am
+++ b/gst-libs/gst/farsight/Makefile.am
@@ -13,7 +13,7 @@ libgstfarsightinclude_HEADERS = \
fs-plugin.h \
fs-marshal.h \
fs-enum-types.h \
- fs-utils.h
+ fs-element-added-notifier.h
lib_LTLIBRARIES = libgstfarsight- at GST_MAJORMINOR@.la
@@ -38,7 +38,7 @@ libgstfarsight_ at GST_MAJORMINOR@_la_SOURCES = \
fs-plugin.c \
fs-marshal.c \
fs-enum-types.c \
- fs-utils.c
+ fs-element-added-notifier.c
noinst_HEADERS = \
fs-marshal.h \
diff --git a/gst-libs/gst/farsight/fs-element-added-notifier.c b/gst-libs/gst/farsight/fs-element-added-notifier.c
new file mode 100644
index 0000000..068040b
--- /dev/null
+++ b/gst-libs/gst/farsight/fs-element-added-notifier.c
@@ -0,0 +1,452 @@
+/*
+ * Farsight2 - Recursive element addition notifier
+ *
+ * Copyright 2007-2008 Collabora Ltd.
+ * @author: Olivier Crete <olivier.crete at collabora.co.uk>
+ * Copyright 2007-2008 Nokia Corp.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+/**
+ * SECTION:fs-element-added-notifier
+ * @short_description: Recursive element addition notifier
+ *
+ * This object can be attach to any #GstBin and will emit a the
+ * #FsElementAddedNotifier::element-added signal for every element inside the
+ * #GstBin or any sub-bin and any element added in the future to the bin or
+ * its sub-bins. There is also a utility method to have it used to
+ * set the properties of elements based on a GKeyfile.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "fs-element-added-notifier.h"
+#include "fs-marshal.h"
+
+
+/* Signals */
+enum
+{
+ ELEMENT_ADDED,
+ LAST_SIGNAL
+};
+
+#define FS_ELEMENT_ADDED_NOTIFIER_GET_PRIVATE(o) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), FS_TYPE_ELEMENT_ADDED_NOTIFIER, \
+ FsElementAddedNotifierPrivate))
+
+struct _FsElementAddedNotifierPrivate {
+ GList *keyfiles;
+};
+
+static void _element_added_callback (GstBin *parent, GstElement *element,
+ gpointer user_data);
+
+static void fs_element_added_notifier_finalize (GObject *object);
+
+
+G_DEFINE_TYPE(FsElementAddedNotifier, fs_element_added_notifier, G_TYPE_OBJECT);
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+static GObjectClass *parent_class = NULL;
+
+static void
+fs_element_added_notifier_class_init (FsElementAddedNotifierClass *klass)
+{
+ GObjectClass *gobject_class;
+
+ gobject_class = (GObjectClass *) klass;
+ parent_class = g_type_class_peek_parent (klass);
+
+ gobject_class->finalize = fs_element_added_notifier_finalize;
+
+ /**
+ * FsElementAddedNotifier::element-added:
+ * @self: #FsElementAddedNotifier that emitted the signal
+ * @bin: The #GstBin to which this object was added
+ * @element: The #GstElement that was added
+ *
+ * This signal is emitted when an element is added to a #GstBin that was added
+ * to this object or one of its sub-bins.
+ */
+ signals[ELEMENT_ADDED] = g_signal_new ("element-added",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL,
+ NULL,
+ fs_marshal_VOID__OBJECT_OBJECT,
+ G_TYPE_NONE, 2, GST_TYPE_BIN, GST_TYPE_ELEMENT);
+
+ g_type_class_add_private (klass, sizeof (FsElementAddedNotifierPrivate));
+}
+
+
+static void
+fs_element_added_notifier_init (FsElementAddedNotifier *notifier)
+{
+ notifier->priv = FS_ELEMENT_ADDED_NOTIFIER_GET_PRIVATE(notifier);
+}
+
+
+
+static void
+fs_element_added_notifier_finalize (GObject *object)
+{
+ FsElementAddedNotifier *self = FS_ELEMENT_ADDED_NOTIFIER (object);
+
+ g_list_foreach (self->priv->keyfiles, (GFunc) g_key_file_free, NULL);
+ g_list_free (self->priv->keyfiles);
+ self->priv->keyfiles = NULL;
+}
+
+/**
+ * fs_element_added_notifier_new:
+ *
+ * Creates a new #FsElementAddedNotifier object
+ *
+ * Returns: the newly-created #FsElementAddedNotifier
+ */
+
+FsElementAddedNotifier *
+fs_element_added_notifier_new (void)
+{
+ return (FsElementAddedNotifier *)
+ g_object_new (FS_TYPE_ELEMENT_ADDED_NOTIFIER, NULL);
+}
+
+/**
+ * fs_element_added_notifier_add:
+ * @notifier: a #FsElementAddedNotifier
+ * @bin: A #GstBin to watch to added elements
+ *
+ * Add a #GstBin to on which the #FsElementAddedNotifier::element-added signal
+ * will be called on every element and sub-element present and added in the
+ * future.
+ */
+
+void
+fs_element_added_notifier_add (FsElementAddedNotifier *notifier,
+ GstBin *bin)
+{
+ _element_added_callback (NULL, GST_ELEMENT_CAST (bin), notifier);
+}
+
+
+static void
+_bin_unparented_cb (GstObject *object, GstObject *parent, gpointer user_data)
+{
+ GstIterator *iter = NULL;
+ gboolean done;
+
+ /* Return if there was no handler connected */
+ if (g_signal_handlers_disconnect_by_func(object, _element_added_callback,
+ user_data) == 0)
+ return;
+
+ iter = gst_bin_iterate_elements (GST_BIN (object));
+
+ done = FALSE;
+ while (!done)
+ {
+ gpointer item;
+
+ switch (gst_iterator_next (iter, &item)) {
+ case GST_ITERATOR_OK:
+ {
+ if (GST_IS_BIN (item))
+ _bin_unparented_cb (GST_OBJECT (item), object, user_data);
+ }
+ break;
+ case GST_ITERATOR_RESYNC:
+ // We don't rollback anything, we just ignore already processed ones
+ gst_iterator_resync (iter);
+ break;
+ case GST_ITERATOR_ERROR:
+ g_error ("Wrong parameters were given?");
+ done = TRUE;
+ break;
+ case GST_ITERATOR_DONE:
+ done = TRUE;
+ break;
+ }
+ }
+
+ gst_iterator_free (iter);
+}
+
+
+/**
+ * fs_element_added_notifier_remove:
+ * @notifier: a #FsElementAddedNotifier
+ * @bin: A #GstBin to stop watching
+ *
+ * Stop watching the passed bin and its subbins.
+ *
+ * Returns: %TRUE if the #GstBin was being watched, %FALSE otherwise
+ */
+
+gboolean
+fs_element_added_notifier_remove (FsElementAddedNotifier *notifier,
+ GstBin *bin)
+{
+ if (g_signal_handler_find (bin,
+ G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
+ 0, 0, NULL, /* id, detail, closure */
+ _element_added_callback, notifier) != 0)
+ {
+ _bin_unparented_cb (GST_OBJECT (bin), NULL, notifier);
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+
+#if 1
+# define DEBUG(...) do {} while (0)
+#else
+# define DEBUG g_debug
+#endif
+
+static void
+_bin_added_from_keyfile (FsElementAddedNotifier *notifier, GstBin *bin,
+ GstElement *element, gpointer user_data)
+{
+ GKeyFile *keyfile = user_data;
+ GstElementFactory *factory = NULL;
+ const gchar *name;
+ gchar **keys;
+ gint i;
+
+ factory = gst_element_get_factory (element);
+
+ g_assert (factory);
+
+ name = gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory));
+
+ if (!name)
+ return;
+
+
+ if (!g_key_file_has_group (keyfile, name))
+ return;
+
+
+ DEBUG ("Found config for %s", name);
+ keys = g_key_file_get_keys (keyfile, name, NULL, NULL);
+
+ for (i = 0; keys[i]; i++)
+ {
+ GParamSpec *param_spec;
+ GValue key_value = { 0 };
+ GValue prop_value = { 0 };
+
+ gchar *str_key_value;
+ gboolean bool_key_value;
+ gint int_key_value;
+ gdouble double_key_value;
+ glong long_key_value;
+ gulong ulong_key_value;
+
+ DEBUG ("getting %s", keys[i]);
+ param_spec = g_object_class_find_property
+ (G_OBJECT_GET_CLASS(element), keys[i]);
+
+ /* If the paremeter does not exist, or is one of those,
+ * then lets skip it
+ * TODO: What if we want to pass GstCaps as strings?
+ */
+ if (!param_spec ||
+ g_type_is_a (param_spec->value_type, G_TYPE_OBJECT) ||
+ g_type_is_a (param_spec->value_type, GST_TYPE_MINI_OBJECT) ||
+ g_type_is_a (param_spec->value_type, G_TYPE_INTERFACE) ||
+ g_type_is_a (param_spec->value_type, G_TYPE_BOXED) ||
+ g_type_is_a (param_spec->value_type, G_TYPE_GTYPE) ||
+ g_type_is_a (param_spec->value_type, G_TYPE_POINTER))
+ {
+ continue;
+ }
+
+ g_value_init (&prop_value, param_spec->value_type);
+
+ switch (param_spec->value_type)
+ {
+ case G_TYPE_STRING:
+ str_key_value = g_key_file_get_value (keyfile, name,
+ keys[i], NULL);
+ g_value_init (&key_value, G_TYPE_STRING);
+ g_value_set_string (&key_value, str_key_value);
+ DEBUG ("%s is a string: %s", keys[i], str_key_value);
+ g_free (str_key_value);
+ break;
+ case G_TYPE_BOOLEAN:
+ bool_key_value = g_key_file_get_boolean (keyfile, name,
+ keys[i], NULL);
+ g_value_init (&key_value, G_TYPE_BOOLEAN);
+ g_value_set_boolean (&key_value, bool_key_value);
+ DEBUG ("%s is a boolean: %d", keys[i], bool_key_value);
+ break;
+ case G_TYPE_UINT64:
+ case G_TYPE_INT64:
+ case G_TYPE_DOUBLE:
+ /* FIXME it seems get_double is only in 2.12, so for now get a
+ * string and convert it to double */
+#if GLIB_CHECK_VERSION(2,12,0)
+ double_key_value = g_key_file_get_double (keyfile, name,
+ keys[i], NULL);
+#else
+ str_key_value = g_key_file_get_value (keyfile, name, keys[i],
+ NULL);
+ double_key_value = g_strtod(str_key_value, NULL);
+#endif
+ g_value_init (&key_value, G_TYPE_DOUBLE);
+ g_value_set_double (&key_value, double_key_value);
+ DEBUG ("%s is a uint64", keys[i]);
+ DEBUG ("%s is a int64", keys[i]);
+ DEBUG ("%s is a double: %f", keys[i], double_key_value);
+ break;
+ case G_TYPE_ULONG:
+ str_key_value = g_key_file_get_value (keyfile, name, keys[i],
+ NULL);
+ ulong_key_value = strtoul(str_key_value, NULL, 10);
+ g_value_init (&key_value, G_TYPE_ULONG);
+ g_value_set_ulong (&key_value, ulong_key_value);
+ DEBUG ("%s is a ulong: %lu", keys[i], ulong_key_value);
+ break;
+ case G_TYPE_LONG:
+ str_key_value = g_key_file_get_value (keyfile, name, keys[i],
+ NULL);
+ long_key_value = strtol(str_key_value, NULL, 10);
+ g_value_init (&key_value, G_TYPE_LONG);
+ g_value_set_long (&key_value, long_key_value);
+ DEBUG ("%s is a long: %ld", keys[i], long_key_value);
+ break;
+ case G_TYPE_INT:
+ case G_TYPE_UINT:
+ case G_TYPE_ENUM:
+ default:
+ int_key_value = g_key_file_get_integer (keyfile, name,
+ keys[i], NULL);
+ g_value_init (&key_value, G_TYPE_INT);
+ g_value_set_int (&key_value, int_key_value);
+ DEBUG ("%s is a int: %d", keys[i], int_key_value);
+ DEBUG ("%s is a uint", keys[i]);
+ DEBUG ("%s is an enum", keys[i]);
+ DEBUG ("%s is something else, attempting to int conv", keys[i]);
+ break;
+ }
+
+ if (!g_value_transform (&key_value, &prop_value))
+ {
+ DEBUG ("Could not transform gvalue pair");
+ continue;
+ }
+
+ DEBUG ("Setting %s to on %s", keys[i], name);
+ g_object_set_property (G_OBJECT(element), keys[i], &prop_value);
+ }
+
+ g_strfreev(keys);
+}
+
+
+/**
+ * fs_element_added_notifier_set_properties_from_keyfile:
+ * @notifier: a #FsElementAddedNotifier
+ * @keyfile: a #GKeyFile
+ *
+ * Using a #GKeyFile where the groups are the element's type and the key=value
+ * are the property and its value, this function will set the properties
+ * on the elements added to this object after this function has been called.
+ * It will take ownership of the GKeyFile structure.
+ */
+void
+fs_element_added_notifier_set_properties_from_keyfile (
+ FsElementAddedNotifier *notifier,
+ GKeyFile *keyfile)
+{
+ g_signal_connect (notifier, "element-added",
+ G_CALLBACK (_bin_added_from_keyfile), keyfile);
+
+ notifier->priv->keyfiles =
+ g_list_prepend (notifier->priv->keyfiles, keyfile);
+}
+
+
+static void
+_element_added_callback (GstBin *parent, GstElement *element,
+ gpointer user_data)
+{
+ FsElementAddedNotifier *notifier = FS_ELEMENT_ADDED_NOTIFIER (user_data);
+
+ if (GST_IS_BIN (element)) {
+ GstIterator *iter = NULL;
+ gboolean done;
+
+ g_object_ref (notifier);
+ g_object_weak_ref (G_OBJECT (element), (GWeakNotify) g_object_unref,
+ notifier);
+ g_signal_connect (element, "element-added",
+ G_CALLBACK (_element_added_callback), notifier);
+
+ if (parent)
+ g_signal_connect (element, "parent-unset",
+ G_CALLBACK (_bin_unparented_cb), notifier);
+
+ iter = gst_bin_iterate_elements (GST_BIN (element));
+
+ done = FALSE;
+ while (!done)
+ {
+ gpointer item = NULL;
+
+ switch (gst_iterator_next (iter, &item)) {
+ case GST_ITERATOR_OK:
+ /* We make sure the callback has not already been added */
+ if (g_signal_handler_find (item,
+ G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
+ 0, 0, NULL, /* id, detail, closure */
+ _element_added_callback, notifier) == 0)
+ _element_added_callback (GST_BIN_CAST (element), item, notifier);
+ gst_object_unref (item);
+ break;
+ case GST_ITERATOR_RESYNC:
+ // We don't rollback anything, we just ignore already processed ones
+ gst_iterator_resync (iter);
+ break;
+ case GST_ITERATOR_ERROR:
+ g_error ("Wrong parameters were given?");
+ done = TRUE;
+ break;
+ case GST_ITERATOR_DONE:
+ done = TRUE;
+ break;
+ }
+ }
+
+ gst_iterator_free (iter);
+ }
+
+ g_signal_emit (notifier, signals[ELEMENT_ADDED], 0, parent, element);
+}
+
diff --git a/gst-libs/gst/farsight/fs-element-added-notifier.h b/gst-libs/gst/farsight/fs-element-added-notifier.h
new file mode 100644
index 0000000..aa62895
--- /dev/null
+++ b/gst-libs/gst/farsight/fs-element-added-notifier.h
@@ -0,0 +1,97 @@
+/*
+ * Farsight2 - Recursive element addition notifier
+ *
+ * Copyright 2007-2008 Collabora Ltd.
+ * @author: Olivier Crete <olivier.crete at collabora.co.uk>
+ * Copyright 2007-2008 Nokia Corp.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __FS_ELEMENT_ADDED_NOTIFIER_H__
+#define __FS_ELEMENT_ADDED_NOTIFIER_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+
+/* TYPE MACROS */
+#define FS_TYPE_ELEMENT_ADDED_NOTIFIER \
+ (fs_element_added_notifier_get_type())
+#define FS_ELEMENT_ADDED_NOTIFIER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), FS_TYPE_ELEMENT_ADDED_NOTIFIER, \
+ FsElementAddedNotifier))
+#define FS_ELEMENT_ADDED_NOTIFIER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), FS_TYPE_ELEMENT_ADDED_NOTIFIER, \
+ FsElementAddedNotifierClass))
+#define FS_IS_ELEMENT_ADDED_NOTIFIER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), FS_TYPE_ELEMENT_ADDED_NOTIFIER))
+#define FS_IS_ELEMENT_ADDED_NOTIFIER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), FS_TYPE_ELEMENT_ADDED_NOTIFIER))
+#define FS_ELEMENT_ADDED_NOTIFIER_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), FS_TYPE_ELEMENT_ADDED_NOTIFIER, \
+ FsElementAddedNotifierClass))
+
+
+typedef struct _FsElementAddedNotifier FsElementAddedNotifier;
+typedef struct _FsElementAddedNotifierClass FsElementAddedNotifierClass;
+typedef struct _FsElementAddedNotifierPrivate FsElementAddedNotifierPrivate;
+
+/**
+ * FsElementAddedNotifier:
+ * @parent: the #GObject parent
+ *
+ * All members are private
+ */
+
+struct _FsElementAddedNotifier
+{
+ GObject parent;
+
+ /*< private >*/
+
+ FsElementAddedNotifierPrivate *priv;
+};
+
+/**
+ * FsElementAddedNotifierClass:
+ * @parent_class: the #GObjectClass parent
+ *
+ * All members are private
+ */
+struct _FsElementAddedNotifierClass
+{
+ GObjectClass parent_class;
+};
+
+
+GType fs_element_added_notifier_get_type (void);
+
+FsElementAddedNotifier *fs_element_added_notifier_new (void);
+
+void fs_element_added_notifier_add (FsElementAddedNotifier *notifier,
+ GstBin *bin);
+
+gboolean fs_element_added_notifier_remove (FsElementAddedNotifier *notifier,
+ GstBin *bin);
+
+void fs_element_added_notifier_set_properties_from_keyfile (
+ FsElementAddedNotifier *notifier,
+ GKeyFile *keyfile);
+
+G_END_DECLS
+
+#endif /* __FS_ELEMENT_ADDED_NOTIFIER_H__ */
diff --git a/gst-libs/gst/farsight/fs-marshal.list b/gst-libs/gst/farsight/fs-marshal.list
index 5b8f6ef..e16bb50 100644
--- a/gst-libs/gst/farsight/fs-marshal.list
+++ b/gst-libs/gst/farsight/fs-marshal.list
@@ -1,3 +1,4 @@
VOID:OBJECT,INT,STRING,STRING
VOID:INT,STRING,STRING
VOID:BOXED,BOXED
+VOID:OBJECT,OBJECT
diff --git a/gst-libs/gst/farsight/fs-utils.c b/gst-libs/gst/farsight/fs-utils.c
deleted file mode 100644
index d1eb424..0000000
--- a/gst-libs/gst/farsight/fs-utils.c
+++ /dev/null
@@ -1,411 +0,0 @@
-/*
- * Farsight2 - Utility functions
- *
- * Copyright 2007 Collabora Ltd.
- * @author: Olivier Crete <olivier.crete at collabora.co.uk>
- * Copyright 2007 Nokia Corp.
- *
- * fs-session.h - A Farsight Session gobject (base implementation)
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-
-/**
- * SECTION:fs-utils
- * @short_description: Various utility functions
- *
- * This file contains various utility functions for farsight
- */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include "fs-utils.h"
-
-struct FsElementAddedData {
- gint refcount;
- FsElementAddedCallback callback;
- gpointer user_data;
- GstElement *head;
-};
-
-
-static gpointer _element_added_callback (GstBin *parent, GstElement *element,
- gpointer user_data);
-
-
-static struct FsElementAddedData *
-element_added_data_new (FsElementAddedCallback callback, gpointer user_data,
- GstElement *head)
-{
- struct FsElementAddedData *data =
- g_new (struct FsElementAddedData, 1);
-
- data->refcount = 0;
- data->callback = callback;
- data->user_data = user_data;
- data->head = head;
-
- return data;
-}
-
-static void
-element_added_data_inc (struct FsElementAddedData *data)
-{
- g_atomic_int_inc (&data->refcount);
-}
-
-
-static void
-element_added_data_dec (struct FsElementAddedData *data)
-{
- if (g_atomic_int_dec_and_test (&data->refcount))
- {
- g_free (data);
- }
-}
-
-
-static void
-_bin_unparented_cb (GstObject *object, GstObject *parent, gpointer user_data)
-{
- GstIterator *iter = NULL;
- gboolean done;
-
- /* Return if there was no handler connected */
- if (g_signal_handlers_disconnect_by_func(object, _element_added_callback,
- user_data) == 0)
- return;
-
- iter = gst_bin_iterate_elements (GST_BIN (object));
-
- done = FALSE;
- while (!done)
- {
- gpointer item;
-
- switch (gst_iterator_next (iter, &item)) {
- case GST_ITERATOR_OK:
- {
- if (GST_IS_BIN (item))
- _bin_unparented_cb (GST_OBJECT (item), object, user_data);
- }
- break;
- case GST_ITERATOR_RESYNC:
- // We don't rollback anything, we just ignore already processed ones
- gst_iterator_resync (iter);
- break;
- case GST_ITERATOR_ERROR:
- g_error ("Wrong parameters were given?");
- done = TRUE;
- break;
- case GST_ITERATOR_DONE:
- done = TRUE;
- break;
- }
- }
-
- gst_iterator_free (iter);
-}
-
-static gpointer
-_element_added_callback (GstBin *parent, GstElement *element,
- gpointer user_data)
-{
- struct FsElementAddedData *data = user_data;
-
- if (GST_IS_BIN (element)) {
- GstIterator *iter = NULL;
- gboolean done;
-
- element_added_data_inc (data);
- g_object_weak_ref (G_OBJECT (element), (GWeakNotify) element_added_data_dec,
- user_data);
- g_signal_connect (element, "element-added",
- G_CALLBACK (_element_added_callback), user_data);
-
- if (data->head != element)
- g_signal_connect (element, "parent-unset",
- G_CALLBACK (_bin_unparented_cb), user_data);
-
- iter = gst_bin_iterate_elements (GST_BIN (element));
-
- done = FALSE;
- while (!done)
- {
- gpointer item = NULL;
-
- switch (gst_iterator_next (iter, &item)) {
- case GST_ITERATOR_OK:
- /* We make sure the callback has not already been added */
- if (g_signal_handler_find (item,
- G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
- 0, 0, NULL, /* id, detail, closure */
- _element_added_callback, user_data) == 0)
- _element_added_callback (GST_BIN_CAST (element), item, user_data);
- gst_object_unref (item);
- break;
- case GST_ITERATOR_RESYNC:
- // We don't rollback anything, we just ignore already processed ones
- gst_iterator_resync (iter);
- break;
- case GST_ITERATOR_ERROR:
- g_error ("Wrong parameters were given?");
- done = TRUE;
- break;
- case GST_ITERATOR_DONE:
- done = TRUE;
- break;
- }
- }
-
- gst_iterator_free (iter);
- }
-
- data->callback (parent, element, data->user_data);
-
- return data;
-}
-
-/**
- * fs_utils_add_recursive_element_added_notification:
- * @element: A #GstElement
- * @callback: the function to be called when a new element is added
- * @user_data: data that will be passed to the callback
- *
- * The callback will be called on the element and every sub-element if its a
- * bin and this will be done recursively. The function will also be called on
- * any element added in the future to the bin. The callback may be called more
- * than once and should be thread safe (elements may be added from the streaming
- * threads).
- *
- * Returns: a handle that can be used when calling
- * fs_utils_remove_recursive_element_added_notification(), or NULL if there was
- * an error
- */
-
-gpointer
-fs_utils_add_recursive_element_added_notification (GstElement *element,
- FsElementAddedCallback callback,
- gpointer user_data)
-{
- g_assert (callback);
-
- return _element_added_callback (NULL, element,
- element_added_data_new (callback, user_data, element));
-}
-
-/**
- * fs_utils_remove_recursive_element_added_notification:
- * @element: a #GstElement on which
- * fs_utils_add_recursive_element_added_notification() has been called
- * @handle: the handle returned by
- * fs_utils_add_recursive_element_added_notification()
- *
- * This function will remove the callback added by
- * fs_utils_add_recursive_element_added_notification()
- *
- * Returns: TRUE if the notification could be removed, FALSE otherwise
- */
-gboolean
-fs_utils_remove_recursive_element_added_notification (GstElement *element,
- gpointer handle)
-{
- struct FsElementAddedData *data = handle;
-
- if (g_signal_handler_find (element,
- G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
- 0, 0, NULL, /* id, detail, closure */
- _element_added_callback, data) != 0)
- {
- g_assert (data->head == element);
- _bin_unparented_cb (GST_OBJECT (data->head), NULL, data);
- return TRUE;
- }
- else
- {
- return FALSE;
- }
-}
-
-#if 1
-# define DEBUG(...) do {} while (0)
-#else
-# define DEBUG g_debug
-#endif
-
-static void
-_bin_added_from_keyfile (GstBin *bin, GstElement *element, gpointer user_data)
-{
- GKeyFile *keyfile = user_data;
- GstElementFactory *factory = NULL;
- const gchar *name;
- gchar **keys;
- gint i;
-
- factory = gst_element_get_factory (element);
-
- g_assert (factory);
-
- name = gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory));
-
- if (!name)
- return;
-
-
- if (!g_key_file_has_group (keyfile, name))
- return;
-
-
- DEBUG ("Found config for %s", name);
- keys = g_key_file_get_keys (keyfile, name, NULL, NULL);
-
- for (i = 0; keys[i]; i++)
- {
- GParamSpec *param_spec;
- GValue key_value = { 0 };
- GValue prop_value = { 0 };
-
- gchar *str_key_value;
- gboolean bool_key_value;
- gint int_key_value;
- gdouble double_key_value;
- glong long_key_value;
- gulong ulong_key_value;
-
- DEBUG ("getting %s", keys[i]);
- param_spec = g_object_class_find_property
- (G_OBJECT_GET_CLASS(element), keys[i]);
-
- /* If the paremeter does not exist, or is one of those,
- * then lets skip it
- * TODO: What if we want to pass GstCaps as strings?
- */
- if (!param_spec ||
- g_type_is_a (param_spec->value_type, G_TYPE_OBJECT) ||
- g_type_is_a (param_spec->value_type, GST_TYPE_MINI_OBJECT) ||
- g_type_is_a (param_spec->value_type, G_TYPE_INTERFACE) ||
- g_type_is_a (param_spec->value_type, G_TYPE_BOXED) ||
- g_type_is_a (param_spec->value_type, G_TYPE_GTYPE) ||
- g_type_is_a (param_spec->value_type, G_TYPE_POINTER))
- {
- continue;
- }
-
- g_value_init (&prop_value, param_spec->value_type);
-
- switch (param_spec->value_type)
- {
- case G_TYPE_STRING:
- str_key_value = g_key_file_get_value (keyfile, name,
- keys[i], NULL);
- g_value_init (&key_value, G_TYPE_STRING);
- g_value_set_string (&key_value, str_key_value);
- DEBUG ("%s is a string: %s", keys[i], str_key_value);
- g_free (str_key_value);
- break;
- case G_TYPE_BOOLEAN:
- bool_key_value = g_key_file_get_boolean (keyfile, name,
- keys[i], NULL);
- g_value_init (&key_value, G_TYPE_BOOLEAN);
- g_value_set_boolean (&key_value, bool_key_value);
- DEBUG ("%s is a boolean: %d", keys[i], bool_key_value);
- break;
- case G_TYPE_UINT64:
- case G_TYPE_INT64:
- case G_TYPE_DOUBLE:
- /* FIXME it seems get_double is only in 2.12, so for now get a
- * string and convert it to double */
-#if GLIB_CHECK_VERSION(2,12,0)
- double_key_value = g_key_file_get_double (keyfile, name,
- keys[i], NULL);
-#else
- str_key_value = g_key_file_get_value (keyfile, name, keys[i],
- NULL);
- double_key_value = g_strtod(str_key_value, NULL);
-#endif
- g_value_init (&key_value, G_TYPE_DOUBLE);
- g_value_set_double (&key_value, double_key_value);
- DEBUG ("%s is a uint64", keys[i]);
- DEBUG ("%s is a int64", keys[i]);
- DEBUG ("%s is a double: %f", keys[i], double_key_value);
- break;
- case G_TYPE_ULONG:
- str_key_value = g_key_file_get_value (keyfile, name, keys[i],
- NULL);
- ulong_key_value = strtoul(str_key_value, NULL, 10);
- g_value_init (&key_value, G_TYPE_ULONG);
- g_value_set_ulong (&key_value, ulong_key_value);
- DEBUG ("%s is a ulong: %lu", keys[i], ulong_key_value);
- break;
- case G_TYPE_LONG:
- str_key_value = g_key_file_get_value (keyfile, name, keys[i],
- NULL);
- long_key_value = strtol(str_key_value, NULL, 10);
- g_value_init (&key_value, G_TYPE_LONG);
- g_value_set_long (&key_value, long_key_value);
- DEBUG ("%s is a long: %ld", keys[i], long_key_value);
- break;
- case G_TYPE_INT:
- case G_TYPE_UINT:
- case G_TYPE_ENUM:
- default:
- int_key_value = g_key_file_get_integer (keyfile, name,
- keys[i], NULL);
- g_value_init (&key_value, G_TYPE_INT);
- g_value_set_int (&key_value, int_key_value);
- DEBUG ("%s is a int: %d", keys[i], int_key_value);
- DEBUG ("%s is a uint", keys[i]);
- DEBUG ("%s is an enum", keys[i]);
- DEBUG ("%s is something else, attempting to int conv", keys[i]);
- break;
- }
-
- if (!g_value_transform (&key_value, &prop_value))
- {
- DEBUG ("Could not transform gvalue pair");
- continue;
- }
-
- DEBUG ("Setting %s to on %s", keys[i], name);
- g_object_set_property (G_OBJECT(element), keys[i], &prop_value);
- }
-
- g_strfreev(keys);
-}
-
-/**
- * fs_utils_add_recursive_element_setter_from_keyfile:
- * @element: a #GstElement
- * @keyfile: a #GKeyFile
- *
- * Using a keyfile where the groups are the element's type and the key=value
- * are the property and its value, this function will set the properties on the
- * element passed and its subelements.
- *
- * Returns: a handle that can be used for
- * fs_utils_remove_recursive_element_added_notification(), or NULL if there is
- * an error
- */
-gpointer
-fs_utils_add_recursive_element_setter_from_keyfile (GstElement *element,
- GKeyFile *keyfile)
-{
- return fs_utils_add_recursive_element_added_notification (element,
- _bin_added_from_keyfile,
- keyfile);
-}
diff --git a/gst-libs/gst/farsight/fs-utils.h b/gst-libs/gst/farsight/fs-utils.h
deleted file mode 100644
index 4dcb0d4..0000000
--- a/gst-libs/gst/farsight/fs-utils.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Farsight2 - Utility functions
- *
- * Copyright 2007 Collabora Ltd.
- * @author: Olivier Crete <olivier.crete at collabora.co.uk>
- * Copyright 2007 Nokia Corp.
- *
- * fs-session.h - A Farsight Session gobject (base implementation)
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef __FS_UTILS_H__
-#define __FS_UTILS_H__
-
-#include <gst/gst.h>
-
-G_BEGIN_DECLS
-
-/**
- * FsElementAddedCallback:
- * @bin: The #GstBin to which the element was added, will be NULL if the element
- * is the top-level bin
- * @element: The just-added #GstElement
- * @user_data: The user data passed by the user
- *
- * The callback used by #fs_utils_add_recursive_element_added_notification
- */
-
-typedef void (*FsElementAddedCallback) (GstBin *bin,
- GstElement *element,
- gpointer user_data);
-
-gpointer fs_utils_add_recursive_element_added_notification (GstElement *element,
- FsElementAddedCallback callback,
- gpointer user_data);
-
-gboolean fs_utils_remove_recursive_element_added_notification (
- GstElement *element,
- gpointer handle);
-
-
-gpointer fs_utils_add_recursive_element_setter_from_keyfile (
- GstElement *element,
- GKeyFile *keyfile);
-
-G_END_DECLS
-
-#endif /* __FS_UTILS_H__ */
diff --git a/tests/check/utils/binadded.c b/tests/check/utils/binadded.c
index acca926..5d1891f 100644
--- a/tests/check/utils/binadded.c
+++ b/tests/check/utils/binadded.c
@@ -24,14 +24,15 @@
#endif
#include <gst/check/gstcheck.h>
-#include <gst/farsight/fs-utils.h>
+#include <gst/farsight/fs-element-added-notifier.h>
gboolean called = FALSE;
gpointer last_added = NULL;
gpointer last_bin = NULL;
static void
-_added_cb (GstBin *bin, GstElement *element, gpointer user_data)
+_added_cb (FsElementAddedNotifier *notifier, GstBin *bin, GstElement *element,
+ gpointer user_data)
{
GstObject *parent = NULL;
@@ -54,17 +55,19 @@ GST_START_TEST (test_bin_added_simple)
{
GstElement *pipeline = NULL;
GstElement *identity = NULL;
- gpointer handle = NULL;
+ FsElementAddedNotifier *notifier = NULL;
pipeline = gst_pipeline_new (NULL);
identity = gst_element_factory_make ("identity", NULL);
gst_object_ref (identity);
- handle = fs_utils_add_recursive_element_added_notification (pipeline,
- _added_cb, &last_added);
+ notifier = fs_element_added_notifier_new ();
- fail_if (handle == NULL, "Could not add notification to pipeline");
+ g_signal_connect (notifier, "element-added",
+ G_CALLBACK (_added_cb), &last_added);
+
+ fs_element_added_notifier_add (notifier, GST_BIN (pipeline));
fail_unless (gst_bin_add (GST_BIN (pipeline), identity),
"Could not add identity to pipeline");
@@ -85,10 +88,9 @@ GST_START_TEST (test_bin_added_simple)
called = FALSE;
last_added = last_bin = NULL;
-
fail_unless (
- fs_utils_remove_recursive_element_added_notification (pipeline, handle),
- "Could not remove notification handle %p", handle);
+ fs_element_added_notifier_remove (notifier, GST_BIN (pipeline)),
+ "Could not remove notification");
fail_unless (gst_bin_add (GST_BIN (pipeline), identity),
"Could not add identity to pipeline");
@@ -98,6 +100,7 @@ GST_START_TEST (test_bin_added_simple)
called = FALSE;
last_added = last_bin = NULL;
+ g_object_unref (notifier);
gst_object_unref (identity);
gst_object_unref (pipeline);
}
@@ -109,7 +112,7 @@ GST_START_TEST (test_bin_added_recursive)
GstElement *pipeline = NULL;
GstElement *bin = NULL;
GstElement *identity = NULL;
- gpointer handle = NULL;
+ FsElementAddedNotifier *notifier = NULL;
pipeline = gst_pipeline_new (NULL);
@@ -121,10 +124,12 @@ GST_START_TEST (test_bin_added_recursive)
identity = gst_element_factory_make ("identity", NULL);
gst_object_ref (identity);
- handle = fs_utils_add_recursive_element_added_notification (pipeline,
- _added_cb, &last_added);
+ notifier = fs_element_added_notifier_new ();
+
+ g_signal_connect (notifier, "element-added",
+ G_CALLBACK (_added_cb), &last_added);
- fail_if (handle == NULL, "Could not add notification to bin");
+ fs_element_added_notifier_add (notifier, GST_BIN (pipeline));
fail_unless (gst_bin_add (GST_BIN (bin), identity),
"Could not add identity to bin");
@@ -147,8 +152,8 @@ GST_START_TEST (test_bin_added_recursive)
fail_unless (
- fs_utils_remove_recursive_element_added_notification (pipeline, handle),
- "Could not remove notification handle %p", handle);
+ fs_element_added_notifier_remove (notifier, GST_BIN (pipeline)),
+ "Could not remove notification");
fail_unless (gst_bin_add (GST_BIN (bin), identity),
"Could not add identity to bin");
@@ -158,10 +163,7 @@ GST_START_TEST (test_bin_added_recursive)
fail_unless (gst_bin_remove (GST_BIN (bin), identity),
"Could not remove identity from bin");
- handle = fs_utils_add_recursive_element_added_notification (pipeline,
- _added_cb, &last_added);
-
- fail_if (handle == NULL, "Could not re-add notification to bin");
+ fs_element_added_notifier_add (notifier, GST_BIN (pipeline));
called = FALSE;
last_added = last_bin = NULL;
@@ -175,6 +177,7 @@ GST_START_TEST (test_bin_added_recursive)
" but the callback was still called");
+ g_object_unref (notifier);
gst_object_unref (identity);
gst_object_unref (bin);
gst_object_unref (pipeline);
@@ -187,7 +190,7 @@ GST_START_TEST (test_bin_keyfile)
GKeyFile *keyfile = g_key_file_new ();
GstElement *pipeline = NULL;
GstElement *identity = NULL;
- gpointer handle = NULL;
+ FsElementAddedNotifier *notifier = NULL;
gboolean sync;
g_key_file_set_boolean (keyfile, "identity", "sync", TRUE);
@@ -200,9 +203,11 @@ GST_START_TEST (test_bin_keyfile)
g_object_get (identity, "sync", &sync, NULL);
fail_unless (sync == FALSE, "sync prop on identity does not start at FALSE");
- handle = fs_utils_add_recursive_element_setter_from_keyfile (pipeline,
- keyfile);
- fail_if (handle == NULL, "Could not add notification to pipeline");
+ notifier = fs_element_added_notifier_new ();
+
+ fs_element_added_notifier_set_properties_from_keyfile (notifier, keyfile);
+
+ fs_element_added_notifier_add (notifier, GST_BIN (pipeline));
fail_unless (gst_bin_add (GST_BIN (pipeline), identity),
"Could not add identity to pipeline");
@@ -220,8 +225,8 @@ GST_START_TEST (test_bin_keyfile)
fail_unless (sync == FALSE, "sync prop on identity not reset to FALSE");
fail_unless (
- fs_utils_remove_recursive_element_added_notification (pipeline, handle),
- "Could not remove notification handle %p", handle);
+ fs_element_added_notifier_remove (notifier, GST_BIN (pipeline)),
+ "Could not remove notification");
fail_unless (gst_bin_add (GST_BIN (pipeline), identity),
"Could not add identity to bin");
@@ -229,16 +234,13 @@ GST_START_TEST (test_bin_keyfile)
g_object_get (identity, "sync", &sync, NULL);
fail_if (sync == TRUE, "sync prop on identity changed to TRUE");
- handle = fs_utils_add_recursive_element_setter_from_keyfile (pipeline,
- keyfile);
- fail_if (handle == NULL, "Could not add notification to pipeline");
+ fs_element_added_notifier_add (notifier, GST_BIN (pipeline));
g_object_get (identity, "sync", &sync, NULL);
fail_unless (sync == TRUE, "sync prop on identity is not changed to TRUE");
gst_object_unref (identity);
gst_object_unref (pipeline);
- g_key_file_free (keyfile);
}
GST_END_TEST;
--
1.5.6.5
More information about the farsight-commits
mailing list