Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include <u.h>
#include <libc.h>
#include <thread.h>
#include "usb.h"
#include "audio.h"
#include "audioctl.h"

int endpt[2] =          {-1, -1};
int interface[2] =      {-1, -1};
int featureid[2] =      {-1, -1};
int selectorid[2] =     {-1, -1};
int mixerid[2] =        {-1, -1};
int curalt[2] =         {-1, -1};
int buttonendpt =       -1;

int id;
Dev *ad;

Audiocontrol controls[2][Ncontrol] = {
        {
        [Speed_control] = {             "speed",        0, {0}, 0,      44100,  Undef},
        [Mute_control] = {              "mute",         0, {0}, 0,      0,      Undef},
        [Volume_control] = {            "volume",       0, {0}, 0,      0,      Undef},
        [Bass_control] = {              "bass",         0, {0}, 0,      0,      Undef},
        [Mid_control] = {               "mid",          0, {0}, 0,      0,      Undef},
        [Treble_control] = {            "treble",       0, {0}, 0,      0,      Undef},
        [Equalizer_control] = {         "equalizer",    0, {0}, 0,      0,      Undef},
        [Agc_control] = {               "agc",          0, {0}, 0,      0,      Undef},
        [Delay_control] = {             "delay",        0, {0}, 0,      0,      Undef},
        [Bassboost_control] = {         "bassboost",    0, {0}, 0,      0,      Undef},
        [Loudness_control] = {          "loudness",     0, {0}, 0,      0,      Undef},
        [Channel_control] = {           "channels",     0, {0}, 0,      2,      Undef},
        [Resolution_control] = {        "resolution",   0, {0}, 0,      16,     Undef},
//      [Selector_control] = {          "selector",     0, {0}, 0,      0,      Undef},
        }, {
        [Speed_control] = {             "speed",        0, {0}, 0,      44100,  Undef},
        [Mute_control] = {              "mute",         0, {0}, 0,      0,      Undef},
        [Volume_control] = {            "volume",       0, {0}, 0,      0,      Undef},
        [Bass_control] = {              "bass",         0, {0}, 0,      0,      Undef},
        [Mid_control] = {               "mid",          0, {0}, 0,      0,      Undef},
        [Treble_control] = {            "treble",       0, {0}, 0,      0,      Undef},
        [Equalizer_control] = {         "equalizer",    0, {0}, 0,      0,      Undef},
        [Agc_control] = {               "agc",          0, {0}, 0,      0,      Undef},
        [Delay_control] = {             "delay",        0, {0}, 0,      0,      Undef},
        [Bassboost_control] = {         "bassboost",    0, {0}, 0,      0,      Undef},
        [Loudness_control] = {          "loudness",     0, {0}, 0,      0,      Undef},
        [Channel_control] = {           "channels",     0, {0}, 0,      2,      Undef},
        [Resolution_control] = {        "resolution",   0, {0}, 0,      16,     Undef},
//      [Selector_control] = {          "selector",     0, {0}, 0,      0,      Undef},
        }
};

int
setaudioalt(int rec, Audiocontrol *c, int control)
{
        dprint(2, "setcontrol %s: Set alt %d\n", c->name, control);
        curalt[rec] = control;
        if(usbcmd(ad, Rh2d|Rstd|Riface, Rsetiface, control, interface[rec], nil, 0) < 0){
                dprint(2, "setcontrol: setupcmd %s failed\n", c->name);
                return -1;
        }
        return control;
}

int
findalt(int rec, int nchan, int res, int speed)
{
        Ep *ep;
        Audioalt *a;
        Altc *da;
        int i, j, k, retval;

        retval = -1;
        controls[rec][Channel_control].min = 1000000;
        controls[rec][Channel_control].max = 0;
        controls[rec][Channel_control].step = Undef;
        controls[rec][Resolution_control].min = 1000000;
        controls[rec][Resolution_control].max = 0;
        controls[rec][Resolution_control].step = Undef;
        for(i = 0; i < nelem(ad->usb->ep); i++){
                if((ep = ad->usb->ep[i]) == nil)
                        continue;
                if(ep->iface == nil){
                        fprint(2, "\tno interface\n");
                        return 0;
                }
                if(ep->iface->csp != CSP(Claudio, 2, 0))
                        continue;
                if((rec == Play && (ep->addr &  0x80))
                || (rec == Record && (ep->addr &  0x80) == 0))
                        continue;
                for(j = 0; j < 16; j++){
                        if((da = ep->iface->altc[j]) == nil || (a = da->aux) == nil)
                                continue;
                        if(a->nchan < controls[rec][Channel_control].min)
                                controls[rec][Channel_control].min = a->nchan;
                        if(a->nchan > controls[rec][Channel_control].max)
                                controls[rec][Channel_control].max = a->nchan;
                        if(a->res < controls[rec][Resolution_control].min)
                                controls[rec][Resolution_control].min = a->res;
                        if(a->res > controls[rec][Resolution_control].max)
                                controls[rec][Resolution_control].max = a->res;
                        controls[rec][Channel_control].settable = 1;
                        controls[rec][Channel_control].readable = 1;
                        controls[rec][Resolution_control].settable = 1;
                        controls[rec][Resolution_control].readable = 1;
                        controls[rec][Speed_control].settable = 1;
                        controls[rec][Speed_control].readable = 1;
                        if(a->nchan == nchan && a->res == res){
                                if(speed == Undef)
                                        retval = j;
                                else if(a->caps & (has_discfreq|onefreq)){
                                        for(k = 0; k < nelem(a->freqs); k++){
                                                if(a->freqs[k] == speed){
                                                        retval = j;
                                                        break;
                                                }
                                        }
                                }else{
                                        if(speed >= a->minfreq && speed <= a->maxfreq)
                                                retval = j;
                                }
                        }
                }
        }
        if(usbdebug && retval < 0)
                fprint(2, "findalt(%d, %d, %d, %d) failed\n", rec, nchan, res, speed);
        return retval;
}

int
setspeed(int rec, int speed)
{
        int ps, n, no, dist, i;
        Audioalt *a;
        Altc *da;
        Ep *ep;
        uchar buf[3];

        if(rec == Record && !setrec)
                return Undef;
        if(curalt[rec] < 0){
                fprint(2, "Must set channels and resolution before speed\n");
                return Undef;
        }
        if(endpt[rec] < 0)
                sysfatal("endpt[%s] not set", rec?"Record":"Playback");
        ep = ad->usb->ep[endpt[rec]];
        if(ep->iface == nil)
                sysfatal("no interface");
        if(curalt[rec] < 0)
                sysfatal("curalt[%s] not set", rec?"Record":"Playback");
        da = ep->iface->altc[curalt[rec]];
        a = da->aux;
        if(a->caps & onefreq){
                dprint(2, "setspeed %d: onefreq\n", speed);
                /* speed not settable, but packet size must still be set */
                speed = a->freqs[0];
        }else if(a->caps & has_contfreq){
                dprint(2, "setspeed %d: contfreq\n", speed);
                if(speed < a->minfreq)
                        speed = a->minfreq;
                else if(speed > a->maxfreq)
                        speed = a->maxfreq;
                dprint(2, "Setting continuously variable %s speed to %d\n",
                                rec?"record":"playback", speed);
        }else if(a->caps & has_discfreq){
                dprint(2, "setspeed %d: discfreq\n", speed);
                dist = 1000000;
                no = -1;
                for(i = 0; a->freqs[i] > 0; i++)
                        if(abs(a->freqs[i] - speed) < dist){
                                dist = abs(a->freqs[i] - speed);
                                no = i;
                        }
                if(no == -1){
                        dprint(2, "no = -1\n");
                        return Undef;
                }
                speed = a->freqs[no];
                dprint(2, "Setting discreetly variable %s speed to %d\n",
                                rec?"record":"playback", speed);
        }else{
                dprint(2, "can't happen\n?");
                return Undef;
        }
        if(a->caps & has_setspeed){
                dprint(2, "Setting %s speed to %d Hz;", rec?"record":"playback", speed);
                buf[0] = speed;
                buf[1] = speed >> 8;
                buf[2] = speed >> 16;
                n = endpt[rec];
                if(rec)
                        n |= 0x80;
                if(usbcmd(ad, Rh2d|Rclass|Rep, Rsetcur, sampling_freq_control<<8, n, buf, 3) < 0){
                        fprint(2, "Error in setupcmd\n");
                        return Undef;
                }
                if((n=usbcmd(ad, Rd2h|Rclass|Rep, Rgetcur, sampling_freq_control<<8, n, buf, 3)) < 0){
                        fprint(2, "Error in setupreq\n");
                        return Undef;
                }
                if(n != 3)
                        fprint(2, "Error in setupreply: %d\n", n);
                else{
                        n = buf[0] | buf[1] << 8 | buf[2] << 16;
                        if(buf[2] || n == 0){
                                dprint(2, "Speed out of bounds %d (0x%x)\n", n, n);
                        }else if(n != speed && ad->usb->vid == 0x077d &&
                            (ad->usb->did == 0x0223 || ad->usb->did == 0x07af)){
                                /* Griffin iMic responds incorrectly to sample rate inquiry */
                                dprint(2, " reported as %d (iMic bug?);", n);
                        }else
                                speed = n;
                }
                dprint(2, " speed now %d Hz;", speed);
        }
        ps = ((speed * da->interval + 999) / 1000)
                * controls[rec][Channel_control].value[0]
                * controls[rec][Resolution_control].value[0]/8;
        if(ps > ep->maxpkt){
                fprint(2, "%s: setspeed(rec %d, speed %d): packet size %d > "
                        "maximum packet size %d\n",
                        argv0, rec, speed, ps, ep->maxpkt);
                return Undef;
        }
        dprint(2, "Configuring %s endpoint for %d Hz\n",
                                rec?"record":"playback", speed);
        epdev[rec] = openep(ad, endpt[rec]);
        if(epdev[rec] == nil)
                sysfatal("openep rec %d: %r", rec);

        devctl(epdev[rec], "pollival %d", da->interval);
        devctl(epdev[rec], "samplesz %ld", controls[rec][Channel_control].value[0] *
                                controls[rec][Resolution_control].value[0]/8);
        devctl(epdev[rec], "hz %d", speed);

        /* NO: the client uses the endpoint file directly
        if(opendevdata(epdev[rec], rec ? OREAD : OWRITE) < 0)
                sysfatal("openep rec %d: %r", rec);
        */
        return speed;
}

long
getspeed(int rec, int which)
{
        int i, n;
        Audioalt *a;
        Altc *da;
        Ep *ep;
        uchar buf[3];
        int r;

        if(curalt[rec] < 0){
                fprint(2, "Must set channels and resolution before getspeed\n");
                return Undef;
        }
        if(endpt[rec] < 0)
                sysfatal("endpt[%s] not set", rec?"Record":"Playback");
        dprint(2, "getspeed: endpt[%d] == %d\n", rec, endpt[rec]);
        ep = ad->usb->ep[endpt[rec]];
        if(ep->iface == nil)
                sysfatal("no interface");
        if(curalt[rec] < 0)
                sysfatal("curalt[%s] not set", rec?"Record":"Playback");
        da = ep->iface->altc[curalt[rec]];
        a = da->aux;
        if(a->caps & onefreq){
                dprint(2, "getspeed: onefreq\n");
                if(which == Rgetres)
                        return Undef;
                return a->freqs[0];             /* speed not settable */
        }
        if(a->caps & has_setspeed){
                dprint(2, "getspeed: has_setspeed, ask\n");
                n = endpt[rec];
                if(rec)
                        n |= 0x80;
                r = Rd2h|Rclass|Rep;
                if(usbcmd(ad,r,which,sampling_freq_control<<8, n, buf, 3) < 0)
                        return Undef;
                if(n == 3){
                        if(buf[2]){
                                dprint(2, "Speed out of bounds\n");
                                if((a->caps & has_discfreq) && (buf[0] | buf[1] << 8) < 8)
                                        return a->freqs[buf[0] | buf[1] << 8];
                        }
                        return buf[0] | buf[1] << 8 | buf[2] << 16;
                }
                dprint(2, "getspeed: n = %d\n", n);
        }
        if(a->caps & has_contfreq){
                dprint(2, "getspeed: has_contfreq\n");
                if(which == Rgetcur)
                        return controls[rec][Speed_control].value[0];
                if(which == Rgetmin)
                        return a->minfreq;
                if(which == Rgetmax)
                        return a->maxfreq;
                if(which == Rgetres)
                        return 1;
        }
        if(a->caps & has_discfreq){
                dprint(2, "getspeed: has_discfreq\n");
                if(which == Rgetcur)
                        return controls[rec][Speed_control].value[0];
                if(which == Rgetmin)
                        return a->freqs[0];
                for(i = 0; i < 8 && a->freqs[i] > 0; i++)
                        ;
                if(which == Rgetmax)
                        return a->freqs[i-1];
                if(which == Rgetres)
                        return Undef;
        }
        dprint(2, "can't happen\n?");
        return Undef;
}

int
setcontrol(int rec, char *name, long *value)
{
        int i, ctl, m;
        byte buf[3];
        int type, req, control, index, count;
        Audiocontrol *c;

        c = nil;
        for(ctl = 0; ctl < Ncontrol; ctl++){
                c = &controls[rec][ctl];
                if(strcmp(name, c->name) == 0)
                        break;
        }
        if(ctl == Ncontrol){
                dprint(2, "setcontrol: control not found\n");
                return -1;
        }
        if(c->settable == 0){
                dprint(2, "setcontrol: control %d.%d not settable\n", rec, ctl);
                if(c->chans){
                        for(i = 0; i < 8; i++)
                                if((c->chans & 1 << i) && c->value[i] != value[i])
                                        return -1;
                        return 0;
                }
                if(c->value[0] != value[0])
                        return -1;
                return 0;
        }
        if(c->chans){
                value[0] = 0;   // set to average
                m = 0;
                for(i = 1; i < 8; i++)
                        if(c->chans & 1 << i){
                                if(c->min != Undef && value[i] < c->min)
                                        value[i] = c->min;
                                if(c->max != Undef && value[i] > c->max)
                                        value[i] = c->max;
                                value[0] += value[i];
                                m++;
                        }else
                                value[i] = Undef;
                if(m) value[0] /= m;
        }else{
                if(c->min != Undef && value[0] < c->min)
                        value[0] = c->min;
                if(c->max != Undef && value[0] > c->max)
                        value[0] = c->max;
        }
        req = Rsetcur;
        count = 1;
        switch(ctl){
        default:
                dprint(2, "setcontrol: can't happen\n");
                return -1;
        case Speed_control:
                if((rec != Record || setrec) && (value[0] = setspeed(rec, value[0])) < 0)
                        return -1;
                c->value[0] = value[0];
                return 0;
        case Equalizer_control:
                /* not implemented */
                return -1;
        case Resolution_control:
                control = findalt(rec, controls[rec][Channel_control].value[0], value[0], defaultspeed[rec]);
                if(control < 0 || setaudioalt(rec, c, control) < 0){
                        dprint(2, "setcontrol: can't find setting for %s\n", c->name);
                        return -1;
                }
                c->value[0] = value[0];
                controls[rec][Speed_control].value[0] = defaultspeed[rec];
                return 0;
        case Volume_control:
        case Delay_control:
                count = 2;
                /* fall through */
        case Mute_control:
        case Bass_control:
        case Mid_control:
        case Treble_control:
        case Agc_control:
        case Bassboost_control:
        case Loudness_control:
                type = Rh2d|Rclass|Riface;
                control = ctl<<8;
                index = featureid[rec]<<8;
                break;
        case Selector_control:
                type = Rh2d|Rclass|Riface;
                control = 0;
                index = selectorid[rec]<<8;
                break;
        case Channel_control:
                control = findalt(rec, value[0], controls[rec][Resolution_control].value[0], defaultspeed[rec]);
                if(control < 0 || setaudioalt(rec, c, control) < 0){
                        dprint(2, "setcontrol: can't find setting for %s\n", c->name);
                        return -1;
                }
                c->value[0] = value[0];
                controls[rec][Speed_control].value[0] = defaultspeed[rec];
                return 0;
        }
        if(c->chans){
                for(i = 1; i < 8; i++)
                        if(c->chans & 1 << i){
                                switch(count){
                                case 2:
                                        buf[1] = value[i] >> 8;
                                case 1:
                                        buf[0] = value[i];
                                }
                                if(usbcmd(ad, type, req, control | i, index, buf, count) < 0){
                                        dprint(2, "setcontrol: setupcmd %s failed\n",
                                                controls[rec][ctl].name);
                                        return -1;
                                }
                                c->value[i] = value[i];
                        }
        }else{
                switch(count){
                case 2:
                        buf[1] = value[0] >> 8;
                case 1:
                        buf[0] = value[0];
                }
                if(usbcmd(ad, type, req, control, index, buf, count) < 0){
                        dprint(2, "setcontrol: setupcmd %s failed\n", c->name);
                        return -1;
                }
        }
        c->value[0] = value[0];
        return 0;
}

int
getspecialcontrol(int rec, int ctl, int req, long *value)
{
        byte buf[3];
        int m, n, i;
        int type, control, index, count, signedbyte;
        short svalue;

        count = 1;
        signedbyte = 0;
        switch(ctl){
        default:
                return Undef;
        case Speed_control:
                value[0] =  getspeed(rec, req);
                return 0;
        case Channel_control:
        case Resolution_control:
                if(req == Rgetmin)
                        value[0] = controls[rec][ctl].min;
                if(req == Rgetmax)
                        value[0] = controls[rec][ctl].max;
                if(req == Rgetres)
                        value[0] = controls[rec][ctl].step;
                if(req == Rgetcur)
                        value[0] = controls[rec][ctl].value[0];
                return 0;
        case Volume_control:
        case Delay_control:
                count = 2;
                /* fall through */
        case Bass_control:
        case Mid_control:
        case Treble_control:
        case Equalizer_control:
                signedbyte = 1;
                type = Rd2h|Rclass|Riface;
                control = ctl<<8;
                index = featureid[rec]<<8;
                break;
        case Selector_control:
                type = Rd2h|Rclass|Riface;
                control = 0;
                index = selectorid[rec]<<8;
                break;
        case Mute_control:
        case Agc_control:
        case Bassboost_control:
        case Loudness_control:
                if(req != Rgetcur)
                        return Undef;
                type = Rd2h|Rclass|Riface;
                control = ctl<<8;
                index = featureid[rec]<<8;
                break;
        }
        if(controls[rec][ctl].chans){
                m = 0;
                value[0] = 0; // set to average
                for(i = 1; i < 8; i++){
                        value[i] = Undef;
                        if(controls[rec][ctl].chans & 1 << i){
                                n=usbcmd(ad, type,req, control|i,index,buf,count);
                                if(n < 0)
                                        return Undef;
                                if(n != count)
                                        return -1;
                                switch (count){
                                case 2:
                                        svalue = buf[1] << 8 | buf[0];
                                        if(req == Rgetcur){
                                                value[i] = svalue;
                                                value[0] += svalue;
                                                m++;
                                        }else
                                                value[0] = svalue;
                                        break;
                                case 1:
                                        svalue = buf[0];
                                        if(signedbyte && (svalue&0x80))
                                                svalue |= 0xFF00;
                                        if(req == Rgetcur){
                                                value[i] = svalue;
                                                value[0] += svalue;
                                                m++;
                                        }else
                                                value[0] = svalue;
                                }
                        }
                }
                if(m) value[0] /= m;
                return 0;
        }
        value[0] = Undef;
        if(usbcmd(ad, type, req, control, index, buf, count) != count)
                return -1;
        switch (count){
        case 2:
                svalue = buf[1] << 8 | buf[0];
                value[0] = svalue;
                break;
        case 1:
                svalue = buf[0];
                if(signedbyte && (svalue&0x80))
                        svalue |= 0xFF00;
                value[0] = svalue;
        }
        return 0;
}

int
getcontrol(int rec, char *name, long *value)
{
        int i;

        for(i = 0; i < Ncontrol; i++){
                if(strcmp(name, controls[rec][i].name) == 0)
                        break;
        }
        if(i == Ncontrol)
                return -1;
        if(controls[rec][i].readable == 0)
                return -1;
        if(getspecialcontrol(rec, i, Rgetcur, value) < 0)
                return -1;
        memmove(controls[rec][i].value, value, sizeof controls[rec][i].value);
        return 0;
}

void
getcontrols(void)
{
        int rec, ctl, i;
        Audiocontrol *c;
        long v[8];

        for(rec = 0; rec < 2; rec++){
                if(rec == Record && !setrec)
                        continue;
                for(ctl = 0; ctl < Ncontrol; ctl++){
                        c = &controls[rec][ctl];
                        if(c->readable){
                                if(verbose)
                                        fprint(2, "%s %s control",
                                                rec?"Record":"Playback", controls[rec][ctl].name);
                                c->min = (getspecialcontrol(rec, ctl, Rgetmin, v) < 0) ? Undef : v[0];
                                if(verbose && c->min != Undef)
                                        fprint(2, ", min %ld", c->min);
                                c->max = (getspecialcontrol(rec, ctl, Rgetmax, v) < 0) ? Undef : v[0];
                                if(verbose && c->max != Undef)
                                        fprint(2, ", max %ld", c->max);
                                c->step = (getspecialcontrol(rec, ctl, Rgetres, v) < 0) ? Undef : v[0];
                                if(verbose && c->step != Undef)
                                        fprint(2, ", step %ld", c->step);
                                if(getspecialcontrol(rec, ctl, Rgetcur, c->value) == 0){
                                        if(verbose){
                                                if(c->chans){
                                                        fprint(2, ", values");
                                                        for(i = 1; i < 8; i++)
                                                                if(c->chans & 1 << i)
                                                                        fprint(2, "[%d] %ld  ", i, c->value[i]);
                                                }else
                                                        fprint(2, ", value %ld", c->value[0]);
                                        }
                                }
                                if(verbose)
                                        fprint(2, "\n");
                        }else{
                                c->min = Undef;
                                c->max = Undef;
                                c->step = Undef;
                                c->value[0] = Undef;
                                dprint(2, "%s %s control not settable\n",
                                        rec?"Playback":"Record", controls[rec][ctl].name);
                        }
                }
        }
}

int
ctlparse(char *s, Audiocontrol *c, long *v)
{
        int i, j, nf, m;
        char *vals[9];
        char *p;
        long val;

        nf = tokenize(s, vals, nelem(vals));
        if(nf <= 0)
                return -1;
        if(c->chans){
                j = 0;
                m = 0;
                SET(val);
                v[0] = 0;       // will compute average of v[i]
                for(i = 1; i < 8; i++)
                        if(c->chans & 1 << i){
                                if(j < nf){
                                        val = strtol(vals[j], &p, 0);
                                        if(val == 0 && *p != '\0' && *p != '%')
                                                return -1;
                                        if(*p == '%' && c->min != Undef)
                                                val = (val*c->max + (100-val)*c->min)/100;
                                        j++;
                                }
                                v[i] = val;
                                v[0] += val;
                                m++;
                        }else
                                v[i] = Undef;
                if(m) v[0] /= m;
        }else{
                val = strtol(vals[0], &p, 0);
                if(*p == '%' && c->min != Undef)
                        val = (val*c->max + (100-val)*c->min)/100;
                v[0] = val;
        }
        return 0;
}

int
Aconv(Fmt *fp)
{
        char str[256];
        Audiocontrol *c;
        int fst, i;
        char *p;

        c = va_arg(fp->args, Audiocontrol*);
        p = str;
        if(c->chans){
                fst = 1;
                for(i = 1; i < 8; i++)
                        if(c->chans & 1 << i){
                                p = seprint(p, str+sizeof str, "%s%ld", fst?"'":" ", c->value[i]);
                                fst = 0;
                        }
                seprint(p, str+sizeof str, "'");
        }else
                seprint(p, str+sizeof str, "%ld", c->value[0]);
        return fmtstrcpy(fp, str);
}