From 62dfae4bf6a967076140a1625dfc7b41d1cac3e5 Mon Sep 17 00:00:00 2001 From: Sjoerd Simons Date: Tue, 3 Mar 2009 17:34:38 +0000 Subject: Add volume control and rms/peak level signals Signed-off-by: Sjoerd Simons svn path=/trunk/; revision=2560 --- libempathy-gtk/empathy-audio-src.c | 278 +++++++++++++++++++++++++++++++++++-- libempathy-gtk/empathy-audio-src.h | 3 + 2 files changed, 269 insertions(+), 12 deletions(-) (limited to 'libempathy-gtk') diff --git a/libempathy-gtk/empathy-audio-src.c b/libempathy-gtk/empathy-audio-src.c index c7437e93e..c3e11095c 100644 --- a/libempathy-gtk/empathy-audio-src.c +++ b/libempathy-gtk/empathy-audio-src.c @@ -22,19 +22,26 @@ #include #include +#include #include "empathy-audio-src.h" G_DEFINE_TYPE(EmpathyGstAudioSrc, empathy_audio_src, GST_TYPE_BIN) /* signal enum */ -#if 0 enum { + PEAK_LEVEL_CHANGED, + RMS_LEVEL_CHANGED, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = {0}; -#endif + +enum { + PROP_VOLUME = 1, + PROP_RMS_LEVEL, + PROP_PEAK_LEVEL, +}; /* private structure */ typedef struct _EmpathyGstAudioSrcPrivate EmpathyGstAudioSrcPrivate; @@ -43,30 +50,72 @@ struct _EmpathyGstAudioSrcPrivate { gboolean dispose_has_run; GstElement *src; + GstElement *volume; + GstElement *level; + FsElementAddedNotifier *notifier; + + gdouble peak_level; + gdouble rms_level; + + GMutex *lock; + guint idle_id; }; #define EMPATHY_GST_AUDIO_SRC_GET_PRIVATE(o) \ (G_TYPE_INSTANCE_GET_PRIVATE ((o), EMPATHY_TYPE_GST_AUDIO_SRC, \ EmpathyGstAudioSrcPrivate)) +static void +empathy_audio_src_element_added_cb (FsElementAddedNotifier *notifier, + GstBin *bin, GstElement *element, EmpathyGstAudioSrc *self) +{ + EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (self); + + if (g_object_class_find_property (G_OBJECT_GET_CLASS (element), "volume")) + { + gdouble volume; + + volume = empathy_audio_src_get_volume (self); + empathy_audio_src_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_src_set_volume (self, volume); + } +} + static void empathy_audio_src_init (EmpathyGstAudioSrc *obj) { EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (obj); - //GstElement *resample; GstPad *ghost, *src; - /* allocate any data required by the object here */ - //resample = gst_element_factory_make ("audioresample", NULL); + priv->peak_level = -G_MAXDOUBLE; + priv->lock = g_mutex_new (); + + priv->notifier = fs_element_added_notifier_new (); + g_signal_connect (priv->notifier, "element-added", + G_CALLBACK (empathy_audio_src_element_added_cb), obj); priv->src = gst_element_factory_make ("gconfaudiosrc", NULL); + gst_bin_add (GST_BIN (obj), priv->src); + + fs_element_added_notifier_add (priv->notifier, GST_BIN (priv->src)); + + priv->volume = gst_element_factory_make ("volume", NULL); + g_object_ref (priv->volume); - //gst_bin_add_many (GST_BIN (obj), priv->src, resample, NULL); - gst_bin_add_many (GST_BIN (obj), priv->src, NULL); - //gst_element_link_many (priv->src, resample, NULL); + gst_bin_add (GST_BIN (obj), priv->volume); + gst_element_link (priv->src, priv->volume); - //src = gst_element_get_static_pad (resample, "src"); - src = gst_element_get_static_pad (priv->src, "src"); + priv->level = gst_element_factory_make ("level", NULL); + gst_bin_add (GST_BIN (obj), priv->level); + gst_element_link (priv->volume, priv->level); + + src = gst_element_get_static_pad (priv->level, "src"); ghost = gst_ghost_pad_new ("src", src); gst_element_add_pad (GST_ELEMENT (obj), ghost); @@ -76,18 +125,105 @@ empathy_audio_src_init (EmpathyGstAudioSrc *obj) static void empathy_audio_src_dispose (GObject *object); static void empathy_audio_src_finalize (GObject *object); +static void empathy_audio_src_handle_message (GstBin *bin, + GstMessage *message); + +static gboolean empathy_audio_src_levels_updated (gpointer user_data); + +static void +empathy_audio_src_set_property (GObject *object, + guint property_id, const GValue *value, GParamSpec *pspec) +{ + switch (property_id) + { + case PROP_VOLUME: + empathy_audio_src_set_volume (EMPATHY_GST_AUDIO_SRC (object), + g_value_get_double (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +empathy_audio_src_get_property (GObject *object, + guint property_id, GValue *value, GParamSpec *pspec) +{ + EmpathyGstAudioSrc *self = EMPATHY_GST_AUDIO_SRC (object); + EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (self); + + switch (property_id) + { + case PROP_VOLUME: + g_value_set_double (value, + empathy_audio_src_get_volume (self)); + break; + case PROP_PEAK_LEVEL: + g_mutex_lock (priv->lock); + g_value_set_double (value, priv->peak_level); + g_mutex_unlock (priv->lock); + break; + case PROP_RMS_LEVEL: + g_mutex_lock (priv->lock); + g_value_set_double (value, priv->rms_level); + g_mutex_unlock (priv->lock); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} static void empathy_audio_src_class_init (EmpathyGstAudioSrcClass *empathy_audio_src_class) { GObjectClass *object_class = G_OBJECT_CLASS (empathy_audio_src_class); + GstBinClass *gstbin_class = GST_BIN_CLASS (empathy_audio_src_class); + GParamSpec *param_spec; g_type_class_add_private (empathy_audio_src_class, sizeof (EmpathyGstAudioSrcPrivate)); object_class->dispose = empathy_audio_src_dispose; object_class->finalize = empathy_audio_src_finalize; + + object_class->set_property = empathy_audio_src_set_property; + object_class->get_property = empathy_audio_src_get_property; + + gstbin_class->handle_message = + GST_DEBUG_FUNCPTR (empathy_audio_src_handle_message); + + param_spec = g_param_spec_double ("volume", "Volume", "volume contol", + 0.0, 5.0, 1.0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_VOLUME, param_spec); + + param_spec = g_param_spec_double ("peak-level", "peak level", "peak level", + -G_MAXDOUBLE, G_MAXDOUBLE, 0, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_VOLUME, param_spec); + + signals[PEAK_LEVEL_CHANGED] = g_signal_new ("peak-level-changed", + G_TYPE_FROM_CLASS (empathy_audio_src_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__DOUBLE, + G_TYPE_NONE, 1, G_TYPE_DOUBLE); + + param_spec = g_param_spec_double ("rms-level", "RMS level", "RMS level", + -G_MAXDOUBLE, G_MAXDOUBLE, 0, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_VOLUME, param_spec); + + + signals[RMS_LEVEL_CHANGED] = g_signal_new ("rms-level-changed", + G_TYPE_FROM_CLASS (empathy_audio_src_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__DOUBLE, + G_TYPE_NONE, 1, G_TYPE_DOUBLE); } void @@ -101,6 +237,11 @@ empathy_audio_src_dispose (GObject *object) priv->dispose_has_run = TRUE; + if (priv->idle_id != 0) + g_source_remove (priv->idle_id); + + priv->idle_id = 0; + /* release any references held by the object here */ if (G_OBJECT_CLASS (empathy_audio_src_parent_class)->dispose) @@ -110,16 +251,129 @@ empathy_audio_src_dispose (GObject *object) void empathy_audio_src_finalize (GObject *object) { - //EmpathyGstAudioSrc *self = EMPATHY_GST_AUDIO_SRC (object); - //EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (self); + EmpathyGstAudioSrc *self = EMPATHY_GST_AUDIO_SRC (object); + EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (self); /* free any data held directly by the object here */ + g_mutex_free (priv->lock); G_OBJECT_CLASS (empathy_audio_src_parent_class)->finalize (object); } +static gboolean +empathy_audio_src_levels_updated (gpointer user_data) +{ + EmpathyGstAudioSrc *self = EMPATHY_GST_AUDIO_SRC (user_data); + EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (self); + + g_mutex_lock (priv->lock); + + g_signal_emit (self, signals[PEAK_LEVEL_CHANGED], 0, priv->peak_level); + g_signal_emit (self, signals[RMS_LEVEL_CHANGED], 0, priv->rms_level); + priv->idle_id = 0; + + g_mutex_unlock (priv->lock); + + return FALSE; +} + +static void +empathy_audio_src_handle_message (GstBin *bin, GstMessage *message) +{ + EmpathyGstAudioSrc *self = EMPATHY_GST_AUDIO_SRC (bin); + EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (self); + + if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ELEMENT && + GST_MESSAGE_SRC (message) == GST_OBJECT (priv->level)) + { + const GstStructure *s; + const gchar *name; + const GValue *list; + guint i, len; + gdouble peak = -G_MAXDOUBLE; + gdouble rms = -G_MAXDOUBLE; + + + s = gst_message_get_structure (message); + name = gst_structure_get_name (s); + + if (g_strcmp0 ("level", name) != 0) + goto out; + + list = gst_structure_get_value (s, "peak"); + len = gst_value_list_get_size (list); + + for (i =0 ; i < len; i++) + { + const GValue *value; + gdouble db; + + value = gst_value_list_get_value (list, i); + db = g_value_get_double (value); + peak = MAX (db, peak); + } + + list = gst_structure_get_value (s, "rms"); + len = gst_value_list_get_size (list); + + for (i =0 ; i < len; i++) + { + const GValue *value; + gdouble db; + + value = gst_value_list_get_value (list, i); + db = g_value_get_double (value); + rms = MAX (db, rms); + } + + g_mutex_lock (priv->lock); + + priv->peak_level = peak; + priv->rms_level = rms; + if (priv->idle_id == 0) + priv->idle_id = g_idle_add (empathy_audio_src_levels_updated, self); + + g_mutex_unlock (priv->lock); + } + +out: + GST_BIN_CLASS (empathy_audio_src_parent_class)->handle_message (bin, + message); +} + GstElement * empathy_audio_src_new (void) { return GST_ELEMENT (g_object_new (EMPATHY_TYPE_GST_AUDIO_SRC, NULL)); } + +void +empathy_audio_src_set_volume (EmpathyGstAudioSrc *src, gdouble volume) +{ + EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (src); + GParamSpec *pspec; + GParamSpecDouble *pspec_double; + + pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (priv->volume), + "volume"); + + g_assert (pspec != NULL); + + pspec_double = G_PARAM_SPEC_DOUBLE (pspec); + + volume = CLAMP (volume, pspec_double->minimum, pspec_double->maximum); + + g_object_set (G_OBJECT (priv->volume), "volume", volume, NULL); +} + +gdouble +empathy_audio_src_get_volume (EmpathyGstAudioSrc *src) +{ + EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (src); + gdouble volume; + + + g_object_get (G_OBJECT (priv->volume), "volume", &volume, NULL); + + return volume; +} diff --git a/libempathy-gtk/empathy-audio-src.h b/libempathy-gtk/empathy-audio-src.h index 7a68bbe15..4f48fe1f7 100644 --- a/libempathy-gtk/empathy-audio-src.h +++ b/libempathy-gtk/empathy-audio-src.h @@ -58,6 +58,9 @@ GType empathy_audio_src_get_type (void); GstElement *empathy_audio_src_new (void); +void empathy_audio_src_set_volume (EmpathyGstAudioSrc *src, gdouble volume); +gdouble empathy_audio_src_get_volume (EmpathyGstAudioSrc *src); + G_END_DECLS #endif /* #ifndef __EMPATHY_GST_AUDIO_SRC_H__*/ -- cgit v1.2.3