2005-07-11 13:11:40 +00:00
|
|
|
/* Copyright 2005 Red Hat, Inc.
|
|
|
|
*
|
|
|
|
* Portions extraced from various ALSA code:
|
|
|
|
* Copyright (c) by Abramo Bagnara <abramo@alsa-project.org>
|
|
|
|
* Jaroslav Kysela <perex@suse.cz>
|
|
|
|
* Takashi Iwai <tiwai@suse.de>
|
|
|
|
* Bernd Kaindl <bk@suse.de>
|
|
|
|
* Jan ONDREJ (SAL) <ondrejj@salstar.sk>
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2006-01-25 09:53:26 +00:00
|
|
|
#define VERSION "0.2"
|
|
|
|
|
2005-07-11 13:11:40 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
|
|
|
|
#include <alsa/asoundlib.h>
|
|
|
|
|
|
|
|
#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, ""},
|
2006-10-02 08:15:39 +00:00
|
|
|
{"Mono", 75, 1, 0, 0, ""},
|
2005-07-11 13:11:40 +00:00
|
|
|
|
|
|
|
// 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, ""},
|
2006-05-03 08:46:12 +00:00
|
|
|
// removed - should by set by driver
|
|
|
|
// {"Audigy Analog/Digital Output Jack", 0, 0, 0, 0, ""},
|
2005-07-11 13:11:40 +00:00
|
|
|
|
|
|
|
// 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
|
2006-05-03 08:46:12 +00:00
|
|
|
// Removed (#187807)
|
|
|
|
// {"Audigy Analog/Digital Output Jack", 0,1,0, 0, "snd-emu10k1"},
|
2005-07-11 13:11:40 +00:00
|
|
|
{"IEC958 Optical Raw", 0, 0, 0, 0, "snd-emu10k1"},
|
|
|
|
{"Tone", 0, 0, 0, 0, "snd-emu10k1"},
|
|
|
|
|
|
|
|
// Specific config for snd-intel8x0
|
2005-08-23 10:51:22 +00:00
|
|
|
{"External Amplifier", 1, 1, 0, 0, "snd-intel8x0"},
|
2005-07-11 13:11:40 +00:00
|
|
|
|
|
|
|
// Specific config for snd-intel8x0 (xw8000)
|
|
|
|
{"Master Mono", 75, 1, 0, 0, "snd-intel8x0"},
|
|
|
|
|
2005-11-09 13:25:58 +00:00
|
|
|
// Specific config for snd-ens1371
|
2007-01-10 10:24:44 +00:00
|
|
|
{"IEC958", 0, 0, 0, 0, "snd-ens1371"},
|
|
|
|
{"iSpeaker", 75, 1, 0, 0, "snd-hda-intel"}
|
|
|
|
|
2005-07-11 13:11:40 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2006-01-25 09:53:26 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-07-11 13:11:40 +00:00
|
|
|
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)
|
|
|
|
{
|
2006-01-25 09:53:26 +00:00
|
|
|
printf("Alsa Unmute utility, Version %s, Copyright 2005 Red Hat, Inc.\n",VERSION);
|
2005-07-11 13:11:40 +00:00
|
|
|
printf("This software may be freely redistributed under the terms of the GNU\n");
|
|
|
|
printf("public license.\n\n");
|
|
|
|
|
2006-07-20 13:36:29 +00:00
|
|
|
printf("Usage: alsaunmute card_number [-v] [-s volume]\n\n");
|
2006-01-25 09:53:26 +00:00
|
|
|
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");
|
2005-07-11 13:11:40 +00:00
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Unmute specified card
|
|
|
|
alsaunmute 0
|
|
|
|
*/
|
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
const char *p_driver;
|
|
|
|
int index;
|
2006-01-25 09:53:26 +00:00
|
|
|
int volume = 75;
|
|
|
|
int param;
|
2005-07-11 13:11:40 +00:00
|
|
|
|
|
|
|
if (argc < 2) {
|
|
|
|
usage(argv[0]);
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
index = atoi(argv[1]);
|
|
|
|
p_driver = get_card_driver(index);
|
2006-01-25 09:53:26 +00:00
|
|
|
|
|
|
|
for(param = 2; param < argc; param++) {
|
|
|
|
if (!strcmp(argv[param],"-v") || !strcmp(argv[param],"-V")) {
|
|
|
|
verbose = TRUE;
|
|
|
|
continue;
|
|
|
|
}
|
2005-07-11 13:11:40 +00:00
|
|
|
|
2006-01-25 09:53:26 +00:00
|
|
|
if (param+1 < argc && (!strcmp(argv[param],"-s") || !strcmp(argv[param],"-S"))) {
|
|
|
|
param++;
|
|
|
|
volume = atoi(argv[param]);
|
|
|
|
}
|
2005-07-11 13:11:40 +00:00
|
|
|
}
|
2006-01-25 09:53:26 +00:00
|
|
|
|
2005-07-11 13:11:40 +00:00
|
|
|
|
|
|
|
if(!p_driver) {
|
|
|
|
fprintf(stderr,"Wrong card index %d...\n",index);
|
|
|
|
return(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(verbose) {
|
2006-01-25 09:53:26 +00:00
|
|
|
fprintf(stderr,"Card %d Driver %s Volume %d%%...\n",index,p_driver,volume);
|
2005-07-11 13:11:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
check_data();
|
|
|
|
|
2006-01-25 09:53:26 +00:00
|
|
|
// setting volume
|
|
|
|
set_volume(volume);
|
|
|
|
|
2005-07-11 13:11:40 +00:00
|
|
|
// default settings for all cards
|
|
|
|
unmute_card(index,"");
|
|
|
|
|
|
|
|
// specific setting for selected card_number
|
|
|
|
unmute_card(index,p_driver);
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|