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