Tizen 2.0 Release
[framework/multimedia/gst-plugins-good0.10.git] / ext / pulse / pulsemixer.c
1 /*
2  *  GStreamer pulseaudio plugin
3  *
4  *  Copyright (c) 2004-2008 Lennart Poettering
5  *
6  *  gst-pulse is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU Lesser General Public License as
8  *  published by the Free Software Foundation; either version 2.1 of the
9  *  License, or (at your option) any later version.
10  *
11  *  gst-pulse is distributed in the hope that it will be useful, but
12  *  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 gst-pulse; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19  *  USA.
20  */
21
22 /**
23  * SECTION:element-pulsemixer
24  * @see_also: pulsesrc, pulsesink
25  *
26  * This element lets you adjust sound input and output levels for the
27  * PulseAudio sound server. It supports the GstMixer interface, which can be
28  * used to obtain a list of available mixer tracks. Set the mixer element to
29  * READY state before using the GstMixer interface on it.
30  *
31  * <refsect2>
32  * <title>Example pipelines</title>
33  * <para>
34  * pulsemixer can't be used in a sensible way in gst-launch.
35  * </para>
36  * </refsect2>
37  */
38
39 #ifdef HAVE_CONFIG_H
40 #include "config.h"
41 #endif
42
43 #include <string.h>
44 #include <stdio.h>
45
46 #include "pulsemixer.h"
47
48 enum
49 {
50   PROP_SERVER = 1,
51   PROP_DEVICE,
52   PROP_DEVICE_NAME
53 };
54
55 GST_DEBUG_CATEGORY_EXTERN (pulse_debug);
56 #define GST_CAT_DEFAULT pulse_debug
57
58 static void gst_pulsemixer_set_property (GObject * object, guint prop_id,
59     const GValue * value, GParamSpec * pspec);
60 static void gst_pulsemixer_get_property (GObject * object, guint prop_id,
61     GValue * value, GParamSpec * pspec);
62 static void gst_pulsemixer_finalize (GObject * object);
63
64 static GstStateChangeReturn gst_pulsemixer_change_state (GstElement * element,
65     GstStateChange transition);
66
67 static void gst_pulsemixer_init_interfaces (GType type);
68
69 GST_IMPLEMENT_PULSEMIXER_CTRL_METHODS (GstPulseMixer, gst_pulsemixer);
70 GST_IMPLEMENT_PULSEPROBE_METHODS (GstPulseMixer, gst_pulsemixer);
71 GST_BOILERPLATE_FULL (GstPulseMixer, gst_pulsemixer, GstElement,
72     GST_TYPE_ELEMENT, gst_pulsemixer_init_interfaces);
73
74 static gboolean
75 gst_pulsemixer_interface_supported (GstImplementsInterface
76     * iface, GType interface_type)
77 {
78   GstPulseMixer *this = GST_PULSEMIXER (iface);
79
80   if (interface_type == GST_TYPE_MIXER && this->mixer)
81     return TRUE;
82
83   if (interface_type == GST_TYPE_PROPERTY_PROBE && this->probe)
84     return TRUE;
85
86   return FALSE;
87 }
88
89 static void
90 gst_pulsemixer_implements_interface_init (GstImplementsInterfaceClass * klass)
91 {
92   klass->supported = gst_pulsemixer_interface_supported;
93 }
94
95 static void
96 gst_pulsemixer_init_interfaces (GType type)
97 {
98   static const GInterfaceInfo implements_iface_info = {
99     (GInterfaceInitFunc) gst_pulsemixer_implements_interface_init,
100     NULL,
101     NULL,
102   };
103   static const GInterfaceInfo mixer_iface_info = {
104     (GInterfaceInitFunc) gst_pulsemixer_mixer_interface_init,
105     NULL,
106     NULL,
107   };
108   static const GInterfaceInfo probe_iface_info = {
109     (GInterfaceInitFunc) gst_pulsemixer_property_probe_interface_init,
110     NULL,
111     NULL,
112   };
113
114   g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE,
115       &implements_iface_info);
116   g_type_add_interface_static (type, GST_TYPE_MIXER, &mixer_iface_info);
117   g_type_add_interface_static (type, GST_TYPE_PROPERTY_PROBE,
118       &probe_iface_info);
119 }
120
121 static void
122 gst_pulsemixer_base_init (gpointer g_class)
123 {
124   gst_element_class_set_details_simple (GST_ELEMENT_CLASS (g_class),
125       "PulseAudio Mixer",
126       "Generic/Audio",
127       "Control sound input and output levels for PulseAudio",
128       "Lennart Poettering");
129 }
130
131 static void
132 gst_pulsemixer_class_init (GstPulseMixerClass * g_class)
133 {
134   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
135   GObjectClass *gobject_class = G_OBJECT_CLASS (g_class);
136
137   gstelement_class->change_state =
138       GST_DEBUG_FUNCPTR (gst_pulsemixer_change_state);
139
140   gobject_class->finalize = gst_pulsemixer_finalize;
141   gobject_class->get_property = gst_pulsemixer_get_property;
142   gobject_class->set_property = gst_pulsemixer_set_property;
143
144   g_object_class_install_property (gobject_class,
145       PROP_SERVER,
146       g_param_spec_string ("server", "Server",
147           "The PulseAudio server to connect to", NULL,
148           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
149
150   g_object_class_install_property (gobject_class,
151       PROP_DEVICE,
152       g_param_spec_string ("device", "Device",
153           "The PulseAudio sink or source to control", NULL,
154           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
155
156   g_object_class_install_property (gobject_class,
157       PROP_DEVICE_NAME,
158       g_param_spec_string ("device-name", "Device name",
159           "Human-readable name of the sound device", NULL,
160           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
161 }
162
163 static void
164 gst_pulsemixer_init (GstPulseMixer * this, GstPulseMixerClass * g_class)
165 {
166   this->mixer = NULL;
167   this->server = NULL;
168   this->device = NULL;
169
170   this->probe =
171       gst_pulseprobe_new (G_OBJECT (this), G_OBJECT_GET_CLASS (this),
172       PROP_DEVICE, this->device, TRUE, TRUE);
173 }
174
175 static void
176 gst_pulsemixer_finalize (GObject * object)
177 {
178   GstPulseMixer *this = GST_PULSEMIXER (object);
179
180   g_free (this->server);
181   g_free (this->device);
182
183   if (this->mixer) {
184     gst_pulsemixer_ctrl_free (this->mixer);
185     this->mixer = NULL;
186   }
187
188   if (this->probe) {
189     gst_pulseprobe_free (this->probe);
190     this->probe = NULL;
191   }
192
193   G_OBJECT_CLASS (parent_class)->finalize (object);
194 }
195
196 static void
197 gst_pulsemixer_set_property (GObject * object,
198     guint prop_id, const GValue * value, GParamSpec * pspec)
199 {
200   GstPulseMixer *this = GST_PULSEMIXER (object);
201
202   switch (prop_id) {
203     case PROP_SERVER:
204       g_free (this->server);
205       this->server = g_value_dup_string (value);
206
207       if (this->probe)
208         gst_pulseprobe_set_server (this->probe, this->server);
209
210       break;
211
212     case PROP_DEVICE:
213       g_free (this->device);
214       this->device = g_value_dup_string (value);
215       break;
216
217     default:
218       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
219       break;
220   }
221 }
222
223 static void
224 gst_pulsemixer_get_property (GObject * object,
225     guint prop_id, GValue * value, GParamSpec * pspec)
226 {
227   GstPulseMixer *this = GST_PULSEMIXER (object);
228
229   switch (prop_id) {
230     case PROP_SERVER:
231       g_value_set_string (value, this->server);
232       break;
233     case PROP_DEVICE:
234       g_value_set_string (value, this->device);
235       break;
236     case PROP_DEVICE_NAME:
237       if (this->mixer) {
238         char *t = g_strdup_printf ("%s: %s",
239             this->mixer->type == GST_PULSEMIXER_SINK ? "Playback" : "Capture",
240             this->mixer->description);
241         g_value_take_string (value, t);
242       } else
243         g_value_set_string (value, NULL);
244       break;
245     default:
246       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
247       break;
248   }
249 }
250
251 static GstStateChangeReturn
252 gst_pulsemixer_change_state (GstElement * element, GstStateChange transition)
253 {
254   GstPulseMixer *this = GST_PULSEMIXER (element);
255   GstStateChangeReturn res;
256
257   switch (transition) {
258     case GST_STATE_CHANGE_NULL_TO_READY:
259       if (!this->mixer)
260         this->mixer =
261             gst_pulsemixer_ctrl_new (G_OBJECT (this), this->server,
262             this->device, GST_PULSEMIXER_UNKNOWN);
263       break;
264     default:
265       ;
266   }
267
268   res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
269
270   switch (transition) {
271     case GST_STATE_CHANGE_READY_TO_NULL:
272       if (this->mixer) {
273         gst_pulsemixer_ctrl_free (this->mixer);
274         this->mixer = NULL;
275       }
276       break;
277     default:
278       ;
279   }
280
281   return res;
282 }