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