]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-audio-src.c
add myself to AUTHORS
[empathy.git] / libempathy-gtk / empathy-audio-src.c
1 /*
2  * empathy-gst-audio-src.c - Source for EmpathyGstAudioSrc
3  * Copyright (C) 2008 Collabora Ltd.
4  * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20
21
22 #include <stdio.h>
23 #include <stdlib.h>
24
25 #include <gst/farsight/fs-element-added-notifier.h>
26 #include "empathy-audio-src.h"
27
28 G_DEFINE_TYPE(EmpathyGstAudioSrc, empathy_audio_src, GST_TYPE_BIN)
29
30 /* signal enum */
31 enum
32 {
33     PEAK_LEVEL_CHANGED,
34     RMS_LEVEL_CHANGED,
35     LAST_SIGNAL
36 };
37
38 static guint signals[LAST_SIGNAL] = {0};
39
40 enum {
41     PROP_VOLUME = 1,
42     PROP_RMS_LEVEL,
43     PROP_PEAK_LEVEL,
44 };
45
46 /* private structure */
47 typedef struct _EmpathyGstAudioSrcPrivate EmpathyGstAudioSrcPrivate;
48
49 struct _EmpathyGstAudioSrcPrivate
50 {
51   gboolean dispose_has_run;
52   GstElement *src;
53   GstElement *volume;
54   GstElement *level;
55   FsElementAddedNotifier *notifier;
56
57   gdouble peak_level;
58   gdouble rms_level;
59
60   GMutex *lock;
61   guint idle_id;
62 };
63
64 #define EMPATHY_GST_AUDIO_SRC_GET_PRIVATE(o) \
65   (G_TYPE_INSTANCE_GET_PRIVATE ((o), EMPATHY_TYPE_GST_AUDIO_SRC, \
66   EmpathyGstAudioSrcPrivate))
67
68 static void
69 empathy_audio_src_element_added_cb (FsElementAddedNotifier *notifier,
70   GstBin *bin, GstElement *element, EmpathyGstAudioSrc *self)
71 {
72   EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (self);
73
74   if (g_object_class_find_property (G_OBJECT_GET_CLASS (element), "volume"))
75     {
76       gdouble volume;
77
78       volume = empathy_audio_src_get_volume (self);
79       empathy_audio_src_set_volume (self, 1.0);
80
81       if (priv->volume != NULL)
82         g_object_unref (priv->volume);
83       priv->volume = g_object_ref (element);
84
85       if (volume != 1.0)
86         empathy_audio_src_set_volume (self, volume);
87     }
88 }
89
90 static void
91 empathy_audio_src_init (EmpathyGstAudioSrc *obj)
92 {
93   EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (obj);
94   GstPad *ghost, *src;
95
96   priv->peak_level = -G_MAXDOUBLE;
97   priv->lock = g_mutex_new ();
98
99   priv->notifier = fs_element_added_notifier_new ();
100   g_signal_connect (priv->notifier, "element-added",
101     G_CALLBACK (empathy_audio_src_element_added_cb), obj);
102
103   priv->src = gst_element_factory_make ("gconfaudiosrc", NULL);
104   gst_bin_add (GST_BIN (obj), priv->src);
105
106   fs_element_added_notifier_add (priv->notifier, GST_BIN (priv->src));
107
108   priv->volume = gst_element_factory_make ("volume", NULL);
109   g_object_ref (priv->volume);
110
111   gst_bin_add (GST_BIN (obj), priv->volume);
112   gst_element_link (priv->src, priv->volume);
113
114   priv->level = gst_element_factory_make ("level", NULL);
115   gst_bin_add (GST_BIN (obj), priv->level);
116   gst_element_link (priv->volume, priv->level);
117
118   src = gst_element_get_static_pad (priv->level, "src");
119
120   ghost = gst_ghost_pad_new ("src", src);
121   gst_element_add_pad (GST_ELEMENT (obj), ghost);
122
123   gst_object_unref (G_OBJECT (src));
124 }
125
126 static void empathy_audio_src_dispose (GObject *object);
127 static void empathy_audio_src_finalize (GObject *object);
128 static void empathy_audio_src_handle_message (GstBin *bin,
129   GstMessage *message);
130
131 static gboolean empathy_audio_src_levels_updated (gpointer user_data);
132
133 static void
134 empathy_audio_src_set_property (GObject *object,
135   guint property_id, const GValue *value, GParamSpec *pspec)
136 {
137   switch (property_id)
138     {
139       case PROP_VOLUME:
140         empathy_audio_src_set_volume (EMPATHY_GST_AUDIO_SRC (object),
141           g_value_get_double (value));
142         break;
143       default:
144         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
145     }
146 }
147
148 static void
149 empathy_audio_src_get_property (GObject *object,
150   guint property_id, GValue *value, GParamSpec *pspec)
151 {
152   EmpathyGstAudioSrc *self = EMPATHY_GST_AUDIO_SRC (object);
153   EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (self);
154
155   switch (property_id)
156     {
157       case PROP_VOLUME:
158         g_value_set_double (value,
159           empathy_audio_src_get_volume (self));
160         break;
161       case PROP_PEAK_LEVEL:
162         g_mutex_lock (priv->lock);
163         g_value_set_double (value, priv->peak_level);
164         g_mutex_unlock (priv->lock);
165         break;
166       case PROP_RMS_LEVEL:
167         g_mutex_lock (priv->lock);
168         g_value_set_double (value, priv->rms_level);
169         g_mutex_unlock (priv->lock);
170         break;
171       default:
172         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
173     }
174 }
175
176 static void
177 empathy_audio_src_class_init (EmpathyGstAudioSrcClass
178   *empathy_audio_src_class)
179 {
180   GObjectClass *object_class = G_OBJECT_CLASS (empathy_audio_src_class);
181   GstBinClass *gstbin_class = GST_BIN_CLASS (empathy_audio_src_class);
182   GParamSpec *param_spec;
183
184   g_type_class_add_private (empathy_audio_src_class,
185     sizeof (EmpathyGstAudioSrcPrivate));
186
187   object_class->dispose = empathy_audio_src_dispose;
188   object_class->finalize = empathy_audio_src_finalize;
189
190   object_class->set_property = empathy_audio_src_set_property;
191   object_class->get_property = empathy_audio_src_get_property;
192
193   gstbin_class->handle_message =
194     GST_DEBUG_FUNCPTR (empathy_audio_src_handle_message);
195
196   param_spec = g_param_spec_double ("volume", "Volume", "volume contol",
197     0.0, 5.0, 1.0,
198     G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
199   g_object_class_install_property (object_class, PROP_VOLUME, param_spec);
200
201   param_spec = g_param_spec_double ("peak-level", "peak level", "peak level",
202     -G_MAXDOUBLE, G_MAXDOUBLE, 0,
203     G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
204   g_object_class_install_property (object_class, PROP_VOLUME, param_spec);
205
206   signals[PEAK_LEVEL_CHANGED] = g_signal_new ("peak-level-changed",
207     G_TYPE_FROM_CLASS (empathy_audio_src_class),
208     G_SIGNAL_RUN_LAST,
209     0,
210     NULL, NULL,
211     g_cclosure_marshal_VOID__DOUBLE,
212     G_TYPE_NONE, 1, G_TYPE_DOUBLE);
213
214   param_spec = g_param_spec_double ("rms-level", "RMS level", "RMS level",
215     -G_MAXDOUBLE, G_MAXDOUBLE, 0,
216     G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
217   g_object_class_install_property (object_class, PROP_VOLUME, param_spec);
218
219
220   signals[RMS_LEVEL_CHANGED] = g_signal_new ("rms-level-changed",
221     G_TYPE_FROM_CLASS (empathy_audio_src_class),
222     G_SIGNAL_RUN_LAST,
223     0,
224     NULL, NULL,
225     g_cclosure_marshal_VOID__DOUBLE,
226     G_TYPE_NONE, 1, G_TYPE_DOUBLE);
227 }
228
229 void
230 empathy_audio_src_dispose (GObject *object)
231 {
232   EmpathyGstAudioSrc *self = EMPATHY_GST_AUDIO_SRC (object);
233   EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (self);
234
235   if (priv->dispose_has_run)
236     return;
237
238   priv->dispose_has_run = TRUE;
239
240   if (priv->idle_id != 0)
241     g_source_remove (priv->idle_id);
242
243   priv->idle_id = 0;
244
245   /* release any references held by the object here */
246
247   if (G_OBJECT_CLASS (empathy_audio_src_parent_class)->dispose)
248     G_OBJECT_CLASS (empathy_audio_src_parent_class)->dispose (object);
249 }
250
251 void
252 empathy_audio_src_finalize (GObject *object)
253 {
254   EmpathyGstAudioSrc *self = EMPATHY_GST_AUDIO_SRC (object);
255   EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (self);
256
257   /* free any data held directly by the object here */
258   g_mutex_free (priv->lock);
259
260   G_OBJECT_CLASS (empathy_audio_src_parent_class)->finalize (object);
261 }
262
263 static gboolean
264 empathy_audio_src_levels_updated (gpointer user_data)
265 {
266   EmpathyGstAudioSrc *self = EMPATHY_GST_AUDIO_SRC (user_data);
267   EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (self);
268
269   g_mutex_lock (priv->lock);
270
271   g_signal_emit (self, signals[PEAK_LEVEL_CHANGED], 0, priv->peak_level);
272   g_signal_emit (self, signals[RMS_LEVEL_CHANGED], 0, priv->rms_level);
273   priv->idle_id = 0;
274
275   g_mutex_unlock (priv->lock);
276
277   return FALSE;
278 }
279
280 static void
281 empathy_audio_src_handle_message (GstBin *bin, GstMessage *message)
282 {
283   EmpathyGstAudioSrc *self = EMPATHY_GST_AUDIO_SRC (bin);
284   EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (self);
285
286   if  (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ELEMENT &&
287         GST_MESSAGE_SRC (message) == GST_OBJECT (priv->level))
288     {
289       const GstStructure *s;
290       const gchar *name;
291       const GValue *list;
292       guint i, len;
293       gdouble peak = -G_MAXDOUBLE;
294       gdouble rms = -G_MAXDOUBLE;
295
296       s = gst_message_get_structure (message);
297       name = gst_structure_get_name (s);
298
299       if (g_strcmp0 ("level", name) != 0)
300         goto out;
301
302       list = gst_structure_get_value (s, "peak");
303       len = gst_value_list_get_size (list);
304
305       for (i =0 ; i < len; i++)
306         {
307           const GValue *value;
308           gdouble db;
309
310           value = gst_value_list_get_value (list, i);
311           db = g_value_get_double (value);
312           peak = MAX (db, peak);
313         }
314
315       list = gst_structure_get_value (s, "rms");
316       len = gst_value_list_get_size (list);
317
318       for (i =0 ; i < len; i++)
319         {
320           const GValue *value;
321           gdouble db;
322
323           value = gst_value_list_get_value (list, i);
324           db = g_value_get_double (value);
325           rms = MAX (db, rms);
326         }
327
328       g_mutex_lock (priv->lock);
329
330       priv->peak_level = peak;
331       priv->rms_level = rms;
332       if (priv->idle_id == 0)
333         priv->idle_id = g_idle_add (empathy_audio_src_levels_updated, self);
334
335       g_mutex_unlock (priv->lock);
336     }
337
338 out:
339    GST_BIN_CLASS (empathy_audio_src_parent_class)->handle_message (bin,
340     message);
341 }
342
343 GstElement *
344 empathy_audio_src_new (void)
345 {
346   static gboolean registered = FALSE;
347
348   if (!registered) {
349     if (!gst_element_register (NULL, "empathyaudiosrc",
350             GST_RANK_NONE, EMPATHY_TYPE_GST_AUDIO_SRC))
351       return NULL;
352     registered = TRUE;
353   }
354   return gst_element_factory_make ("empathyaudiosrc", NULL);
355 }
356
357 void
358 empathy_audio_src_set_volume (EmpathyGstAudioSrc *src, gdouble volume)
359 {
360   EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (src);
361   GParamSpec *pspec;
362   GParamSpecDouble *pspec_double;
363
364   pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (priv->volume),
365     "volume");
366
367   g_assert (pspec != NULL);
368
369   pspec_double = G_PARAM_SPEC_DOUBLE (pspec);
370
371   volume = CLAMP (volume, pspec_double->minimum, pspec_double->maximum);
372
373   g_object_set (G_OBJECT (priv->volume), "volume", volume, NULL);
374 }
375
376 gdouble
377 empathy_audio_src_get_volume (EmpathyGstAudioSrc *src)
378 {
379   EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (src);
380   gdouble volume;
381
382   g_object_get (G_OBJECT (priv->volume), "volume", &volume, NULL);
383
384   return volume;
385 }
386
387