aboutsummaryrefslogtreecommitdiffstats
path: root/src/empathy-audio-sink.c
diff options
context:
space:
mode:
authorSjoerd Simons <sjoerd.simons@collabora.co.uk>2011-03-12 03:01:17 +0800
committerEmilio Pozuelo Monfort <emilio.pozuelo@collabora.co.uk>2011-06-09 17:20:06 +0800
commite9fb5d29ff44ae35411b02c3715ae9650b61dd25 (patch)
tree152c8278e8bfc5fe79eb5cc700bce2cc52a5e8a7 /src/empathy-audio-sink.c
parent8cbd6a5c6addfd360bdd274ac60e3c035b2ebc9b (diff)
downloadgsoc2013-empathy-e9fb5d29ff44ae35411b02c3715ae9650b61dd25.tar
gsoc2013-empathy-e9fb5d29ff44ae35411b02c3715ae9650b61dd25.tar.gz
gsoc2013-empathy-e9fb5d29ff44ae35411b02c3715ae9650b61dd25.tar.bz2
gsoc2013-empathy-e9fb5d29ff44ae35411b02c3715ae9650b61dd25.tar.lz
gsoc2013-empathy-e9fb5d29ff44ae35411b02c3715ae9650b61dd25.tar.xz
gsoc2013-empathy-e9fb5d29ff44ae35411b02c3715ae9650b61dd25.tar.zst
gsoc2013-empathy-e9fb5d29ff44ae35411b02c3715ae9650b61dd25.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
Diffstat (limited to 'src/empathy-audio-sink.c')
-rw-r--r--src/empathy-audio-sink.c274
1 files changed, 228 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);
}