VirtualBox

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

最後變更 在這個檔案從3085是 3085,由 vboxsync 提交於 18 年 前

warning

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

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