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