]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/nusb/audio/audio.c
merge
[plan9front.git] / sys / src / cmd / nusb / audio / audio.c
1 #include <u.h>
2 #include <libc.h>
3 #include <fcall.h>
4 #include <thread.h>
5 #include <9p.h>
6 #include "usb.h"
7
8 typedef struct Audio Audio;
9 struct Audio
10 {
11         Audio   *next;
12
13         int     minfreq;
14         int     maxfreq;
15 };
16
17 int audiodelay = 1764;  /* 40 ms */
18 int audiofreq = 44100;
19 int audiochan = 2;
20 int audiores = 16;
21
22 char user[] = "audio";
23
24 Dev *audiodev = nil;
25
26 Ep *audioepin = nil;
27 Ep *audioepout = nil;
28
29 void
30 parsedescr(Desc *dd)
31 {
32         Audio *a, **ap;
33         uchar *b;
34         int i;
35
36         if(dd == nil || dd->iface == nil || dd->altc == nil)
37                 return;
38         b = (uchar*)&dd->data;
39         if(Subclass(dd->iface->csp) != 2 || b[1] != 0x24 || b[2] != 0x02)
40                 return;
41         if(b[4] != audiochan)
42                 return;
43         if(b[6] != audiores)
44                 return;
45
46         ap = (Audio**)&dd->altc->aux;
47         if(b[7] == 0){
48                 a = mallocz(sizeof(*a), 1);
49                 a->minfreq = b[8] | b[9]<<8 | b[10]<<16;
50                 a->maxfreq = b[11] | b[12]<<8 | b[13]<<16;
51                 a->next = *ap;
52                 *ap = a;
53         } else {
54                 for(i=0; i<b[7]; i++){
55                         a = mallocz(sizeof(*a), 1);
56                         a->minfreq = b[8+3*i] | b[9+3*i]<<8 | b[10+3*i]<<16;
57                         a->maxfreq = a->minfreq;
58                         a->next = *ap;
59                         *ap = a;
60                 }
61         }
62 }
63
64 Dev*
65 setupep(Dev *d, Ep *e, int speed)
66 {
67         uchar b[4];
68         Audio *x;
69         Altc *a;
70         int i;
71
72         for(i = 0; i < nelem(e->iface->altc); i++)
73                 if(a = e->iface->altc[i])
74                         for(x = a->aux; x; x = x->next)
75                                 if(speed >= x->minfreq && speed <= x->maxfreq)
76                                         goto Foundaltc;
77
78         werrstr("no altc found");
79         return nil;
80
81 Foundaltc:
82         if(usbcmd(d, Rh2d|Rstd|Riface, Rsetiface, i, e->iface->id, nil, 0) < 0){
83                 werrstr("set altc: %r");
84                 return nil;
85         }
86
87         b[0] = speed;
88         b[1] = speed >> 8;
89         b[2] = speed >> 16;
90         if(usbcmd(d, Rh2d|Rclass|Rep, Rsetcur, 0x100, e->addr, b, 3) < 0)
91                 fprint(2, "warning: set freq: %r\n");
92
93         if((d = openep(d, e->id)) == nil){
94                 werrstr("openep: %r");
95                 return nil;
96         }
97         devctl(d, "pollival %d", a->interval);
98         devctl(d, "samplesz %d", audiochan*audiores/8);
99         devctl(d, "sampledelay %d", audiodelay);
100         devctl(d, "hz %d", speed);
101         if(e->dir == Ein)
102                 devctl(d, "name audioin");
103         else
104                 devctl(d, "name audio");
105         return d;
106 }
107
108 void
109 fsread(Req *r)
110 {
111         char *msg;
112
113         msg = smprint("master 100 100\nspeed %d\ndelay %d\n", audiofreq, audiodelay);
114         readstr(r, msg);
115         respond(r, nil);
116         free(msg);
117 }
118
119 void
120 fswrite(Req *r)
121 {
122         char msg[256], *f[4];
123         int nf, speed;
124
125         snprint(msg, sizeof(msg), "%.*s", r->ifcall.count, r->ifcall.data);
126         nf = tokenize(msg, f, nelem(f));
127         if(nf < 2){
128                 respond(r, "invalid ctl message");
129                 return;
130         }
131         if(strcmp(f[0], "speed") == 0){
132                 Dev *d;
133
134                 speed = atoi(f[1]);
135 Setup:
136                 if((d = setupep(audiodev, audioepout, speed)) == nil){
137                         responderror(r);
138                         return;
139                 }
140                 closedev(d);
141                 if(audioepin != nil && audioepin != audioepout){
142                         if(d = setupep(audiodev, audioepin, speed))
143                                 closedev(d);
144                 }
145                 audiofreq = speed;
146         } else if(strcmp(f[0], "delay") == 0){
147                 audiodelay = atoi(f[1]);
148                 speed = audiofreq;
149                 goto Setup;
150         }
151         r->ofcall.count = r->ifcall.count;
152         respond(r, nil);
153 }
154
155 Srv fs = {
156         .read = fsread,
157         .write = fswrite,
158 };
159
160 void
161 usage(void)
162 {
163         fprint(2, "%s devid\n", argv0);
164         exits("usage");
165 }
166
167 void
168 main(int argc, char *argv[])
169 {
170         char buf[32];
171         Dev *d, *ed;
172         Ep *e;
173         int i;
174
175         ARGBEGIN {
176         case 'D':
177                 chatty9p++;
178                 break;
179         case 'd':
180                 usbdebug++;
181                 break;
182         } ARGEND;
183
184         if(argc == 0)
185                 usage();
186
187         if((d = getdev(atoi(*argv))) == nil)
188                 sysfatal("getdev: %r");
189         audiodev = d;
190
191         /* parse descriptors, mark valid altc */
192         for(i = 0; i < nelem(d->usb->ddesc); i++)
193                 parsedescr(d->usb->ddesc[i]);
194         for(i = 0; i < nelem(d->usb->ep); i++){
195                 e = d->usb->ep[i];
196                 if(e && e->iface && e->iface->csp == CSP(Claudio, 2, 0)){
197                         switch(e->dir){
198                         case Ein:
199                                 if(audioepin != nil)
200                                         continue;
201                                 audioepin = e;
202                                 break;
203                         case Eout:
204                                 if(audioepout != nil)
205                                         continue;
206                                 audioepout = e;
207                                 break;
208                         case Eboth:
209                                 if(audioepin != nil && audioepout != nil)
210                                         continue;
211                                 if(audioepin == nil)
212                                         audioepin = e;
213                                 if(audioepout == nil)
214                                         audioepout = e;
215                                 break;
216                         }
217                         if((ed = setupep(audiodev, e, audiofreq)) == nil)
218                                 sysfatal("setupep: %r");
219                         closedev(ed);
220                 }
221         }
222         if(audioepout == nil)
223                 sysfatal("no endpoints found");
224
225         fs.tree = alloctree(user, "usb", DMDIR|0555, nil);
226         createfile(fs.tree->root, "volume", user, 0666, nil);
227
228         snprint(buf, sizeof buf, "%d.audio", audiodev->id);
229         postsharesrv(&fs, nil, "usb", buf);
230
231         exits(0);
232 }