Annotation of src/usr.bin/aucat/safile.c, Revision 1.4
1.4 ! ratchov 1: /* $OpenBSD: safile.c,v 1.3 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:
18: #include <sys/types.h>
19: #include <sys/time.h>
20:
21: #include <poll.h>
22: #include <stdio.h>
23: #include <stdlib.h>
24: #include <string.h>
1.2 ratchov 25: #include <sndio.h>
1.1 ratchov 26:
27: #include "conf.h"
28: #include "file.h"
29: #include "aproc.h"
30: #include "aparams.h"
31: #include "safile.h"
32: #include "dev.h"
33:
34: struct safile {
35: struct file file;
1.2 ratchov 36: struct sio_hdl *hdl;
1.1 ratchov 37: #ifdef DEBUG
38: struct timeval itv, otv;
39: #endif
40: };
41:
42: void safile_close(struct file *);
43: unsigned safile_read(struct file *, unsigned char *, unsigned);
44: unsigned safile_write(struct file *, unsigned char *, unsigned);
45: void safile_start(struct file *);
46: void safile_stop(struct file *);
47: int safile_nfds(struct file *);
48: int safile_pollfd(struct file *, struct pollfd *, int);
49: int safile_revents(struct file *, struct pollfd *);
50:
51: struct fileops safile_ops = {
1.3 ratchov 52: "sndio",
1.1 ratchov 53: sizeof(struct safile),
54: safile_close,
55: safile_read,
56: safile_write,
57: safile_start,
58: safile_stop,
59: safile_nfds,
60: safile_pollfd,
61: safile_revents
62: };
63:
1.3 ratchov 64: /*
65: * list of (rate, block-size) pairs ordered by frequency preference and
66: * then by block size preference (except for jumbo block sizes that are
67: * less prefered than anything else).
68: */
69: struct blkdesc {
70: unsigned rate; /* sample rate */
71: unsigned round; /* usable block sizes */
72: } blkdesc[] = {
73: { 44100, 882 },
74: { 44100, 840 },
75: { 44100, 441 },
76: { 44100, 420 },
77: { 44100, 1764 },
78: { 44100, 1680 },
79: { 48000, 960 },
80: { 48000, 768 },
81: { 48000, 480 },
82: { 48000, 384 },
83: { 48000, 1920 },
84: { 48000, 1536 },
85: { 32000, 640 },
86: { 32000, 512 },
87: { 32000, 320 },
88: { 32000, 256 },
89: { 32000, 1280 },
90: { 32000, 1024 },
91: { 44100, 2940 },
92: { 48000, 2976 },
93: { 32000, 3200 },
94: { 8000, 320 },
95: { 8000, 256 },
96: { 0, 0 }
97: };
98:
99:
100: int
101: safile_trypar(struct sio_hdl *hdl, struct sio_par *par, int blkio)
102: {
103: struct blkdesc *d;
104: struct sio_par np;
105: unsigned rate = par->rate;
106: unsigned round = par->round;
107:
108: if (!blkio) {
1.4 ! ratchov 109: DPRINTF("safile_trypar: not setting block size\n");
1.3 ratchov 110: if (!sio_setpar(hdl, par))
111: return 0;
112: if (!sio_getpar(hdl, par))
113: return 0;
114: return 1;
115: }
116:
117: /*
118: * find the rate we want to use
119: */
120: for (d = blkdesc;; d++) {
121: if (d->rate == 0) {
122: d = blkdesc;
123: break;
124: }
125: if (d->rate == rate)
126: break;
127: }
128:
129: /*
130: * find the first matching entry, (the blkdesc array is)
131: * sorted by order of preference)
132: */
133: for (;; d++) {
134: if (d->rate == 0)
135: break;
136: if (d->round > round)
137: continue;
138: par->rate = d->rate;
139: par->round = d->round;
140: if (!sio_setpar(hdl, par))
141: return 0;
142: if (!sio_getpar(hdl, &np))
143: return 0;
144: if (np.rate == d->rate && np.round == d->round) {
145: *par = np;
146: if (d->round >= d->rate / 15)
147: fprintf(stderr,
148: "Warning: using jumbo block size, "
149: "try to use another sample rate.\n");
150: return 1;
151: }
152: DPRINTF("safile_trypar: %uHz/%ufr failed, got %uHz/%ufr\n",
153: d->rate, d->round, np.rate, np.round);
154: }
155: fprintf(stderr, "Couldn't set block size to <%u frames.\n", round);
156: return 0;
157: }
158:
1.1 ratchov 159: void
160: safile_cb(void *addr, int delta)
161: {
162: struct safile *f = (struct safile *)addr;
163: struct aproc *p;
164:
165: if (delta != 0) {
166: p = f->file.wproc;
167: if (p && p->ops->opos)
168: p->ops->opos(p, NULL, delta);
169: }
170: if (delta != 0) {
171: p = f->file.rproc;
172: if (p && p->ops->ipos)
173: p->ops->ipos(p, NULL, delta);
174: }
175: }
176:
177: /*
178: * open the device
179: */
180: struct safile *
181: safile_new(struct fileops *ops, char *path,
182: struct aparams *ipar, struct aparams *opar,
1.3 ratchov 183: unsigned *bufsz, unsigned *round, int blkio)
1.1 ratchov 184: {
1.2 ratchov 185: struct sio_par par;
186: struct sio_hdl *hdl;
1.1 ratchov 187: struct safile *f;
188: int mode;
189:
190: mode = 0;
191: if (ipar)
1.2 ratchov 192: mode |= SIO_REC;
1.1 ratchov 193: if (opar)
1.2 ratchov 194: mode |= SIO_PLAY;
1.4 ! ratchov 195: if (!mode) {
! 196: fprintf(stderr, "select at least play or record mode\n");
! 197: return NULL;
! 198: }
1.2 ratchov 199: hdl = sio_open(path, mode, 1);
1.1 ratchov 200: if (hdl == NULL) {
201: fprintf(stderr, "safile_new: can't open device\n");
202: return NULL;
203: }
1.2 ratchov 204: sio_initpar(&par);
1.1 ratchov 205: if (ipar) {
206: par.bits = ipar->bits;
207: par.bps = ipar->bps;
208: par.sig = ipar->sig;
209: par.le = ipar->le;
210: par.msb = ipar->msb;
211: par.rate = ipar->rate;
212: par.rchan = ipar->cmax - ipar->cmin + 1;
213: } else {
214: par.bits = opar->bits;
215: par.bps = opar->bps;
216: par.sig = opar->sig;
217: par.le = opar->le;
218: par.msb = opar->msb;
219: par.rate = opar->rate;
220: }
221: if (opar)
222: par.pchan = opar->cmax - opar->cmin + 1;
1.3 ratchov 223: par.bufsz = *bufsz;
224: par.round = *round;
225: if (!safile_trypar(hdl, &par, blkio))
1.1 ratchov 226: exit(1);
227: if (ipar) {
228: ipar->bits = par.bits;
229: ipar->bps = par.bps;
230: ipar->sig = par.sig;
231: ipar->le = par.le;
232: ipar->msb = par.msb;
233: ipar->rate = par.rate;
234: ipar->cmax = par.rchan - 1;
235: ipar->cmin = 0;
236: }
237: if (opar) {
238: opar->bits = par.bits;
239: opar->bps = par.bps;
240: opar->sig = par.sig;
241: opar->le = par.le;
242: opar->msb = par.msb;
243: opar->rate = par.rate;
244: opar->cmax = par.pchan - 1;
245: opar->cmin = 0;
246: }
247: *bufsz = par.bufsz;
248: *round = par.round;
1.3 ratchov 249: DPRINTF("safile_new: using %u(%u) fpb\n", *bufsz, *round);
1.2 ratchov 250: f = (struct safile *)file_new(ops, "hdl", sio_nfds(hdl));
1.1 ratchov 251: f->hdl = hdl;
1.2 ratchov 252: sio_onmove(f->hdl, safile_cb, f);
1.1 ratchov 253: return f;
254: }
255:
256: void
257: safile_start(struct file *file)
258: {
259: struct safile *f = (struct safile *)file;
260:
1.2 ratchov 261: if (!sio_start(f->hdl)) {
262: fprintf(stderr, "safile_start: sio_start() failed\n");
1.1 ratchov 263: exit(1);
264: }
265: DPRINTF("safile_start: play/rec started\n");
266: }
267:
268: void
269: safile_stop(struct file *file)
270: {
271: struct safile *f = (struct safile *)file;
272:
1.2 ratchov 273: if (!sio_stop(f->hdl)) {
274: fprintf(stderr, "safile_stop: sio_start() filed\n");
1.1 ratchov 275: exit(1);
276: }
277: DPRINTF("safile_stop: play/rec stopped\n");
278: }
279:
280: unsigned
281: safile_read(struct file *file, unsigned char *data, unsigned count)
282: {
283: struct safile *f = (struct safile *)file;
284: unsigned n;
285: #ifdef DEBUG
286: struct timeval tv0, tv1, dtv;
287: unsigned us;
288:
289: if (!(f->file.state & FILE_ROK)) {
290: DPRINTF("file_read: %s: bad state\n", f->file.name);
291: abort();
292: }
293: gettimeofday(&tv0, NULL);
294: #endif
1.2 ratchov 295: n = sio_read(f->hdl, data, count);
1.1 ratchov 296: if (n == 0) {
297: f->file.state &= ~FILE_ROK;
1.2 ratchov 298: if (sio_eof(f->hdl)) {
1.1 ratchov 299: fprintf(stderr, "safile_read: eof\n");
300: file_eof(&f->file);
301: } else {
302: DPRINTFN(3, "safile_read: %s: blocking...\n",
303: f->file.name);
304: }
305: return 0;
306: }
307: #ifdef DEBUG
308: gettimeofday(&tv1, NULL);
309: timersub(&tv1, &tv0, &dtv);
310: us = dtv.tv_sec * 1000000 + dtv.tv_usec;
311: DPRINTFN(us < 5000 ? 4 : 1,
312: "safile_read: %s: got %d bytes in %uus\n",
313: f->file.name, n, us);
314: #endif
315: return n;
316:
317: }
318:
319: unsigned
320: safile_write(struct file *file, unsigned char *data, unsigned count)
321: {
322: struct safile *f = (struct safile *)file;
323: unsigned n;
324: #ifdef DEBUG
325: struct timeval tv0, tv1, dtv;
326: unsigned us;
327:
328: if (!(f->file.state & FILE_WOK)) {
329: DPRINTF("safile_write: %s: bad state\n", f->file.name);
330: abort();
331: }
332: gettimeofday(&tv0, NULL);
333: #endif
1.2 ratchov 334: n = sio_write(f->hdl, data, count);
1.1 ratchov 335: if (n == 0) {
336: f->file.state &= ~FILE_WOK;
1.2 ratchov 337: if (sio_eof(f->hdl)) {
1.1 ratchov 338: fprintf(stderr, "safile_write: %s: hup\n", f->file.name);
339: file_hup(&f->file);
340: } else {
341: DPRINTFN(3, "safile_write: %s: blocking...\n",
342: f->file.name);
343: }
344: return 0;
345: }
346: #ifdef DEBUG
347: gettimeofday(&tv1, NULL);
348: timersub(&tv1, &tv0, &dtv);
349: us = dtv.tv_sec * 1000000 + dtv.tv_usec;
350: DPRINTFN(us < 5000 ? 4 : 1,
351: "safile_write: %s: wrote %d bytes in %uus\n",
352: f->file.name, n, us);
353: #endif
354: return n;
355: }
356:
357: int
358: safile_nfds(struct file *file)
359: {
1.2 ratchov 360: return sio_nfds(((struct safile *)file)->hdl);
1.1 ratchov 361: }
362:
363: int
364: safile_pollfd(struct file *file, struct pollfd *pfd, int events)
365: {
1.2 ratchov 366: return sio_pollfd(((struct safile *)file)->hdl, pfd, events);
1.1 ratchov 367: }
368:
369: int
370: safile_revents(struct file *file, struct pollfd *pfd)
371: {
1.2 ratchov 372: return sio_revents(((struct safile *)file)->hdl, pfd);
1.1 ratchov 373: }
374:
375: void
376: safile_close(struct file *file)
377: {
1.2 ratchov 378: return sio_close(((struct safile *)file)->hdl);
1.1 ratchov 379: }