• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * QEMU ALSA audio driver
3  *
4  * Copyright (c) 2008-2010 The Android Open Source Project
5  * Copyright (c) 2005 Vassili Karpov (malc)
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to deal
9  * in the Software without restriction, including without limitation the rights
10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in
15  * all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23  * THE SOFTWARE.
24  */
25 #include <alsa/asoundlib.h>
26 #include "qemu-common.h"
27 #include "sysemu/char.h"
28 #include "audio.h"
29 
30 #if QEMU_GNUC_PREREQ(4, 3)
31 #pragma GCC diagnostic ignored "-Waddress"
32 #endif
33 
34 #define AUDIO_CAP "alsa"
35 #include "audio_int.h"
36 #include <dlfcn.h>
37 #include <pthread.h>
38 #include "android/qemu-debug.h"
39 
40 #define  DEBUG  1
41 
42 #if DEBUG
43 #  include <stdio.h>
44 #  define D(...)  VERBOSE_PRINT(audio,__VA_ARGS__)
45 #  define D_ACTIVE  VERBOSE_CHECK(audio)
46 #  define O(...)  VERBOSE_PRINT(audioout,__VA_ARGS__)
47 #  define I(...)  VERBOSE_PRINT(audioin,__VA_ARGS__)
48 #else
49 #  define D(...)  ((void)0)
50 #  define D_ACTIVE  0
51 #  define O(...)  ((void)0)
52 #  define I(...)  ((void)0)
53 #endif
54 
55 #define  DYNLINK_FUNCTIONS   \
56     DYNLINK_FUNC(size_t,snd_pcm_sw_params_sizeof,(void))    \
57     DYNLINK_FUNC(int,snd_pcm_hw_params_current,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)) \
58     DYNLINK_FUNC(int,snd_pcm_sw_params_set_start_threshold,(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val))  \
59     DYNLINK_FUNC(int,snd_pcm_sw_params,(snd_pcm_t *pcm, snd_pcm_sw_params_t *params))  \
60     DYNLINK_FUNC(int,snd_pcm_sw_params_current,(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)) \
61     DYNLINK_FUNC(size_t,snd_pcm_hw_params_sizeof,(void))  \
62     DYNLINK_FUNC(int,snd_pcm_hw_params_any,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params))  \
63     DYNLINK_FUNC(int,snd_pcm_hw_params_set_access,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t _access))  \
64     DYNLINK_FUNC(int,snd_pcm_hw_params_get_format,(const snd_pcm_hw_params_t *params, snd_pcm_format_t *val)) \
65     DYNLINK_FUNC(int,snd_pcm_hw_params_set_format,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t val))  \
66     DYNLINK_FUNC(int,snd_pcm_hw_params_set_rate_near,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir))  \
67     DYNLINK_FUNC(int,snd_pcm_hw_params_set_channels_near,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val))  \
68     DYNLINK_FUNC(int,snd_pcm_hw_params_set_buffer_time_near,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir))  \
69     DYNLINK_FUNC(int,snd_pcm_hw_params,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params))  \
70     DYNLINK_FUNC(int,snd_pcm_hw_params_get_buffer_size,(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val))  \
71     DYNLINK_FUNC(int,snd_pcm_prepare,(snd_pcm_t *pcm))  \
72     DYNLINK_FUNC(int,snd_pcm_hw_params_get_period_size,(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *frames, int *dir))  \
73     DYNLINK_FUNC(int,snd_pcm_hw_params_get_period_size_min,(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *frames, int *dir))  \
74     DYNLINK_FUNC(int,snd_pcm_hw_params_set_period_size,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val, int dir))  \
75     DYNLINK_FUNC(int,snd_pcm_hw_params_get_buffer_size_min,(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val)) \
76     DYNLINK_FUNC(int,snd_pcm_hw_params_set_buffer_size,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val))  \
77     DYNLINK_FUNC(int,snd_pcm_hw_params_set_period_time_near,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir))  \
78     DYNLINK_FUNC(snd_pcm_sframes_t,snd_pcm_avail_update,(snd_pcm_t *pcm)) \
79     DYNLINK_FUNC(int,snd_pcm_drop,(snd_pcm_t *pcm))  \
80     DYNLINK_FUNC(snd_pcm_sframes_t,snd_pcm_writei,(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size))  \
81     DYNLINK_FUNC(snd_pcm_sframes_t,snd_pcm_readi,(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size))  \
82     DYNLINK_FUNC(snd_pcm_state_t,snd_pcm_state,(snd_pcm_t *pcm))  \
83     DYNLINK_FUNC(const char*,snd_strerror,(int errnum)) \
84     DYNLINK_FUNC(int,snd_pcm_open,(snd_pcm_t **pcm, const char *name,snd_pcm_stream_t stream, int mode)) \
85     DYNLINK_FUNC(int,snd_pcm_close,(snd_pcm_t *pcm))  \
86     DYNLINK_FUNC(int,snd_pcm_hw_params_set_buffer_size_near,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val)) \
87     DYNLINK_FUNC(int,snd_pcm_hw_params_set_period_size_near,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir)) \
88     DYNLINK_FUNC(int,snd_pcm_hw_params_get_format,(const snd_pcm_hw_params_t *params, snd_pcm_format_t *val)) \
89     DYNLINK_FUNC(int,snd_pcm_resume,(snd_pcm_t *pcm)) \
90     DYNLINK_FUNC(int,snd_pcm_poll_descriptors_revents,(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)) \
91     DYNLINK_FUNC(int,snd_pcm_poll_descriptors_count,(snd_pcm_t *pcm)) \
92     DYNLINK_FUNC(int,snd_pcm_poll_descriptors,(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space)) \
93 
94 #define DYNLINK_FUNCTIONS_INIT \
95     alsa_dynlink_init
96 
97 #include "android/dynlink.h"
98 
99 /* these are inlined functions in the original headers */
100 #define FF_snd_pcm_hw_params_alloca(ptr) \
101     do { *ptr = (snd_pcm_hw_params_t *) alloca(FF(snd_pcm_hw_params_sizeof)()); memset(*ptr, 0, FF(snd_pcm_hw_params_sizeof)()); } while (0)
102 
103 #define FF_snd_pcm_sw_params_alloca(ptr) \
104     do { *ptr = (snd_pcm_sw_params_t *) alloca(FF(snd_pcm_sw_params_sizeof)()); memset(*ptr, 0, FF(snd_pcm_sw_params_sizeof)()); } while (0)
105 
106 static void*  alsa_lib;
107 
108 struct pollhlp {
109     snd_pcm_t *handle;
110     struct pollfd *pfds;
111     int count;
112     int mask;
113 };
114 
115 typedef struct ALSAVoiceOut {
116     HWVoiceOut hw;
117     int wpos;
118     int pending;
119     void *pcm_buf;
120     snd_pcm_t *handle;
121     struct pollhlp pollhlp;
122 } ALSAVoiceOut;
123 
124 typedef struct ALSAVoiceIn {
125     HWVoiceIn hw;
126     snd_pcm_t *handle;
127     void *pcm_buf;
128     struct pollhlp pollhlp;
129 } ALSAVoiceIn;
130 
131 static struct {
132     int size_in_usec_in;
133     int size_in_usec_out;
134     const char *pcm_name_in;
135     const char *pcm_name_out;
136     unsigned int buffer_size_in;
137     unsigned int period_size_in;
138     unsigned int buffer_size_out;
139     unsigned int period_size_out;
140     unsigned int threshold;
141 
142     int buffer_size_in_overridden;
143     int period_size_in_overridden;
144 
145     int buffer_size_out_overridden;
146     int period_size_out_overridden;
147     int verbose;
148 } conf = {
149     .buffer_size_out = 4096,
150     .period_size_out = 1024,
151     .pcm_name_out = "default",
152     .pcm_name_in = "default",
153 };
154 
155 struct alsa_params_req {
156     int freq;
157     snd_pcm_format_t fmt;
158     int nchannels;
159     int size_in_usec;
160     int override_mask;
161     unsigned int buffer_size;
162     unsigned int period_size;
163 };
164 
165 struct alsa_params_obt {
166     int freq;
167     audfmt_e fmt;
168     int endianness;
169     int nchannels;
170     snd_pcm_uframes_t samples;
171 };
172 
alsa_logerr(int err,const char * fmt,...)173 static void GCC_FMT_ATTR (2, 3) alsa_logerr (int err, const char *fmt, ...)
174 {
175     va_list ap;
176 
177     va_start (ap, fmt);
178     AUD_vlog (AUDIO_CAP, fmt, ap);
179     va_end (ap);
180 
181     AUD_log (AUDIO_CAP, "Reason: %s\n", FF(snd_strerror) (err));
182 }
183 
alsa_logerr2(int err,const char * typ,const char * fmt,...)184 static void GCC_FMT_ATTR (3, 4) alsa_logerr2 (
185     int err,
186     const char *typ,
187     const char *fmt,
188     ...
189     )
190 {
191     va_list ap;
192 
193     AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
194 
195     va_start (ap, fmt);
196     AUD_vlog (AUDIO_CAP, fmt, ap);
197     va_end (ap);
198 
199     AUD_log (AUDIO_CAP, "Reason: %s\n", FF(snd_strerror) (err));
200 }
201 
alsa_fini_poll(struct pollhlp * hlp)202 static void alsa_fini_poll (struct pollhlp *hlp)
203 {
204     int i;
205     struct pollfd *pfds = hlp->pfds;
206 
207     if (pfds) {
208         for (i = 0; i < hlp->count; ++i) {
209             qemu_set_fd_handler (pfds[i].fd, NULL, NULL, NULL);
210         }
211         g_free (pfds);
212     }
213     hlp->pfds = NULL;
214     hlp->count = 0;
215     hlp->handle = NULL;
216 }
217 
alsa_anal_close1(snd_pcm_t ** handlep)218 static void alsa_anal_close1 (snd_pcm_t **handlep)
219 {
220     int err = FF(snd_pcm_close) (*handlep);
221     if (err) {
222         alsa_logerr (err, "Failed to close PCM handle %p\n", *handlep);
223     }
224     *handlep = NULL;
225 }
226 
alsa_anal_close(snd_pcm_t ** handlep,struct pollhlp * hlp)227 static void alsa_anal_close (snd_pcm_t **handlep, struct pollhlp *hlp)
228 {
229     alsa_fini_poll (hlp);
230     alsa_anal_close1 (handlep);
231 }
232 
alsa_recover(snd_pcm_t * handle)233 static int alsa_recover (snd_pcm_t *handle)
234 {
235     int err = FF(snd_pcm_prepare) (handle);
236     if (err < 0) {
237         alsa_logerr (err, "Failed to prepare handle %p\n", handle);
238         return -1;
239     }
240     return 0;
241 }
242 
alsa_resume(snd_pcm_t * handle)243 static int alsa_resume (snd_pcm_t *handle)
244 {
245     int err = FF(snd_pcm_resume) (handle);
246     if (err < 0) {
247         alsa_logerr (err, "Failed to resume handle %p\n", handle);
248         return -1;
249     }
250     return 0;
251 }
252 
alsa_poll_handler(void * opaque)253 static void alsa_poll_handler (void *opaque)
254 {
255     int err, count;
256     snd_pcm_state_t state;
257     struct pollhlp *hlp = opaque;
258     unsigned short revents;
259 
260     count = poll (hlp->pfds, hlp->count, 0);
261     if (count < 0) {
262         dolog ("alsa_poll_handler: poll %s\n", strerror (errno));
263         return;
264     }
265 
266     if (!count) {
267         return;
268     }
269 
270     /* XXX: ALSA example uses initial count, not the one returned by
271        poll, correct? */
272     err = FF(snd_pcm_poll_descriptors_revents) (hlp->handle, hlp->pfds,
273                                             hlp->count, &revents);
274     if (err < 0) {
275         alsa_logerr (err, "snd_pcm_poll_descriptors_revents");
276         return;
277     }
278 
279     if (!(revents & hlp->mask)) {
280         if (conf.verbose) {
281             dolog ("revents = %d\n", revents);
282         }
283         return;
284     }
285 
286     state = FF(snd_pcm_state) (hlp->handle);
287     switch (state) {
288     case SND_PCM_STATE_SETUP:
289         alsa_recover (hlp->handle);
290         break;
291 
292     case SND_PCM_STATE_XRUN:
293         alsa_recover (hlp->handle);
294         break;
295 
296     case SND_PCM_STATE_SUSPENDED:
297         alsa_resume (hlp->handle);
298         break;
299 
300     case SND_PCM_STATE_PREPARED:
301         audio_run ("alsa run (prepared)");
302         break;
303 
304     case SND_PCM_STATE_RUNNING:
305         audio_run ("alsa run (running)");
306         break;
307 
308     default:
309         dolog ("Unexpected state %d\n", state);
310     }
311 }
312 
alsa_poll_helper(snd_pcm_t * handle,struct pollhlp * hlp,int mask)313 static int alsa_poll_helper (snd_pcm_t *handle, struct pollhlp *hlp, int mask)
314 {
315     int i, count, err;
316     struct pollfd *pfds;
317 
318     count = FF(snd_pcm_poll_descriptors_count) (handle);
319     if (count <= 0) {
320         dolog ("Could not initialize poll mode\n"
321                "Invalid number of poll descriptors %d\n", count);
322         return -1;
323     }
324 
325     pfds = audio_calloc ("alsa_poll_helper", count, sizeof (*pfds));
326     if (!pfds) {
327         dolog ("Could not initialize poll mode\n");
328         return -1;
329     }
330 
331     err = FF(snd_pcm_poll_descriptors) (handle, pfds, count);
332     if (err < 0) {
333         alsa_logerr (err, "Could not initialize poll mode\n"
334                      "Could not obtain poll descriptors\n");
335         g_free (pfds);
336         return -1;
337     }
338 
339     for (i = 0; i < count; ++i) {
340         if (pfds[i].events & POLLIN) {
341             err = qemu_set_fd_handler (pfds[i].fd, alsa_poll_handler,
342                                        NULL, hlp);
343         }
344         if (pfds[i].events & POLLOUT) {
345             if (conf.verbose) {
346                 dolog ("POLLOUT %d %d\n", i, pfds[i].fd);
347             }
348             err = qemu_set_fd_handler (pfds[i].fd, NULL,
349                                        alsa_poll_handler, hlp);
350         }
351         if (conf.verbose) {
352             dolog ("Set handler events=%#x index=%d fd=%d err=%d\n",
353                    pfds[i].events, i, pfds[i].fd, err);
354         }
355 
356         if (err) {
357             dolog ("Failed to set handler events=%#x index=%d fd=%d err=%d\n",
358                    pfds[i].events, i, pfds[i].fd, err);
359 
360             while (i--) {
361                 qemu_set_fd_handler (pfds[i].fd, NULL, NULL, NULL);
362             }
363             g_free (pfds);
364             return -1;
365         }
366     }
367     hlp->pfds = pfds;
368     hlp->count = count;
369     hlp->handle = handle;
370     hlp->mask = mask;
371     return 0;
372 }
373 
alsa_poll_out(HWVoiceOut * hw)374 static int alsa_poll_out (HWVoiceOut *hw)
375 {
376     ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
377 
378     return alsa_poll_helper (alsa->handle, &alsa->pollhlp, POLLOUT);
379 }
380 
alsa_poll_in(HWVoiceIn * hw)381 static int alsa_poll_in (HWVoiceIn *hw)
382 {
383     ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
384 
385     return alsa_poll_helper (alsa->handle, &alsa->pollhlp, POLLIN);
386 }
387 
alsa_write(SWVoiceOut * sw,void * buf,int len)388 static int alsa_write (SWVoiceOut *sw, void *buf, int len)
389 {
390     return audio_pcm_sw_write (sw, buf, len);
391 }
392 
aud_to_alsafmt(audfmt_e fmt)393 static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt)
394 {
395     switch (fmt) {
396     case AUD_FMT_S8:
397         return SND_PCM_FORMAT_S8;
398 
399     case AUD_FMT_U8:
400         return SND_PCM_FORMAT_U8;
401 
402     case AUD_FMT_S16:
403         return SND_PCM_FORMAT_S16_LE;
404 
405     case AUD_FMT_U16:
406         return SND_PCM_FORMAT_U16_LE;
407 
408     case AUD_FMT_S32:
409         return SND_PCM_FORMAT_S32_LE;
410 
411     case AUD_FMT_U32:
412         return SND_PCM_FORMAT_U32_LE;
413 
414     default:
415         dolog ("Internal logic error: Bad audio format %d\n", fmt);
416 #ifdef DEBUG_AUDIO
417         abort ();
418 #endif
419         return SND_PCM_FORMAT_U8;
420     }
421 }
422 
alsa_to_audfmt(snd_pcm_format_t alsafmt,audfmt_e * fmt,int * endianness)423 static int alsa_to_audfmt (snd_pcm_format_t alsafmt, audfmt_e *fmt,
424                            int *endianness)
425 {
426     switch (alsafmt) {
427     case SND_PCM_FORMAT_S8:
428         *endianness = 0;
429         *fmt = AUD_FMT_S8;
430         break;
431 
432     case SND_PCM_FORMAT_U8:
433         *endianness = 0;
434         *fmt = AUD_FMT_U8;
435         break;
436 
437     case SND_PCM_FORMAT_S16_LE:
438         *endianness = 0;
439         *fmt = AUD_FMT_S16;
440         break;
441 
442     case SND_PCM_FORMAT_U16_LE:
443         *endianness = 0;
444         *fmt = AUD_FMT_U16;
445         break;
446 
447     case SND_PCM_FORMAT_S16_BE:
448         *endianness = 1;
449         *fmt = AUD_FMT_S16;
450         break;
451 
452     case SND_PCM_FORMAT_U16_BE:
453         *endianness = 1;
454         *fmt = AUD_FMT_U16;
455         break;
456 
457     case SND_PCM_FORMAT_S32_LE:
458         *endianness = 0;
459         *fmt = AUD_FMT_S32;
460         break;
461 
462     case SND_PCM_FORMAT_U32_LE:
463         *endianness = 0;
464         *fmt = AUD_FMT_U32;
465         break;
466 
467     case SND_PCM_FORMAT_S32_BE:
468         *endianness = 1;
469         *fmt = AUD_FMT_S32;
470         break;
471 
472     case SND_PCM_FORMAT_U32_BE:
473         *endianness = 1;
474         *fmt = AUD_FMT_U32;
475         break;
476 
477     default:
478         dolog ("Unrecognized audio format %d\n", alsafmt);
479         return -1;
480     }
481 
482     return 0;
483 }
484 
alsa_dump_info(struct alsa_params_req * req,struct alsa_params_obt * obt,snd_pcm_format_t obtfmt)485 static void alsa_dump_info (struct alsa_params_req *req,
486                             struct alsa_params_obt *obt,
487                             snd_pcm_format_t obtfmt)
488 {
489     dolog ("parameter | requested value | obtained value\n");
490     dolog ("format    |      %10d |     %10d\n", req->fmt, obtfmt);
491     dolog ("channels  |      %10d |     %10d\n",
492            req->nchannels, obt->nchannels);
493     dolog ("frequency |      %10d |     %10d\n", req->freq, obt->freq);
494     dolog ("============================================\n");
495     dolog ("requested: buffer size %d period size %d\n",
496            req->buffer_size, req->period_size);
497     dolog ("obtained: samples %ld\n", obt->samples);
498 }
499 
alsa_set_threshold(snd_pcm_t * handle,snd_pcm_uframes_t threshold)500 static void alsa_set_threshold (snd_pcm_t *handle, snd_pcm_uframes_t threshold)
501 {
502     int err;
503     snd_pcm_sw_params_t *sw_params;
504 
505     FF_snd_pcm_sw_params_alloca (&sw_params);
506 
507     err = FF(snd_pcm_sw_params_current) (handle, sw_params);
508     if (err < 0) {
509         dolog ("Could not fully initialize DAC\n");
510         alsa_logerr (err, "Failed to get current software parameters\n");
511         return;
512     }
513 
514     err = FF(snd_pcm_sw_params_set_start_threshold) (handle, sw_params, threshold);
515     if (err < 0) {
516         dolog ("Could not fully initialize DAC\n");
517         alsa_logerr (err, "Failed to set software threshold to %ld\n",
518                      threshold);
519         return;
520     }
521 
522     err = FF(snd_pcm_sw_params) (handle, sw_params);
523     if (err < 0) {
524         dolog ("Could not fully initialize DAC\n");
525         alsa_logerr (err, "Failed to set software parameters\n");
526         return;
527     }
528 }
529 
alsa_open(int in,struct alsa_params_req * req,struct alsa_params_obt * obt,snd_pcm_t ** handlep)530 static int alsa_open (int in, struct alsa_params_req *req,
531                       struct alsa_params_obt *obt, snd_pcm_t **handlep)
532 {
533     snd_pcm_t *handle;
534     snd_pcm_hw_params_t *hw_params;
535     int err;
536     int size_in_usec;
537     unsigned int freq, nchannels;
538     const char *pcm_name = in ? conf.pcm_name_in : conf.pcm_name_out;
539     snd_pcm_uframes_t obt_buffer_size;
540     const char *typ = in ? "ADC" : "DAC";
541     snd_pcm_format_t obtfmt;
542 
543     freq = req->freq;
544     nchannels = req->nchannels;
545     size_in_usec = req->size_in_usec;
546 
547     FF_snd_pcm_hw_params_alloca (&hw_params);
548 
549     err = FF(snd_pcm_open) (
550         &handle,
551         pcm_name,
552         in ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
553         SND_PCM_NONBLOCK
554         );
555     if (err < 0) {
556         alsa_logerr2 (err, typ, "Failed to open `%s':\n", pcm_name);
557         return -1;
558     }
559 
560     err = FF(snd_pcm_hw_params_any) (handle, hw_params);
561     if (err < 0) {
562         alsa_logerr2 (err, typ, "Failed to initialize hardware parameters\n");
563         goto err;
564     }
565 
566     err = FF(snd_pcm_hw_params_set_access) (
567         handle,
568         hw_params,
569         SND_PCM_ACCESS_RW_INTERLEAVED
570         );
571     if (err < 0) {
572         alsa_logerr2 (err, typ, "Failed to set access type\n");
573         goto err;
574     }
575 
576     err = FF(snd_pcm_hw_params_set_format) (handle, hw_params, req->fmt);
577     if (err < 0 && conf.verbose) {
578         alsa_logerr2 (err, typ, "Failed to set format %d\n", req->fmt);
579         goto err;
580     }
581 
582     err = FF(snd_pcm_hw_params_set_rate_near) (handle, hw_params, &freq, 0);
583     if (err < 0) {
584         alsa_logerr2 (err, typ, "Failed to set frequency %d\n", req->freq);
585         goto err;
586     }
587 
588     err = FF(snd_pcm_hw_params_set_channels_near) (
589         handle,
590         hw_params,
591         &nchannels
592         );
593     if (err < 0) {
594         alsa_logerr2 (err, typ, "Failed to set number of channels %d\n",
595                       req->nchannels);
596         goto err;
597     }
598 
599     if (nchannels != 1 && nchannels != 2) {
600         alsa_logerr2 (err, typ,
601                       "Can not handle obtained number of channels %d\n",
602                       nchannels);
603         goto err;
604     }
605 
606     if (req->buffer_size) {
607         unsigned long obt;
608 
609         if (size_in_usec) {
610             int dir = 0;
611             unsigned int btime = req->buffer_size;
612 
613             err = FF(snd_pcm_hw_params_set_buffer_time_near) (
614                 handle,
615                 hw_params,
616                 &btime,
617                 &dir
618                 );
619             obt = btime;
620         }
621         else {
622             snd_pcm_uframes_t bsize = req->buffer_size;
623 
624             err = FF(snd_pcm_hw_params_set_buffer_size_near) (
625                 handle,
626                 hw_params,
627                 &bsize
628                 );
629             obt = bsize;
630         }
631         if (err < 0) {
632             alsa_logerr2 (err, typ, "Failed to set buffer %s to %d\n",
633                           size_in_usec ? "time" : "size", req->buffer_size);
634             goto err;
635         }
636 
637         if ((req->override_mask & 2) && (obt - req->buffer_size))
638             dolog ("Requested buffer %s %u was rejected, using %lu\n",
639                    size_in_usec ? "time" : "size", req->buffer_size, obt);
640     }
641 
642     if (req->period_size) {
643         unsigned long obt;
644 
645         if (size_in_usec) {
646             int dir = 0;
647             unsigned int ptime = req->period_size;
648 
649             err = FF(snd_pcm_hw_params_set_period_time_near) (
650                 handle,
651                 hw_params,
652                 &ptime,
653                 &dir
654                 );
655             obt = ptime;
656         }
657         else {
658             int dir = 0;
659             snd_pcm_uframes_t psize = req->period_size;
660 
661             err = FF(snd_pcm_hw_params_set_period_size_near) (
662                 handle,
663                 hw_params,
664                 &psize,
665                 &dir
666                 );
667             obt = psize;
668         }
669 
670         if (err < 0) {
671             alsa_logerr2 (err, typ, "Failed to set period %s to %d\n",
672                           size_in_usec ? "time" : "size", req->period_size);
673             goto err;
674         }
675 
676         if (((req->override_mask & 1) && (obt - req->period_size)))
677             dolog ("Requested period %s %u was rejected, using %lu\n",
678                    size_in_usec ? "time" : "size", req->period_size, obt);
679     }
680 
681     err = FF(snd_pcm_hw_params) (handle, hw_params);
682     if (err < 0) {
683         alsa_logerr2 (err, typ, "Failed to apply audio parameters\n");
684         goto err;
685     }
686 
687     err = FF(snd_pcm_hw_params_get_buffer_size) (hw_params, &obt_buffer_size);
688     if (err < 0) {
689         alsa_logerr2 (err, typ, "Failed to get buffer size\n");
690         goto err;
691     }
692 
693     err = FF(snd_pcm_hw_params_get_format) (hw_params, &obtfmt);
694     if (err < 0) {
695         alsa_logerr2 (err, typ, "Failed to get format\n");
696         goto err;
697     }
698 
699     if (alsa_to_audfmt (obtfmt, &obt->fmt, &obt->endianness)) {
700         dolog ("Invalid format was returned %d\n", obtfmt);
701         goto err;
702     }
703 
704     err = FF(snd_pcm_prepare) (handle);
705     if (err < 0) {
706         alsa_logerr2 (err, typ, "Could not prepare handle %p\n", handle);
707         goto err;
708     }
709 
710     if (!in && conf.threshold) {
711         snd_pcm_uframes_t threshold;
712         int bytes_per_sec;
713 
714         bytes_per_sec = freq << (nchannels == 2);
715 
716         switch (obt->fmt) {
717         case AUD_FMT_S8:
718         case AUD_FMT_U8:
719             break;
720 
721         case AUD_FMT_S16:
722         case AUD_FMT_U16:
723             bytes_per_sec <<= 1;
724             break;
725 
726         case AUD_FMT_S32:
727         case AUD_FMT_U32:
728             bytes_per_sec <<= 2;
729             break;
730         }
731 
732         threshold = (conf.threshold * bytes_per_sec) / 1000;
733         alsa_set_threshold (handle, threshold);
734     }
735 
736     obt->nchannels = nchannels;
737     obt->freq = freq;
738     obt->samples = obt_buffer_size;
739 
740     *handlep = handle;
741 
742     if (conf.verbose &&
743         (obtfmt != req->fmt ||
744          obt->nchannels != req->nchannels ||
745          obt->freq != req->freq)) {
746         dolog ("Audio parameters for %s\n", typ);
747         alsa_dump_info (req, obt, obtfmt);
748     }
749 
750 #ifdef DEBUG
751     alsa_dump_info (req, obt, obtfmt);
752 #endif
753     return 0;
754 
755  err:
756     alsa_anal_close1 (&handle);
757     return -1;
758 }
759 
alsa_get_avail(snd_pcm_t * handle)760 static snd_pcm_sframes_t alsa_get_avail (snd_pcm_t *handle)
761 {
762     snd_pcm_sframes_t avail;
763 
764     avail = FF(snd_pcm_avail_update) (handle);
765     if (avail < 0) {
766         if (avail == -EPIPE) {
767             if (!alsa_recover (handle)) {
768                 avail = FF(snd_pcm_avail_update) (handle);
769             }
770         }
771 
772         if (avail < 0) {
773             alsa_logerr (avail,
774                          "Could not obtain number of available frames\n");
775             return -1;
776         }
777     }
778 
779     return avail;
780 }
781 
alsa_write_pending(ALSAVoiceOut * alsa)782 static void alsa_write_pending (ALSAVoiceOut *alsa)
783 {
784     HWVoiceOut *hw = &alsa->hw;
785 
786     while (alsa->pending) {
787         int left_till_end_samples = hw->samples - alsa->wpos;
788         int len = audio_MIN (alsa->pending, left_till_end_samples);
789         char *src = advance (alsa->pcm_buf, alsa->wpos << hw->info.shift);
790 
791         while (len) {
792             snd_pcm_sframes_t written;
793 
794             written = FF(snd_pcm_writei) (alsa->handle, src, len);
795 
796             if (written <= 0) {
797                 switch (written) {
798                 case 0:
799                     if (conf.verbose) {
800                         dolog ("Failed to write %d frames (wrote zero)\n", len);
801                     }
802                     return;
803 
804                 case -EPIPE:
805                     if (alsa_recover (alsa->handle)) {
806                         alsa_logerr (written, "Failed to write %d frames\n",
807                                      len);
808                         return;
809                     }
810                     if (conf.verbose) {
811                         dolog ("Recovering from playback xrun\n");
812                     }
813                     continue;
814 
815                 case -ESTRPIPE:
816                     /* stream is suspended and waiting for an
817                        application recovery */
818                     if (alsa_resume (alsa->handle)) {
819                         alsa_logerr (written, "Failed to write %d frames\n",
820                                      len);
821                         return;
822                     }
823                     if (conf.verbose) {
824                         dolog ("Resuming suspended output stream\n");
825                     }
826                     continue;
827 
828                 case -EAGAIN:
829                     return;
830 
831                 default:
832                     alsa_logerr (written, "Failed to write %d frames from %p\n",
833                                  len, src);
834                     return;
835                 }
836             }
837 
838             alsa->wpos = (alsa->wpos + written) % hw->samples;
839             alsa->pending -= written;
840             len -= written;
841         }
842     }
843 }
844 
alsa_run_out(HWVoiceOut * hw,int live)845 static int alsa_run_out (HWVoiceOut *hw, int live)
846 {
847     ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
848     int decr;
849     snd_pcm_sframes_t avail;
850 
851     avail = alsa_get_avail (alsa->handle);
852     if (avail < 0) {
853         dolog ("Could not get number of available playback frames\n");
854         return 0;
855     }
856 
857     decr = audio_MIN (live, avail);
858     decr = audio_pcm_hw_clip_out (hw, alsa->pcm_buf, decr, alsa->pending);
859     alsa->pending += decr;
860     alsa_write_pending (alsa);
861     return decr;
862 }
863 
alsa_fini_out(HWVoiceOut * hw)864 static void alsa_fini_out (HWVoiceOut *hw)
865 {
866     ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
867 
868     ldebug ("alsa_fini\n");
869     alsa_anal_close (&alsa->handle, &alsa->pollhlp);
870 
871     if (alsa->pcm_buf) {
872         g_free (alsa->pcm_buf);
873         alsa->pcm_buf = NULL;
874     }
875 }
876 
alsa_init_out(HWVoiceOut * hw,struct audsettings * as)877 static int alsa_init_out (HWVoiceOut *hw, struct audsettings *as)
878 {
879     ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
880     struct alsa_params_req req;
881     struct alsa_params_obt obt;
882     snd_pcm_t *handle;
883     struct audsettings obt_as;
884     int  result = -1;
885 
886     /* shut alsa debug spew */
887     if (!D_ACTIVE)
888         stdio_disable();
889 
890     req.fmt = aud_to_alsafmt (as->fmt);
891     req.freq = as->freq;
892     req.nchannels = as->nchannels;
893     req.period_size = conf.period_size_out;
894     req.buffer_size = conf.buffer_size_out;
895     req.size_in_usec = conf.size_in_usec_out;
896     req.override_mask =
897         (conf.period_size_out_overridden ? 1 : 0) |
898         (conf.buffer_size_out_overridden ? 2 : 0);
899 
900     if (alsa_open (0, &req, &obt, &handle)) {
901         goto Exit;
902     }
903 
904     obt_as.freq = obt.freq;
905     obt_as.nchannels = obt.nchannels;
906     obt_as.fmt = obt.fmt;
907     obt_as.endianness = obt.endianness;
908 
909     audio_pcm_init_info (&hw->info, &obt_as);
910     hw->samples = obt.samples;
911 
912     alsa->pcm_buf = audio_calloc (AUDIO_FUNC, obt.samples, 1 << hw->info.shift);
913     if (!alsa->pcm_buf) {
914         dolog ("Could not allocate DAC buffer (%d samples, each %d bytes)\n",
915                hw->samples, 1 << hw->info.shift);
916         alsa_anal_close1 (&handle);
917         goto Exit;
918     }
919 
920     alsa->handle = handle;
921     result       = 0;  /* success */
922 
923 Exit:
924     if (!D_ACTIVE)
925         stdio_enable();
926 
927     return result;
928 }
929 
alsa_voice_ctl(snd_pcm_t * handle,const char * typ,int pause)930 static int alsa_voice_ctl (snd_pcm_t *handle, const char *typ, int pause)
931 {
932     int err;
933 
934     if (pause) {
935         err = FF(snd_pcm_drop) (handle);
936         if (err < 0) {
937             alsa_logerr (err, "Could not stop %s\n", typ);
938             return -1;
939         }
940     }
941     else {
942         err = FF(snd_pcm_prepare) (handle);
943         if (err < 0) {
944             alsa_logerr (err, "Could not prepare handle for %s\n", typ);
945             return -1;
946         }
947     }
948 
949     return 0;
950 }
951 
alsa_ctl_out(HWVoiceOut * hw,int cmd,...)952 static int alsa_ctl_out (HWVoiceOut *hw, int cmd, ...)
953 {
954     ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
955 
956     switch (cmd) {
957     case VOICE_ENABLE:
958         {
959             va_list ap;
960             int poll_mode;
961 
962             va_start (ap, cmd);
963             poll_mode = va_arg (ap, int);
964             va_end (ap);
965 
966             ldebug ("enabling voice\n");
967             if (poll_mode && alsa_poll_out (hw)) {
968                 poll_mode = 0;
969             }
970             hw->poll_mode = poll_mode;
971             return alsa_voice_ctl (alsa->handle, "playback", 0);
972         }
973 
974     case VOICE_DISABLE:
975         ldebug ("disabling voice\n");
976         return alsa_voice_ctl (alsa->handle, "playback", 1);
977     }
978 
979     return -1;
980 }
981 
alsa_init_in(HWVoiceIn * hw,struct audsettings * as)982 static int alsa_init_in (HWVoiceIn *hw, struct audsettings *as)
983 {
984     ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
985     struct alsa_params_req req;
986     struct alsa_params_obt obt;
987     snd_pcm_t *handle;
988     struct audsettings obt_as;
989     int result = -1;
990 
991     /* shut alsa debug spew */
992     if (!D_ACTIVE)
993         stdio_disable();
994 
995     req.fmt = aud_to_alsafmt (as->fmt);
996     req.freq = as->freq;
997     req.nchannels = as->nchannels;
998     req.period_size = conf.period_size_in;
999     req.buffer_size = conf.buffer_size_in;
1000     req.size_in_usec = conf.size_in_usec_in;
1001     req.override_mask =
1002         (conf.period_size_in_overridden ? 1 : 0) |
1003         (conf.buffer_size_in_overridden ? 2 : 0);
1004 
1005     if (alsa_open (1, &req, &obt, &handle)) {
1006         goto Exit;
1007     }
1008 
1009     obt_as.freq = obt.freq;
1010     obt_as.nchannels = obt.nchannels;
1011     obt_as.fmt = obt.fmt;
1012     obt_as.endianness = obt.endianness;
1013 
1014     audio_pcm_init_info (&hw->info, &obt_as);
1015     hw->samples = obt.samples;
1016 
1017     alsa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
1018     if (!alsa->pcm_buf) {
1019         dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
1020                hw->samples, 1 << hw->info.shift);
1021         alsa_anal_close1 (&handle);
1022         goto Exit;
1023     }
1024 
1025     alsa->handle = handle;
1026     result       = 0;  /* success */
1027 
1028 Exit:
1029     if (!D_ACTIVE)
1030         stdio_enable();
1031 
1032     return result;
1033 }
1034 
alsa_fini_in(HWVoiceIn * hw)1035 static void alsa_fini_in (HWVoiceIn *hw)
1036 {
1037     ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
1038 
1039     alsa_anal_close (&alsa->handle, &alsa->pollhlp);
1040 
1041     if (alsa->pcm_buf) {
1042         g_free (alsa->pcm_buf);
1043         alsa->pcm_buf = NULL;
1044     }
1045 }
1046 
alsa_run_in(HWVoiceIn * hw)1047 static int alsa_run_in (HWVoiceIn *hw)
1048 {
1049     ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
1050     int hwshift = hw->info.shift;
1051     int i;
1052     int live = audio_pcm_hw_get_live_in (hw);
1053     int dead = hw->samples - live;
1054     int decr;
1055     struct {
1056         int add;
1057         int len;
1058     } bufs[2] = {
1059         { .add = hw->wpos, .len = 0 },
1060         { .add = 0,        .len = 0 }
1061     };
1062     snd_pcm_sframes_t avail;
1063     snd_pcm_uframes_t read_samples = 0;
1064 
1065     if (!dead) {
1066         return 0;
1067     }
1068 
1069     avail = alsa_get_avail (alsa->handle);
1070     if (avail < 0) {
1071         dolog ("Could not get number of captured frames\n");
1072         return 0;
1073     }
1074 
1075     if (!avail) {
1076         snd_pcm_state_t state;
1077 
1078         state = FF(snd_pcm_state) (alsa->handle);
1079         switch (state) {
1080         case SND_PCM_STATE_PREPARED:
1081             avail = hw->samples;
1082             break;
1083         case SND_PCM_STATE_SUSPENDED:
1084             /* stream is suspended and waiting for an application recovery */
1085             if (alsa_resume (alsa->handle)) {
1086                 dolog ("Failed to resume suspended input stream\n");
1087                 return 0;
1088             }
1089             if (conf.verbose) {
1090                 dolog ("Resuming suspended input stream\n");
1091             }
1092             break;
1093         default:
1094             if (conf.verbose) {
1095                 dolog ("No frames available and ALSA state is %d\n", state);
1096             }
1097             return 0;
1098         }
1099     }
1100 
1101     decr = audio_MIN (dead, avail);
1102     if (!decr) {
1103         return 0;
1104     }
1105 
1106     if (hw->wpos + decr > hw->samples) {
1107         bufs[0].len = (hw->samples - hw->wpos);
1108         bufs[1].len = (decr - (hw->samples - hw->wpos));
1109     }
1110     else {
1111         bufs[0].len = decr;
1112     }
1113 
1114     for (i = 0; i < 2; ++i) {
1115         void *src;
1116         struct st_sample *dst;
1117         snd_pcm_sframes_t nread;
1118         snd_pcm_uframes_t len;
1119 
1120         len = bufs[i].len;
1121 
1122         src = advance (alsa->pcm_buf, bufs[i].add << hwshift);
1123         dst = hw->conv_buf + bufs[i].add;
1124 
1125         while (len) {
1126             nread = FF(snd_pcm_readi) (alsa->handle, src, len);
1127 
1128             if (nread <= 0) {
1129                 switch (nread) {
1130                 case 0:
1131                     if (conf.verbose) {
1132                         dolog ("Failed to read %ld frames (read zero)\n", len);
1133                     }
1134                     goto exit;
1135 
1136                 case -EPIPE:
1137                     if (alsa_recover (alsa->handle)) {
1138                         alsa_logerr (nread, "Failed to read %ld frames\n", len);
1139                         goto exit;
1140                     }
1141                     if (conf.verbose) {
1142                         dolog ("Recovering from capture xrun\n");
1143                     }
1144                     continue;
1145 
1146                 case -EAGAIN:
1147                     goto exit;
1148 
1149                 default:
1150                     alsa_logerr (
1151                         nread,
1152                         "Failed to read %ld frames from %p\n",
1153                         len,
1154                         src
1155                         );
1156                     goto exit;
1157                 }
1158             }
1159 
1160             hw->conv (dst, src, nread, &nominal_volume);
1161 
1162             src = advance (src, nread << hwshift);
1163             dst += nread;
1164 
1165             read_samples += nread;
1166             len -= nread;
1167         }
1168     }
1169 
1170  exit:
1171     hw->wpos = (hw->wpos + read_samples) % hw->samples;
1172     return read_samples;
1173 }
1174 
alsa_read(SWVoiceIn * sw,void * buf,int size)1175 static int alsa_read (SWVoiceIn *sw, void *buf, int size)
1176 {
1177     return audio_pcm_sw_read (sw, buf, size);
1178 }
1179 
alsa_ctl_in(HWVoiceIn * hw,int cmd,...)1180 static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...)
1181 {
1182     ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
1183 
1184     switch (cmd) {
1185     case VOICE_ENABLE:
1186         {
1187             va_list ap;
1188             int poll_mode;
1189 
1190             va_start (ap, cmd);
1191             poll_mode = va_arg (ap, int);
1192             va_end (ap);
1193 
1194             ldebug ("enabling voice\n");
1195             if (poll_mode && alsa_poll_in (hw)) {
1196                 poll_mode = 0;
1197             }
1198             hw->poll_mode = poll_mode;
1199 
1200             return alsa_voice_ctl (alsa->handle, "capture", 0);
1201         }
1202 
1203     case VOICE_DISABLE:
1204         ldebug ("disabling voice\n");
1205         if (hw->poll_mode) {
1206             hw->poll_mode = 0;
1207             alsa_fini_poll (&alsa->pollhlp);
1208         }
1209         return alsa_voice_ctl (alsa->handle, "capture", 1);
1210     }
1211 
1212     return -1;
1213 }
1214 
alsa_audio_init(void)1215 static void *alsa_audio_init (void)
1216 {
1217     void*    result = NULL;
1218 
1219     alsa_lib = dlopen( "libasound.so", RTLD_NOW );
1220     if (alsa_lib == NULL)
1221         alsa_lib = dlopen( "libasound.so.2", RTLD_NOW );
1222 
1223     if (alsa_lib == NULL) {
1224         ldebug("could not find libasound on this system\n");
1225         goto Exit;
1226     }
1227 
1228     if (alsa_dynlink_init(alsa_lib) < 0)
1229         goto Fail;
1230 
1231     result = &conf;
1232     goto Exit;
1233 
1234 Fail:
1235     ldebug("%s: failed to open library\n", __FUNCTION__);
1236     dlclose(alsa_lib);
1237 
1238 Exit:
1239     return result;
1240 }
1241 
alsa_audio_fini(void * opaque)1242 static void alsa_audio_fini (void *opaque)
1243 {
1244     if (alsa_lib != NULL) {
1245         dlclose(alsa_lib);
1246         alsa_lib = NULL;
1247     }
1248     (void) opaque;
1249 }
1250 
1251 static struct audio_option alsa_options[] = {
1252     {
1253         .name        = "DAC_SIZE_IN_USEC",
1254         .tag         = AUD_OPT_BOOL,
1255         .valp        = &conf.size_in_usec_out,
1256         .descr       = "DAC period/buffer size in microseconds (otherwise in frames)"
1257     },
1258     {
1259         .name        = "DAC_PERIOD_SIZE",
1260         .tag         = AUD_OPT_INT,
1261         .valp        = &conf.period_size_out,
1262         .descr       = "DAC period size (0 to go with system default)",
1263         .overriddenp = &conf.period_size_out_overridden
1264     },
1265     {
1266         .name        = "DAC_BUFFER_SIZE",
1267         .tag         = AUD_OPT_INT,
1268         .valp        = &conf.buffer_size_out,
1269         .descr       = "DAC buffer size (0 to go with system default)",
1270         .overriddenp = &conf.buffer_size_out_overridden
1271     },
1272     {
1273         .name        = "ADC_SIZE_IN_USEC",
1274         .tag         = AUD_OPT_BOOL,
1275         .valp        = &conf.size_in_usec_in,
1276         .descr       =
1277         "ADC period/buffer size in microseconds (otherwise in frames)"
1278     },
1279     {
1280         .name        = "ADC_PERIOD_SIZE",
1281         .tag         = AUD_OPT_INT,
1282         .valp        = &conf.period_size_in,
1283         .descr       = "ADC period size (0 to go with system default)",
1284         .overriddenp = &conf.period_size_in_overridden
1285     },
1286     {
1287         .name        = "ADC_BUFFER_SIZE",
1288         .tag         = AUD_OPT_INT,
1289         .valp        = &conf.buffer_size_in,
1290         .descr       = "ADC buffer size (0 to go with system default)",
1291         .overriddenp = &conf.buffer_size_in_overridden
1292     },
1293     {
1294         .name        = "THRESHOLD",
1295         .tag         = AUD_OPT_INT,
1296         .valp        = &conf.threshold,
1297         .descr       = "(undocumented)"
1298     },
1299     {
1300         .name        = "DAC_DEV",
1301         .tag         = AUD_OPT_STR,
1302         .valp        = &conf.pcm_name_out,
1303         .descr       = "DAC device name (for instance dmix)"
1304     },
1305     {
1306         .name        = "ADC_DEV",
1307         .tag         = AUD_OPT_STR,
1308         .valp        = &conf.pcm_name_in,
1309         .descr       = "ADC device name"
1310     },
1311     {
1312         .name        = "VERBOSE",
1313         .tag         = AUD_OPT_BOOL,
1314         .valp        = &conf.verbose,
1315         .descr       = "Behave in a more verbose way"
1316     },
1317     { /* End of list */ }
1318 };
1319 
1320 static struct audio_pcm_ops alsa_pcm_ops = {
1321     .init_out = alsa_init_out,
1322     .fini_out = alsa_fini_out,
1323     .run_out  = alsa_run_out,
1324     .write    = alsa_write,
1325     .ctl_out  = alsa_ctl_out,
1326 
1327     .init_in  = alsa_init_in,
1328     .fini_in  = alsa_fini_in,
1329     .run_in   = alsa_run_in,
1330     .read     = alsa_read,
1331     .ctl_in   = alsa_ctl_in,
1332 };
1333 
1334 struct audio_driver alsa_audio_driver = {
1335     .name           = "alsa",
1336     .descr          = "ALSA http://www.alsa-project.org",
1337     .options        = alsa_options,
1338     .init           = alsa_audio_init,
1339     .fini           = alsa_audio_fini,
1340     .pcm_ops        = &alsa_pcm_ops,
1341     .can_be_default = 1,
1342     .max_voices_out = INT_MAX,
1343     .max_voices_in  = INT_MAX,
1344     .voice_size_out = sizeof (ALSAVoiceOut),
1345     .voice_size_in  = sizeof (ALSAVoiceIn)
1346 };
1347