1 /* ALSA mixer implementation. |
|
2 * Copyright (C) 2003 Leif Johnson <leif@ambient.2y.net> |
|
3 * |
|
4 * This library is free software; you can redistribute it and/or |
|
5 * modify it under the terms of the GNU Library General Public |
|
6 * License as published by the Free Software Foundation; either |
|
7 * version 2 of the License, or (at your option) any later version. |
|
8 * |
|
9 * This library is distributed in the hope that it will be useful, |
|
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
12 * Library General Public License for more details. |
|
13 * |
|
14 * You should have received a copy of the GNU Library General Public |
|
15 * License along with this library; if not, write to the |
|
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
|
17 * Boston, MA 02111-1307, USA. |
|
18 */ |
|
19 |
|
20 |
|
21 #ifdef HAVE_CONFIG_H |
|
22 #include "config.h" |
|
23 #endif |
|
24 |
|
25 #include "gstalsamixerelement.h" |
|
26 #include "gstalsadeviceprobe.h" |
|
27 |
|
28 #define DEFAULT_PROP_DEVICE "default" |
|
29 #define DEFAULT_PROP_DEVICE_NAME "" |
|
30 |
|
31 enum |
|
32 { |
|
33 PROP_0, |
|
34 PROP_DEVICE, |
|
35 PROP_DEVICE_NAME |
|
36 }; |
|
37 |
|
38 static const GstElementDetails gst_alsa_mixer_element_details = |
|
39 GST_ELEMENT_DETAILS ("Alsa mixer", |
|
40 "Generic/Audio", |
|
41 "Control sound input and output levels with ALSA", |
|
42 "Leif Johnson <leif@ambient.2y.net>"); |
|
43 |
|
44 static void gst_alsa_mixer_element_init_interfaces (GType type); |
|
45 |
|
46 GST_BOILERPLATE_FULL (GstAlsaMixerElement, gst_alsa_mixer_element, |
|
47 GstElement, GST_TYPE_ELEMENT, gst_alsa_mixer_element_init_interfaces); |
|
48 |
|
49 /* massive macro that takes care of all the GstMixer stuff */ |
|
50 GST_IMPLEMENT_ALSA_MIXER_METHODS (GstAlsaMixerElement, gst_alsa_mixer_element); |
|
51 |
|
52 static void gst_alsa_mixer_element_get_property (GObject * object, |
|
53 guint prop_id, GValue * value, GParamSpec * pspec); |
|
54 static void gst_alsa_mixer_element_set_property (GObject * object, |
|
55 guint prop_id, const GValue * value, GParamSpec * pspec); |
|
56 static void gst_alsa_mixer_element_finalize (GObject * object); |
|
57 |
|
58 static GstStateChangeReturn gst_alsa_mixer_element_change_state (GstElement |
|
59 * element, GstStateChange transition); |
|
60 |
|
61 static gboolean |
|
62 gst_alsa_mixer_element_interface_supported (GstAlsaMixerElement * this, |
|
63 GType interface_type) |
|
64 { |
|
65 if (interface_type == GST_TYPE_MIXER) { |
|
66 return gst_alsa_mixer_element_supported (this, interface_type); |
|
67 } |
|
68 |
|
69 g_return_val_if_reached (FALSE); |
|
70 } |
|
71 |
|
72 static void |
|
73 gst_implements_interface_init (GstImplementsInterfaceClass * klass) |
|
74 { |
|
75 klass->supported = (gpointer) gst_alsa_mixer_element_interface_supported; |
|
76 } |
|
77 |
|
78 static void |
|
79 gst_alsa_mixer_element_init_interfaces (GType type) |
|
80 { |
|
81 static const GInterfaceInfo implements_iface_info = { |
|
82 (GInterfaceInitFunc) gst_implements_interface_init, |
|
83 NULL, |
|
84 NULL, |
|
85 }; |
|
86 static const GInterfaceInfo mixer_iface_info = { |
|
87 (GInterfaceInitFunc) gst_alsa_mixer_element_interface_init, |
|
88 NULL, |
|
89 NULL, |
|
90 }; |
|
91 |
|
92 g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE, |
|
93 &implements_iface_info); |
|
94 g_type_add_interface_static (type, GST_TYPE_MIXER, &mixer_iface_info); |
|
95 |
|
96 gst_alsa_type_add_device_property_probe_interface (type); |
|
97 } |
|
98 |
|
99 static void |
|
100 gst_alsa_mixer_element_base_init (gpointer klass) |
|
101 { |
|
102 gst_element_class_set_details (GST_ELEMENT_CLASS (klass), |
|
103 &gst_alsa_mixer_element_details); |
|
104 } |
|
105 |
|
106 static void |
|
107 gst_alsa_mixer_element_class_init (GstAlsaMixerElementClass * klass) |
|
108 { |
|
109 GstElementClass *element_class; |
|
110 GObjectClass *gobject_class; |
|
111 |
|
112 element_class = (GstElementClass *) klass; |
|
113 gobject_class = (GObjectClass *) klass; |
|
114 |
|
115 gobject_class->finalize = gst_alsa_mixer_element_finalize; |
|
116 gobject_class->get_property = gst_alsa_mixer_element_get_property; |
|
117 gobject_class->set_property = gst_alsa_mixer_element_set_property; |
|
118 |
|
119 g_object_class_install_property (gobject_class, PROP_DEVICE, |
|
120 g_param_spec_string ("device", "Device", |
|
121 "ALSA device, as defined in an asound configuration file", |
|
122 DEFAULT_PROP_DEVICE, G_PARAM_READWRITE)); |
|
123 |
|
124 g_object_class_install_property (gobject_class, PROP_DEVICE_NAME, |
|
125 g_param_spec_string ("device-name", "Device name", |
|
126 "Human-readable name of the sound device", |
|
127 DEFAULT_PROP_DEVICE_NAME, G_PARAM_READABLE)); |
|
128 |
|
129 element_class->change_state = |
|
130 GST_DEBUG_FUNCPTR (gst_alsa_mixer_element_change_state); |
|
131 } |
|
132 |
|
133 static void |
|
134 gst_alsa_mixer_element_finalize (GObject * obj) |
|
135 { |
|
136 GstAlsaMixerElement *this = GST_ALSA_MIXER_ELEMENT (obj); |
|
137 |
|
138 g_free (this->device); |
|
139 |
|
140 G_OBJECT_CLASS (parent_class)->finalize (obj); |
|
141 } |
|
142 |
|
143 static void |
|
144 gst_alsa_mixer_element_init (GstAlsaMixerElement * this, |
|
145 GstAlsaMixerElementClass * klass) |
|
146 { |
|
147 this->mixer = NULL; |
|
148 this->device = g_strdup (DEFAULT_PROP_DEVICE); |
|
149 } |
|
150 |
|
151 static void |
|
152 gst_alsa_mixer_element_set_property (GObject * object, guint prop_id, |
|
153 const GValue * value, GParamSpec * pspec) |
|
154 { |
|
155 GstAlsaMixerElement *this = GST_ALSA_MIXER_ELEMENT (object); |
|
156 |
|
157 switch (prop_id) { |
|
158 case PROP_DEVICE:{ |
|
159 GST_OBJECT_LOCK (this); |
|
160 g_free (this->device); |
|
161 this->device = g_value_dup_string (value); |
|
162 /* make sure we never set NULL, this is nice when we want to open the |
|
163 * device. */ |
|
164 if (this->device == NULL) |
|
165 this->device = g_strdup (DEFAULT_PROP_DEVICE); |
|
166 GST_OBJECT_UNLOCK (this); |
|
167 break; |
|
168 } |
|
169 default: |
|
170 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
|
171 break; |
|
172 } |
|
173 } |
|
174 |
|
175 static void |
|
176 gst_alsa_mixer_element_get_property (GObject * object, guint prop_id, |
|
177 GValue * value, GParamSpec * pspec) |
|
178 { |
|
179 GstAlsaMixerElement *this = GST_ALSA_MIXER_ELEMENT (object); |
|
180 |
|
181 switch (prop_id) { |
|
182 case PROP_DEVICE:{ |
|
183 GST_OBJECT_LOCK (this); |
|
184 g_value_set_string (value, this->device); |
|
185 GST_OBJECT_UNLOCK (this); |
|
186 break; |
|
187 } |
|
188 case PROP_DEVICE_NAME:{ |
|
189 GST_OBJECT_LOCK (this); |
|
190 if (this->mixer) { |
|
191 g_value_set_string (value, this->mixer->cardname); |
|
192 } else { |
|
193 g_value_set_string (value, NULL); |
|
194 } |
|
195 GST_OBJECT_UNLOCK (this); |
|
196 break; |
|
197 } |
|
198 default: |
|
199 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
|
200 break; |
|
201 } |
|
202 } |
|
203 |
|
204 static GstStateChangeReturn |
|
205 gst_alsa_mixer_element_change_state (GstElement * element, |
|
206 GstStateChange transition) |
|
207 { |
|
208 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; |
|
209 GstAlsaMixerElement *this = GST_ALSA_MIXER_ELEMENT (element); |
|
210 |
|
211 switch (transition) { |
|
212 case GST_STATE_CHANGE_NULL_TO_READY: |
|
213 if (!this->mixer) { |
|
214 this->mixer = gst_alsa_mixer_new (this->device, GST_ALSA_MIXER_ALL); |
|
215 if (!this->mixer) |
|
216 goto open_failed; |
|
217 _gst_alsa_mixer_set_interface (this->mixer, GST_MIXER (element)); |
|
218 } |
|
219 break; |
|
220 default: |
|
221 break; |
|
222 } |
|
223 |
|
224 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); |
|
225 if (ret == GST_STATE_CHANGE_FAILURE) |
|
226 return ret; |
|
227 |
|
228 switch (transition) { |
|
229 case GST_STATE_CHANGE_READY_TO_NULL: |
|
230 if (this->mixer) { |
|
231 gst_alsa_mixer_free (this->mixer); |
|
232 this->mixer = NULL; |
|
233 } |
|
234 break; |
|
235 default: |
|
236 break; |
|
237 } |
|
238 |
|
239 return ret; |
|
240 |
|
241 /* ERRORS */ |
|
242 open_failed: |
|
243 { |
|
244 GST_ELEMENT_ERROR (element, RESOURCE, OPEN_READ_WRITE, (NULL), |
|
245 ("Failed to open alsa mixer device '%s'", this->device)); |
|
246 return GST_STATE_CHANGE_FAILURE; |
|
247 } |
|
248 } |
|