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;
 }

Reply via email to