1 /* ALSA mixer track implementation.
2 * Copyright (C) 2003 Leif Johnson <leif@ambient.2y.net>
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.
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.
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.
24 #include <gst/gst-i18n-plugin.h>
26 #include "gstalsamixertrack.h"
28 static void gst_alsa_mixer_track_init (GstAlsaMixerTrack * alsa_track);
29 static void gst_alsa_mixer_track_class_init (gpointer g_class,
32 static GstMixerTrackClass *parent_class = NULL;
35 gst_alsa_mixer_track_get_type (void)
37 static GType track_type = 0;
40 static const GTypeInfo track_info = {
41 sizeof (GstAlsaMixerTrackClass),
44 gst_alsa_mixer_track_class_init,
47 sizeof (GstAlsaMixerTrack),
49 (GInstanceInitFunc) gst_alsa_mixer_track_init,
54 g_type_register_static (GST_TYPE_MIXER_TRACK, "GstAlsaMixerTrack",
62 gst_alsa_mixer_track_class_init (gpointer g_class, gpointer class_data)
64 parent_class = g_type_class_peek_parent (g_class);
68 gst_alsa_mixer_track_init (GstAlsaMixerTrack * alsa_track)
73 gst_alsa_mixer_track_update_alsa_capabilities (GstAlsaMixerTrack * alsa_track)
75 alsa_track->alsa_flags = 0;
76 alsa_track->capture_group = -1;
79 if (snd_mixer_selem_has_common_volume (alsa_track->element))
80 alsa_track->alsa_flags |= GST_ALSA_MIXER_TRACK_VOLUME;
82 if (snd_mixer_selem_has_common_switch (alsa_track->element))
83 alsa_track->alsa_flags |= GST_ALSA_MIXER_TRACK_SWITCH;
85 /* Since we create two separate mixer track objects for alsa elements that
86 * support both playback and capture, we're going to 'hide' the alsa flags
87 * that don't pertain to this mixer track from alsa_flags, otherwise
88 * gst_alsa_mixer_track_update() is going to do things we don't want */
91 if ((GST_MIXER_TRACK (alsa_track)->flags & GST_MIXER_TRACK_OUTPUT)) {
92 if (snd_mixer_selem_has_playback_volume (alsa_track->element))
93 alsa_track->alsa_flags |= GST_ALSA_MIXER_TRACK_PVOLUME;
95 if (snd_mixer_selem_has_playback_switch (alsa_track->element))
96 alsa_track->alsa_flags |= GST_ALSA_MIXER_TRACK_PSWITCH;
100 if ((GST_MIXER_TRACK (alsa_track)->flags & GST_MIXER_TRACK_INPUT)) {
101 if (snd_mixer_selem_has_capture_volume (alsa_track->element))
102 alsa_track->alsa_flags |= GST_ALSA_MIXER_TRACK_CVOLUME;
104 if (snd_mixer_selem_has_capture_switch (alsa_track->element)) {
105 alsa_track->alsa_flags |= GST_ALSA_MIXER_TRACK_CSWITCH;
107 if (snd_mixer_selem_has_capture_switch_exclusive (alsa_track->element)) {
108 alsa_track->alsa_flags |= GST_ALSA_MIXER_TRACK_CSWITCH_EXCL;
109 alsa_track->capture_group =
110 snd_mixer_selem_get_capture_group (alsa_track->element);
115 GST_LOG ("[%s] alsa_flags=0x%08x, capture_group=%d",
116 snd_mixer_selem_get_name (alsa_track->element),
117 alsa_track->alsa_flags, alsa_track->capture_group);
120 inline static gboolean
121 alsa_track_has_cap (GstAlsaMixerTrack * alsa_track, guint32 flag)
123 return ((alsa_track->alsa_flags & flag) != 0);
127 gst_alsa_mixer_track_new (snd_mixer_elem_t * element,
128 gint num, gint track_num, gint flags, gboolean sw,
129 GstAlsaMixerTrack * shared_mute_track, gboolean append_capture)
131 GstAlsaMixerTrack *alsa_track;
132 GstMixerTrack *track;
137 long min = 0, max = 0;
140 const gchar orig[12];
141 const gchar trans[12];
142 } alsa_track_labels[] = {
144 "Master", N_("Master")}, {
145 "Bass", N_("Bass")}, {
146 "Treble", N_("Treble")}, {
148 "Synth", N_("Synth")}, {
149 "Line", N_("Line-in")}, {
151 "Mic", N_("Microphone")}, {
152 "PC Speaker", N_("PC Speaker")}, {
153 "Playback", N_("Playback")}, {
154 "Capture", N_("Capture")}
157 name = snd_mixer_selem_get_name (element);
158 index = snd_mixer_selem_get_index (element);
161 ("[%s,%u] num=%d,track_num=%d,flags=0x%08x,sw=%s,shared_mute_track=%p",
162 name, index, num, track_num, flags, (sw) ? "true" : "false",
165 track = (GstMixerTrack *) g_object_new (GST_ALSA_MIXER_TRACK_TYPE,
166 "untranslated-label", name, "index", index, NULL);
168 alsa_track = (GstAlsaMixerTrack *) track;
170 GST_LOG ("[%s] created new mixer track %p", name, track);
172 /* This reflects the assumptions used for GstAlsaMixerTrack */
173 if (!(! !(flags & GST_MIXER_TRACK_OUTPUT) ^ ! !(flags &
174 GST_MIXER_TRACK_INPUT))) {
175 GST_ERROR ("Mixer track must be either output or input!");
176 g_return_val_if_reached (NULL);
179 track->flags = flags;
180 alsa_track->element = element;
181 alsa_track->shared_mute = shared_mute_track;
182 alsa_track->track_num = track_num;
183 alsa_track->alsa_channels = 0;
185 gst_alsa_mixer_track_update_alsa_capabilities (alsa_track);
187 if (flags & GST_MIXER_TRACK_OUTPUT) {
188 while (alsa_track->alsa_channels < GST_ALSA_MAX_CHANNELS &&
189 snd_mixer_selem_has_playback_channel (element,
190 alsa_track->alsa_channels)) {
191 alsa_track->alsa_channels++;
193 GST_LOG ("[%s] %d output channels", name, alsa_track->alsa_channels);
194 } else if (flags & GST_MIXER_TRACK_INPUT) {
195 while (alsa_track->alsa_channels < GST_ALSA_MAX_CHANNELS &&
196 snd_mixer_selem_has_capture_channel (element,
197 alsa_track->alsa_channels)) {
198 alsa_track->alsa_channels++;
200 GST_LOG ("[%s] %d input channels", name, alsa_track->alsa_channels);
202 g_assert_not_reached ();
206 track->num_channels = 0;
208 track->num_channels = alsa_track->alsa_channels;
210 /* translate the name if we can */
212 for (i = 0; i < G_N_ELEMENTS (alsa_track_labels); ++i) {
213 if (g_utf8_collate (label, alsa_track_labels[i].orig) == 0) {
214 label = _(alsa_track_labels[i].trans);
220 track->label = g_strdup_printf ("%s%s%s", label,
221 append_capture ? " " : "", append_capture ? _("Capture") : "");
223 track->label = g_strdup_printf ("%s%s%s %d", label,
224 append_capture ? " " : "", append_capture ? _("Capture") : "", num);
227 /* set volume information */
228 if (track->num_channels > 0) {
229 if ((flags & GST_MIXER_TRACK_OUTPUT))
230 snd_mixer_selem_get_playback_volume_range (element, &min, &max);
232 snd_mixer_selem_get_capture_volume_range (element, &min, &max);
234 track->min_volume = (gint) min;
235 track->max_volume = (gint) max;
237 for (i = 0; i < track->num_channels; i++) {
240 if (flags & GST_MIXER_TRACK_OUTPUT)
241 snd_mixer_selem_get_playback_volume (element, i, &tmp);
243 snd_mixer_selem_get_capture_volume (element, i, &tmp);
245 alsa_track->volumes[i] = (gint) tmp;
248 gst_alsa_mixer_track_update (alsa_track);
254 gst_alsa_mixer_track_update (GstAlsaMixerTrack * alsa_track)
256 GstMixerTrack *track = (GstMixerTrack *) alsa_track;
258 gint audible = !(track->flags & GST_MIXER_TRACK_MUTE);
260 if (alsa_track_has_cap (alsa_track, GST_ALSA_MIXER_TRACK_PVOLUME)) {
261 /* update playback volume */
262 for (i = 0; i < track->num_channels; i++) {
265 snd_mixer_selem_get_playback_volume (alsa_track->element, i, &vol);
266 alsa_track->volumes[i] = (gint) vol;
270 if (alsa_track_has_cap (alsa_track, GST_ALSA_MIXER_TRACK_CVOLUME)) {
271 /* update capture volume */
272 for (i = 0; i < track->num_channels; i++) {
275 snd_mixer_selem_get_capture_volume (alsa_track->element, i, &vol);
276 alsa_track->volumes[i] = (gint) vol;
280 /* Any updates in flags? */
281 if (alsa_track_has_cap (alsa_track, GST_ALSA_MIXER_TRACK_PSWITCH)) {
285 for (i = 0; i < alsa_track->alsa_channels; ++i) {
286 snd_mixer_selem_get_playback_switch (alsa_track->element, i, &v);
290 } else if (alsa_track_has_cap (alsa_track, GST_ALSA_MIXER_TRACK_PVOLUME) &&
291 track->flags & GST_MIXER_TRACK_MUTE) {
292 /* check if user has raised volume with a parallel running application */
294 for (i = 0; i < track->num_channels; i++) {
297 snd_mixer_selem_get_playback_volume (alsa_track->element, i, &vol);
299 if (vol > track->min_volume) {
306 if (! !(audible) != !(track->flags & GST_MIXER_TRACK_MUTE)) {
308 track->flags &= ~GST_MIXER_TRACK_MUTE;
310 if (alsa_track->shared_mute)
311 ((GstMixerTrack *) (alsa_track->shared_mute))->flags &=
312 ~GST_MIXER_TRACK_MUTE;
314 track->flags |= GST_MIXER_TRACK_MUTE;
316 if (alsa_track->shared_mute)
317 ((GstMixerTrack *) (alsa_track->shared_mute))->flags |=
318 GST_MIXER_TRACK_MUTE;
322 if (track->flags & GST_MIXER_TRACK_INPUT) {
323 gint recording = track->flags & GST_MIXER_TRACK_RECORD;
325 if (alsa_track_has_cap (alsa_track, GST_ALSA_MIXER_TRACK_CSWITCH)) {
329 for (i = 0; i < alsa_track->alsa_channels; ++i) {
330 snd_mixer_selem_get_capture_switch (alsa_track->element, i, &v);
334 } else if (alsa_track_has_cap (alsa_track, GST_ALSA_MIXER_TRACK_CVOLUME) &&
335 !(track->flags & GST_MIXER_TRACK_RECORD)) {
336 /* check if user has raised volume with a parallel running application */
338 for (i = 0; i < track->num_channels; i++) {
341 snd_mixer_selem_get_capture_volume (alsa_track->element, i, &vol);
343 if (vol > track->min_volume) {
351 track->flags |= GST_MIXER_TRACK_RECORD;
353 track->flags &= ~GST_MIXER_TRACK_RECORD;