gst_plugins_base/ext/alsa/gstalsamixertrack.c
branchRCL_3
changeset 30 7e817e7e631c
parent 0 0e761a78d257
equal deleted inserted replaced
29:567bb019e3e3 30:7e817e7e631c
       
     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   if (snd_mixer_selem_has_common_volume (alsa_track->element))
       
    79     alsa_track->alsa_flags |= GST_ALSA_MIXER_TRACK_VOLUME;
       
    80 
       
    81   if (snd_mixer_selem_has_playback_volume (alsa_track->element))
       
    82     alsa_track->alsa_flags |= GST_ALSA_MIXER_TRACK_PVOLUME;
       
    83 
       
    84   if (snd_mixer_selem_has_capture_volume (alsa_track->element))
       
    85     alsa_track->alsa_flags |= GST_ALSA_MIXER_TRACK_CVOLUME;
       
    86 
       
    87   if (snd_mixer_selem_has_common_switch (alsa_track->element))
       
    88     alsa_track->alsa_flags |= GST_ALSA_MIXER_TRACK_SWITCH;
       
    89 
       
    90   if (snd_mixer_selem_has_playback_switch (alsa_track->element))
       
    91     alsa_track->alsa_flags |= GST_ALSA_MIXER_TRACK_PSWITCH;
       
    92 
       
    93   if (snd_mixer_selem_has_capture_switch (alsa_track->element)) {
       
    94     alsa_track->alsa_flags |= GST_ALSA_MIXER_TRACK_CSWITCH;
       
    95 
       
    96     if (snd_mixer_selem_has_capture_switch_exclusive (alsa_track->element)) {
       
    97       alsa_track->alsa_flags |= GST_ALSA_MIXER_TRACK_CSWITCH_EXCL;
       
    98       alsa_track->capture_group =
       
    99           snd_mixer_selem_get_capture_group (alsa_track->element);
       
   100     }
       
   101   }
       
   102 
       
   103   GST_LOG ("[%s] alsa_flags=0x%08x, capture_group=%d",
       
   104       snd_mixer_selem_get_name (alsa_track->element),
       
   105       alsa_track->alsa_flags, alsa_track->capture_group);
       
   106 }
       
   107 
       
   108 inline static gboolean
       
   109 alsa_track_has_cap (GstAlsaMixerTrack * alsa_track, guint32 flag)
       
   110 {
       
   111   return ((alsa_track->alsa_flags & flag) != 0);
       
   112 }
       
   113 
       
   114 GstMixerTrack *
       
   115 gst_alsa_mixer_track_new (snd_mixer_elem_t * element,
       
   116     gint num, gint track_num, gint flags, gboolean sw,
       
   117     GstAlsaMixerTrack * shared_mute_track, gboolean append_capture)
       
   118 {
       
   119   GstAlsaMixerTrack *alsa_track;
       
   120   GstMixerTrack *track;
       
   121   const gchar *name;
       
   122   const gchar *label;
       
   123   gint i;
       
   124   long min = 0, max = 0;
       
   125   const struct
       
   126   {
       
   127     const gchar orig[12];
       
   128     const gchar trans[12];
       
   129   } alsa_track_labels[] = {
       
   130     {
       
   131     "Master", N_("Master")}, {
       
   132     "Bass", N_("Bass")}, {
       
   133     "Treble", N_("Treble")}, {
       
   134     "PCM", N_("PCM")}, {
       
   135     "Synth", N_("Synth")}, {
       
   136     "Line", N_("Line-in")}, {
       
   137     "CD", N_("CD")}, {
       
   138     "Mic", N_("Microphone")}, {
       
   139     "PC Speaker", N_("PC Speaker")}, {
       
   140     "Playback", N_("Playback")}, {
       
   141     "Capture", N_("Capture")}
       
   142   };
       
   143 
       
   144   name = snd_mixer_selem_get_name (element);
       
   145 
       
   146   GST_LOG ("[%s] num=%d,track_num=%d,flags=0x%08x,sw=%s,shared_mute_track=%p",
       
   147       name, num, track_num, flags, (sw) ? "true" : "false", shared_mute_track);
       
   148 
       
   149   track = (GstMixerTrack *) g_object_new (GST_ALSA_MIXER_TRACK_TYPE,
       
   150       "untranslated-label", name, NULL);
       
   151 
       
   152   alsa_track = (GstAlsaMixerTrack *) track;
       
   153 
       
   154   GST_LOG ("[%s] created new mixer track %p", name, track);
       
   155 
       
   156   /* This reflects the assumptions used for GstAlsaMixerTrack */
       
   157   if (!(!!(flags & GST_MIXER_TRACK_OUTPUT) ^ !!(flags & GST_MIXER_TRACK_INPUT))) {
       
   158     GST_ERROR ("Mixer track must be either output or input!");
       
   159     g_return_val_if_reached (NULL);
       
   160   }
       
   161 
       
   162   track->flags = flags;
       
   163   alsa_track->element = element;
       
   164   alsa_track->shared_mute = shared_mute_track;
       
   165   alsa_track->track_num = track_num;
       
   166   alsa_track->alsa_channels = 0;
       
   167 
       
   168   gst_alsa_mixer_track_update_alsa_capabilities (alsa_track);
       
   169 
       
   170   if (flags & GST_MIXER_TRACK_OUTPUT) {
       
   171     while (alsa_track->alsa_channels < GST_ALSA_MAX_CHANNELS &&
       
   172         snd_mixer_selem_has_playback_channel (element,
       
   173             alsa_track->alsa_channels)) {
       
   174       alsa_track->alsa_channels++;
       
   175     }
       
   176     GST_LOG ("[%s] %d output channels", name, alsa_track->alsa_channels);
       
   177   } else if (flags & GST_MIXER_TRACK_INPUT) {
       
   178     while (alsa_track->alsa_channels < GST_ALSA_MAX_CHANNELS &&
       
   179         snd_mixer_selem_has_capture_channel (element,
       
   180             alsa_track->alsa_channels)) {
       
   181       alsa_track->alsa_channels++;
       
   182     }
       
   183     GST_LOG ("[%s] %d input channels", name, alsa_track->alsa_channels);
       
   184   } else {
       
   185     g_assert_not_reached ();
       
   186   }
       
   187 
       
   188   if (sw)
       
   189     track->num_channels = 0;
       
   190   else
       
   191     track->num_channels = alsa_track->alsa_channels;
       
   192 
       
   193   /* translate the name if we can */
       
   194   label = name;
       
   195   for (i = 0; i < G_N_ELEMENTS (alsa_track_labels); ++i) {
       
   196     if (g_utf8_collate (label, alsa_track_labels[i].orig) == 0) {
       
   197       label = _(alsa_track_labels[i].trans);
       
   198       break;
       
   199     }
       
   200   }
       
   201 
       
   202   if (num == 0) {
       
   203     track->label = g_strdup_printf ("%s%s%s", label,
       
   204         append_capture ? " " : "", append_capture ? _("Capture") : "");
       
   205   } else {
       
   206     track->label = g_strdup_printf ("%s%s%s %d", label,
       
   207         append_capture ? " " : "", append_capture ? _("Capture") : "", num);
       
   208   }
       
   209 
       
   210   /* set volume information */
       
   211   if (track->num_channels > 0) {
       
   212     if ((flags & GST_MIXER_TRACK_OUTPUT))
       
   213       snd_mixer_selem_get_playback_volume_range (element, &min, &max);
       
   214     else
       
   215       snd_mixer_selem_get_capture_volume_range (element, &min, &max);
       
   216   }
       
   217   track->min_volume = (gint) min;
       
   218   track->max_volume = (gint) max;
       
   219 
       
   220   for (i = 0; i < track->num_channels; i++) {
       
   221     long tmp = 0;
       
   222 
       
   223     if (flags & GST_MIXER_TRACK_OUTPUT)
       
   224       snd_mixer_selem_get_playback_volume (element, i, &tmp);
       
   225     else
       
   226       snd_mixer_selem_get_capture_volume (element, i, &tmp);
       
   227 
       
   228     alsa_track->volumes[i] = (gint) tmp;
       
   229   }
       
   230 
       
   231   gst_alsa_mixer_track_update (alsa_track);
       
   232 
       
   233   return track;
       
   234 }
       
   235 
       
   236 void
       
   237 gst_alsa_mixer_track_update (GstAlsaMixerTrack * alsa_track)
       
   238 {
       
   239   GstMixerTrack *track = (GstMixerTrack *) alsa_track;
       
   240   gint i;
       
   241   gint audible = !(track->flags & GST_MIXER_TRACK_MUTE);
       
   242 
       
   243   if (alsa_track_has_cap (alsa_track, GST_ALSA_MIXER_TRACK_PVOLUME)) {
       
   244     /* update playback volume */
       
   245     for (i = 0; i < track->num_channels; i++) {
       
   246       long vol = 0;
       
   247 
       
   248       snd_mixer_selem_get_playback_volume (alsa_track->element, i, &vol);
       
   249       alsa_track->volumes[i] = (gint) vol;
       
   250     }
       
   251   }
       
   252 
       
   253   if (alsa_track_has_cap (alsa_track, GST_ALSA_MIXER_TRACK_CVOLUME)) {
       
   254     /* update capture volume */
       
   255     for (i = 0; i < track->num_channels; i++) {
       
   256       long vol = 0;
       
   257 
       
   258       snd_mixer_selem_get_capture_volume (alsa_track->element, i, &vol);
       
   259       alsa_track->volumes[i] = (gint) vol;
       
   260     }
       
   261   }
       
   262 
       
   263   /* Any updates in flags? */
       
   264   if (alsa_track_has_cap (alsa_track, GST_ALSA_MIXER_TRACK_PSWITCH)) {
       
   265     int v = 0;
       
   266 
       
   267     audible = 0;
       
   268     for (i = 0; i < alsa_track->alsa_channels; ++i) {
       
   269       snd_mixer_selem_get_playback_switch (alsa_track->element, i, &v);
       
   270       audible += v;
       
   271     }
       
   272 
       
   273   } else if (alsa_track_has_cap (alsa_track, GST_ALSA_MIXER_TRACK_PVOLUME) &&
       
   274       track->flags & GST_MIXER_TRACK_MUTE) {
       
   275     /* check if user has raised volume with a parallel running application */
       
   276 
       
   277     for (i = 0; i < track->num_channels; i++) {
       
   278       long vol = 0;
       
   279 
       
   280       snd_mixer_selem_get_playback_volume (alsa_track->element, i, &vol);
       
   281 
       
   282       if (vol > track->min_volume) {
       
   283         audible = 1;
       
   284         break;
       
   285       }
       
   286     }
       
   287   }
       
   288 
       
   289   if (!!(audible) != !(track->flags & GST_MIXER_TRACK_MUTE)) {
       
   290     if (audible) {
       
   291       track->flags &= ~GST_MIXER_TRACK_MUTE;
       
   292 
       
   293       if (alsa_track->shared_mute)
       
   294         ((GstMixerTrack *) (alsa_track->shared_mute))->flags &=
       
   295             ~GST_MIXER_TRACK_MUTE;
       
   296     } else {
       
   297       track->flags |= GST_MIXER_TRACK_MUTE;
       
   298 
       
   299       if (alsa_track->shared_mute)
       
   300         ((GstMixerTrack *) (alsa_track->shared_mute))->flags |=
       
   301             GST_MIXER_TRACK_MUTE;
       
   302     }
       
   303   }
       
   304 
       
   305   if (track->flags & GST_MIXER_TRACK_INPUT) {
       
   306     gint recording = track->flags & GST_MIXER_TRACK_RECORD;
       
   307 
       
   308     if (alsa_track_has_cap (alsa_track, GST_ALSA_MIXER_TRACK_CSWITCH)) {
       
   309       int v = 0;
       
   310 
       
   311       recording = 0;
       
   312       for (i = 0; i < alsa_track->alsa_channels; ++i) {
       
   313         snd_mixer_selem_get_capture_switch (alsa_track->element, i, &v);
       
   314         recording += v;
       
   315       }
       
   316 
       
   317     } else if (alsa_track_has_cap (alsa_track, GST_ALSA_MIXER_TRACK_CVOLUME) &&
       
   318         !(track->flags & GST_MIXER_TRACK_RECORD)) {
       
   319       /* check if user has raised volume with a parallel running application */
       
   320 
       
   321       for (i = 0; i < track->num_channels; i++) {
       
   322         long vol = 0;
       
   323 
       
   324         snd_mixer_selem_get_capture_volume (alsa_track->element, i, &vol);
       
   325 
       
   326         if (vol > track->min_volume) {
       
   327           recording = 1;
       
   328           break;
       
   329         }
       
   330       }
       
   331     }
       
   332 
       
   333     if (recording)
       
   334       track->flags |= GST_MIXER_TRACK_RECORD;
       
   335     else
       
   336       track->flags &= ~GST_MIXER_TRACK_RECORD;
       
   337   }
       
   338 
       
   339 }