]> git.ipfire.org Git - thirdparty/qemu.git/blame - audio/alsaaudio.c
alsa/oss: Remove fd transfer handlers before closing oss/alsa fd/handle
[thirdparty/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>
749bc4bf 25#include "qemu-common.h"
8b438ba3 26#include "qemu-char.h"
749bc4bf 27#include "audio.h"
1d14ffa9 28
2637872b 29#if QEMU_GNUC_PREREQ(4, 3)
30#pragma GCC diagnostic ignored "-Waddress"
31#endif
32
1d14ffa9
FB
33#define AUDIO_CAP "alsa"
34#include "audio_int.h"
35
8b438ba3 36struct pollhlp {
37 snd_pcm_t *handle;
38 struct pollfd *pfds;
39 int count;
40};
41
1d14ffa9
FB
42typedef struct ALSAVoiceOut {
43 HWVoiceOut hw;
44 void *pcm_buf;
45 snd_pcm_t *handle;
8b438ba3 46 struct pollhlp pollhlp;
1d14ffa9
FB
47} ALSAVoiceOut;
48
49typedef struct ALSAVoiceIn {
50 HWVoiceIn hw;
51 snd_pcm_t *handle;
52 void *pcm_buf;
8b438ba3 53 struct pollhlp pollhlp;
1d14ffa9
FB
54} ALSAVoiceIn;
55
56static struct {
57 int size_in_usec_in;
58 int size_in_usec_out;
59 const char *pcm_name_in;
60 const char *pcm_name_out;
61 unsigned int buffer_size_in;
62 unsigned int period_size_in;
63 unsigned int buffer_size_out;
64 unsigned int period_size_out;
65 unsigned int threshold;
66
fe8f096b
TS
67 int buffer_size_in_overridden;
68 int period_size_in_overridden;
1d14ffa9 69
fe8f096b
TS
70 int buffer_size_out_overridden;
71 int period_size_out_overridden;
571ec3d6 72 int verbose;
1d14ffa9 73} conf = {
adf7d8fb 74 .buffer_size_out = 1024,
8ead62cf
FB
75 .pcm_name_out = "default",
76 .pcm_name_in = "default",
1d14ffa9
FB
77};
78
79struct alsa_params_req {
ca9cc28c
AZ
80 int freq;
81 snd_pcm_format_t fmt;
82 int nchannels;
7a24c800 83 int size_in_usec;
64333899 84 int override_mask;
1d14ffa9
FB
85 unsigned int buffer_size;
86 unsigned int period_size;
87};
88
89struct alsa_params_obt {
90 int freq;
91 audfmt_e fmt;
ca9cc28c 92 int endianness;
1d14ffa9 93 int nchannels;
c0fe3827 94 snd_pcm_uframes_t samples;
1d14ffa9
FB
95};
96
97static void GCC_FMT_ATTR (2, 3) alsa_logerr (int err, const char *fmt, ...)
98{
99 va_list ap;
100
101 va_start (ap, fmt);
102 AUD_vlog (AUDIO_CAP, fmt, ap);
103 va_end (ap);
104
105 AUD_log (AUDIO_CAP, "Reason: %s\n", snd_strerror (err));
106}
107
108static void GCC_FMT_ATTR (3, 4) alsa_logerr2 (
109 int err,
110 const char *typ,
111 const char *fmt,
112 ...
113 )
114{
115 va_list ap;
116
c0fe3827 117 AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
1d14ffa9
FB
118
119 va_start (ap, fmt);
120 AUD_vlog (AUDIO_CAP, fmt, ap);
121 va_end (ap);
122
123 AUD_log (AUDIO_CAP, "Reason: %s\n", snd_strerror (err));
124}
125
6ebfda13 126static void alsa_fini_poll (struct pollhlp *hlp)
127{
128 int i;
129 struct pollfd *pfds = hlp->pfds;
130
131 if (pfds) {
132 for (i = 0; i < hlp->count; ++i) {
133 qemu_set_fd_handler (pfds[i].fd, NULL, NULL, NULL);
134 }
135 qemu_free (pfds);
136 }
137 hlp->pfds = NULL;
138 hlp->count = 0;
139 hlp->handle = NULL;
140}
141
142static void alsa_anal_close1 (snd_pcm_t **handlep)
1d14ffa9
FB
143{
144 int err = snd_pcm_close (*handlep);
145 if (err) {
146 alsa_logerr (err, "Failed to close PCM handle %p\n", *handlep);
147 }
148 *handlep = NULL;
149}
150
6ebfda13 151static void alsa_anal_close (snd_pcm_t **handlep, struct pollhlp *hlp)
152{
153 alsa_fini_poll (hlp);
154 alsa_anal_close1 (handlep);
155}
156
8b438ba3 157static int alsa_recover (snd_pcm_t *handle)
158{
159 int err = snd_pcm_prepare (handle);
160 if (err < 0) {
161 alsa_logerr (err, "Failed to prepare handle %p\n", handle);
162 return -1;
163 }
164 return 0;
165}
166
167static int alsa_resume (snd_pcm_t *handle)
168{
169 int err = snd_pcm_resume (handle);
170 if (err < 0) {
171 alsa_logerr (err, "Failed to resume handle %p\n", handle);
172 return -1;
173 }
174 return 0;
175}
176
177static void alsa_poll_handler (void *opaque)
178{
179 int err, count;
180 snd_pcm_state_t state;
181 struct pollhlp *hlp = opaque;
182 unsigned short revents;
183
184 count = poll (hlp->pfds, hlp->count, 0);
185 if (count < 0) {
186 dolog ("alsa_poll_handler: poll %s\n", strerror (errno));
187 return;
188 }
189
190 if (!count) {
191 return;
192 }
193
194 /* XXX: ALSA example uses initial count, not the one returned by
195 poll, correct? */
196 err = snd_pcm_poll_descriptors_revents (hlp->handle, hlp->pfds,
197 hlp->count, &revents);
198 if (err < 0) {
199 alsa_logerr (err, "snd_pcm_poll_descriptors_revents");
200 return;
201 }
202
203 if (!(revents & POLLOUT)) {
204 if (conf.verbose) {
205 dolog ("revents = %d\n", revents);
206 }
207 return;
208 }
209
210 state = snd_pcm_state (hlp->handle);
211 switch (state) {
212 case SND_PCM_STATE_XRUN:
213 alsa_recover (hlp->handle);
214 break;
215
216 case SND_PCM_STATE_SUSPENDED:
217 alsa_resume (hlp->handle);
218 break;
219
220 case SND_PCM_STATE_PREPARED:
221 audio_run ("alsa run (prepared)");
222 break;
223
224 case SND_PCM_STATE_RUNNING:
225 audio_run ("alsa run (running)");
226 break;
227
228 default:
229 dolog ("Unexpected state %d\n", state);
230 }
231}
232
233static int alsa_poll_helper (snd_pcm_t *handle, struct pollhlp *hlp)
234{
235 int i, count, err;
236 struct pollfd *pfds;
237
238 count = snd_pcm_poll_descriptors_count (handle);
239 if (count <= 0) {
240 dolog ("Could not initialize poll mode\n"
241 "Invalid number of poll descriptors %d\n", count);
242 return -1;
243 }
244
245 pfds = audio_calloc ("alsa_poll_helper", count, sizeof (*pfds));
246 if (!pfds) {
247 dolog ("Could not initialize poll mode\n");
248 return -1;
249 }
250
251 err = snd_pcm_poll_descriptors (handle, pfds, count);
252 if (err < 0) {
253 alsa_logerr (err, "Could not initialize poll mode\n"
254 "Could not obtain poll descriptors\n");
255 qemu_free (pfds);
256 return -1;
257 }
258
259 for (i = 0; i < count; ++i) {
260 if (pfds[i].events & POLLIN) {
261 err = qemu_set_fd_handler (pfds[i].fd, alsa_poll_handler,
262 NULL, hlp);
263 }
264 if (pfds[i].events & POLLOUT) {
265 if (conf.verbose) {
266 dolog ("POLLOUT %d %d\n", i, pfds[i].fd);
267 }
268 err = qemu_set_fd_handler (pfds[i].fd, NULL,
269 alsa_poll_handler, hlp);
270 }
271 if (conf.verbose) {
272 dolog ("Set handler events=%#x index=%d fd=%d err=%d\n",
273 pfds[i].events, i, pfds[i].fd, err);
274 }
275
276 if (err) {
277 dolog ("Failed to set handler events=%#x index=%d fd=%d err=%d\n",
278 pfds[i].events, i, pfds[i].fd, err);
279
280 while (i--) {
281 qemu_set_fd_handler (pfds[i].fd, NULL, NULL, NULL);
282 }
283 qemu_free (pfds);
284 return -1;
285 }
286 }
287 hlp->pfds = pfds;
288 hlp->count = count;
289 hlp->handle = handle;
290 return 0;
291}
292
293static int alsa_poll_out (HWVoiceOut *hw)
294{
295 ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
296
297 return alsa_poll_helper (alsa->handle, &alsa->pollhlp);
298}
299
300static int alsa_poll_in (HWVoiceIn *hw)
301{
302 ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
303
304 return alsa_poll_helper (alsa->handle, &alsa->pollhlp);
305}
306
1d14ffa9
FB
307static int alsa_write (SWVoiceOut *sw, void *buf, int len)
308{
309 return audio_pcm_sw_write (sw, buf, len);
310}
311
ca9cc28c 312static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt)
1d14ffa9
FB
313{
314 switch (fmt) {
315 case AUD_FMT_S8:
316 return SND_PCM_FORMAT_S8;
317
318 case AUD_FMT_U8:
319 return SND_PCM_FORMAT_U8;
320
321 case AUD_FMT_S16:
322 return SND_PCM_FORMAT_S16_LE;
323
324 case AUD_FMT_U16:
325 return SND_PCM_FORMAT_U16_LE;
326
f941aa25
TS
327 case AUD_FMT_S32:
328 return SND_PCM_FORMAT_S32_LE;
329
330 case AUD_FMT_U32:
331 return SND_PCM_FORMAT_U32_LE;
332
1d14ffa9
FB
333 default:
334 dolog ("Internal logic error: Bad audio format %d\n", fmt);
335#ifdef DEBUG_AUDIO
336 abort ();
337#endif
338 return SND_PCM_FORMAT_U8;
339 }
340}
341
ca9cc28c
AZ
342static int alsa_to_audfmt (snd_pcm_format_t alsafmt, audfmt_e *fmt,
343 int *endianness)
1d14ffa9
FB
344{
345 switch (alsafmt) {
346 case SND_PCM_FORMAT_S8:
347 *endianness = 0;
348 *fmt = AUD_FMT_S8;
349 break;
350
351 case SND_PCM_FORMAT_U8:
352 *endianness = 0;
353 *fmt = AUD_FMT_U8;
354 break;
355
356 case SND_PCM_FORMAT_S16_LE:
357 *endianness = 0;
358 *fmt = AUD_FMT_S16;
359 break;
360
361 case SND_PCM_FORMAT_U16_LE:
362 *endianness = 0;
363 *fmt = AUD_FMT_U16;
364 break;
365
366 case SND_PCM_FORMAT_S16_BE:
367 *endianness = 1;
368 *fmt = AUD_FMT_S16;
369 break;
370
371 case SND_PCM_FORMAT_U16_BE:
372 *endianness = 1;
373 *fmt = AUD_FMT_U16;
374 break;
375
f941aa25
TS
376 case SND_PCM_FORMAT_S32_LE:
377 *endianness = 0;
378 *fmt = AUD_FMT_S32;
379 break;
380
381 case SND_PCM_FORMAT_U32_LE:
382 *endianness = 0;
383 *fmt = AUD_FMT_U32;
384 break;
385
386 case SND_PCM_FORMAT_S32_BE:
387 *endianness = 1;
388 *fmt = AUD_FMT_S32;
389 break;
390
391 case SND_PCM_FORMAT_U32_BE:
392 *endianness = 1;
393 *fmt = AUD_FMT_U32;
394 break;
395
1d14ffa9
FB
396 default:
397 dolog ("Unrecognized audio format %d\n", alsafmt);
398 return -1;
399 }
400
401 return 0;
402}
403
1d14ffa9
FB
404static void alsa_dump_info (struct alsa_params_req *req,
405 struct alsa_params_obt *obt)
406{
407 dolog ("parameter | requested value | obtained value\n");
408 dolog ("format | %10d | %10d\n", req->fmt, obt->fmt);
409 dolog ("channels | %10d | %10d\n",
410 req->nchannels, obt->nchannels);
411 dolog ("frequency | %10d | %10d\n", req->freq, obt->freq);
412 dolog ("============================================\n");
413 dolog ("requested: buffer size %d period size %d\n",
414 req->buffer_size, req->period_size);
c0fe3827 415 dolog ("obtained: samples %ld\n", obt->samples);
1d14ffa9 416}
1d14ffa9
FB
417
418static void alsa_set_threshold (snd_pcm_t *handle, snd_pcm_uframes_t threshold)
419{
420 int err;
421 snd_pcm_sw_params_t *sw_params;
422
423 snd_pcm_sw_params_alloca (&sw_params);
424
425 err = snd_pcm_sw_params_current (handle, sw_params);
426 if (err < 0) {
c0fe3827 427 dolog ("Could not fully initialize DAC\n");
1d14ffa9
FB
428 alsa_logerr (err, "Failed to get current software parameters\n");
429 return;
430 }
431
432 err = snd_pcm_sw_params_set_start_threshold (handle, sw_params, threshold);
433 if (err < 0) {
c0fe3827 434 dolog ("Could not fully initialize DAC\n");
1d14ffa9
FB
435 alsa_logerr (err, "Failed to set software threshold to %ld\n",
436 threshold);
437 return;
438 }
439
440 err = snd_pcm_sw_params (handle, sw_params);
441 if (err < 0) {
c0fe3827 442 dolog ("Could not fully initialize DAC\n");
1d14ffa9
FB
443 alsa_logerr (err, "Failed to set software parameters\n");
444 return;
445 }
446}
447
448static int alsa_open (int in, struct alsa_params_req *req,
449 struct alsa_params_obt *obt, snd_pcm_t **handlep)
450{
451 snd_pcm_t *handle;
452 snd_pcm_hw_params_t *hw_params;
60fe76f3 453 int err;
7a24c800 454 int size_in_usec;
60fe76f3 455 unsigned int freq, nchannels;
1d14ffa9 456 const char *pcm_name = in ? conf.pcm_name_in : conf.pcm_name_out;
1d14ffa9
FB
457 snd_pcm_uframes_t obt_buffer_size;
458 const char *typ = in ? "ADC" : "DAC";
ca9cc28c 459 snd_pcm_format_t obtfmt;
1d14ffa9
FB
460
461 freq = req->freq;
1d14ffa9 462 nchannels = req->nchannels;
7a24c800 463 size_in_usec = req->size_in_usec;
1d14ffa9
FB
464
465 snd_pcm_hw_params_alloca (&hw_params);
466
467 err = snd_pcm_open (
468 &handle,
469 pcm_name,
470 in ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
471 SND_PCM_NONBLOCK
472 );
473 if (err < 0) {
474 alsa_logerr2 (err, typ, "Failed to open `%s':\n", pcm_name);
475 return -1;
476 }
477
478 err = snd_pcm_hw_params_any (handle, hw_params);
479 if (err < 0) {
480 alsa_logerr2 (err, typ, "Failed to initialize hardware parameters\n");
481 goto err;
482 }
483
484 err = snd_pcm_hw_params_set_access (
485 handle,
486 hw_params,
487 SND_PCM_ACCESS_RW_INTERLEAVED
488 );
489 if (err < 0) {
490 alsa_logerr2 (err, typ, "Failed to set access type\n");
491 goto err;
492 }
493
494 err = snd_pcm_hw_params_set_format (handle, hw_params, req->fmt);
ca9cc28c 495 if (err < 0 && conf.verbose) {
1d14ffa9 496 alsa_logerr2 (err, typ, "Failed to set format %d\n", req->fmt);
1d14ffa9
FB
497 }
498
499 err = snd_pcm_hw_params_set_rate_near (handle, hw_params, &freq, 0);
500 if (err < 0) {
501 alsa_logerr2 (err, typ, "Failed to set frequency %d\n", req->freq);
502 goto err;
503 }
504
505 err = snd_pcm_hw_params_set_channels_near (
506 handle,
507 hw_params,
508 &nchannels
509 );
510 if (err < 0) {
511 alsa_logerr2 (err, typ, "Failed to set number of channels %d\n",
512 req->nchannels);
513 goto err;
514 }
515
516 if (nchannels != 1 && nchannels != 2) {
517 alsa_logerr2 (err, typ,
518 "Can not handle obtained number of channels %d\n",
519 nchannels);
520 goto err;
521 }
522
7a24c800 523 if (req->buffer_size) {
f3b52983 524 unsigned long obt;
525
7a24c800 526 if (size_in_usec) {
527 int dir = 0;
528 unsigned int btime = req->buffer_size;
1d14ffa9
FB
529
530 err = snd_pcm_hw_params_set_buffer_time_near (
531 handle,
532 hw_params,
7a24c800 533 &btime,
534 &dir
c0fe3827 535 );
f3b52983 536 obt = btime;
1d14ffa9
FB
537 }
538 else {
7a24c800 539 snd_pcm_uframes_t bsize = req->buffer_size;
1d14ffa9 540
7a24c800 541 err = snd_pcm_hw_params_set_buffer_size_near (
542 handle,
543 hw_params,
544 &bsize
545 );
f3b52983 546 obt = bsize;
7a24c800 547 }
548 if (err < 0) {
549 alsa_logerr2 (err, typ, "Failed to set buffer %s to %d\n",
550 size_in_usec ? "time" : "size", req->buffer_size);
551 goto err;
552 }
f3b52983 553
64333899 554 if ((req->override_mask & 2) && (obt - req->buffer_size))
f3b52983 555 dolog ("Requested buffer %s %u was rejected, using %lu\n",
556 size_in_usec ? "time" : "size", req->buffer_size, obt);
7a24c800 557 }
558
559 if (req->period_size) {
f3b52983 560 unsigned long obt;
561
7a24c800 562 if (size_in_usec) {
563 int dir = 0;
564 unsigned int ptime = req->period_size;
1d14ffa9 565
7a24c800 566 err = snd_pcm_hw_params_set_period_time_near (
567 handle,
1d14ffa9 568 hw_params,
7a24c800 569 &ptime,
570 &dir
1d14ffa9 571 );
f3b52983 572 obt = ptime;
7a24c800 573 }
574 else {
a7bb29ba 575 int dir = 0;
7a24c800 576 snd_pcm_uframes_t psize = req->period_size;
1d14ffa9 577
a7bb29ba 578 err = snd_pcm_hw_params_set_period_size_near (
1d14ffa9
FB
579 handle,
580 hw_params,
a7bb29ba 581 &psize,
582 &dir
1d14ffa9 583 );
f3b52983 584 obt = psize;
1d14ffa9 585 }
7a24c800 586
587 if (err < 0) {
588 alsa_logerr2 (err, typ, "Failed to set period %s to %d\n",
589 size_in_usec ? "time" : "size", req->period_size);
590 goto err;
591 }
f3b52983 592
64333899 593 if ((req->override_mask & 1) && (obt - req->period_size))
f3b52983 594 dolog ("Requested period %s %u was rejected, using %lu\n",
595 size_in_usec ? "time" : "size", req->period_size, obt);
1d14ffa9
FB
596 }
597
598 err = snd_pcm_hw_params (handle, hw_params);
599 if (err < 0) {
600 alsa_logerr2 (err, typ, "Failed to apply audio parameters\n");
601 goto err;
602 }
603
604 err = snd_pcm_hw_params_get_buffer_size (hw_params, &obt_buffer_size);
605 if (err < 0) {
606 alsa_logerr2 (err, typ, "Failed to get buffer size\n");
607 goto err;
608 }
609
ca9cc28c
AZ
610 err = snd_pcm_hw_params_get_format (hw_params, &obtfmt);
611 if (err < 0) {
612 alsa_logerr2 (err, typ, "Failed to get format\n");
613 goto err;
614 }
615
616 if (alsa_to_audfmt (obtfmt, &obt->fmt, &obt->endianness)) {
617 dolog ("Invalid format was returned %d\n", obtfmt);
618 goto err;
619 }
620
1d14ffa9
FB
621 err = snd_pcm_prepare (handle);
622 if (err < 0) {
c0fe3827 623 alsa_logerr2 (err, typ, "Could not prepare handle %p\n", handle);
1d14ffa9
FB
624 goto err;
625 }
626
1d14ffa9
FB
627 if (!in && conf.threshold) {
628 snd_pcm_uframes_t threshold;
629 int bytes_per_sec;
630
ca9cc28c
AZ
631 bytes_per_sec = freq << (nchannels == 2);
632
633 switch (obt->fmt) {
634 case AUD_FMT_S8:
635 case AUD_FMT_U8:
636 break;
637
638 case AUD_FMT_S16:
639 case AUD_FMT_U16:
640 bytes_per_sec <<= 1;
641 break;
642
643 case AUD_FMT_S32:
644 case AUD_FMT_U32:
645 bytes_per_sec <<= 2;
646 break;
647 }
1d14ffa9
FB
648
649 threshold = (conf.threshold * bytes_per_sec) / 1000;
650 alsa_set_threshold (handle, threshold);
651 }
652
1d14ffa9
FB
653 obt->nchannels = nchannels;
654 obt->freq = freq;
c0fe3827 655 obt->samples = obt_buffer_size;
ca9cc28c 656
1d14ffa9
FB
657 *handlep = handle;
658
ca9cc28c
AZ
659 if (conf.verbose &&
660 (obt->fmt != req->fmt ||
661 obt->nchannels != req->nchannels ||
662 obt->freq != req->freq)) {
663 dolog ("Audio paramters for %s\n", typ);
1d14ffa9 664 alsa_dump_info (req, obt);
1d14ffa9
FB
665 }
666
667#ifdef DEBUG
668 alsa_dump_info (req, obt);
669#endif
670 return 0;
671
672 err:
6ebfda13 673 alsa_anal_close1 (&handle);
1d14ffa9
FB
674 return -1;
675}
676
571ec3d6
FB
677static snd_pcm_sframes_t alsa_get_avail (snd_pcm_t *handle)
678{
679 snd_pcm_sframes_t avail;
680
681 avail = snd_pcm_avail_update (handle);
682 if (avail < 0) {
683 if (avail == -EPIPE) {
684 if (!alsa_recover (handle)) {
685 avail = snd_pcm_avail_update (handle);
686 }
687 }
688
689 if (avail < 0) {
690 alsa_logerr (avail,
691 "Could not obtain number of available frames\n");
692 return -1;
693 }
694 }
695
696 return avail;
697}
698
1d14ffa9
FB
699static int alsa_run_out (HWVoiceOut *hw)
700{
701 ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
702 int rpos, live, decr;
703 int samples;
704 uint8_t *dst;
1ea879e5 705 struct st_sample *src;
1d14ffa9
FB
706 snd_pcm_sframes_t avail;
707
708 live = audio_pcm_hw_get_live_out (hw);
709 if (!live) {
710 return 0;
711 }
712
571ec3d6 713 avail = alsa_get_avail (alsa->handle);
1d14ffa9 714 if (avail < 0) {
571ec3d6 715 dolog ("Could not get number of available playback frames\n");
1d14ffa9
FB
716 return 0;
717 }
718
1d14ffa9
FB
719 decr = audio_MIN (live, avail);
720 samples = decr;
721 rpos = hw->rpos;
722 while (samples) {
723 int left_till_end_samples = hw->samples - rpos;
571ec3d6 724 int len = audio_MIN (samples, left_till_end_samples);
1d14ffa9
FB
725 snd_pcm_sframes_t written;
726
727 src = hw->mix_buf + rpos;
728 dst = advance (alsa->pcm_buf, rpos << hw->info.shift);
729
571ec3d6 730 hw->clip (dst, src, len);
1d14ffa9 731
571ec3d6
FB
732 while (len) {
733 written = snd_pcm_writei (alsa->handle, dst, len);
4787c71d 734
571ec3d6 735 if (written <= 0) {
4787c71d 736 switch (written) {
571ec3d6
FB
737 case 0:
738 if (conf.verbose) {
739 dolog ("Failed to write %d frames (wrote zero)\n", len);
4787c71d 740 }
4787c71d
FB
741 goto exit;
742
571ec3d6
FB
743 case -EPIPE:
744 if (alsa_recover (alsa->handle)) {
745 alsa_logerr (written, "Failed to write %d frames\n",
746 len);
747 goto exit;
748 }
749 if (conf.verbose) {
750 dolog ("Recovering from playback xrun\n");
751 }
4787c71d
FB
752 continue;
753
86635821
BM
754 case -ESTRPIPE:
755 /* stream is suspended and waiting for an
756 application recovery */
757 if (alsa_resume (alsa->handle)) {
758 alsa_logerr (written, "Failed to write %d frames\n",
759 len);
760 goto exit;
761 }
762 if (conf.verbose) {
763 dolog ("Resuming suspended output stream\n");
764 }
765 continue;
766
571ec3d6
FB
767 case -EAGAIN:
768 goto exit;
769
4787c71d
FB
770 default:
771 alsa_logerr (written, "Failed to write %d frames to %p\n",
571ec3d6 772 len, dst);
4787c71d 773 goto exit;
1d14ffa9 774 }
1d14ffa9 775 }
1d14ffa9 776
4787c71d
FB
777 rpos = (rpos + written) % hw->samples;
778 samples -= written;
571ec3d6 779 len -= written;
4787c71d
FB
780 dst = advance (dst, written << hw->info.shift);
781 src += written;
782 }
1d14ffa9
FB
783 }
784
785 exit:
786 hw->rpos = rpos;
787 return decr;
788}
789
790static void alsa_fini_out (HWVoiceOut *hw)
791{
792 ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
793
794 ldebug ("alsa_fini\n");
6ebfda13 795 alsa_anal_close (&alsa->handle, &alsa->pollhlp);
1d14ffa9
FB
796
797 if (alsa->pcm_buf) {
798 qemu_free (alsa->pcm_buf);
799 alsa->pcm_buf = NULL;
800 }
801}
802
1ea879e5 803static int alsa_init_out (HWVoiceOut *hw, struct audsettings *as)
1d14ffa9
FB
804{
805 ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
806 struct alsa_params_req req;
807 struct alsa_params_obt obt;
1d14ffa9 808 snd_pcm_t *handle;
1ea879e5 809 struct audsettings obt_as;
1d14ffa9 810
c0fe3827
FB
811 req.fmt = aud_to_alsafmt (as->fmt);
812 req.freq = as->freq;
813 req.nchannels = as->nchannels;
1d14ffa9
FB
814 req.period_size = conf.period_size_out;
815 req.buffer_size = conf.buffer_size_out;
23fb600b 816 req.size_in_usec = conf.size_in_usec_out;
97f155dd
GH
817 req.override_mask =
818 (conf.period_size_out_overridden ? 1 : 0) |
819 (conf.buffer_size_out_overridden ? 2 : 0);
1d14ffa9
FB
820
821 if (alsa_open (0, &req, &obt, &handle)) {
822 return -1;
823 }
824
c0fe3827
FB
825 obt_as.freq = obt.freq;
826 obt_as.nchannels = obt.nchannels;
ca9cc28c
AZ
827 obt_as.fmt = obt.fmt;
828 obt_as.endianness = obt.endianness;
c0fe3827 829
d929eba5 830 audio_pcm_init_info (&hw->info, &obt_as);
c0fe3827 831 hw->samples = obt.samples;
1d14ffa9 832
c0fe3827 833 alsa->pcm_buf = audio_calloc (AUDIO_FUNC, obt.samples, 1 << hw->info.shift);
1d14ffa9 834 if (!alsa->pcm_buf) {
4787c71d
FB
835 dolog ("Could not allocate DAC buffer (%d samples, each %d bytes)\n",
836 hw->samples, 1 << hw->info.shift);
6ebfda13 837 alsa_anal_close1 (&handle);
1d14ffa9
FB
838 return -1;
839 }
840
841 alsa->handle = handle;
1d14ffa9
FB
842 return 0;
843}
844
571ec3d6 845static int alsa_voice_ctl (snd_pcm_t *handle, const char *typ, int pause)
1d14ffa9
FB
846{
847 int err;
571ec3d6
FB
848
849 if (pause) {
850 err = snd_pcm_drop (handle);
851 if (err < 0) {
32d448c4 852 alsa_logerr (err, "Could not stop %s\n", typ);
571ec3d6
FB
853 return -1;
854 }
855 }
856 else {
857 err = snd_pcm_prepare (handle);
858 if (err < 0) {
32d448c4 859 alsa_logerr (err, "Could not prepare handle for %s\n", typ);
571ec3d6
FB
860 return -1;
861 }
862 }
863
864 return 0;
865}
866
867static int alsa_ctl_out (HWVoiceOut *hw, int cmd, ...)
868{
8b438ba3 869 va_list ap;
870 int poll_mode;
1d14ffa9
FB
871 ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
872
8b438ba3 873 va_start (ap, cmd);
874 poll_mode = va_arg (ap, int);
875 va_end (ap);
876
1d14ffa9
FB
877 switch (cmd) {
878 case VOICE_ENABLE:
879 ldebug ("enabling voice\n");
8b438ba3 880 if (poll_mode && alsa_poll_out (hw)) {
881 poll_mode = 0;
882 }
883 hw->poll_mode = poll_mode;
571ec3d6 884 return alsa_voice_ctl (alsa->handle, "playback", 0);
1d14ffa9
FB
885
886 case VOICE_DISABLE:
887 ldebug ("disabling voice\n");
571ec3d6 888 return alsa_voice_ctl (alsa->handle, "playback", 1);
1d14ffa9 889 }
571ec3d6
FB
890
891 return -1;
1d14ffa9
FB
892}
893
1ea879e5 894static int alsa_init_in (HWVoiceIn *hw, struct audsettings *as)
1d14ffa9
FB
895{
896 ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
897 struct alsa_params_req req;
898 struct alsa_params_obt obt;
1d14ffa9 899 snd_pcm_t *handle;
1ea879e5 900 struct audsettings obt_as;
1d14ffa9 901
c0fe3827
FB
902 req.fmt = aud_to_alsafmt (as->fmt);
903 req.freq = as->freq;
904 req.nchannels = as->nchannels;
1d14ffa9
FB
905 req.period_size = conf.period_size_in;
906 req.buffer_size = conf.buffer_size_in;
7a24c800 907 req.size_in_usec = conf.size_in_usec_in;
97f155dd
GH
908 req.override_mask =
909 (conf.period_size_in_overridden ? 1 : 0) |
910 (conf.buffer_size_in_overridden ? 2 : 0);
1d14ffa9
FB
911
912 if (alsa_open (1, &req, &obt, &handle)) {
913 return -1;
914 }
915
c0fe3827
FB
916 obt_as.freq = obt.freq;
917 obt_as.nchannels = obt.nchannels;
ca9cc28c
AZ
918 obt_as.fmt = obt.fmt;
919 obt_as.endianness = obt.endianness;
c0fe3827 920
d929eba5 921 audio_pcm_init_info (&hw->info, &obt_as);
c0fe3827
FB
922 hw->samples = obt.samples;
923
924 alsa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
1d14ffa9 925 if (!alsa->pcm_buf) {
4787c71d
FB
926 dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
927 hw->samples, 1 << hw->info.shift);
6ebfda13 928 alsa_anal_close1 (&handle);
1d14ffa9
FB
929 return -1;
930 }
931
932 alsa->handle = handle;
933 return 0;
934}
935
936static void alsa_fini_in (HWVoiceIn *hw)
937{
938 ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
939
6ebfda13 940 alsa_anal_close (&alsa->handle, &alsa->pollhlp);
1d14ffa9
FB
941
942 if (alsa->pcm_buf) {
943 qemu_free (alsa->pcm_buf);
944 alsa->pcm_buf = NULL;
945 }
946}
947
948static int alsa_run_in (HWVoiceIn *hw)
949{
950 ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
951 int hwshift = hw->info.shift;
952 int i;
953 int live = audio_pcm_hw_get_live_in (hw);
954 int dead = hw->samples - live;
571ec3d6 955 int decr;
1d14ffa9
FB
956 struct {
957 int add;
958 int len;
959 } bufs[2] = {
98f9f48c 960 { .add = hw->wpos, .len = 0 },
961 { .add = 0, .len = 0 }
1d14ffa9 962 };
571ec3d6 963 snd_pcm_sframes_t avail;
1d14ffa9
FB
964 snd_pcm_uframes_t read_samples = 0;
965
966 if (!dead) {
967 return 0;
968 }
969
571ec3d6
FB
970 avail = alsa_get_avail (alsa->handle);
971 if (avail < 0) {
972 dolog ("Could not get number of captured frames\n");
973 return 0;
974 }
975
86635821
BM
976 if (!avail) {
977 snd_pcm_state_t state;
978
979 state = snd_pcm_state (alsa->handle);
980 switch (state) {
981 case SND_PCM_STATE_PREPARED:
982 avail = hw->samples;
983 break;
984 case SND_PCM_STATE_SUSPENDED:
985 /* stream is suspended and waiting for an application recovery */
986 if (alsa_resume (alsa->handle)) {
987 dolog ("Failed to resume suspended input stream\n");
988 return 0;
989 }
990 if (conf.verbose) {
991 dolog ("Resuming suspended input stream\n");
992 }
993 break;
994 default:
995 if (conf.verbose) {
996 dolog ("No frames available and ALSA state is %d\n", state);
997 }
998 return 0;
999 }
571ec3d6
FB
1000 }
1001
1002 decr = audio_MIN (dead, avail);
1003 if (!decr) {
1004 return 0;
1005 }
1006
1007 if (hw->wpos + decr > hw->samples) {
1d14ffa9 1008 bufs[0].len = (hw->samples - hw->wpos);
571ec3d6 1009 bufs[1].len = (decr - (hw->samples - hw->wpos));
1d14ffa9
FB
1010 }
1011 else {
571ec3d6 1012 bufs[0].len = decr;
1d14ffa9
FB
1013 }
1014
1d14ffa9
FB
1015 for (i = 0; i < 2; ++i) {
1016 void *src;
1ea879e5 1017 struct st_sample *dst;
1d14ffa9
FB
1018 snd_pcm_sframes_t nread;
1019 snd_pcm_uframes_t len;
1020
1021 len = bufs[i].len;
1022
1023 src = advance (alsa->pcm_buf, bufs[i].add << hwshift);
1024 dst = hw->conv_buf + bufs[i].add;
1025
1026 while (len) {
1027 nread = snd_pcm_readi (alsa->handle, src, len);
1028
571ec3d6 1029 if (nread <= 0) {
1d14ffa9 1030 switch (nread) {
571ec3d6
FB
1031 case 0:
1032 if (conf.verbose) {
1033 dolog ("Failed to read %ld frames (read zero)\n", len);
1d14ffa9 1034 }
1d14ffa9
FB
1035 goto exit;
1036
571ec3d6
FB
1037 case -EPIPE:
1038 if (alsa_recover (alsa->handle)) {
1039 alsa_logerr (nread, "Failed to read %ld frames\n", len);
1040 goto exit;
1041 }
1042 if (conf.verbose) {
1043 dolog ("Recovering from capture xrun\n");
1044 }
1d14ffa9
FB
1045 continue;
1046
571ec3d6
FB
1047 case -EAGAIN:
1048 goto exit;
1049
1d14ffa9
FB
1050 default:
1051 alsa_logerr (
1052 nread,
1053 "Failed to read %ld frames from %p\n",
1054 len,
1055 src
1056 );
1057 goto exit;
1058 }
1059 }
1060
1061 hw->conv (dst, src, nread, &nominal_volume);
1062
1063 src = advance (src, nread << hwshift);
1064 dst += nread;
1065
1066 read_samples += nread;
1067 len -= nread;
1068 }
1069 }
1070
1071 exit:
1072 hw->wpos = (hw->wpos + read_samples) % hw->samples;
1073 return read_samples;
1074}
1075
1076static int alsa_read (SWVoiceIn *sw, void *buf, int size)
1077{
1078 return audio_pcm_sw_read (sw, buf, size);
1079}
1080
1081static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...)
1082{
8b438ba3 1083 va_list ap;
1084 int poll_mode;
571ec3d6
FB
1085 ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
1086
8b438ba3 1087 va_start (ap, cmd);
1088 poll_mode = va_arg (ap, int);
1089 va_end (ap);
1090
571ec3d6
FB
1091 switch (cmd) {
1092 case VOICE_ENABLE:
1093 ldebug ("enabling voice\n");
8b438ba3 1094 if (poll_mode && alsa_poll_in (hw)) {
1095 poll_mode = 0;
1096 }
1097 hw->poll_mode = poll_mode;
1098
571ec3d6
FB
1099 return alsa_voice_ctl (alsa->handle, "capture", 0);
1100
1101 case VOICE_DISABLE:
1102 ldebug ("disabling voice\n");
8b438ba3 1103 if (hw->poll_mode) {
1104 hw->poll_mode = 0;
1105 alsa_fini_poll (&alsa->pollhlp);
1106 }
571ec3d6
FB
1107 return alsa_voice_ctl (alsa->handle, "capture", 1);
1108 }
1109
1110 return -1;
1d14ffa9
FB
1111}
1112
1113static void *alsa_audio_init (void)
1114{
1115 return &conf;
1116}
1117
1118static void alsa_audio_fini (void *opaque)
1119{
1120 (void) opaque;
1121}
1122
1123static struct audio_option alsa_options[] = {
98f9f48c 1124 {
1125 .name = "DAC_SIZE_IN_USEC",
1126 .tag = AUD_OPT_BOOL,
1127 .valp = &conf.size_in_usec_out,
1128 .descr = "DAC period/buffer size in microseconds (otherwise in frames)"
1129 },
1130 {
1131 .name = "DAC_PERIOD_SIZE",
1132 .tag = AUD_OPT_INT,
1133 .valp = &conf.period_size_out,
1134 .descr = "DAC period size (0 to go with system default)",
1135 .overriddenp = &conf.period_size_out_overridden
1136 },
1137 {
1138 .name = "DAC_BUFFER_SIZE",
1139 .tag = AUD_OPT_INT,
1140 .valp = &conf.buffer_size_out,
1141 .descr = "DAC buffer size (0 to go with system default)",
1142 .overriddenp = &conf.buffer_size_out_overridden
1143 },
1144 {
1145 .name = "ADC_SIZE_IN_USEC",
1146 .tag = AUD_OPT_BOOL,
1147 .valp = &conf.size_in_usec_in,
1148 .descr =
1149 "ADC period/buffer size in microseconds (otherwise in frames)"
1150 },
1151 {
1152 .name = "ADC_PERIOD_SIZE",
1153 .tag = AUD_OPT_INT,
1154 .valp = &conf.period_size_in,
1155 .descr = "ADC period size (0 to go with system default)",
1156 .overriddenp = &conf.period_size_in_overridden
1157 },
1158 {
1159 .name = "ADC_BUFFER_SIZE",
1160 .tag = AUD_OPT_INT,
1161 .valp = &conf.buffer_size_in,
1162 .descr = "ADC buffer size (0 to go with system default)",
1163 .overriddenp = &conf.buffer_size_in_overridden
1164 },
1165 {
1166 .name = "THRESHOLD",
1167 .tag = AUD_OPT_INT,
1168 .valp = &conf.threshold,
1169 .descr = "(undocumented)"
1170 },
1171 {
1172 .name = "DAC_DEV",
1173 .tag = AUD_OPT_STR,
1174 .valp = &conf.pcm_name_out,
1175 .descr = "DAC device name (for instance dmix)"
1176 },
1177 {
1178 .name = "ADC_DEV",
1179 .tag = AUD_OPT_STR,
1180 .valp = &conf.pcm_name_in,
1181 .descr = "ADC device name"
1182 },
1183 {
1184 .name = "VERBOSE",
1185 .tag = AUD_OPT_BOOL,
1186 .valp = &conf.verbose,
1187 .descr = "Behave in a more verbose way"
1188 },
2700efa3 1189 { /* End of list */ }
1d14ffa9
FB
1190};
1191
35f4b58c 1192static struct audio_pcm_ops alsa_pcm_ops = {
1dd3e4d1
JQ
1193 .init_out = alsa_init_out,
1194 .fini_out = alsa_fini_out,
1195 .run_out = alsa_run_out,
1196 .write = alsa_write,
1197 .ctl_out = alsa_ctl_out,
1198
1199 .init_in = alsa_init_in,
1200 .fini_in = alsa_fini_in,
1201 .run_in = alsa_run_in,
1202 .read = alsa_read,
8b438ba3 1203 .ctl_in = alsa_ctl_in,
1d14ffa9
FB
1204};
1205
1206struct audio_driver alsa_audio_driver = {
bee37f32
JQ
1207 .name = "alsa",
1208 .descr = "ALSA http://www.alsa-project.org",
1209 .options = alsa_options,
1210 .init = alsa_audio_init,
1211 .fini = alsa_audio_fini,
1212 .pcm_ops = &alsa_pcm_ops,
1213 .can_be_default = 1,
1214 .max_voices_out = INT_MAX,
1215 .max_voices_in = INT_MAX,
1216 .voice_size_out = sizeof (ALSAVoiceOut),
1217 .voice_size_in = sizeof (ALSAVoiceIn)
1d14ffa9 1218};