#include #include #include #include #include #include <9p.h> enum { Xmixer = 1, Mixmax = 16, }; Alt *a; Channel *outchan; int nmix; int audiofd; struct muxdata { short *data; long len; long ptr; }; void buffer_thread(void *_p) { struct muxdata *md = mallocz(Mixmax * sizeof(struct muxdata*), 1); int i, j, k, m, minlen, nalts; Req *r = nil; short *out = nil; short *p = nil; minlen = nalts = i = j = k = m = 0; USED(_p); while (1) { while (nmix == 0) sleep(1000); /* mux */ i = alt(a); print("data on alt %d\n", i); /* no more data */ if (i == nmix) { out = mallocz(minlen, 1); /* * we only work on the smallest buffer we have so we don't * over/underflow. */ for (j = 0; j < nalts; j++) for (k = 0; k < minlen; k++) { p = md[i].data + md[i].ptr; print ("p %p\n", p); out[k] += p[k]; md[i].ptr += minlen; if (md[i].ptr == md[i].len) { free(md[i].data); md[i].data = nil; md[i].ptr = md[i].len = 0; } } print ("Sending %d bytes\n", minlen); sendul(outchan, minlen); sendp(outchan, out); /* block waiting for more data */ a[i].op = CHANEND; minlen = nalts = 0; continue; } /* we're getting data, don't block anymore... */ a[nmix].op = CHANNOBLK; r = *(Req **)a[i].v; if (md[i].data == nil) { md[i].data = mallocz(r->ifcall.count, 1); md[i].ptr = 0; } else md[i].data = realloc(md[i].data, r->ifcall.count + md[i].len); if (md[i].data == nil) { respond(r, "no memory"); exits("no memory"); } for (int m = 0; m < r->ifcall.count; m++) { short *ptr = (short *)r->ifcall.data; md[i].data[md[i].len] = *ptr++; } memcpy((char *)(md[i].data + md[i].len), r->ifcall.data, r->ifcall.count); md[i].len += r->ifcall.count; if (minlen == 0 || md[i].len ofcall.count = r->ifcall.count; print("oink ack %d bytes\n", r->ifcall.count); nalts++; } } void out_thread(void *p) { USED(p); while (1) { ulong len; short *r; len = recvul(outchan); r = recvp(outchan); print("received %l bytes\n", len); write(audiofd, r, len); } } void fsopen(Req *r) { int i = nmix++; a[nmix].c = a[nmix].v = nil; a[nmix].op = CHANEND; if (i == 16) { respond(r, "all channels in use"); return; } a[i].c = chancreate(sizeof(Req *), 0); a[i].op = CHANRCV; a[i].v = malloc(sizeof(Req *)); r->fid->aux = (void *)a[i].c; respond(r, nil); } void fswrite(Req *r) { Channel *c = (Channel *)r->fid->aux; /* don't bother if you can't fill our minimum buffer size */ if (r->ifcall.count < 8) { r->ofcall.count = 0; respond(r, nil); } else { print("Sending %l bytes\n", r->ifcall.count); sendp(c, r); } /* respond() done in buffer thread */ } Srv fs = { .open= fsopen, .write= fswrite, }; void threadmain(int argc, char **argv) { char *mtpt = "/dev/"; USED(argc); USED(argv); a = mallocz(16 * sizeof (Alt), 1); outchan = chancreate(sizeof (char *), 0); audiofd = open("/dev/audio", OWRITE); proccreate(buffer_thread, a, 32768); proccreate(out_thread, outchan, 32768); fs.tree = alloctree(nil, nil, DMDIR|0777, nil); closefile(createfile(fs.tree->root, "audio", nil, 0666, (void *)Xmixer)); threadpostmountsrv(&fs, "audiomux", mtpt, MBEFORE); recvp(chancreate(sizeof(void *), 0)); }