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