GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libsndio/sio_aucat.c Lines: 0 242 0.0 %
Date: 2017-11-07 Branches: 0 145 0.0 %

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