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
2001-12-30 10:32:53 +01:00
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
1999-05-02 18:21:40 +02:00
*
*/
# 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>
2001-09-11 11:34:14 +02:00
# include <alsa/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"
2001-07-23 15:26:34 +02:00
# define LEVEL_BASIC (1<<0)
# define LEVEL_INACTIVE (1<<1)
# define LEVEL_ID (1<<2)
1999-05-02 18:21:40 +02:00
2005-12-01 12:32:28 +01:00
static int quiet = 0 ;
static int debugflag = 0 ;
static int no_check = 0 ;
static int smixer_level = 0 ;
static int ignore_error = 0 ;
static struct snd_mixer_selem_regopt smixer_options ;
static char card [ 64 ] = " default " ;
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
{
2005-12-01 12:32:28 +01:00
printf ( " Usage: amixer <options> [command] \n " ) ;
1999-05-02 18:21:40 +02:00
printf ( " \n Available options: \n " ) ;
printf ( " -h,--help this help \n " ) ;
2002-05-07 14:20:55 +02:00
printf ( " -c,--card N select the card \n " ) ;
2002-04-07 22:42:20 +02:00
printf ( " -D,--device N select the device, default '%s' \n " , card ) ;
printf ( " -d,--debug debug mode \n " ) ;
2005-02-04 16:35:27 +01:00
printf ( " -n,--nocheck do not perform range checking \n " ) ;
1999-05-02 18:21:40 +02:00
printf ( " -v,--version print version of this program \n " ) ;
2001-07-23 15:26:34 +02:00
printf ( " -q,--quiet be quiet \n " ) ;
printf ( " -i,--inactive show also inactive controls \n " ) ;
2005-03-27 14:50:34 +02:00
printf ( " -a,--abstract L select abstraction level (none or basic) \n " ) ;
2005-12-01 12:32:28 +01:00
printf ( " -s,--stdin Read and execute commands from stdin sequentially \n " ) ;
1999-05-02 18:21:40 +02:00
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 " ) ;
2001-03-16 08:35:25 +01:00
printf ( " sget sID get contents for one mixer simple control \n " ) ;
2000-08-11 21:29:55 +02:00
printf ( " controls show all controls for given card \n " ) ;
printf ( " contents show contents of all controls for given card \n " ) ;
2001-03-16 08:35:25 +01:00
printf ( " cset cID P set control contents for one control \n " ) ;
printf ( " cget cID get control contents for one control \n " ) ;
2000-08-11 21:29:55 +02:00
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
2001-03-26 14:45:50 +02:00
if ( ( err = snd_ctl_open ( & handle , card , 0 ) ) < 0 ) {
2003-04-01 16:09:09 +02:00
error ( " Control device %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-09-05 11:23:31 +02:00
2001-02-07 16:13:17 +01:00
if ( ( err = snd_ctl_card_info ( handle , info ) ) < 0 ) {
2003-04-01 16:09:09 +02:00
error ( " Control device %s 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 name : '%s' \n " , snd_ctl_card_info_get_mixername ( info ) ) ;
2001-06-25 15:14:51 +02:00
printf ( " Components : '%s' \n " , snd_ctl_card_info_get_components ( 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-03-26 14:45:50 +02:00
if ( ( err = snd_mixer_open ( & mhandle , 0 ) ) < 0 ) {
2001-02-11 16:45:44 +01:00
error ( " Mixer open error: %s " , snd_strerror ( err ) ) ;
return err ;
}
2005-06-06 16:02:10 +02:00
if ( smixer_level = = 0 & & ( err = snd_mixer_attach ( mhandle , card ) ) < 0 ) {
2001-02-11 16:45:44 +01:00
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
}
2005-03-27 14:50:34 +02:00
if ( ( err = snd_mixer_selem_register ( mhandle , smixer_level > 0 ? & smixer_options : NULL , NULL ) ) < 0 ) {
2001-02-11 16:45:44 +01:00
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 ) {
2004-02-21 19:44:18 +01:00
error ( " Mixer load %s error: %s " , card , snd_strerror ( err ) ) ;
2001-02-11 16:45:44 +01:00
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 ' : ' - ' ;
2006-07-05 17:46:10 +02:00
* res + + = snd_ctl_elem_info_is_tlv_readable ( info ) ? ' R ' : ' - ' ;
* res + + = snd_ctl_elem_info_is_tlv_writable ( info ) ? ' W ' : ' - ' ;
* res + + = snd_ctl_elem_info_is_tlv_commandable ( info ) ? ' C ' : ' - ' ;
2000-08-11 21:29:55 +02:00
* res + + = ' \0 ' ;
return result ;
}
2006-08-25 12:00:14 +02:00
# define check_range(val, min, max) \
( no_check ? ( val ) : ( ( val < min ) ? ( min ) : ( val > max ) ? ( max ) : ( 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 */
2006-08-25 12:00:14 +02:00
# define convert_prange1(val, min, max) \
ceil ( ( val ) * ( ( max ) - ( min ) ) * 0.01 + ( min ) )
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
{
2006-08-25 12:00:14 +02:00
long val = min ;
char * p = * ptr , * s ;
1999-05-02 18:21:40 +02:00
2006-08-25 12:00:14 +02:00
if ( * p = = ' : ' )
p + + ;
if ( * p = = ' \0 ' | | ( ! isdigit ( * p ) & & * p ! = ' - ' ) )
goto out ;
s = p ;
val = strtol ( s , & p , 10 ) ;
if ( * p = = ' . ' ) {
p + + ;
strtol ( p , & p , 10 ) ;
1999-05-02 18:21:40 +02:00
}
2006-08-25 12:00:14 +02:00
if ( * p = = ' % ' ) {
val = ( long ) convert_prange1 ( strtod ( s , NULL ) , min , max ) ;
p + + ;
1999-05-02 18:21:40 +02:00
}
2006-08-25 12:00:14 +02:00
val = check_range ( val , min , max ) ;
if ( * p = = ' , ' )
p + + ;
out :
* ptr = p ;
return val ;
1999-05-02 18:21:40 +02:00
}
2002-05-13 11:54:24 +02:00
static long get_integer64 ( char * * ptr , long long min , long long max )
{
2006-08-25 12:00:14 +02:00
long long val = min ;
char * p = * ptr , * s ;
2002-05-13 11:54:24 +02:00
2006-08-25 12:00:14 +02:00
if ( * p = = ' : ' )
p + + ;
if ( * p = = ' \0 ' | | ( ! isdigit ( * p ) & & * p ! = ' - ' ) )
goto out ;
s = p ;
val = strtol ( s , & p , 10 ) ;
if ( * p = = ' . ' ) {
p + + ;
strtol ( p , & p , 10 ) ;
2002-05-13 11:54:24 +02:00
}
2006-08-25 12:00:14 +02:00
if ( * p = = ' % ' ) {
val = ( long long ) convert_prange1 ( strtod ( s , NULL ) , min , max ) ;
p + + ;
2002-05-13 11:54:24 +02:00
}
2006-08-25 12:00:14 +02:00
val = check_range ( val , min , max ) ;
if ( * p = = ' , ' )
p + + ;
out :
* ptr = p ;
return val ;
2002-05-13 11:54:24 +02:00
}
2006-08-25 12:00:14 +02:00
struct volume_ops {
int ( * get_range ) ( snd_mixer_elem_t * elem , long * min , long * max ) ;
int ( * get ) ( snd_mixer_elem_t * elem , snd_mixer_selem_channel_id_t c ,
long * value ) ;
int ( * set ) ( snd_mixer_elem_t * elem , snd_mixer_selem_channel_id_t c ,
long value ) ;
} ;
enum { VOL_RAW , VOL_DB } ;
struct volume_ops_set {
int ( * has_volume ) ( snd_mixer_elem_t * elem ) ;
struct volume_ops v [ 2 ] ;
} ;
static int set_playback_dB ( snd_mixer_elem_t * elem ,
snd_mixer_selem_channel_id_t c , long value )
1999-07-21 13:52:55 +02:00
{
2006-08-25 12:00:14 +02:00
return snd_mixer_selem_set_playback_dB ( elem , c , value , 0 ) ;
}
1999-07-21 13:52:55 +02:00
2006-08-25 12:00:14 +02:00
static int set_capture_dB ( snd_mixer_elem_t * elem ,
snd_mixer_selem_channel_id_t c , long value )
{
return snd_mixer_selem_set_capture_dB ( elem , c , value , 0 ) ;
}
static struct volume_ops_set vol_ops [ 2 ] = {
{
. has_volume = snd_mixer_selem_has_playback_volume ,
. v = { { snd_mixer_selem_get_playback_volume_range ,
snd_mixer_selem_get_playback_volume ,
snd_mixer_selem_set_playback_volume } ,
{ snd_mixer_selem_get_playback_dB_range ,
snd_mixer_selem_get_playback_dB ,
set_playback_dB } } ,
} ,
{
. has_volume = snd_mixer_selem_has_capture_volume ,
. v = { { snd_mixer_selem_get_capture_volume_range ,
snd_mixer_selem_get_capture_volume ,
snd_mixer_selem_set_capture_volume } ,
{ snd_mixer_selem_get_capture_dB_range ,
snd_mixer_selem_get_capture_dB ,
set_capture_dB } } ,
} ,
} ;
static int set_volume_simple ( snd_mixer_elem_t * elem ,
snd_mixer_selem_channel_id_t chn ,
char * * ptr , int dir )
{
long val , orig , pmin , pmax ;
char * p = * ptr , * s ;
2006-10-04 09:47:41 +02:00
int invalid = 0 , err = 0 , vol_type = VOL_RAW ;
2006-08-25 12:00:14 +02:00
if ( ! vol_ops [ dir ] . has_volume ( elem ) )
invalid = 1 ;
if ( * p = = ' : ' )
p + + ;
if ( * p = = ' \0 ' | | ( ! isdigit ( * p ) & & * p ! = ' - ' ) )
goto skip ;
if ( ! invalid & &
vol_ops [ dir ] . v [ VOL_RAW ] . get_range ( elem , & pmin , & pmax ) < 0 )
invalid = 1 ;
s = p ;
val = strtol ( s , & p , 10 ) ;
if ( * p = = ' . ' ) {
p + + ;
strtol ( p , & p , 10 ) ;
1999-07-21 13:52:55 +02:00
}
2006-08-25 12:00:14 +02:00
if ( * p = = ' % ' ) {
if ( ! invalid )
val = ( long ) convert_prange1 ( strtod ( s , NULL ) , pmin , pmax ) ;
p + + ;
} else if ( p [ 0 ] = = ' d ' & & p [ 1 ] = = ' B ' ) {
if ( ! invalid ) {
val = ( long ) ( strtod ( s , NULL ) * 100.0 ) ;
vol_type = VOL_DB ;
if ( vol_ops [ dir ] . v [ vol_type ] . get_range ( elem , & pmin , & pmax ) < 0 )
invalid = 1 ;
}
p + = 2 ;
1999-07-21 13:52:55 +02:00
}
2006-08-25 12:00:14 +02:00
if ( * p = = ' + ' | | * p = = ' - ' ) {
if ( ! invalid ) {
if ( vol_ops [ dir ] . v [ vol_type ] . get ( elem , chn , & orig ) < 0 )
invalid = 1 ;
if ( * p = = ' + ' )
val = orig + val ;
else
val = orig - val ;
}
p + + ;
2000-03-18 19:00:37 +01:00
}
2006-08-25 12:00:14 +02:00
if ( ! invalid ) {
val = check_range ( val , pmin , pmax ) ;
2006-10-04 09:47:41 +02:00
err = vol_ops [ dir ] . v [ vol_type ] . set ( elem , chn , val ) ;
2006-08-25 12:00:14 +02:00
}
skip :
if ( * p = = ' , ' )
p + + ;
* ptr = p ;
2006-10-04 09:47:41 +02:00
return err ? err : ( invalid ? - ENOENT : 0 ) ;
1999-07-21 13:52:55 +02:00
}
2001-08-27 11:15:44 +02:00
static int get_bool_simple ( char * * ptr , char * str , int invert , int orig )
{
if ( * * ptr = = ' : ' )
( * ptr ) + + ;
if ( ! strncasecmp ( * ptr , str , strlen ( str ) ) ) {
orig = 1 ^ ( invert ? 1 : 0 ) ;
while ( * * ptr ! = ' \0 ' & & * * ptr ! = ' , ' & & * * ptr ! = ' : ' )
( * ptr ) + + ;
}
if ( * * ptr = = ' , ' | | * * ptr = = ' : ' )
( * ptr ) + + ;
return orig ;
}
static int simple_skip_word ( char * * ptr , char * str )
{
char * xptr = * ptr ;
if ( * xptr = = ' : ' )
xptr + + ;
if ( ! strncasecmp ( xptr , str , strlen ( str ) ) ) {
while ( * xptr ! = ' \0 ' & & * xptr ! = ' , ' & & * xptr ! = ' : ' )
xptr + + ;
if ( * xptr = = ' , ' | | * xptr = = ' : ' )
xptr + + ;
* ptr = xptr ;
return 1 ;
}
return 0 ;
}
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
}
2006-07-05 17:46:10 +02:00
static void print_spaces ( unsigned int spaces )
{
while ( spaces - - > 0 )
putc ( ' ' , stdout ) ;
}
2006-07-27 11:02:00 +02:00
static void print_dB ( long dB )
2006-07-05 17:46:10 +02:00
{
2006-07-27 11:02:00 +02:00
printf ( " %li.%02lidB " , dB / 100 , ( dB < 0 ? - dB : dB ) % 100 ) ;
2006-07-05 17:46:10 +02:00
}
static void decode_tlv ( unsigned int spaces , unsigned int * tlv , unsigned int tlv_size )
{
unsigned int type = tlv [ 0 ] ;
unsigned int size ;
unsigned int idx = 0 ;
if ( tlv_size < 2 * sizeof ( unsigned int ) ) {
printf ( " TLV size error! \n " ) ;
return ;
}
print_spaces ( spaces ) ;
printf ( " | " ) ;
type = tlv [ idx + + ] ;
size = tlv [ idx + + ] ;
tlv_size - = 2 * sizeof ( unsigned int ) ;
if ( size > tlv_size ) {
printf ( " TLV size error (%i, %i, %i)! \n " , type , size , tlv_size ) ;
return ;
}
switch ( type ) {
case SND_CTL_TLVT_CONTAINER :
size + = sizeof ( unsigned int ) - 1 ;
size / = sizeof ( unsigned int ) ;
while ( idx < size ) {
if ( tlv [ idx + 1 ] > ( size - idx ) * sizeof ( unsigned int ) ) {
printf ( " TLV size error in compound! \n " ) ;
return ;
}
decode_tlv ( spaces + 2 , tlv + idx , tlv [ idx + 1 ] ) ;
idx + = 2 + ( tlv [ 1 ] + sizeof ( unsigned int ) - 1 ) / sizeof ( unsigned int ) ;
}
break ;
case SND_CTL_TLVT_DB_SCALE :
printf ( " dBscale- " ) ;
if ( size ! = 2 * sizeof ( unsigned int ) ) {
while ( size > 0 ) {
printf ( " 0x%x " , tlv [ idx + + ] ) ;
size - = sizeof ( unsigned int ) ;
}
} else {
printf ( " min= " ) ;
print_dB ( tlv [ 2 ] ) ;
printf ( " ,step= " ) ;
print_dB ( tlv [ 3 ] & 0xffff ) ;
printf ( " ,mute=%i " , ( tlv [ 3 ] > > 16 ) & 1 ) ;
}
break ;
2006-08-28 13:28:46 +02:00
# ifdef SND_CTL_TLVT_DB_LINEAR
case SND_CTL_TLVT_DB_LINEAR :
printf ( " dBlinear- " ) ;
if ( size ! = 2 * sizeof ( unsigned int ) ) {
while ( size > 0 ) {
printf ( " 0x%x " , tlv [ idx + + ] ) ;
size - = sizeof ( unsigned int ) ;
}
} else {
printf ( " min= " ) ;
print_dB ( tlv [ 2 ] ) ;
printf ( " ,max= " ) ;
print_dB ( tlv [ 3 ] ) ;
}
break ;
# endif
2006-07-05 17:46:10 +02:00
default :
printf ( " unk-%i- " , type ) ;
while ( size > 0 ) {
printf ( " 0x%x " , tlv [ idx + + ] ) ;
size - = sizeof ( unsigned int ) ;
}
break ;
}
putc ( ' \n ' , stdout ) ;
}
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 ;
2006-07-05 17:46:10 +02:00
unsigned int item , idx , count , * tlv ;
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 ) {
2001-07-23 15:26:34 +02:00
error ( " Control %s snd_hctl_elem_info error: %s \n " , card , snd_strerror ( err ) ) ;
2000-08-11 21:29:55 +02:00
return err ;
}
2001-07-23 15:26:34 +02:00
if ( level & LEVEL_ID ) {
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 ) ;
2001-07-11 17:00:59 +02:00
switch ( 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 ;
2002-05-13 11:54:24 +02:00
case SND_CTL_ELEM_TYPE_INTEGER64 :
printf ( " ,min=%Li,max=%Li,step=%Li \n " ,
snd_ctl_elem_info_get_min64 ( info ) ,
snd_ctl_elem_info_get_max64 ( info ) ,
snd_ctl_elem_info_get_step64 ( info ) ) ;
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
}
2001-07-23 15:26:34 +02:00
if ( level & LEVEL_BASIC ) {
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-07-11 17:00:59 +02:00
switch ( 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 ;
2002-05-13 11:54:24 +02:00
case SND_CTL_ELEM_TYPE_INTEGER64 :
printf ( " %Li " , snd_ctl_elem_value_get_integer64 ( control , idx ) ) ;
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 " ) ;
2006-07-05 17:46:10 +02:00
if ( ! snd_ctl_elem_info_is_tlv_readable ( info ) )
goto __skip_tlv ;
tlv = malloc ( 4096 ) ;
if ( ( err = snd_hctl_elem_tlv_read ( elem , tlv , 4096 ) ) < 0 ) {
error ( " Control %s element TLV read error: %s \n " , card , snd_strerror ( err ) ) ;
free ( tlv ) ;
return err ;
}
decode_tlv ( strlen ( space ) , tlv , 4096 ) ;
free ( tlv ) ;
1999-05-02 18:21:40 +02:00
}
2006-07-05 17:46:10 +02:00
__skip_tlv :
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 ;
2001-07-23 15:26:34 +02:00
snd_ctl_elem_info_t * info ;
2001-02-09 12:20:32 +01:00
snd_ctl_elem_id_alloca ( & id ) ;
2001-07-23 15:26:34 +02:00
snd_ctl_elem_info_alloca ( & info ) ;
1999-05-02 18:21:40 +02:00
2001-03-26 14:45:50 +02:00
if ( ( err = snd_hctl_open ( & handle , card , 0 ) ) < 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 ) ) {
2001-07-23 15:26:34 +02:00
if ( ( err = snd_hctl_elem_info ( elem , info ) ) < 0 ) {
error ( " Control %s snd_hctl_elem_info error: %s \n " , card , snd_strerror ( err ) ) ;
return err ;
}
if ( ! ( level & LEVEL_INACTIVE ) & & snd_ctl_elem_info_is_inactive ( info ) )
continue ;
2001-02-09 12:20:32 +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 " ) ;
2001-07-23 15:26:34 +02:00
if ( level & LEVEL_BASIC )
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-11 16:45:44 +01:00
snd_mixer_selem_channel_id_t chn ;
2001-02-16 00:05:42 +01:00
long pmin = 0 , pmax = 0 ;
long cmin = 0 , cmax = 0 ;
long pvol , cvol ;
int psw , csw ;
2001-07-23 15:26:34 +02:00
int pmono , cmono , mono_ok = 0 ;
2006-07-27 11:02:00 +02:00
long db ;
2001-02-09 12:20:32 +01:00
snd_mixer_elem_t * elem ;
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-07-23 15:26:34 +02:00
if ( level & LEVEL_BASIC ) {
1999-07-21 13:52:55 +02:00
printf ( " %sCapabilities: " , space ) ;
2001-02-16 00:05:42 +01:00
if ( snd_mixer_selem_has_common_volume ( elem ) ) {
1999-07-21 00:00:59 +02:00
printf ( " volume " ) ;
2001-02-16 00:05:42 +01:00
if ( snd_mixer_selem_has_playback_volume_joined ( elem ) )
printf ( " volume-joined " ) ;
2001-07-23 15:26:34 +02:00
} else {
if ( snd_mixer_selem_has_playback_volume ( elem ) ) {
printf ( " pvolume " ) ;
if ( snd_mixer_selem_has_playback_volume_joined ( elem ) )
printf ( " pvolume-joined " ) ;
}
if ( snd_mixer_selem_has_capture_volume ( elem ) ) {
printf ( " cvolume " ) ;
if ( snd_mixer_selem_has_capture_volume_joined ( elem ) )
printf ( " cvolume-joined " ) ;
}
2001-02-16 00:05:42 +01:00
}
if ( snd_mixer_selem_has_common_switch ( elem ) ) {
printf ( " switch " ) ;
if ( snd_mixer_selem_has_playback_switch_joined ( elem ) )
printf ( " switch-joined " ) ;
2001-07-23 15:26:34 +02:00
} else {
if ( snd_mixer_selem_has_playback_switch ( elem ) ) {
printf ( " pswitch " ) ;
if ( snd_mixer_selem_has_playback_switch_joined ( elem ) )
printf ( " pswitch-joined " ) ;
}
if ( snd_mixer_selem_has_capture_switch ( elem ) ) {
printf ( " cswitch " ) ;
if ( snd_mixer_selem_has_capture_switch_joined ( elem ) )
printf ( " cswitch-joined " ) ;
if ( snd_mixer_selem_has_capture_switch_exclusive ( elem ) )
printf ( " cswitch-exclusive " ) ;
}
1999-07-21 00:00:59 +02:00
}
2005-06-15 16:55:37 +02:00
if ( snd_mixer_selem_is_enumerated ( elem ) ) {
printf ( " enum " ) ;
}
1999-07-21 00:00:59 +02:00
printf ( " \n " ) ;
2005-06-15 16:55:37 +02:00
if ( snd_mixer_selem_is_enumerated ( elem ) ) {
2005-09-22 14:47:02 +02:00
int i , items ;
unsigned int idx ;
2005-06-15 16:55:37 +02:00
char itemname [ 40 ] ;
items = snd_mixer_selem_get_enum_items ( elem ) ;
printf ( " Items: " ) ;
for ( i = 0 ; i < items ; i + + ) {
snd_mixer_selem_get_enum_item_name ( elem , i , sizeof ( itemname ) - 1 , itemname ) ;
printf ( " '%s' " , itemname ) ;
}
printf ( " \n " ) ;
for ( i = 0 ; ! snd_mixer_selem_get_enum_item ( elem , i , & idx ) ; i + + ) {
snd_mixer_selem_get_enum_item_name ( elem , idx , sizeof ( itemname ) - 1 , itemname ) ;
printf ( " Item%d: '%s' \n " , i , itemname ) ;
}
return 0 ; /* no more thing to do */
}
2001-02-16 00:05:42 +01:00
if ( snd_mixer_selem_has_capture_switch_exclusive ( elem ) )
2001-02-11 16:45:44 +01:00
printf ( " %sCapture exclusive group: %i \n " , space ,
2001-02-16 00:05:42 +01:00
snd_mixer_selem_get_capture_group ( elem ) ) ;
if ( snd_mixer_selem_has_playback_volume ( elem ) | |
snd_mixer_selem_has_playback_switch ( elem ) ) {
2003-02-24 14:51:15 +01:00
printf ( " %sPlayback channels: " , space ) ;
2001-02-16 00:05:42 +01:00
if ( snd_mixer_selem_is_playback_mono ( elem ) ) {
2003-02-24 14:51:15 +01:00
printf ( " Mono " ) ;
2001-02-16 00:05:42 +01:00
} else {
2001-07-23 15:26:34 +02:00
int first = 1 ;
2001-07-11 17:00:59 +02:00
for ( chn = 0 ; chn < = SND_MIXER_SCHN_LAST ; chn + + ) {
2001-02-16 00:05:42 +01:00
if ( ! snd_mixer_selem_has_playback_channel ( elem , chn ) )
continue ;
2001-07-23 15:26:34 +02:00
if ( ! first )
2003-02-24 14:51:15 +01:00
printf ( " - " ) ;
printf ( " %s " , snd_mixer_selem_channel_name ( chn ) ) ;
2001-07-23 15:26:34 +02:00
first = 0 ;
2001-02-16 00:05:42 +01:00
}
1999-07-22 20:10:19 +02:00
}
2001-02-16 00:05:42 +01:00
printf ( " \n " ) ;
1999-07-21 00:00:59 +02:00
}
2001-02-16 00:05:42 +01:00
if ( snd_mixer_selem_has_capture_volume ( elem ) | |
snd_mixer_selem_has_capture_switch ( elem ) ) {
2003-02-24 14:51:15 +01:00
printf ( " %sCapture channels: " , space ) ;
2001-02-16 00:05:42 +01:00
if ( snd_mixer_selem_is_capture_mono ( elem ) ) {
2003-02-24 14:51:15 +01:00
printf ( " Mono " ) ;
2001-02-16 00:05:42 +01:00
} else {
2001-07-23 15:26:34 +02:00
int first = 1 ;
2001-07-11 17:00:59 +02:00
for ( chn = 0 ; chn < = SND_MIXER_SCHN_LAST ; chn + + ) {
2001-02-16 00:05:42 +01:00
if ( ! snd_mixer_selem_has_capture_channel ( elem , chn ) )
continue ;
2001-07-23 15:26:34 +02:00
if ( ! first )
2003-02-24 14:51:15 +01:00
printf ( " - " ) ;
printf ( " %s " , snd_mixer_selem_channel_name ( chn ) ) ;
2001-07-23 15:26:34 +02:00
first = 0 ;
2001-02-16 00:05:42 +01:00
}
}
printf ( " \n " ) ;
}
if ( snd_mixer_selem_has_playback_volume ( elem ) | |
snd_mixer_selem_has_capture_volume ( elem ) ) {
2003-02-24 14:51:15 +01:00
printf ( " %sLimits: " , space ) ;
2001-07-23 15:26:34 +02:00
if ( snd_mixer_selem_has_common_volume ( elem ) ) {
2001-03-30 11:43:30 +02:00
snd_mixer_selem_get_playback_volume_range ( elem , & pmin , & pmax ) ;
snd_mixer_selem_get_capture_volume_range ( elem , & cmin , & cmax ) ;
2003-02-24 14:51:15 +01:00
printf ( " %li - %li " , pmin , pmax ) ;
2001-07-23 15:26:34 +02:00
} else {
if ( snd_mixer_selem_has_playback_volume ( elem ) ) {
snd_mixer_selem_get_playback_volume_range ( elem , & pmin , & pmax ) ;
2003-02-24 14:51:15 +01:00
printf ( " Playback %li - %li " , pmin , pmax ) ;
2001-07-23 15:26:34 +02:00
}
if ( snd_mixer_selem_has_capture_volume ( elem ) ) {
snd_mixer_selem_get_capture_volume_range ( elem , & cmin , & cmax ) ;
2003-02-24 14:51:15 +01:00
printf ( " Capture %li - %li " , cmin , cmax ) ;
2001-07-23 15:26:34 +02:00
}
2001-02-16 00:05:42 +01:00
}
printf ( " \n " ) ;
}
2001-07-23 15:26:34 +02:00
pmono = snd_mixer_selem_has_playback_channel ( elem , SND_MIXER_SCHN_MONO ) & &
( snd_mixer_selem_is_playback_mono ( elem ) | |
2001-02-16 00:05:42 +01:00
( ! snd_mixer_selem_has_playback_volume ( elem ) & &
2001-07-23 15:26:34 +02:00
! snd_mixer_selem_has_playback_switch ( elem ) ) ) ;
cmono = snd_mixer_selem_has_capture_channel ( elem , SND_MIXER_SCHN_MONO ) & &
( snd_mixer_selem_is_capture_mono ( elem ) | |
2001-02-16 00:05:42 +01:00
( ! snd_mixer_selem_has_capture_volume ( elem ) & &
2001-07-23 15:26:34 +02:00
! snd_mixer_selem_has_capture_switch ( elem ) ) ) ;
#if 0
printf ( " pmono = %i, cmono = %i (%i, %i, %i, %i) \n " , pmono , cmono ,
snd_mixer_selem_has_capture_channel ( elem , SND_MIXER_SCHN_MONO ) ,
snd_mixer_selem_is_capture_mono ( elem ) ,
snd_mixer_selem_has_capture_volume ( elem ) ,
snd_mixer_selem_has_capture_switch ( elem ) ) ;
# endif
if ( pmono | | cmono ) {
if ( ! mono_ok ) {
2003-02-24 14:51:15 +01:00
printf ( " %s%s: " , space , " Mono " ) ;
2001-07-23 15:26:34 +02:00
mono_ok = 1 ;
}
if ( snd_mixer_selem_has_common_volume ( elem ) ) {
snd_mixer_selem_get_playback_volume ( elem , SND_MIXER_SCHN_MONO , & pvol ) ;
2003-02-24 14:51:15 +01:00
printf ( " %s " , get_percent ( pvol , pmin , pmax ) ) ;
2006-07-27 11:02:00 +02:00
if ( ! snd_mixer_selem_get_playback_dB ( elem , SND_MIXER_SCHN_MONO , & db ) ) {
printf ( " [ " ) ;
print_dB ( db ) ;
printf ( " ] " ) ;
}
2001-07-23 15:26:34 +02:00
}
if ( snd_mixer_selem_has_common_switch ( elem ) ) {
snd_mixer_selem_get_playback_switch ( elem , SND_MIXER_SCHN_MONO , & psw ) ;
2003-02-24 14:51:15 +01:00
printf ( " [%s] " , psw ? " on " : " off " ) ;
2001-07-23 15:26:34 +02:00
}
}
if ( pmono & & snd_mixer_selem_has_playback_channel ( elem , SND_MIXER_SCHN_MONO ) ) {
int title = 0 ;
if ( ! mono_ok ) {
2003-02-24 14:51:15 +01:00
printf ( " %s%s: " , space , " Mono " ) ;
2001-07-23 15:26:34 +02:00
mono_ok = 1 ;
}
if ( ! snd_mixer_selem_has_common_volume ( elem ) ) {
2001-02-16 00:05:42 +01:00
if ( snd_mixer_selem_has_playback_volume ( elem ) ) {
2003-02-24 14:51:15 +01:00
printf ( " Playback " ) ;
2001-07-23 15:26:34 +02:00
title = 1 ;
snd_mixer_selem_get_playback_volume ( elem , SND_MIXER_SCHN_MONO , & pvol ) ;
2003-02-24 14:51:15 +01:00
printf ( " %s " , get_percent ( pvol , pmin , pmax ) ) ;
2006-07-27 11:02:00 +02:00
if ( ! snd_mixer_selem_get_playback_dB ( elem , SND_MIXER_SCHN_MONO , & db ) ) {
printf ( " [ " ) ;
print_dB ( db ) ;
printf ( " ] " ) ;
}
2001-02-16 00:05:42 +01:00
}
2001-07-23 15:26:34 +02:00
}
if ( ! snd_mixer_selem_has_common_switch ( elem ) ) {
2001-02-16 00:05:42 +01:00
if ( snd_mixer_selem_has_playback_switch ( elem ) ) {
2001-07-23 15:26:34 +02:00
if ( ! title )
2003-02-24 14:51:15 +01:00
printf ( " Playback " ) ;
2001-07-23 15:26:34 +02:00
snd_mixer_selem_get_playback_switch ( elem , SND_MIXER_SCHN_MONO , & psw ) ;
2003-02-24 14:51:15 +01:00
printf ( " [%s] " , psw ? " on " : " off " ) ;
2001-02-16 00:05:42 +01:00
}
}
2001-07-23 15:26:34 +02:00
}
if ( cmono & & snd_mixer_selem_has_capture_channel ( elem , SND_MIXER_SCHN_MONO ) ) {
int title = 0 ;
if ( ! mono_ok ) {
2003-02-24 14:51:15 +01:00
printf ( " %s%s: " , space , " Mono " ) ;
2001-07-23 15:26:34 +02:00
mono_ok = 1 ;
}
if ( ! snd_mixer_selem_has_common_volume ( elem ) ) {
2001-02-16 00:05:42 +01:00
if ( snd_mixer_selem_has_capture_volume ( elem ) ) {
2003-02-24 14:51:15 +01:00
printf ( " Capture " ) ;
2001-07-23 15:26:34 +02:00
title = 1 ;
snd_mixer_selem_get_capture_volume ( elem , SND_MIXER_SCHN_MONO , & cvol ) ;
2003-02-24 14:51:15 +01:00
printf ( " %s " , get_percent ( cvol , cmin , cmax ) ) ;
2006-07-27 11:02:00 +02:00
if ( ! snd_mixer_selem_get_capture_dB ( elem , SND_MIXER_SCHN_MONO , & db ) ) {
printf ( " [ " ) ;
print_dB ( db ) ;
printf ( " ] " ) ;
}
2001-02-16 00:05:42 +01:00
}
2001-07-23 15:26:34 +02:00
}
if ( ! snd_mixer_selem_has_common_switch ( elem ) ) {
2001-02-16 00:05:42 +01:00
if ( snd_mixer_selem_has_capture_switch ( elem ) ) {
2001-07-23 15:26:34 +02:00
if ( ! title )
2003-02-24 14:51:15 +01:00
printf ( " Capture " ) ;
2001-07-23 15:26:34 +02:00
snd_mixer_selem_get_capture_switch ( elem , SND_MIXER_SCHN_MONO , & csw ) ;
2003-02-24 14:51:15 +01:00
printf ( " [%s] " , csw ? " on " : " off " ) ;
2001-02-16 00:05:42 +01:00
}
1999-07-22 20:10:19 +02:00
}
2001-07-23 15:26:34 +02:00
}
if ( pmono | | cmono )
2001-02-16 00:05:42 +01:00
printf ( " \n " ) ;
2001-07-23 15:26:34 +02:00
if ( ! pmono | | ! cmono ) {
for ( chn = 0 ; chn < = SND_MIXER_SCHN_LAST ; chn + + ) {
if ( ( pmono | | ! snd_mixer_selem_has_playback_channel ( elem , chn ) ) & &
( cmono | | ! snd_mixer_selem_has_capture_channel ( elem , chn ) ) )
continue ;
2003-02-24 14:51:15 +01:00
printf ( " %s%s: " , space , snd_mixer_selem_channel_name ( chn ) ) ;
2001-07-25 13:49:32 +02:00
if ( ! pmono & & ! cmono & & snd_mixer_selem_has_common_volume ( elem ) ) {
2001-07-23 15:26:34 +02:00
snd_mixer_selem_get_playback_volume ( elem , chn , & pvol ) ;
2003-02-24 14:51:15 +01:00
printf ( " %s " , get_percent ( pvol , pmin , pmax ) ) ;
2006-07-27 11:02:00 +02:00
if ( ! snd_mixer_selem_get_playback_dB ( elem , chn , & db ) ) {
printf ( " [ " ) ;
print_dB ( db ) ;
printf ( " ] " ) ;
}
2001-07-23 15:26:34 +02:00
}
2001-07-25 13:49:32 +02:00
if ( ! pmono & & ! cmono & & snd_mixer_selem_has_common_switch ( elem ) ) {
2001-07-23 15:26:34 +02:00
snd_mixer_selem_get_playback_switch ( elem , chn , & psw ) ;
2003-02-24 14:51:15 +01:00
printf ( " [%s] " , psw ? " on " : " off " ) ;
2001-07-23 15:26:34 +02:00
}
if ( ! pmono & & snd_mixer_selem_has_playback_channel ( elem , chn ) ) {
int title = 0 ;
if ( ! snd_mixer_selem_has_common_volume ( elem ) ) {
if ( snd_mixer_selem_has_playback_volume ( elem ) ) {
2003-02-24 14:51:15 +01:00
printf ( " Playback " ) ;
2001-07-23 15:26:34 +02:00
title = 1 ;
snd_mixer_selem_get_playback_volume ( elem , chn , & pvol ) ;
2003-02-24 14:51:15 +01:00
printf ( " %s " , get_percent ( pvol , pmin , pmax ) ) ;
2006-07-27 11:02:00 +02:00
if ( ! snd_mixer_selem_get_playback_dB ( elem , chn , & db ) ) {
printf ( " [ " ) ;
print_dB ( db ) ;
printf ( " ] " ) ;
}
2001-07-23 15:26:34 +02:00
}
}
if ( ! snd_mixer_selem_has_common_switch ( elem ) ) {
if ( snd_mixer_selem_has_playback_switch ( elem ) ) {
if ( ! title )
2003-02-24 14:51:15 +01:00
printf ( " Playback " ) ;
2001-07-23 15:26:34 +02:00
snd_mixer_selem_get_playback_switch ( elem , chn , & psw ) ;
2003-02-24 14:51:15 +01:00
printf ( " [%s] " , psw ? " on " : " off " ) ;
2001-07-23 15:26:34 +02:00
}
}
}
if ( ! cmono & & snd_mixer_selem_has_capture_channel ( elem , chn ) ) {
int title = 0 ;
if ( ! snd_mixer_selem_has_common_volume ( elem ) ) {
if ( snd_mixer_selem_has_capture_volume ( elem ) ) {
2003-02-24 14:51:15 +01:00
printf ( " Capture " ) ;
2001-07-23 15:26:34 +02:00
title = 1 ;
snd_mixer_selem_get_capture_volume ( elem , chn , & cvol ) ;
2003-02-24 14:51:15 +01:00
printf ( " %s " , get_percent ( cvol , cmin , cmax ) ) ;
2006-07-27 11:02:00 +02:00
if ( ! snd_mixer_selem_get_capture_dB ( elem , chn , & db ) ) {
printf ( " [ " ) ;
print_dB ( db ) ;
printf ( " ] " ) ;
}
2001-07-23 15:26:34 +02:00
}
}
if ( ! snd_mixer_selem_has_common_switch ( elem ) ) {
if ( snd_mixer_selem_has_capture_switch ( elem ) ) {
if ( ! title )
2003-02-24 14:51:15 +01:00
printf ( " Capture " ) ;
2001-07-23 15:26:34 +02:00
snd_mixer_selem_get_capture_switch ( elem , chn , & csw ) ;
2003-02-24 14:51:15 +01:00
printf ( " [%s] " , csw ? " on " : " off " ) ;
2001-07-23 15:26:34 +02:00
}
}
}
printf ( " \n " ) ;
}
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-03-26 14:45:50 +02:00
if ( ( err = snd_mixer_open ( & handle , 0 ) ) < 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
}
2005-06-06 16:02:10 +02:00
if ( smixer_level = = 0 & & ( err = snd_mixer_attach ( handle , card ) ) < 0 ) {
2001-02-11 16:45:44 +01:00
error ( " Mixer attach %s error: %s " , card , snd_strerror ( err ) ) ;
snd_mixer_close ( handle ) ;
return err ;
}
2005-03-27 14:50:34 +02:00
if ( ( err = snd_mixer_selem_register ( handle , smixer_level > 0 ? & smixer_options : NULL , NULL ) ) < 0 ) {
2001-02-11 16:45:44 +01:00
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 ) {
2004-02-24 10:19:31 +01:00
error ( " Mixer %s load error: %s " , card , snd_strerror ( err ) ) ;
2001-02-11 16:45:44 +01:00
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 ) ;
2001-07-23 15:26:34 +02:00
if ( ! ( level & LEVEL_INACTIVE ) & & ! snd_mixer_selem_is_active ( elem ) )
continue ;
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 , " " , 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
{
2005-06-15 16:55:37 +02:00
int c , size , numid ;
2000-08-11 21:29:55 +02:00
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 ;
2005-06-15 16:55:37 +02:00
numid = atoi ( str ) ;
if ( numid < = 0 ) {
fprintf ( stderr , " amixer: Invalid numid %d \n " , numid ) ;
return - EINVAL ;
}
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 ) {
2003-02-04 17:03:36 +01:00
if ( size < ( int ) sizeof ( buf ) ) {
2000-08-11 21:29:55 +02:00
* ptr + + = * str ;
size + + ;
}
str + + ;
}
if ( * str = = c )
str + + ;
} else {
while ( * str & & * str ! = ' , ' ) {
2003-02-04 17:03:36 +01:00
if ( size < ( int ) 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 ;
2001-06-25 11:16:27 +02:00
size = 1 ; /* for '\0' */
1999-07-21 13:52:55 +02:00
if ( * str ! = ' " ' & & * str ! = ' \' ' ) {
while ( * str & & * str ! = ' , ' ) {
2003-02-04 17:03:36 +01:00
if ( size < ( int ) sizeof ( buf ) ) {
1999-07-21 13:52:55 +02:00
* ptr + + = * str ;
size + + ;
}
str + + ;
}
} else {
c = * str + + ;
while ( * str & & * str ! = c ) {
2003-02-04 17:03:36 +01:00
if ( size < ( int ) sizeof ( buf ) ) {
1999-07-21 13:52:55 +02:00
* ptr + + = * str ;
size + + ;
}
str + + ;
}
if ( * str = = c )
str + + ;
}
2001-06-25 11:16:27 +02:00
if ( * str = = ' \0 ' ) {
snd_mixer_selem_id_set_index ( sid , 0 ) ;
* ptr = 0 ;
goto _set ;
}
1999-07-21 13:52:55 +02:00
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 ) ) ;
2001-06-25 11:16:27 +02:00
_set :
2001-02-09 12:20:32 +01:00
snd_mixer_selem_id_set_name ( sid , buf ) ;
1999-05-02 18:21:40 +02:00
return 0 ;
}
2005-12-01 12:32:28 +01:00
static int cset ( int argc , char * argv [ ] , int roflag , int keep_handle )
1999-05-02 18:21:40 +02:00
{
int err ;
2005-12-01 12:32:28 +01:00
static snd_ctl_t * handle = NULL ;
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
}
2005-12-01 12:32:28 +01:00
if ( handle = = NULL & &
( err = snd_ctl_open ( & handle , card , 0 ) ) < 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 ) {
2005-12-01 12:32:28 +01:00
if ( ignore_error )
return 0 ;
2005-06-15 16:55:37 +02:00
error ( " Cannot find the given element from control %s \n " , card ) ;
2006-10-04 09:47:41 +02:00
if ( ! keep_handle ) {
snd_ctl_close ( handle ) ;
handle = NULL ;
}
2000-08-11 21:29:55 +02:00
return err ;
}
2001-02-15 10:14:28 +01:00
snd_ctl_elem_info_get_id ( info , id ) ; /* FIXME: Remove it when hctl find works ok !!! */
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 ] ;
2002-02-17 18:50:02 +01:00
for ( idx = 0 ; idx < count & & idx < 128 & & ptr & & * ptr ; idx + + ) {
2001-07-11 17:00:59 +02:00
switch ( 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 ;
2001-09-27 19:07:07 +02:00
} else if ( ! strncasecmp ( ptr , " toggle " , 6 ) ) {
2001-09-27 21:14:26 +02:00
tmp = snd_ctl_elem_value_get_boolean ( control , idx ) ;
tmp = tmp > 0 ? 0 : 1 ;
2001-09-27 19:07:07 +02:00
ptr + = 6 ;
2002-01-10 09:32:29 +01:00
} else if ( isdigit ( * ptr ) ) {
tmp = atoi ( ptr ) > 0 ? 1 : 0 ;
2000-08-11 21:29:55 +02:00
while ( isdigit ( * ptr ) )
ptr + + ;
2002-01-10 09:32:29 +01:00
} else {
while ( * ptr & & * ptr ! = ' , ' )
ptr + + ;
2000-08-11 21:29:55 +02:00
}
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 ;
2002-05-13 11:54:24 +02:00
case SND_CTL_ELEM_TYPE_INTEGER64 :
tmp = get_integer64 ( & ptr ,
snd_ctl_elem_info_get_min64 ( info ) ,
snd_ctl_elem_info_get_max64 ( info ) ) ;
snd_ctl_elem_value_set_integer64 ( control , idx , tmp ) ;
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 ) {
2006-10-04 09:47:41 +02:00
if ( ! ignore_error )
error ( " Control %s element write error: %s \n " , card , snd_strerror ( err ) ) ;
if ( ! keep_handle ) {
snd_ctl_close ( handle ) ;
handle = NULL ;
}
return ignore_error ? 0 : err ;
1999-05-02 18:21:40 +02:00
}
}
2005-12-01 12:32:28 +01:00
if ( ! keep_handle ) {
snd_ctl_close ( handle ) ;
handle = NULL ;
}
2001-02-09 16:38:59 +01:00
if ( ! quiet ) {
snd_hctl_t * hctl ;
2001-02-15 10:14:28 +01:00
snd_hctl_elem_t * elem ;
2001-03-26 14:45:50 +02:00
if ( ( err = snd_hctl_open ( & hctl , card , 0 ) ) < 0 ) {
2001-02-09 16:38:59 +01:00
error ( " Control %s open error: %s \n " , card , snd_strerror ( err ) ) ;
return err ;
}
2001-02-15 10:14:28 +01:00
if ( ( err = snd_hctl_load ( hctl ) ) < 0 ) {
2001-02-11 16:45:44 +01:00
error ( " Control %s load error: %s \n " , card , snd_strerror ( err ) ) ;
return err ;
}
elem = snd_hctl_find_elem ( hctl , id ) ;
2001-02-15 10:14:28 +01:00
if ( elem )
2001-07-23 15:26:34 +02:00
show_control ( " " , elem , LEVEL_BASIC | LEVEL_ID ) ;
2001-02-15 10:14:28 +01:00
else
printf ( " Could not find the specified element \n " ) ;
2001-02-09 16:38:59 +01:00
snd_hctl_close ( hctl ) ;
}
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-08-27 11:15:44 +02:00
static unsigned int channels_mask ( char * * arg , unsigned int def )
2000-03-18 19:00:37 +01:00
{
channel_mask_t * c ;
for ( c = chanmask ; c - > name ; c + + ) {
2001-08-27 11:15:44 +02:00
if ( strncasecmp ( * arg , c - > name , strlen ( c - > name ) ) = = 0 ) {
while ( * * arg ! = ' \0 ' & & * * arg ! = ' , ' & & * * arg ! = ' ' & & * * arg ! = ' \t ' )
( * arg ) + + ;
if ( * * arg = = ' , ' | | * * arg = = ' ' | | * * arg = = ' \t ' )
( * arg ) + + ;
2001-02-09 12:20:32 +01:00
return c - > mask ;
2001-08-27 11:15:44 +02:00
}
2000-03-18 19:00:37 +01:00
}
2001-08-27 11:15:44 +02:00
return def ;
}
static unsigned int dir_mask ( char * * arg , unsigned int def )
{
int findend = 0 ;
if ( strncasecmp ( * arg , " playback " , 8 ) = = 0 )
def = findend = 1 ;
else if ( strncasecmp ( * arg , " capture " , 8 ) = = 0 )
def = findend = 2 ;
if ( findend ) {
while ( * * arg ! = ' \0 ' & & * * arg ! = ' , ' & & * * arg ! = ' ' & & * * arg ! = ' \t ' )
( * arg ) + + ;
if ( * * arg = = ' , ' | | * * arg = = ' ' | | * * arg = = ' \t ' )
( * arg ) + + ;
}
return def ;
2000-03-18 19:00:37 +01:00
}
2005-06-15 16:55:37 +02:00
static int get_enum_item_index ( snd_mixer_elem_t * elem , char * * ptrp )
{
char * ptr = * ptrp ;
int items , i , len ;
char name [ 40 ] ;
items = snd_mixer_selem_get_enum_items ( elem ) ;
if ( items < = 0 )
return - 1 ;
for ( i = 0 ; i < items ; i + + ) {
if ( snd_mixer_selem_get_enum_item_name ( elem , i , sizeof ( name ) - 1 , name ) < 0 )
continue ;
len = strlen ( name ) ;
if ( ! strncmp ( name , ptr , len ) ) {
if ( ! ptr [ len ] | | ptr [ len ] = = ' , ' | | ptr [ len ] = = ' \n ' ) {
ptr + = len ;
* ptrp = ptr ;
return i ;
}
}
}
return - 1 ;
}
2005-12-01 12:32:28 +01:00
static int sset ( unsigned int argc , char * argv [ ] , int roflag , int keep_handle )
1999-07-21 13:52:55 +02:00
{
2006-10-04 09:47:41 +02:00
int err , check_flag ;
2001-02-05 16:44:45 +01:00
unsigned int idx ;
2001-02-11 16:45:44 +01:00
snd_mixer_selem_channel_id_t chn ;
2004-08-04 17:21:12 +02:00
unsigned int channels = ~ 0U ;
2005-09-22 14:39:26 +02:00
unsigned int dir = 3 , okflag = 3 ;
2005-12-01 12:32:28 +01:00
static snd_mixer_t * handle = NULL ;
2001-02-09 12:20:32 +01:00
snd_mixer_elem_t * elem ;
snd_mixer_selem_id_t * sid ;
snd_mixer_selem_id_alloca ( & sid ) ;
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 ;
}
2005-12-01 12:32:28 +01:00
if ( handle = = NULL ) {
if ( ( err = snd_mixer_open ( & handle , 0 ) ) < 0 ) {
error ( " Mixer %s open error: %s \n " , card , snd_strerror ( err ) ) ;
return err ;
}
if ( smixer_level = = 0 & & ( err = snd_mixer_attach ( handle , card ) ) < 0 ) {
error ( " Mixer attach %s error: %s " , card , snd_strerror ( err ) ) ;
snd_mixer_close ( handle ) ;
handle = NULL ;
return err ;
}
if ( ( err = snd_mixer_selem_register ( handle , smixer_level > 0 ? & smixer_options : NULL , NULL ) ) < 0 ) {
error ( " Mixer register error: %s " , snd_strerror ( err ) ) ;
snd_mixer_close ( handle ) ;
handle = NULL ;
return err ;
}
err = snd_mixer_load ( handle ) ;
if ( err < 0 ) {
error ( " Mixer %s load error: %s " , card , snd_strerror ( err ) ) ;
snd_mixer_close ( handle ) ;
handle = NULL ;
return err ;
}
2001-02-11 16:45:44 +01:00
}
2001-02-09 12:20:32 +01:00
elem = snd_mixer_find_selem ( handle , sid ) ;
if ( ! elem ) {
2005-12-01 12:32:28 +01:00
if ( ignore_error )
return 0 ;
2001-07-23 15:26:34 +02:00
error ( " Unable to find simple control '%s',%i \n " , snd_mixer_selem_id_get_name ( sid ) , snd_mixer_selem_id_get_index ( sid ) ) ;
2001-02-09 12:20:32 +01:00
snd_mixer_close ( handle ) ;
2005-12-01 12:32:28 +01:00
handle = NULL ;
2001-02-09 12:20:32 +01:00
return - ENOENT ;
}
2000-08-11 21:29:55 +02:00
if ( roflag )
goto __skip_write ;
2006-10-04 09:47:41 +02:00
check_flag = 0 ;
1999-07-21 13:52:55 +02:00
for ( idx = 1 ; idx < argc ; idx + + ) {
2001-08-27 11:15:44 +02:00
char * ptr = argv [ idx ] , * optr ;
2001-09-20 10:31:12 +02:00
int multi , firstchn = 1 ;
2001-08-27 11:15:44 +02:00
channels = channels_mask ( & ptr , channels ) ;
if ( * ptr = = ' \0 ' )
2000-03-18 19:00:37 +01:00
continue ;
2001-08-27 11:15:44 +02:00
dir = dir_mask ( & ptr , dir ) ;
if ( * ptr = = ' \0 ' )
2000-03-18 19:00:37 +01:00
continue ;
2001-08-27 11:15:44 +02:00
multi = ( strchr ( ptr , ' , ' ) ! = NULL ) ;
optr = ptr ;
for ( chn = 0 ; chn < = SND_MIXER_SCHN_LAST ; chn + + ) {
char * sptr = NULL ;
int ival ;
2000-03-18 19:00:37 +01:00
2001-08-27 11:15:44 +02:00
if ( ! ( channels & ( 1 < < chn ) ) )
continue ;
2005-06-15 16:55:37 +02:00
/* enum control */
if ( snd_mixer_selem_is_enumerated ( elem ) ) {
int idx = get_enum_item_index ( elem , & ptr ) ;
2006-10-04 09:47:41 +02:00
if ( idx < 0 ) {
2005-06-15 16:55:37 +02:00
break ;
2006-10-04 09:47:41 +02:00
} else {
if ( snd_mixer_selem_set_enum_item ( elem , chn , idx ) > = 0 )
check_flag = 1 ;
}
2005-06-15 16:55:37 +02:00
if ( ! multi )
ptr = optr ;
continue ;
}
2001-08-27 11:15:44 +02:00
if ( ( dir & 1 ) & & snd_mixer_selem_has_playback_channel ( elem , chn ) ) {
sptr = ptr ;
if ( ! strncmp ( ptr , " mute " , 4 ) & & snd_mixer_selem_has_playback_switch ( elem ) ) {
snd_mixer_selem_get_playback_switch ( elem , chn , & ival ) ;
2006-10-04 09:47:41 +02:00
if ( snd_mixer_selem_set_playback_switch ( elem , chn , get_bool_simple ( & ptr , " mute " , 1 , ival ) ) > = 0 )
check_flag = 1 ;
2001-08-27 11:15:44 +02:00
} else if ( ! strncmp ( ptr , " off " , 3 ) & & snd_mixer_selem_has_playback_switch ( elem ) ) {
snd_mixer_selem_get_playback_switch ( elem , chn , & ival ) ;
2006-10-04 09:47:41 +02:00
if ( snd_mixer_selem_set_playback_switch ( elem , chn , get_bool_simple ( & ptr , " off " , 1 , ival ) ) > = 0 )
check_flag = 1 ;
2001-08-27 11:15:44 +02:00
} else if ( ! strncmp ( ptr , " unmute " , 6 ) & & snd_mixer_selem_has_playback_switch ( elem ) ) {
snd_mixer_selem_get_playback_switch ( elem , chn , & ival ) ;
2006-10-04 09:47:41 +02:00
if ( snd_mixer_selem_set_playback_switch ( elem , chn , get_bool_simple ( & ptr , " unmute " , 0 , ival ) ) > = 0 )
check_flag = 1 ;
2001-08-27 11:15:44 +02:00
} else if ( ! strncmp ( ptr , " on " , 2 ) & & snd_mixer_selem_has_playback_switch ( elem ) ) {
snd_mixer_selem_get_playback_switch ( elem , chn , & ival ) ;
2006-10-04 09:47:41 +02:00
if ( snd_mixer_selem_set_playback_switch ( elem , chn , get_bool_simple ( & ptr , " on " , 0 , ival ) ) > = 0 )
check_flag = 1 ;
2001-09-20 10:31:12 +02:00
} else if ( ! strncmp ( ptr , " toggle " , 6 ) & & snd_mixer_selem_has_playback_switch ( elem ) ) {
if ( firstchn | | ! snd_mixer_selem_has_playback_switch_joined ( elem ) ) {
snd_mixer_selem_get_playback_switch ( elem , chn , & ival ) ;
2006-10-04 09:47:41 +02:00
if ( snd_mixer_selem_set_playback_switch ( elem , chn , ( ival ? 1 : 0 ) ^ 1 ) > = 0 )
check_flag = 1 ;
2001-09-20 10:31:12 +02:00
}
simple_skip_word ( & ptr , " toggle " ) ;
} else if ( isdigit ( * ptr ) | | * ptr = = ' - ' | | * ptr = = ' + ' ) {
2006-10-04 09:47:41 +02:00
if ( set_volume_simple ( elem , chn , & ptr , 0 ) > = 0 )
check_flag = 1 ;
2001-08-27 11:15:44 +02:00
} else if ( simple_skip_word ( & ptr , " cap " ) | | simple_skip_word ( & ptr , " rec " ) | |
simple_skip_word ( & ptr , " nocap " ) | | simple_skip_word ( & ptr , " norec " ) ) {
/* nothing */
} else {
2005-09-22 14:47:02 +02:00
okflag & = ~ 1 ;
2001-08-27 11:15:44 +02:00
}
1999-07-22 20:10:19 +02:00
}
2001-08-27 11:15:44 +02:00
if ( ( dir & 2 ) & & snd_mixer_selem_has_capture_channel ( elem , chn ) ) {
if ( sptr ! = NULL )
ptr = sptr ;
sptr = ptr ;
if ( ! strncmp ( ptr , " cap " , 3 ) & & snd_mixer_selem_has_capture_switch ( elem ) ) {
snd_mixer_selem_get_capture_switch ( elem , chn , & ival ) ;
2006-10-04 09:47:41 +02:00
if ( snd_mixer_selem_set_capture_switch ( elem , chn , get_bool_simple ( & ptr , " cap " , 0 , ival ) ) > = 0 )
check_flag = 1 ;
2001-08-27 11:15:44 +02:00
} else if ( ! strncmp ( ptr , " rec " , 3 ) & & snd_mixer_selem_has_capture_switch ( elem ) ) {
snd_mixer_selem_get_capture_switch ( elem , chn , & ival ) ;
2006-10-04 09:47:41 +02:00
if ( snd_mixer_selem_set_capture_switch ( elem , chn , get_bool_simple ( & ptr , " rec " , 0 , ival ) ) > = 0 )
check_flag = 1 ;
2001-08-27 11:15:44 +02:00
} else if ( ! strncmp ( ptr , " nocap " , 5 ) & & snd_mixer_selem_has_capture_switch ( elem ) ) {
snd_mixer_selem_get_capture_switch ( elem , chn , & ival ) ;
2006-10-04 09:47:41 +02:00
if ( snd_mixer_selem_set_capture_switch ( elem , chn , get_bool_simple ( & ptr , " nocap " , 1 , ival ) ) > = 0 )
check_flag = 1 ;
2001-08-27 11:15:44 +02:00
} else if ( ! strncmp ( ptr , " norec " , 5 ) & & snd_mixer_selem_has_capture_switch ( elem ) ) {
snd_mixer_selem_get_capture_switch ( elem , chn , & ival ) ;
2006-10-04 09:47:41 +02:00
if ( snd_mixer_selem_set_capture_switch ( elem , chn , get_bool_simple ( & ptr , " norec " , 1 , ival ) ) > = 0 )
check_flag = 1 ;
2001-09-20 10:31:12 +02:00
} else if ( ! strncmp ( ptr , " toggle " , 6 ) & & snd_mixer_selem_has_capture_switch ( elem ) ) {
if ( firstchn | | ! snd_mixer_selem_has_capture_switch_joined ( elem ) ) {
snd_mixer_selem_get_capture_switch ( elem , chn , & ival ) ;
2006-10-04 09:47:41 +02:00
if ( snd_mixer_selem_set_capture_switch ( elem , chn , ( ival ? 1 : 0 ) ^ 1 ) > = 0 )
check_flag = 1 ;
2001-09-20 10:31:12 +02:00
}
simple_skip_word ( & ptr , " toggle " ) ;
} else if ( isdigit ( * ptr ) | | * ptr = = ' - ' | | * ptr = = ' + ' ) {
2006-10-04 09:47:41 +02:00
if ( set_volume_simple ( elem , chn , & ptr , 1 ) > = 0 )
check_flag = 1 ;
2001-08-27 11:15:44 +02:00
} else if ( simple_skip_word ( & ptr , " mute " ) | | simple_skip_word ( & ptr , " off " ) | |
simple_skip_word ( & ptr , " unmute " ) | | simple_skip_word ( & ptr , " on " ) ) {
/* nothing */
} else {
2005-09-22 14:39:26 +02:00
okflag & = ~ 2 ;
2001-08-27 11:15:44 +02:00
}
}
2005-09-22 14:39:26 +02:00
if ( okflag = = 0 ) {
2005-12-01 12:32:28 +01:00
if ( debugflag ) {
if ( dir & 1 )
2006-10-04 09:47:41 +02:00
error ( " Unknown playback setup '%s'.. " , ptr ) ;
2005-12-01 12:32:28 +01:00
if ( dir & 2 )
2006-10-04 09:47:41 +02:00
error ( " Unknown capture setup '%s'.. " , ptr ) ;
2005-12-01 12:32:28 +01:00
}
if ( ! keep_handle ) {
snd_mixer_close ( handle ) ;
handle = NULL ;
}
return 0 ;
2005-09-22 14:39:26 +02:00
}
2001-08-27 11:15:44 +02:00
if ( ! multi )
ptr = optr ;
2001-09-20 10:31:12 +02:00
firstchn = 0 ;
1999-07-21 13:52:55 +02:00
}
2006-10-04 09:47:41 +02:00
}
if ( ! check_flag ) {
error ( " Invalid command! " ) ;
if ( ! keep_handle ) {
snd_mixer_close ( handle ) ;
handle = NULL ;
}
return 1 ;
}
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
}
2005-12-01 12:32:28 +01:00
if ( ! keep_handle ) {
snd_mixer_close ( handle ) ;
handle = NULL ;
}
1999-07-21 13:52:55 +02:00
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-03-26 14:45:50 +02:00
if ( ( err = snd_hctl_open ( & handle , card , 0 ) ) < 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 ) ;
2005-05-13 19:30:00 +02:00
return 0 ;
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-03-26 14:45:50 +02:00
if ( ( err = snd_mixer_open ( & handle , 0 ) ) < 0 ) {
2001-02-11 16:45:44 +01:00
error ( " Mixer %s open error: %s " , card , snd_strerror ( err ) ) ;
return err ;
}
2005-06-06 16:02:10 +02:00
if ( smixer_level = = 0 & & ( err = snd_mixer_attach ( handle , card ) ) < 0 ) {
2001-02-11 16:45:44 +01:00
error ( " Mixer attach %s error: %s " , card , snd_strerror ( err ) ) ;
snd_mixer_close ( handle ) ;
return err ;
}
2005-03-27 14:50:34 +02:00
if ( ( err = snd_mixer_selem_register ( handle , smixer_level > 0 ? & smixer_options : NULL , NULL ) ) < 0 ) {
2001-02-11 16:45:44 +01:00
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 ) {
2004-02-24 10:19:31 +01:00
error ( " Mixer %s 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 ) ;
2005-05-13 19:30:00 +02:00
return 0 ;
2000-08-16 15:36:24 +02:00
}
2005-12-01 12:32:28 +01:00
/*
* split a line into tokens
* the content in the line buffer is modified
*/
static int split_line ( char * buf , char * * token , int max_token )
{
char * dst ;
int n , esc , quote ;
for ( n = 0 ; n < max_token ; n + + ) {
while ( isspace ( * buf ) )
buf + + ;
if ( ! * buf | | * buf = = ' \n ' )
return n ;
/* skip comments */
if ( * buf = = ' # ' | | * buf = = ' ! ' )
return n ;
esc = 0 ;
quote = 0 ;
token [ n ] = buf ;
for ( dst = buf ; * buf & & * buf ! = ' \n ' ; buf + + ) {
if ( esc )
esc = 0 ;
else if ( isspace ( * buf ) & & ! quote ) {
buf + + ;
break ;
} else if ( * buf = = ' \\ ' ) {
esc = 1 ;
continue ;
} else if ( * buf = = ' \' ' | | * buf = = ' " ' ) {
if ( ! quote ) {
quote = * buf ;
continue ;
} else if ( * buf = = quote ) {
quote = 0 ;
continue ;
}
}
* dst + + = * buf ;
}
* dst = 0 ;
}
return n ;
}
# define MAX_ARGS 32
static int exec_stdin ( void )
{
int narg ;
char buf [ 256 ] , * args [ MAX_ARGS ] ;
int err = 0 ;
/* quiet = 1; */
ignore_error = 1 ;
while ( fgets ( buf , sizeof ( buf ) , stdin ) ) {
narg = split_line ( buf , args , MAX_ARGS ) ;
if ( narg > 0 ) {
if ( ! strcmp ( args [ 0 ] , " sset " ) | | ! strcmp ( args [ 0 ] , " set " ) )
err = sset ( narg - 1 , args + 1 , 0 , 1 ) ;
else if ( ! strcmp ( args [ 0 ] , " cset " ) )
err = cset ( narg - 1 , args + 1 , 0 , 1 ) ;
if ( err < 0 )
return 1 ;
}
}
return 0 ;
}
1999-05-02 18:21:40 +02:00
int main ( int argc , char * argv [ ] )
{
2001-07-23 15:26:34 +02:00
int morehelp , level = 0 ;
2005-12-01 12:32:28 +01:00
int read_stdin = 0 ;
static struct option long_option [ ] =
1999-05-02 18:21:40 +02:00
{
2005-12-01 12:32:28 +01:00
{ " help " , 0 , NULL , ' h ' } ,
{ " card " , 1 , NULL , ' c ' } ,
{ " device " , 1 , NULL , ' D ' } ,
{ " quiet " , 0 , NULL , ' q ' } ,
{ " inactive " , 0 , NULL , ' i ' } ,
{ " debug " , 0 , NULL , ' d ' } ,
{ " nocheck " , 0 , NULL , ' n ' } ,
{ " version " , 0 , NULL , ' v ' } ,
{ " abstract " , 1 , NULL , ' a ' } ,
{ " stdin " , 0 , NULL , ' s ' } ,
1999-05-02 18:21:40 +02:00
{ NULL , 0 , NULL , 0 } ,
} ;
morehelp = 0 ;
while ( 1 ) {
int c ;
2005-12-01 12:32:28 +01:00
if ( ( c = getopt_long ( argc , argv , " hc:D:qidnva:s " , long_option , NULL ) ) < 0 )
1999-05-02 18:21:40 +02:00
break ;
switch ( c ) {
case ' h ' :
2005-01-31 14:52:09 +01:00
help ( ) ;
return 0 ;
1999-05-02 18:21:40 +02:00
case ' c ' :
2002-04-07 22:42:20 +02:00
{
int i ;
i = snd_card_get_index ( optarg ) ;
if ( i > = 0 & & i < 32 )
sprintf ( card , " hw:%i " , i ) ;
else {
fprintf ( stderr , " \07 Invalid card number. \n " ) ;
morehelp + + ;
}
}
break ;
case ' D ' :
2004-08-10 11:46:19 +02:00
strncpy ( card , optarg , sizeof ( card ) - 1 ) ;
2003-10-17 09:34:19 +02:00
card [ sizeof ( card ) - 1 ] = ' \0 ' ;
1999-05-02 18:21:40 +02:00
break ;
case ' q ' :
quiet = 1 ;
break ;
2001-07-23 15:26:34 +02:00
case ' i ' :
level | = LEVEL_INACTIVE ;
break ;
2002-04-07 22:42:20 +02:00
case ' d ' :
1999-05-02 18:21:40 +02:00
debugflag = 1 ;
break ;
2005-02-04 16:35:27 +01:00
case ' n ' :
no_check = 1 ;
break ;
1999-05-02 18:21:40 +02:00
case ' v ' :
printf ( " amixer version " SND_UTIL_VERSION_STR " \n " ) ;
return 1 ;
2005-03-27 14:50:34 +02:00
case ' a ' :
smixer_level = 1 ;
memset ( & smixer_options , 0 , sizeof ( smixer_options ) ) ;
smixer_options . ver = 1 ;
if ( ! strcmp ( optarg , " none " ) )
smixer_options . abstract = SND_MIXER_SABSTRACT_NONE ;
else if ( ! strcmp ( optarg , " basic " ) )
2005-03-29 16:06:29 +02:00
smixer_options . abstract = SND_MIXER_SABSTRACT_BASIC ;
2005-03-27 14:50:34 +02:00
else {
fprintf ( stderr , " Select correct abstraction level (none or basic)... \n " ) ;
morehelp + + ;
}
break ;
2005-12-01 12:32:28 +01:00
case ' s ' :
read_stdin = 1 ;
break ;
1999-05-02 18:21:40 +02:00
default :
fprintf ( stderr , " \07 Invalid switch or option needs an argument. \n " ) ;
morehelp + + ;
}
}
if ( morehelp ) {
help ( ) ;
2005-01-31 14:52:09 +01:00
return 1 ;
1999-05-02 18:21:40 +02:00
}
2005-06-06 16:02:10 +02:00
smixer_options . device = card ;
2005-12-01 12:32:28 +01:00
if ( read_stdin )
return exec_stdin ( ) ;
1999-05-02 18:21:40 +02:00
if ( argc - optind < = 0 ) {
2001-07-23 15:26:34 +02:00
return selems ( LEVEL_BASIC | level ) ? 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 " ) ) {
2001-07-23 15:26:34 +02:00
return controls ( level ) ? 1 : 0 ;
1999-05-02 18:21:40 +02:00
} else if ( ! strcmp ( argv [ optind ] , " contents " ) ) {
2001-07-23 15:26:34 +02:00
return controls ( LEVEL_BASIC | level ) ? 1 : 0 ;
2000-08-11 21:29:55 +02:00
} else if ( ! strcmp ( argv [ optind ] , " scontrols " ) | | ! strcmp ( argv [ optind ] , " simple " ) ) {
2001-07-23 15:26:34 +02:00
return selems ( level ) ? 1 : 0 ;
2000-07-15 12:21:59 +02:00
} else if ( ! strcmp ( argv [ optind ] , " scontents " ) ) {
2001-07-23 15:26:34 +02:00
return selems ( LEVEL_BASIC | level ) ? 1 : 0 ;
2000-08-11 21:29:55 +02:00
} else if ( ! strcmp ( argv [ optind ] , " sset " ) | | ! strcmp ( argv [ optind ] , " set " ) ) {
2005-12-01 12:32:28 +01:00
return sset ( argc - optind - 1 , argc - optind > 1 ? argv + optind + 1 : NULL , 0 , 0 ) ? 1 : 0 ;
2000-08-11 21:29:55 +02:00
} else if ( ! strcmp ( argv [ optind ] , " sget " ) | | ! strcmp ( argv [ optind ] , " get " ) ) {
2005-12-01 12:32:28 +01:00
return sset ( argc - optind - 1 , argc - optind > 1 ? argv + optind + 1 : NULL , 1 , 0 ) ? 1 : 0 ;
2000-07-15 12:21:59 +02:00
} else if ( ! strcmp ( argv [ optind ] , " cset " ) ) {
2005-12-01 12:32:28 +01:00
return cset ( argc - optind - 1 , argc - optind > 1 ? argv + optind + 1 : NULL , 0 , 0 ) ? 1 : 0 ;
2000-07-15 12:21:59 +02:00
} else if ( ! strcmp ( argv [ optind ] , " cget " ) ) {
2005-12-01 12:32:28 +01:00
return cset ( argc - optind - 1 , argc - optind > 1 ? argv + optind + 1 : NULL , 1 , 0 ) ? 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 ;
}