2 #include "../port/lib.h"
7 #include "../port/error.h"
8 #include "../port/audioif.h"
10 typedef struct Audioprobe Audioprobe;
11 typedef struct Audiochan Audiochan;
38 static Dirtab audiodir[] = {
39 ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
40 "audio", {Qaudio}, 0, 0666,
41 "audioctl", {Qaudioctl}, 0, 0222,
42 "audiostat", {Qaudiostat}, 0, 0444,
43 "volume", {Qvolume}, 0, 0666,
47 static int naudioprobes;
48 static Audioprobe audioprobes[16];
49 static Audio *audiodevs;
51 static char Evolume[] = "illegal volume specifier";
52 static char Ebusy[] = "device is busy";
55 addaudiocard(char *name, int (*probefn)(Audio *))
59 if(naudioprobes >= nelem(audioprobes))
62 probe = &audioprobes[naudioprobes++];
64 probe->probe = probefn;
75 *pp = malloc(sizeof(Audio));
77 for(i=0; i<naudioprobes; i++){
78 probe = &audioprobes[i];
82 print("audio: no memory\n");
85 memset(*pp, 0, sizeof(Audio));
86 (*pp)->ctlrno = ctlrno;
87 (*pp)->name = probe->name;
93 *pp = malloc(sizeof(Audio));
102 audioclone(Chan *c, Audio *adev)
106 ac = malloc(sizeof(Audiochan));
121 audioattach(char *spec)
123 static int attached = 0;
129 if(spec != nil && *spec != '\0')
130 i = strtol(spec, 0, 10);
133 for(adev = audiodevs; adev; adev = adev->next)
134 if(adev->ctlrno == i)
139 c = devattach('A', spec);
142 if((ac = audioclone(c, adev)) == nil)
146 if((attached & i) == 0){
147 static char *settings[] = {
149 "delay 882", /* 20 ms */
156 for(i=0; i<nelem(settings) && adev->volwrite; i++){
157 strcpy(ac->buf, settings[i]);
159 adev->volwrite(adev, ac->buf, strlen(ac->buf), 0);
169 audioopen(Chan *c, int omode)
176 if((c->qid.path == Qaudio) && (incref(&adev->audioopen) != 1)){
177 decref(&adev->audioopen);
180 return devopen(c, omode, audiodir, nelem(audiodir), devgen);
184 audioread(Chan *c, void *a, long n, vlong off)
188 long (*fn)(Audio *, void *, long, vlong);
194 switch((ulong)c->qid.path){
196 audiodir[Qaudio].length = adev->buffered ? adev->buffered(adev) : 0;
197 return devdirread(c, a, n, audiodir, nelem(audiodir), devgen);
216 switch((ulong)c->qid.path){
219 /* generate the text on first read */
220 if(ac->data == nil || off == 0){
224 l = fn(adev, ac->buf, sizeof(ac->buf)-1, 0);
230 /* then serve all requests from buffer */
231 n = readstr(off, a, n, ac->data);
235 n = fn(adev, a, n, off);
243 audiowrite(Chan *c, void *a, long n, vlong off)
247 long (*fn)(Audio *, void *, long, vlong);
253 switch((ulong)c->qid.path){
272 switch((ulong)c->qid.path){
275 if(n >= sizeof(ac->buf))
278 /* copy data to audiochan buffer so it can be modified */
280 memmove(ac->buf, a, n);
285 n = fn(adev, a, n, off);
299 if((c->qid.path == Qaudio) && (c->flag & COPEN)){
306 decref(&adev->audioopen);
316 audiowalk(Chan *c, Chan *nc, char **name, int nname)
324 wq = devwalk(c, nc, name, nname, audiodir, nelem(audiodir), devgen);
326 if(audioclone(wq->clone, adev) == nil){
335 audiostat(Chan *c, uchar *dp, int n)
342 if((ulong)c->qid.path == Qaudio)
343 audiodir[Qaudio].length = adev->buffered ? adev->buffered(adev) : 0;
344 return devstat(c, dp, n, audiodir, nelem(audiodir), devgen);
348 * audioread() made sure the buffer is big enougth so a full volume
349 * table can be serialized in one pass.
352 genaudiovolread(Audio *adev, void *a, long n, vlong,
353 Volume *vol, int (*volget)(Audio *, int, int *), ulong caps)
360 for(i = 0; vol[i].name != 0; ++i){
361 if(vol[i].cap && (vol[i].cap & caps) == 0)
365 if((*volget)(adev, i, v) != 0)
367 if(vol[i].type == Absolute)
368 p += snprint(p, e - p, "%s %d\n", vol[i].name, v[0]);
370 if(vol[i].range == 0)
375 if(v[j] > vol[i].range)
377 v[j] = (v[j]*100)/vol[i].range;
381 p += snprint(p, e - p, "%s %d\n", vol[i].name, v[0]);
384 p += snprint(p, e - p, "%s %d\n", vol[i].name, v[1]);
387 p += snprint(p, e - p, "%s %d %d\n", vol[i].name, v[0], v[1]);
397 * genaudiovolwrite modifies the buffer that gets passed to it. this
398 * is ok as long as it is called from inside Audio.volwrite() because
399 * audiowrite() copies the data to Audiochan.buf[] and inserts a
400 * terminating \0 byte before calling Audio.volwrite().
403 genaudiovolwrite(Audio *adev, void *a, long n, vlong,
404 Volume *vol, int (*volset)(Audio *, int, int *), ulong caps)
406 int ntok, i, j, v[2];
407 char *p, *e, *x, *tok[4];
413 if(x = strchr(p, '\n'))
417 ntok = tokenize(p, tok, 4);
425 for(i = 0; vol[i].name != 0; i++){
426 if(vol[i].cap && (vol[i].cap & caps) == 0)
428 if(cistrcmp(vol[i].name, tok[0]))
431 if((ntok>2) && (!cistrcmp(tok[1], "out") || !cistrcmp(tok[1], "in")))
432 memmove(tok+1, tok+2, --ntok);
437 v[0] = v[1] = atoi(tok[1]);
440 if(vol[i].type == Absolute)
441 (*volset)(adev, i, v);
444 v[j] = (50+(v[j]*vol[i].range))/100;
447 if(v[j] > vol[i].range)
450 (*volset)(adev, i, v);
454 if(vol[i].name == nil)