1999-05-02 18:21:40 +02:00
/*
* ALSA command line mixer utility
2000-07-15 12:21:59 +02:00
* Copyright ( c ) 1999 - 2000 by Jaroslav Kysela < perex @ suse . cz >
1999-05-02 18:21:40 +02:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*
*/
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <getopt.h>
# include <stdarg.h>
# include <ctype.h>
# include <math.h>
2000-08-11 21:29:55 +02:00
# include <errno.h>
2000-08-12 17:34:17 +02:00
# include <assert.h>
1999-05-02 18:21:40 +02:00
# include <sys/asoundlib.h>
2000-08-12 17:34:17 +02:00
# include <sys/poll.h>
1999-05-02 18:21:40 +02:00
# include "amixer.h"
# define HELPID_HELP 1000
# define HELPID_CARD 1001
2000-07-15 12:21:59 +02:00
# define HELPID_QUIET 1002
# define HELPID_DEBUG 1003
# define HELPID_VERSION 1004
1999-05-02 18:21:40 +02:00
int quiet = 0 ;
int debugflag = 0 ;
2000-11-21 21:38:50 +01:00
char * card = " hw:0 " ;
1999-05-02 18:21:40 +02:00
2000-08-12 17:34:17 +02:00
static void error ( const char * fmt , . . . )
1999-05-02 18:21:40 +02:00
{
va_list va ;
va_start ( va , fmt ) ;
fprintf ( stderr , " amixer: " ) ;
vfprintf ( stderr , fmt , va ) ;
fprintf ( stderr , " \n " ) ;
va_end ( va ) ;
}
2000-08-11 21:29:55 +02:00
static int help ( void )
1999-05-02 18:21:40 +02:00
{
printf ( " Usage: amixer <options> command \n " ) ;
printf ( " \n Available options: \n " ) ;
printf ( " -h,--help this help \n " ) ;
2000-11-21 21:38:50 +01:00
printf ( " -c,--card N use a ctl name, default %s \n " , card ) ;
1999-05-02 18:21:40 +02:00
printf ( " -D,--debug debug mode \n " ) ;
printf ( " -v,--version print version of this program \n " ) ;
printf ( " \n Available commands: \n " ) ;
2000-08-11 21:29:55 +02:00
printf ( " scontrols show all mixer simple controls \n " ) ;
printf ( " scontents show contents of all mixer simple controls (default command) \n " ) ;
printf ( " sset sID P set contents for one mixer simple control \n " ) ;
printf ( " sget sID P get contents for one mixer simple control \n " ) ;
printf ( " controls show all controls for given card \n " ) ;
printf ( " contents show contents of all controls for given card \n " ) ;
printf ( " cset cID P set control contents for one control \n " ) ;
printf ( " cget cID P get control contents for one control \n " ) ;
return 0 ;
1999-05-02 18:21:40 +02:00
}
2000-08-12 17:34:17 +02:00
static int info ( void )
1999-05-02 18:21:40 +02:00
{
int err ;
2000-07-15 12:21:59 +02:00
snd_ctl_t * handle ;
snd_mixer_t * mhandle ;
2001-02-07 16:13:17 +01:00
snd_ctl_card_info_t * info ;
2001-02-09 12:20:32 +01:00
snd_ctl_elem_list_t * clist ;
2001-02-07 16:13:17 +01:00
snd_ctl_card_info_alloca ( & info ) ;
2001-02-09 12:20:32 +01:00
snd_ctl_elem_list_alloca ( & clist ) ;
1999-05-02 18:21:40 +02:00
2000-07-15 12:21:59 +02:00
if ( ( err = snd_ctl_open ( & handle , card ) ) < 0 ) {
error ( " Control device %i open error: %s " , card , snd_strerror ( err ) ) ;
2000-08-11 21:29:55 +02:00
return err ;
1999-05-02 18:21:40 +02:00
}
2001-02-07 16:13:17 +01:00
if ( ( err = snd_ctl_card_info ( handle , info ) ) < 0 ) {
2000-07-15 12:21:59 +02:00
error ( " Control device %i hw info error: %s " , card , snd_strerror ( err ) ) ;
2000-08-11 21:29:55 +02:00
return err ;
1999-05-02 18:21:40 +02:00
}
2001-02-07 16:13:17 +01:00
printf ( " Card %s '%s'/'%s' \n " , card , snd_ctl_card_info_get_id ( info ) ,
snd_ctl_card_info_get_longname ( info ) ) ;
printf ( " Mixer ID : '%s' \n " , snd_ctl_card_info_get_mixerid ( info ) ) ;
printf ( " Mixer name : '%s' \n " , snd_ctl_card_info_get_mixername ( info ) ) ;
2001-02-09 12:20:32 +01:00
if ( ( err = snd_ctl_elem_list ( handle , clist ) ) < 0 ) {
error ( " snd_ctl_elem_list failure: %s " , snd_strerror ( err ) ) ;
2000-07-15 12:21:59 +02:00
} else {
2001-02-09 12:20:32 +01:00
printf ( " Controls : %i \n " , snd_ctl_elem_list_get_count ( clist ) ) ;
2000-07-15 12:21:59 +02:00
}
snd_ctl_close ( handle ) ;
2001-02-11 16:45:44 +01:00
if ( ( err = snd_mixer_open ( & mhandle ) ) < 0 ) {
error ( " Mixer open error: %s " , snd_strerror ( err ) ) ;
return err ;
}
if ( ( err = snd_mixer_attach ( mhandle , card ) ) < 0 ) {
error ( " Mixer attach %s error: %s " , card , snd_strerror ( err ) ) ;
snd_mixer_close ( mhandle ) ;
2000-08-11 21:29:55 +02:00
return err ;
2000-07-15 12:21:59 +02:00
}
2001-02-11 16:45:44 +01:00
if ( ( err = snd_mixer_selem_register ( mhandle , 0 ) ) < 0 ) {
error ( " Mixer register error: %s " , snd_strerror ( err ) ) ;
snd_mixer_close ( mhandle ) ;
return err ;
}
err = snd_mixer_load ( mhandle ) ;
2001-02-09 12:20:32 +01:00
if ( err < 0 ) {
2001-02-11 16:45:44 +01:00
error ( " Mixer load error: %s " , card , snd_strerror ( err ) ) ;
snd_mixer_close ( mhandle ) ;
return err ;
2000-07-15 12:21:59 +02:00
}
2001-02-11 16:45:44 +01:00
printf ( " Simple ctrls : %i \n " , snd_mixer_get_count ( mhandle ) ) ;
2000-07-15 12:21:59 +02:00
snd_mixer_close ( mhandle ) ;
1999-05-02 18:21:40 +02:00
return 0 ;
}
2001-02-09 12:20:32 +01:00
static const char * control_iface ( snd_ctl_elem_id_t * id )
2000-08-11 21:29:55 +02:00
{
2001-02-09 12:20:32 +01:00
return snd_ctl_elem_iface_name ( snd_ctl_elem_id_get_interface ( id ) ) ;
2000-08-11 21:29:55 +02:00
}
2001-02-09 12:20:32 +01:00
static const char * control_type ( snd_ctl_elem_info_t * info )
2000-08-11 21:29:55 +02:00
{
2001-02-09 12:20:32 +01:00
return snd_ctl_elem_type_name ( snd_ctl_elem_info_get_type ( info ) ) ;
2000-08-11 21:29:55 +02:00
}
2001-02-09 12:20:32 +01:00
static const char * control_access ( snd_ctl_elem_info_t * info )
2000-08-11 21:29:55 +02:00
{
2001-02-07 00:48:29 +01:00
static char result [ 10 ] ;
2000-08-11 21:29:55 +02:00
char * res = result ;
2001-02-09 12:20:32 +01:00
* res + + = snd_ctl_elem_info_is_readable ( info ) ? ' r ' : ' - ' ;
* res + + = snd_ctl_elem_info_is_writable ( info ) ? ' w ' : ' - ' ;
* res + + = snd_ctl_elem_info_is_inactive ( info ) ? ' i ' : ' - ' ;
* res + + = snd_ctl_elem_info_is_volatile ( info ) ? ' v ' : ' - ' ;
* res + + = snd_ctl_elem_info_is_locked ( info ) ? ' l ' : ' - ' ;
2000-08-11 21:29:55 +02:00
* res + + = ' \0 ' ;
return result ;
}
1999-05-02 18:21:40 +02:00
static int check_range ( int val , int min , int max )
{
if ( val < min )
return min ;
if ( val > max )
return max ;
return val ;
}
2000-08-11 21:29:55 +02:00
#if 0
1999-05-02 18:21:40 +02:00
static int convert_range ( int val , int omin , int omax , int nmin , int nmax )
{
int orange = omax - omin , nrange = nmax - nmin ;
if ( orange = = 0 )
return 0 ;
1999-07-30 23:58:34 +02:00
return rint ( ( ( ( double ) nrange * ( ( double ) val - ( double ) omin ) ) + ( ( double ) orange / 2.0 ) ) / ( ( double ) orange + ( double ) nmin ) ) ;
1999-05-02 18:21:40 +02:00
}
2000-08-11 21:29:55 +02:00
# endif
1999-05-02 18:21:40 +02:00
2000-08-11 21:29:55 +02:00
#if 0
1999-05-02 18:21:40 +02:00
static int convert_db_range ( int val , int omin , int omax , int nmin , int nmax )
{
int orange = omax - omin , nrange = nmax - nmin ;
if ( orange = = 0 )
return 0 ;
2000-08-11 21:29:55 +02:00
return rint ( ( ( ( double ) nrange * ( ( double ) val - ( double ) omin ) ) + ( ( double ) orange / 2.0 ) ) / ( double ) orange + ( double ) nmin ) ;
1999-05-02 18:21:40 +02:00
}
2000-08-11 21:29:55 +02:00
# endif
1999-05-02 18:21:40 +02:00
1999-07-30 23:58:34 +02:00
/* Fuction to convert from volume to percentage. val = volume */
1999-05-02 18:21:40 +02:00
static int convert_prange ( int val , int min , int max )
{
1999-07-31 00:24:24 +02:00
int range = max - min ;
int tmp ;
if ( range = = 0 )
1999-07-30 23:58:34 +02:00
return 0 ;
1999-07-31 00:24:24 +02:00
val - = min ;
tmp = rint ( ( double ) val / ( double ) range * 100 ) ;
return tmp ;
1999-07-30 23:58:34 +02:00
}
/* Function to convert from percentage to volume. val = percentage */
static int convert_prange1 ( int val , int min , int max )
{
int range = max - min ;
int tmp ;
if ( range = = 0 )
return 0 ;
1999-07-31 00:24:24 +02:00
2000-08-11 21:29:55 +02:00
tmp = rint ( ( double ) range * ( ( double ) val * .01 ) ) + min ;
1999-07-30 23:58:34 +02:00
return tmp ;
1999-05-02 18:21:40 +02:00
}
static const char * get_percent ( int val , int min , int max )
{
static char str [ 32 ] ;
int p ;
1999-07-30 23:58:34 +02:00
p = convert_prange ( val , min , max ) ;
1999-05-02 18:21:40 +02:00
sprintf ( str , " %i [%i%%] " , val , p ) ;
return str ;
}
2000-08-11 21:29:55 +02:00
#if 0
1999-05-02 18:21:40 +02:00
static const char * get_percent1 ( int val , int min , int max , int min_dB , int max_dB )
{
static char str [ 32 ] ;
int p , db ;
1999-07-30 23:58:34 +02:00
p = convert_prange ( val , min , max ) ;
1999-05-02 18:21:40 +02:00
db = convert_db_range ( val , min , max , min_dB , max_dB ) ;
sprintf ( str , " %i [%i%%] [%i.%02idB] " , val , p , db / 100 , abs ( db % 100 ) ) ;
return str ;
}
2000-08-11 21:29:55 +02:00
# endif
1999-05-02 18:21:40 +02:00
2000-08-11 21:29:55 +02:00
static long get_integer ( char * * ptr , long min , long max )
1999-05-02 18:21:40 +02:00
{
int tmp , tmp1 , tmp2 ;
if ( * * ptr = = ' : ' )
( * ptr ) + + ;
if ( * * ptr = = ' \0 ' | | ( ! isdigit ( * * ptr ) & & * * ptr ! = ' - ' ) )
return min ;
2000-08-11 21:29:55 +02:00
tmp = strtol ( * ptr , ptr , 10 ) ;
1999-05-02 18:21:40 +02:00
tmp1 = tmp ;
tmp2 = 0 ;
if ( * * ptr = = ' . ' ) {
( * ptr ) + + ;
2000-08-11 21:29:55 +02:00
tmp2 = strtol ( * ptr , ptr , 10 ) ;
1999-05-02 18:21:40 +02:00
}
if ( * * ptr = = ' % ' ) {
1999-07-30 23:58:34 +02:00
tmp1 = convert_prange1 ( tmp , min , max ) ;
1999-05-02 18:21:40 +02:00
( * ptr ) + + ;
}
tmp1 = check_range ( tmp1 , min , max ) ;
if ( * * ptr = = ' , ' )
( * ptr ) + + ;
return tmp1 ;
}
2000-03-18 19:00:37 +01:00
static int get_volume_simple ( char * * ptr , int min , int max , int orig )
1999-07-21 13:52:55 +02:00
{
int tmp , tmp1 , tmp2 ;
if ( * * ptr = = ' : ' )
( * ptr ) + + ;
if ( * * ptr = = ' \0 ' | | ( ! isdigit ( * * ptr ) & & * * ptr ! = ' - ' ) )
return min ;
tmp = atoi ( * ptr ) ;
if ( * * ptr = = ' - ' )
( * ptr ) + + ;
while ( isdigit ( * * ptr ) )
( * ptr ) + + ;
tmp1 = tmp ;
tmp2 = 0 ;
if ( * * ptr = = ' . ' ) {
( * ptr ) + + ;
tmp2 = atoi ( * ptr ) ;
while ( isdigit ( * * ptr ) )
( * ptr ) + + ;
}
if ( * * ptr = = ' % ' ) {
1999-07-30 23:58:34 +02:00
tmp1 = convert_prange1 ( tmp , min , max ) ;
1999-07-21 13:52:55 +02:00
( * ptr ) + + ;
}
2000-03-18 19:00:37 +01:00
if ( * * ptr = = ' + ' ) {
tmp1 = orig + tmp1 ;
( * ptr ) + + ;
} else if ( * * ptr = = ' - ' ) {
tmp1 = orig - tmp1 ;
( * ptr ) + + ;
}
1999-07-21 13:52:55 +02:00
tmp1 = check_range ( tmp1 , min , max ) ;
if ( * * ptr = = ' , ' )
( * ptr ) + + ;
return tmp1 ;
}
2001-02-09 12:20:32 +01:00
static void show_control_id ( snd_ctl_elem_id_t * id )
1999-05-02 18:21:40 +02:00
{
2001-02-07 00:48:29 +01:00
unsigned int index , device , subdevice ;
printf ( " numid=%u,iface=%s,name='%s' " ,
2001-02-09 12:20:32 +01:00
snd_ctl_elem_id_get_numid ( id ) ,
2001-02-07 00:48:29 +01:00
control_iface ( id ) ,
2001-02-09 12:20:32 +01:00
snd_ctl_elem_id_get_name ( id ) ) ;
index = snd_ctl_elem_id_get_index ( id ) ;
device = snd_ctl_elem_id_get_device ( id ) ;
subdevice = snd_ctl_elem_id_get_subdevice ( id ) ;
2001-02-07 00:48:29 +01:00
if ( index )
printf ( " ,index=%i " , index ) ;
if ( device )
printf ( " ,device=%i " , device ) ;
if ( subdevice )
printf ( " ,subdevice=%i " , subdevice ) ;
2000-08-11 21:29:55 +02:00
}
2001-02-11 16:45:44 +01:00
static int show_control ( const char * space , snd_hctl_elem_t * elem ,
int level )
2000-08-11 21:29:55 +02:00
{
int err ;
unsigned int item , idx ;
2001-02-07 00:48:29 +01:00
unsigned int count ;
2001-02-09 12:20:32 +01:00
snd_ctl_elem_type_t type ;
2001-02-11 16:45:44 +01:00
snd_ctl_elem_id_t * id ;
2001-02-09 12:20:32 +01:00
snd_ctl_elem_info_t * info ;
2001-02-11 16:45:44 +01:00
snd_ctl_elem_value_t * control ;
snd_ctl_elem_id_alloca ( & id ) ;
2001-02-09 12:20:32 +01:00
snd_ctl_elem_info_alloca ( & info ) ;
2001-02-11 16:45:44 +01:00
snd_ctl_elem_value_alloca ( & control ) ;
if ( ( err = snd_hctl_elem_info ( elem , info ) ) < 0 ) {
2000-09-18 11:47:01 +02:00
error ( " Control %s cinfo error: %s \n " , card , snd_strerror ( err ) ) ;
2000-08-11 21:29:55 +02:00
return err ;
}
if ( level & 2 ) {
2001-02-11 16:45:44 +01:00
snd_hctl_elem_get_id ( elem , id ) ;
2001-02-07 00:48:29 +01:00
show_control_id ( id ) ;
2000-08-11 21:29:55 +02:00
printf ( " \n " ) ;
1999-05-02 18:21:40 +02:00
}
2001-02-09 12:20:32 +01:00
count = snd_ctl_elem_info_get_count ( info ) ;
type = snd_ctl_elem_info_get_type ( info ) ;
2001-02-07 00:48:29 +01:00
printf ( " %s; type=%s,access=%s,values=%i " , space , control_type ( info ) , control_access ( info ) , count ) ;
switch ( snd_enum_to_int ( type ) ) {
2001-02-09 12:20:32 +01:00
case SND_CTL_ELEM_TYPE_INTEGER :
2001-02-07 00:48:29 +01:00
printf ( " ,min=%li,max=%li,step=%li \n " ,
2001-02-09 12:20:32 +01:00
snd_ctl_elem_info_get_min ( info ) ,
snd_ctl_elem_info_get_max ( info ) ,
snd_ctl_elem_info_get_step ( info ) ) ;
2000-08-11 21:29:55 +02:00
break ;
2001-02-09 12:20:32 +01:00
case SND_CTL_ELEM_TYPE_ENUMERATED :
2001-02-07 00:48:29 +01:00
{
2001-02-09 12:20:32 +01:00
unsigned int items = snd_ctl_elem_info_get_items ( info ) ;
2001-02-07 00:48:29 +01:00
printf ( " ,items=%u \n " , items ) ;
for ( item = 0 ; item < items ; item + + ) {
2001-02-09 12:20:32 +01:00
snd_ctl_elem_info_set_item ( info , item ) ;
2001-02-11 16:45:44 +01:00
if ( ( err = snd_hctl_elem_info ( elem , info ) ) < 0 ) {
2001-02-09 12:20:32 +01:00
error ( " Control %s element info error: %s \n " , card , snd_strerror ( err ) ) ;
2000-08-11 21:29:55 +02:00
return err ;
}
2001-02-09 12:20:32 +01:00
printf ( " %s; Item #%u '%s' \n " , space , item , snd_ctl_elem_info_get_item_name ( info ) ) ;
2000-08-11 21:29:55 +02:00
}
break ;
2001-02-07 00:48:29 +01:00
}
2000-08-11 21:29:55 +02:00
default :
printf ( " \n " ) ;
break ;
1999-05-02 18:21:40 +02:00
}
2000-08-11 21:29:55 +02:00
if ( level & 1 ) {
2001-02-11 16:45:44 +01:00
if ( ( err = snd_hctl_elem_read ( elem , control ) ) < 0 ) {
2001-02-09 12:20:32 +01:00
error ( " Control %s element read error: %s \n " , card , snd_strerror ( err ) ) ;
2000-08-11 21:29:55 +02:00
return err ;
}
printf ( " %s: values= " , space ) ;
2001-02-07 00:48:29 +01:00
for ( idx = 0 ; idx < count ; idx + + ) {
2000-08-11 21:29:55 +02:00
if ( idx > 0 )
printf ( " , " ) ;
2001-02-07 00:48:29 +01:00
switch ( snd_enum_to_int ( type ) ) {
2001-02-09 12:20:32 +01:00
case SND_CTL_ELEM_TYPE_BOOLEAN :
2001-02-11 16:45:44 +01:00
printf ( " %s " , snd_ctl_elem_value_get_boolean ( control , idx ) ? " on " : " off " ) ;
2000-08-11 21:29:55 +02:00
break ;
2001-02-09 12:20:32 +01:00
case SND_CTL_ELEM_TYPE_INTEGER :
2001-02-11 16:45:44 +01:00
printf ( " %li " , snd_ctl_elem_value_get_integer ( control , idx ) ) ;
2000-08-11 21:29:55 +02:00
break ;
2001-02-09 12:20:32 +01:00
case SND_CTL_ELEM_TYPE_ENUMERATED :
2001-02-11 16:45:44 +01:00
printf ( " %u " , snd_ctl_elem_value_get_enumerated ( control , idx ) ) ;
2000-08-11 21:29:55 +02:00
break ;
2001-02-09 12:20:32 +01:00
case SND_CTL_ELEM_TYPE_BYTES :
2001-02-11 16:45:44 +01:00
printf ( " 0x%02x " , snd_ctl_elem_value_get_byte ( control , idx ) ) ;
2000-08-11 21:29:55 +02:00
break ;
default :
printf ( " ? " ) ;
break ;
}
}
printf ( " \n " ) ;
1999-05-02 18:21:40 +02:00
}
return 0 ;
}
2000-08-11 21:29:55 +02:00
static int controls ( int level )
1999-05-02 18:21:40 +02:00
{
2001-02-05 16:44:45 +01:00
int err ;
2001-02-09 16:38:59 +01:00
snd_hctl_t * handle ;
2001-02-09 12:20:32 +01:00
snd_hctl_elem_t * elem ;
snd_ctl_elem_id_t * id ;
snd_ctl_elem_id_alloca ( & id ) ;
1999-05-02 18:21:40 +02:00
2001-02-09 16:38:59 +01:00
if ( ( err = snd_hctl_open ( & handle , card ) ) < 0 ) {
2000-09-18 11:47:01 +02:00
error ( " Control %s open error: %s " , card , snd_strerror ( err ) ) ;
2000-08-11 21:29:55 +02:00
return err ;
}
2001-02-11 16:45:44 +01:00
if ( ( err = snd_hctl_load ( handle ) ) < 0 ) {
error ( " Control %s local error: %s \n " , card , snd_strerror ( err ) ) ;
return err ;
}
2001-02-09 12:20:32 +01:00
for ( elem = snd_hctl_first_elem ( handle ) ; elem ; elem = snd_hctl_elem_next ( elem ) ) {
snd_hctl_elem_get_id ( elem , id ) ;
2001-02-07 00:48:29 +01:00
show_control_id ( id ) ;
2000-08-11 21:29:55 +02:00
printf ( " \n " ) ;
if ( level > 0 )
2001-02-11 16:45:44 +01:00
show_control ( " " , elem , 1 ) ;
1999-05-02 18:21:40 +02:00
}
2001-02-09 16:38:59 +01:00
snd_hctl_close ( handle ) ;
1999-05-02 18:21:40 +02:00
return 0 ;
}
2001-02-09 12:20:32 +01:00
static int show_selem ( snd_mixer_t * handle , snd_mixer_selem_id_t * id , const char * space , int level )
1999-05-02 18:21:40 +02:00
{
2001-02-05 16:44:45 +01:00
int err ;
2001-02-11 16:45:44 +01:00
snd_mixer_selem_channel_id_t chn ;
2001-02-09 12:20:32 +01:00
long min , max ;
snd_mixer_elem_t * elem ;
2001-02-11 16:45:44 +01:00
snd_mixer_selem_info_t * sinfo ;
snd_mixer_selem_value_t * scontrol ;
snd_mixer_selem_info_alloca ( & sinfo ) ;
snd_mixer_selem_value_alloca ( & scontrol ) ;
1999-05-02 18:21:40 +02:00
2001-02-09 12:20:32 +01:00
elem = snd_mixer_find_selem ( handle , id ) ;
if ( ! elem ) {
error ( " Mixer %s simple element not found " , card ) ;
return - ENOENT ;
}
2001-02-11 16:45:44 +01:00
if ( ( err = snd_mixer_selem_info ( elem , sinfo ) ) < 0 ) {
error ( " Mixer %s selem info error: %s " , card , snd_strerror ( err ) ) ;
return err ;
}
2001-02-09 12:20:32 +01:00
if ( ( err = snd_mixer_selem_read ( elem , scontrol ) ) < 0 ) {
2001-02-11 16:45:44 +01:00
error ( " Mixer %s selem read error: %s " , card , snd_strerror ( err ) ) ;
2000-08-11 21:29:55 +02:00
return err ;
1999-05-02 18:21:40 +02:00
}
2001-02-09 12:20:32 +01:00
if ( ( level & 1 ) ! = 0 ) {
1999-07-21 13:52:55 +02:00
printf ( " %sCapabilities: " , space ) ;
2001-02-11 16:45:44 +01:00
if ( snd_mixer_selem_info_has_volume ( sinfo ) )
1999-07-21 00:00:59 +02:00
printf ( " volume " ) ;
2001-02-11 16:45:44 +01:00
if ( snd_mixer_selem_info_has_joined_volume ( sinfo ) )
2001-02-09 12:20:32 +01:00
printf ( " joined-volume " ) ;
2001-02-11 16:45:44 +01:00
if ( snd_mixer_selem_info_has_mute ( sinfo ) )
1999-07-21 00:00:59 +02:00
printf ( " mute " ) ;
2001-02-11 16:45:44 +01:00
if ( snd_mixer_selem_info_has_joined_mute ( sinfo ) )
2001-02-09 12:20:32 +01:00
printf ( " joined-mute " ) ;
2001-02-11 16:45:44 +01:00
if ( snd_mixer_selem_info_has_capture ( sinfo ) ) {
1999-07-23 00:23:42 +02:00
printf ( " capture " ) ;
1999-07-21 00:00:59 +02:00
}
2001-02-11 16:45:44 +01:00
if ( snd_mixer_selem_info_has_joined_capture ( sinfo ) )
2001-02-09 12:20:32 +01:00
printf ( " joined-capture " ) ;
2001-02-11 16:45:44 +01:00
if ( snd_mixer_selem_info_has_exclusive_capture ( sinfo ) )
1999-07-23 00:23:42 +02:00
printf ( " exclusive-capture " ) ;
1999-07-21 00:00:59 +02:00
printf ( " \n " ) ;
2001-02-11 16:45:44 +01:00
if ( snd_mixer_selem_info_has_capture ( sinfo ) & &
snd_mixer_selem_info_has_exclusive_capture ( sinfo ) )
printf ( " %sCapture exclusive group: %i \n " , space ,
snd_mixer_selem_info_get_capture_group ( sinfo ) ) ;
1999-07-21 13:52:55 +02:00
printf ( " %sChannels: " , space ) ;
2001-02-11 16:45:44 +01:00
if ( snd_mixer_selem_info_is_mono ( sinfo ) ) {
1999-07-21 00:00:59 +02:00
printf ( " Mono " ) ;
} else {
2001-02-11 16:45:44 +01:00
for ( chn = 0 ; chn < = SND_MIXER_SCHN_LAST ; snd_enum_incr ( chn ) ) {
if ( ! snd_mixer_selem_info_has_channel ( sinfo , chn ) )
1999-07-22 20:10:19 +02:00
continue ;
2001-02-11 16:45:44 +01:00
printf ( " %s " , snd_mixer_selem_channel_name ( chn ) ) ;
1999-07-22 20:10:19 +02:00
}
1999-07-21 00:00:59 +02:00
}
printf ( " \n " ) ;
2001-02-11 16:45:44 +01:00
min = snd_mixer_selem_info_get_min ( sinfo ) ;
max = snd_mixer_selem_info_get_max ( sinfo ) ;
2001-02-09 12:20:32 +01:00
printf ( " %sLimits: min = %li, max = %li \n " , space , min , max ) ;
2001-02-11 16:45:44 +01:00
if ( snd_mixer_selem_info_is_mono ( sinfo ) ) {
2001-02-09 12:20:32 +01:00
printf ( " %sMono: %s [%s] \n " , space ,
2001-02-11 16:45:44 +01:00
get_percent ( snd_mixer_selem_value_get_volume ( scontrol , SND_MIXER_SCHN_MONO ) , min , max ) ,
snd_mixer_selem_value_get_mute ( scontrol , SND_MIXER_SCHN_MONO ) ? " mute " : " on " ) ;
1999-07-21 00:00:59 +02:00
} else {
2001-02-11 16:45:44 +01:00
for ( chn = 0 ; chn < = SND_MIXER_SCHN_LAST ; snd_enum_incr ( chn ) ) {
if ( ! snd_mixer_selem_info_has_channel ( sinfo , chn ) )
1999-07-22 20:10:19 +02:00
continue ;
printf ( " %s%s: %s [%s] [%s] \n " ,
2001-02-11 16:45:44 +01:00
space ,
snd_mixer_selem_channel_name ( chn ) ,
get_percent ( snd_mixer_selem_value_get_volume ( scontrol , chn ) , min , max ) ,
snd_mixer_selem_value_get_mute ( scontrol , chn ) ? " mute " : " on " ,
snd_mixer_selem_value_get_capture ( scontrol , chn ) ? " capture " : " --- " ) ;
1999-07-22 20:10:19 +02:00
}
1999-07-21 00:00:59 +02:00
}
}
1999-05-02 18:21:40 +02:00
return 0 ;
}
2001-02-09 12:20:32 +01:00
static int selems ( int level )
1999-05-02 18:21:40 +02:00
{
2001-02-05 16:44:45 +01:00
int err ;
1999-06-02 02:40:31 +02:00
snd_mixer_t * handle ;
2001-02-09 12:20:32 +01:00
snd_mixer_selem_id_t * sid ;
snd_mixer_elem_t * elem ;
snd_mixer_selem_id_alloca ( & sid ) ;
1999-05-02 18:21:40 +02:00
2001-02-11 16:45:44 +01:00
if ( ( err = snd_mixer_open ( & handle ) ) < 0 ) {
2000-09-18 11:47:01 +02:00
error ( " Mixer %s open error: %s " , card , snd_strerror ( err ) ) ;
2000-08-11 21:29:55 +02:00
return err ;
1999-05-02 18:21:40 +02:00
}
2001-02-11 16:45:44 +01:00
if ( ( err = snd_mixer_attach ( handle , card ) ) < 0 ) {
error ( " Mixer attach %s error: %s " , card , snd_strerror ( err ) ) ;
snd_mixer_close ( handle ) ;
return err ;
}
if ( ( err = snd_mixer_selem_register ( handle , 0 ) ) < 0 ) {
error ( " Mixer register error: %s " , snd_strerror ( err ) ) ;
snd_mixer_close ( handle ) ;
return err ;
}
err = snd_mixer_load ( handle ) ;
2001-02-09 12:20:32 +01:00
if ( err < 0 ) {
2001-02-11 16:45:44 +01:00
error ( " Mixer load error: %s " , card , snd_strerror ( err ) ) ;
snd_mixer_close ( handle ) ;
2000-08-11 21:29:55 +02:00
return err ;
1999-05-02 18:21:40 +02:00
}
2001-02-09 12:20:32 +01:00
for ( elem = snd_mixer_first_elem ( handle ) ; elem ; elem = snd_mixer_elem_next ( elem ) ) {
snd_mixer_selem_get_id ( elem , sid ) ;
printf ( " Simple mixer control '%s',%i \n " , snd_mixer_selem_id_get_name ( sid ) , snd_mixer_selem_id_get_index ( sid ) ) ;
show_selem ( handle , sid , " " , level ) ;
1999-05-02 18:21:40 +02:00
}
snd_mixer_close ( handle ) ;
return 0 ;
}
2001-02-09 12:20:32 +01:00
static int parse_control_id ( const char * str , snd_ctl_elem_id_t * id )
1999-07-21 13:52:55 +02:00
{
2000-08-11 21:29:55 +02:00
int c , size ;
char * ptr ;
1999-07-21 13:52:55 +02:00
2000-08-11 21:29:55 +02:00
while ( * str = = ' ' | | * str = = ' \t ' )
str + + ;
if ( ! ( * str ) )
return - EINVAL ;
2001-02-09 12:20:32 +01:00
snd_ctl_elem_id_set_interface ( id , SND_CTL_ELEM_IFACE_MIXER ) ; /* default */
2000-08-11 21:29:55 +02:00
while ( * str ) {
if ( ! strncasecmp ( str , " numid= " , 6 ) ) {
2001-02-07 00:48:29 +01:00
str + = 6 ;
2001-02-09 12:20:32 +01:00
snd_ctl_elem_id_set_numid ( id , atoi ( str ) ) ;
2000-08-11 21:29:55 +02:00
while ( isdigit ( * str ) )
str + + ;
} else if ( ! strncasecmp ( str , " iface= " , 6 ) ) {
str + = 6 ;
if ( ! strncasecmp ( str , " card " , 4 ) ) {
2001-02-09 12:20:32 +01:00
snd_ctl_elem_id_set_interface ( id , SND_CTL_ELEM_IFACE_CARD ) ;
2000-08-11 21:29:55 +02:00
str + = 4 ;
} else if ( ! strncasecmp ( str , " mixer " , 5 ) ) {
2001-02-09 12:20:32 +01:00
snd_ctl_elem_id_set_interface ( id , SND_CTL_ELEM_IFACE_MIXER ) ;
2000-08-11 21:29:55 +02:00
str + = 5 ;
} else if ( ! strncasecmp ( str , " pcm " , 3 ) ) {
2001-02-09 12:20:32 +01:00
snd_ctl_elem_id_set_interface ( id , SND_CTL_ELEM_IFACE_PCM ) ;
2000-08-11 21:29:55 +02:00
str + = 3 ;
} else if ( ! strncasecmp ( str , " rawmidi " , 7 ) ) {
2001-02-09 12:20:32 +01:00
snd_ctl_elem_id_set_interface ( id , SND_CTL_ELEM_IFACE_RAWMIDI ) ;
2000-08-11 21:29:55 +02:00
str + = 7 ;
} else if ( ! strncasecmp ( str , " timer " , 5 ) ) {
2001-02-09 12:20:32 +01:00
snd_ctl_elem_id_set_interface ( id , SND_CTL_ELEM_IFACE_TIMER ) ;
2000-08-11 21:29:55 +02:00
str + = 5 ;
} else if ( ! strncasecmp ( str , " sequencer " , 9 ) ) {
2001-02-09 12:20:32 +01:00
snd_ctl_elem_id_set_interface ( id , SND_CTL_ELEM_IFACE_SEQUENCER ) ;
2000-08-11 21:29:55 +02:00
str + = 9 ;
} else {
return - EINVAL ;
}
} else if ( ! strncasecmp ( str , " name= " , 5 ) ) {
2001-02-07 00:48:29 +01:00
char buf [ 64 ] ;
2000-08-11 21:29:55 +02:00
str + = 5 ;
2001-02-07 00:48:29 +01:00
ptr = buf ;
2000-08-11 21:29:55 +02:00
size = 0 ;
if ( * str = = ' \' ' | | * str = = ' \" ' ) {
c = * str + + ;
while ( * str & & * str ! = c ) {
2001-02-07 00:48:29 +01:00
if ( size < sizeof ( buf ) ) {
2000-08-11 21:29:55 +02:00
* ptr + + = * str ;
size + + ;
}
str + + ;
}
if ( * str = = c )
str + + ;
} else {
while ( * str & & * str ! = ' , ' ) {
2001-02-07 00:48:29 +01:00
if ( size < sizeof ( buf ) ) {
2000-08-11 21:29:55 +02:00
* ptr + + = * str ;
size + + ;
}
str + + ;
}
* ptr = ' \0 ' ;
}
2001-02-09 12:20:32 +01:00
snd_ctl_elem_id_set_name ( id , buf ) ;
2000-08-11 21:29:55 +02:00
} else if ( ! strncasecmp ( str , " index= " , 6 ) ) {
2001-02-07 00:48:29 +01:00
str + = 6 ;
2001-02-09 12:20:32 +01:00
snd_ctl_elem_id_set_index ( id , atoi ( str ) ) ;
2000-08-11 21:29:55 +02:00
while ( isdigit ( * str ) )
str + + ;
} else if ( ! strncasecmp ( str , " device= " , 7 ) ) {
2001-02-07 00:48:29 +01:00
str + = 7 ;
2001-02-09 12:20:32 +01:00
snd_ctl_elem_id_set_device ( id , atoi ( str ) ) ;
2000-08-11 21:29:55 +02:00
while ( isdigit ( * str ) )
str + + ;
} else if ( ! strncasecmp ( str , " subdevice= " , 10 ) ) {
2001-02-07 00:48:29 +01:00
str + = 10 ;
2001-02-09 12:20:32 +01:00
snd_ctl_elem_id_set_subdevice ( id , atoi ( str ) ) ;
2000-08-11 21:29:55 +02:00
while ( isdigit ( * str ) )
str + + ;
}
if ( * str = = ' , ' ) {
str + + ;
} else {
if ( * str )
return - EINVAL ;
}
}
2000-07-15 12:21:59 +02:00
return 0 ;
1999-07-21 13:52:55 +02:00
}
2001-02-09 12:20:32 +01:00
static int parse_simple_id ( const char * str , snd_mixer_selem_id_t * sid )
1999-07-21 13:52:55 +02:00
{
int c , size ;
2001-02-09 12:20:32 +01:00
char buf [ 128 ] ;
char * ptr = buf ;
1999-07-21 13:52:55 +02:00
while ( * str = = ' ' | | * str = = ' \t ' )
str + + ;
if ( ! ( * str ) )
2000-08-11 21:29:55 +02:00
return - EINVAL ;
1999-07-21 13:52:55 +02:00
size = 0 ;
if ( * str ! = ' " ' & & * str ! = ' \' ' ) {
while ( * str & & * str ! = ' , ' ) {
2001-02-09 12:20:32 +01:00
if ( size < sizeof ( buf ) ) {
1999-07-21 13:52:55 +02:00
* ptr + + = * str ;
size + + ;
}
str + + ;
}
} else {
c = * str + + ;
while ( * str & & * str ! = c ) {
2001-02-09 12:20:32 +01:00
if ( size < sizeof ( buf ) ) {
1999-07-21 13:52:55 +02:00
* ptr + + = * str ;
size + + ;
}
str + + ;
}
if ( * str = = c )
str + + ;
}
if ( * str = = ' \0 ' )
return 0 ;
if ( * str ! = ' , ' )
2000-08-11 21:29:55 +02:00
return - EINVAL ;
2001-02-12 14:33:25 +01:00
* ptr = 0 ; /* terminate the string */
1999-07-21 13:52:55 +02:00
str + + ;
if ( ! isdigit ( * str ) )
2000-08-11 21:29:55 +02:00
return - EINVAL ;
2001-02-09 12:20:32 +01:00
snd_mixer_selem_id_set_index ( sid , atoi ( str ) ) ;
snd_mixer_selem_id_set_name ( sid , buf ) ;
1999-05-02 18:21:40 +02:00
return 0 ;
}
2000-08-12 17:34:17 +02:00
static int cset ( int argc , char * argv [ ] , int roflag )
1999-05-02 18:21:40 +02:00
{
int err ;
2000-08-11 21:29:55 +02:00
snd_ctl_t * handle ;
2001-02-09 12:20:32 +01:00
snd_ctl_elem_info_t * info ;
snd_ctl_elem_id_t * id ;
2001-02-11 16:45:44 +01:00
snd_ctl_elem_value_t * control ;
2000-08-11 21:29:55 +02:00
char * ptr ;
2001-02-07 00:48:29 +01:00
unsigned int idx , count ;
2000-08-11 21:29:55 +02:00
long tmp ;
2001-02-09 12:20:32 +01:00
snd_ctl_elem_type_t type ;
snd_ctl_elem_info_alloca ( & info ) ;
snd_ctl_elem_id_alloca ( & id ) ;
2001-02-11 16:45:44 +01:00
snd_ctl_elem_value_alloca ( & control ) ;
1999-05-02 18:21:40 +02:00
if ( argc < 1 ) {
2000-08-11 21:29:55 +02:00
fprintf ( stderr , " Specify a full control identifier: [[iface=<iface>,][name='name',][index=<index>,][device=<device>,][subdevice=<subdevice>]]|[numid=<numid>] \n " ) ;
return - EINVAL ;
1999-05-02 18:21:40 +02:00
}
2001-02-07 00:48:29 +01:00
if ( parse_control_id ( argv [ 0 ] , id ) ) {
2000-08-11 21:29:55 +02:00
fprintf ( stderr , " Wrong control identifier: %s \n " , argv [ 0 ] ) ;
return - EINVAL ;
1999-05-02 18:21:40 +02:00
}
2000-08-11 21:29:55 +02:00
if ( debugflag ) {
printf ( " VERIFY ID: " ) ;
2001-02-07 00:48:29 +01:00
show_control_id ( id ) ;
2000-08-11 21:29:55 +02:00
printf ( " \n " ) ;
1999-05-02 18:21:40 +02:00
}
2000-08-11 21:29:55 +02:00
if ( ( err = snd_ctl_open ( & handle , card ) ) < 0 ) {
2000-09-18 11:47:01 +02:00
error ( " Control %s open error: %s \n " , card , snd_strerror ( err ) ) ;
2000-08-11 21:29:55 +02:00
return err ;
}
2001-02-09 12:20:32 +01:00
snd_ctl_elem_info_set_id ( info , id ) ;
if ( ( err = snd_ctl_elem_info ( handle , info ) ) < 0 ) {
2000-09-18 11:47:01 +02:00
error ( " Control %s cinfo error: %s \n " , card , snd_strerror ( err ) ) ;
2000-08-11 21:29:55 +02:00
return err ;
}
2001-02-09 12:20:32 +01:00
type = snd_ctl_elem_info_get_type ( info ) ;
count = snd_ctl_elem_info_get_count ( info ) ;
2001-02-11 16:45:44 +01:00
snd_ctl_elem_value_set_id ( control , id ) ;
2001-02-07 00:48:29 +01:00
2000-08-11 21:29:55 +02:00
if ( ! roflag ) {
ptr = argv [ 1 ] ;
2001-02-07 00:48:29 +01:00
for ( idx = 0 ; idx < count & & idx < 128 & & * ptr ; idx + + ) {
switch ( snd_enum_to_int ( type ) ) {
2001-02-09 12:20:32 +01:00
case SND_CTL_ELEM_TYPE_BOOLEAN :
2000-08-11 21:29:55 +02:00
tmp = 0 ;
if ( ! strncasecmp ( ptr , " on " , 2 ) | | ! strncasecmp ( ptr , " up " , 2 ) ) {
tmp = 1 ;
ptr + = 2 ;
} else if ( ! strncasecmp ( ptr , " yes " , 3 ) ) {
tmp = 1 ;
ptr + = 3 ;
} else if ( atoi ( ptr ) ) {
tmp = 1 ;
while ( isdigit ( * ptr ) )
ptr + + ;
}
2001-02-11 16:45:44 +01:00
snd_ctl_elem_value_set_boolean ( control , idx , tmp ) ;
2000-08-11 21:29:55 +02:00
break ;
2001-02-09 12:20:32 +01:00
case SND_CTL_ELEM_TYPE_INTEGER :
2000-08-11 21:29:55 +02:00
tmp = get_integer ( & ptr ,
2001-02-09 12:20:32 +01:00
snd_ctl_elem_info_get_min ( info ) ,
snd_ctl_elem_info_get_max ( info ) ) ;
2001-02-11 16:45:44 +01:00
snd_ctl_elem_value_set_integer ( control , idx , tmp ) ;
2000-08-11 21:29:55 +02:00
break ;
2001-02-09 12:20:32 +01:00
case SND_CTL_ELEM_TYPE_ENUMERATED :
tmp = get_integer ( & ptr , 0 , snd_ctl_elem_info_get_items ( info ) - 1 ) ;
2001-02-11 16:45:44 +01:00
snd_ctl_elem_value_set_enumerated ( control , idx , tmp ) ;
2000-08-11 21:29:55 +02:00
break ;
2001-02-09 12:20:32 +01:00
case SND_CTL_ELEM_TYPE_BYTES :
2001-02-07 00:48:29 +01:00
tmp = get_integer ( & ptr , 0 , 255 ) ;
2001-02-11 16:45:44 +01:00
snd_ctl_elem_value_set_byte ( control , idx , tmp ) ;
2000-08-11 21:29:55 +02:00
break ;
default :
break ;
}
if ( ! strchr ( argv [ 1 ] , ' , ' ) )
ptr = argv [ 1 ] ;
else if ( * ptr = = ' , ' )
ptr + + ;
1999-05-02 18:21:40 +02:00
}
2001-02-09 12:20:32 +01:00
if ( ( err = snd_ctl_elem_write ( handle , control ) ) < 0 ) {
error ( " Control %s element write error: %s \n " , card , snd_strerror ( err ) ) ;
2000-08-11 21:29:55 +02:00
return err ;
1999-05-02 18:21:40 +02:00
}
}
2000-08-11 21:29:55 +02:00
snd_ctl_close ( handle ) ;
2001-02-11 16:45:44 +01:00
#if 0
/* FIXME */
2001-02-09 16:38:59 +01:00
if ( ! quiet ) {
snd_hctl_t * hctl ;
2001-02-11 16:45:44 +01:00
snd_hctl_t * elem ;
2001-02-09 16:38:59 +01:00
if ( ( err = snd_hctl_open ( & hctl , card ) ) < 0 ) {
error ( " Control %s open error: %s \n " , card , snd_strerror ( err ) ) ;
return err ;
}
2001-02-11 16:45:44 +01:00
if ( ( err = snd_hctl_load ( & hctl ) ) < 0 ) {
error ( " Control %s load error: %s \n " , card , snd_strerror ( err ) ) ;
return err ;
}
elem = snd_hctl_find_elem ( hctl , id ) ;
assert ( elem ) ;
show_control ( " " , elem , 3 ) ;
2001-02-09 16:38:59 +01:00
snd_hctl_close ( hctl ) ;
}
2001-02-11 16:45:44 +01:00
# endif
1999-05-02 18:21:40 +02:00
return 0 ;
}
2000-03-18 19:00:37 +01:00
typedef struct channel_mask {
char * name ;
unsigned int mask ;
} channel_mask_t ;
static channel_mask_t chanmask [ ] = {
2001-02-11 16:45:44 +01:00
{ " frontleft " , 1 < < SND_MIXER_SCHN_FRONT_LEFT } ,
{ " frontright " , 1 < < SND_MIXER_SCHN_FRONT_RIGHT } ,
{ " frontcenter " , 1 < < SND_MIXER_SCHN_FRONT_CENTER } ,
{ " front " , ( ( 1 < < SND_MIXER_SCHN_FRONT_LEFT ) |
( 1 < < SND_MIXER_SCHN_FRONT_RIGHT ) ) } ,
{ " center " , 1 < < SND_MIXER_SCHN_FRONT_CENTER } ,
{ " rearleft " , 1 < < SND_MIXER_SCHN_REAR_LEFT } ,
{ " rearright " , 1 < < SND_MIXER_SCHN_REAR_RIGHT } ,
{ " rear " , ( ( 1 < < SND_MIXER_SCHN_REAR_LEFT ) |
( 1 < < SND_MIXER_SCHN_REAR_RIGHT ) ) } ,
{ " woofer " , 1 < < SND_MIXER_SCHN_WOOFER } ,
2001-02-05 16:44:45 +01:00
{ NULL , 0 }
2000-03-18 19:00:37 +01:00
} ;
2001-02-09 12:20:32 +01:00
static unsigned int channels_mask ( char * arg )
2000-03-18 19:00:37 +01:00
{
channel_mask_t * c ;
for ( c = chanmask ; c - > name ; c + + ) {
2001-02-09 12:20:32 +01:00
if ( strncmp ( arg , c - > name , strlen ( c - > name ) ) = = 0 )
return c - > mask ;
2000-03-18 19:00:37 +01:00
}
2001-02-09 12:20:32 +01:00
return ~ 0U ;
2000-03-18 19:00:37 +01:00
}
2001-02-05 16:44:45 +01:00
static int sset ( unsigned int argc , char * argv [ ] , int roflag )
1999-07-21 13:52:55 +02:00
{
2001-02-05 16:44:45 +01:00
int err ;
unsigned int idx ;
2001-02-11 16:45:44 +01:00
snd_mixer_selem_channel_id_t chn ;
2000-03-18 19:00:37 +01:00
unsigned int channels ;
2001-02-09 12:20:32 +01:00
long min , max ;
1999-07-21 13:52:55 +02:00
snd_mixer_t * handle ;
2001-02-09 12:20:32 +01:00
snd_mixer_elem_t * elem ;
snd_mixer_selem_id_t * sid ;
2001-02-11 16:45:44 +01:00
snd_mixer_selem_value_t * control ;
snd_mixer_selem_info_t * info ;
2001-02-09 12:20:32 +01:00
snd_mixer_selem_id_alloca ( & sid ) ;
2001-02-11 16:45:44 +01:00
snd_mixer_selem_value_alloca ( & control ) ;
snd_mixer_selem_info_alloca ( & info ) ;
1999-07-21 13:52:55 +02:00
if ( argc < 1 ) {
2000-07-15 12:21:59 +02:00
fprintf ( stderr , " Specify a scontrol identifier: 'name',index \n " ) ;
1999-07-21 13:52:55 +02:00
return 1 ;
}
2001-02-09 12:20:32 +01:00
if ( parse_simple_id ( argv [ 0 ] , sid ) ) {
2000-07-15 12:21:59 +02:00
fprintf ( stderr , " Wrong scontrol identifier: %s \n " , argv [ 0 ] ) ;
1999-07-21 13:52:55 +02:00
return 1 ;
}
2000-08-11 21:29:55 +02:00
if ( ! roflag & & argc < 2 ) {
1999-07-21 13:52:55 +02:00
fprintf ( stderr , " Specify what you want to set... \n " ) ;
return 1 ;
}
2001-02-11 16:45:44 +01:00
if ( ( err = snd_mixer_open ( & handle ) ) < 0 ) {
2000-09-18 11:47:01 +02:00
error ( " Mixer %s open error: %s \n " , card , snd_strerror ( err ) ) ;
2000-08-11 21:29:55 +02:00
return err ;
1999-07-21 13:52:55 +02:00
}
2001-02-11 16:45:44 +01:00
if ( ( err = snd_mixer_attach ( handle , card ) ) < 0 ) {
error ( " Mixer attach %s error: %s " , card , snd_strerror ( err ) ) ;
snd_mixer_close ( handle ) ;
return err ;
}
if ( ( err = snd_mixer_selem_register ( handle , 0 ) ) < 0 ) {
error ( " Mixer register error: %s " , snd_strerror ( err ) ) ;
snd_mixer_close ( handle ) ;
return err ;
}
err = snd_mixer_load ( handle ) ;
if ( err < 0 ) {
error ( " Mixer load error: %s " , card , snd_strerror ( err ) ) ;
snd_mixer_close ( handle ) ;
return err ;
}
2001-02-09 12:20:32 +01:00
elem = snd_mixer_find_selem ( handle , sid ) ;
if ( ! elem ) {
error ( " Unable to find simple control '%s',%i: %s \n " , snd_mixer_selem_id_get_name ( sid ) , snd_mixer_selem_id_get_index ( sid ) , snd_strerror ( err ) ) ;
snd_mixer_close ( handle ) ;
return - ENOENT ;
}
2001-02-11 16:45:44 +01:00
if ( ( err = snd_mixer_selem_info ( elem , info ) ) < 0 ) {
error ( " Unable to get simple info '%s',%i: %s \n " , snd_mixer_selem_id_get_name ( sid ) , snd_mixer_selem_id_get_index ( sid ) , snd_strerror ( err ) ) ;
snd_mixer_close ( handle ) ;
return err ;
}
2001-02-09 12:20:32 +01:00
if ( ( err = snd_mixer_selem_read ( elem , control ) ) < 0 ) {
error ( " Unable to read simple control '%s',%i: %s \n " , snd_mixer_selem_id_get_name ( sid ) , snd_mixer_selem_id_get_index ( sid ) , snd_strerror ( err ) ) ;
1999-07-21 13:52:55 +02:00
snd_mixer_close ( handle ) ;
2000-08-11 21:29:55 +02:00
return err ;
1999-07-21 13:52:55 +02:00
}
2001-02-11 16:45:44 +01:00
min = snd_mixer_selem_info_get_min ( info ) ;
2001-02-12 14:33:25 +01:00
max = snd_mixer_selem_info_get_max ( info ) ;
2000-08-11 21:29:55 +02:00
if ( roflag )
goto __skip_write ;
1999-07-21 13:52:55 +02:00
for ( idx = 1 ; idx < argc ; idx + + ) {
1999-07-22 20:10:19 +02:00
if ( ! strncmp ( argv [ idx ] , " mute " , 4 ) | |
! strncmp ( argv [ idx ] , " off " , 3 ) ) {
2001-02-11 16:45:44 +01:00
snd_mixer_selem_value_set_mute_all ( control , 1 ) ;
2000-03-18 19:00:37 +01:00
continue ;
1999-07-22 20:10:19 +02:00
} else if ( ! strncmp ( argv [ idx ] , " unmute " , 6 ) | |
! strncmp ( argv [ idx ] , " on " , 2 ) ) {
2001-02-11 16:45:44 +01:00
snd_mixer_selem_value_set_mute_all ( control , 0 ) ;
2000-03-18 19:00:37 +01:00
continue ;
1999-12-09 17:28:24 +01:00
} else if ( ! strncmp ( argv [ idx ] , " cap " , 3 ) | |
1999-07-23 00:23:42 +02:00
! strncmp ( argv [ idx ] , " rec " , 3 ) ) {
2001-02-11 16:45:44 +01:00
snd_mixer_selem_value_set_capture_all ( control , 1 ) ;
2000-03-18 19:00:37 +01:00
continue ;
1999-12-09 17:28:24 +01:00
} else if ( ! strncmp ( argv [ idx ] , " nocap " , 5 ) | |
1999-07-23 00:23:42 +02:00
! strncmp ( argv [ idx ] , " norec " , 5 ) ) {
2001-02-11 16:45:44 +01:00
snd_mixer_selem_value_set_capture_all ( control , 0 ) ;
2000-03-18 19:00:37 +01:00
continue ;
}
2001-02-09 12:20:32 +01:00
channels = channels_mask ( argv [ idx ] ) ;
2000-03-18 19:00:37 +01:00
if ( isdigit ( argv [ idx ] [ 0 ] ) | |
argv [ idx ] [ 0 ] = = ' + ' | |
argv [ idx ] [ 0 ] = = ' - ' ) {
1999-07-21 13:52:55 +02:00
char * ptr ;
2000-03-18 19:00:37 +01:00
int multi ;
1999-07-21 13:52:55 +02:00
2000-03-18 19:00:37 +01:00
multi = ( strchr ( argv [ idx ] , ' , ' ) ! = NULL ) ;
1999-07-21 13:52:55 +02:00
ptr = argv [ idx ] ;
2001-02-11 16:45:44 +01:00
for ( chn = 0 ; chn < = SND_MIXER_SCHN_LAST ; snd_enum_incr ( chn ) ) {
2001-02-09 12:20:32 +01:00
if ( ! ( channels & ( 1 < < chn ) ) | |
2001-02-11 16:45:44 +01:00
! snd_mixer_selem_info_has_channel ( info , chn ) )
1999-07-22 20:10:19 +02:00
continue ;
2000-03-18 19:00:37 +01:00
if ( ! multi )
ptr = argv [ idx ] ;
2001-02-11 16:45:44 +01:00
snd_mixer_selem_value_set_volume ( control , chn , get_volume_simple ( & ptr , min , max , snd_mixer_selem_value_get_volume ( control , chn ) ) ) ;
1999-07-22 20:10:19 +02:00
}
1999-07-21 13:52:55 +02:00
} else {
error ( " Unknown setup '%s'.. \n " , argv [ idx ] ) ;
snd_mixer_close ( handle ) ;
2000-08-11 21:29:55 +02:00
return err ;
1999-07-21 13:52:55 +02:00
}
}
2001-02-09 12:20:32 +01:00
if ( ( err = snd_mixer_selem_write ( elem , control ) ) < 0 ) {
error ( " Unable to write control '%s',%i: %s \n " , snd_mixer_selem_id_get_name ( sid ) , snd_mixer_selem_id_get_index ( sid ) , snd_strerror ( err ) ) ;
1999-07-21 13:52:55 +02:00
snd_mixer_close ( handle ) ;
2000-08-11 21:29:55 +02:00
return err ;
1999-07-21 13:52:55 +02:00
}
2000-08-11 21:29:55 +02:00
__skip_write :
1999-07-21 13:52:55 +02:00
if ( ! quiet ) {
2001-02-09 12:20:32 +01:00
printf ( " Simple mixer control '%s',%i \n " , snd_mixer_selem_id_get_name ( sid ) , snd_mixer_selem_id_get_index ( sid ) ) ;
show_selem ( handle , sid , " " , 1 ) ;
1999-07-21 13:52:55 +02:00
}
snd_mixer_close ( handle ) ;
return 0 ;
}
2001-02-11 16:45:44 +01:00
static void events_info ( snd_hctl_elem_t * helem )
2000-08-12 17:34:17 +02:00
{
2001-02-09 12:20:32 +01:00
snd_ctl_elem_id_t * id ;
snd_ctl_elem_id_alloca ( & id ) ;
snd_hctl_elem_get_id ( helem , id ) ;
2001-02-11 16:45:44 +01:00
printf ( " event info: " ) ;
2001-02-07 00:48:29 +01:00
show_control_id ( id ) ;
2000-08-12 17:34:17 +02:00
printf ( " \n " ) ;
}
2001-02-09 12:20:32 +01:00
static void events_value ( snd_hctl_elem_t * helem )
2000-08-12 17:34:17 +02:00
{
2001-02-09 12:20:32 +01:00
snd_ctl_elem_id_t * id ;
snd_ctl_elem_id_alloca ( & id ) ;
snd_hctl_elem_get_id ( helem , id ) ;
2000-08-12 17:34:17 +02:00
printf ( " event value: " ) ;
2001-02-07 00:48:29 +01:00
show_control_id ( id ) ;
2000-08-12 17:34:17 +02:00
printf ( " \n " ) ;
}
2001-02-09 12:20:32 +01:00
static void events_remove ( snd_hctl_elem_t * helem )
2000-08-12 17:34:17 +02:00
{
2001-02-09 12:20:32 +01:00
snd_ctl_elem_id_t * id ;
snd_ctl_elem_id_alloca ( & id ) ;
snd_hctl_elem_get_id ( helem , id ) ;
2000-08-12 17:34:17 +02:00
printf ( " event remove: " ) ;
2001-02-07 00:48:29 +01:00
show_control_id ( id ) ;
2000-08-12 17:34:17 +02:00
printf ( " \n " ) ;
}
2001-02-13 22:29:38 +01:00
int element_callback ( snd_hctl_elem_t * elem , unsigned int mask )
2000-08-12 17:34:17 +02:00
{
2001-02-13 22:29:38 +01:00
if ( mask = = SND_CTL_EVENT_MASK_REMOVE ) {
2001-02-09 12:20:32 +01:00
events_remove ( elem ) ;
2001-02-13 22:29:38 +01:00
return 0 ;
2001-02-09 12:20:32 +01:00
}
2001-02-13 22:29:38 +01:00
if ( mask & SND_CTL_EVENT_MASK_INFO )
events_info ( elem ) ;
if ( mask & SND_CTL_EVENT_MASK_VALUE )
events_value ( elem ) ;
2001-02-09 12:20:32 +01:00
return 0 ;
}
static void events_add ( snd_hctl_elem_t * helem )
{
snd_ctl_elem_id_t * id ;
snd_ctl_elem_id_alloca ( & id ) ;
snd_hctl_elem_get_id ( helem , id ) ;
2000-08-12 17:34:17 +02:00
printf ( " event add: " ) ;
2001-02-07 00:48:29 +01:00
show_control_id ( id ) ;
2000-08-12 17:34:17 +02:00
printf ( " \n " ) ;
2001-02-09 12:20:32 +01:00
snd_hctl_elem_set_callback ( helem , element_callback ) ;
}
2001-02-13 22:29:38 +01:00
int ctl_callback ( snd_hctl_t * ctl , unsigned int mask ,
2001-02-09 12:20:32 +01:00
snd_hctl_elem_t * elem )
{
2001-02-13 22:29:38 +01:00
if ( mask & SND_CTL_EVENT_MASK_ADD )
2001-02-09 12:20:32 +01:00
events_add ( elem ) ;
return 0 ;
2000-08-12 17:34:17 +02:00
}
2001-02-05 16:44:45 +01:00
static int events ( int argc ATTRIBUTE_UNUSED , char * argv [ ] ATTRIBUTE_UNUSED )
2000-08-12 17:34:17 +02:00
{
2001-02-09 16:38:59 +01:00
snd_hctl_t * handle ;
2001-02-09 12:20:32 +01:00
snd_hctl_elem_t * helem ;
2000-08-12 17:34:17 +02:00
int err ;
2001-02-09 16:38:59 +01:00
if ( ( err = snd_hctl_open ( & handle , card ) ) < 0 ) {
2000-09-18 11:47:01 +02:00
error ( " Control %s open error: %s \n " , card , snd_strerror ( err ) ) ;
2000-08-12 17:34:17 +02:00
return err ;
}
2001-02-09 12:20:32 +01:00
snd_hctl_set_callback ( handle , ctl_callback ) ;
2001-02-11 16:45:44 +01:00
if ( ( err = snd_hctl_load ( handle ) ) < 0 ) {
error ( " Control %s hbuild error: %s \n " , card , snd_strerror ( err ) ) ;
return err ;
}
2001-02-09 12:20:32 +01:00
for ( helem = snd_hctl_first_elem ( handle ) ; helem ; helem = snd_hctl_elem_next ( helem ) ) {
snd_hctl_elem_set_callback ( helem , element_callback ) ;
2000-08-12 17:34:17 +02:00
}
printf ( " Ready to listen... \n " ) ;
while ( 1 ) {
2001-02-13 00:51:53 +01:00
int res = snd_hctl_wait ( handle , - 1 ) ;
if ( res > = 0 ) {
2000-08-16 15:36:24 +02:00
printf ( " Poll ok: %i \n " , res ) ;
2001-02-11 16:45:44 +01:00
res = snd_hctl_handle_events ( handle ) ;
assert ( res > 0 ) ;
2000-08-12 17:34:17 +02:00
}
}
2001-02-09 16:38:59 +01:00
snd_hctl_close ( handle ) ;
2000-08-12 17:34:17 +02:00
}
2001-02-09 12:20:32 +01:00
static void sevents_value ( snd_mixer_selem_id_t * sid )
2000-08-16 15:36:24 +02:00
{
2001-02-09 12:20:32 +01:00
printf ( " event value: '%s',%i \n " , snd_mixer_selem_id_get_name ( sid ) , snd_mixer_selem_id_get_index ( sid ) ) ;
2000-08-16 15:36:24 +02:00
}
2001-02-11 16:45:44 +01:00
static void sevents_info ( snd_mixer_selem_id_t * sid )
2000-08-16 15:36:24 +02:00
{
2001-02-11 16:45:44 +01:00
printf ( " event info: '%s',%i \n " , snd_mixer_selem_id_get_name ( sid ) , snd_mixer_selem_id_get_index ( sid ) ) ;
2000-08-16 15:36:24 +02:00
}
2001-02-09 12:20:32 +01:00
static void sevents_remove ( snd_mixer_selem_id_t * sid )
2000-08-16 15:36:24 +02:00
{
2001-02-09 12:20:32 +01:00
printf ( " event remove: '%s',%i \n " , snd_mixer_selem_id_get_name ( sid ) , snd_mixer_selem_id_get_index ( sid ) ) ;
2000-08-16 15:36:24 +02:00
}
2001-02-13 22:29:38 +01:00
int melem_event ( snd_mixer_elem_t * elem , unsigned int mask )
2000-08-16 15:36:24 +02:00
{
2001-02-09 12:20:32 +01:00
snd_mixer_selem_id_t * sid ;
snd_mixer_selem_id_alloca ( & sid ) ;
snd_mixer_selem_get_id ( elem , sid ) ;
2001-02-13 22:29:38 +01:00
if ( mask = = SND_CTL_EVENT_MASK_REMOVE ) {
2001-02-09 12:20:32 +01:00
sevents_remove ( sid ) ;
2001-02-13 22:29:38 +01:00
return 0 ;
2001-02-09 12:20:32 +01:00
}
2001-02-13 22:29:38 +01:00
if ( mask & SND_CTL_EVENT_MASK_INFO )
sevents_info ( sid ) ;
if ( mask & SND_CTL_EVENT_MASK_VALUE )
sevents_value ( sid ) ;
2001-02-09 12:20:32 +01:00
return 0 ;
}
2000-08-16 15:36:24 +02:00
2001-02-09 12:20:32 +01:00
static void sevents_add ( snd_mixer_elem_t * elem )
2000-08-16 15:36:24 +02:00
{
2001-02-09 12:20:32 +01:00
snd_mixer_selem_id_t * sid ;
snd_mixer_selem_id_alloca ( & sid ) ;
snd_mixer_selem_get_id ( elem , sid ) ;
printf ( " event add: '%s',%i \n " , snd_mixer_selem_id_get_name ( sid ) , snd_mixer_selem_id_get_index ( sid ) ) ;
2001-02-11 16:45:44 +01:00
snd_mixer_elem_set_callback ( elem , melem_event ) ;
2001-02-09 12:20:32 +01:00
}
2000-08-16 15:36:24 +02:00
2001-02-13 22:29:38 +01:00
int mixer_event ( snd_mixer_t * mixer , unsigned int mask ,
2001-02-09 12:20:32 +01:00
snd_mixer_elem_t * elem )
{
2001-02-13 22:29:38 +01:00
if ( mask & SND_CTL_EVENT_MASK_ADD )
2001-02-09 12:20:32 +01:00
sevents_add ( elem ) ;
return 0 ;
2000-08-16 15:36:24 +02:00
}
2001-02-05 16:44:45 +01:00
static int sevents ( int argc ATTRIBUTE_UNUSED , char * argv [ ] ATTRIBUTE_UNUSED )
2000-08-16 15:36:24 +02:00
{
snd_mixer_t * handle ;
int err ;
2001-02-11 16:45:44 +01:00
if ( ( err = snd_mixer_open ( & handle ) ) < 0 ) {
error ( " Mixer %s open error: %s " , card , snd_strerror ( err ) ) ;
return err ;
}
if ( ( err = snd_mixer_attach ( handle , card ) ) < 0 ) {
error ( " Mixer attach %s error: %s " , card , snd_strerror ( err ) ) ;
snd_mixer_close ( handle ) ;
return err ;
}
if ( ( err = snd_mixer_selem_register ( handle , 0 ) ) < 0 ) {
error ( " Mixer register error: %s " , snd_strerror ( err ) ) ;
snd_mixer_close ( handle ) ;
2000-08-16 15:36:24 +02:00
return err ;
}
2001-02-09 12:20:32 +01:00
snd_mixer_set_callback ( handle , mixer_event ) ;
2001-02-11 16:45:44 +01:00
err = snd_mixer_load ( handle ) ;
2001-02-09 12:20:32 +01:00
if ( err < 0 ) {
2001-02-11 16:45:44 +01:00
error ( " Mixer load error: %s " , card , snd_strerror ( err ) ) ;
2001-02-09 12:20:32 +01:00
snd_mixer_close ( handle ) ;
return err ;
}
2000-08-16 15:36:24 +02:00
printf ( " Ready to listen... \n " ) ;
while ( 1 ) {
int res ;
2001-02-13 00:51:53 +01:00
res = snd_mixer_wait ( handle , - 1 ) ;
if ( res > = 0 ) {
2000-08-16 15:36:24 +02:00
printf ( " Poll ok: %i \n " , res ) ;
2001-02-11 16:45:44 +01:00
res = snd_mixer_handle_events ( handle ) ;
assert ( res > = 0 ) ;
2000-08-16 15:36:24 +02:00
}
}
snd_mixer_close ( handle ) ;
}
1999-05-02 18:21:40 +02:00
int main ( int argc , char * argv [ ] )
{
int morehelp ;
struct option long_option [ ] =
{
{ " help " , 0 , NULL , HELPID_HELP } ,
{ " card " , 1 , NULL , HELPID_CARD } ,
{ " quiet " , 0 , NULL , HELPID_QUIET } ,
{ " debug " , 0 , NULL , HELPID_DEBUG } ,
{ " version " , 0 , NULL , HELPID_VERSION } ,
{ NULL , 0 , NULL , 0 } ,
} ;
morehelp = 0 ;
while ( 1 ) {
int c ;
2000-07-15 12:21:59 +02:00
if ( ( c = getopt_long ( argc , argv , " hc:qDv " , long_option , NULL ) ) < 0 )
1999-05-02 18:21:40 +02:00
break ;
switch ( c ) {
case ' h ' :
case HELPID_HELP :
morehelp + + ;
break ;
case ' c ' :
case HELPID_CARD :
2000-09-11 17:49:33 +02:00
card = optarg ;
1999-05-02 18:21:40 +02:00
break ;
case ' q ' :
case HELPID_QUIET :
quiet = 1 ;
break ;
case ' D ' :
case HELPID_DEBUG :
debugflag = 1 ;
break ;
case ' v ' :
case HELPID_VERSION :
printf ( " amixer version " SND_UTIL_VERSION_STR " \n " ) ;
return 1 ;
default :
fprintf ( stderr , " \07 Invalid switch or option needs an argument. \n " ) ;
morehelp + + ;
}
}
if ( morehelp ) {
help ( ) ;
return 1 ;
}
if ( argc - optind < = 0 ) {
2001-02-09 12:20:32 +01:00
return selems ( 1 ) ? 1 : 0 ;
1999-05-02 18:21:40 +02:00
}
2000-08-11 21:29:55 +02:00
if ( ! strcmp ( argv [ optind ] , " help " ) ) {
return help ( ) ? 1 : 0 ;
} else if ( ! strcmp ( argv [ optind ] , " info " ) ) {
1999-05-02 18:21:40 +02:00
return info ( ) ? 1 : 0 ;
2000-07-15 12:21:59 +02:00
} else if ( ! strcmp ( argv [ optind ] , " controls " ) ) {
2000-08-11 21:29:55 +02:00
return controls ( 0 ) ? 1 : 0 ;
1999-05-02 18:21:40 +02:00
} else if ( ! strcmp ( argv [ optind ] , " contents " ) ) {
2000-08-11 21:29:55 +02:00
return controls ( 1 ) ? 1 : 0 ;
} else if ( ! strcmp ( argv [ optind ] , " scontrols " ) | | ! strcmp ( argv [ optind ] , " simple " ) ) {
2001-02-09 12:20:32 +01:00
return selems ( 0 ) ? 1 : 0 ;
2000-07-15 12:21:59 +02:00
} else if ( ! strcmp ( argv [ optind ] , " scontents " ) ) {
2001-02-09 12:20:32 +01:00
return selems ( 1 ) ? 1 : 0 ;
2000-08-11 21:29:55 +02:00
} else if ( ! strcmp ( argv [ optind ] , " sset " ) | | ! strcmp ( argv [ optind ] , " set " ) ) {
return sset ( argc - optind - 1 , argc - optind > 1 ? argv + optind + 1 : NULL , 0 ) ? 1 : 0 ;
} else if ( ! strcmp ( argv [ optind ] , " sget " ) | | ! strcmp ( argv [ optind ] , " get " ) ) {
return sset ( argc - optind - 1 , argc - optind > 1 ? argv + optind + 1 : NULL , 1 ) ? 1 : 0 ;
2000-07-15 12:21:59 +02:00
} else if ( ! strcmp ( argv [ optind ] , " cset " ) ) {
2000-08-11 21:29:55 +02:00
return cset ( argc - optind - 1 , argc - optind > 1 ? argv + optind + 1 : NULL , 0 ) ? 1 : 0 ;
2000-07-15 12:21:59 +02:00
} else if ( ! strcmp ( argv [ optind ] , " cget " ) ) {
2000-08-11 21:29:55 +02:00
return cset ( argc - optind - 1 , argc - optind > 1 ? argv + optind + 1 : NULL , 1 ) ? 1 : 0 ;
2000-08-12 17:34:17 +02:00
} else if ( ! strcmp ( argv [ optind ] , " events " ) ) {
return events ( argc - optind - 1 , argc - optind > 1 ? argv + optind + 1 : NULL ) ;
2000-08-16 15:36:24 +02:00
} else if ( ! strcmp ( argv [ optind ] , " sevents " ) ) {
return sevents ( argc - optind - 1 , argc - optind > 1 ? argv + optind + 1 : NULL ) ;
1999-05-02 18:21:40 +02:00
} else {
fprintf ( stderr , " amixer: Unknown command '%s'... \n " , argv [ optind ] ) ;
}
return 0 ;
}