GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/audioctl/audioctl.c Lines: 0 137 0.0 %
Date: 2016-12-06 Branches: 0 133 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: audioctl.c,v 1.33 2016/06/21 22:35:39 jmc Exp $	*/
2
/*
3
 * Copyright (c) 2016 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 <sys/types.h>
18
#include <sys/ioctl.h>
19
#include <sys/audioio.h>
20
#include <fcntl.h>
21
#include <limits.h>
22
#include <stdio.h>
23
#include <stdlib.h>
24
#include <unistd.h>
25
#include <string.h>
26
#include <err.h>
27
28
/*
29
 * Default bytes per sample for the given bits per sample.
30
 */
31
#define BPS(bits) (((bits) <= 8) ? 1 : (((bits) <= 16) ? 2 : 4))
32
33
struct audio_device rname;
34
struct audio_status rstatus;
35
struct audio_swpar rpar, wpar;
36
struct audio_pos rpos;
37
38
struct field {
39
	char *name;
40
	void *raddr, *waddr;
41
#define MODE	0
42
#define NUM	1
43
#define STR	2
44
#define ENC	3
45
	int type;
46
	int set;
47
} fields[] = {
48
	{"name",		&rname.name,		NULL,		STR},
49
	{"mode",		&rstatus.mode,		NULL,		MODE},
50
	{"pause",		&rstatus.pause,		NULL,		NUM},
51
	{"active",		&rstatus.active,	NULL,		NUM},
52
	{"nblks",		&rpar.nblks,		&wpar.nblks,	NUM},
53
	{"blksz",		&rpar.round,		&wpar.round,	NUM},
54
	{"rate",		&rpar.rate,		&wpar.rate,	NUM},
55
	{"encoding",		&rpar,			&wpar,		ENC},
56
	{"play.channels",	&rpar.pchan,		&wpar.pchan,	NUM},
57
	{"play.bytes",		&rpos.play_pos,		NULL,		NUM},
58
	{"play.errors",		&rpos.play_xrun,	NULL,		NUM},
59
	{"record.channels",	&rpar.rchan,		&wpar.rchan, 	NUM},
60
	{"record.bytes",	&rpos.rec_pos,		NULL,		NUM},
61
	{"record.errors",	&rpos.rec_xrun,		NULL,		NUM},
62
	{NULL,			NULL,			0}
63
};
64
65
const char usagestr[] =
66
	"usage: audioctl [-f file]\n"
67
	"       audioctl [-n] [-f file] name ...\n"
68
	"       audioctl [-nq] [-f file] name=value ...\n";
69
70
/*
71
 * parse encoding string (examples: s8, u8, s16, s16le, s24be ...)
72
 * and fill enconding fields of audio_swpar structure
73
 */
74
int
75
strtoenc(struct audio_swpar *ap, char *p)
76
{
77
	/* expect "s" or "u" (signedness) */
78
	if (*p == 's')
79
		ap->sig = 1;
80
	else if (*p == 'u')
81
		ap->sig = 0;
82
	else
83
		return 0;
84
	p++;
85
86
	/* expect 1-2 decimal digits (bits per sample) */
87
	ap->bits = 0;
88
	while (*p >= '0' && *p <= '9') {
89
		ap->bits = (ap->bits * 10) + *p++ - '0';
90
		if (ap->bits > 32)
91
			return 0;
92
	}
93
	if (ap->bits < 8)
94
		return 0;
95
96
	/* set defaults as next tokens are optional */
97
	ap->bps = BPS(ap->bits);
98
	ap->le = (BYTE_ORDER == LITTLE_ENDIAN);
99
	ap->msb = 1;
100
	if (*p == '\0')
101
		return 1;
102
103
	/* expect "le" or "be" (endianness) */
104
	if (p[0] == 'l' && p[1] == 'e')
105
		ap->le = 1;
106
	else if (p[0] == 'b' && p[1] == 'e')
107
		ap->le = 0;
108
	else
109
		return 0;
110
	p += 2;
111
	if (*p == '\0')
112
		return 1;
113
114
	/* expect 1 decimal digit (number of bytes) */
115
	if (*p < '0' || *p > '9')
116
		return 0;
117
	ap->bps = *p - '0';
118
	if (ap->bps < ((ap->bits + 7) >> 3) || ap->bps > 4)
119
		return 0;
120
	if (*++p == '\0')
121
		return 1;
122
123
	/* expect "msb" or "lsb" (alignment) */
124
	if (p[0] == 'm' && p[1] == 's' && p[2] == 'b')
125
		ap->msb = 1;
126
	else if (p[0] == 'l' && p[1] == 's' && p[2] == 'b')
127
		ap->msb = 0;
128
	else if (*p == '\0')
129
		return 1;
130
	p += 3;
131
	if (*p == '\0')
132
		return 1;
133
134
	/* must be no additional junk */
135
	return 0;
136
}
137
138
void
139
print_val(struct field *p, void *addr)
140
{
141
	int mode;
142
	struct audio_swpar *ap;
143
144
	switch (p->type) {
145
	case NUM:
146
		printf("%u", *(unsigned int *)addr);
147
		break;
148
	case STR:
149
		printf("%s", (char *)addr);
150
		break;
151
	case MODE:
152
		mode = *(unsigned int *)addr;
153
		if (mode & AUMODE_PLAY)
154
			printf("play");
155
		if (mode & AUMODE_RECORD) {
156
			if (mode & AUMODE_PLAY)
157
				printf(",");
158
			printf("record");
159
		}
160
		break;
161
	case ENC:
162
		ap = addr;
163
		printf("%s%u", ap->sig ? "s" : "u", ap->bits);
164
		if (ap->bps == 1)
165
			break;
166
		printf("%s", ap->le ? "le" : "be");
167
		if (ap->bps != BPS(ap->bits) || ap->bits < ap->bps * 8) {
168
			printf("%u", ap->bps);
169
			if (ap->bits < ap->bps * 8)
170
				printf("%s", ap->msb ? "msb" : "lsb");
171
		}
172
	}
173
}
174
175
void
176
parse_val(struct field *f, void *addr, char *p)
177
{
178
	const char *strerr;
179
180
	switch (f->type) {
181
	case NUM:
182
		*(unsigned int *)addr = strtonum(p, 0, UINT_MAX, &strerr);
183
		if (strerr)
184
			errx(1, "%s: %s", p, strerr);
185
		break;
186
	case ENC:
187
		if (!strtoenc((struct audio_swpar *)addr, p))
188
			errx(1, "%s: bad encoding", p);
189
	}
190
}
191
192
int
193
main(int argc, char **argv)
194
{
195
	struct field *f;
196
	char *lhs, *rhs, *path = "/dev/audioctl0";
197
	int fd, c, set = 0, print_names = 1, quiet = 0;
198
199
	while ((c = getopt(argc, argv, "anf:q")) != -1) {
200
		switch (c) {
201
		case 'a':	/* ignored, compat */
202
			break;
203
		case 'n':
204
			print_names = 0;
205
			break;
206
		case 'f':
207
			path = optarg;
208
			break;
209
		case 'q':
210
			quiet = 1;
211
			break;
212
		default:
213
			fputs(usagestr, stderr);
214
			return 1;
215
		}
216
	}
217
	argc -= optind;
218
	argv += optind;
219
220
	fd = open(path, O_RDWR);
221
	if (fd < 0)
222
		err(1, "%s", path);
223
	if (ioctl(fd, AUDIO_GETSTATUS, &rstatus) < 0)
224
		err(1, "AUDIO_GETSTATUS");
225
	if (ioctl(fd, AUDIO_GETDEV, &rname) < 0)
226
		err(1, "AUDIO_GETDEV");
227
	if (ioctl(fd, AUDIO_GETPAR, &rpar) < 0)
228
		err(1, "AUDIO_GETPAR");
229
	if (ioctl(fd, AUDIO_GETPOS, &rpos) < 0)
230
		err(1, "AUDIO_GETPOS");
231
	if (argc == 0) {
232
		for (f = fields; f->name != NULL; f++) {
233
			printf("%s=", f->name);
234
			print_val(f, f->raddr);
235
			printf("\n");
236
		}
237
	}
238
	AUDIO_INITPAR(&wpar);
239
	for (; argc > 0; argc--, argv++) {
240
		lhs = *argv;
241
		rhs = strchr(*argv, '=');
242
		if (rhs)
243
			*rhs++ = '\0';
244
		for (f = fields;; f++) {
245
			if (f->name == NULL)
246
				errx(1, "%s: unknown parameter", lhs);
247
			if (strcmp(f->name, lhs) == 0)
248
				break;
249
		}
250
		if (rhs) {
251
			if (f->waddr == NULL)
252
				errx(1, "%s: is read only", f->name);
253
			parse_val(f, f->waddr, rhs);
254
			f->set = 1;
255
			set = 1;
256
		} else {
257
			if (print_names)
258
				printf("%s=", f->name);
259
			print_val(f, f->raddr);
260
			printf("\n");
261
		}
262
	}
263
	if (!set)
264
		return 0;
265
	if (ioctl(fd, AUDIO_SETPAR, &wpar) < 0)
266
		err(1, "AUDIO_SETPAR");
267
	if (ioctl(fd, AUDIO_GETPAR, &wpar) < 0)
268
		err(1, "AUDIO_GETPAR");
269
	for (f = fields; f->name != NULL; f++) {
270
		if (!f->set || quiet)
271
			continue;
272
		if (print_names) {
273
			printf("%s: ", f->name);
274
			print_val(f, f->raddr);
275
			printf(" -> ");
276
		}
277
		print_val(f, f->waddr);
278
		printf("\n");
279
	}
280
	return 0;
281
}