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