ctl.c revision 1.9 1 /* $NetBSD: ctl.c,v 1.9 1997/10/07 13:55:03 augustss Exp $ */
2
3 /*
4 * Copyright (c) 1997 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * Author: Lennart Augustsson
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the NetBSD
20 * Foundation, Inc. and its contributors.
21 * 4. Neither the name of The NetBSD Foundation nor the names of its
22 * contributors may be used to endorse or promote products derived
23 * from this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
26 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
29 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 */
37
38 #include <stdio.h>
39 #include <fcntl.h>
40 #include <err.h>
41 #include <unistd.h>
42 #include <string.h>
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <sys/ioctl.h>
46 #include <sys/audioio.h>
47
48 struct field *findfield __P((char *name));
49 void prfield __P((struct field *p, char *sep));
50 void rdfield __P((struct field *p, char *q));
51 void getinfo __P((int fd));
52 void usage __P((void));
53 int main __P((int argc, char **argv));
54
55 FILE *out = stdout;
56
57 char *prog;
58
59 audio_device_t adev;
60
61 audio_info_t info;
62
63 char encbuf[1000];
64
65 int properties, fullduplex, rerror;
66
67 struct field {
68 char *name;
69 void *valp;
70 int format;
71 #define STRING 1
72 #define INT 2
73 #define UINT 3
74 #define P_R 4
75 #define ULONG 5
76 #define UCHAR 6
77 #define ENC 7
78 #define PROPS 8
79 char flags;
80 #define READONLY 1
81 #define ALIAS 2
82 #define SET 4
83 } fields[] = {
84 { "name", &adev.name, STRING, READONLY },
85 { "version", &adev.version, STRING, READONLY },
86 { "config", &adev.config, STRING, READONLY },
87 { "encodings", encbuf, STRING, READONLY },
88 { "properties", &properties, PROPS, READONLY },
89 { "full_duplex", &fullduplex, INT, 0 },
90 { "buffersize", &info.buffersize, UINT, 0 },
91 { "blocksize", &info.blocksize, UINT, 0 },
92 { "hiwat", &info.hiwat, UINT, 0 },
93 { "lowat", &info.lowat, UINT, 0 },
94 { "backlog", &info.backlog, UINT, 0 },
95 { "mode", &info.mode, P_R, READONLY },
96 { "play.rate", &info.play.sample_rate, UINT, 0 },
97 { "play.sample_rate", &info.play.sample_rate, UINT, ALIAS },
98 { "play.channels", &info.play.channels, UINT, 0 },
99 { "play.precision", &info.play.precision, UINT, 0 },
100 { "play.encoding", &info.play.encoding, ENC, 0 },
101 { "play.gain", &info.play.gain, UINT, 0 },
102 { "play.port", &info.play.port, UINT, 0 },
103 { "play.seek", &info.play.seek, ULONG, READONLY },
104 { "play.samples", &info.play.samples, UINT, READONLY },
105 { "play.eof", &info.play.eof, UINT, READONLY },
106 { "play.pause", &info.play.pause, UCHAR, 0 },
107 { "play.error", &info.play.error, UCHAR, READONLY },
108 { "play.waiting", &info.play.waiting, UCHAR, READONLY },
109 { "play.open", &info.play.open, UCHAR, READONLY },
110 { "play.active", &info.play.active, UCHAR, READONLY },
111 { "record.rate", &info.record.sample_rate,UINT, 0 },
112 { "record.sample_rate", &info.record.sample_rate,UINT, ALIAS },
113 { "record.channels", &info.record.channels, UINT, 0 },
114 { "record.precision", &info.record.precision, UINT, 0 },
115 { "record.encoding", &info.record.encoding, ENC, 0 },
116 { "record.gain", &info.record.gain, UINT, 0 },
117 { "record.port", &info.record.port, UINT, 0 },
118 { "record.seek", &info.record.seek, ULONG, READONLY },
119 { "record.samples", &info.record.samples, UINT, READONLY },
120 { "record.eof", &info.record.eof, UINT, READONLY },
121 { "record.pause", &info.record.pause, UCHAR, 0 },
122 { "record.error", &info.record.error, UCHAR, READONLY },
123 { "record.waiting", &info.record.waiting, UCHAR, READONLY },
124 { "record.open", &info.record.open, UCHAR, READONLY },
125 { "record.active", &info.record.active, UCHAR, READONLY },
126 { "record.errors", &rerror, INT, READONLY },
127 { 0 }
128 };
129
130 struct {
131 char *ename;
132 int eno;
133 } encs[] = {
134 { "ulaw", AUDIO_ENCODING_ULAW },
135 { "mulaw", AUDIO_ENCODING_ULAW },
136 { "alaw", AUDIO_ENCODING_ALAW },
137 { "slinear", AUDIO_ENCODING_SLINEAR },
138 { "linear", AUDIO_ENCODING_SLINEAR },
139 { "ulinear", AUDIO_ENCODING_ULINEAR },
140 { "adpcm", AUDIO_ENCODING_ADPCM },
141 { "ADPCM", AUDIO_ENCODING_ADPCM },
142 { "slinear_le", AUDIO_ENCODING_SLINEAR_LE },
143 { "linear_le", AUDIO_ENCODING_SLINEAR_LE },
144 { "ulinear_le", AUDIO_ENCODING_ULINEAR_LE },
145 { "slinear_be", AUDIO_ENCODING_SLINEAR_BE },
146 { "linear_be", AUDIO_ENCODING_SLINEAR_BE },
147 { "ulinear_be", AUDIO_ENCODING_ULINEAR_BE },
148 { 0 }
149 };
150
151 struct field *
152 findfield(name)
153 char *name;
154 {
155 int i;
156 for(i = 0; fields[i].name; i++)
157 if (strcmp(fields[i].name, name) == 0)
158 return &fields[i];
159 return 0;
160 }
161
162 void
163 prfield(p, sep)
164 struct field *p;
165 char *sep;
166 {
167 u_int v;
168 char *cm;
169 int i;
170
171 if (sep)
172 fprintf(out, "%s%s", p->name, sep);
173 switch(p->format) {
174 case STRING:
175 fprintf(out, "%s", (char*)p->valp);
176 break;
177 case INT:
178 fprintf(out, "%d", *(int*)p->valp);
179 break;
180 case UINT:
181 fprintf(out, "%u", *(u_int*)p->valp);
182 break;
183 case UCHAR:
184 fprintf(out, "%u", *(u_char*)p->valp);
185 break;
186 case ULONG:
187 fprintf(out, "%lu", *(u_long*)p->valp);
188 break;
189 case P_R:
190 v = *(u_int*)p->valp;
191 cm = "";
192 if (v & AUMODE_PLAY) {
193 if (v & AUMODE_PLAY_ALL)
194 fprintf(out, "play");
195 else
196 fprintf(out, "playsync");
197 cm = ",";
198 }
199 if (v & AUMODE_RECORD)
200 fprintf(out, "%srecord", cm);
201 break;
202 case ENC:
203 v = *(u_int*)p->valp;
204 for(i = 0; encs[i].ename; i++)
205 if (encs[i].eno == v)
206 break;
207 if (encs[i].ename)
208 fprintf(out, "%s", encs[i].ename);
209 else
210 fprintf(out, "%u", v);
211 break;
212 case PROPS:
213 v = *(u_int*)p->valp;
214 cm = "";
215 if (v & AUDIO_PROP_FULLDUPLEX) {
216 fprintf(out, "%sfull_duplex", cm);
217 cm = ",";
218 }
219 if (v & AUDIO_PROP_MMAP) {
220 fprintf(out, "%smmap", cm);
221 cm = ",";
222 }
223 break;
224 default:
225 errx(1, "Invalid format.");
226 }
227 }
228
229 void
230 rdfield(p, q)
231 struct field *p;
232 char *q;
233 {
234 int i;
235
236 switch(p->format) {
237 case UINT:
238 if (sscanf(q, "%u", (unsigned int *)p->valp) != 1)
239 warnx("Bad number %s", q);
240 break;
241 case ENC:
242 for(i = 0; encs[i].ename; i++)
243 if (strcmp(encs[i].ename, q) == 0)
244 break;
245 if (encs[i].ename)
246 *(u_int*)p->valp = encs[i].eno;
247 else
248 warnx("Unknown encoding: %s", q);
249 break;
250 default:
251 errx(1, "Invalid format.");
252 }
253 p->flags |= SET;
254 }
255
256 void
257 getinfo(fd)
258 int fd;
259 {
260 int pos, i;
261
262 if (ioctl(fd, AUDIO_GETDEV, &adev) < 0)
263 err(1, "AUDIO_GETDEV");
264 for(pos = 0, i = 0; ; i++) {
265 audio_encoding_t enc;
266 enc.index = i;
267 if (ioctl(fd, AUDIO_GETENC, &enc) < 0)
268 break;
269 if (pos)
270 encbuf[pos++] = ',';
271 sprintf(encbuf+pos, "%s:%d%s", enc.name,
272 enc.precision,
273 enc.flags & AUDIO_ENCODINGFLAG_EMULATED ? "*" : "");
274 pos += strlen(encbuf+pos);
275 }
276 if (ioctl(fd, AUDIO_GETFD, &fullduplex) < 0)
277 err(1, "AUDIO_GETFD");
278 if (ioctl(fd, AUDIO_GETPROPS, &properties) < 0)
279 err(1, "AUDIO_GETPROPS");
280 if (ioctl(fd, AUDIO_RERROR, &rerror) < 0)
281 err(1, "AUDIO_RERROR");
282 if (ioctl(fd, AUDIO_GETINFO, &info) < 0)
283 err(1, "AUDIO_GETINFO");
284 }
285
286 void
287 usage()
288 {
289 fprintf(out, "%s [-f file] [-n] name ...\n", prog);
290 fprintf(out, "%s [-f file] [-n] -w name=value ...\n", prog);
291 fprintf(out, "%s [-f file] [-n] -a\n", prog);
292 exit(1);
293 }
294
295 int
296 main(argc, argv)
297 int argc;
298 char **argv;
299 {
300 int fd, i, ch;
301 int aflag = 0, wflag = 0;
302 struct stat dstat, ostat;
303 char *file = "/dev/audioctl";
304 char *sep = "=";
305
306 prog = *argv;
307
308 while ((ch = getopt(argc, argv, "af:nw")) != -1) {
309 switch(ch) {
310 case 'a':
311 aflag++;
312 break;
313 case 'w':
314 wflag++;
315 break;
316 case 'n':
317 sep = 0;
318 break;
319 case 'f':
320 file = optarg;
321 break;
322 case '?':
323 default:
324 usage();
325 }
326 }
327 argc -= optind;
328 argv += optind;
329
330 fd = open(file, O_WRONLY);
331 if (fd < 0)
332 fd = open(file, O_RDONLY);
333 if (fd < 0)
334 err(1, "%s", file);
335
336 /* Check if stdout is the same device as the audio device. */
337 if (fstat(fd, &dstat) < 0)
338 err(1, "fstat au");
339 if (fstat(STDOUT_FILENO, &ostat) < 0)
340 err(1, "fstat stdout");
341 if (S_ISCHR(dstat.st_mode) && S_ISCHR(ostat.st_mode) &&
342 major(dstat.st_dev) == major(ostat.st_dev) &&
343 minor(dstat.st_dev) == minor(ostat.st_dev))
344 /* We can't write to stdout so use stderr */
345 out = stderr;
346
347 if (!wflag)
348 getinfo(fd);
349
350 if (argc == 0 && aflag && !wflag) {
351 for(i = 0; fields[i].name; i++) {
352 if (!(fields[i].flags & ALIAS)) {
353 prfield(&fields[i], sep);
354 fprintf(out, "\n");
355 }
356 }
357 } else if (argc > 0 && !aflag) {
358 struct field *p;
359 if (wflag) {
360 AUDIO_INITINFO(&info);
361 while(argc--) {
362 char *q;
363
364 q = strchr(*argv, '=');
365 if (q) {
366 *q++ = 0;
367 p = findfield(*argv);
368 if (p == 0)
369 warnx("field `%s' does not exist", *argv);
370 else {
371 if (p->flags & READONLY)
372 warnx("`%s' is read only", *argv);
373 else {
374 rdfield(p, q);
375 if (p->valp == &fullduplex)
376 if (ioctl(fd, AUDIO_SETFD, &fullduplex) < 0)
377 err(1, "set failed");
378 }
379 }
380 } else
381 warnx("No `=' in %s", *argv);
382 argv++;
383 }
384 if (ioctl(fd, AUDIO_SETINFO, &info) < 0)
385 err(1, "set failed");
386 if (sep) {
387 getinfo(fd);
388 for(i = 0; fields[i].name; i++) {
389 if (fields[i].flags & SET) {
390 fprintf(out, "%s: -> ", fields[i].name);
391 prfield(&fields[i], 0);
392 fprintf(out, "\n");
393 }
394 }
395 }
396 } else {
397 while(argc--) {
398 p = findfield(*argv);
399 if (p == 0) {
400 if (strchr(*argv, '='))
401 warnx("field %s does not exist (use -w to set a variable)", *argv);
402 else
403 warnx("field %s does not exist", *argv);
404 } else {
405 prfield(p, sep);
406 fprintf(out, "\n");
407 }
408 argv++;
409 }
410 }
411 } else
412 usage();
413 exit(0);
414 }
415