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