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