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 <stdlib.h>
21 #include <alsa/asoundlib.h>
22 
23 #include "sio.h"
24 
25 #define STEREO	2
26 #define RATE	48000
27 #define FPS	25
28 
29 static snd_pcm_t *hdl;
30 static snd_pcm_hw_params_t *par;
31 static int16_t *buffer;
32 static unsigned int samples;
33 
34 struct data {
35 	int16_t left;
36 	int16_t right;
37 };
38 
39 int
init_sio(void)40 init_sio(void)
41 {
42 	snd_pcm_uframes_t round;
43 	unsigned int rate;
44 	int rc;
45 
46 	rc = snd_pcm_open(&hdl, "default", SND_PCM_STREAM_CAPTURE, 0);
47 	if (rc < 0)
48 		errx(1, "unable to open pcm device: %s", snd_strerror(rc));
49 
50 	snd_pcm_hw_params_malloc(&par);
51 	snd_pcm_hw_params_any(hdl, par);
52 	snd_pcm_hw_params_set_access(hdl, par,
53 		SND_PCM_ACCESS_RW_INTERLEAVED);
54 	snd_pcm_hw_params_set_format(hdl, par,
55 		SND_PCM_FORMAT_S16_LE);
56 	snd_pcm_hw_params_set_channels(hdl, par, STEREO);
57 	snd_pcm_hw_params_set_rate(hdl, par, RATE, 0);
58 
59 	rc = snd_pcm_hw_params(hdl, par);
60 	if (rc < 0)
61 		errx(1, "unable to set hw parameters: %s", snd_strerror(rc));
62 
63 	snd_pcm_hw_params_get_period_size(par, &round, NULL);
64 	snd_pcm_hw_params_get_rate(par, &rate, 0);
65 	snd_pcm_hw_params_free(par);
66 	snd_pcm_prepare(hdl);
67 
68 	samples = rate / FPS;
69 	samples -= samples % round - round;
70 	buffer = calloc(samples * STEREO, sizeof(int16_t));
71 	assert(buffer);
72 
73 	return 0;
74 }
75 
76 unsigned int
max_samples_sio(void)77 max_samples_sio(void)
78 {
79 	return samples;
80 }
81 
82 void
read_sio(double * left,double * right,size_t n)83 read_sio(double *left, double *right, size_t n)
84 {
85 	snd_pcm_sframes_t rc;
86 	struct data *data;
87 	int i;
88 
89 	if (n > samples)
90 		n = samples;
91 
92 	rc = snd_pcm_readi(hdl, buffer, samples);
93 	if (rc != samples) {
94 		warnx("audio read error: %s", snd_strerror(rc));
95 		if (rc == -EPIPE)
96 			snd_pcm_prepare(hdl);
97 	}
98 
99 	data = (struct data *)&buffer[samples - n];
100 
101 	for (i = 0; i < n; i++) {
102 		left[i] = data[i].left;
103 		right[i] = data[i].right;
104 	}
105 }
106 
107 void
free_sio(void)108 free_sio(void)
109 {
110 	snd_pcm_drain(hdl);
111 	snd_pcm_close(hdl);
112 	free(buffer);
113 }
114