Исходный код утилиты mix_ctl
Приложение захватывает группы и переключатели микшера:
/** (c) 2014, SWD Embedded Systems Limited, http://www.kpda.ru*//** $QNXLicenseC:* Copyright 2007, QNX Software Systems. All Rights Reserved.** You must obtain a written license from and pay applicable license fees to QNX* Software Systems before you may reproduce, modify or distribute this software,* or any work that includes all or part of this software. Free development* licenses are available for evaluation and non-commercial purposes. For more* information visit http://licensing.qnx.com or email licensing@qnx.com.** This file may contain contributions from others. Please review this entire* file for other proprietary rights or license notices, as well as the QNX* Development Suite License Guide at http://licensing.qnx.com/license-guide/* for other information.* $*/#include <errno.h>#include <fcntl.h>#include <fnmatch.h>#include <gulliver.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/ioctl.h>#include <sys/select.h>#include <sys/stat.h>#include <sys/termio.h>#include <sys/types.h>#include <unistd.h>#include <sys/asoundlib.h>//*****************************************************************************#ifdef __USAGE%C [Options] CmdsOptions:-a[card#:]<dev#> the card & mixer device number to accessCmds:groups [-d] [-c] [-p] [pattern]-d will print the group details-c will show only groups effecting capture-p will show only groups effecting playbackgroup name [mute[Y]=off|on] [capture[Y]=off|on] [volume[Y]=x|x%] ...- name is the group name quoted if it contains white space- the Y is a option the restricts the change to only one voice (if possible)switches [pattern]switch name [value]- name is the switch name quoted if it contains white space#endif//*****************************************************************************void display_group( snd_mixer_t * mixer_handle, snd_mixer_gid_t * gid, snd_mixer_group_t * group ){int j;printf( "\"%s\",%d - %s \n", gid->name, gid->index,group->caps & SND_MIXER_GRPCAP_PLAY_GRP ? "Playback Group" : "Capture Group" );printf( "\tCapabilities - " );if ( group->caps & SND_MIXER_GRPCAP_VOLUME )printf( " Volume" );if ( group->caps & SND_MIXER_GRPCAP_JOINTLY_MUTE )printf( " Jointly-Mute" );elseif ( group->caps & SND_MIXER_GRPCAP_MUTE )printf( " Mute" );if ( group->caps & SND_MIXER_GRPCAP_JOINTLY_CAPTURE )printf( " Jointly-Capture" );if ( group->caps & SND_MIXER_GRPCAP_EXCL_CAPTURE )printf( " Exclusive-Capture" );elseif ( group->caps & SND_MIXER_GRPCAP_CAPTURE )printf( " Capture" );printf ("\n");printf ("\tChannels - ");for ( j = 0; j <= SND_MIXER_CHN_LAST; j++ ){if ( !(group->channels & (1 << j)) )continue;printf( "%s ", snd_mixer_channel_name( j ) );}printf ("\n");printf( "\tVolume Range - minimum=%i, maximum=%i\n", group->min, group->max );for ( j = 0; j <= SND_MIXER_CHN_LAST; j++ ){if ( !(group->channels & (1 << j)) )continue;printf( "\tChannel %d %-12.12s - %3d (%3d%%) %s %s\n", j,snd_mixer_channel_name( j ),group->volume.values[j],(group->max - group->min) <= 0 ? 0 : 100 * (group->volume.values[j] - group->min) / (group->max - group->min),group->mute & (1 << j) ? "Muted" : "",group->capture & (1 << j) ? "Capture" : "" );}}void display_groups( snd_mixer_t * mixer_handle, int argc, char *argv[] ){char details = 0;char playback_only = 0,capture_only = 0;char *pattern;snd_mixer_groups_t groups;int i;int rtn;snd_mixer_group_t group;optind = 1;while ( (i = getopt( argc, argv, "cdp" )) != EOF ){switch ( i ){case 'c':capture_only = 1;playback_only = 0;break;case 'd':details = 1;break;case 'p':capture_only = 0;playback_only = 1;break;}}pattern = (optind >= argc) ? "*" : argv[optind];while ( 1 ){memset( &groups, 0, sizeof( groups ) );if ( snd_mixer_groups( mixer_handle, &groups ) < 0 )fprintf( stderr, "snd_mixer_groups API call - %s", strerror( errno ) );elseif ( groups.groups == 0 ){fprintf( stderr, "--> No mixer groups to list <-- \n" );break;}if ( groups.groups_over > 0 ){groups.groups_size = groups.groups_over;groups.pgroups = (snd_mixer_gid_t *)malloc( sizeof( snd_mixer_gid_t ) * groups.groups_size );if ( groups.pgroups == NULL )fprintf( stderr, "Unable to malloc group array - %s", strerror( errno ) );groups.groups_over = 0;groups.groups = 0;if ( snd_mixer_groups( mixer_handle, &groups ) < 0 )fprintf( stderr, "No Mixer Groups " );if ( groups.groups_over > 0 ){free( groups.pgroups );continue;} else {snd_mixer_sort_gid_table( groups.pgroups, groups.groups_size, snd_mixer_default_weights );break;}}}for ( i = 0; i < groups.groups; i++ ){if ( fnmatch( pattern, groups.pgroups[i].name, 0 ) == 0 ){memset( &group, 0, sizeof( group ));memcpy( &group.gid, &groups.pgroups[i], sizeof( snd_mixer_gid_t ) );if ( (rtn = snd_mixer_group_read( mixer_handle, &group )) < 0 )fprintf( stderr, "snd_mixer_group_read failed: %s\n", snd_strerror( rtn ) );if ( playback_only && group.caps & SND_MIXER_GRPCAP_CAP_GRP )continue;if ( capture_only && group.caps & SND_MIXER_GRPCAP_PLAY_GRP )continue;if ( details )display_group( mixer_handle, &groups.pgroups[i], &group );else{printf( "\"%s\",%d%*c - %s \n",groups.pgroups[i].name,groups.pgroups[i].index,2 + sizeof (groups.pgroups[i].name) - strlen (groups.pgroups[i].name),' ',group.caps & SND_MIXER_GRPCAP_PLAY_GRP ? "Playback Group" : "Capture Group" );}}}}int find_group_best_match( snd_mixer_t *mixer_handle, snd_mixer_gid_t *gid, snd_mixer_group_t *group ){snd_mixer_groups_t groups;int i;while ( 1 ){memset( &groups, 0, sizeof( groups ) );if ( snd_mixer_groups( mixer_handle, &groups ) < 0 ){fprintf( stderr, "snd_mixer_groups API call - %s", strerror( errno ) );}if ( groups.groups_over > 0 ){groups.groups_size = groups.groups_over;groups.pgroups = (snd_mixer_gid_t *)malloc( sizeof( snd_mixer_gid_t ) * groups.groups_size );if ( groups.pgroups == NULL )fprintf( stderr, "Unable to malloc group array - %s", strerror( errno ) );groups.groups_over = 0;groups.groups = 0;if ( snd_mixer_groups( mixer_handle, &groups ) < 0 )fprintf( stderr, "No Mixer Groups " );if ( groups.groups_over > 0 ){free( groups.pgroups );continue;} elsebreak;}}for ( i = 0; i < groups.groups; i++ ){if ( stricmp( gid->name, groups.pgroups[i].name ) == 0 && gid->index == groups.pgroups[i].index ){memset( group, 0, sizeof( group ) );memcpy( gid, &groups.pgroups[i], sizeof( snd_mixer_gid_t ) );memcpy( &group->gid, &groups.pgroups[i], sizeof( snd_mixer_gid_t ) );if ( (snd_mixer_group_read( mixer_handle, group )) < 0 )return ENOENT;elsereturn EOK;}}return ENOENT;}int group_option_value( char *option ){char *ptr;int value;if ( (ptr = strrchr( option, '=' )) != NULL ){if ( *(ptr + 1) == 0 )value = -2;else if ( stricmp( ptr + 1, "off" ) == 0 )value = 0;else if ( stricmp( ptr + 1, "on" ) == 0 )value = 1;elsevalue = atoi( ptr + 1 );} elsevalue = -1;return (value);}void modify_group( snd_mixer_t * mixer_handle, int argc, char *argv[] ){int optind = 1;snd_mixer_gid_t gid;char *ptr;int rtn;snd_mixer_group_t group;uint32_t channel = 0,j;int32_t value;char modified = 0;if ( optind >= argc ){fprintf( stderr, "No Group specified \n" );return;}memset( &gid, 0, sizeof( gid ) );ptr = strtok (argv[optind++], ",");strncpy( gid.name, ptr, sizeof( gid.name ) );ptr = strtok( NULL, " " );if ( ptr != NULL )gid.index = atoi( ptr );memset( &group, 0, sizeof( group ) );memcpy( &group.gid, &gid, sizeof( snd_mixer_gid_t ) );if ( (rtn = snd_mixer_group_read( mixer_handle, &group )) < 0 ){if ( rtn == -ENXIO )rtn = find_group_best_match( mixer_handle, &gid, &group );if ( rtn != EOK ){fprintf( stderr, "snd_mixer_group_read failed: %s\n", snd_strerror( rtn ) );return;}}/* if we have a value option set the group, write and reread it (to get true driver state) *//* some things like capture (MUX) can't be turned off but can only be set on another group */while ( optind < argc ){modified = 1;if ( (value = group_option_value( argv[optind] )) < 0 )printf( "\n\t>>>> Unrecognized option [%s] <<<<\n\n", argv[optind] );else if ( strnicmp( argv[optind], "mute", 4 ) == 0 ){if ( argv[optind][4] == '=' )channel = LONG_MAX;elsechannel = atoi( &argv[optind][4] );if ( channel == LONG_MAX )group.mute = value ? LONG_MAX : 0;else {group.mute = value ? group.mute | (1 << channel) : group.mute & ~(1 << channel);}} else if ( strnicmp( argv[optind], "capture", 7 ) == 0 ){if ( argv[optind][7] == '=' )channel = LONG_MAX;elsechannel = atoi( &argv[optind][7] );if ( channel == LONG_MAX )group.capture = value ? LONG_MAX : 0;elsegroup.capture = value ? group.capture | (1 << channel) : group.capture & ~(1 << channel);}else if ( strnicmp( argv[optind], "volume", 6 ) == 0 ){if ( argv[optind][6] == '=' )channel = LONG_MAX;elsechannel = atoi (&argv[optind][6]);if ( argv[optind][strlen( argv[optind] ) - 1] == '%' && (group.max - group.min) >= 0 )value = (value * (group.max - group.min)) / 100 + group.min;if ( value > group.max )value = group.max;if ( value < group.min )value = group.min;for ( j = 0; j <= SND_MIXER_CHN_LAST; j++ ){if ( !(group.channels & (1 << j)) )continue;if ( channel == LONG_MAX || channel == j )group.volume.values[j] = value;}} else if ( strnicmp( argv[optind], "delay", 5 ) == 0 ){if ( argv[optind][5] == '=' )group.change_duration = value;elsegroup.change_duration = 50000;} elseprintf( "\n\t>>>> Unrecognized option [%s] <<<<\n\n", argv[optind] );if ( channel != LONG_MAX && !(group.channels & (1 << channel)) )printf( "\n\t>>>> Channel specified [%d] Not in group <<<<\n\n", channel );optind++;}if ( modified )if ( (rtn = snd_mixer_group_write( mixer_handle, &group )) < 0 )fprintf( stderr, "snd_mixer_group_write failed: %s\n", snd_strerror( rtn ) );if ( (rtn = snd_mixer_group_read( mixer_handle, &group )) < 0 )fprintf( stderr, "snd_mixer_group_read failed: %s\n", snd_strerror( rtn ) );/* display the current group state */display_group( mixer_handle, &gid, &group );}void display_switch( snd_switch_t * sw, char table_formatted ){printf( "\"%s\"%*c ", sw->name, table_formatted ? sizeof( sw->name ) - strlen( sw->nam) : 1, ' ' );switch ( sw->type ){case SND_SW_TYPE_BOOLEAN:printf( "%s %s \n", "BOOLEAN", sw->value.enable ? "on" : "off" );break;case SND_SW_TYPE_BYTE:printf( "%s %d \n", "BYTE ", sw->value.byte.data );break;case SND_SW_TYPE_WORD:printf( "%s %d \n", "WORD ", sw->value.word.data );break;case SND_SW_TYPE_DWORD:printf( "%s %d \n", "DWORD ", sw->value.dword.data );break;case SND_SW_TYPE_LIST:if ( sw->subtype == SND_SW_SUBTYPE_HEXA )printf( "%s 0x%x \n", "LIST ", sw->value.list.data );elseprintf( "%s %d \n", "LIST ", sw->value.list.data );break;case SND_SW_TYPE_STRING_11:printf( "%s \"%s\" \n", "STRING ", sw->value.string_11.strings[sw->value.string_11.selection] );break;default:printf( "%s %d \n", "? ", 0 );}}void display_switches( snd_ctl_t * ctl_handle, int mixer_dev, int argc, char *argv[] ){int i;char *pattern;snd_switch_list_t list;snd_switch_t sw;int rtn;optind = 1;while ( (i = getopt( argc, argv, "d" )) != EOF ){switch (i){}}pattern = (optind >= argc) ? "*" : argv[optind];while ( 1 ){memset( &list, 0, sizeof( list ) );if ( snd_ctl_mixer_switch_list( ctl_handle, mixer_dev, &list ) < 0 ){fprintf( stderr, "snd_ctl_mixer_switch_list API call - %s", strerror( errno ) );}else if ( list.switches == 0 ){fprintf( stderr, "--> No mixer switches to list <-- \n" );break;}if ( list.switches_over > 0 ){list.switches_size = list.switches_over;list.pswitches = malloc( sizeof( snd_switch_list_item_t ) * list.switches_size );if ( list.pswitches == NULL )fprintf( stderr, "Unable to malloc switch array - %s", strerror( errno ) );list.switches_over = 0;list.switches = 0;if ( snd_ctl_mixer_switch_list( ctl_handle, mixer_dev, &list ) < 0 )fprintf( stderr, "No Switches " );if ( list.switches_over > 0 ){free( list.pswitches );continue;} elsebreak;}}for ( i = 0; i < list.switches_size; i++ ){memset( &sw, 0, sizeof( sw ) );strncpy( sw.name, (&list.pswitches[i])->name, sizeof( sw.name ) );if ( (rtn = snd_ctl_mixer_switch_read( ctl_handle, mixer_dev, &sw )) < 0 )fprintf( stderr, "snd_ctl_mixer_switch_read failed: %s\n", snd_strerror( rtn ) );display_switch( &sw, 1 );}}void modify_switch( snd_ctl_t * ctl_handle, int mixer_dev, int argc, char *argv[] ){int optind = 1;snd_switch_t sw;int rtn;int value = 0;char *string = NULL;if ( optind >= argc ){fprintf( stderr, "No Switch specified \n" );return;}memset( &sw, 0, sizeof( sw ) );strncpy( sw.name, argv[optind++], sizeof( sw.name ) );if ( (rtn = snd_ctl_mixer_switch_read( ctl_handle, mixer_dev, &sw )) < 0 ){fprintf( stderr, "snd_ctl_mixer_switch_read failed: %s\n", snd_strerror( rtn ) );return;}/* if we have a value option set the sw, write and reread it (to get true driver state) */if ( optind < argc ){if ( stricmp( argv[optind], "off" ) == 0 )value = 0;else if ( stricmp( argv[optind], "on" ) == 0 )value = 1;else if ( strnicmp( argv[optind], "0x", 2 ) == 0 )value = strtol( argv[optind], NULL, 16 );else {value = atoi( argv[optind] );string = argv[optind];}optind++;if ( sw.type == SND_SW_TYPE_BOOLEAN )sw.value.enable = value;else if ( sw.type == SND_SW_TYPE_BYTE )sw.value.byte.data = value;else if ( sw.type == SND_SW_TYPE_WORD )sw.value.word.data = value;else if ( sw.type == SND_SW_TYPE_DWORD )sw.value.dword.data = value;else if ( sw.type == SND_SW_TYPE_LIST )sw.value.list.data = value;else if ( sw.type == SND_SW_TYPE_STRING_11 ){for ( rtn = 0; rtn < sw.value.string_11.strings_cnt; rtn++ ){if ( stricmp( string, sw.value.string_11.strings[rtn] ) == 0 ){sw.value.string_11.selection = rtn;break;}}if ( rtn == sw.value.string_11.strings_cnt ){fprintf( stderr, "ERROR string \"%s\" NOT IN LIST \n", string );snd_ctl_mixer_switch_read( ctl_handle, mixer_dev, &sw );}}if ( (rtn = snd_ctl_mixer_switch_write( ctl_handle, mixer_dev, &sw )) < 0 )fprintf( stderr, "snd_ctl_mixer_switch_write failed: %s\n", snd_strerror( rtn ) );if ( (rtn = snd_ctl_mixer_switch_read( ctl_handle, mixer_dev, &sw )) < 0 )fprintf( stderr, "snd_ctl_mixer_switch_read failed: %s\n", snd_strerror( rtn ) );}/* display the current switch state */display_switch( &sw, 0 );}int main( int argc, char *argv[] ){int c;int card = 0;int dev = 0;int rtn;snd_ctl_t *ctl_handle;snd_mixer_t *mixer_handle;optind = 1;while ( (c = getopt( argc, argv, "a:" )) != EOF ){switch ( c ){case 'a':if ( strchr( optarg, ':' ) ){card = atoi( optarg );dev = atoi( strchr( optarg, ':' ) + 1 );} elsedev = atoi( optarg );printf( "Using card %d device %d \n", card, dev );break;default:return 1;}}if ( (rtn = snd_ctl_open( &ctl_handle, card )) < 0 ){fprintf( stderr, "snd_ctlr_open failed: %s\n", snd_strerror( rtn ) );return -1;}if ( (rtn = snd_mixer_open( &mixer_handle, card, dev )) < 0 ){fprintf( stderr, "snd_mixer_open failed: %s\n", snd_strerror( rtn ) );return -1;}if ( optind >= argc )display_groups( mixer_handle, argc - optind, argv + optind );else if ( stricmp( argv[optind], "groups" ) == 0 )display_groups( mixer_handle, argc - optind, argv + optind );else if ( stricmp( argv[optind], "group" ) == 0 )modify_group( mixer_handle, argc - optind, argv + optind );else if ( stricmp( argv[optind], "switches" ) == 0 )display_switches( ctl_handle, dev, argc - optind, argv + optind );else if ( stricmp( argv[optind], "switch" ) == 0 )modify_switch( ctl_handle, dev, argc - optind, argv + optind );elsefprintf( stderr, "Unknown command specified \n" );snd_mixer_close( mixer_handle );snd_ctl_close( ctl_handle );return (0);}
Предыдущий раздел: Библиотека libasound