playbin2: Look for volume/mute properties recursively in audio element.
authorMichael Smith <msmith@songbirdnest.com>
Wed, 11 Feb 2009 01:10:33 +0000 (17:10 -0800)
committerMichael Smith <msmith@songbirdnest.com>
Wed, 11 Feb 2009 01:20:12 +0000 (17:20 -0800)
Rather than only checking for volume property on the audio sink
directly, recursively look for it on sinks within it (if it's a bin).
Allows use of sink-as-volume-control where the application has supplied
an audio-sink bin that includes a real audio sink internally.

gst/playback/gstplaysink.c

index 822cc45..f926e3d 100644 (file)
@@ -640,6 +640,50 @@ gst_play_sink_find_property (GstPlaySink * playsink, GstElement * obj,
   return result;
 }
 
+static gint
+find_property_sink (GstElement * element, const gchar * name)
+{
+  gint res;
+  gboolean is_sink;
+
+  GST_OBJECT_LOCK (element);
+  is_sink = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_IS_SINK);
+  GST_OBJECT_UNLOCK (element);
+
+  if (is_sink &&
+      g_object_class_find_property (G_OBJECT_GET_CLASS (element), name)) {
+    res = 0;
+    GST_DEBUG_OBJECT (element, "found %s property on sink", name);
+  } else {
+    GST_DEBUG_OBJECT (element, "did not find %s property", name);
+    res = 1;
+    gst_object_unref (element);
+  }
+  return res;
+}
+
+/* find a sink in the hierarchy with a property named @name */
+static GstElement *
+gst_play_sink_find_property_sinks (GstPlaySink * playsink, GstElement * obj,
+    const gchar * name)
+{
+  GstElement *result = NULL;
+  GstIterator *it;
+
+  if (GST_IS_BIN (obj)) {
+    it = gst_bin_iterate_recurse (GST_BIN_CAST (obj));
+    result = gst_iterator_find_custom (it,
+        (GCompareFunc) find_property_sink, (gpointer) name);
+    gst_iterator_free (it);
+  } else {
+    if (g_object_class_find_property (G_OBJECT_GET_CLASS (obj), name)) {
+      result = obj;
+      gst_object_ref (obj);
+    }
+  }
+  return result;
+}
+
 /* try to change the state of an element. This function returns the element when
  * the state change could be performed. When this function returns NULL an error
  * occured and the element is unreffed. */
@@ -956,21 +1000,28 @@ gen_audio_chain (GstPlaySink * playsink, gboolean raw, gboolean queue)
     prev = NULL;
   }
 
-  /* check if the sink has the volume property, if it does we don't need to
-   * add a volume element. */
+  /* check if the sink, or something within the sink, has the volume property.
+   * If it does we don't need to add a volume element.  */
+  elem = NULL;
   if (g_object_class_find_property (G_OBJECT_GET_CLASS (chain->sink), "volume")) {
+    elem = gst_object_ref (chain->sink);
+  } else if (GST_IS_BIN (chain->sink)) {
+    elem = gst_play_sink_find_property_sinks (playsink, chain->sink, "volume");
+  }
+  if (elem) {
     GST_DEBUG_OBJECT (playsink, "the sink has a volume property");
     have_volume = TRUE;
     /* use the sink to control the volume */
-    chain->volume = chain->sink;
-    g_object_set (G_OBJECT (chain->volume), "volume", playsink->volume, NULL);
+    chain->volume = elem;
+    g_object_set (G_OBJECT (elem), "volume", playsink->volume, NULL);
     /* if the sink also has a mute property we can use this as well. We'll only
      * use the mute property if there is a volume property. We can simulate the
      * mute with the volume otherwise. */
-    if (g_object_class_find_property (G_OBJECT_GET_CLASS (chain->sink), "mute")) {
+    if (g_object_class_find_property (G_OBJECT_GET_CLASS (elem), "mute")) {
       GST_DEBUG_OBJECT (playsink, "the sink has a mute property");
-      chain->mute = chain->sink;
+      chain->mute = elem;
     }
+    gst_object_unref (elem);
   } else {
     /* no volume, we need to add a volume element when we can */
     GST_DEBUG_OBJECT (playsink, "the sink has no volume property");