xref: /openbsd-src/lib/libsndio/sio_aucat.c (revision 7e5c91da414179335982dec10d2728a79533d1fb)
1 /*	$OpenBSD: sio_aucat.c,v 1.5 2011/04/18 23:57:35 ratchov Exp $	*/
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/socket.h>
20 #include <sys/un.h>
21 
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <poll.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 
30 #include "aucat.h"
31 #include "debug.h"
32 #include "sio_priv.h"
33 
34 struct sio_aucat_hdl {
35 	struct sio_hdl sio;
36 	struct aucat aucat;
37 	unsigned rbpf, wbpf;		/* read and write bytes-per-frame */
38 	int maxwrite;			/* latency constraint */
39 	int events;			/* events the user requested */
40 	unsigned curvol, reqvol;	/* current and requested volume */
41 	int delta;			/* some of received deltas */
42 #define PSTATE_INIT	0
43 #define PSTATE_RUN	1
44 	int pstate;
45 };
46 
47 static void sio_aucat_close(struct sio_hdl *);
48 static int sio_aucat_start(struct sio_hdl *);
49 static int sio_aucat_stop(struct sio_hdl *);
50 static int sio_aucat_setpar(struct sio_hdl *, struct sio_par *);
51 static int sio_aucat_getpar(struct sio_hdl *, struct sio_par *);
52 static int sio_aucat_getcap(struct sio_hdl *, struct sio_cap *);
53 static size_t sio_aucat_read(struct sio_hdl *, void *, size_t);
54 static size_t sio_aucat_write(struct sio_hdl *, const void *, size_t);
55 static int sio_aucat_nfds(struct sio_hdl *);
56 static int sio_aucat_pollfd(struct sio_hdl *, struct pollfd *, int);
57 static int sio_aucat_revents(struct sio_hdl *, struct pollfd *);
58 static int sio_aucat_setvol(struct sio_hdl *, unsigned);
59 static void sio_aucat_getvol(struct sio_hdl *);
60 
61 static struct sio_ops sio_aucat_ops = {
62 	sio_aucat_close,
63 	sio_aucat_setpar,
64 	sio_aucat_getpar,
65 	sio_aucat_getcap,
66 	sio_aucat_write,
67 	sio_aucat_read,
68 	sio_aucat_start,
69 	sio_aucat_stop,
70 	sio_aucat_nfds,
71 	sio_aucat_pollfd,
72 	sio_aucat_revents,
73 	sio_aucat_setvol,
74 	sio_aucat_getvol
75 };
76 
77 /*
78  * execute the next message, return 0 if blocked
79  */
80 static int
81 sio_aucat_runmsg(struct sio_aucat_hdl *hdl)
82 {
83 	if (!aucat_rmsg(&hdl->aucat, &hdl->sio.eof))
84 		return 0;
85 	switch (hdl->aucat.rmsg.cmd) {
86 	case AMSG_DATA:
87 		if (hdl->aucat.rmsg.u.data.size == 0 ||
88 		    hdl->aucat.rmsg.u.data.size % hdl->rbpf) {
89 			DPRINTF("sio_aucat_runmsg: bad data message\n");
90 			hdl->sio.eof = 1;
91 			return 0;
92 		}
93 		return 1;
94 	case AMSG_POS:
95 		hdl->maxwrite += hdl->aucat.rmsg.u.ts.delta * (int)hdl->wbpf;
96 		DPRINTF("aucat: pos = %d, maxwrite = %d\n",
97 		    hdl->aucat.rmsg.u.ts.delta, hdl->maxwrite);
98 		hdl->delta = hdl->aucat.rmsg.u.ts.delta;
99 		break;
100 	case AMSG_MOVE:
101 		hdl->maxwrite += hdl->aucat.rmsg.u.ts.delta * hdl->wbpf;
102 		hdl->delta += hdl->aucat.rmsg.u.ts.delta;
103 		DPRINTF("aucat: move = %d, delta = %d, maxwrite = %d\n",
104 		    hdl->aucat.rmsg.u.ts.delta, hdl->delta, hdl->maxwrite);
105 		if (hdl->delta >= 0) {
106 			sio_onmove_cb(&hdl->sio, hdl->delta);
107 			hdl->delta = 0;
108 		}
109 		break;
110 	case AMSG_SETVOL:
111 		hdl->curvol = hdl->reqvol = hdl->aucat.rmsg.u.vol.ctl;
112 		sio_onvol_cb(&hdl->sio, hdl->curvol);
113 		break;
114 	case AMSG_STOP:
115 		hdl->pstate = PSTATE_INIT;
116 		break;
117 	default:
118 		DPRINTF("sio_aucat_runmsg: unhandled message %u\n", hdl->aucat.rmsg.cmd);
119 		hdl->sio.eof = 1;
120 		return 0;
121 	}
122 	hdl->aucat.rstate = RSTATE_MSG;
123 	hdl->aucat.rtodo = sizeof(struct amsg);
124 	return 1;
125 }
126 
127 static int
128 sio_aucat_buildmsg(struct sio_aucat_hdl *hdl)
129 {
130 	if (hdl->curvol != hdl->reqvol) {
131 		hdl->aucat.wstate = WSTATE_MSG;
132 		hdl->aucat.wtodo = sizeof(struct amsg);
133 		hdl->aucat.wmsg.cmd = AMSG_SETVOL;
134 		hdl->aucat.wmsg.u.vol.ctl = hdl->reqvol;
135 		hdl->curvol = hdl->reqvol;
136 		return aucat_wmsg(&hdl->aucat, &hdl->sio.eof);
137 	}
138 	return 0;
139 }
140 
141 struct sio_hdl *
142 sio_aucat_open(const char *str, unsigned mode, int nbio)
143 {
144 	struct sio_aucat_hdl *hdl;
145 
146 	hdl = malloc(sizeof(struct sio_aucat_hdl));
147 	if (hdl == NULL)
148 		return NULL;
149 	if (!aucat_open(&hdl->aucat, str, mode, 1)) {
150 		free(hdl);
151 		return NULL;
152 	}
153 	sio_create(&hdl->sio, &sio_aucat_ops, mode, nbio);
154 	hdl->curvol = SIO_MAXVOL;
155 	hdl->reqvol = SIO_MAXVOL;
156 	hdl->pstate = PSTATE_INIT;
157 	return (struct sio_hdl *)hdl;
158 }
159 
160 static void
161 sio_aucat_close(struct sio_hdl *sh)
162 {
163 	struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh;
164 
165 	if (!hdl->sio.eof && hdl->sio.started)
166 		(void)sio_aucat_stop(&hdl->sio);
167 	aucat_close(&hdl->aucat, hdl->sio.eof);
168 	free(hdl);
169 }
170 
171 static int
172 sio_aucat_start(struct sio_hdl *sh)
173 {
174 	struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh;
175 	struct sio_par par;
176 
177 	/*
178 	 * save bpf
179 	 */
180 	if (!sio_getpar(&hdl->sio, &par))
181 		return 0;
182 	hdl->wbpf = par.bps * par.pchan;
183 	hdl->rbpf = par.bps * par.rchan;
184 	hdl->maxwrite = hdl->wbpf * par.bufsz;
185 	hdl->delta = 0;
186 	DPRINTF("aucat: start, maxwrite = %d\n", hdl->maxwrite);
187 
188 	AMSG_INIT(&hdl->aucat.wmsg);
189 	hdl->aucat.wmsg.cmd = AMSG_START;
190 	hdl->aucat.wtodo = sizeof(struct amsg);
191 	if (!aucat_wmsg(&hdl->aucat, &hdl->sio.eof))
192 		return 0;
193 	hdl->aucat.rstate = RSTATE_MSG;
194 	hdl->aucat.rtodo = sizeof(struct amsg);
195 	if (!aucat_setfl(&hdl->aucat, 1, &hdl->sio.eof))
196 		return 0;
197 	hdl->pstate = PSTATE_RUN;
198 	return 1;
199 }
200 
201 static int
202 sio_aucat_stop(struct sio_hdl *sh)
203 {
204 #define ZERO_MAX 0x400
205 	static unsigned char zero[ZERO_MAX];
206 	struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh;
207 	unsigned n, count;
208 
209 	if (!aucat_setfl(&hdl->aucat, 0, &hdl->sio.eof))
210 		return 0;
211 	/*
212 	 * complete message or data block in progress
213 	 */
214 	if (hdl->aucat.wstate == WSTATE_MSG) {
215 		if (!aucat_wmsg(&hdl->aucat, &hdl->sio.eof))
216 			return 0;
217 	}
218 	if (hdl->aucat.wstate == WSTATE_DATA) {
219 		hdl->maxwrite = hdl->aucat.wtodo;
220 		while (hdl->aucat.wstate != WSTATE_IDLE) {
221 			count = hdl->aucat.wtodo;
222 			if (count > ZERO_MAX)
223 				count = ZERO_MAX;
224 			n = sio_aucat_write(&hdl->sio, zero, count);
225 			if (n == 0)
226 				return 0;
227 		}
228 	}
229 
230 	/*
231 	 * send stop message
232 	 */
233 	AMSG_INIT(&hdl->aucat.wmsg);
234 	hdl->aucat.wmsg.cmd = AMSG_STOP;
235 	hdl->aucat.wtodo = sizeof(struct amsg);
236 	if (!aucat_wmsg(&hdl->aucat, &hdl->sio.eof))
237 		return 0;
238 
239 	/*
240 	 * wait for the STOP ACK
241 	 */
242 	while (hdl->pstate != PSTATE_INIT) {
243 		switch (hdl->aucat.rstate) {
244 		case RSTATE_MSG:
245 			if (!sio_aucat_runmsg(hdl))
246 				return 0;
247 			break;
248 		case RSTATE_DATA:
249 			if (!sio_aucat_read(&hdl->sio, zero, ZERO_MAX))
250 				return 0;
251 			break;
252 		}
253 	}
254 	return 1;
255 }
256 
257 static int
258 sio_aucat_setpar(struct sio_hdl *sh, struct sio_par *par)
259 {
260 	struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh;
261 
262 	AMSG_INIT(&hdl->aucat.wmsg);
263 	hdl->aucat.wmsg.cmd = AMSG_SETPAR;
264 	hdl->aucat.wmsg.u.par.bits = par->bits;
265 	hdl->aucat.wmsg.u.par.bps = par->bps;
266 	hdl->aucat.wmsg.u.par.sig = par->sig;
267 	hdl->aucat.wmsg.u.par.le = par->le;
268 	hdl->aucat.wmsg.u.par.msb = par->msb;
269 	hdl->aucat.wmsg.u.par.rate = par->rate;
270 	hdl->aucat.wmsg.u.par.appbufsz = par->appbufsz;
271 	hdl->aucat.wmsg.u.par.xrun = par->xrun;
272 	if (hdl->sio.mode & SIO_REC)
273 		hdl->aucat.wmsg.u.par.rchan = par->rchan;
274 	if (hdl->sio.mode & SIO_PLAY)
275 		hdl->aucat.wmsg.u.par.pchan = par->pchan;
276 	hdl->aucat.wtodo = sizeof(struct amsg);
277 	if (!aucat_wmsg(&hdl->aucat, &hdl->sio.eof))
278 		return 0;
279 	return 1;
280 }
281 
282 static int
283 sio_aucat_getpar(struct sio_hdl *sh, struct sio_par *par)
284 {
285 	struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh;
286 
287 	AMSG_INIT(&hdl->aucat.wmsg);
288 	hdl->aucat.wmsg.cmd = AMSG_GETPAR;
289 	hdl->aucat.wtodo = sizeof(struct amsg);
290 	if (!aucat_wmsg(&hdl->aucat, &hdl->sio.eof))
291 		return 0;
292 	hdl->aucat.rtodo = sizeof(struct amsg);
293 	if (!aucat_rmsg(&hdl->aucat, &hdl->sio.eof))
294 		return 0;
295 	if (hdl->aucat.rmsg.cmd != AMSG_GETPAR) {
296 		DPRINTF("sio_aucat_getpar: protocol err\n");
297 		hdl->sio.eof = 1;
298 		return 0;
299 	}
300 	par->bits = hdl->aucat.rmsg.u.par.bits;
301 	par->bps = hdl->aucat.rmsg.u.par.bps;
302 	par->sig = hdl->aucat.rmsg.u.par.sig;
303 	par->le = hdl->aucat.rmsg.u.par.le;
304 	par->msb = hdl->aucat.rmsg.u.par.msb;
305 	par->rate = hdl->aucat.rmsg.u.par.rate;
306 	par->bufsz = hdl->aucat.rmsg.u.par.bufsz;
307 	par->appbufsz = hdl->aucat.rmsg.u.par.appbufsz;
308 	par->xrun = hdl->aucat.rmsg.u.par.xrun;
309 	par->round = hdl->aucat.rmsg.u.par.round;
310 	if (hdl->sio.mode & SIO_PLAY)
311 		par->pchan = hdl->aucat.rmsg.u.par.pchan;
312 	if (hdl->sio.mode & SIO_REC)
313 		par->rchan = hdl->aucat.rmsg.u.par.rchan;
314 	return 1;
315 }
316 
317 static int
318 sio_aucat_getcap(struct sio_hdl *sh, struct sio_cap *cap)
319 {
320 	unsigned i, bps, le, sig, chan, rindex, rmult;
321 	static unsigned rates[] = { 8000, 11025, 12000 };
322 
323 	bps = 1;
324 	sig = le = 0;
325 	cap->confs[0].enc = 0;
326 	for (i = 0; i < SIO_NENC; i++) {
327 		if (bps > 4)
328 			break;
329 		cap->confs[0].enc |= 1 << i;
330 		cap->enc[i].bits = bps == 4 ? 24 : bps * 8;
331 		cap->enc[i].bps = bps;
332 		cap->enc[i].sig = sig ^ 1;
333 		cap->enc[i].le = bps > 1 ? le : SIO_LE_NATIVE;
334 		cap->enc[i].msb = 1;
335 		le++;
336 		if (le > 1 || bps == 1) {
337 			le = 0;
338 			sig++;
339 		}
340 		if (sig > 1 || (le == 0 && bps > 1)) {
341 			sig = 0;
342 			bps++;
343 		}
344 	}
345 	chan = 1;
346 	cap->confs[0].rchan = 0;
347 	for (i = 0; i < SIO_NCHAN; i++) {
348 		if (chan > 16)
349 			break;
350 		cap->confs[0].rchan |= 1 << i;
351 		cap->rchan[i] = chan;
352 		if (chan >= 12) {
353 			chan += 4;
354 		} else if (chan >= 2) {
355 			chan += 2;
356 		} else
357 			chan++;
358 	}
359 	chan = 1;
360 	cap->confs[0].pchan = 0;
361 	for (i = 0; i < SIO_NCHAN; i++) {
362 		if (chan > 16)
363 			break;
364 		cap->confs[0].pchan |= 1 << i;
365 		cap->pchan[i] = chan;
366 		if (chan >= 12) {
367 			chan += 4;
368 		} else if (chan >= 2) {
369 			chan += 2;
370 		} else
371 			chan++;
372 	}
373 	rindex = 0;
374 	rmult = 1;
375 	cap->confs[0].rate = 0;
376 	for (i = 0; i < SIO_NRATE; i++) {
377 		if (rmult >= 32)
378 			break;
379 		cap->rate[i] = rates[rindex] * rmult;
380 		cap->confs[0].rate |= 1 << i;
381 		rindex++;
382 		if (rindex == sizeof(rates) / sizeof(unsigned)) {
383 			rindex = 0;
384 			rmult *= 2;
385 		}
386 	}
387 	cap->nconf = 1;
388 	return 1;
389 }
390 
391 static size_t
392 sio_aucat_read(struct sio_hdl *sh, void *buf, size_t len)
393 {
394 	struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh;
395 
396 	while (hdl->aucat.rstate == RSTATE_MSG) {
397 		if (!sio_aucat_runmsg(hdl))
398 			return 0;
399 	}
400 	return aucat_rdata(&hdl->aucat, buf, len, &hdl->sio.eof);
401 }
402 
403 static size_t
404 sio_aucat_write(struct sio_hdl *sh, const void *buf, size_t len)
405 {
406 	struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh;
407 	size_t n;
408 
409 	while (hdl->aucat.wstate == WSTATE_IDLE) {
410 		if (!sio_aucat_buildmsg(hdl))
411 			break;
412 	}
413 	if (len <= 0 || hdl->maxwrite <= 0)
414 		return 0;
415 	if (len > hdl->maxwrite)
416 		len = hdl->maxwrite;
417 	n = aucat_wdata(&hdl->aucat, buf, len, hdl->wbpf, &hdl->sio.eof);
418 	hdl->maxwrite -= n;
419 	return n;
420 }
421 
422 static int
423 sio_aucat_nfds(struct sio_hdl *hdl)
424 {
425 	return 1;
426  }
427 
428 static int
429 sio_aucat_pollfd(struct sio_hdl *sh, struct pollfd *pfd, int events)
430 {
431 	struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh;
432 
433 	hdl->events = events;
434 	if (hdl->maxwrite <= 0)
435 		events &= ~POLLOUT;
436 	return aucat_pollfd(&hdl->aucat, pfd, events);
437 }
438 
439 static int
440 sio_aucat_revents(struct sio_hdl *sh, struct pollfd *pfd)
441 {
442 	struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh;
443 	int revents = pfd->revents;
444 
445 	if (revents & POLLIN) {
446 		while (hdl->aucat.rstate == RSTATE_MSG) {
447 			if (!sio_aucat_runmsg(hdl))
448 				break;
449 		}
450 		if (hdl->aucat.rstate != RSTATE_DATA)
451 			revents &= ~POLLIN;
452 	}
453 	if (revents & POLLOUT) {
454 		if (hdl->maxwrite <= 0)
455 			revents &= ~POLLOUT;
456 	}
457 	if (hdl->sio.eof)
458 		return POLLHUP;
459 	DPRINTF("sio_aucat_revents: %x\n", revents & hdl->events);
460 	return revents & (hdl->events | POLLHUP);
461 }
462 
463 static int
464 sio_aucat_setvol(struct sio_hdl *sh, unsigned vol)
465 {
466 	struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh;
467 
468 	hdl->reqvol = vol;
469 	return 1;
470 }
471 
472 static void
473 sio_aucat_getvol(struct sio_hdl *sh)
474 {
475 	struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh;
476 
477 	sio_onvol_cb(&hdl->sio, hdl->reqvol);
478 	return;
479 }
480