1 #include <errno.h>
2 #include <fcntl.h>
3 #include <poll.h>
4 #include <stdio.h>
5 #include <string.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <sndio.h>
9 #include "tools.h"
10 
11 void cb(void *, int);
12 void usage(void);
13 
14 unsigned char *buf;
15 struct sio_par par;
16 char *xstr[] = SIO_XSTRINGS;
17 
18 unsigned long long recpos = 0, readpos = 0;
19 int tick = 0;
20 
21 void
cb(void * addr,int delta)22 cb(void *addr, int delta)
23 {
24 	unsigned int bytes;
25 
26 	bytes = delta * par.bps * par.rchan;
27 	// fprintf(stderr, "advanced by %d\n", bytes);
28 	recpos += bytes;
29 	tick = 1;
30 }
31 
32 void
usage(void)33 usage(void)
34 {
35 	fprintf(stderr,
36 	    "usage: rec [-b size] [-c nchan] [-e enc] [-n nbytes] "
37 	    "[-r rate] [-x xrun]\n");
38 }
39 
40 int
main(int argc,char ** argv)41 main(int argc, char **argv)
42 {
43 	int ch;
44 	struct sio_hdl *hdl;
45 	size_t bufsz;
46 	ssize_t n, nbytes;
47 
48 	/*
49 	 * defaults parameters
50 	 */
51 	sio_initpar(&par);
52 	par.sig = 1;
53 	par.bits = 16;
54 	par.rchan = 2;
55 	par.rate = 48000;
56 	nbytes = -1;
57 
58 	while ((ch = getopt(argc, argv, "b:c:e:n:r:x:")) != -1) {
59 		switch (ch) {
60 		case 'b':
61 			if (sscanf(optarg, "%u", &par.appbufsz) != 1) {
62 				fprintf(stderr, "%s: bad buf size\n", optarg);
63 				exit(1);
64 			}
65 			break;
66 		case 'c':
67 			if (sscanf(optarg, "%u", &par.rchan) != 1) {
68 				fprintf(stderr, "%s: bad channels number\n", optarg);
69 				exit(1);
70 			}
71 			break;
72 		case 'e':
73 			if (!strtoenc(&par, optarg)) {
74 				fprintf(stderr, "%s: unknown encoding\n", optarg);
75 				exit(1);
76 			}
77 			break;
78 		case 'n':
79 			if (sscanf(optarg, "%zu", &nbytes) != 1) {
80 				fprintf(stderr, "%s: bad bytes count\n", optarg);
81 				exit(1);
82 			}
83 			break;
84 		case 'r':
85 			if (sscanf(optarg, "%u", &par.rate) != 1) {
86 				fprintf(stderr, "%s: bad rate\n", optarg);
87 				exit(1);
88 			}
89 			break;
90 		case 'x':
91 			for (par.xrun = 0;; par.xrun++) {
92 				if (par.xrun == sizeof(xstr) / sizeof(char *)) {
93 					fprintf(stderr,
94 					    "%s: bad xrun mode\n", optarg);
95 					exit(1);
96 				}
97 				if (strcmp(xstr[par.xrun], optarg) == 0)
98 					break;
99 			}
100 			break;
101 		default:
102 			usage();
103 			exit(1);
104 			break;
105 		}
106 	}
107 
108 	hdl = sio_open(SIO_DEVANY, SIO_REC, 0);
109 	if (hdl == NULL) {
110 		fprintf(stderr, "sio_open() failed\n");
111 		exit(1);
112 	}
113 	sio_onmove(hdl, cb, NULL);
114 	if (!sio_setpar(hdl, &par)) {
115 		fprintf(stderr, "sio_setpar() failed\n");
116 		exit(1);
117 	}
118 	if (!sio_getpar(hdl, &par)) {
119 		fprintf(stderr, "sio_getpar() failed\n");
120 		exit(1);
121 	}
122 	bufsz = par.bps * par.rchan * par.round;
123 	buf = malloc(bufsz);
124 	if (buf == NULL) {
125 		fprintf(stderr, "failed to allocate %zu bytes\n", bufsz);
126 		exit(1);
127 	}
128 	fprintf(stderr, "%zu bytes buffer, max latency %u frames\n",
129 	    bufsz, par.bufsz);
130 	if (!sio_start(hdl)) {
131 		fprintf(stderr, "sio_start() failed\n");
132 		exit(1);
133 	}
134 	while (nbytes != 0) {
135 		n = bufsz;
136 		if (nbytes >= 0 && n > nbytes)
137 			n = nbytes;
138 		n = sio_read(hdl, buf, n);
139 		if (n == 0) {
140 			fprintf(stderr, "sio_write: failed\n");
141 			exit(1);
142 		}
143 		nbytes -= n;
144 		readpos += n;
145 		if (tick) {
146 			fprintf(stderr,
147 			    "recpos = %lld, readpos = %lld, latency = %lld\n",
148 			    recpos, readpos, recpos - readpos);
149 			tick = 0;
150 		}
151 		if (write(STDOUT_FILENO, buf, n) < 0) {
152 			perror("stdout");
153 			exit(1);
154 		}
155 	}
156 	sio_close(hdl);
157 	return 0;
158 }
159