1 #include <sys/time.h> 2 #include <errno.h> 3 #include <fcntl.h> 4 #include <poll.h> 5 #include <stdio.h> 6 #include <string.h> 7 #include <stdlib.h> 8 #include <unistd.h> 9 #include <sndio.h> 10 #include "tools.h" 11 12 struct buf { /* simple circular fifo */ 13 unsigned start; /* first used byte */ 14 unsigned used; /* number of used bytes */ 15 #define BUF_LEN (240 * 0x1000) /* i/o buffer size */ 16 unsigned char data[BUF_LEN]; 17 }; 18 19 void cb(void *, int); 20 void buf_read(struct buf *, int); 21 void buf_write(struct buf *, int); 22 unsigned buf_rec(struct buf *, struct sio_hdl *); 23 unsigned buf_play(struct buf *, struct sio_hdl *); 24 void usage(void); 25 26 char *xstr[] = SIO_XSTRINGS; 27 struct sio_par par; 28 struct buf playbuf, recbuf; 29 30 long long pos = 0; 31 int plat = 0, rlat = 0; 32 33 void 34 cb(void *addr, int delta) 35 { 36 pos += delta; 37 fprintf(stderr, "cb: delta = %+7d, pos = %+7lld, " 38 "plat = %+7d, rlat = %+7d\n", 39 delta, pos, plat, rlat); 40 plat -= delta; 41 rlat += delta; 42 } 43 44 /* 45 * read buffer contents from a file without blocking 46 */ 47 void 48 buf_read(struct buf *buf, int fd) 49 { 50 unsigned count, end, avail; 51 int n; 52 53 for (;;) { 54 avail = BUF_LEN - buf->used; 55 if (avail == 0) 56 break; 57 end = buf->start + buf->used; 58 if (end >= BUF_LEN) 59 end -= BUF_LEN; 60 count = BUF_LEN - end; 61 if (count > avail) 62 count = avail; 63 n = read(fd, buf->data + end, count); 64 if (n < 0) { 65 perror("buf_read: read"); 66 exit(1); 67 } 68 if (n == 0) { 69 bzero(buf->data + end, count); 70 n = count; 71 } 72 buf->used += n; 73 } 74 } 75 76 /* 77 * write buffer contents to file, without blocking 78 */ 79 void 80 buf_write(struct buf *buf, int fd) 81 { 82 unsigned count; 83 int n; 84 85 while (buf->used) { 86 count = BUF_LEN - buf->start; 87 if (count > buf->used) 88 count = buf->used; 89 n = write(fd, buf->data + buf->start, count); 90 if (n < 0) { 91 perror("buf_write: write"); 92 exit(1); 93 } 94 buf->used -= n; 95 buf->start += n; 96 if (buf->start >= BUF_LEN) 97 buf->start -= BUF_LEN; 98 } 99 } 100 101 /* 102 * read buffer contents from a file without blocking 103 */ 104 unsigned 105 buf_rec(struct buf *buf, struct sio_hdl *hdl) 106 { 107 unsigned count, end, avail, done = 0; 108 int bpf = par.rchan * par.bps; 109 int n; 110 111 for (;;) { 112 avail = BUF_LEN - buf->used; 113 if (avail == 0) 114 break; 115 end = buf->start + buf->used; 116 if (end >= BUF_LEN) 117 end -= BUF_LEN; 118 count = BUF_LEN - end; 119 if (count > avail) 120 count = avail; 121 n = sio_read(hdl, buf->data + end, count); 122 if (n == 0) { 123 if (sio_eof(hdl)) { 124 fprintf(stderr, "sio_read() failed\n"); 125 exit(1); 126 } 127 break; 128 } 129 if (n % bpf) { 130 fprintf(stderr, "rec: bad align: %u bytes\n", n); 131 exit(1); 132 } 133 rlat -= n / bpf; 134 buf->used += n; 135 done += n; 136 } 137 return done; 138 } 139 140 /* 141 * write buffer contents to file, without blocking 142 */ 143 unsigned 144 buf_play(struct buf *buf, struct sio_hdl *hdl) 145 { 146 unsigned count, done = 0; 147 int bpf = par.pchan * par.bps; 148 int n; 149 150 while (buf->used) { 151 count = BUF_LEN - buf->start; 152 if (count > buf->used) 153 count = buf->used; 154 /* try to confuse the server */ 155 //count = 1 + (rand() % count); 156 n = sio_write(hdl, buf->data + buf->start, count); 157 if (n == 0) { 158 if (sio_eof(hdl)) { 159 fprintf(stderr, "sio_write() failed\n"); 160 exit(1); 161 } 162 break; 163 } 164 if (n % bpf) { 165 fprintf(stderr, "play: bad align: %u bytes\n", n); 166 exit(1); 167 } 168 plat += n / bpf; 169 //write(STDOUT_FILENO, buf->data + buf->start, n); 170 buf->used -= n; 171 buf->start += n; 172 if (buf->start >= BUF_LEN) 173 buf->start -= BUF_LEN; 174 done += n; 175 } 176 return done; 177 } 178 179 void 180 usage(void) 181 { 182 fprintf(stderr, 183 "usage: fd [-v] [-r rate] [-c ichan] [-C ochan] [-e enc] " 184 "[-i file] [-o file]\n"); 185 } 186 187 int 188 main(int argc, char **argv) 189 { 190 int ch, recfd, playfd, nfds, events, revents; 191 char *recpath, *playpath; 192 struct sio_hdl *hdl; 193 #define NFDS 16 194 struct pollfd pfd[NFDS]; 195 unsigned mode; 196 197 recfd = -1; 198 recpath = NULL; 199 playfd = -1; 200 playpath = NULL; 201 202 /* 203 * defaults parameters 204 */ 205 sio_initpar(&par); 206 par.sig = 1; 207 par.bits = 16; 208 par.pchan = par.rchan = 2; 209 par.rate = 44100; 210 211 while ((ch = getopt(argc, argv, "r:c:C:e:i:o:b:x:")) != -1) { 212 switch(ch) { 213 case 'r': 214 if (sscanf(optarg, "%u", &par.rate) != 1) { 215 fprintf(stderr, "%s: bad rate\n", optarg); 216 exit(1); 217 } 218 break; 219 case 'c': 220 if (sscanf(optarg, "%u", &par.pchan) != 1) { 221 fprintf(stderr, "%s: bad play chans\n", optarg); 222 exit(1); 223 } 224 break; 225 case 'C': 226 if (sscanf(optarg, "%u", &par.rchan) != 1) { 227 fprintf(stderr, "%s: bad rec chans\n", optarg); 228 exit(1); 229 } 230 break; 231 case 'e': 232 if (!sio_strtoenc(&par, optarg)) { 233 fprintf(stderr, "%s: unknown encoding\n", optarg); 234 exit(1); 235 } 236 break; 237 case 'o': 238 recpath = optarg; 239 break; 240 case 'i': 241 playpath = optarg; 242 break; 243 case 'b': 244 if (sscanf(optarg, "%u", &par.appbufsz) != 1) { 245 fprintf(stderr, "%s: bad buf size\n", optarg); 246 exit(1); 247 } 248 break; 249 case 'x': 250 for (par.xrun = 0;; par.xrun++) { 251 if (par.xrun == sizeof(xstr) / sizeof(char *)) { 252 fprintf(stderr, 253 "%s: bad xrun mode\n", optarg); 254 exit(1); 255 } 256 if (strcmp(xstr[par.xrun], optarg) == 0) 257 break; 258 } 259 break; 260 default: 261 usage(); 262 exit(1); 263 break; 264 } 265 } 266 mode = 0; 267 if (recpath) 268 mode |= SIO_REC; 269 if (playpath) 270 mode |= SIO_PLAY; 271 if (mode == 0) { 272 fprintf(stderr, "-i or -o option required\n"); 273 exit(0); 274 } 275 hdl = sio_open(SIO_DEVANY, mode, 1); 276 if (hdl == NULL) { 277 fprintf(stderr, "sio_open() failed\n"); 278 exit(1); 279 } 280 if (sio_nfds(hdl) > NFDS) { 281 fprintf(stderr, "too many descriptors to poll\n"); 282 exit(1); 283 } 284 sio_onmove(hdl, cb, NULL); 285 if (!sio_setpar(hdl, &par)) { 286 fprintf(stderr, "sio_setpar() failed\n"); 287 exit(1); 288 } 289 if (!sio_getpar(hdl, &par)) { 290 fprintf(stderr, "sio_setpar() failed\n"); 291 exit(1); 292 } 293 fprintf(stderr, "using %u%%%u frame buffer\n", par.bufsz, par.round); 294 if (!sio_start(hdl)) { 295 fprintf(stderr, "sio_start() failed\n"); 296 exit(1); 297 } 298 299 events = 0; 300 if (recpath) { 301 recfd = open(recpath, O_CREAT | O_WRONLY | O_TRUNC, 0666); 302 if (recfd < 0) { 303 perror(recpath); 304 exit(1); 305 } 306 events |= POLLIN; 307 } 308 if (playpath) { 309 playfd = open(playpath, O_RDONLY); 310 if (playfd < 0) { 311 perror(playpath); 312 exit(1); 313 } 314 events |= POLLOUT; 315 buf_read(&playbuf, playfd); 316 buf_play(&playbuf, hdl); 317 } 318 for (;;) { 319 nfds = sio_pollfd(hdl, pfd, events); 320 while (poll(pfd, nfds, 1000) < 0) { 321 if (errno == EINTR) 322 continue; 323 perror("poll"); 324 exit(1); 325 } 326 revents = sio_revents(hdl, pfd); 327 if (revents & POLLHUP) { 328 fprintf(stderr, "device hangup\n"); 329 exit(0); 330 } 331 if (revents & POLLIN) { 332 buf_rec(&recbuf, hdl); 333 buf_write(&recbuf, recfd); 334 } 335 if (revents & POLLOUT) { 336 buf_play(&playbuf, hdl); 337 buf_read(&playbuf, playfd); 338 } 339 } 340 sio_close(hdl); 341 return 0; 342 } 343