#include #include #include #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); }