rendered paste body#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <alsa/asoundlib.h>
/*
FIXME: If needed, allow the selection of another card besides "default"
ALSO: Handle the channels better. ;)
*/
/*
typedef struct opt_s {
char *name;
enum { opt_flag, opt_optinal, opt_required } type;
char *value;
} opt_t;
opt_t opts[] = {
{ "get", opt_flag, NULL },
{ "set", opt_required, NULL },
{ "inc", opt_flag, NULL },
{ "dec", opt_flag, NULL },
{ "sr", opt_flag, NULL },
{ "er", opt_flag, NULL },
{ "card", opt_required, NULL },
{ "elem", opt_required, NULL },
{ NULL, 0, NULL },
};
int parseopts(int argc, char **argv)
{
int i = 0;
for(i=0; i<argc-1; i++) {
if(strcmp(argv[i], "--")==0) break;
}
return i;
}
*/
#ifdef DEBUG
#define debug(a,b...) printf(a, ##b)
#else
#define debug(a,b...) (void)0
#endif
int main(int argc, char **argv)
{
snd_mixer_t *mixer = NULL;
snd_mixer_elem_t *elem = NULL;
enum { GET=1, SET, INC, DEC, START_RANGE, END_RANGE } mode;
if(argc < 3)
goto useage;
if(strcasecmp(argv[1], "GET") != 0) {
if(strcasecmp(argv[1], "SET") != 0) {
if(strcasecmp(argv[1], "INC") != 0) {
if(strcasecmp(argv[1], "DEC") != 0) {
if(strcasecmp(argv[1], "SRANGE") != 0) {
if(strcasecmp(argv[1], "ERANGE") != 0) {
goto useage;
} else
mode = END_RANGE;
} else
mode = START_RANGE;
} else {
mode = DEC;
}
} else {
mode = INC;
}
} else {
if(argc < 4)
goto useage;
mode = SET;
}
} else
mode = GET;
debug("opening mixer\n");
{
char *string = NULL;
int i = 0;
while(i > -1) {
snd_card_get_name(i, &string);
//printf("Card name: \"%s\"\n", string);
snd_card_next(&i);
}
}
if(snd_mixer_open(&mixer, 0) < 0) {
debug("Failed...\n");
exit(EXIT_FAILURE);
}
debug("attaching card to mixer\n");
if(snd_mixer_attach(mixer, "default") < 0) {
debug("Failed...\n");
exit(EXIT_FAILURE);
}
if(snd_mixer_selem_register (mixer, NULL, NULL) < 0) {
debug("Failed...\n");
exit(EXIT_FAILURE);
}
debug("loading mixer elems\n");
if(snd_mixer_load(mixer) < 0) {
debug("Failed...\n");
exit(EXIT_FAILURE);
}
elem = snd_mixer_first_elem(mixer);
while(elem) {
const char *name = snd_mixer_selem_get_name(elem);
long min=0, max=0;
unsigned int id = snd_mixer_selem_get_index(elem);
//printf("elem \"%s\" == \"%i\"\n", name, id);
if(strcasecmp(name, argv[2]) != 0) {
elem = snd_mixer_elem_next(elem);
continue;
}
switch(mode) {
case GET: {
long vol = 0;
snd_mixer_selem_get_playback_volume(elem, 0, &vol);
printf("%li\n", vol);
} break;
case SET: {
long vol = strtol(argv[3], NULL, 0);
snd_mixer_selem_set_playback_volume(elem, 0, vol);
snd_mixer_selem_set_playback_volume(elem, 1, vol);
} break;
case INC: {
long inc = argc > 3 ? strtol(argv[3], NULL, 0) : 1, vol = 0;
snd_mixer_selem_get_playback_volume(elem, 0, &vol);
snd_mixer_selem_set_playback_volume(elem, 0, vol+inc);
snd_mixer_selem_set_playback_volume(elem, 1, vol+inc);
} break;
case DEC: {
long dec = argc > 3 ? strtol(argv[3], NULL, 0) : 1, vol = 0;
snd_mixer_selem_get_playback_volume(elem, 0, &vol);
snd_mixer_selem_set_playback_volume(elem, 0, vol-dec);
snd_mixer_selem_set_playback_volume(elem, 1, vol-dec);
} break;
case START_RANGE: {
snd_mixer_selem_get_playback_volume_range(elem, &min, &max);
printf("%li\n", min);
} break;
case END_RANGE: {
snd_mixer_selem_get_playback_volume_range(elem, &min, &max);
printf("%li\n", max);
}
}
elem = snd_mixer_elem_next(elem);
// break;
}
snd_mixer_close(mixer);
return 0;
useage:
fprintf(stderr, "Useage: %s (set|get|inc|dec|srange|erange) \"control name\" <value>\n", argv[0]);
exit(EXIT_FAILURE);
}