Added gst-plugins-base-subtitles0.10-0.10.34 for Meego Harmattan 1.2
[mafwsubrenderer] / gst-plugins-base-subtitles0.10 / ext / alsa / gstalsamixertrack.c
1 /* ALSA mixer track 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 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <gst/gst-i18n-plugin.h>
25
26 #include "gstalsamixertrack.h"
27
28 static void gst_alsa_mixer_track_init (GstAlsaMixerTrack * alsa_track);
29 static void gst_alsa_mixer_track_class_init (gpointer g_class,
30     gpointer class_data);
31
32 static GstMixerTrackClass *parent_class = NULL;
33
34 GType
35 gst_alsa_mixer_track_get_type (void)
36 {
37   static GType track_type = 0;
38
39   if (!track_type) {
40     static const GTypeInfo track_info = {
41       sizeof (GstAlsaMixerTrackClass),
42       NULL,
43       NULL,
44       gst_alsa_mixer_track_class_init,
45       NULL,
46       NULL,
47       sizeof (GstAlsaMixerTrack),
48       0,
49       (GInstanceInitFunc) gst_alsa_mixer_track_init,
50       NULL
51     };
52
53     track_type =
54         g_type_register_static (GST_TYPE_MIXER_TRACK, "GstAlsaMixerTrack",
55         &track_info, 0);
56   }
57
58   return track_type;
59 }
60
61 static void
62 gst_alsa_mixer_track_class_init (gpointer g_class, gpointer class_data)
63 {
64   parent_class = g_type_class_peek_parent (g_class);
65 }
66
67 static void
68 gst_alsa_mixer_track_init (GstAlsaMixerTrack * alsa_track)
69 {
70 }
71
72 static void
73 gst_alsa_mixer_track_update_alsa_capabilities (GstAlsaMixerTrack * alsa_track)
74 {
75   alsa_track->alsa_flags = 0;
76   alsa_track->capture_group = -1;
77
78   /* common flags */
79   if (snd_mixer_selem_has_common_volume (alsa_track->element))
80     alsa_track->alsa_flags |= GST_ALSA_MIXER_TRACK_VOLUME;
81
82   if (snd_mixer_selem_has_common_switch (alsa_track->element))
83     alsa_track->alsa_flags |= GST_ALSA_MIXER_TRACK_SWITCH;
84
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 */
89
90   /* playback flags */
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;
94
95     if (snd_mixer_selem_has_playback_switch (alsa_track->element))
96       alsa_track->alsa_flags |= GST_ALSA_MIXER_TRACK_PSWITCH;
97   }
98
99   /* capture flags */
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;
103
104     if (snd_mixer_selem_has_capture_switch (alsa_track->element)) {
105       alsa_track->alsa_flags |= GST_ALSA_MIXER_TRACK_CSWITCH;
106
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);
111       }
112     }
113   }
114
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);
118 }
119
120 inline static gboolean
121 alsa_track_has_cap (GstAlsaMixerTrack * alsa_track, guint32 flag)
122 {
123   return ((alsa_track->alsa_flags & flag) != 0);
124 }
125
126 GstMixerTrack *
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)
130 {
131   GstAlsaMixerTrack *alsa_track;
132   GstMixerTrack *track;
133   const gchar *name;
134   guint index;
135   const gchar *label;
136   gint i;
137   long min = 0, max = 0;
138   const struct
139   {
140     const gchar orig[12];
141     const gchar trans[12];
142   } alsa_track_labels[] = {
143     {
144     "Master", N_("Master")}, {
145     "Bass", N_("Bass")}, {
146     "Treble", N_("Treble")}, {
147     "PCM", N_("PCM")}, {
148     "Synth", N_("Synth")}, {
149     "Line", N_("Line-in")}, {
150     "CD", N_("CD")}, {
151     "Mic", N_("Microphone")}, {
152     "PC Speaker", N_("PC Speaker")}, {
153     "Playback", N_("Playback")}, {
154     "Capture", N_("Capture")}
155   };
156
157   name = snd_mixer_selem_get_name (element);
158   index = snd_mixer_selem_get_index (element);
159
160   GST_LOG
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",
163       shared_mute_track);
164
165   track = (GstMixerTrack *) g_object_new (GST_ALSA_MIXER_TRACK_TYPE,
166       "untranslated-label", name, "index", index, NULL);
167
168   alsa_track = (GstAlsaMixerTrack *) track;
169
170   GST_LOG ("[%s] created new mixer track %p", name, track);
171
172   /* This reflects the assumptions used for GstAlsaMixerTrack */
173   if (!(!!(flags & GST_MIXER_TRACK_OUTPUT) ^ !!(flags & GST_MIXER_TRACK_INPUT))) {
174     GST_ERROR ("Mixer track must be either output or input!");
175     g_return_val_if_reached (NULL);
176   }
177
178   track->flags = flags;
179   alsa_track->element = element;
180   alsa_track->shared_mute = shared_mute_track;
181   alsa_track->track_num = track_num;
182   alsa_track->alsa_channels = 0;
183
184   gst_alsa_mixer_track_update_alsa_capabilities (alsa_track);
185
186   if (flags & GST_MIXER_TRACK_OUTPUT) {
187     while (alsa_track->alsa_channels < GST_ALSA_MAX_CHANNELS &&
188         snd_mixer_selem_has_playback_channel (element,
189             alsa_track->alsa_channels)) {
190       alsa_track->alsa_channels++;
191     }
192     GST_LOG ("[%s] %d output channels", name, alsa_track->alsa_channels);
193   } else if (flags & GST_MIXER_TRACK_INPUT) {
194     while (alsa_track->alsa_channels < GST_ALSA_MAX_CHANNELS &&
195         snd_mixer_selem_has_capture_channel (element,
196             alsa_track->alsa_channels)) {
197       alsa_track->alsa_channels++;
198     }
199     GST_LOG ("[%s] %d input channels", name, alsa_track->alsa_channels);
200   } else {
201     g_assert_not_reached ();
202   }
203
204   if (sw)
205     track->num_channels = 0;
206   else
207     track->num_channels = alsa_track->alsa_channels;
208
209   /* translate the name if we can */
210   label = name;
211   for (i = 0; i < G_N_ELEMENTS (alsa_track_labels); ++i) {
212     if (g_utf8_collate (label, alsa_track_labels[i].orig) == 0) {
213       label = _(alsa_track_labels[i].trans);
214       break;
215     }
216   }
217
218   if (num == 0) {
219     track->label = g_strdup_printf ("%s%s%s", label,
220         append_capture ? " " : "", append_capture ? _("Capture") : "");
221   } else {
222     track->label = g_strdup_printf ("%s%s%s %d", label,
223         append_capture ? " " : "", append_capture ? _("Capture") : "", num);
224   }
225
226   /* set volume information */
227   if (track->num_channels > 0) {
228     if ((flags & GST_MIXER_TRACK_OUTPUT))
229       snd_mixer_selem_get_playback_volume_range (element, &min, &max);
230     else
231       snd_mixer_selem_get_capture_volume_range (element, &min, &max);
232   }
233   track->min_volume = (gint) min;
234   track->max_volume = (gint) max;
235
236   for (i = 0; i < track->num_channels; i++) {
237     long tmp = 0;
238
239     if (flags & GST_MIXER_TRACK_OUTPUT)
240       snd_mixer_selem_get_playback_volume (element, i, &tmp);
241     else
242       snd_mixer_selem_get_capture_volume (element, i, &tmp);
243
244     alsa_track->volumes[i] = (gint) tmp;
245   }
246
247   gst_alsa_mixer_track_update (alsa_track);
248
249   return track;
250 }
251
252 void
253 gst_alsa_mixer_track_update (GstAlsaMixerTrack * alsa_track)
254 {
255   GstMixerTrack *track = (GstMixerTrack *) alsa_track;
256   gint i;
257   gint audible = !(track->flags & GST_MIXER_TRACK_MUTE);
258
259   if (alsa_track_has_cap (alsa_track, GST_ALSA_MIXER_TRACK_PVOLUME)) {
260     /* update playback volume */
261     for (i = 0; i < track->num_channels; i++) {
262       long vol = 0;
263
264       snd_mixer_selem_get_playback_volume (alsa_track->element, i, &vol);
265       alsa_track->volumes[i] = (gint) vol;
266     }
267   }
268
269   if (alsa_track_has_cap (alsa_track, GST_ALSA_MIXER_TRACK_CVOLUME)) {
270     /* update capture volume */
271     for (i = 0; i < track->num_channels; i++) {
272       long vol = 0;
273
274       snd_mixer_selem_get_capture_volume (alsa_track->element, i, &vol);
275       alsa_track->volumes[i] = (gint) vol;
276     }
277   }
278
279   /* Any updates in flags? */
280   if (alsa_track_has_cap (alsa_track, GST_ALSA_MIXER_TRACK_PSWITCH)) {
281     int v = 0;
282
283     audible = 0;
284     for (i = 0; i < alsa_track->alsa_channels; ++i) {
285       snd_mixer_selem_get_playback_switch (alsa_track->element, i, &v);
286       audible += v;
287     }
288
289   } else if (alsa_track_has_cap (alsa_track, GST_ALSA_MIXER_TRACK_PVOLUME) &&
290       track->flags & GST_MIXER_TRACK_MUTE) {
291     /* check if user has raised volume with a parallel running application */
292
293     for (i = 0; i < track->num_channels; i++) {
294       long vol = 0;
295
296       snd_mixer_selem_get_playback_volume (alsa_track->element, i, &vol);
297
298       if (vol > track->min_volume) {
299         audible = 1;
300         break;
301       }
302     }
303   }
304
305   if (!!(audible) != !(track->flags & GST_MIXER_TRACK_MUTE)) {
306     if (audible) {
307       track->flags &= ~GST_MIXER_TRACK_MUTE;
308
309       if (alsa_track->shared_mute)
310         ((GstMixerTrack *) (alsa_track->shared_mute))->flags &=
311             ~GST_MIXER_TRACK_MUTE;
312     } else {
313       track->flags |= GST_MIXER_TRACK_MUTE;
314
315       if (alsa_track->shared_mute)
316         ((GstMixerTrack *) (alsa_track->shared_mute))->flags |=
317             GST_MIXER_TRACK_MUTE;
318     }
319   }
320
321   if (track->flags & GST_MIXER_TRACK_INPUT) {
322     gint recording = track->flags & GST_MIXER_TRACK_RECORD;
323
324     if (alsa_track_has_cap (alsa_track, GST_ALSA_MIXER_TRACK_CSWITCH)) {
325       int v = 0;
326
327       recording = 0;
328       for (i = 0; i < alsa_track->alsa_channels; ++i) {
329         snd_mixer_selem_get_capture_switch (alsa_track->element, i, &v);
330         recording += v;
331       }
332
333     } else if (alsa_track_has_cap (alsa_track, GST_ALSA_MIXER_TRACK_CVOLUME) &&
334         !(track->flags & GST_MIXER_TRACK_RECORD)) {
335       /* check if user has raised volume with a parallel running application */
336
337       for (i = 0; i < track->num_channels; i++) {
338         long vol = 0;
339
340         snd_mixer_selem_get_capture_volume (alsa_track->element, i, &vol);
341
342         if (vol > track->min_volume) {
343           recording = 1;
344           break;
345         }
346       }
347     }
348
349     if (recording)
350       track->flags |= GST_MIXER_TRACK_RECORD;
351     else
352       track->flags &= ~GST_MIXER_TRACK_RECORD;
353   }
354
355 }