]> git.0d.be Git - empathy.git/blob - src/empathy-audio-sink.c
Get the env variable in create_{src,sink} directly
[empathy.git] / src / empathy-audio-sink.c
1 /*
2  * empathy-gst-audio-sink.c - Source for EmpathyGstAudioSink
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/audio/audio.h>
26 #include <telepathy-glib/telepathy-glib.h>
27
28 #include <libempathy-gtk/empathy-call-utils.h>
29
30 #include "empathy-audio-sink.h"
31
32 #define DEBUG_FLAG EMPATHY_DEBUG_VOIP
33 #include <libempathy/empathy-debug.h>
34
35 G_DEFINE_TYPE(EmpathyGstAudioSink, empathy_audio_sink, GST_TYPE_BIN)
36
37 /* signal enum */
38 #if 0
39 enum
40 {
41     LAST_SIGNAL
42 };
43
44 static guint signals[LAST_SIGNAL] = {0};
45 #endif
46
47 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE(
48     "sink%d",
49     GST_PAD_SINK,
50     GST_PAD_REQUEST,
51     GST_STATIC_CAPS ( GST_AUDIO_INT_PAD_TEMPLATE_CAPS " ; "
52         GST_AUDIO_FLOAT_PAD_TEMPLATE_CAPS)
53 );
54
55 enum {
56   PROP_VOLUME = 1,
57 };
58
59 struct _EmpathyGstAudioSinkPrivate
60 {
61   GstElement *sink;
62 };
63
64 #define EMPATHY_GST_AUDIO_SINK_GET_PRIVATE(o) \
65   (G_TYPE_INSTANCE_GET_PRIVATE ((o), EMPATHY_TYPE_GST_AUDIO_SINK, \
66   EmpathyGstAudioSinkPrivate))
67
68 static void
69 empathy_audio_sink_init (EmpathyGstAudioSink *self)
70 {
71   self->priv = EMPATHY_GST_AUDIO_SINK_GET_PRIVATE (self);
72 }
73
74 static GstPad * empathy_audio_sink_request_new_pad (GstElement *self,
75   GstPadTemplate *templ,
76   const gchar* name);
77
78 static void empathy_audio_sink_release_pad (GstElement *self,
79   GstPad *pad);
80
81 static void
82 empathy_audio_sink_set_property (GObject *object,
83   guint property_id, const GValue *value, GParamSpec *pspec)
84 {
85   switch (property_id)
86     {
87       case PROP_VOLUME:
88         empathy_audio_sink_set_volume (EMPATHY_GST_AUDIO_SINK (object),
89           g_value_get_double (value));
90         break;
91       default:
92         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
93     }
94 }
95
96 static void
97 empathy_audio_sink_get_property (GObject *object,
98   guint property_id, GValue *value, GParamSpec *pspec)
99 {
100   switch (property_id)
101     {
102       case PROP_VOLUME:
103         g_value_set_double (value,
104           empathy_audio_sink_get_volume (EMPATHY_GST_AUDIO_SINK (object)));
105         break;
106       default:
107         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
108     }
109 }
110
111 static void
112 empathy_audio_sink_class_init (EmpathyGstAudioSinkClass
113   *empathy_audio_sink_class)
114 {
115   GObjectClass *object_class = G_OBJECT_CLASS (empathy_audio_sink_class);
116   GstElementClass *element_class =
117     GST_ELEMENT_CLASS (empathy_audio_sink_class);
118   GParamSpec *param_spec;
119
120   gst_element_class_add_pad_template (element_class,
121     gst_static_pad_template_get (&sink_template));
122
123   g_type_class_add_private (empathy_audio_sink_class,
124     sizeof (EmpathyGstAudioSinkPrivate));
125
126   object_class->set_property = empathy_audio_sink_set_property;
127   object_class->get_property = empathy_audio_sink_get_property;
128
129   element_class->request_new_pad = empathy_audio_sink_request_new_pad;
130   element_class->release_pad = empathy_audio_sink_release_pad;
131
132   param_spec = g_param_spec_double ("volume", "Volume", "volume control",
133     0.0, 5.0, 1.0,
134     G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
135   g_object_class_install_property (object_class, PROP_VOLUME, param_spec);
136 }
137
138 GstElement *
139 empathy_audio_sink_new (void)
140 {
141   static gboolean registered = FALSE;
142
143   if (!registered) {
144     if (!gst_element_register (NULL, "empathyaudiosink",
145             GST_RANK_NONE, EMPATHY_TYPE_GST_AUDIO_SINK))
146       return NULL;
147     registered = TRUE;
148   }
149   return gst_element_factory_make ("empathyaudiosink", NULL);
150 }
151
152 static gboolean
153 check_volume_support (EmpathyGstAudioSink *self)
154 {
155   gchar *name;
156
157   if (g_object_class_find_property (G_OBJECT_GET_CLASS (self->priv->sink),
158         "volume"))
159     return TRUE;
160
161   name = gst_element_get_name (self->priv->sink);
162   DEBUG ("Element %s doesn't support volume", name);
163
164   g_free (name);
165   return FALSE;
166 }
167
168 void
169 empathy_audio_sink_set_volume (EmpathyGstAudioSink *sink, gdouble volume)
170 {
171   EmpathyGstAudioSinkPrivate *priv = EMPATHY_GST_AUDIO_SINK_GET_PRIVATE (sink);
172
173   if (!check_volume_support (sink))
174       return;
175
176   g_object_set (priv->sink, "volume", volume, NULL);
177 }
178
179 gdouble
180 empathy_audio_sink_get_volume (EmpathyGstAudioSink *sink)
181 {
182   EmpathyGstAudioSinkPrivate *priv = EMPATHY_GST_AUDIO_SINK_GET_PRIVATE (sink);
183   gdouble volume;
184
185   if (!check_volume_support (sink))
186       return 1.0;
187
188   g_object_get (priv->sink, "volume", &volume, NULL);
189   return volume;
190 }
191
192 static GstElement *
193 create_sink (void)
194 {
195   GstElement *sink;
196   const gchar *description;
197
198   description = g_getenv ("EMPATHY_AUDIO_SINK");
199
200   if (description != NULL)
201     {
202       GError *error = NULL;
203
204       sink = gst_parse_bin_from_description (description, TRUE, &error);
205       if (sink == NULL)
206         {
207           DEBUG ("Failed to create bin %s: %s", description, error->message);
208           g_error_free (error);
209         }
210
211       return sink;
212     }
213
214   /* Use pulsesink as default */
215   sink = gst_element_factory_make ("pulsesink", NULL);
216   if (sink == NULL)
217     return NULL;
218
219   empathy_call_set_stream_properties (sink);
220
221   return sink;
222 }
223
224 static GstPad *
225 empathy_audio_sink_request_new_pad (GstElement *element,
226   GstPadTemplate *templ,
227   const gchar* name)
228 {
229   EmpathyGstAudioSink *self = EMPATHY_GST_AUDIO_SINK (element);
230   GstElement *bin, *volume, *resample, *audioconvert0, *audioconvert1;
231   GstPad *pad = NULL;
232   GstPad *subpad, *filterpad;
233
234   bin = gst_bin_new (NULL);
235
236   audioconvert0 = gst_element_factory_make ("audioconvert", NULL);
237   if (audioconvert0 == NULL)
238     goto error;
239
240   gst_bin_add (GST_BIN (bin), audioconvert0);
241
242   resample = gst_element_factory_make ("audioresample", NULL);
243   if (resample == NULL)
244     goto error;
245
246   gst_bin_add (GST_BIN (bin), resample);
247
248   audioconvert1 = gst_element_factory_make ("audioconvert", NULL);
249   if (audioconvert1 == NULL)
250     goto error;
251
252   gst_bin_add (GST_BIN (bin), audioconvert1);
253
254   volume = gst_element_factory_make ("volume", NULL);
255   if (volume == NULL)
256     goto error;
257
258   gst_bin_add (GST_BIN (bin), volume);
259
260   self->priv->sink = create_sink ();
261   if (self->priv->sink == NULL)
262     goto error;
263
264   gst_bin_add (GST_BIN (bin), self->priv->sink);
265
266   if (!gst_element_link_many (audioconvert0, resample, audioconvert1,
267       volume, self->priv->sink, NULL))
268     goto error;
269
270   filterpad = gst_element_get_static_pad (audioconvert0, "sink");
271
272   if (filterpad == NULL)
273     goto error;
274
275   subpad = gst_ghost_pad_new ("sink", filterpad);
276   if (!gst_element_add_pad (GST_ELEMENT (bin), subpad))
277     goto error;
278
279   gst_bin_add (GST_BIN (self), bin);
280
281   pad = gst_ghost_pad_new (name, subpad);
282   g_assert (pad != NULL);
283
284   if (!gst_element_sync_state_with_parent (bin))
285     goto error;
286
287   if (!gst_pad_set_active (pad, TRUE))
288     goto error;
289
290   if (!gst_element_add_pad (GST_ELEMENT (self), pad))
291     goto error;
292
293   return pad;
294
295 error:
296   if (pad != NULL)
297     {
298       gst_object_unref (pad);
299     }
300
301   gst_object_unref (bin);
302   g_warning ("Failed to create output subpipeline");
303   return NULL;
304 }
305
306 static void
307 empathy_audio_sink_release_pad (GstElement *element,
308   GstPad *pad)
309 {
310   gst_pad_set_active (pad, FALSE);
311   gst_element_remove_pad (element, pad);
312 }