VirtualBox

source: vbox/trunk/src/VBox/Devices/Audio/alsaaudio.c@ 5116

Last change on this file since 5116 was 5077, checked in by vboxsync, 17 years ago

...and added code to load libasound.so.2 dynamically instead

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 29.7 KB
Line 
1/*
2 * QEMU ALSA audio driver
3 *
4 * Copyright (c) 2005 Vassili Karpov (malc)
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24#ifdef VBOX
25#ifndef DEBUG
26#define NDEBUG
27#endif
28#define LOG_GROUP LOG_GROUP_DEV_AUDIO
29#include <VBox/log.h>
30#endif
31
32#include <alsa/asoundlib.h>
33
34#include "Builtins.h"
35#include "../../vl_vbox.h"
36#include "audio.h"
37#ifdef VBOX
38#include "alsa_stubs.h"
39#endif
40#include <iprt/alloc.h>
41
42#define AUDIO_CAP "alsa"
43#include "audio_int.h"
44
45typedef struct ALSAVoiceOut {
46 HWVoiceOut hw;
47 void *pcm_buf;
48 snd_pcm_t *handle;
49} ALSAVoiceOut;
50
51typedef struct ALSAVoiceIn {
52 HWVoiceIn hw;
53 snd_pcm_t *handle;
54 void *pcm_buf;
55} ALSAVoiceIn;
56
57/* latency = period_size * periods / (rate * bytes_per_frame) */
58
59static struct {
60 int size_in_usec_in;
61 int size_in_usec_out;
62 const char *pcm_name_in;
63 const char *pcm_name_out;
64 unsigned int buffer_size_in;
65 unsigned int period_size_in;
66 unsigned int buffer_size_out;
67 unsigned int period_size_out;
68 unsigned int threshold;
69
70 int buffer_size_in_overriden;
71 int period_size_in_overriden;
72
73 int buffer_size_out_overriden;
74 int period_size_out_overriden;
75 int verbose;
76} conf = {
77#ifdef HIGH_LATENCY
78 INIT_FIELD (.size_in_usec_in =) 1,
79 INIT_FIELD (.size_in_usec_out =) 1,
80#else
81 INIT_FIELD (.size_in_usec_in =) 0,
82 INIT_FIELD (.size_in_usec_out =) 0,
83#endif
84 INIT_FIELD (.pcm_name_out =) "default",
85 INIT_FIELD (.pcm_name_in =) "default",
86#ifdef HIGH_LATENCY
87 INIT_FIELD (.buffer_size_in =) 400000,
88 INIT_FIELD (.period_size_in =) 400000 / 4,
89 INIT_FIELD (.buffer_size_out =) 400000,
90 INIT_FIELD (.period_size_out =) 400000 / 4,
91#else
92#define DEFAULT_BUFFER_SIZE 1024
93#define DEFAULT_PERIOD_SIZE 256
94 INIT_FIELD (.buffer_size_in =) DEFAULT_BUFFER_SIZE * 4,
95 INIT_FIELD (.period_size_in =) DEFAULT_PERIOD_SIZE * 4,
96 INIT_FIELD (.buffer_size_out =) DEFAULT_BUFFER_SIZE,
97 INIT_FIELD (.period_size_out =) DEFAULT_PERIOD_SIZE,
98#endif
99 INIT_FIELD (.threshold =) 0,
100 INIT_FIELD (.buffer_size_in_overriden =) 0,
101 INIT_FIELD (.period_size_in_overriden =) 0,
102 INIT_FIELD (.buffer_size_out_overriden =) 0,
103 INIT_FIELD (.period_size_out_overriden =) 0,
104 INIT_FIELD (.verbose =) 0
105};
106
107struct alsa_params_req {
108 int freq;
109 audfmt_e fmt;
110 int nchannels;
111 unsigned long buffer_size;
112 unsigned long period_size;
113};
114
115struct alsa_params_obt {
116 int freq;
117 audfmt_e fmt;
118 int nchannels;
119 snd_pcm_uframes_t samples;
120};
121
122static void GCC_FMT_ATTR (2, 3) alsa_logerr (int err, const char *fmt, ...)
123{
124 va_list ap;
125
126 va_start (ap, fmt);
127 AUD_vlog (AUDIO_CAP, fmt, ap);
128 va_end (ap);
129
130 AUD_log (AUDIO_CAP, "Reason: %s\n", snd_strerror (err));
131}
132
133static void GCC_FMT_ATTR (3, 4) alsa_logerr2 (
134 int err,
135 const char *typ,
136 const char *fmt,
137 ...
138 )
139{
140 va_list ap;
141
142 AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
143
144 va_start (ap, fmt);
145 AUD_vlog (AUDIO_CAP, fmt, ap);
146 va_end (ap);
147
148 AUD_log (AUDIO_CAP, "Reason: %s\n", snd_strerror (err));
149}
150
151static void alsa_anal_close (snd_pcm_t **handlep)
152{
153 int err = snd_pcm_close (*handlep);
154 if (err) {
155 alsa_logerr (err, "Failed to close PCM handle %p\n",
156 (void *) *handlep);
157 }
158 *handlep = NULL;
159}
160
161static int alsa_write (SWVoiceOut *sw, void *buf, int len)
162{
163 return audio_pcm_sw_write (sw, buf, len);
164}
165
166static int aud_to_alsafmt (audfmt_e fmt)
167{
168 switch (fmt) {
169 case AUD_FMT_S8:
170 return SND_PCM_FORMAT_S8;
171
172 case AUD_FMT_U8:
173 return SND_PCM_FORMAT_U8;
174
175 case AUD_FMT_S16:
176 return SND_PCM_FORMAT_S16_LE;
177
178 case AUD_FMT_U16:
179 return SND_PCM_FORMAT_U16_LE;
180
181 default:
182 dolog ("Internal logic error: Bad audio format %d\n", fmt);
183#ifdef DEBUG_AUDIO
184 abort ();
185#endif
186 return SND_PCM_FORMAT_U8;
187 }
188}
189
190static int alsa_to_audfmt (int alsafmt, audfmt_e *fmt, int *endianness)
191{
192 switch (alsafmt) {
193 case SND_PCM_FORMAT_S8:
194 *endianness = 0;
195 *fmt = AUD_FMT_S8;
196 break;
197
198 case SND_PCM_FORMAT_U8:
199 *endianness = 0;
200 *fmt = AUD_FMT_U8;
201 break;
202
203 case SND_PCM_FORMAT_S16_LE:
204 *endianness = 0;
205 *fmt = AUD_FMT_S16;
206 break;
207
208 case SND_PCM_FORMAT_U16_LE:
209 *endianness = 0;
210 *fmt = AUD_FMT_U16;
211 break;
212
213 case SND_PCM_FORMAT_S16_BE:
214 *endianness = 1;
215 *fmt = AUD_FMT_S16;
216 break;
217
218 case SND_PCM_FORMAT_U16_BE:
219 *endianness = 1;
220 *fmt = AUD_FMT_U16;
221 break;
222
223 default:
224 dolog ("Unrecognized audio format %d\n", alsafmt);
225 return -1;
226 }
227
228 return 0;
229}
230
231#if defined DEBUG_MISMATCHES || defined DEBUG
232static void alsa_dump_info (struct alsa_params_req *req,
233 struct alsa_params_obt *obt)
234{
235 dolog ("parameter | requested value | obtained value\n");
236 dolog ("format | %10d | %10d\n", req->fmt, obt->fmt);
237 dolog ("channels | %10d | %10d\n",
238 req->nchannels, obt->nchannels);
239 dolog ("frequency | %10d | %10d\n", req->freq, obt->freq);
240 dolog ("============================================\n");
241 dolog ("requested: buffer size %d period size %d\n",
242 req->buffer_size, req->period_size);
243 dolog ("obtained: samples %ld\n", obt->samples);
244}
245#endif
246
247static void alsa_set_threshold (snd_pcm_t *handle, snd_pcm_uframes_t threshold)
248{
249 int err;
250 snd_pcm_sw_params_t *sw_params;
251
252 snd_pcm_sw_params_alloca (&sw_params);
253
254 err = snd_pcm_sw_params_current (handle, sw_params);
255 if (err < 0) {
256 dolog ("Could not fully initialize DAC\n");
257 alsa_logerr (err, "Failed to get current software parameters\n");
258 return;
259 }
260
261 err = snd_pcm_sw_params_set_start_threshold (handle, sw_params, threshold);
262 if (err < 0) {
263 dolog ("Could not fully initialize DAC\n");
264 alsa_logerr (err, "Failed to set software threshold to %ld\n",
265 threshold);
266 return;
267 }
268
269 err = snd_pcm_sw_params (handle, sw_params);
270 if (err < 0) {
271 dolog ("Could not fully initialize DAC\n");
272 alsa_logerr (err, "Failed to set software parameters\n");
273 return;
274 }
275}
276
277static int alsa_open (int in, struct alsa_params_req *req,
278 struct alsa_params_obt *obt, snd_pcm_t **handlep)
279{
280 snd_pcm_t *handle;
281 snd_pcm_hw_params_t *hw_params;
282 int err, dir;
283 unsigned int freq, nchannels;
284 const char *pcm_name = in ? conf.pcm_name_in : conf.pcm_name_out;
285 unsigned int period_size, buffer_size;
286 snd_pcm_uframes_t period_size_f, buffer_size_f;
287 snd_pcm_uframes_t obt_buffer_size, obt_period_size;
288 const char *typ = in ? "ADC" : "DAC";
289
290 freq = req->freq;
291 period_size = req->period_size;
292 buffer_size = req->buffer_size;
293 period_size_f = (snd_pcm_uframes_t)period_size;
294 buffer_size_f = (snd_pcm_uframes_t)buffer_size;
295 nchannels = req->nchannels;
296
297 snd_pcm_hw_params_alloca (&hw_params);
298
299 err = snd_pcm_open (
300 &handle,
301 pcm_name,
302 in ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
303 SND_PCM_NONBLOCK
304 );
305 if (err < 0) {
306#ifndef VBOX
307 alsa_logerr2 (err, typ, "Failed to open `%s':\n", pcm_name);
308#else
309 LogRel(("ALSA: Failed to open '%s' as %s\n", pcm_name, typ));
310#endif
311 return -1;
312 }
313
314 err = snd_pcm_hw_params_any (handle, hw_params);
315 if (err < 0) {
316#ifndef VBOX
317 alsa_logerr2 (err, typ, "Failed to initialize hardware parameters\n");
318#else
319 LogRel(("ALSA: Failed to initialize hardware parameters\n"));
320#endif
321 goto err;
322 }
323
324 err = snd_pcm_hw_params_set_access (
325 handle,
326 hw_params,
327 SND_PCM_ACCESS_RW_INTERLEAVED
328 );
329 if (err < 0) {
330#ifndef VBOX
331 alsa_logerr2 (err, typ, "Failed to set access type\n");
332#else
333 LogRel(("ALSA: Failed to set access type\n"));
334#endif
335 goto err;
336 }
337
338 err = snd_pcm_hw_params_set_format (handle, hw_params, req->fmt);
339 if (err < 0) {
340#ifndef VBOX
341 alsa_logerr2 (err, typ, "Failed to set format %d\n", req->fmt);
342#else
343 LogRel(("ALSA: Failed to set format %d\n", req->fmt));
344#endif
345 goto err;
346 }
347
348 err = snd_pcm_hw_params_set_rate_near (handle, hw_params, &freq, 0);
349 if (err < 0) {
350#ifndef VBOX
351 alsa_logerr2 (err, typ, "Failed to set frequency %d\n", req->freq);
352#else
353 LogRel(("ALSA: Failed to set frequency %dHz\n", req->freq));
354#endif
355 goto err;
356 }
357
358 err = snd_pcm_hw_params_set_channels_near (
359 handle,
360 hw_params,
361 &nchannels
362 );
363 if (err < 0) {
364#ifndef VBOX
365 alsa_logerr2 (err, typ, "Failed to set number of channels %d\n",
366 req->nchannels);
367#else
368 LogRel(("ALSA: Failed to set number of channels to %d\n", req->nchannels));
369#endif
370 goto err;
371 }
372
373 if (nchannels != 1 && nchannels != 2) {
374#ifndef VBOX
375 alsa_logerr2 (err, typ,
376 "Can not handle obtained number of channels %d\n",
377 nchannels);
378#else
379 LogRel(("ALSA: Cannot handle obtained number of channels (%d)\n", nchannels));
380#endif
381 goto err;
382 }
383
384 if (!((in && conf.size_in_usec_in) || (!in && conf.size_in_usec_out))) {
385 if (!buffer_size) {
386 buffer_size = DEFAULT_BUFFER_SIZE;
387 period_size= DEFAULT_PERIOD_SIZE;
388 }
389 }
390
391 if (buffer_size) {
392 if ((in && conf.size_in_usec_in) || (!in && conf.size_in_usec_out)) {
393 if (period_size) {
394 err = snd_pcm_hw_params_set_period_time_near (
395 handle,
396 hw_params,
397 &period_size,
398 0
399 );
400 if (err < 0) {
401#ifndef VBOX
402 alsa_logerr2 (err, typ,
403 "Failed to set period time %d\n",
404 req->period_size);
405#else
406 LogRel(("ALSA: Failed to set period time %d\n", req->period_size));
407#endif
408 goto err;
409 }
410 }
411
412 err = snd_pcm_hw_params_set_buffer_time_near (
413 handle,
414 hw_params,
415 &buffer_size,
416 0
417 );
418
419 if (err < 0) {
420#ifndef VBOX
421 alsa_logerr2 (err, typ,
422 "Failed to set buffer time %d\n",
423 req->buffer_size);
424#else
425 LogRel(("ALSA: Failed to set buffer time %d\n", req->buffer_size));
426#endif
427 goto err;
428 }
429 }
430 else {
431 snd_pcm_uframes_t minval;
432
433 if (period_size_f) {
434 minval = period_size_f;
435 dir = 0;
436
437 err = snd_pcm_hw_params_get_period_size_min (
438 hw_params,
439 &minval,
440 &dir
441 );
442 if (err < 0) {
443#ifndef VBOX
444 alsa_logerr (
445 err,
446 "Could not get minmal period size for %s\n",
447 typ
448 );
449#else
450 LogRel(("ALSA: Could not get minimal period size for %s\n", typ));
451#endif
452 }
453 else {
454 dolog("minimal period size %ld\n", minval);
455 if (period_size_f < minval) {
456 if ((in && conf.period_size_in_overriden)
457 || (!in && conf.period_size_out_overriden)) {
458 dolog ("%s period size(%d) is less "
459 "than minmal period size(%ld)\n",
460 typ,
461 period_size_f,
462 minval);
463 }
464 period_size_f = minval;
465 }
466 }
467
468#ifndef VBOX
469 err = snd_pcm_hw_params_set_period_size (
470 handle,
471 hw_params,
472 period_size_f,
473 0
474 );
475#else
476 err = snd_pcm_hw_params_set_period_size_near (
477 handle,
478 hw_params,
479 &period_size_f,
480 0
481 );
482#endif
483 dolog("PERIOD_SIZE %d\n", period_size_f);
484 if (err < 0) {
485#ifndef VBOX
486 alsa_logerr2 (err, typ, "Failed to set period size %d\n",
487 period_size_f);
488#else
489 LogRel(("ALSA: Failed to set period size %d (%s)\n",
490 period_size_f, snd_strerror(err)));
491#endif
492 goto err;
493 }
494 }
495
496#ifdef VBOX
497 /* Calculate default buffer size here since it might have been changed
498 * in the _near functions */
499 buffer_size_f = 4 * period_size_f;
500#endif
501
502 minval = buffer_size_f;
503 err = snd_pcm_hw_params_get_buffer_size_min (
504 hw_params,
505 &minval
506 );
507 if (err < 0) {
508#ifndef VBOX
509 alsa_logerr (err, "Could not get minmal buffer size for %s\n",
510 typ);
511#else
512 LogRel(("ALSA: Could not get minimal buffer size for %s\n", typ));
513#endif
514 }
515 else {
516 if (buffer_size_f < minval) {
517 if ((in && conf.buffer_size_in_overriden)
518 || (!in && conf.buffer_size_out_overriden)) {
519 dolog (
520 "%s buffer size(%d) is less "
521 "than minimal buffer size(%ld)\n",
522 typ,
523 buffer_size_f,
524 minval
525 );
526 }
527 buffer_size_f = minval;
528 }
529 }
530
531 err = snd_pcm_hw_params_set_buffer_size_near (
532 handle,
533 hw_params,
534 &buffer_size_f
535 );
536 dolog("BUFFER_SIZE %d\n", buffer_size_f);
537 if (err < 0) {
538#ifndef VBOX
539 alsa_logerr2 (err, typ, "Failed to set buffer size %d\n",
540 buffer_size_f);
541#else
542 LogRel(("ALSA: Failed to set buffer size %d (%s)\n",
543 buffer_size_f, snd_strerror(err)));
544#endif
545 goto err;
546 }
547 }
548 }
549 else {
550 dolog ("warning: Buffer size is not set\n");
551 }
552
553 err = snd_pcm_hw_params (handle, hw_params);
554 if (err < 0) {
555#ifndef VBOX
556 alsa_logerr2 (err, typ, "Failed to apply audio parameters\n");
557#else
558 LogRel(("ALSA: Failed to apply audio parameters\n"));
559#endif
560 goto err;
561 }
562
563 err = snd_pcm_hw_params_get_buffer_size (hw_params, &obt_buffer_size);
564 if (err < 0) {
565#ifndef VBOX
566 alsa_logerr2 (err, typ, "Failed to get buffer size\n");
567#else
568 LogRel(("ALSA: Failed to get buffer size\n"));
569#endif
570 goto err;
571 }
572
573#ifdef VBOX
574 dir = 0;
575 err = snd_pcm_hw_params_get_period_size (hw_params, &obt_period_size, &dir);
576 if (err < 0)
577 {
578 LogRel(("ALSA: Failed to get period size\n"));
579 goto err;
580 }
581 LogRel(("ALSA: %s frequency %dHz, period size %ld, buffer size %ld\n",
582 typ, req->freq, obt_period_size, obt_buffer_size));
583#endif
584
585 err = snd_pcm_prepare (handle);
586 if (err < 0) {
587 alsa_logerr2 (err, typ, "Could not prepare handle %p\n",
588 (void *) handle);
589 goto err;
590 }
591
592 if (!in && conf.threshold) {
593 snd_pcm_uframes_t threshold;
594 int bytes_per_sec;
595
596 bytes_per_sec = freq
597 << (nchannels == 2)
598 << (req->fmt == AUD_FMT_S16 || req->fmt == AUD_FMT_U16);
599
600 threshold = (conf.threshold * bytes_per_sec) / 1000;
601 alsa_set_threshold (handle, threshold);
602 }
603
604 obt->fmt = req->fmt;
605 obt->nchannels = nchannels;
606 obt->freq = freq;
607 obt->samples = obt_buffer_size;
608 *handlep = handle;
609
610#if defined DEBUG_MISMATCHES || defined DEBUG
611 if (obt->fmt != req->fmt ||
612 obt->nchannels != req->nchannels ||
613 obt->freq != req->freq) {
614 dolog ("Audio paramters mismatch for %s\n", typ);
615 alsa_dump_info (req, obt);
616 }
617#endif
618
619#ifdef DEBUG
620 alsa_dump_info (req, obt);
621#endif
622 return 0;
623
624 err:
625 alsa_anal_close (&handle);
626 return -1;
627}
628
629static int alsa_recover (snd_pcm_t *handle)
630{
631 int err = snd_pcm_prepare (handle);
632 if (err < 0) {
633 alsa_logerr (err, "Failed to prepare handle %p\n",
634 (void *) handle);
635 return -1;
636 }
637 return 0;
638}
639
640static snd_pcm_sframes_t alsa_get_avail (snd_pcm_t *handle)
641{
642 snd_pcm_sframes_t avail;
643
644 avail = snd_pcm_avail_update (handle);
645 if (avail < 0) {
646 if (avail == -EPIPE) {
647 if (!alsa_recover (handle)) {
648 avail = snd_pcm_avail_update (handle);
649 }
650 }
651
652 if (avail < 0) {
653 alsa_logerr (avail,
654 "Could not obtain number of available frames\n");
655 return -1;
656 }
657 }
658
659 return avail;
660}
661
662static int alsa_run_out (HWVoiceOut *hw)
663{
664 ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
665 int rpos, live, decr;
666 int samples;
667 uint8_t *dst;
668 st_sample_t *src;
669 snd_pcm_sframes_t avail;
670
671 live = audio_pcm_hw_get_live_out (hw);
672 if (!live) {
673 return 0;
674 }
675
676 avail = alsa_get_avail (alsa->handle);
677 if (avail < 0) {
678 dolog ("Could not get number of available playback frames\n");
679 return 0;
680 }
681
682 decr = audio_MIN (live, avail);
683 samples = decr;
684 rpos = hw->rpos;
685 while (samples) {
686 int left_till_end_samples = hw->samples - rpos;
687 int len = audio_MIN (samples, left_till_end_samples);
688 snd_pcm_sframes_t written;
689
690 src = hw->mix_buf + rpos;
691 dst = advance (alsa->pcm_buf, rpos << hw->info.shift);
692
693 hw->clip (dst, src, len);
694
695 while (len) {
696 written = snd_pcm_writei (alsa->handle, dst, len);
697
698 if (written <= 0) {
699 switch (written) {
700 case 0:
701 if (conf.verbose) {
702 dolog ("Failed to write %d frames (wrote zero)\n", len);
703 }
704 goto exit;
705
706 case -EPIPE:
707 if (alsa_recover (alsa->handle)) {
708 alsa_logerr (written, "Failed to write %d frames\n",
709 len);
710 goto exit;
711 }
712 if (conf.verbose) {
713 dolog ("Recovering from playback xrun\n");
714 }
715 continue;
716
717 case -EAGAIN:
718 goto exit;
719
720 default:
721 alsa_logerr (written, "Failed to write %d frames to %p\n",
722 len, dst);
723 goto exit;
724 }
725 }
726
727 rpos = (rpos + written) % hw->samples;
728 samples -= written;
729 len -= written;
730 dst = advance (dst, written << hw->info.shift);
731 src += written;
732 }
733 }
734
735 exit:
736 hw->rpos = rpos;
737 return decr;
738}
739
740static void alsa_fini_out (HWVoiceOut *hw)
741{
742 ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
743
744 ldebug ("alsa_fini\n");
745 alsa_anal_close (&alsa->handle);
746
747 if (alsa->pcm_buf) {
748 qemu_free (alsa->pcm_buf);
749 alsa->pcm_buf = NULL;
750 }
751}
752
753static int alsa_init_out (HWVoiceOut *hw, audsettings_t *as)
754{
755 ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
756 struct alsa_params_req req;
757 struct alsa_params_obt obt;
758 audfmt_e effective_fmt;
759 int endianness;
760 int err;
761 snd_pcm_t *handle;
762 audsettings_t obt_as;
763
764 req.fmt = aud_to_alsafmt (as->fmt);
765 req.freq = as->freq;
766 req.nchannels = as->nchannels;
767 req.period_size = conf.period_size_out;
768 req.buffer_size = conf.buffer_size_out;
769
770 if (alsa_open (0, &req, &obt, &handle)) {
771 return -1;
772 }
773
774 err = alsa_to_audfmt (obt.fmt, &effective_fmt, &endianness);
775 if (err) {
776 alsa_anal_close (&handle);
777 return -1;
778 }
779
780 obt_as.freq = obt.freq;
781 obt_as.nchannels = obt.nchannels;
782 obt_as.fmt = effective_fmt;
783 obt_as.endianness = endianness;
784
785 audio_pcm_init_info (&hw->info, &obt_as);
786 hw->samples = obt.samples;
787
788 alsa->pcm_buf = audio_calloc (AUDIO_FUNC, obt.samples, 1 << hw->info.shift);
789 if (!alsa->pcm_buf) {
790 dolog ("Could not allocate DAC buffer (%d samples, each %d bytes)\n",
791 hw->samples, 1 << hw->info.shift);
792 alsa_anal_close (&handle);
793 return -1;
794 }
795
796 alsa->handle = handle;
797 return 0;
798}
799
800static int alsa_voice_ctl (snd_pcm_t *handle, const char *typ, int pause)
801{
802 int err;
803
804 if (pause) {
805 err = snd_pcm_drop (handle);
806 if (err < 0) {
807 alsa_logerr (err, "Could not stop %s\n", typ);
808 return -1;
809 }
810 }
811 else {
812 err = snd_pcm_prepare (handle);
813 if (err < 0) {
814 alsa_logerr (err, "Could not prepare handle for %s\n", typ);
815 return -1;
816 }
817 }
818
819 return 0;
820}
821
822static int alsa_ctl_out (HWVoiceOut *hw, int cmd, ...)
823{
824 ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
825
826 switch (cmd) {
827 case VOICE_ENABLE:
828 ldebug ("enabling voice\n");
829 return alsa_voice_ctl (alsa->handle, "playback", 0);
830
831 case VOICE_DISABLE:
832 ldebug ("disabling voice\n");
833 return alsa_voice_ctl (alsa->handle, "playback", 1);
834 }
835
836 return -1;
837}
838
839static int alsa_init_in (HWVoiceIn *hw, audsettings_t *as)
840{
841 ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
842 struct alsa_params_req req;
843 struct alsa_params_obt obt;
844 int endianness;
845 int err;
846 audfmt_e effective_fmt;
847 snd_pcm_t *handle;
848 audsettings_t obt_as;
849
850 req.fmt = aud_to_alsafmt (as->fmt);
851 req.freq = as->freq;
852 req.nchannels = as->nchannels;
853 req.period_size = conf.period_size_in;
854 req.buffer_size = conf.buffer_size_in;
855
856 if (alsa_open (1, &req, &obt, &handle)) {
857 return -1;
858 }
859
860 err = alsa_to_audfmt (obt.fmt, &effective_fmt, &endianness);
861 if (err) {
862 alsa_anal_close (&handle);
863 return -1;
864 }
865
866 obt_as.freq = obt.freq;
867 obt_as.nchannels = obt.nchannels;
868 obt_as.fmt = effective_fmt;
869 obt_as.endianness = endianness;
870
871 audio_pcm_init_info (&hw->info, &obt_as);
872 hw->samples = obt.samples;
873
874 alsa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
875 if (!alsa->pcm_buf) {
876 dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
877 hw->samples, 1 << hw->info.shift);
878 alsa_anal_close (&handle);
879 return -1;
880 }
881
882 alsa->handle = handle;
883 return 0;
884}
885
886static void alsa_fini_in (HWVoiceIn *hw)
887{
888 ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
889
890 alsa_anal_close (&alsa->handle);
891
892 if (alsa->pcm_buf) {
893 qemu_free (alsa->pcm_buf);
894 alsa->pcm_buf = NULL;
895 }
896}
897
898static int alsa_run_in (HWVoiceIn *hw)
899{
900 ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
901 int hwshift = hw->info.shift;
902 int i;
903 int live = audio_pcm_hw_get_live_in (hw);
904 int dead = hw->samples - live;
905 int decr;
906 struct {
907 int add;
908 int len;
909 } bufs[2];
910
911 snd_pcm_sframes_t avail;
912 snd_pcm_uframes_t read_samples = 0;
913
914 bufs[0].add = hw->wpos;
915 bufs[0].len = 0;
916 bufs[1].add = 0;
917 bufs[1].len = 0;
918
919 if (!dead) {
920 return 0;
921 }
922
923 avail = alsa_get_avail (alsa->handle);
924 if (avail < 0) {
925 dolog ("Could not get number of captured frames\n");
926 return 0;
927 }
928
929 if (!avail && (snd_pcm_state (alsa->handle) == SND_PCM_STATE_PREPARED)) {
930 avail = hw->samples;
931 }
932
933 decr = audio_MIN (dead, avail);
934 if (!decr) {
935 return 0;
936 }
937
938 if (hw->wpos + decr > hw->samples) {
939 bufs[0].len = (hw->samples - hw->wpos);
940 bufs[1].len = (decr - (hw->samples - hw->wpos));
941 }
942 else {
943 bufs[0].len = decr;
944 }
945
946 for (i = 0; i < 2; ++i) {
947 void *src;
948 st_sample_t *dst;
949 snd_pcm_sframes_t nread;
950 snd_pcm_uframes_t len;
951
952 len = bufs[i].len;
953
954 src = advance (alsa->pcm_buf, bufs[i].add << hwshift);
955 dst = hw->conv_buf + bufs[i].add;
956
957 while (len) {
958 nread = snd_pcm_readi (alsa->handle, src, len);
959
960 if (nread <= 0) {
961 switch (nread) {
962 case 0:
963 if (conf.verbose) {
964 dolog ("Failed to read %ld frames (read zero)\n", len);
965 }
966 goto exit;
967
968 case -EPIPE:
969 if (alsa_recover (alsa->handle)) {
970 alsa_logerr (nread, "Failed to read %ld frames\n", len);
971 goto exit;
972 }
973 if (conf.verbose) {
974 dolog ("Recovering from capture xrun\n");
975 }
976 continue;
977
978 case -EAGAIN:
979 goto exit;
980
981 default:
982 alsa_logerr (
983 nread,
984 "Failed to read %ld frames from %p\n",
985 len,
986 src
987 );
988 goto exit;
989 }
990 }
991
992 hw->conv (dst, src, nread, &nominal_volume);
993
994 src = advance (src, nread << hwshift);
995 dst += nread;
996
997 read_samples += nread;
998 len -= nread;
999 }
1000 }
1001
1002 exit:
1003 hw->wpos = (hw->wpos + read_samples) % hw->samples;
1004 return read_samples;
1005}
1006
1007static int alsa_read (SWVoiceIn *sw, void *buf, int size)
1008{
1009 return audio_pcm_sw_read (sw, buf, size);
1010}
1011
1012static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...)
1013{
1014 ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
1015
1016 switch (cmd) {
1017 case VOICE_ENABLE:
1018 ldebug ("enabling voice\n");
1019 return alsa_voice_ctl (alsa->handle, "capture", 0);
1020
1021 case VOICE_DISABLE:
1022 ldebug ("disabling voice\n");
1023 return alsa_voice_ctl (alsa->handle, "capture", 1);
1024 }
1025
1026 return -1;
1027}
1028
1029#ifdef VBOX
1030static void alsa_error_handler(const char *file, int line, const char *function,
1031 int err, const char *fmt, ...)
1032{
1033 /* ignore */
1034}
1035#endif
1036
1037static void *alsa_audio_init (void)
1038{
1039#ifdef VBOX
1040 int rc;
1041
1042 rc = audioLoadAlsaLib();
1043 if (RT_FAILURE(rc)) {
1044 LogRelFunc(("Failed to load the ALSA shared library! Error %Rrc\n", rc));
1045 return NULL;
1046 }
1047 snd_lib_error_set_handler (alsa_error_handler);
1048#endif
1049 return &conf;
1050}
1051
1052static void alsa_audio_fini (void *opaque)
1053{
1054 (void) opaque;
1055}
1056
1057static struct audio_option alsa_options[] = {
1058 {"DAC_SIZE_IN_USEC", AUD_OPT_BOOL, &conf.size_in_usec_out,
1059 "DAC period/buffer size in microseconds (otherwise in frames)", NULL, 0},
1060 {"DAC_PERIOD_SIZE", AUD_OPT_INT, &conf.period_size_out,
1061 "DAC period size", &conf.period_size_out_overriden, 0},
1062 {"DAC_BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_size_out,
1063 "DAC buffer size", &conf.buffer_size_out_overriden, 0},
1064
1065 {"ADC_SIZE_IN_USEC", AUD_OPT_BOOL, &conf.size_in_usec_in,
1066 "ADC period/buffer size in microseconds (otherwise in frames)", NULL, 0},
1067 {"ADC_PERIOD_SIZE", AUD_OPT_INT, &conf.period_size_in,
1068 "ADC period size", &conf.period_size_in_overriden, 0},
1069 {"ADC_BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_size_in,
1070 "ADC buffer size", &conf.buffer_size_in_overriden, 0},
1071
1072 {"THRESHOLD", AUD_OPT_INT, &conf.threshold,
1073 "(undocumented)", NULL, 0},
1074
1075 {"DAC_DEV", AUD_OPT_STR, &conf.pcm_name_out,
1076 "DAC device name (for instance dmix)", NULL, 0},
1077
1078 {"ADC_DEV", AUD_OPT_STR, &conf.pcm_name_in,
1079 "ADC device name", NULL, 0},
1080
1081 {"VERBOSE", AUD_OPT_BOOL, &conf.verbose,
1082 "Behave in a more verbose way", NULL, 0},
1083
1084 {NULL, 0, NULL, NULL, NULL, 0}
1085};
1086
1087static struct audio_pcm_ops alsa_pcm_ops = {
1088 alsa_init_out,
1089 alsa_fini_out,
1090 alsa_run_out,
1091 alsa_write,
1092 alsa_ctl_out,
1093
1094 alsa_init_in,
1095 alsa_fini_in,
1096 alsa_run_in,
1097 alsa_read,
1098 alsa_ctl_in
1099};
1100
1101struct audio_driver alsa_audio_driver = {
1102 INIT_FIELD (name = ) "alsa",
1103 INIT_FIELD (descr = ) "ALSA http://www.alsa-project.org",
1104 INIT_FIELD (options = ) alsa_options,
1105 INIT_FIELD (init = ) alsa_audio_init,
1106 INIT_FIELD (fini = ) alsa_audio_fini,
1107 INIT_FIELD (pcm_ops = ) &alsa_pcm_ops,
1108 INIT_FIELD (can_be_default = ) 1,
1109 INIT_FIELD (max_voices_out = ) INT_MAX,
1110 INIT_FIELD (max_voices_in = ) INT_MAX,
1111 INIT_FIELD (voice_size_out = ) sizeof (ALSAVoiceOut),
1112 INIT_FIELD (voice_size_in = ) sizeof (ALSAVoiceIn)
1113};
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette