Implements ec_enc_patch_initial_bits()
[opus.git] / tools / alsa_device.c
1 /*
2    Copyright (C) 2004-2006 Jean-Marc Valin
3    Copyright (C) 2006 Commonwealth Scientific and Industrial Research
4                       Organisation (CSIRO) Australia
5    
6    Redistribution and use in source and binary forms, with or without
7    modification, are permitted provided that the following conditions are
8    met:
9
10    1. Redistributions of source code must retain the above copyright notice,
11    this list of conditions and the following disclaimer.
12
13    2. Redistributions in binary form must reproduce the above copyright
14    notice, this list of conditions and the following disclaimer in the
15    documentation and/or other materials provided with the distribution.
16
17    THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20    DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
21    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25    STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27    POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include "alsa_device.h"
31 #include <stdlib.h>
32 #include <alsa/asoundlib.h>
33
34 struct AlsaDevice_ {
35    char *device_name;
36    int channels;
37    int period;
38    snd_pcm_t *capture_handle;
39    snd_pcm_t *playback_handle;
40    int readN, writeN;
41    struct pollfd *read_fd, *write_fd;
42 };
43
44 #define PERIODS 3
45 AlsaDevice *alsa_device_open(char *device_name, unsigned int rate, int channels, int period)
46 {
47    int dir;
48    int err;
49    snd_pcm_hw_params_t *hw_params;
50    snd_pcm_sw_params_t *sw_params;
51    snd_pcm_uframes_t period_size = period;
52    snd_pcm_uframes_t buffer_size = PERIODS*period;
53    static snd_output_t *jcd_out;
54    AlsaDevice *dev = malloc(sizeof(*dev));
55    if (!dev)
56       return NULL;
57    dev->device_name = malloc(1+strlen(device_name));
58    if (!dev->device_name)
59    {
60       free(dev);
61       return NULL;
62    }
63    strcpy(dev->device_name, device_name);
64    dev->channels = channels;
65    dev->period = period;
66    err = snd_output_stdio_attach(&jcd_out, stdout, 0);
67    
68    if ((err = snd_pcm_open (&dev->capture_handle, dev->device_name, SND_PCM_STREAM_CAPTURE, 0)) < 0) {
69       fprintf (stderr, "cannot open audio device %s (%s)\n",
70                dev->device_name,
71                snd_strerror (err));
72       assert(0);
73    }
74
75    if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) {
76       fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n",
77                snd_strerror (err));
78       assert(0);
79    }
80
81    if ((err = snd_pcm_hw_params_any (dev->capture_handle, hw_params)) < 0) {
82       fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n",
83                snd_strerror (err));
84       assert(0);
85    }
86
87    if ((err = snd_pcm_hw_params_set_access (dev->capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
88       fprintf (stderr, "cannot set access type (%s)\n",
89                snd_strerror (err));
90       assert(0);
91    }
92
93    if ((err = snd_pcm_hw_params_set_format (dev->capture_handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) {
94       fprintf (stderr, "cannot set sample format (%s)\n",
95                snd_strerror (err));
96       assert(0);
97    }
98
99    if ((err = snd_pcm_hw_params_set_rate_near (dev->capture_handle, hw_params, &rate, 0)) < 0) {
100       fprintf (stderr, "cannot set sample rate (%s)\n",
101                snd_strerror (err));
102       assert(0);
103    }
104    /*fprintf (stderr, "rate = %d\n", rate);*/
105
106    if ((err = snd_pcm_hw_params_set_channels (dev->capture_handle, hw_params, channels)) < 0) {
107       fprintf (stderr, "cannot set channel count (%s)\n",
108                snd_strerror (err));
109       assert(0);
110    }
111    
112    period_size = period;
113    dir = 0;
114    if ((err = snd_pcm_hw_params_set_period_size_near (dev->capture_handle, hw_params, &period_size, &dir)) < 0) {
115       fprintf (stderr, "cannot set period size (%s)\n",
116                snd_strerror (err));
117       assert(0);
118    }
119    
120    if ((err = snd_pcm_hw_params_set_periods (dev->capture_handle, hw_params, PERIODS, 0)) < 0) {
121       fprintf (stderr, "cannot set number of periods (%s)\n",
122                snd_strerror (err));
123       assert(0);
124    }
125    
126    buffer_size = period_size * PERIODS;
127    dir=0;
128    if ((err = snd_pcm_hw_params_set_buffer_size_near (dev->capture_handle, hw_params, &buffer_size)) < 0) {
129       fprintf (stderr, "cannot set buffer time (%s)\n",
130                snd_strerror (err));
131       assert(0);
132    }
133    
134    if ((err = snd_pcm_hw_params (dev->capture_handle, hw_params)) < 0) {
135       fprintf (stderr, "cannot set capture parameters (%s)\n",
136                snd_strerror (err));
137       assert(0);
138    }
139    /*snd_pcm_dump_setup(dev->capture_handle, jcd_out);*/
140    snd_pcm_hw_params_free (hw_params);
141
142    if ((err = snd_pcm_sw_params_malloc (&sw_params)) < 0) {
143       fprintf (stderr, "cannot allocate software parameters structure (%s)\n",
144                snd_strerror (err));
145       assert(0);
146    }
147    if ((err = snd_pcm_sw_params_current (dev->capture_handle, sw_params)) < 0) {
148       fprintf (stderr, "cannot initialize software parameters structure (%s)\n",
149                snd_strerror (err));
150       assert(0);
151    }
152    if ((err = snd_pcm_sw_params_set_avail_min (dev->capture_handle, sw_params, period)) < 0) {
153       fprintf (stderr, "cannot set minimum available count (%s)\n",
154                snd_strerror (err));
155       assert(0);
156    }
157    if ((err = snd_pcm_sw_params (dev->capture_handle, sw_params)) < 0) {
158       fprintf (stderr, "cannot set software parameters (%s)\n",
159                snd_strerror (err));
160       assert(0);
161    }   
162    
163    
164    if ((err = snd_pcm_open (&dev->playback_handle, dev->device_name, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
165       fprintf (stderr, "cannot open audio device %s (%s)\n",
166                dev->device_name,
167                snd_strerror (err));
168       assert(0);
169    }
170    
171    if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) {
172       fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n",
173                snd_strerror (err));
174       assert(0);
175    }
176
177    if ((err = snd_pcm_hw_params_any (dev->playback_handle, hw_params)) < 0) {
178       fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n",
179                snd_strerror (err));
180       assert(0);
181    }
182
183    if ((err = snd_pcm_hw_params_set_access (dev->playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
184       fprintf (stderr, "cannot set access type (%s)\n",
185                snd_strerror (err));
186       assert(0);
187    }
188
189    if ((err = snd_pcm_hw_params_set_format (dev->playback_handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) {
190       fprintf (stderr, "cannot set sample format (%s)\n",
191                snd_strerror (err));
192       assert(0);
193    }
194
195    if ((err = snd_pcm_hw_params_set_rate_near (dev->playback_handle, hw_params, &rate, 0)) < 0) {
196       fprintf (stderr, "cannot set sample rate (%s)\n",
197                snd_strerror (err));
198       assert(0);
199    }
200    /*fprintf (stderr, "rate = %d\n", rate);*/
201
202    if ((err = snd_pcm_hw_params_set_channels (dev->playback_handle, hw_params, channels)) < 0) {
203       fprintf (stderr, "cannot set channel count (%s)\n",
204                snd_strerror (err));
205       assert(0);
206    }
207    
208    period_size = period;
209    dir = 0;
210    if ((err = snd_pcm_hw_params_set_period_size_near (dev->playback_handle, hw_params, &period_size, &dir)) < 0) {
211       fprintf (stderr, "cannot set period size (%s)\n",
212                snd_strerror (err));
213       assert(0);
214    }
215    if ((err = snd_pcm_hw_params_set_periods (dev->playback_handle, hw_params, PERIODS, 0)) < 0) {
216       fprintf (stderr, "cannot set number of periods (%s)\n",
217                snd_strerror (err));
218       assert(0);
219    }
220    buffer_size = period_size * PERIODS;
221    dir=0;
222    if ((err = snd_pcm_hw_params_set_buffer_size_near (dev->playback_handle, hw_params, &buffer_size)) < 0) {
223       fprintf (stderr, "cannot set buffer time (%s)\n",
224                snd_strerror (err));
225       assert(0);
226    }
227
228
229    if ((err = snd_pcm_hw_params (dev->playback_handle, hw_params)) < 0) {
230       fprintf (stderr, "cannot set playback parameters (%s)\n",
231                snd_strerror (err));
232       assert(0);
233    }
234
235    /*snd_pcm_dump_setup(dev->playback_handle, jcd_out);*/
236    snd_pcm_hw_params_free (hw_params);
237
238    
239    if ((err = snd_pcm_sw_params_malloc (&sw_params)) < 0) {
240       fprintf (stderr, "cannot allocate software parameters structure (%s)\n",
241                snd_strerror (err));
242       assert(0);
243    }
244    if ((err = snd_pcm_sw_params_current (dev->playback_handle, sw_params)) < 0) {
245       fprintf (stderr, "cannot initialize software parameters structure (%s)\n",
246                snd_strerror (err));
247       assert(0);
248    }
249    if ((err = snd_pcm_sw_params_set_avail_min (dev->playback_handle, sw_params, period)) < 0) {
250       fprintf (stderr, "cannot set minimum available count (%s)\n",
251                snd_strerror (err));
252       assert(0);
253    }
254    if ((err = snd_pcm_sw_params_set_start_threshold (dev->playback_handle, sw_params, period)) < 0) {
255       fprintf (stderr, "cannot set start mode (%s)\n",
256                snd_strerror (err));
257       assert(0);
258    }
259    if ((err = snd_pcm_sw_params (dev->playback_handle, sw_params)) < 0) {
260       fprintf (stderr, "cannot set software parameters (%s)\n",
261                snd_strerror (err));
262       assert(0);
263    }
264   
265    
266    snd_pcm_link(dev->capture_handle, dev->playback_handle);
267    if ((err = snd_pcm_prepare (dev->capture_handle)) < 0) {
268       fprintf (stderr, "cannot prepare audio interface for use (%s)\n",
269                snd_strerror (err));
270       assert(0);
271    }
272    if ((err = snd_pcm_prepare (dev->playback_handle)) < 0) {
273       fprintf (stderr, "cannot prepare audio interface for use (%s)\n",
274                snd_strerror (err));
275       assert(0);
276    }
277    
278    dev->readN = snd_pcm_poll_descriptors_count(dev->capture_handle);
279    dev->writeN = snd_pcm_poll_descriptors_count(dev->playback_handle);
280
281    dev->read_fd = malloc(dev->readN*sizeof(*dev->read_fd));
282    /*printf ("descriptors: %d %d\n", dev->readN, dev->writeN);*/
283    if (snd_pcm_poll_descriptors(dev->capture_handle, dev->read_fd, dev->readN) != dev->readN)
284    {
285       fprintf (stderr, "cannot obtain capture file descriptors (%s)\n",
286                snd_strerror (err));
287       assert(0);
288    }
289    
290    dev->write_fd = malloc(dev->writeN*sizeof(*dev->read_fd));
291    if (snd_pcm_poll_descriptors(dev->playback_handle, dev->write_fd, dev->writeN) != dev->writeN)
292    {
293       fprintf (stderr, "cannot obtain playback file descriptors (%s)\n",
294                snd_strerror (err));
295       assert(0);
296    }
297    return dev;
298 }
299
300 void alsa_device_close(AlsaDevice *dev)
301 {
302    snd_pcm_close(dev->capture_handle);
303    snd_pcm_close(dev->playback_handle);
304    free(dev->device_name);
305    free(dev);
306 }
307
308 int alsa_device_read(AlsaDevice *dev, short *pcm, int len)
309 {
310    int err;
311    /*fprintf (stderr, "-");*/
312    if ((err = snd_pcm_readi (dev->capture_handle, pcm, len)) != len)
313    {
314       if (err<0)
315       {
316          //fprintf(stderr, "error %d, EPIPE = %d\n", err, EPIPE);
317          if (err == -EPIPE)
318          {
319             fprintf (stderr, "An overrun has occured, reseting capture\n");
320          } else
321          {
322             fprintf (stderr, "read from audio interface failed (%s)\n",
323                      snd_strerror (err));
324          }
325          if ((err = snd_pcm_prepare (dev->capture_handle)) < 0)
326          {
327             fprintf (stderr, "cannot prepare audio interface for use (%s)\n",
328                      snd_strerror (err));
329          }
330          if ((err = snd_pcm_start (dev->capture_handle)) < 0)
331          {
332             fprintf (stderr, "cannot prepare audio interface for use (%s)\n",
333                      snd_strerror (err));
334          }
335          /*alsa_device_read(dev,pcm,len);*/
336       } else {
337          fprintf (stderr, "Couldn't read as many samples as I wanted (%d instead of %d)\n", err, len);
338       }
339       return 1;
340    }
341    return 0;
342 }
343
344 int alsa_device_write(AlsaDevice *dev, const short *pcm, int len)
345 {
346    int err;
347    /*fprintf (stderr, "+");*/
348    if ((err = snd_pcm_writei (dev->playback_handle, pcm, len)) != len)
349    {
350       if (err<0)
351       {
352          if (err == -EPIPE)
353          {
354             fprintf (stderr, "An underrun has occured, reseting playback, len=%d\n", len);
355          } else
356          {
357             fprintf (stderr, "write to audio interface failed (%s)\n",
358                      snd_strerror (err));
359          }
360          if ((err = snd_pcm_prepare (dev->playback_handle)) < 0)
361          {
362             fprintf (stderr, "cannot prepare audio interface for use (%s)\n",
363                      snd_strerror (err));
364          }
365       } else {
366          fprintf (stderr, "Couldn't write as many samples as I wanted (%d instead of %d)\n", err, len);
367       }
368       /*alsa_device_write(dev,pcm,len);*/
369       return 1;
370    }
371    return 0;
372 }
373
374 int alsa_device_capture_ready(AlsaDevice *dev, struct pollfd *pfds, unsigned int nfds)
375 {
376    unsigned short revents=0;
377    int err;
378    if ((err = snd_pcm_poll_descriptors_revents(dev->capture_handle, pfds, dev->readN, &revents)) < 0)
379    {
380       //cerr << "error in snd_pcm_poll_descriptors_revents for capture: " << snd_strerror (err) << endl;
381       //FIXME: This is a kludge
382       fprintf (stderr, "error in alsa_device_capture_ready: %s\n", snd_strerror (err));
383       return pfds[0].revents & POLLIN;
384    }
385    //cerr << (revents & POLLERR) << endl;
386    return revents & POLLIN;
387 }
388
389 int alsa_device_playback_ready(AlsaDevice *dev, struct pollfd *pfds, unsigned int nfds)
390 {
391    unsigned short revents=0;
392    int err;
393    if ((err = snd_pcm_poll_descriptors_revents(dev->playback_handle, pfds+dev->readN, dev->writeN, &revents)) < 0)
394    {
395       //cerr << "error in snd_pcm_poll_descriptors_revents for playback: " << snd_strerror (err) << endl;
396       //FIXME: This is a kludge
397       fprintf (stderr, "error in alsa_device_playback_ready: %s\n", snd_strerror (err));
398       return pfds[1].revents & POLLOUT;
399    }
400    //cerr << (revents & POLLERR) << endl;
401    return revents & POLLOUT;
402 }
403
404 void alsa_device_start(AlsaDevice *dev)
405 {
406    int i;
407    short pcm[dev->period*dev->channels];
408    for (i=0;i<dev->period*dev->channels;i++)
409       pcm[i] = 0;
410    alsa_device_write(dev, pcm, dev->period);
411    alsa_device_write(dev, pcm, dev->period);
412    snd_pcm_start(dev->capture_handle);
413    snd_pcm_start(dev->playback_handle);
414 }
415
416 int alsa_device_nfds(AlsaDevice *dev)
417 {
418    return dev->writeN+dev->readN;
419 }
420
421 void alsa_device_getfds(AlsaDevice *dev, struct pollfd *pfds, unsigned int nfds)
422 {
423    int i;
424    assert (nfds >= dev->writeN+dev->readN);
425    for (i=0;i<dev->readN;i++)
426       pfds[i] = dev->read_fd[i];
427    for (i=0;i<dev->writeN;i++)
428       pfds[i+dev->readN] = dev->write_fd[i];
429 }