1 /* $Id$ */
2 /*
3  * Copyright (c) 2013 Dimitri Sokolyuk <demon@dim13.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <assert.h>
19 #include <err.h>
20 #include <sndio.h>
21 #include <stdlib.h>
22 
23 #include "sio.h"
24 
25 #define STEREO	2
26 #define BITS	16
27 #define SIGNED	1
28 #define FPS	25
29 
30 static struct	sio_hdl *hdl;
31 static struct	sio_par par;
32 static int16_t	*buffer;
33 static unsigned int samples;
34 
35 struct data {
36 	int16_t left;
37 	int16_t right;
38 };
39 
40 int
init_sio(void)41 init_sio(void)
42 {
43 	hdl = sio_open(SIO_DEVANY, SIO_REC, 0);
44 	if (!hdl)
45 		errx(1, "cannot connect to sound server, is it running?");
46 
47 	sio_initpar(&par);
48 
49 	par.rchan = STEREO;
50 	par.bits = BITS;
51 	par.le = SIO_LE_NATIVE;
52 	par.sig = SIGNED;
53 
54 	if (!sio_setpar(hdl, &par))
55 		errx(1, "SIO set params failed");
56 	if (!sio_getpar(hdl, &par))
57 		errx(1, "SIO get params failed");
58 
59 	if (par.rchan != STEREO ||
60 	    par.bits != BITS ||
61 	    par.le != SIO_LE_NATIVE ||
62 	    par.sig != SIGNED)
63 		errx(1, "unsupported audio params");
64 
65 	samples = par.rate / FPS;
66 	samples -= samples % par.round - par.round;
67 	buffer = calloc(samples * par.rchan, sizeof(int16_t));
68 	assert(buffer);
69 
70 	return sio_start(hdl);
71 }
72 
73 unsigned int
max_samples_sio(void)74 max_samples_sio(void)
75 {
76 	/*
77 	 * maximal number of samples we're willing to provide
78 	 * with 1920 at 25 fps and 48000 Hz or
79 	 * with 1764 at 25 fps and 44100 Hz it shall fit on most screens
80 	 */
81 	return samples;
82 }
83 
84 void
read_sio(double * left,double * right,size_t n)85 read_sio(double *left, double *right, size_t n)
86 {
87 	int done, i;
88 	char *p = (char *)buffer;
89 	size_t bufsz = samples * par.rchan * sizeof(int16_t);
90 	size_t rndsz = n * par.rchan * sizeof(int16_t);
91 	struct data *data;
92 
93 	if (rndsz > bufsz)
94 		rndsz = bufsz;
95 
96 	for (done = 0; bufsz > 0; p += done, bufsz -= done) {
97 		done = sio_read(hdl, p, bufsz);
98 		if (sio_eof(hdl))
99 			errx(1, "SIO EOF");
100 	}
101 
102 	/*
103 	 * return a pointer to the latest ROUND samples (the most recent
104 	 * ones) to minimize latency between picture and sound
105 	 */
106 	data = (struct data *)(p - rndsz);
107 
108 	for (i = 0; i < n; i++) {
109 		left[i] = data[i].left;
110 		right[i] = data[i].right;
111 	}
112 }
113 
114 void
free_sio(void)115 free_sio(void)
116 {
117 	sio_stop(hdl);
118 	sio_close(hdl);
119 	free(buffer);
120 }
121