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