aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSjoerd Simons <sjoerd.simons@collabora.co.uk>2011-03-12 03:01:17 +0800
committerSjoerd Simons <sjoerd.simons@collabora.co.uk>2011-03-12 03:01:19 +0800
commit952d1607e5be84369843eaaee6f1b668330bd9ff (patch)
tree7e7fe9ac61700b006b228f27ac47cee94ca856bd
parent2bf0786b1afd3e9c9c4bead7d9704ae2c18303fc (diff)
downloadgsoc2013-empathy-952d1607e5be84369843eaaee6f1b668330bd9ff.tar
gsoc2013-empathy-952d1607e5be84369843eaaee6f1b668330bd9ff.tar.gz
gsoc2013-empathy-952d1607e5be84369843eaaee6f1b668330bd9ff.tar.bz2
gsoc2013-empathy-952d1607e5be84369843eaaee6f1b668330bd9ff.tar.lz
gsoc2013-empathy-952d1607e5be84369843eaaee6f1b668330bd9ff.tar.xz
gsoc2013-empathy-952d1607e5be84369843eaaee6f1b668330bd9ff.tar.zst
gsoc2013-empathy-952d1607e5be84369843eaaee6f1b668330bd9ff.zip
Implement request pads for multiple sinks
Instead of using an live-adder we're moving to using multiple pulseaudio sinks as pulse can do the right thing (tm). To make this easy for the call window have one bin that handles all the juggling of audiosinks and audio conversion
-rw-r--r--src/empathy-audio-sink.c274
-rw-r--r--src/empathy-audio-sink.h2
2 files changed, 230 insertions, 46 deletions
diff --git a/src/empathy-audio-sink.c b/src/empathy-audio-sink.c
index 1d2169593..31fffff10 100644
--- a/src/empathy-audio-sink.c
+++ b/src/empathy-audio-sink.c
@@ -22,6 +22,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <gst/audio/audio.h>
#include <gst/farsight/fs-element-added-notifier.h>
#include "empathy-audio-sink.h"
@@ -38,20 +39,58 @@ enum
static guint signals[LAST_SIGNAL] = {0};
#endif
+typedef struct {
+ GstPad *pad;
+ GstElement *bin;
+ GstElement *volume;
+ GstElement *sink;
+} AudioBin;
+
+static AudioBin *
+audio_bin_new (GstPad *pad,
+ GstElement *bin,
+ GstElement *volume,
+ GstElement *sink)
+{
+ AudioBin *result = g_slice_new0 (AudioBin);
+
+ result->pad = pad;
+ result->bin = bin;
+ result->volume = gst_object_ref (volume);
+ result->sink = sink;
+
+ return result;
+}
+
+static void
+audio_bin_free (AudioBin *bin)
+{
+ gst_object_unref (bin->volume);
+ g_slice_free (AudioBin, bin);
+}
+
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE(
+ "sink%d",
+ GST_PAD_SINK,
+ GST_PAD_REQUEST,
+ GST_STATIC_CAPS ( GST_AUDIO_INT_PAD_TEMPLATE_CAPS " ; "
+ GST_AUDIO_FLOAT_PAD_TEMPLATE_CAPS)
+);
enum {
PROP_VOLUME = 1,
};
-/* private structure */
-typedef struct _EmpathyGstAudioSinkPrivate EmpathyGstAudioSinkPrivate;
-
struct _EmpathyGstAudioSinkPrivate
{
gboolean dispose_has_run;
- GstElement *sink;
- GstElement *volume;
FsElementAddedNotifier *notifier;
+
+ gdouble volume;
+
+ /* Pad -> *owned* subbin hash */
+ GHashTable *audio_bins;
};
#define EMPATHY_GST_AUDIO_SINK_GET_PRIVATE(o) \
@@ -66,54 +105,68 @@ empathy_audio_sink_element_added_cb (FsElementAddedNotifier *notifier,
if (g_object_class_find_property (G_OBJECT_GET_CLASS (element), "volume"))
{
- gdouble volume;
-
- volume = empathy_audio_sink_get_volume (self);
- empathy_audio_sink_set_volume (self, 1.0);
-
- if (priv->volume != NULL)
- g_object_unref (priv->volume);
- priv->volume = g_object_ref (element);
-
- if (volume != 1.0)
- empathy_audio_sink_set_volume (self, volume);
+ /* An element was added with a volume property, lets find its subbin and
+ * update the volume in it */
+ GHashTableIter iter;
+ AudioBin *audio_bin = NULL;
+ gpointer value;
+
+ g_hash_table_iter_init (&iter, priv->audio_bins);
+
+ while (g_hash_table_iter_next (&iter, NULL, &value))
+ {
+ AudioBin *b = value;
+
+ if (gst_object_has_ancestor (GST_OBJECT (element),
+ GST_OBJECT (b->bin)))
+ {
+ audio_bin = b;
+ break;
+ }
+ }
+
+ if (audio_bin == NULL)
+ {
+ g_warning ("Element added that doesn't belong to us ?");
+ return;
+ }
+
+ /* Set the old volume to 1 and the new volume to the volume */
+ g_object_set (audio_bin->volume, "volume", 1.0, NULL);
+ gst_object_unref (audio_bin->volume);
+
+ audio_bin->volume = gst_object_ref (element);
+ g_object_set (audio_bin->volume, "volume", self->priv->volume, NULL);
}
}
static void
-empathy_audio_sink_init (EmpathyGstAudioSink *obj)
+empathy_audio_sink_init (EmpathyGstAudioSink *self)
{
- EmpathyGstAudioSinkPrivate *priv = EMPATHY_GST_AUDIO_SINK_GET_PRIVATE (obj);
- GstElement *resample;
- GstPad *ghost, *sink;
-
- priv->notifier = fs_element_added_notifier_new ();
- g_signal_connect (priv->notifier, "element-added",
- G_CALLBACK (empathy_audio_sink_element_added_cb), obj);
-
- resample = gst_element_factory_make ("audioresample", NULL);
-
- priv->volume = gst_element_factory_make ("volume", NULL);
- g_object_ref (priv->volume);
-
- priv->sink = gst_element_factory_make ("gconfaudiosink", NULL);
-
- fs_element_added_notifier_add (priv->notifier, GST_BIN (priv->sink));
+ EmpathyGstAudioSinkPrivate *priv;
- gst_bin_add_many (GST_BIN (obj), resample, priv->volume, priv->sink, NULL);
- gst_element_link_many (resample, priv->volume, priv->sink, NULL);
+ priv = self->priv = EMPATHY_GST_AUDIO_SINK_GET_PRIVATE (self);
- sink = gst_element_get_static_pad (resample, "sink");
+ priv->volume = 1.0;
- ghost = gst_ghost_pad_new ("sink", sink);
- gst_element_add_pad (GST_ELEMENT (obj), ghost);
+ priv->audio_bins = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+ NULL, (GDestroyNotify) audio_bin_free);
- gst_object_unref (G_OBJECT (sink));
+ priv->notifier = fs_element_added_notifier_new ();
+ g_signal_connect (priv->notifier, "element-added",
+ G_CALLBACK (empathy_audio_sink_element_added_cb), self);
}
static void empathy_audio_sink_dispose (GObject *object);
static void empathy_audio_sink_finalize (GObject *object);
+static GstPad * empathy_audio_sink_request_new_pad (GstElement *self,
+ GstPadTemplate *templ,
+ const gchar* name);
+
+static void empathy_audio_sink_release_pad (GstElement *self,
+ GstPad *pad);
+
static void
empathy_audio_sink_set_property (GObject *object,
guint property_id, const GValue *value, GParamSpec *pspec)
@@ -149,8 +202,13 @@ empathy_audio_sink_class_init (EmpathyGstAudioSinkClass
*empathy_audio_sink_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (empathy_audio_sink_class);
+ GstElementClass *element_class =
+ GST_ELEMENT_CLASS (empathy_audio_sink_class);
GParamSpec *param_spec;
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&sink_template));
+
g_type_class_add_private (empathy_audio_sink_class,
sizeof (EmpathyGstAudioSinkPrivate));
@@ -160,6 +218,9 @@ empathy_audio_sink_class_init (EmpathyGstAudioSinkClass
object_class->set_property = empathy_audio_sink_set_property;
object_class->get_property = empathy_audio_sink_get_property;
+ element_class->request_new_pad = empathy_audio_sink_request_new_pad;
+ element_class->release_pad = empathy_audio_sink_release_pad;
+
param_spec = g_param_spec_double ("volume", "Volume", "volume control",
0.0, 5.0, 1.0,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
@@ -181,9 +242,9 @@ empathy_audio_sink_dispose (GObject *object)
g_object_unref (priv->notifier);
priv->notifier = NULL;
- if (priv->volume != NULL)
- g_object_unref (priv->volume);
- priv->volume = NULL;
+ if (priv->audio_bins != NULL)
+ g_hash_table_unref (priv->audio_bins);
+ priv->audio_bins = NULL;
if (G_OBJECT_CLASS (empathy_audio_sink_parent_class)->dispose)
G_OBJECT_CLASS (empathy_audio_sink_parent_class)->dispose (object);
@@ -219,17 +280,138 @@ void
empathy_audio_sink_set_volume (EmpathyGstAudioSink *sink, gdouble volume)
{
EmpathyGstAudioSinkPrivate *priv = EMPATHY_GST_AUDIO_SINK_GET_PRIVATE (sink);
+ GHashTableIter iter;
+ gpointer value;
+
+ priv->volume = volume;
+ g_hash_table_iter_init (&iter, priv->audio_bins);
- g_object_set (G_OBJECT (priv->volume), "volume", volume, NULL);
+ while (g_hash_table_iter_next (&iter, NULL, &value))
+ {
+ AudioBin *b = value;
+ g_object_set (b->volume, "volume", volume, NULL);
+ }
}
gdouble
empathy_audio_sink_get_volume (EmpathyGstAudioSink *sink)
{
EmpathyGstAudioSinkPrivate *priv = EMPATHY_GST_AUDIO_SINK_GET_PRIVATE (sink);
- gdouble volume;
+ return priv->volume;
+}
+
+static GstPad *
+empathy_audio_sink_request_new_pad (GstElement *element,
+ GstPadTemplate *templ,
+ const gchar* name)
+{
+ EmpathyGstAudioSink *self = EMPATHY_GST_AUDIO_SINK (element);
+ GstElement *bin, *sink, *volume, *resample, *audioconvert0, *audioconvert1;
+ GstPad *pad = NULL;
+ GstPad *subpad, *filterpad;
+ AudioBin *audiobin;
+
+ bin = gst_bin_new (NULL);
+
+ audioconvert0 = gst_element_factory_make ("audioconvert", NULL);
+ if (audioconvert0 == NULL)
+ goto error;
+
+ gst_bin_add (GST_BIN (bin), audioconvert0);
+
+ resample = gst_element_factory_make ("audioresample", NULL);
+ if (resample == NULL)
+ goto error;
+
+ gst_bin_add (GST_BIN (bin), resample);
+
+ audioconvert1 = gst_element_factory_make ("audioconvert", NULL);
+ if (audioconvert1 == NULL)
+ goto error;
+
+ gst_bin_add (GST_BIN (bin), audioconvert1);
+
+ volume = gst_element_factory_make ("volume", NULL);
+ if (volume == NULL)
+ goto error;
+
+ gst_bin_add (GST_BIN (bin), volume);
+
+ sink = gst_element_factory_make ("gconfaudiosink", NULL);
+ if (sink == NULL)
+ goto error;
+
+ gst_bin_add (GST_BIN (bin), sink);
+ fs_element_added_notifier_add (self->priv->notifier, GST_BIN (sink));
+
+ if (!gst_element_link_many (audioconvert0, resample, audioconvert1,
+ volume, sink, NULL))
+ goto error;
+
+ filterpad = gst_element_get_static_pad (audioconvert0, "sink");
+
+ if (filterpad == NULL)
+ goto error;
+
+ subpad = gst_ghost_pad_new ("sink", filterpad);
+ if (!gst_element_add_pad (GST_ELEMENT (bin), subpad))
+ goto error;
+
+ gst_bin_add (GST_BIN (self), bin);
+
+ /* Add elemnt into the hash table before syncing state so we know about it
+ * when elements are added */
+ pad = gst_ghost_pad_new (name, subpad);
+ audiobin = audio_bin_new (pad, bin, volume, sink);
+
+ g_hash_table_insert (self->priv->audio_bins, pad, audiobin);
+
+ if (!gst_element_sync_state_with_parent (bin))
+ goto error;
+
+ if (!gst_pad_set_active (pad, TRUE))
+ goto error;
+
+ if (!gst_element_add_pad (GST_ELEMENT (self), pad))
+ goto error;
+
+
+ return pad;
+
+error:
+ if (pad != NULL)
+ {
+ g_hash_table_remove (self->priv->audio_bins, pad);
+ gst_object_unref (pad);
+ }
+
+ gst_object_unref (bin);
+ g_warning ("Failed to create output subpipeline");
+ return NULL;
+}
+
+static void
+empathy_audio_sink_release_pad (GstElement *element,
+ GstPad *pad)
+{
+ EmpathyGstAudioSink *self = EMPATHY_GST_AUDIO_SINK (element);
+ AudioBin *abin;
+
+ abin = g_hash_table_lookup (self->priv->audio_bins, pad);
+ g_hash_table_steal (self->priv->audio_bins, pad);
+
+ if (abin == NULL)
+ {
+ g_warning ("Releasing a pad that doesn't belong to us ?");
+ return;
+ }
+
+ gst_pad_set_active (pad, FALSE);
+ gst_element_remove_pad (element, pad);
- g_object_get (G_OBJECT (priv->volume), "volume", &volume, NULL);
+ gst_element_set_locked_state (abin->bin, TRUE);
+ gst_element_set_state (abin->bin, GST_STATE_NULL);
+ gst_bin_remove (GST_BIN (self), abin->bin);
- return volume;
+ audio_bin_free (abin);
}
diff --git a/src/empathy-audio-sink.h b/src/empathy-audio-sink.h
index 21ebf2b5a..cc21fc467 100644
--- a/src/empathy-audio-sink.h
+++ b/src/empathy-audio-sink.h
@@ -28,6 +28,7 @@ G_BEGIN_DECLS
typedef struct _EmpathyGstAudioSink EmpathyGstAudioSink;
typedef struct _EmpathyGstAudioSinkClass EmpathyGstAudioSinkClass;
+typedef struct _EmpathyGstAudioSinkPrivate EmpathyGstAudioSinkPrivate;
struct _EmpathyGstAudioSinkClass {
GstBinClass parent_class;
@@ -35,6 +36,7 @@ struct _EmpathyGstAudioSinkClass {
struct _EmpathyGstAudioSink {
GstBin parent;
+ EmpathyGstAudioSinkPrivate *priv;
};
GType empathy_audio_sink_get_type (void);