VirtualBox

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

Last change on this file since 44824 was 40844, checked in by vboxsync, 13 years ago

Devices/Audio: Removal of environment variables which acted as audio configuration parameters .
Now the audio configuration parameters can be set through SetExtraData.
Also, as the configuration parameters are no longer environment variables, there nomenclature

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 31.9 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 "VBoxDD.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 case AUD_FMT_S32:
182 return SND_PCM_FORMAT_S32_LE;
183
184 case AUD_FMT_U32:
185 return SND_PCM_FORMAT_U32_LE;
186
187 default:
188 dolog ("Internal logic error: Bad audio format %d\n", fmt);
189#ifdef DEBUG_AUDIO
190 abort ();
191#endif
192 return SND_PCM_FORMAT_U8;
193 }
194}
195
196static int alsa_to_audfmt (int alsafmt, audfmt_e *fmt, int *endianness)
197{
198 switch (alsafmt) {
199 case SND_PCM_FORMAT_S8:
200 *endianness = 0;
201 *fmt = AUD_FMT_S8;
202 break;
203
204 case SND_PCM_FORMAT_U8:
205 *endianness = 0;
206 *fmt = AUD_FMT_U8;
207 break;
208
209 case SND_PCM_FORMAT_S16_LE:
210 *endianness = 0;
211 *fmt = AUD_FMT_S16;
212 break;
213
214 case SND_PCM_FORMAT_U16_LE:
215 *endianness = 0;
216 *fmt = AUD_FMT_U16;
217 break;
218
219 case SND_PCM_FORMAT_S16_BE:
220 *endianness = 1;
221 *fmt = AUD_FMT_S16;
222 break;
223
224 case SND_PCM_FORMAT_U16_BE:
225 *endianness = 1;
226 *fmt = AUD_FMT_U16;
227 break;
228
229 case SND_PCM_FORMAT_S32_LE:
230 *endianness = 0;
231 *fmt = AUD_FMT_S32;
232 break;
233
234 case SND_PCM_FORMAT_U32_LE:
235 *endianness = 0;
236 *fmt = AUD_FMT_U32;
237 break;
238
239 case SND_PCM_FORMAT_S32_BE:
240 *endianness = 1;
241 *fmt = AUD_FMT_S32;
242 break;
243
244 case SND_PCM_FORMAT_U32_BE:
245 *endianness = 1;
246 *fmt = AUD_FMT_U32;
247 break;
248
249 default:
250 dolog ("Unrecognized audio format %d\n", alsafmt);
251 return -1;
252 }
253
254 return 0;
255}
256
257#if defined DEBUG_MISMATCHES || defined DEBUG
258static void alsa_dump_info (struct alsa_params_req *req,
259 struct alsa_params_obt *obt)
260{
261 dolog ("parameter | requested value | obtained value\n");
262 dolog ("format | %10d | %10d\n", req->fmt, obt->fmt);
263 dolog ("channels | %10d | %10d\n",
264 req->nchannels, obt->nchannels);
265 dolog ("frequency | %10d | %10d\n", req->freq, obt->freq);
266 dolog ("============================================\n");
267 dolog ("requested: buffer size %d period size %d\n",
268 req->buffer_size, req->period_size);
269 dolog ("obtained: samples %ld\n", obt->samples);
270}
271#endif
272
273static void alsa_set_threshold (snd_pcm_t *handle, snd_pcm_uframes_t threshold)
274{
275 int err;
276 snd_pcm_sw_params_t *sw_params;
277
278 snd_pcm_sw_params_alloca (&sw_params);
279
280 err = snd_pcm_sw_params_current (handle, sw_params);
281 if (err < 0) {
282 dolog ("Could not fully initialize DAC\n");
283 alsa_logerr (err, "Failed to get current software parameters\n");
284 return;
285 }
286
287 err = snd_pcm_sw_params_set_start_threshold (handle, sw_params, threshold);
288 if (err < 0) {
289 dolog ("Could not fully initialize DAC\n");
290 alsa_logerr (err, "Failed to set software threshold to %ld\n",
291 threshold);
292 return;
293 }
294
295 err = snd_pcm_sw_params (handle, sw_params);
296 if (err < 0) {
297 dolog ("Could not fully initialize DAC\n");
298 alsa_logerr (err, "Failed to set software parameters\n");
299 return;
300 }
301}
302
303static int alsa_open (int in, struct alsa_params_req *req,
304 struct alsa_params_obt *obt, snd_pcm_t **handlep)
305{
306 snd_pcm_t *handle;
307 snd_pcm_hw_params_t *hw_params;
308 int err, dir;
309 unsigned int freq, nchannels;
310 const char *pcm_name = in ? conf.pcm_name_in : conf.pcm_name_out;
311 unsigned int period_size, buffer_size;
312 snd_pcm_uframes_t period_size_f, buffer_size_f;
313 snd_pcm_uframes_t obt_buffer_size, obt_period_size;
314 const char *typ = in ? "ADC" : "DAC";
315
316 freq = req->freq;
317 period_size = req->period_size;
318 buffer_size = req->buffer_size;
319 period_size_f = (snd_pcm_uframes_t)period_size;
320 buffer_size_f = (snd_pcm_uframes_t)buffer_size;
321 nchannels = req->nchannels;
322
323 snd_pcm_hw_params_alloca (&hw_params);
324
325 err = snd_pcm_open (
326 &handle,
327 pcm_name,
328 in ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
329 SND_PCM_NONBLOCK
330 );
331 if (err < 0) {
332#ifndef VBOX
333 alsa_logerr2 (err, typ, "Failed to open `%s':\n", pcm_name);
334#else
335 LogRel(("ALSA: Failed to open '%s' as %s\n", pcm_name, typ));
336#endif
337 return -1;
338 }
339
340 err = snd_pcm_hw_params_any (handle, hw_params);
341 if (err < 0) {
342#ifndef VBOX
343 alsa_logerr2 (err, typ, "Failed to initialize hardware parameters\n");
344#else
345 LogRel(("ALSA: Failed to initialize hardware parameters\n"));
346#endif
347 goto err;
348 }
349
350 err = snd_pcm_hw_params_set_access (
351 handle,
352 hw_params,
353 SND_PCM_ACCESS_RW_INTERLEAVED
354 );
355 if (err < 0) {
356#ifndef VBOX
357 alsa_logerr2 (err, typ, "Failed to set access type\n");
358#else
359 LogRel(("ALSA: Failed to set access type\n"));
360#endif
361 goto err;
362 }
363
364 err = snd_pcm_hw_params_set_format (handle, hw_params, req->fmt);
365 if (err < 0) {
366#ifndef VBOX
367 alsa_logerr2 (err, typ, "Failed to set format %d\n", req->fmt);
368#else
369 LogRel(("ALSA: Failed to set format %d\n", req->fmt));
370#endif
371 goto err;
372 }
373
374 err = snd_pcm_hw_params_set_rate_near (handle, hw_params, &freq, 0);
375 if (err < 0) {
376#ifndef VBOX
377 alsa_logerr2 (err, typ, "Failed to set frequency %d\n", req->freq);
378#else
379 LogRel(("ALSA: Failed to set frequency %dHz\n", req->freq));
380#endif
381 goto err;
382 }
383
384 err = snd_pcm_hw_params_set_channels_near (
385 handle,
386 hw_params,
387 &nchannels
388 );
389 if (err < 0) {
390#ifndef VBOX
391 alsa_logerr2 (err, typ, "Failed to set number of channels %d\n",
392 req->nchannels);
393#else
394 LogRel(("ALSA: Failed to set number of channels to %d\n", req->nchannels));
395#endif
396 goto err;
397 }
398
399 if (nchannels != 1 && nchannels != 2) {
400#ifndef VBOX
401 alsa_logerr2 (err, typ,
402 "Can not handle obtained number of channels %d\n",
403 nchannels);
404#else
405 LogRel(("ALSA: Cannot handle obtained number of channels (%d)\n", nchannels));
406#endif
407 goto err;
408 }
409
410 if (!((in && conf.size_in_usec_in) || (!in && conf.size_in_usec_out))) {
411 if (!buffer_size) {
412 buffer_size = DEFAULT_BUFFER_SIZE;
413 period_size= DEFAULT_PERIOD_SIZE;
414 }
415 }
416
417 if (buffer_size) {
418 if ((in && conf.size_in_usec_in) || (!in && conf.size_in_usec_out)) {
419 if (period_size) {
420 err = snd_pcm_hw_params_set_period_time_near (
421 handle,
422 hw_params,
423 &period_size,
424 0
425 );
426 if (err < 0) {
427#ifndef VBOX
428 alsa_logerr2 (err, typ,
429 "Failed to set period time %d\n",
430 req->period_size);
431#else
432 LogRel(("ALSA: Failed to set period time %d\n", req->period_size));
433#endif
434 goto err;
435 }
436 }
437
438 err = snd_pcm_hw_params_set_buffer_time_near (
439 handle,
440 hw_params,
441 &buffer_size,
442 0
443 );
444
445 if (err < 0) {
446#ifndef VBOX
447 alsa_logerr2 (err, typ,
448 "Failed to set buffer time %d\n",
449 req->buffer_size);
450#else
451 LogRel(("ALSA: Failed to set buffer time %d\n", req->buffer_size));
452#endif
453 goto err;
454 }
455 }
456 else {
457 snd_pcm_uframes_t minval;
458
459 if (period_size_f) {
460 minval = period_size_f;
461 dir = 0;
462
463 err = snd_pcm_hw_params_get_period_size_min (
464 hw_params,
465 &minval,
466 &dir
467 );
468 if (err < 0) {
469#ifndef VBOX
470 alsa_logerr (
471 err,
472 "Could not get minimal period size for %s\n",
473 typ
474 );
475#else
476 LogRel(("ALSA: Could not get minimal period size for %s\n", typ));
477#endif
478 }
479 else {
480 dolog("minimal period size %ld\n", minval);
481 if (period_size_f < minval) {
482 if ((in && conf.period_size_in_overriden)
483 || (!in && conf.period_size_out_overriden)) {
484 dolog ("%s period size(%d) is less "
485 "than minimal period size(%ld)\n",
486 typ,
487 period_size_f,
488 minval);
489 }
490 period_size_f = minval;
491 }
492 }
493
494#ifndef VBOX
495 err = snd_pcm_hw_params_set_period_size (
496 handle,
497 hw_params,
498 period_size_f,
499 0
500 );
501#else
502 err = snd_pcm_hw_params_set_period_size_near (
503 handle,
504 hw_params,
505 &period_size_f,
506 0
507 );
508#endif
509 dolog("PERIOD_SIZE %d\n", period_size_f);
510 if (err < 0) {
511#ifndef VBOX
512 alsa_logerr2 (err, typ, "Failed to set period size %d\n",
513 period_size_f);
514#else
515 LogRel(("ALSA: Failed to set period size %d (%s)\n",
516 period_size_f, snd_strerror(err)));
517#endif
518 goto err;
519 }
520 }
521
522#ifdef VBOX
523 /* Calculate default buffer size here since it might have been changed
524 * in the _near functions */
525 buffer_size_f = 4 * period_size_f;
526#endif
527
528 minval = buffer_size_f;
529 err = snd_pcm_hw_params_get_buffer_size_min (
530 hw_params,
531 &minval
532 );
533 if (err < 0) {
534#ifndef VBOX
535 alsa_logerr (err, "Could not get minimal buffer size for %s\n",
536 typ);
537#else
538 LogRel(("ALSA: Could not get minimal buffer size for %s\n", typ));
539#endif
540 }
541 else {
542 if (buffer_size_f < minval) {
543 if ((in && conf.buffer_size_in_overriden)
544 || (!in && conf.buffer_size_out_overriden)) {
545 dolog (
546 "%s buffer size(%d) is less "
547 "than minimal buffer size(%ld)\n",
548 typ,
549 buffer_size_f,
550 minval
551 );
552 }
553 buffer_size_f = minval;
554 }
555 }
556
557 err = snd_pcm_hw_params_set_buffer_size_near (
558 handle,
559 hw_params,
560 &buffer_size_f
561 );
562 dolog("BUFFER_SIZE %d\n", buffer_size_f);
563 if (err < 0) {
564#ifndef VBOX
565 alsa_logerr2 (err, typ, "Failed to set buffer size %d\n",
566 buffer_size_f);
567#else
568 LogRel(("ALSA: Failed to set buffer size %d (%s)\n",
569 buffer_size_f, snd_strerror(err)));
570#endif
571 goto err;
572 }
573 }
574 }
575 else {
576 dolog ("warning: Buffer size is not set\n");
577 }
578
579 err = snd_pcm_hw_params (handle, hw_params);
580 if (err < 0) {
581#ifndef VBOX
582 alsa_logerr2 (err, typ, "Failed to apply audio parameters\n");
583#else
584 LogRel(("ALSA: Failed to apply audio parameters\n"));
585#endif
586 goto err;
587 }
588
589 err = snd_pcm_hw_params_get_buffer_size (hw_params, &obt_buffer_size);
590 if (err < 0) {
591#ifndef VBOX
592 alsa_logerr2 (err, typ, "Failed to get buffer size\n");
593#else
594 LogRel(("ALSA: Failed to get buffer size\n"));
595#endif
596 goto err;
597 }
598
599#ifdef VBOX
600 dir = 0;
601 err = snd_pcm_hw_params_get_period_size (hw_params, &obt_period_size, &dir);
602 if (err < 0)
603 {
604 LogRel(("ALSA: Failed to get period size\n"));
605 goto err;
606 }
607 LogRel(("ALSA: %s frequency %dHz, period size %ld, buffer size %ld\n",
608 typ, req->freq, obt_period_size, obt_buffer_size));
609#endif
610
611 err = snd_pcm_prepare (handle);
612 if (err < 0) {
613 alsa_logerr2 (err, typ, "Could not prepare handle %p\n",
614 (void *) handle);
615 goto err;
616 }
617
618 if (!in && conf.threshold) {
619 snd_pcm_uframes_t threshold;
620 int bytes_per_sec;
621
622 bytes_per_sec = freq
623 << (nchannels == 2)
624 << (req->fmt == AUD_FMT_S16 || req->fmt == AUD_FMT_U16);
625
626 threshold = (conf.threshold * bytes_per_sec) / 1000;
627 alsa_set_threshold (handle, threshold);
628 }
629
630 obt->fmt = req->fmt;
631 obt->nchannels = nchannels;
632 obt->freq = freq;
633 obt->samples = obt_buffer_size;
634 *handlep = handle;
635
636#if defined DEBUG_MISMATCHES || defined DEBUG
637 if (obt->fmt != req->fmt ||
638 obt->nchannels != req->nchannels ||
639 obt->freq != req->freq) {
640 dolog ("Audio parameters mismatch for %s\n", typ);
641 alsa_dump_info (req, obt);
642 }
643#endif
644
645#ifdef DEBUG
646 alsa_dump_info (req, obt);
647#endif
648 return 0;
649
650 err:
651 alsa_anal_close (&handle);
652 return -1;
653}
654
655static int alsa_recover (snd_pcm_t *handle)
656{
657 int err = snd_pcm_prepare (handle);
658 if (err < 0) {
659 alsa_logerr (err, "Failed to prepare handle %p\n",
660 (void *) handle);
661 return -1;
662 }
663 return 0;
664}
665
666static int alsa_resume (snd_pcm_t *handle)
667{
668 int err = snd_pcm_resume (handle);
669 if (err < 0) {
670#ifndef VBOX
671 alsa_logerr (err, "Failed to resume handle %p\n", handle);
672#endif
673 return -1;
674 }
675 return 0;
676}
677
678static snd_pcm_sframes_t alsa_get_avail (snd_pcm_t *handle)
679{
680 snd_pcm_sframes_t avail;
681
682 avail = snd_pcm_avail_update (handle);
683 if (avail < 0) {
684 if (avail == -EPIPE) {
685 if (!alsa_recover (handle)) {
686 avail = snd_pcm_avail_update (handle);
687 }
688 }
689
690 if (avail < 0) {
691 alsa_logerr (avail,
692 "Could not obtain number of available frames\n");
693 return -1;
694 }
695 }
696
697 return avail;
698}
699
700static int alsa_run_out (HWVoiceOut *hw)
701{
702 ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
703 int rpos, live, decr;
704 int samples;
705 uint8_t *dst;
706 st_sample_t *src;
707 snd_pcm_sframes_t avail;
708
709 live = audio_pcm_hw_get_live_out (hw);
710 if (!live) {
711 return 0;
712 }
713
714 avail = alsa_get_avail (alsa->handle);
715 if (avail < 0) {
716 dolog ("Could not get number of available playback frames\n");
717 return 0;
718 }
719
720 decr = audio_MIN (live, avail);
721 samples = decr;
722 rpos = hw->rpos;
723 while (samples) {
724 int left_till_end_samples = hw->samples - rpos;
725 int len = audio_MIN (samples, left_till_end_samples);
726 snd_pcm_sframes_t written;
727
728 src = hw->mix_buf + rpos;
729 dst = advance (alsa->pcm_buf, rpos << hw->info.shift);
730
731 hw->clip (dst, src, len);
732
733 while (len) {
734 written = snd_pcm_writei (alsa->handle, dst, len);
735
736 if (written <= 0) {
737 switch (written) {
738 case 0:
739 if (conf.verbose) {
740 dolog ("Failed to write %d frames (wrote zero)\n", len);
741 }
742 goto exit;
743
744 case -EPIPE:
745 if (alsa_recover (alsa->handle)) {
746 alsa_logerr (written, "Failed to write %d frames\n",
747 len);
748 goto exit;
749 }
750 if (conf.verbose) {
751 dolog ("Recovering from playback xrun\n");
752 }
753 continue;
754
755 case -ESTRPIPE:
756 /* stream is suspended and waiting for an
757 application recovery */
758 if (alsa_resume (alsa->handle)) {
759#ifndef VBOX
760 alsa_logerr (written, "Failed to write %d frames\n", len);
761#else
762 LogRel(("ALSA: Failed to resume output stream\n"));
763#endif
764 goto exit;
765 }
766 if (conf.verbose) {
767 dolog ("Resuming suspended output stream\n");
768 }
769 continue;
770
771 case -EAGAIN:
772 goto exit;
773
774 default:
775 alsa_logerr (written, "Failed to write %d frames to %p\n",
776 len, dst);
777 goto exit;
778 }
779 }
780
781 rpos = (rpos + written) % hw->samples;
782 samples -= written;
783 len -= written;
784 dst = advance (dst, written << hw->info.shift);
785 src += written;
786 }
787 }
788
789 exit:
790 hw->rpos = rpos;
791 return decr;
792}
793
794static void alsa_fini_out (HWVoiceOut *hw)
795{
796 ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
797
798 ldebug ("alsa_fini\n");
799 alsa_anal_close (&alsa->handle);
800
801 if (alsa->pcm_buf) {
802 qemu_free (alsa->pcm_buf);
803 alsa->pcm_buf = NULL;
804 }
805}
806
807static int alsa_init_out (HWVoiceOut *hw, audsettings_t *as)
808{
809 ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
810 struct alsa_params_req req;
811 struct alsa_params_obt obt;
812 audfmt_e effective_fmt;
813 int endianness;
814 int err;
815 snd_pcm_t *handle;
816 audsettings_t obt_as;
817
818 req.fmt = aud_to_alsafmt (as->fmt);
819 req.freq = as->freq;
820 req.nchannels = as->nchannels;
821 req.period_size = conf.period_size_out;
822 req.buffer_size = conf.buffer_size_out;
823
824 if (alsa_open (0, &req, &obt, &handle)) {
825 return -1;
826 }
827
828 err = alsa_to_audfmt (obt.fmt, &effective_fmt, &endianness);
829 if (err) {
830 alsa_anal_close (&handle);
831 return -1;
832 }
833
834 obt_as.freq = obt.freq;
835 obt_as.nchannels = obt.nchannels;
836 obt_as.fmt = effective_fmt;
837 obt_as.endianness = endianness;
838
839 audio_pcm_init_info (&hw->info, &obt_as);
840 hw->samples = obt.samples;
841
842 alsa->pcm_buf = audio_calloc (AUDIO_FUNC, obt.samples, 1 << hw->info.shift);
843 if (!alsa->pcm_buf) {
844 dolog ("Could not allocate DAC buffer (%d samples, each %d bytes)\n",
845 hw->samples, 1 << hw->info.shift);
846 alsa_anal_close (&handle);
847 return -1;
848 }
849
850 alsa->handle = handle;
851 return 0;
852}
853
854static int alsa_voice_ctl (snd_pcm_t *handle, const char *typ, int pauseit) /* VBOX: s/pause/pauseit/; -Wshadow */
855{
856 int err;
857
858 if (pauseit) {
859 err = snd_pcm_drop (handle);
860 if (err < 0) {
861 alsa_logerr (err, "Could not stop %s\n", typ);
862 return -1;
863 }
864 }
865 else {
866 err = snd_pcm_prepare (handle);
867 if (err < 0) {
868 alsa_logerr (err, "Could not prepare handle for %s\n", typ);
869 return -1;
870 }
871 }
872
873 return 0;
874}
875
876static int alsa_ctl_out (HWVoiceOut *hw, int cmd, ...)
877{
878 ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
879
880 switch (cmd) {
881 case VOICE_ENABLE:
882 ldebug ("enabling voice\n");
883 return alsa_voice_ctl (alsa->handle, "playback", 0);
884
885 case VOICE_DISABLE:
886 ldebug ("disabling voice\n");
887 return alsa_voice_ctl (alsa->handle, "playback", 1);
888 }
889
890 return -1;
891}
892
893static int alsa_init_in (HWVoiceIn *hw, audsettings_t *as)
894{
895 ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
896 struct alsa_params_req req;
897 struct alsa_params_obt obt;
898 int endianness;
899 int err;
900 audfmt_e effective_fmt;
901 snd_pcm_t *handle;
902 audsettings_t obt_as;
903
904 req.fmt = aud_to_alsafmt (as->fmt);
905 req.freq = as->freq;
906 req.nchannels = as->nchannels;
907 req.period_size = conf.period_size_in;
908 req.buffer_size = conf.buffer_size_in;
909
910 if (alsa_open (1, &req, &obt, &handle)) {
911 return -1;
912 }
913
914 err = alsa_to_audfmt (obt.fmt, &effective_fmt, &endianness);
915 if (err) {
916 alsa_anal_close (&handle);
917 return -1;
918 }
919
920 obt_as.freq = obt.freq;
921 obt_as.nchannels = obt.nchannels;
922 obt_as.fmt = effective_fmt;
923 obt_as.endianness = endianness;
924
925 audio_pcm_init_info (&hw->info, &obt_as);
926 hw->samples = obt.samples;
927
928 alsa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
929 if (!alsa->pcm_buf) {
930 dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
931 hw->samples, 1 << hw->info.shift);
932 alsa_anal_close (&handle);
933 return -1;
934 }
935
936 alsa->handle = handle;
937 return 0;
938}
939
940static void alsa_fini_in (HWVoiceIn *hw)
941{
942 ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
943
944 alsa_anal_close (&alsa->handle);
945
946 if (alsa->pcm_buf) {
947 qemu_free (alsa->pcm_buf);
948 alsa->pcm_buf = NULL;
949 }
950}
951
952static int alsa_run_in (HWVoiceIn *hw)
953{
954 ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
955 int hwshift = hw->info.shift;
956 int i;
957 int live = audio_pcm_hw_get_live_in (hw);
958 int dead = hw->samples - live;
959 int decr;
960 struct {
961 int add;
962 int len;
963 } bufs[2];
964
965 snd_pcm_sframes_t avail;
966 snd_pcm_uframes_t read_samples = 0;
967
968 bufs[0].add = hw->wpos;
969 bufs[0].len = 0;
970 bufs[1].add = 0;
971 bufs[1].len = 0;
972
973 if (!dead) {
974 return 0;
975 }
976
977 avail = alsa_get_avail (alsa->handle);
978 if (avail < 0) {
979 dolog ("Could not get number of captured frames\n");
980 return 0;
981 }
982
983 if (!avail) {
984 snd_pcm_state_t state;
985 state = snd_pcm_state (alsa->handle);
986 switch (state) {
987 case SND_PCM_STATE_PREPARED:
988 avail = hw->samples;
989 break;
990 case SND_PCM_STATE_SUSPENDED:
991 /* stream is suspended and waiting for an application recovery */
992 if (alsa_resume (alsa->handle)) {
993#ifndef VBOX
994 dolog ("Failed to resume suspended input stream\n");
995#else
996 LogRel(("ALSA: Failed to resume input stream\n"));
997#endif
998 return 0;
999 }
1000 if (conf.verbose) {
1001 dolog ("Resuming suspended input stream\n");
1002 }
1003 break;
1004 default:
1005 if (conf.verbose) {
1006 dolog ("No frames available and ALSA state is %d\n", state);
1007 }
1008 return 0;
1009 }
1010 }
1011
1012 decr = audio_MIN (dead, avail);
1013 if (!decr) {
1014 return 0;
1015 }
1016
1017 if (hw->wpos + decr > hw->samples) {
1018 bufs[0].len = (hw->samples - hw->wpos);
1019 bufs[1].len = (decr - (hw->samples - hw->wpos));
1020 }
1021 else {
1022 bufs[0].len = decr;
1023 }
1024
1025 for (i = 0; i < 2; ++i) {
1026 void *src;
1027 st_sample_t *dst;
1028 snd_pcm_sframes_t nread;
1029 snd_pcm_uframes_t len;
1030
1031 len = bufs[i].len;
1032
1033 src = advance (alsa->pcm_buf, bufs[i].add << hwshift);
1034 dst = hw->conv_buf + bufs[i].add;
1035
1036 while (len) {
1037 nread = snd_pcm_readi (alsa->handle, src, len);
1038
1039 if (nread <= 0) {
1040 switch (nread) {
1041 case 0:
1042 if (conf.verbose) {
1043 dolog ("Failed to read %ld frames (read zero)\n", len);
1044 }
1045 goto exit;
1046
1047 case -EPIPE:
1048 if (alsa_recover (alsa->handle)) {
1049 alsa_logerr (nread, "Failed to read %ld frames\n", len);
1050 goto exit;
1051 }
1052 if (conf.verbose) {
1053 dolog ("Recovering from capture xrun\n");
1054 }
1055 continue;
1056
1057 case -EAGAIN:
1058 goto exit;
1059
1060 default:
1061 alsa_logerr (
1062 nread,
1063 "Failed to read %ld frames from %p\n",
1064 len,
1065 src
1066 );
1067 goto exit;
1068 }
1069 }
1070
1071 hw->conv (dst, src, nread, &nominal_volume);
1072
1073 src = advance (src, nread << hwshift);
1074 dst += nread;
1075
1076 read_samples += nread;
1077 len -= nread;
1078 }
1079 }
1080
1081 exit:
1082 hw->wpos = (hw->wpos + read_samples) % hw->samples;
1083 return read_samples;
1084}
1085
1086static int alsa_read (SWVoiceIn *sw, void *buf, int size)
1087{
1088 return audio_pcm_sw_read (sw, buf, size);
1089}
1090
1091static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...)
1092{
1093 ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
1094
1095 switch (cmd) {
1096 case VOICE_ENABLE:
1097 ldebug ("enabling voice\n");
1098 return alsa_voice_ctl (alsa->handle, "capture", 0);
1099
1100 case VOICE_DISABLE:
1101 ldebug ("disabling voice\n");
1102 return alsa_voice_ctl (alsa->handle, "capture", 1);
1103 }
1104
1105 return -1;
1106}
1107
1108#ifdef VBOX
1109static void alsa_error_handler(const char *file, int line, const char *function,
1110 int err, const char *fmt, ...)
1111{
1112 /* ignore */
1113}
1114#endif
1115
1116static void *alsa_audio_init (void)
1117{
1118#ifdef VBOX
1119 int rc;
1120
1121 rc = audioLoadAlsaLib();
1122 if (RT_FAILURE(rc)) {
1123 LogRel(("ALSA: Failed to load the ALSA shared library! Error %Rrc\n", rc));
1124 return NULL;
1125 }
1126 snd_lib_error_set_handler (alsa_error_handler);
1127#endif
1128 return &conf;
1129}
1130
1131static void alsa_audio_fini (void *opaque)
1132{
1133 (void) opaque;
1134}
1135
1136static struct audio_option alsa_options[] = {
1137 {"DACSizeInUsec", AUD_OPT_BOOL, &conf.size_in_usec_out,
1138 "DAC period/buffer size in microseconds (otherwise in frames)", NULL, 0},
1139 {"DACPeriodSize", AUD_OPT_INT, &conf.period_size_out,
1140 "DAC period size", &conf.period_size_out_overriden, 0},
1141 {"DACBufferSize", AUD_OPT_INT, &conf.buffer_size_out,
1142 "DAC buffer size", &conf.buffer_size_out_overriden, 0},
1143
1144 {"ADCSizeInUsec", AUD_OPT_BOOL, &conf.size_in_usec_in,
1145 "ADC period/buffer size in microseconds (otherwise in frames)", NULL, 0},
1146 {"ADCPeriodSize", AUD_OPT_INT, &conf.period_size_in,
1147 "ADC period size", &conf.period_size_in_overriden, 0},
1148 {"ADCBufferSize", AUD_OPT_INT, &conf.buffer_size_in,
1149 "ADC buffer size", &conf.buffer_size_in_overriden, 0},
1150
1151 {"Threshold", AUD_OPT_INT, &conf.threshold,
1152 "(undocumented)", NULL, 0},
1153
1154 {"DACDev", AUD_OPT_STR, &conf.pcm_name_out,
1155 "DAC device name (for instance dmix)", NULL, 0},
1156
1157 {"ADCDev", AUD_OPT_STR, &conf.pcm_name_in,
1158 "ADC device name", NULL, 0},
1159
1160 {"Verbose", AUD_OPT_BOOL, &conf.verbose,
1161 "Behave in a more verbose way", NULL, 0},
1162
1163 {NULL, 0, NULL, NULL, NULL, 0}
1164};
1165
1166static struct audio_pcm_ops alsa_pcm_ops = {
1167 alsa_init_out,
1168 alsa_fini_out,
1169 alsa_run_out,
1170 alsa_write,
1171 alsa_ctl_out,
1172
1173 alsa_init_in,
1174 alsa_fini_in,
1175 alsa_run_in,
1176 alsa_read,
1177 alsa_ctl_in
1178};
1179
1180struct audio_driver alsa_audio_driver = {
1181 INIT_FIELD (name = ) "alsa",
1182 INIT_FIELD (descr = ) "ALSA http://www.alsa-project.org",
1183 INIT_FIELD (options = ) alsa_options,
1184 INIT_FIELD (init = ) alsa_audio_init,
1185 INIT_FIELD (fini = ) alsa_audio_fini,
1186 INIT_FIELD (pcm_ops = ) &alsa_pcm_ops,
1187 INIT_FIELD (can_be_default = ) 1,
1188 INIT_FIELD (max_voices_out = ) INT_MAX,
1189 INIT_FIELD (max_voices_in = ) INT_MAX,
1190 INIT_FIELD (voice_size_out = ) sizeof (ALSAVoiceOut),
1191 INIT_FIELD (voice_size_in = ) sizeof (ALSAVoiceIn)
1192};
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