On Thu, Jul 20, 2006 at 03:36:45PM +0200, [EMAIL PROTECTED] wrote:
> I've been trying to figure out how to get more than two channels of
> audio with, no success. What I read, "it should just work". Now,
> "audioctl play.channels=2" on boot. Whatever I try to change the
> value to, I get 'audioctl: set failed: Invalid argument' even if I try
> to set it to 2. It does seem to change the value, but as soon as I
> start playback it's back to play.channels=2. Any advice, please?
>
> The cards I've tried with:
>
> emu0 at pci2 dev 3 function 0 "Creative Labs SoundBlaster Live" rev
> 0x07: irq 11
> ac97: codec id 0x83847608 (SigmaTel STAC9708/11)
> ac97: codec features 18 bit DAC, 18 bit ADC, SigmaTel 3D
> audio0 at emu0
>
> azalia0 at pci0 dev 6 function 1 "NVIDIA MCP55 HD Audio" rev 0xa2: irq 15
> azalia0: host: High Definition Audio rev. 1.0
> azalia0: codec: 0x04x/0x10ec (rev. 0.2), HDA version 1.0
> audio0 at azalia0
hi,
i'm working on a similar problem for other devices and some other
audio-related stuff; could you try the following patch and see if it
solves the problem?
I'd would be happy if you could send me the output of 'mixerctl -a' and
'audioctl -a' for both devices.
thanks,
--
Alexandre
Index: audiovar.h
===================================================================
RCS file: /cvs/src/sys/dev/audiovar.h,v
retrieving revision 1.9
diff -u -p -b -r1.9 audiovar.h
--- audiovar.h 26 Aug 2002 16:20:04 -0000 1.9
+++ audiovar.h 11 Jul 2006 19:47:58 -0000
@@ -74,14 +74,12 @@ struct audio_ringbuffer {
#define AUDIO_N_PORTS 4
struct au_mixer_ports {
- int index;
- int master;
- int nports;
- u_char isenum;
- u_int allports;
- u_int aumask[AUDIO_N_PORTS];
- u_int misel [AUDIO_N_PORTS];
- u_int miport[AUDIO_N_PORTS];
+ int sel; /* index of the source selector */
+ int gain; /* index of the gain for the port set */
+ int nports; /* number of ports */
+ u_int allports; /* bitmask of all ports */
+ u_int aumask[AUDIO_N_PORTS]; /* mask of each port */
+ u_int selmask[AUDIO_N_PORTS]; /* selector value of each port */
};
/*
Index: audio.c
===================================================================
RCS file: /cvs/src/sys/dev/audio.c,v
retrieving revision 1.51
diff -u -p -b -r1.51 audio.c
--- audio.c 23 Jun 2006 06:27:11 -0000 1.51
+++ audio.c 11 Jul 2006 19:48:06 -0000
@@ -168,9 +168,35 @@ static struct portname otable[] = {
{ AudioNline, AUDIO_LINE_OUT },
{ 0 }
};
+struct gainpref {
+ char *class, *device;
+};
+static struct gainpref ipreftab[] = {
+ { AudioCinputs, AudioNvolume },
+ { AudioCinputs, AudioNinput },
+ { AudioCinputs, AudioNrecord },
+ { AudioCrecord, AudioNrecord },
+ { AudioCrecord, AudioNvolume },
+ { NULL, NULL}
+};
+static struct gainpref opreftab[] = {
+ { AudioCoutputs, AudioNmaster },
+ { AudioCoutputs, AudioNoutput },
+ { AudioCoutputs, AudioNdac },
+ { AudioCinputs, AudioNdac },
+ { NULL, NULL}
+};
+static struct gainpref mpreftab[] = {
+ { AudioCoutputs, AudioNmonitor },
+ { AudioCmonitor, AudioNmonitor },
+ { NULL, NULL}
+};
+
void au_check_ports(struct audio_softc *, struct au_mixer_ports *,
- mixer_devinfo_t *, int, char *, char *,
- struct portname *);
+ struct mixer_devinfo *, struct mixer_devinfo *,
+ char *, char *, struct portname *);
+void au_gain_match(struct audio_softc *, struct gainpref *,
+ struct mixer_devinfo *, struct mixer_devinfo *, int *, int *);
int au_set_gain(struct audio_softc *, struct au_mixer_ports *,
int, int);
void au_get_gain(struct audio_softc *, struct au_mixer_ports *,
@@ -182,8 +208,6 @@ int au_get_lr_value(struct audio_softc *
int *, int *r);
int au_set_lr_value(struct audio_softc *, mixer_ctrl_t *,
int, int);
-int au_portof(struct audio_softc *, char *);
-
/* The default audio mode: 8 kHz mono ulaw */
struct audio_params audio_default =
@@ -239,8 +263,8 @@ audioattach(parent, self, aux)
struct audio_hw_if *hwp = sa->hwif;
void *hdlp = sa->hdl;
int error;
- mixer_devinfo_t mi;
- int iclass, oclass;
+ mixer_devinfo_t mi, cl;
+ int ipref, opref, mpref;
printf("\n");
@@ -297,38 +321,34 @@ audioattach(parent, self, aux)
audio_init_ringbuffer(&sc->sc_pr);
audio_calcwater(sc);
- iclass = oclass = -1;
- sc->sc_inports.index = -1;
+ ipref = opref = mpref = -1;
+ sc->sc_inports.sel = -1;
+ sc->sc_inports.gain = -1;
sc->sc_inports.nports = 0;
- sc->sc_inports.isenum = 0;
sc->sc_inports.allports = 0;
- sc->sc_outports.index = -1;
+ sc->sc_outports.sel = -1;
+ sc->sc_outports.gain = -1;
sc->sc_outports.nports = 0;
- sc->sc_outports.isenum = 0;
sc->sc_outports.allports = 0;
sc->sc_monitor_port = -1;
- for(mi.index = 0; ; mi.index++) {
- if (hwp->query_devinfo(hdlp, &mi) != 0)
- break;
- if (mi.type == AUDIO_MIXER_CLASS &&
- strcmp(mi.label.name, AudioCrecord) == 0)
- iclass = mi.index;
- if (mi.type == AUDIO_MIXER_CLASS &&
- strcmp(mi.label.name, AudioCmonitor) == 0)
- oclass = mi.index;
- }
+
for(mi.index = 0; ; mi.index++) {
if (hwp->query_devinfo(hdlp, &mi) != 0)
break;
if (mi.type == AUDIO_MIXER_CLASS)
continue;
- au_check_ports(sc, &sc->sc_inports, &mi, iclass,
- AudioNsource, AudioNrecord, itable);
- au_check_ports(sc, &sc->sc_outports, &mi, oclass,
- AudioNoutput, AudioNmaster, otable);
- if (mi.mixer_class == oclass &&
- (strcmp(mi.label.name, AudioNmonitor) == 0))
- sc->sc_monitor_port = mi.index;
+ cl.index = mi.mixer_class;
+ if (hwp->query_devinfo(hdlp, &cl) != 0)
+ continue;
+
+ au_gain_match(sc, ipreftab, &cl, &mi, &sc->sc_inports.gain,
&ipref);
+ au_gain_match(sc, opreftab, &cl, &mi, &sc->sc_outports.gain,
&opref);
+ au_gain_match(sc, mpreftab, &cl, &mi, &sc->sc_monitor_port,
&mpref);
+
+ au_check_ports(sc, &sc->sc_inports, &cl, &mi,
+ AudioCrecord, AudioNsource, itable);
+ au_check_ports(sc, &sc->sc_outports, &cl, &mi,
+ AudioCoutputs, AudioNselect, otable);
}
DPRINTF(("audio_attach: inputs ports=0x%x, output ports=0x%x\n",
sc->sc_inports.allports, sc->sc_outports.allports));
@@ -394,71 +414,53 @@ audiodetach(self, flags)
return (0);
}
-int
-au_portof(sc, name)
- struct audio_softc *sc;
- char *name;
+/*
+ * check if the given (class, device) is better
+ * than the current setting (*index), if so, set the
+ * current setting.
+ */
+void
+au_gain_match(struct audio_softc *sc , struct gainpref *tbl,
+ struct mixer_devinfo *cls, struct mixer_devinfo *dev, int *index, int
*pref)
{
- mixer_devinfo_t mi;
+ int i;
- for(mi.index = 0;
- sc->hw_if->query_devinfo(sc->hw_hdl, &mi) == 0;
- mi.index++)
- if (strcmp(mi.label.name, name) == 0)
- return mi.index;
- return -1;
+ for (i = *pref + 1; tbl[i].class != NULL; i++) {
+ if (strcmp(tbl[i].class, cls->label.name) == 0 &&
+ strcmp(tbl[i].device, dev->label.name) == 0) {
+ if (*pref < i) {
+ *index = dev->index;
+ *pref = i;
+ }
+ break;
+ }
+ }
}
void
-au_check_ports(sc, ports, mi, cls, name, mname, tbl)
- struct audio_softc *sc;
- struct au_mixer_ports *ports;
- mixer_devinfo_t *mi;
- int cls;
- char *name;
- char *mname;
- struct portname *tbl;
+au_check_ports(struct audio_softc *sc, struct au_mixer_ports *ports,
+ struct mixer_devinfo *cl, struct mixer_devinfo *mi,
+ char *cname, char *mname, struct portname *tbl)
{
int i, j;
- if (mi->mixer_class != cls)
- return;
- if (strcmp(mi->label.name, mname) == 0) {
- ports->master = mi->index;
+ if (mi->type != AUDIO_MIXER_SET ||
+ strcmp(cl->label.name, cname) != 0 ||
+ strcmp(mi->label.name, mname) != 0)
return;
- }
- if (strcmp(mi->label.name, name) != 0)
- return;
- if (mi->type == AUDIO_MIXER_ENUM) {
- ports->index = mi->index;
- for(i = 0; tbl[i].name; i++) {
- for(j = 0; j < mi->un.e.num_mem; j++) {
- if (strcmp(mi->un.e.member[j].label.name,
- tbl[i].name) == 0) {
- ports->aumask[ports->nports] = tbl[i].mask;
- ports->misel [ports->nports] = mi->un.e.member[j].ord;
- ports->miport[ports->nports++] =
- au_portof(sc, mi->un.e.member[j].label.name);
- ports->allports |= tbl[i].mask;
- }
- }
- }
- ports->isenum = 1;
- } else if (mi->type == AUDIO_MIXER_SET) {
- ports->index = mi->index;
+
for(i = 0; tbl[i].name; i++) {
for(j = 0; j < mi->un.s.num_mem; j++) {
- if (strcmp(mi->un.s.member[j].label.name,
- tbl[i].name) == 0) {
- ports->aumask[ports->nports] = tbl[i].mask;
- ports->misel [ports->nports] = mi->un.s.member[j].mask;
- ports->miport[ports->nports++] =
- au_portof(sc, mi->un.s.member[j].label.name);
+ if (strcmp(mi->un.s.member[j].label.name, tbl[i].name)
== 0) {
ports->allports |= tbl[i].mask;
+ ports->aumask[ports->nports] = tbl[i].mask;
+ ports->selmask[ports->nports] =
mi->un.s.member[j].mask;
+ ports->nports++;
}
}
}
- }
+ if (ports->nports != 0)
+ ports->sel = mi->index;
}
/*
@@ -2295,10 +2297,11 @@ au_set_gain(sc, ports, gain, balance)
int balance;
{
mixer_ctrl_t ct;
- int i, error;
+ int error;
int l, r;
- u_int mask;
- int nset;
+
+ if (ports->gain == -1)
+ return 0; /* just ignore it silently */
if (balance == AUDIO_MID_BALANCE) {
l = r = gain;
@@ -2313,48 +2316,8 @@ au_set_gain(sc, ports, gain, balance)
DPRINTF(("au_set_gain: gain=%d balance=%d, l=%d r=%d\n",
gain, balance, l, r));
- if (ports->index == -1) {
- usemaster:
- if (ports->master == -1)
- return 0; /* just ignore it silently */
- ct.dev = ports->master;
+ ct.dev = ports->gain;
error = au_set_lr_value(sc, &ct, l, r);
- } else {
- ct.dev = ports->index;
- if (ports->isenum) {
- ct.type = AUDIO_MIXER_ENUM;
- error = sc->hw_if->get_port(sc->hw_hdl, &ct);
- if (error)
- return error;
- for(i = 0; i < ports->nports; i++) {
- if (ports->misel[i] == ct.un.ord) {
- ct.dev = ports->miport[i];
- if (ct.dev == -1 ||
- au_set_lr_value(sc, &ct, l, r))
- goto usemaster;
- else
- break;
- }
- }
- } else {
- ct.type = AUDIO_MIXER_SET;
- error = sc->hw_if->get_port(sc->hw_hdl, &ct);
- if (error)
- return error;
- mask = ct.un.mask;
- nset = 0;
- for(i = 0; i < ports->nports; i++) {
- if (ports->misel[i] & mask) {
- ct.dev = ports->miport[i];
- if (ct.dev != -1 &&
- au_set_lr_value(sc, &ct, l, r) == 0)
- nset++;
- }
- }
- if (nset == 0)
- goto usemaster;
- }
- }
if (!error)
mixer_signal(sc);
return error;
@@ -2390,61 +2353,13 @@ au_get_gain(sc, ports, pgain, pbalance)
u_char *pbalance;
{
mixer_ctrl_t ct;
- int i, l, r, n;
- int lgain = AUDIO_MAX_GAIN/2, rgain = AUDIO_MAX_GAIN/2;
+ int lgain = AUDIO_MAX_GAIN / 2, rgain = AUDIO_MAX_GAIN / 2;
- if (ports->index == -1) {
- usemaster:
- if (ports->master == -1)
- goto bad;
- ct.dev = ports->master;
- ct.type = AUDIO_MIXER_VALUE;
- if (au_get_lr_value(sc, &ct, &lgain, &rgain))
- goto bad;
- } else {
- ct.dev = ports->index;
- if (ports->isenum) {
- ct.type = AUDIO_MIXER_ENUM;
- if (sc->hw_if->get_port(sc->hw_hdl, &ct))
- goto bad;
- ct.type = AUDIO_MIXER_VALUE;
- for(i = 0; i < ports->nports; i++) {
- if (ports->misel[i] == ct.un.ord) {
- ct.dev = ports->miport[i];
- if (ct.dev == -1 ||
- au_get_lr_value(sc, &ct,
- &lgain, &rgain))
- goto usemaster;
- else
- break;
- }
- }
- } else {
- ct.type = AUDIO_MIXER_SET;
- if (sc->hw_if->get_port(sc->hw_hdl, &ct))
- goto bad;
+ if (ports->gain != -1) {
+ ct.dev = ports->gain;
ct.type = AUDIO_MIXER_VALUE;
- lgain = rgain = n = 0;
- for(i = 0; i < ports->nports; i++) {
- if (ports->misel[i] & ct.un.mask) {
- ct.dev = ports->miport[i];
- if (ct.dev == -1 ||
- au_get_lr_value(sc, &ct, &l, &r))
- goto usemaster;
- else {
- lgain += l;
- rgain += r;
- n++;
- }
+ (void)au_get_lr_value(sc, &ct, &lgain, &rgain);
}
- }
- if (n != 0) {
- lgain /= n;
- rgain /= n;
- }
- }
- }
-bad:
if (lgain == rgain) { /* handles lgain==rgain==0 */
*pgain = lgain;
*pbalance = AUDIO_MID_BALANCE;
@@ -2470,31 +2385,20 @@ au_set_port(sc, ports, port)
if (port == 0 && ports->allports == 0)
return 0; /* allow this special case */
- if (ports->index == -1)
+ if (ports->sel == -1)
return EINVAL;
- ct.dev = ports->index;
- if (ports->isenum) {
- if (port & (port-1))
- return EINVAL; /* Only one port allowed */
- ct.type = AUDIO_MIXER_ENUM;
- error = EINVAL;
- for(i = 0; i < ports->nports; i++)
- if (ports->aumask[i] == port) {
- ct.un.ord = ports->misel[i];
- error = sc->hw_if->set_port(sc->hw_hdl, &ct);
- break;
- }
- } else {
+ ct.dev = ports->sel;
ct.type = AUDIO_MIXER_SET;
ct.un.mask = 0;
for(i = 0; i < ports->nports; i++)
- if (ports->aumask[i] & port)
- ct.un.mask |= ports->misel[i];
- if (port != 0 && ct.un.mask == 0)
+ if (ports->aumask[i] & port) {
+ ct.un.mask |= ports->selmask[i];
+ port &= ~ports->aumask[i];
+ }
+ if (port != 0)
error = EINVAL;
else
error = sc->hw_if->set_port(sc->hw_hdl, &ct);
- }
if (!error)
mixer_signal(sc);
return error;
@@ -2508,22 +2412,16 @@ au_get_port(sc, ports)
mixer_ctrl_t ct;
int i, aumask;
- if (ports->index == -1)
+ if (ports->sel == -1)
return 0;
- ct.dev = ports->index;
- ct.type = ports->isenum ? AUDIO_MIXER_ENUM : AUDIO_MIXER_SET;
+ ct.dev = ports->sel;
+ ct.type = AUDIO_MIXER_SET;
if (sc->hw_if->get_port(sc->hw_hdl, &ct))
return 0;
aumask = 0;
- if (ports->isenum) {
for(i = 0; i < ports->nports; i++)
- if (ct.un.ord == ports->misel[i])
- aumask = ports->aumask[i];
- } else {
- for(i = 0; i < ports->nports; i++)
- if (ct.un.mask & ports->misel[i])
+ if (ct.un.mask & ports->selmask[i])
aumask |= ports->aumask[i];
- }
return aumask;
}