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