VirtualBox

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

Last change on this file since 2390 was 1948, checked in by vboxsync, 18 years ago

removed tab

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