Annotation of src/usr.bin/aucat/dev.c, Revision 1.12
1.12 ! ratchov 1: /* $OpenBSD: dev.c,v 1.11 2008/11/07 21:01:15 ratchov Exp $ */
1.1 ratchov 2: /*
3: * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
4: *
5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
8: *
9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16: */
17: #include <stdio.h>
18: #include <stdlib.h>
19: #include <unistd.h>
20:
21: #include "dev.h"
22: #include "abuf.h"
23: #include "aproc.h"
1.3 ratchov 24: #include "pipe.h"
1.1 ratchov 25: #include "conf.h"
1.3 ratchov 26: #include "safile.h"
1.1 ratchov 27:
1.3 ratchov 28: unsigned dev_bufsz, dev_round, dev_rate;
29: unsigned dev_rate_div, dev_round_div;
1.1 ratchov 30: struct aparams dev_ipar, dev_opar;
31: struct aproc *dev_mix, *dev_sub, *dev_rec, *dev_play;
1.3 ratchov 32: struct file *dev_file;
1.1 ratchov 33:
34: /*
1.3 ratchov 35: * supported rates
1.1 ratchov 36: */
1.3 ratchov 37: #define NRATES (sizeof(dev_rates) / sizeof(dev_rates[0]))
38: unsigned dev_rates[] = {
39: 6400, 7200, 8000, 9600, 11025, 12000,
40: 12800, 14400, 16000, 19200, 22050, 24000,
41: 25600, 28800, 32000, 38400, 44100, 48000,
42: 51200, 57600, 64000, 76800, 88200, 96000,
43: 102400, 115200, 128000, 153600, 176400, 192000
44: };
1.1 ratchov 45:
46: /*
1.3 ratchov 47: * factors of supported rates
1.1 ratchov 48: */
1.3 ratchov 49: #define NPRIMES (sizeof(dev_primes) / sizeof(dev_primes[0]))
50: unsigned dev_primes[] = {2, 3, 5, 7};
1.1 ratchov 51:
1.3 ratchov 52: int
53: dev_setrate(unsigned rate)
1.1 ratchov 54: {
1.3 ratchov 55: unsigned i, r, p;
1.1 ratchov 56:
1.3 ratchov 57: r = 1000 * rate;
58: for (i = 0; i < NRATES; i++) {
59: if (i == NRATES) {
60: fprintf(stderr, "dev_setrate: %u, unsupported\n", rate);
61: return 0;
62: }
63: if (r > 996 * dev_rates[i] &&
64: r < 1004 * dev_rates[i]) {
65: dev_rate = dev_rates[i];
1.1 ratchov 66: break;
67: }
1.3 ratchov 68: }
69:
70: dev_rate_div = dev_rate;
71: dev_round_div = dev_round;
72: for (i = 0; i < NPRIMES; i++) {
73: p = dev_primes[i];
74: while (dev_rate_div % p == 0 && dev_round_div % p == 0) {
75: dev_rate_div /= p;
76: dev_round_div /= p;
1.1 ratchov 77: }
78: }
1.3 ratchov 79: return 1;
1.1 ratchov 80: }
81:
82: void
1.3 ratchov 83: dev_roundrate(unsigned *newrate, unsigned *newround)
1.1 ratchov 84: {
1.3 ratchov 85: *newrate += dev_rate_div - 1;
86: *newrate -= *newrate % dev_rate_div;
87: *newround = *newrate * dev_round_div / dev_rate_div;
1.1 ratchov 88: }
89:
90: /*
91: * open the device with the given hardware parameters and create a mixer
92: * and a multiplexer connected to it with all necessary conversions
93: * setup
94: */
95: void
1.3 ratchov 96: dev_init(char *devpath,
1.11 ratchov 97: struct aparams *dipar, struct aparams *dopar,
98: unsigned bufsz, int blkio)
1.1 ratchov 99: {
100: struct aparams ipar, opar;
101: struct aproc *conv;
102: struct abuf *buf;
1.3 ratchov 103: unsigned nfr, ibufsz, obufsz;
1.1 ratchov 104:
1.3 ratchov 105: /*
1.11 ratchov 106: * ask for 1/4 of the buffer for the kernel ring and
107: * limit the block size to 1/4 of the requested buffer
1.3 ratchov 108: */
109: dev_bufsz = (bufsz + 3) / 4;
1.11 ratchov 110: dev_round = (bufsz + 3) / 4;
1.3 ratchov 111: dev_file = (struct file *)safile_new(&safile_ops, devpath,
1.11 ratchov 112: dipar, dopar, &dev_bufsz, &dev_round, blkio);
1.3 ratchov 113: if (!dev_file)
114: exit(1);
115: if (!dev_setrate(dipar ? dipar->rate : dopar->rate))
1.1 ratchov 116: exit(1);
1.3 ratchov 117: if (dipar) {
118: dipar->rate = dev_rate;
119: if (debug_level > 0) {
1.9 ratchov 120: fprintf(stderr, "dev_init: hw recording ");
1.3 ratchov 121: aparams_print(dipar);
1.9 ratchov 122: fprintf(stderr, "\n");
1.3 ratchov 123: }
124: }
125: if (dopar) {
126: dopar->rate = dev_rate;
127: if (debug_level > 0) {
1.9 ratchov 128: fprintf(stderr, "dev_init: hw playing ");
1.3 ratchov 129: aparams_print(dopar);
1.9 ratchov 130: fprintf(stderr, "\n");
1.3 ratchov 131: }
132: }
1.11 ratchov 133: ibufsz = obufsz = dev_bufsz;
134: bufsz = (bufsz > dev_bufsz) ? bufsz - dev_bufsz : 0;
1.1 ratchov 135:
136: /*
1.11 ratchov 137: * use 1/8 of the buffer for the mixer/converters. Since we
138: * already consumed 1/4 for the device, bufsz represents the
139: * remaining 3/4. So 1/8 is 1/6 of 3/4
140: */
141: nfr = (bufsz + 5) / 6;
142: nfr += dev_round - 1;
143: nfr -= nfr % dev_round;
144: if (nfr == 0)
145: nfr = dev_round;
146:
147: /*
148: * create record chain
1.1 ratchov 149: */
150: if (dipar) {
151: aparams_init(&ipar, dipar->cmin, dipar->cmax, dipar->rate);
152: /*
153: * create the read end
154: */
155: dev_rec = rpipe_new(dev_file);
1.4 ratchov 156: buf = abuf_new(nfr, dipar);
1.1 ratchov 157: aproc_setout(dev_rec, buf);
1.3 ratchov 158: ibufsz += nfr;
1.1 ratchov 159:
160: /*
161: * append a converter, if needed
162: */
1.4 ratchov 163: if (!aparams_eqenc(dipar, &ipar)) {
1.9 ratchov 164: conv = dec_new("subin", dipar);
1.1 ratchov 165: aproc_setin(conv, buf);
1.4 ratchov 166: buf = abuf_new(nfr, &ipar);
1.1 ratchov 167: aproc_setout(conv, buf);
1.3 ratchov 168: ibufsz += nfr;
1.1 ratchov 169: }
170: dev_ipar = ipar;
171:
172: /*
173: * append a "sub" to which clients will connect
174: */
1.3 ratchov 175: dev_sub = sub_new("sub", nfr);
1.1 ratchov 176: aproc_setin(dev_sub, buf);
177: } else {
178: dev_rec = NULL;
179: dev_sub = NULL;
180: }
181:
182: /*
183: * create play chain
184: */
185: if (dopar) {
186: aparams_init(&opar, dopar->cmin, dopar->cmax, dopar->rate);
187: /*
188: * create the write end
189: */
190: dev_play = wpipe_new(dev_file);
1.4 ratchov 191: buf = abuf_new(nfr, dopar);
1.1 ratchov 192: aproc_setin(dev_play, buf);
1.3 ratchov 193: obufsz += nfr;
194:
1.1 ratchov 195: /*
196: * append a converter, if needed
197: */
1.4 ratchov 198: if (!aparams_eqenc(&opar, dopar)) {
1.9 ratchov 199: conv = enc_new("mixout", dopar);
1.1 ratchov 200: aproc_setout(conv, buf);
1.4 ratchov 201: buf = abuf_new(nfr, &opar);
1.1 ratchov 202: aproc_setin(conv, buf);
1.3 ratchov 203: obufsz += nfr;
1.1 ratchov 204: }
205: dev_opar = opar;
206:
207: /*
208: * append a "mix" to which clients will connect
209: */
1.3 ratchov 210: dev_mix = mix_new("mix", nfr);
1.1 ratchov 211: aproc_setout(dev_mix, buf);
212: } else {
213: dev_play = NULL;
214: dev_mix = NULL;
215: }
1.3 ratchov 216: dev_bufsz = (dopar) ? obufsz : ibufsz;
217: DPRINTF("dev_init: using %u fpb\n", dev_bufsz);
218: dev_start();
1.1 ratchov 219: }
220:
221: /*
222: * cleanly stop and drain everything and close the device
223: * once both play chain and record chain are gone
224: */
225: void
226: dev_done(void)
227: {
228: struct file *f;
229:
1.3 ratchov 230: if (dev_mix) {
231: /*
232: * generate EOF on all inputs (but not the device), and
233: * put the mixer in ``autoquit'' state, so once buffers
234: * are drained the mixer will terminate and shutdown the
235: * write-end of the device
236: *
237: * NOTE: since file_eof() can destroy the file and
238: * reorder the file_list, we have to restart the loop
239: * after each call to file_eof()
240: */
241: restart:
242: LIST_FOREACH(f, &file_list, entry) {
243: if (f != dev_file && f->rproc) {
244: file_eof(f);
245: goto restart;
246: }
247: }
248: if (dev_mix)
249: dev_mix->u.mix.flags |= MIX_AUTOQUIT;
250:
251: /*
252: * wait play chain to terminate
253: */
254: while (dev_file->wproc != NULL) {
255: if (!file_poll())
256: break;
257: }
258: dev_mix = 0;
1.1 ratchov 259: }
1.3 ratchov 260: if (dev_sub) {
261: /*
262: * same as above, but for the record chain: generate eof
263: * on the read-end of the device and wait record buffers
264: * to desappear. We must stop the device first, because
265: * play-end will underrun (and xrun correction code will
266: * insert silence on the record-end of the device)
267: */
268: dev_stop();
269: file_eof(dev_file);
270: if (dev_sub)
271: dev_sub->u.sub.flags |= SUB_AUTOQUIT;
272: for (;;) {
273: if (!file_poll())
274: break;
275: }
276: dev_sub = NULL;
1.1 ratchov 277: }
278: }
279:
280: /*
281: * start the (paused) device. By default it's paused
282: */
283: void
284: dev_start(void)
285: {
286: if (dev_mix)
287: dev_mix->u.mix.flags |= MIX_DROP;
288: if (dev_sub)
289: dev_sub->u.sub.flags |= SUB_DROP;
1.3 ratchov 290: dev_file->ops->start(dev_file);
1.1 ratchov 291: }
292:
293: /*
294: * pause the device
295: */
296: void
297: dev_stop(void)
298: {
1.3 ratchov 299: dev_file->ops->stop(dev_file);
1.1 ratchov 300: if (dev_mix)
301: dev_mix->u.mix.flags &= ~MIX_DROP;
302: if (dev_sub)
303: dev_sub->u.sub.flags &= ~SUB_DROP;
304: }
305:
306: /*
1.3 ratchov 307: * sync play buffer to rec buffer (for instance when one of
308: * them underruns/overruns)
1.1 ratchov 309: */
310: void
1.3 ratchov 311: dev_sync(struct abuf *ibuf, struct abuf *obuf)
1.1 ratchov 312: {
1.3 ratchov 313: struct abuf *pbuf, *rbuf;
314: int delta;
315:
316: if (!dev_mix || !dev_sub)
317: return;
318: pbuf = LIST_FIRST(&dev_mix->obuflist);
319: if (!pbuf)
320: return;
321: rbuf = LIST_FIRST(&dev_sub->ibuflist);
322: if (!rbuf)
323: return;
324: for (;;) {
325: if (!ibuf || !ibuf->rproc) {
326: DPRINTF("dev_sync: reader desappeared\n");
327: return;
328: }
329: if (ibuf->rproc == dev_mix)
1.1 ratchov 330: break;
1.3 ratchov 331: ibuf = LIST_FIRST(&ibuf->rproc->obuflist);
332: }
333: for (;;) {
334: if (!obuf || !obuf->wproc) {
335: DPRINTF("dev_sync: writer desappeared\n");
336: return;
337: }
338: if (obuf->wproc == dev_sub)
1.1 ratchov 339: break;
1.3 ratchov 340: obuf = LIST_FIRST(&obuf->wproc->ibuflist);
1.1 ratchov 341: }
1.3 ratchov 342:
343: /*
344: * calculate delta, the number of frames the play chain is ahead
345: * of the record chain. It's necessary to schedule silences (or
346: * drops) in order to start playback and record in sync.
347: */
348: delta =
349: rbuf->bpf * (pbuf->abspos + pbuf->used) -
350: pbuf->bpf * rbuf->abspos;
351: delta /= pbuf->bpf * rbuf->bpf;
352: DPRINTF("dev_sync: delta = %d, ppos = %u, pused = %u, rpos = %u\n",
353: delta, pbuf->abspos, pbuf->used, rbuf->abspos);
354:
355: if (delta > 0) {
356: /*
357: * if the play chain is ahead (most cases) drop some of
358: * the recorded input, to get both in sync
359: */
360: obuf->drop += delta * obuf->bpf;
361: abuf_ipos(obuf, -delta);
362: } else if (delta < 0) {
363: /*
364: * if record chain is ahead (should never happen,
365: * right?) then insert silence to play
366: */
367: ibuf->silence += -delta * ibuf->bpf;
368: abuf_opos(ibuf, delta);
369: } else
370: DPRINTF("dev_sync: nothing to do\n");
1.1 ratchov 371: }
372:
373: /*
374: * attach the given input and output buffers to the mixer and the
375: * multiplexer respectively. The operation is done synchronously, so
376: * both buffers enter in sync. If buffers do not match play
377: * and rec
378: */
379: void
380: dev_attach(char *name,
1.10 ratchov 381: struct abuf *ibuf, struct aparams *sipar, unsigned underrun,
382: struct abuf *obuf, struct aparams *sopar, unsigned overrun)
1.1 ratchov 383: {
384: struct abuf *pbuf = NULL, *rbuf = NULL;
1.12 ! ratchov 385: struct aparams ipar, opar;
1.1 ratchov 386: struct aproc *conv;
1.3 ratchov 387: unsigned nfr;
1.1 ratchov 388:
389: if (ibuf) {
1.12 ! ratchov 390: ipar = *sipar;
1.1 ratchov 391: pbuf = LIST_FIRST(&dev_mix->obuflist);
1.10 ratchov 392: if (!aparams_eqenc(&ipar, &dev_opar)) {
1.3 ratchov 393: nfr = (dev_bufsz + 3) / 4 + dev_round - 1;
394: nfr -= nfr % dev_round;
1.10 ratchov 395: conv = dec_new(name, &ipar);
396: ipar.bps = dev_opar.bps;
397: ipar.bits = dev_opar.bits;
398: ipar.sig = dev_opar.sig;
399: ipar.le = dev_opar.le;
400: ipar.msb = dev_opar.msb;
1.9 ratchov 401: aproc_setin(conv, ibuf);
1.10 ratchov 402: ibuf = abuf_new(nfr, &ipar);
1.9 ratchov 403: aproc_setout(conv, ibuf);
1.8 ratchov 404: }
1.10 ratchov 405: if (!aparams_subset(&ipar, &dev_opar)) {
1.7 ratchov 406: nfr = (dev_bufsz + 3) / 4 + dev_round - 1;
407: nfr -= nfr % dev_round;
1.10 ratchov 408: conv = cmap_new(name, &ipar, &dev_opar);
409: ipar.cmin = dev_opar.cmin;
410: ipar.cmax = dev_opar.cmax;
1.7 ratchov 411: aproc_setin(conv, ibuf);
1.10 ratchov 412: ibuf = abuf_new(nfr, &ipar);
1.7 ratchov 413: aproc_setout(conv, ibuf);
1.6 ratchov 414: }
1.10 ratchov 415: if (!aparams_eqrate(&ipar, &dev_opar)) {
1.5 ratchov 416: nfr = (dev_bufsz + 3) / 4 + dev_round - 1;
417: nfr -= nfr % dev_round;
1.10 ratchov 418: conv = resamp_new(name, &ipar, &dev_opar);
419: ipar.rate = dev_opar.rate;
1.5 ratchov 420: aproc_setin(conv, ibuf);
1.10 ratchov 421: ibuf = abuf_new(nfr, &ipar);
1.5 ratchov 422: aproc_setout(conv, ibuf);
1.1 ratchov 423: }
424: aproc_setin(dev_mix, ibuf);
1.3 ratchov 425: abuf_opos(ibuf, -dev_mix->u.mix.lat);
1.1 ratchov 426: ibuf->xrun = underrun;
427: }
428: if (obuf) {
1.12 ! ratchov 429: opar = *sopar;
1.1 ratchov 430: rbuf = LIST_FIRST(&dev_sub->ibuflist);
1.10 ratchov 431: if (!aparams_eqenc(&opar, &dev_ipar)) {
1.3 ratchov 432: nfr = (dev_bufsz + 3) / 4 + dev_round - 1;
433: nfr -= nfr % dev_round;
1.10 ratchov 434: conv = enc_new(name, &opar);
435: opar.bps = dev_ipar.bps;
436: opar.bits = dev_ipar.bits;
437: opar.sig = dev_ipar.sig;
438: opar.le = dev_ipar.le;
439: opar.msb = dev_ipar.msb;
1.9 ratchov 440: aproc_setout(conv, obuf);
1.10 ratchov 441: obuf = abuf_new(nfr, &opar);
1.9 ratchov 442: aproc_setin(conv, obuf);
1.8 ratchov 443: }
1.10 ratchov 444: if (!aparams_subset(&opar, &dev_ipar)) {
1.7 ratchov 445: nfr = (dev_bufsz + 3) / 4 + dev_round - 1;
446: nfr -= nfr % dev_round;
1.10 ratchov 447: conv = cmap_new(name, &dev_ipar, &opar);
448: opar.cmin = dev_ipar.cmin;
449: opar.cmax = dev_ipar.cmax;
1.7 ratchov 450: aproc_setout(conv, obuf);
1.10 ratchov 451: obuf = abuf_new(nfr, &opar);
1.7 ratchov 452: aproc_setin(conv, obuf);
1.6 ratchov 453: }
1.10 ratchov 454: if (!aparams_eqrate(&opar, &dev_ipar)) {
1.5 ratchov 455: nfr = (dev_bufsz + 3) / 4 + dev_round - 1;
456: nfr -= nfr % dev_round;
1.10 ratchov 457: conv = resamp_new(name, &dev_ipar, &opar);
458: opar.rate = dev_ipar.rate;
1.1 ratchov 459: aproc_setout(conv, obuf);
1.10 ratchov 460: obuf = abuf_new(nfr, &opar);
1.1 ratchov 461: aproc_setin(conv, obuf);
462: }
463: aproc_setout(dev_sub, obuf);
1.3 ratchov 464: abuf_ipos(obuf, -dev_sub->u.sub.lat);
1.1 ratchov 465: obuf->xrun = overrun;
466: }
467:
468: /*
1.3 ratchov 469: * sync play to record
1.1 ratchov 470: */
471: if (ibuf && obuf) {
1.3 ratchov 472: ibuf->duplex = obuf;
473: obuf->duplex = ibuf;
474: dev_sync(ibuf, obuf);
1.1 ratchov 475: }
476: }