/* Copyright 2005 Red Hat, Inc. * * Portions extraced from various ALSA code: * Copyright (c) by Abramo Bagnara * Jaroslav Kysela * Takashi Iwai * Bernd Kaindl * Jan ONDREJ (SAL) * * This software may be freely redistributed under the terms of the GNU * public license. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #define VERSION "0.2" #include #include #include #include #include #define TRUE (1==1) #define FALSE (1!=1) int verbose = 0; typedef struct _CHANNEL { char name[100]; int play_volume; int play_switch; int rec_volume; int rec_switch; char driver[100]; } CHANNEL; CHANNEL channels[] = { // channel pl vol pl swt rec vol rec swt driver {"Master", 75, 1, 0, 0, ""}, {"Front", 75, 1, 0, 0, ""}, {"PCM", 75, 1, 0, 0, ""}, {"PCM-2", 75, 1, 0, 0, ""}, {"Synth", 75, 1, 0, 0, ""}, {"CD", 75, 1, 90, 1, ""}, {"Mono", 75, 1, 0, 0, ""}, {"Master Mono", 75, 1, 0, 0, ""}, {"Speaker", 75, 1, 0, 0, ""}, // mute mic {"Mic", 0, 0, 0, 0, ""}, // Trident/YMFPCI/emu10k1 {"Wave", 100, 1, 0, 0, ""}, {"Music", 100, 1, 0, 0, ""}, {"AC97", 100, 1, 0, 0, ""}, // CS4237B chipset {"Master Digital", 75, 1, 0, 0, ""}, // Envy24 chips with analog outs {"DAC", 75, 1, 0, 0, ""}, // Powermacs {"DRC Range", 75, 1, 0, 0, ""}, // some notebooks use headphone instead of master {"Headphone", 75, 1, 0, 0, ""}, {"Playback", 100, 1, 0, 0, ""}, // turn off digital switches {"SB Live Analog/Digital Output Jack", 0, 0, 0, 0, ""}, // removed - should by set by driver // {"Audigy Analog/Digital Output Jack", 0, 0, 0, 0, ""}, // Specific config for ca0106 {"Analog Front", 75, 1, 0, 0, "snd-ca0106"}, {"Analog Rear", 75, 1, 0, 0, "snd-ca0106"}, {"SPDIF Out", 0, 0, 0, 0, "snd-ca0106"}, // Specific config for snd-emu10k1 // Removed (#187807) // {"Audigy Analog/Digital Output Jack", 0,1,0, 0, "snd-emu10k1"}, {"IEC958 Optical Raw", 0, 0, 0, 0, "snd-emu10k1"}, {"Tone", 0, 0, 0, 0, "snd-emu10k1"}, // Specific config for AC97/HDA {"External Amplifier", 1, 1, 0, 0, "snd-intel8x0"}, {"iSpeaker", 75, 1, 0, 0, "snd-hda-intel"}, {"Internal Speaker", 75, 1, 0, 0, "snd-hda-intel"}, // Specific config for snd-ens1371 {"IEC958", 0, 0, 0, 0, "snd-ens1371"} }; char * strlwr(char *a) { char *ret = a; while (*a != '\0') { if (isupper (*a)) *a = tolower (*a); a++; } return ret; } CHANNEL * channel_find(const char *p_name, const char *p_driver) { int i; for (i = 0; i < sizeof(channels) / sizeof(channels[0]); i++) if (!strcmp(channels[i].driver, p_driver) && !strcmp(channels[i].name, p_name)) return (channels + i); return (NULL); } int calc_volume(long min, long max, int percent) { return ((int)(min + ((max - min) / 100.0f) * percent)); } int unmute_card(int index, const char *p_driver) { CHANNEL *p_chan; long pmin, pmax; long rmin, rmax; int rc = 0; char card[32]; char channel_name[500]; int c,vol; snd_mixer_t *handle; snd_mixer_selem_id_t *sid; snd_mixer_elem_t *elem; snd_mixer_selem_id_alloca(&sid); if(verbose) { fprintf(stderr,"Unmuting %s...\n",p_driver ? p_driver : ""); } sprintf(card, "hw:%d", index); if ((rc = snd_mixer_open(&handle, 0)) < 0) { if(verbose) { fprintf(stderr,"%s: error file %s, line %d...\n",__FUNCTION__,__FILE__,__LINE__); } return rc; } if ((rc = snd_mixer_attach(handle, card)) < 0) { if(verbose) { fprintf(stderr,"%s: error file %s, line %d...\n",__FUNCTION__,__FILE__,__LINE__); } goto out; } if ((rc = snd_mixer_selem_register(handle, NULL, NULL)) < 0) { if(verbose) { fprintf(stderr,"%s: error file %s, line %d...\n",__FUNCTION__,__FILE__,__LINE__); } goto out; } rc = snd_mixer_load(handle); if (rc < 0) { if(verbose) { fprintf(stderr,"%s: error file %s, line %d...\n",__FUNCTION__,__FILE__,__LINE__); } goto out; } for (elem = snd_mixer_first_elem(handle); elem; elem = snd_mixer_elem_next(elem)) { snd_mixer_selem_get_id(elem, sid); strncpy(channel_name,snd_mixer_selem_id_get_name(sid),500); channel_name[499] = '\0'; p_chan = channel_find(strlwr(channel_name),p_driver); if (!p_chan) continue; for (c = 0; c < SND_MIXER_SCHN_LAST; c++) { if (snd_mixer_selem_has_capture_channel(elem, c)) { if (snd_mixer_selem_has_capture_switch(elem)) { snd_mixer_selem_set_capture_switch(elem, c, p_chan->rec_switch); if(verbose) { fprintf(stderr,"Cap. Switch %s(%d) to %d\n",p_chan->name,c,p_chan->rec_switch); } } if (snd_mixer_selem_has_capture_volume(elem)) { snd_mixer_selem_get_capture_volume_range(elem, &rmin, &rmax); vol = calc_volume(rmin, rmax,p_chan->rec_volume); snd_mixer_selem_set_capture_volume(elem, c, vol); if(verbose) { fprintf(stderr,"Cap. Volume %s(%d) to %d\n",p_chan->name,c,vol); } } } if (snd_mixer_selem_has_playback_channel(elem, c)) { if (snd_mixer_selem_has_playback_switch(elem)) { snd_mixer_selem_set_playback_switch(elem, c, p_chan->play_switch); if(verbose) { fprintf(stderr,"Play. Switch %s(%d) to %d\n",p_chan->name,c,p_chan->play_switch); } } if (snd_mixer_selem_has_playback_volume(elem)) { snd_mixer_selem_get_playback_volume_range(elem, &pmin, &pmax); vol = calc_volume(pmin, pmax,p_chan->play_volume); snd_mixer_selem_set_playback_volume(elem, c, vol); if(verbose) { fprintf(stderr,"Play. Volume %s(%d) to %d\n",p_chan->name,c,vol); } } } } } return(TRUE); out: snd_mixer_close(handle); return rc; } char * check_driver_name(char *p_name) { char *p_tmp = strchr(p_name,'-'); if(p_tmp) { *p_tmp = '_'; } return(p_name); } #define PROC_MODULES "/proc/asound/modules" static char driver_name[100]; const char * get_card_driver(int index) { FILE *f = fopen(PROC_MODULES,"r"); char tmp[100]; int id; if(!f) return(NULL); while(fgets(tmp,100,f)) { sscanf(tmp," %d %s",&id,driver_name); if(id == index) { return(check_driver_name(driver_name)); } } return(NULL); } void set_volume(int volume) { int i; for (i = 0; i < sizeof(channels) / sizeof(channels[0]); i++) { if (channels[i].play_volume > 1) channels[i].play_volume = volume; } } void check_data(void) { int i; for (i = 0; i < sizeof(channels) / sizeof(channels[0]); i++) { strlwr(channels[i].name); check_driver_name(channels[i].driver); } } void usage(char *p_name) { printf("Alsa Unmute utility, Version %s, Copyright 2005 Red Hat, Inc.\n",VERSION); printf("This software may be freely redistributed under the terms of the GNU\n"); printf("public license.\n\n"); printf("Usage: alsaunmute card_number [-v] [-s volume]\n\n"); printf(" card_number - number of unmuted card\n"); printf(" [-v] - verbose mode\n"); printf(" [-s volume] - set this volume level instead of the default (75%%)\n"); printf(" the volume is number from 0 to 100\n\n"); exit(0); } /* Unmute specified card alsaunmute 0 */ int main(int argc, char **argv) { const char *p_driver; int index; int volume = 75; int param; if (argc < 2) { usage(argv[0]); exit(0); } index = atoi(argv[1]); p_driver = get_card_driver(index); for(param = 2; param < argc; param++) { if (!strcmp(argv[param],"-v") || !strcmp(argv[param],"-V")) { verbose = TRUE; continue; } if (param+1 < argc && (!strcmp(argv[param],"-s") || !strcmp(argv[param],"-S"))) { param++; volume = atoi(argv[param]); } } if(!p_driver) { fprintf(stderr,"Wrong card index %d...\n",index); return(1); } if(verbose) { fprintf(stderr,"Card %d Driver %s Volume %d%%...\n",index,p_driver,volume); } check_data(); // setting volume set_volume(volume); // default settings for all cards unmute_card(index,""); // specific setting for selected card_number unmute_card(index,p_driver); return (0); }