|
|
1.1 root 1: /*
2: * QEMU Audio subsystem
1.1.1.2 root 3: *
4: * Copyright (c) 2003-2005 Vassili Karpov (malc)
5: *
1.1 root 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 "vl.h"
25:
1.1.1.2 root 26: #define AUDIO_CAP "audio"
27: #include "audio_int.h"
1.1 root 28:
1.1.1.2 root 29: /* #define DEBUG_PLIVE */
30: /* #define DEBUG_LIVE */
31: /* #define DEBUG_OUT */
1.1.1.3 ! root 32: /* #define DEBUG_CAPTURE */
1.1 root 33:
1.1.1.2 root 34: #define SW_NAME(sw) (sw)->name ? (sw)->name : "unknown"
35:
36: static struct audio_driver *drvtab[] = {
37: #ifdef CONFIG_OSS
38: &oss_audio_driver,
39: #endif
40: #ifdef CONFIG_ALSA
41: &alsa_audio_driver,
42: #endif
43: #ifdef CONFIG_COREAUDIO
44: &coreaudio_audio_driver,
45: #endif
46: #ifdef CONFIG_DSOUND
47: &dsound_audio_driver,
48: #endif
49: #ifdef CONFIG_FMOD
50: &fmod_audio_driver,
1.1 root 51: #endif
1.1.1.2 root 52: #ifdef CONFIG_SDL
53: &sdl_audio_driver,
54: #endif
55: &no_audio_driver,
56: &wav_audio_driver
57: };
58:
59: struct fixed_settings {
60: int enabled;
61: int nb_voices;
62: int greedy;
63: audsettings_t settings;
64: };
65:
66: static struct {
67: struct fixed_settings fixed_out;
68: struct fixed_settings fixed_in;
69: union {
70: int hz;
71: int64_t ticks;
72: } period;
73: int plive;
74: int log_to_monitor;
75: } conf = {
76: { /* DAC fixed settings */
77: 1, /* enabled */
78: 1, /* nb_voices */
79: 1, /* greedy */
80: {
81: 44100, /* freq */
82: 2, /* nchannels */
83: AUD_FMT_S16 /* fmt */
84: }
85: },
86:
87: { /* ADC fixed settings */
88: 1, /* enabled */
89: 1, /* nb_voices */
90: 1, /* greedy */
91: {
92: 44100, /* freq */
93: 2, /* nchannels */
94: AUD_FMT_S16 /* fmt */
95: }
96: },
97:
98: { 0 }, /* period */
99: 0, /* plive */
100: 0 /* log_to_monitor */
101: };
1.1 root 102:
1.1.1.2 root 103: static AudioState glob_audio_state;
104:
105: volume_t nominal_volume = {
106: 0,
107: #ifdef FLOAT_MIXENG
108: 1.0,
109: 1.0
110: #else
111: UINT_MAX,
112: UINT_MAX
113: #endif
1.1 root 114: };
115:
116: /* http://www.df.lth.se/~john_e/gems/gem002d.html */
117: /* http://www.multi-platforms.com/Tips/PopCount.htm */
118: uint32_t popcount (uint32_t u)
119: {
120: u = ((u&0x55555555) + ((u>>1)&0x55555555));
121: u = ((u&0x33333333) + ((u>>2)&0x33333333));
122: u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f));
123: u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff));
124: u = ( u&0x0000ffff) + (u>>16);
125: return u;
126: }
127:
128: inline uint32_t lsbindex (uint32_t u)
129: {
130: return popcount ((u&-u)-1);
131: }
132:
1.1.1.2 root 133: #ifdef AUDIO_IS_FLAWLESS_AND_NO_CHECKS_ARE_REQURIED
134: #error No its not
135: #else
136: int audio_bug (const char *funcname, int cond)
137: {
138: if (cond) {
139: static int shown;
140:
1.1.1.3 ! root 141: AUD_log (NULL, "A bug was just triggered in %s\n", funcname);
1.1.1.2 root 142: if (!shown) {
143: shown = 1;
144: AUD_log (NULL, "Save all your work and restart without audio\n");
145: AUD_log (NULL, "Please send bug report to [email protected]\n");
146: AUD_log (NULL, "I am sorry\n");
147: }
148: AUD_log (NULL, "Context:\n");
149:
150: #if defined AUDIO_BREAKPOINT_ON_BUG
151: # if defined HOST_I386
152: # if defined __GNUC__
153: __asm__ ("int3");
154: # elif defined _MSC_VER
155: _asm _emit 0xcc;
156: # else
157: abort ();
158: # endif
159: # else
160: abort ();
161: # endif
162: #endif
163: }
164:
165: return cond;
166: }
167: #endif
168:
169: void *audio_calloc (const char *funcname, int nmemb, size_t size)
170: {
171: int cond;
172: size_t len;
173:
174: len = nmemb * size;
175: cond = !nmemb || !size;
176: cond |= nmemb < 0;
177: cond |= len < size;
178:
179: if (audio_bug ("audio_calloc", cond)) {
180: AUD_log (NULL, "%s passed invalid arguments to audio_calloc\n",
181: funcname);
182: AUD_log (NULL, "nmemb=%d size=%zu (len=%zu)\n", nmemb, size, len);
183: return NULL;
184: }
185:
186: return qemu_mallocz (len);
187: }
188:
189: static char *audio_alloc_prefix (const char *s)
1.1 root 190: {
1.1.1.2 root 191: const char qemu_prefix[] = "QEMU_";
192: size_t len;
193: char *r;
194:
195: if (!s) {
196: return NULL;
197: }
198:
199: len = strlen (s);
200: r = qemu_malloc (len + sizeof (qemu_prefix));
201:
202: if (r) {
203: size_t i;
204: char *u = r + sizeof (qemu_prefix) - 1;
205:
206: strcpy (r, qemu_prefix);
207: strcat (r, s);
208:
209: for (i = 0; i < len; ++i) {
210: u[i] = toupper (u[i]);
211: }
212: }
213: return r;
214: }
215:
216: const char *audio_audfmt_to_string (audfmt_e fmt)
217: {
218: switch (fmt) {
219: case AUD_FMT_U8:
220: return "U8";
221:
222: case AUD_FMT_U16:
223: return "U16";
224:
225: case AUD_FMT_S8:
226: return "S8";
227:
228: case AUD_FMT_S16:
229: return "S16";
230: }
231:
232: dolog ("Bogus audfmt %d returning S16\n", fmt);
233: return "S16";
234: }
235:
236: audfmt_e audio_string_to_audfmt (const char *s, audfmt_e defval, int *defaultp)
237: {
238: if (!strcasecmp (s, "u8")) {
239: *defaultp = 0;
240: return AUD_FMT_U8;
241: }
242: else if (!strcasecmp (s, "u16")) {
243: *defaultp = 0;
244: return AUD_FMT_U16;
245: }
246: else if (!strcasecmp (s, "s8")) {
247: *defaultp = 0;
248: return AUD_FMT_S8;
249: }
250: else if (!strcasecmp (s, "s16")) {
251: *defaultp = 0;
252: return AUD_FMT_S16;
253: }
254: else {
255: dolog ("Bogus audio format `%s' using %s\n",
256: s, audio_audfmt_to_string (defval));
257: *defaultp = 1;
258: return defval;
259: }
260: }
261:
262: static audfmt_e audio_get_conf_fmt (const char *envname,
263: audfmt_e defval,
264: int *defaultp)
265: {
266: const char *var = getenv (envname);
267: if (!var) {
268: *defaultp = 1;
269: return defval;
270: }
271: return audio_string_to_audfmt (var, defval, defaultp);
272: }
273:
274: static int audio_get_conf_int (const char *key, int defval, int *defaultp)
275: {
276: int val;
1.1 root 277: char *strval;
278:
279: strval = getenv (key);
280: if (strval) {
1.1.1.2 root 281: *defaultp = 0;
1.1 root 282: val = atoi (strval);
1.1.1.2 root 283: return val;
284: }
285: else {
286: *defaultp = 1;
287: return defval;
1.1 root 288: }
289: }
290:
1.1.1.2 root 291: static const char *audio_get_conf_str (const char *key,
292: const char *defval,
293: int *defaultp)
1.1 root 294: {
295: const char *val = getenv (key);
1.1.1.2 root 296: if (!val) {
297: *defaultp = 1;
1.1 root 298: return defval;
1.1.1.2 root 299: }
300: else {
301: *defaultp = 0;
1.1 root 302: return val;
1.1.1.2 root 303: }
304: }
305:
306: void AUD_vlog (const char *cap, const char *fmt, va_list ap)
307: {
308: if (conf.log_to_monitor) {
309: if (cap) {
310: term_printf ("%s: ", cap);
311: }
312:
313: term_vprintf (fmt, ap);
314: }
315: else {
316: if (cap) {
317: fprintf (stderr, "%s: ", cap);
318: }
319:
320: vfprintf (stderr, fmt, ap);
321: }
1.1 root 322: }
323:
324: void AUD_log (const char *cap, const char *fmt, ...)
325: {
326: va_list ap;
1.1.1.2 root 327:
1.1 root 328: va_start (ap, fmt);
1.1.1.2 root 329: AUD_vlog (cap, fmt, ap);
1.1 root 330: va_end (ap);
331: }
332:
1.1.1.2 root 333: static void audio_print_options (const char *prefix,
334: struct audio_option *opt)
1.1 root 335: {
1.1.1.2 root 336: char *uprefix;
337:
338: if (!prefix) {
339: dolog ("No prefix specified\n");
340: return;
341: }
342:
343: if (!opt) {
344: dolog ("No options\n");
345: return;
346: }
347:
348: uprefix = audio_alloc_prefix (prefix);
349:
350: for (; opt->name; opt++) {
351: const char *state = "default";
352: printf (" %s_%s: ", uprefix, opt->name);
353:
354: if (opt->overridenp && *opt->overridenp) {
355: state = "current";
356: }
357:
358: switch (opt->tag) {
359: case AUD_OPT_BOOL:
360: {
361: int *intp = opt->valp;
362: printf ("boolean, %s = %d\n", state, *intp ? 1 : 0);
363: }
364: break;
365:
366: case AUD_OPT_INT:
367: {
368: int *intp = opt->valp;
369: printf ("integer, %s = %d\n", state, *intp);
370: }
371: break;
372:
373: case AUD_OPT_FMT:
374: {
375: audfmt_e *fmtp = opt->valp;
376: printf (
377: "format, %s = %s, (one of: U8 S8 U16 S16)\n",
378: state,
379: audio_audfmt_to_string (*fmtp)
380: );
381: }
382: break;
383:
384: case AUD_OPT_STR:
385: {
386: const char **strp = opt->valp;
387: printf ("string, %s = %s\n",
388: state,
389: *strp ? *strp : "(not set)");
390: }
391: break;
392:
393: default:
394: printf ("???\n");
395: dolog ("Bad value tag for option %s_%s %d\n",
396: uprefix, opt->name, opt->tag);
397: break;
398: }
399: printf (" %s\n", opt->descr);
400: }
401:
402: qemu_free (uprefix);
1.1 root 403: }
404:
1.1.1.2 root 405: static void audio_process_options (const char *prefix,
406: struct audio_option *opt)
1.1 root 407: {
1.1.1.2 root 408: char *optname;
409: const char qemu_prefix[] = "QEMU_";
410: size_t preflen;
411:
412: if (audio_bug (AUDIO_FUNC, !prefix)) {
413: dolog ("prefix = NULL\n");
414: return;
415: }
416:
417: if (audio_bug (AUDIO_FUNC, !opt)) {
418: dolog ("opt = NULL\n");
419: return;
420: }
421:
422: preflen = strlen (prefix);
423:
424: for (; opt->name; opt++) {
425: size_t len, i;
426: int def;
427:
428: if (!opt->valp) {
429: dolog ("Option value pointer for `%s' is not set\n",
430: opt->name);
431: continue;
432: }
433:
434: len = strlen (opt->name);
435: /* len of opt->name + len of prefix + size of qemu_prefix
436: * (includes trailing zero) + zero + underscore (on behalf of
437: * sizeof) */
438: optname = qemu_malloc (len + preflen + sizeof (qemu_prefix) + 1);
439: if (!optname) {
440: dolog ("Could not allocate memory for option name `%s'\n",
441: opt->name);
442: continue;
443: }
444:
445: strcpy (optname, qemu_prefix);
446:
447: /* copy while upper-casing, including trailing zero */
448: for (i = 0; i <= preflen; ++i) {
449: optname[i + sizeof (qemu_prefix) - 1] = toupper (prefix[i]);
450: }
451: strcat (optname, "_");
452: strcat (optname, opt->name);
453:
454: def = 1;
455: switch (opt->tag) {
456: case AUD_OPT_BOOL:
457: case AUD_OPT_INT:
458: {
459: int *intp = opt->valp;
460: *intp = audio_get_conf_int (optname, *intp, &def);
461: }
462: break;
463:
464: case AUD_OPT_FMT:
465: {
466: audfmt_e *fmtp = opt->valp;
467: *fmtp = audio_get_conf_fmt (optname, *fmtp, &def);
468: }
469: break;
470:
471: case AUD_OPT_STR:
472: {
473: const char **strp = opt->valp;
474: *strp = audio_get_conf_str (optname, *strp, &def);
475: }
476: break;
1.1 root 477:
1.1.1.2 root 478: default:
479: dolog ("Bad value tag for option `%s' - %d\n",
480: optname, opt->tag);
481: break;
482: }
483:
484: if (!opt->overridenp) {
485: opt->overridenp = &opt->overriden;
486: }
487: *opt->overridenp = !def;
488: qemu_free (optname);
489: }
490: }
491:
492: static void audio_print_settings (audsettings_t *as)
493: {
494: dolog ("frequency=%d nchannels=%d fmt=", as->freq, as->nchannels);
495:
496: switch (as->fmt) {
497: case AUD_FMT_S8:
498: AUD_log (NULL, "S8");
499: break;
500: case AUD_FMT_U8:
501: AUD_log (NULL, "U8");
502: break;
503: case AUD_FMT_S16:
504: AUD_log (NULL, "S16");
505: break;
506: case AUD_FMT_U16:
507: AUD_log (NULL, "U16");
508: break;
509: default:
510: AUD_log (NULL, "invalid(%d)", as->fmt);
511: break;
512: }
1.1.1.3 ! root 513:
! 514: AUD_log (NULL, " endianness=");
! 515: switch (as->endianness) {
! 516: case 0:
! 517: AUD_log (NULL, "little");
! 518: break;
! 519: case 1:
! 520: AUD_log (NULL, "big");
! 521: break;
! 522: default:
! 523: AUD_log (NULL, "invalid");
! 524: break;
! 525: }
1.1.1.2 root 526: AUD_log (NULL, "\n");
527: }
528:
1.1.1.3 ! root 529: static int audio_validate_settings (audsettings_t *as)
1.1.1.2 root 530: {
531: int invalid;
532:
533: invalid = as->nchannels != 1 && as->nchannels != 2;
1.1.1.3 ! root 534: invalid |= as->endianness != 0 && as->endianness != 1;
1.1.1.2 root 535:
536: switch (as->fmt) {
537: case AUD_FMT_S8:
538: case AUD_FMT_U8:
539: case AUD_FMT_S16:
540: case AUD_FMT_U16:
541: break;
542: default:
543: invalid = 1;
544: break;
545: }
546:
547: invalid |= as->freq <= 0;
1.1.1.3 ! root 548: return invalid ? -1 : 0;
1.1 root 549: }
550:
1.1.1.2 root 551: static int audio_pcm_info_eq (struct audio_pcm_info *info, audsettings_t *as)
1.1 root 552: {
1.1.1.2 root 553: int bits = 8, sign = 0;
554:
555: switch (as->fmt) {
556: case AUD_FMT_S8:
557: sign = 1;
558: case AUD_FMT_U8:
559: break;
560:
561: case AUD_FMT_S16:
562: sign = 1;
563: case AUD_FMT_U16:
564: bits = 16;
565: break;
566: }
567: return info->freq == as->freq
568: && info->nchannels == as->nchannels
569: && info->sign == sign
1.1.1.3 ! root 570: && info->bits == bits
! 571: && info->swap_endianness == (as->endianness != AUDIO_HOST_ENDIANNESS);
1.1 root 572: }
573:
1.1.1.3 ! root 574: void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as)
1.1 root 575: {
576: int bits = 8, sign = 0;
577:
1.1.1.2 root 578: switch (as->fmt) {
1.1 root 579: case AUD_FMT_S8:
580: sign = 1;
581: case AUD_FMT_U8:
582: break;
583:
584: case AUD_FMT_S16:
585: sign = 1;
586: case AUD_FMT_U16:
587: bits = 16;
588: break;
589: }
590:
1.1.1.2 root 591: info->freq = as->freq;
592: info->bits = bits;
593: info->sign = sign;
594: info->nchannels = as->nchannels;
595: info->shift = (as->nchannels == 2) + (bits == 16);
596: info->align = (1 << info->shift) - 1;
597: info->bytes_per_second = info->freq << info->shift;
1.1.1.3 ! root 598: info->swap_endianness = (as->endianness != AUDIO_HOST_ENDIANNESS);
1.1 root 599: }
600:
1.1.1.2 root 601: void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
1.1 root 602: {
1.1.1.2 root 603: if (!len) {
604: return;
605: }
606:
607: if (info->sign) {
608: memset (buf, len << info->shift, 0x00);
609: }
610: else {
611: if (info->bits == 8) {
612: memset (buf, len << info->shift, 0x80);
613: }
614: else {
615: int i;
616: uint16_t *p = buf;
617: int shift = info->nchannels - 1;
618: short s = INT16_MAX;
619:
1.1.1.3 ! root 620: if (info->swap_endianness) {
1.1.1.2 root 621: s = bswap16 (s);
622: }
623:
624: for (i = 0; i < len << shift; i++) {
625: p[i] = s;
626: }
627: }
628: }
1.1 root 629: }
630:
1.1.1.2 root 631: /*
1.1.1.3 ! root 632: * Capture
! 633: */
! 634: static void noop_conv (st_sample_t *dst, const void *src,
! 635: int samples, volume_t *vol)
! 636: {
! 637: (void) src;
! 638: (void) dst;
! 639: (void) samples;
! 640: (void) vol;
! 641: }
! 642:
! 643: static CaptureVoiceOut *audio_pcm_capture_find_specific (
! 644: AudioState *s,
! 645: audsettings_t *as
! 646: )
! 647: {
! 648: CaptureVoiceOut *cap;
! 649:
! 650: for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) {
! 651: if (audio_pcm_info_eq (&cap->hw.info, as)) {
! 652: return cap;
! 653: }
! 654: }
! 655: return NULL;
! 656: }
! 657:
! 658: static void audio_notify_capture (CaptureVoiceOut *cap, audcnotification_e cmd)
! 659: {
! 660: struct capture_callback *cb;
! 661:
! 662: #ifdef DEBUG_CAPTURE
! 663: dolog ("notification %d sent\n", cmd);
! 664: #endif
! 665: for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) {
! 666: cb->ops.notify (cb->opaque, cmd);
! 667: }
! 668: }
! 669:
! 670: static void audio_capture_maybe_changed (CaptureVoiceOut *cap, int enabled)
! 671: {
! 672: if (cap->hw.enabled != enabled) {
! 673: audcnotification_e cmd;
! 674: cap->hw.enabled = enabled;
! 675: cmd = enabled ? AUD_CNOTIFY_ENABLE : AUD_CNOTIFY_DISABLE;
! 676: audio_notify_capture (cap, cmd);
! 677: }
! 678: }
! 679:
! 680: static void audio_recalc_and_notify_capture (CaptureVoiceOut *cap)
! 681: {
! 682: HWVoiceOut *hw = &cap->hw;
! 683: SWVoiceOut *sw;
! 684: int enabled = 0;
! 685:
! 686: for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
! 687: if (sw->active) {
! 688: enabled = 1;
! 689: break;
! 690: }
! 691: }
! 692: audio_capture_maybe_changed (cap, enabled);
! 693: }
! 694:
! 695: static void audio_detach_capture (HWVoiceOut *hw)
! 696: {
! 697: SWVoiceCap *sc = hw->cap_head.lh_first;
! 698:
! 699: while (sc) {
! 700: SWVoiceCap *sc1 = sc->entries.le_next;
! 701: SWVoiceOut *sw = &sc->sw;
! 702: CaptureVoiceOut *cap = sc->cap;
! 703: int was_active = sw->active;
! 704:
! 705: if (sw->rate) {
! 706: st_rate_stop (sw->rate);
! 707: sw->rate = NULL;
! 708: }
! 709:
! 710: LIST_REMOVE (sw, entries);
! 711: LIST_REMOVE (sc, entries);
! 712: qemu_free (sc);
! 713: if (was_active) {
! 714: /* We have removed soft voice from the capture:
! 715: this might have changed the overall status of the capture
! 716: since this might have been the only active voice */
! 717: audio_recalc_and_notify_capture (cap);
! 718: }
! 719: sc = sc1;
! 720: }
! 721: }
! 722:
! 723: static int audio_attach_capture (AudioState *s, HWVoiceOut *hw)
! 724: {
! 725: CaptureVoiceOut *cap;
! 726:
! 727: audio_detach_capture (hw);
! 728: for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) {
! 729: SWVoiceCap *sc;
! 730: SWVoiceOut *sw;
! 731: HWVoiceOut *hw_cap = &cap->hw;
! 732:
! 733: sc = audio_calloc (AUDIO_FUNC, 1, sizeof (*sc));
! 734: if (!sc) {
! 735: dolog ("Could not allocate soft capture voice (%zu bytes)\n",
! 736: sizeof (*sc));
! 737: return -1;
! 738: }
! 739:
! 740: sc->cap = cap;
! 741: sw = &sc->sw;
! 742: sw->hw = hw_cap;
! 743: sw->info = hw->info;
! 744: sw->empty = 1;
! 745: sw->active = hw->enabled;
! 746: sw->conv = noop_conv;
! 747: sw->ratio = ((int64_t) hw_cap->info.freq << 32) / sw->info.freq;
! 748: sw->rate = st_rate_start (sw->info.freq, hw_cap->info.freq);
! 749: if (!sw->rate) {
! 750: dolog ("Could not start rate conversion for `%s'\n", SW_NAME (sw));
! 751: qemu_free (sw);
! 752: return -1;
! 753: }
! 754: LIST_INSERT_HEAD (&hw_cap->sw_head, sw, entries);
! 755: LIST_INSERT_HEAD (&hw->cap_head, sc, entries);
! 756: #ifdef DEBUG_CAPTURE
! 757: asprintf (&sw->name, "for %p %d,%d,%d",
! 758: hw, sw->info.freq, sw->info.bits, sw->info.nchannels);
! 759: dolog ("Added %s active = %d\n", sw->name, sw->active);
! 760: #endif
! 761: if (sw->active) {
! 762: audio_capture_maybe_changed (cap, 1);
! 763: }
! 764: }
! 765: return 0;
! 766: }
! 767:
! 768: /*
1.1.1.2 root 769: * Hard voice (capture)
770: */
771: static int audio_pcm_hw_find_min_in (HWVoiceIn *hw)
1.1 root 772: {
1.1.1.2 root 773: SWVoiceIn *sw;
774: int m = hw->total_samples_captured;
775:
776: for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
777: if (sw->active) {
778: m = audio_MIN (m, sw->total_hw_samples_acquired);
779: }
1.1 root 780: }
1.1.1.2 root 781: return m;
1.1 root 782: }
783:
1.1.1.2 root 784: int audio_pcm_hw_get_live_in (HWVoiceIn *hw)
1.1 root 785: {
1.1.1.2 root 786: int live = hw->total_samples_captured - audio_pcm_hw_find_min_in (hw);
787: if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
788: dolog ("live=%d hw->samples=%d\n", live, hw->samples);
789: return 0;
790: }
791: return live;
1.1 root 792: }
793:
1.1.1.2 root 794: /*
795: * Soft voice (capture)
796: */
797: static int audio_pcm_sw_get_rpos_in (SWVoiceIn *sw)
1.1 root 798: {
1.1.1.2 root 799: HWVoiceIn *hw = sw->hw;
800: int live = hw->total_samples_captured - sw->total_hw_samples_acquired;
801: int rpos;
1.1 root 802:
1.1.1.2 root 803: if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
804: dolog ("live=%d hw->samples=%d\n", live, hw->samples);
805: return 0;
1.1 root 806: }
807:
1.1.1.2 root 808: rpos = hw->wpos - live;
809: if (rpos >= 0) {
810: return rpos;
811: }
812: else {
813: return hw->samples + rpos;
814: }
1.1 root 815: }
816:
1.1.1.2 root 817: int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size)
1.1 root 818: {
1.1.1.2 root 819: HWVoiceIn *hw = sw->hw;
820: int samples, live, ret = 0, swlim, isamp, osamp, rpos, total = 0;
821: st_sample_t *src, *dst = sw->buf;
1.1 root 822:
1.1.1.2 root 823: rpos = audio_pcm_sw_get_rpos_in (sw) % hw->samples;
824:
825: live = hw->total_samples_captured - sw->total_hw_samples_acquired;
826: if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
827: dolog ("live_in=%d hw->samples=%d\n", live, hw->samples);
828: return 0;
829: }
830:
831: samples = size >> sw->info.shift;
832: if (!live) {
833: return 0;
834: }
835:
836: swlim = (live * sw->ratio) >> 32;
837: swlim = audio_MIN (swlim, samples);
838:
839: while (swlim) {
840: src = hw->conv_buf + rpos;
841: isamp = hw->wpos - rpos;
842: /* XXX: <= ? */
843: if (isamp <= 0) {
844: isamp = hw->samples - rpos;
1.1 root 845: }
1.1.1.2 root 846:
847: if (!isamp) {
848: break;
849: }
850: osamp = swlim;
851:
852: if (audio_bug (AUDIO_FUNC, osamp < 0)) {
853: dolog ("osamp=%d\n", osamp);
854: return 0;
855: }
856:
857: st_rate_flow (sw->rate, src, dst, &isamp, &osamp);
858: swlim -= osamp;
859: rpos = (rpos + isamp) % hw->samples;
860: dst += osamp;
861: ret += osamp;
862: total += isamp;
1.1 root 863: }
864:
1.1.1.2 root 865: sw->clip (buf, sw->buf, ret);
866: sw->total_hw_samples_acquired += total;
867: return ret << sw->info.shift;
1.1 root 868: }
869:
1.1.1.2 root 870: /*
871: * Hard voice (playback)
872: */
873: static int audio_pcm_hw_find_min_out (HWVoiceOut *hw, int *nb_livep)
1.1 root 874: {
1.1.1.2 root 875: SWVoiceOut *sw;
876: int m = INT_MAX;
877: int nb_live = 0;
1.1 root 878:
1.1.1.2 root 879: for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
880: if (sw->active || !sw->empty) {
881: m = audio_MIN (m, sw->total_hw_samples_mixed);
882: nb_live += 1;
1.1 root 883: }
884: }
1.1.1.2 root 885:
886: *nb_livep = nb_live;
887: return m;
1.1 root 888: }
889:
1.1.1.2 root 890: int audio_pcm_hw_get_live_out2 (HWVoiceOut *hw, int *nb_live)
1.1 root 891: {
1.1.1.2 root 892: int smin;
1.1 root 893:
1.1.1.2 root 894: smin = audio_pcm_hw_find_min_out (hw, nb_live);
1.1 root 895:
1.1.1.2 root 896: if (!*nb_live) {
897: return 0;
898: }
899: else {
900: int live = smin;
1.1 root 901:
1.1.1.2 root 902: if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
903: dolog ("live=%d hw->samples=%d\n", live, hw->samples);
904: return 0;
1.1 root 905: }
1.1.1.2 root 906: return live;
1.1 root 907: }
908: }
909:
1.1.1.2 root 910: int audio_pcm_hw_get_live_out (HWVoiceOut *hw)
911: {
912: int nb_live;
913: int live;
914:
915: live = audio_pcm_hw_get_live_out2 (hw, &nb_live);
916: if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
917: dolog ("live=%d hw->samples=%d\n", live, hw->samples);
918: return 0;
919: }
920: return live;
921: }
922:
923: /*
924: * Soft voice (playback)
925: */
926: int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size)
1.1 root 927: {
928: int hwsamples, samples, isamp, osamp, wpos, live, dead, left, swlim, blck;
1.1.1.2 root 929: int ret = 0, pos = 0, total = 0;
930:
931: if (!sw) {
1.1 root 932: return size;
1.1.1.2 root 933: }
1.1 root 934:
935: hwsamples = sw->hw->samples;
936:
1.1.1.2 root 937: live = sw->total_hw_samples_mixed;
938: if (audio_bug (AUDIO_FUNC, live < 0 || live > hwsamples)){
939: dolog ("live=%d hw->samples=%d\n", live, hwsamples);
940: return 0;
1.1 root 941: }
1.1.1.2 root 942:
943: if (live == hwsamples) {
1.1.1.3 ! root 944: #ifdef DEBUG_OUT
! 945: dolog ("%s is full %d\n", sw->name, live);
! 946: #endif
1.1.1.2 root 947: return 0;
948: }
949:
950: wpos = (sw->hw->rpos + live) % hwsamples;
951: samples = size >> sw->info.shift;
952:
1.1 root 953: dead = hwsamples - live;
1.1.1.2 root 954: swlim = ((int64_t) dead << 32) / sw->ratio;
1.1 root 955: swlim = audio_MIN (swlim, samples);
1.1.1.2 root 956: if (swlim) {
957: sw->conv (sw->buf, buf, swlim, &sw->vol);
958: }
1.1 root 959:
960: while (swlim) {
961: dead = hwsamples - live;
962: left = hwsamples - wpos;
963: blck = audio_MIN (dead, left);
964: if (!blck) {
965: break;
966: }
967: isamp = swlim;
968: osamp = blck;
1.1.1.2 root 969: st_rate_flow_mix (
970: sw->rate,
971: sw->buf + pos,
972: sw->hw->mix_buf + wpos,
973: &isamp,
974: &osamp
975: );
1.1 root 976: ret += isamp;
977: swlim -= isamp;
978: pos += isamp;
979: live += osamp;
1.1.1.2 root 980: wpos = (wpos + osamp) % hwsamples;
981: total += osamp;
1.1 root 982: }
983:
1.1.1.2 root 984: sw->total_hw_samples_mixed += total;
985: sw->empty = sw->total_hw_samples_mixed == 0;
1.1 root 986:
1.1.1.2 root 987: #ifdef DEBUG_OUT
988: dolog (
989: "%s: write size %d ret %d total sw %d\n",
990: SW_NAME (sw),
991: size >> sw->info.shift,
992: ret,
993: sw->total_hw_samples_mixed
994: );
995: #endif
1.1 root 996:
1.1.1.2 root 997: return ret << sw->info.shift;
1.1 root 998: }
999:
1.1.1.2 root 1000: #ifdef DEBUG_AUDIO
1001: static void audio_pcm_print_info (const char *cap, struct audio_pcm_info *info)
1.1 root 1002: {
1.1.1.2 root 1003: dolog ("%s: bits %d, sign %d, freq %d, nchan %d\n",
1004: cap, info->bits, info->sign, info->freq, info->nchannels);
1.1 root 1005: }
1.1.1.2 root 1006: #endif
1.1 root 1007:
1.1.1.2 root 1008: #define DAC
1009: #include "audio_template.h"
1010: #undef DAC
1011: #include "audio_template.h"
1.1 root 1012:
1.1.1.2 root 1013: int AUD_write (SWVoiceOut *sw, void *buf, int size)
1.1 root 1014: {
1.1.1.2 root 1015: int bytes;
1016:
1017: if (!sw) {
1018: /* XXX: Consider options */
1019: return size;
1.1 root 1020: }
1021:
1.1.1.2 root 1022: if (!sw->hw->enabled) {
1023: dolog ("Writing to disabled voice %s\n", SW_NAME (sw));
1024: return 0;
1.1 root 1025: }
1.1.1.2 root 1026:
1027: bytes = sw->hw->pcm_ops->write (sw, buf, size);
1028: return bytes;
1.1 root 1029: }
1030:
1.1.1.2 root 1031: int AUD_read (SWVoiceIn *sw, void *buf, int size)
1.1 root 1032: {
1.1.1.2 root 1033: int bytes;
1034:
1035: if (!sw) {
1036: /* XXX: Consider options */
1037: return size;
1.1 root 1038: }
1039:
1.1.1.2 root 1040: if (!sw->hw->enabled) {
1041: dolog ("Reading from disabled voice %s\n", SW_NAME (sw));
1042: return 0;
1.1 root 1043: }
1.1.1.2 root 1044:
1045: bytes = sw->hw->pcm_ops->read (sw, buf, size);
1046: return bytes;
1.1 root 1047: }
1048:
1.1.1.2 root 1049: int AUD_get_buffer_size_out (SWVoiceOut *sw)
1.1 root 1050: {
1.1.1.2 root 1051: return sw->hw->samples << sw->hw->info.shift;
1.1 root 1052: }
1053:
1.1.1.2 root 1054: void AUD_set_active_out (SWVoiceOut *sw, int on)
1.1 root 1055: {
1.1.1.2 root 1056: HWVoiceOut *hw;
1.1 root 1057:
1.1.1.2 root 1058: if (!sw) {
1059: return;
1.1 root 1060: }
1061:
1.1.1.2 root 1062: hw = sw->hw;
1063: if (sw->active != on) {
1064: SWVoiceOut *temp_sw;
1.1.1.3 ! root 1065: SWVoiceCap *sc;
1.1 root 1066:
1.1.1.2 root 1067: if (on) {
1068: hw->pending_disable = 0;
1069: if (!hw->enabled) {
1070: hw->enabled = 1;
1071: hw->pcm_ops->ctl_out (hw, VOICE_ENABLE);
1072: }
1.1 root 1073: }
1.1.1.2 root 1074: else {
1075: if (hw->enabled) {
1076: int nb_active = 0;
1077:
1078: for (temp_sw = hw->sw_head.lh_first; temp_sw;
1079: temp_sw = temp_sw->entries.le_next) {
1080: nb_active += temp_sw->active != 0;
1081: }
1.1 root 1082:
1.1.1.2 root 1083: hw->pending_disable = nb_active == 1;
1084: }
1085: }
1.1.1.3 ! root 1086:
! 1087: for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) {
! 1088: sc->sw.active = hw->enabled;
! 1089: if (hw->enabled) {
! 1090: audio_capture_maybe_changed (sc->cap, 1);
! 1091: }
! 1092: }
1.1.1.2 root 1093: sw->active = on;
1094: }
1.1 root 1095: }
1096:
1.1.1.2 root 1097: void AUD_set_active_in (SWVoiceIn *sw, int on)
1.1 root 1098: {
1.1.1.2 root 1099: HWVoiceIn *hw;
1.1 root 1100:
1.1.1.2 root 1101: if (!sw) {
1102: return;
1103: }
1.1 root 1104:
1.1.1.2 root 1105: hw = sw->hw;
1106: if (sw->active != on) {
1107: SWVoiceIn *temp_sw;
1.1 root 1108:
1.1.1.2 root 1109: if (on) {
1110: if (!hw->enabled) {
1111: hw->enabled = 1;
1112: hw->pcm_ops->ctl_in (hw, VOICE_ENABLE);
1113: }
1114: sw->total_hw_samples_acquired = hw->total_samples_captured;
1.1 root 1115: }
1.1.1.2 root 1116: else {
1117: if (hw->enabled) {
1118: int nb_active = 0;
1119:
1120: for (temp_sw = hw->sw_head.lh_first; temp_sw;
1121: temp_sw = temp_sw->entries.le_next) {
1122: nb_active += temp_sw->active != 0;
1123: }
1.1 root 1124:
1.1.1.2 root 1125: if (nb_active == 1) {
1126: hw->enabled = 0;
1127: hw->pcm_ops->ctl_in (hw, VOICE_DISABLE);
1128: }
1.1 root 1129: }
1130: }
1.1.1.2 root 1131: sw->active = on;
1.1 root 1132: }
1.1.1.2 root 1133: }
1134:
1135: static int audio_get_avail (SWVoiceIn *sw)
1136: {
1137: int live;
1138:
1139: if (!sw) {
1140: return 0;
1.1 root 1141: }
1.1.1.2 root 1142:
1143: live = sw->hw->total_samples_captured - sw->total_hw_samples_acquired;
1144: if (audio_bug (AUDIO_FUNC, live < 0 || live > sw->hw->samples)) {
1145: dolog ("live=%d sw->hw->samples=%d\n", live, sw->hw->samples);
1146: return 0;
1147: }
1148:
1149: ldebug (
1.1.1.3 ! root 1150: "%s: get_avail live %d ret %" PRId64 "\n",
1.1.1.2 root 1151: SW_NAME (sw),
1152: live, (((int64_t) live << 32) / sw->ratio) << sw->info.shift
1153: );
1154:
1155: return (((int64_t) live << 32) / sw->ratio) << sw->info.shift;
1.1 root 1156: }
1157:
1.1.1.2 root 1158: static int audio_get_free (SWVoiceOut *sw)
1.1 root 1159: {
1.1.1.2 root 1160: int live, dead;
1.1 root 1161:
1.1.1.2 root 1162: if (!sw) {
1163: return 0;
1164: }
1.1 root 1165:
1.1.1.2 root 1166: live = sw->total_hw_samples_mixed;
1.1 root 1167:
1.1.1.2 root 1168: if (audio_bug (AUDIO_FUNC, live < 0 || live > sw->hw->samples)) {
1169: dolog ("live=%d sw->hw->samples=%d\n", live, sw->hw->samples);
1170: return 0;
1171: }
1.1 root 1172:
1.1.1.2 root 1173: dead = sw->hw->samples - live;
1.1 root 1174:
1.1.1.2 root 1175: #ifdef DEBUG_OUT
1.1.1.3 ! root 1176: dolog ("%s: get_free live %d dead %d ret %" PRId64 "\n",
1.1.1.2 root 1177: SW_NAME (sw),
1178: live, dead, (((int64_t) dead << 32) / sw->ratio) << sw->info.shift);
1179: #endif
1.1 root 1180:
1.1.1.2 root 1181: return (((int64_t) dead << 32) / sw->ratio) << sw->info.shift;
1.1 root 1182: }
1183:
1.1.1.3 ! root 1184: static void audio_capture_mix_and_clear (HWVoiceOut *hw, int rpos, int samples)
! 1185: {
! 1186: int n;
! 1187:
! 1188: if (hw->enabled) {
! 1189: SWVoiceCap *sc;
! 1190:
! 1191: for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) {
! 1192: SWVoiceOut *sw = &sc->sw;
! 1193: int rpos2 = rpos;
! 1194:
! 1195: n = samples;
! 1196: while (n) {
! 1197: int till_end_of_hw = hw->samples - rpos2;
! 1198: int to_write = audio_MIN (till_end_of_hw, n);
! 1199: int bytes = to_write << hw->info.shift;
! 1200: int written;
! 1201:
! 1202: sw->buf = hw->mix_buf + rpos2;
! 1203: written = audio_pcm_sw_write (sw, NULL, bytes);
! 1204: if (written - bytes) {
! 1205: dolog ("Could not mix %d bytes into a capture "
! 1206: "buffer, mixed %d\n",
! 1207: bytes, written);
! 1208: break;
! 1209: }
! 1210: n -= to_write;
! 1211: rpos2 = (rpos2 + to_write) % hw->samples;
! 1212: }
! 1213: }
! 1214: }
! 1215:
! 1216: n = audio_MIN (samples, hw->samples - rpos);
! 1217: mixeng_clear (hw->mix_buf + rpos, n);
! 1218: mixeng_clear (hw->mix_buf, samples - n);
! 1219: }
! 1220:
1.1.1.2 root 1221: static void audio_run_out (AudioState *s)
1.1 root 1222: {
1.1.1.2 root 1223: HWVoiceOut *hw = NULL;
1224: SWVoiceOut *sw;
1.1 root 1225:
1.1.1.2 root 1226: while ((hw = audio_pcm_hw_find_any_enabled_out (s, hw))) {
1227: int played;
1.1.1.3 ! root 1228: int live, free, nb_live, cleanup_required, prev_rpos;
1.1 root 1229:
1.1.1.2 root 1230: live = audio_pcm_hw_get_live_out2 (hw, &nb_live);
1231: if (!nb_live) {
1232: live = 0;
1233: }
1.1 root 1234:
1.1.1.2 root 1235: if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
1236: dolog ("live=%d hw->samples=%d\n", live, hw->samples);
1237: continue;
1238: }
1239:
1240: if (hw->pending_disable && !nb_live) {
1.1.1.3 ! root 1241: SWVoiceCap *sc;
1.1.1.2 root 1242: #ifdef DEBUG_OUT
1243: dolog ("Disabling voice\n");
1244: #endif
1245: hw->enabled = 0;
1246: hw->pending_disable = 0;
1247: hw->pcm_ops->ctl_out (hw, VOICE_DISABLE);
1.1.1.3 ! root 1248: for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) {
! 1249: sc->sw.active = 0;
! 1250: audio_recalc_and_notify_capture (sc->cap);
! 1251: }
1.1.1.2 root 1252: continue;
1253: }
1.1 root 1254:
1.1.1.2 root 1255: if (!live) {
1256: for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
1257: if (sw->active) {
1258: free = audio_get_free (sw);
1259: if (free > 0) {
1260: sw->callback.fn (sw->callback.opaque, free);
1261: }
1262: }
1.1 root 1263: }
1.1.1.2 root 1264: continue;
1.1 root 1265: }
1.1.1.2 root 1266:
1.1.1.3 ! root 1267: prev_rpos = hw->rpos;
1.1.1.2 root 1268: played = hw->pcm_ops->run_out (hw);
1269: if (audio_bug (AUDIO_FUNC, hw->rpos >= hw->samples)) {
1270: dolog ("hw->rpos=%d hw->samples=%d played=%d\n",
1271: hw->rpos, hw->samples, played);
1272: hw->rpos = 0;
1.1 root 1273: }
1274:
1.1.1.2 root 1275: #ifdef DEBUG_OUT
1276: dolog ("played=%d\n", played);
1277: #endif
1.1 root 1278:
1.1.1.2 root 1279: if (played) {
1280: hw->ts_helper += played;
1.1.1.3 ! root 1281: audio_capture_mix_and_clear (hw, prev_rpos, played);
1.1.1.2 root 1282: }
1.1 root 1283:
1.1.1.2 root 1284: cleanup_required = 0;
1285: for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
1286: if (!sw->active && sw->empty) {
1287: continue;
1288: }
1.1 root 1289:
1.1.1.2 root 1290: if (audio_bug (AUDIO_FUNC, played > sw->total_hw_samples_mixed)) {
1291: dolog ("played=%d sw->total_hw_samples_mixed=%d\n",
1292: played, sw->total_hw_samples_mixed);
1293: played = sw->total_hw_samples_mixed;
1294: }
1.1 root 1295:
1.1.1.2 root 1296: sw->total_hw_samples_mixed -= played;
1.1 root 1297:
1.1.1.2 root 1298: if (!sw->total_hw_samples_mixed) {
1299: sw->empty = 1;
1300: cleanup_required |= !sw->active && !sw->callback.fn;
1301: }
1.1 root 1302:
1.1.1.2 root 1303: if (sw->active) {
1304: free = audio_get_free (sw);
1305: if (free > 0) {
1306: sw->callback.fn (sw->callback.opaque, free);
1307: }
1.1 root 1308: }
1309: }
1310:
1.1.1.2 root 1311: if (cleanup_required) {
1.1.1.3 ! root 1312: SWVoiceOut *sw1;
! 1313:
! 1314: sw = hw->sw_head.lh_first;
! 1315: while (sw) {
! 1316: sw1 = sw->entries.le_next;
1.1.1.2 root 1317: if (!sw->active && !sw->callback.fn) {
1318: #ifdef DEBUG_PLIVE
1319: dolog ("Finishing with old voice\n");
1320: #endif
1321: audio_close_out (s, sw);
1.1 root 1322: }
1.1.1.3 ! root 1323: sw = sw1;
1.1 root 1324: }
1325: }
1326: }
1327: }
1328:
1.1.1.2 root 1329: static void audio_run_in (AudioState *s)
1.1 root 1330: {
1.1.1.2 root 1331: HWVoiceIn *hw = NULL;
1.1 root 1332:
1.1.1.2 root 1333: while ((hw = audio_pcm_hw_find_any_enabled_in (s, hw))) {
1334: SWVoiceIn *sw;
1335: int captured, min;
1.1 root 1336:
1.1.1.2 root 1337: captured = hw->pcm_ops->run_in (hw);
1.1 root 1338:
1.1.1.2 root 1339: min = audio_pcm_hw_find_min_in (hw);
1340: hw->total_samples_captured += captured - min;
1341: hw->ts_helper += captured;
1.1 root 1342:
1.1.1.2 root 1343: for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
1344: sw->total_hw_samples_acquired -= min;
1.1 root 1345:
1.1.1.2 root 1346: if (sw->active) {
1347: int avail;
1.1 root 1348:
1.1.1.2 root 1349: avail = audio_get_avail (sw);
1350: if (avail > 0) {
1351: sw->callback.fn (sw->callback.opaque, avail);
1352: }
1353: }
1354: }
1355: }
1.1 root 1356: }
1357:
1.1.1.3 ! root 1358: static void audio_run_capture (AudioState *s)
! 1359: {
! 1360: CaptureVoiceOut *cap;
! 1361:
! 1362: for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) {
! 1363: int live, rpos, captured;
! 1364: HWVoiceOut *hw = &cap->hw;
! 1365: SWVoiceOut *sw;
! 1366:
! 1367: captured = live = audio_pcm_hw_get_live_out (hw);
! 1368: rpos = hw->rpos;
! 1369: while (live) {
! 1370: int left = hw->samples - rpos;
! 1371: int to_capture = audio_MIN (live, left);
! 1372: st_sample_t *src;
! 1373: struct capture_callback *cb;
! 1374:
! 1375: src = hw->mix_buf + rpos;
! 1376: hw->clip (cap->buf, src, to_capture);
! 1377: mixeng_clear (src, to_capture);
! 1378:
! 1379: for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) {
! 1380: cb->ops.capture (cb->opaque, cap->buf,
! 1381: to_capture << hw->info.shift);
! 1382: }
! 1383: rpos = (rpos + to_capture) % hw->samples;
! 1384: live -= to_capture;
! 1385: }
! 1386: hw->rpos = rpos;
! 1387:
! 1388: for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
! 1389: if (!sw->active && sw->empty) {
! 1390: continue;
! 1391: }
! 1392:
! 1393: if (audio_bug (AUDIO_FUNC, captured > sw->total_hw_samples_mixed)) {
! 1394: dolog ("captured=%d sw->total_hw_samples_mixed=%d\n",
! 1395: captured, sw->total_hw_samples_mixed);
! 1396: captured = sw->total_hw_samples_mixed;
! 1397: }
! 1398:
! 1399: sw->total_hw_samples_mixed -= captured;
! 1400: sw->empty = sw->total_hw_samples_mixed == 0;
! 1401: }
! 1402: }
! 1403: }
! 1404:
1.1.1.2 root 1405: static void audio_timer (void *opaque)
1.1 root 1406: {
1.1.1.2 root 1407: AudioState *s = opaque;
1408:
1409: audio_run_out (s);
1410: audio_run_in (s);
1.1.1.3 ! root 1411: audio_run_capture (s);
1.1.1.2 root 1412:
1413: qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks);
1.1 root 1414: }
1415:
1.1.1.2 root 1416: static struct audio_option audio_options[] = {
1417: /* DAC */
1418: {"DAC_FIXED_SETTINGS", AUD_OPT_BOOL, &conf.fixed_out.enabled,
1419: "Use fixed settings for host DAC", NULL, 0},
1.1 root 1420:
1.1.1.2 root 1421: {"DAC_FIXED_FREQ", AUD_OPT_INT, &conf.fixed_out.settings.freq,
1422: "Frequency for fixed host DAC", NULL, 0},
1.1 root 1423:
1.1.1.2 root 1424: {"DAC_FIXED_FMT", AUD_OPT_FMT, &conf.fixed_out.settings.fmt,
1425: "Format for fixed host DAC", NULL, 0},
1.1 root 1426:
1.1.1.2 root 1427: {"DAC_FIXED_CHANNELS", AUD_OPT_INT, &conf.fixed_out.settings.nchannels,
1428: "Number of channels for fixed DAC (1 - mono, 2 - stereo)", NULL, 0},
1.1 root 1429:
1.1.1.2 root 1430: {"DAC_VOICES", AUD_OPT_INT, &conf.fixed_out.nb_voices,
1431: "Number of voices for DAC", NULL, 0},
1432:
1433: /* ADC */
1434: {"ADC_FIXED_SETTINGS", AUD_OPT_BOOL, &conf.fixed_in.enabled,
1435: "Use fixed settings for host ADC", NULL, 0},
1436:
1437: {"ADC_FIXED_FREQ", AUD_OPT_INT, &conf.fixed_in.settings.freq,
1438: "Frequency for fixed host ADC", NULL, 0},
1439:
1440: {"ADC_FIXED_FMT", AUD_OPT_FMT, &conf.fixed_in.settings.fmt,
1441: "Format for fixed host ADC", NULL, 0},
1442:
1443: {"ADC_FIXED_CHANNELS", AUD_OPT_INT, &conf.fixed_in.settings.nchannels,
1444: "Number of channels for fixed ADC (1 - mono, 2 - stereo)", NULL, 0},
1445:
1446: {"ADC_VOICES", AUD_OPT_INT, &conf.fixed_in.nb_voices,
1447: "Number of voices for ADC", NULL, 0},
1448:
1449: /* Misc */
1450: {"TIMER_PERIOD", AUD_OPT_INT, &conf.period.hz,
1451: "Timer period in HZ (0 - use lowest possible)", NULL, 0},
1452:
1453: {"PLIVE", AUD_OPT_BOOL, &conf.plive,
1454: "(undocumented)", NULL, 0},
1455:
1456: {"LOG_TO_MONITOR", AUD_OPT_BOOL, &conf.log_to_monitor,
1457: "print logging messages to montior instead of stderr", NULL, 0},
1458:
1459: {NULL, 0, NULL, NULL, NULL, 0}
1460: };
1461:
1462: static void audio_pp_nb_voices (const char *typ, int nb)
1463: {
1464: switch (nb) {
1465: case 0:
1466: printf ("Does not support %s\n", typ);
1467: break;
1468: case 1:
1469: printf ("One %s voice\n", typ);
1470: break;
1471: case INT_MAX:
1472: printf ("Theoretically supports many %s voices\n", typ);
1473: break;
1474: default:
1475: printf ("Theoretically supports upto %d %s voices\n", nb, typ);
1476: break;
1.1 root 1477: }
1.1.1.2 root 1478:
1.1 root 1479: }
1480:
1.1.1.2 root 1481: void AUD_help (void)
1.1 root 1482: {
1.1.1.2 root 1483: size_t i;
1.1 root 1484:
1.1.1.2 root 1485: audio_process_options ("AUDIO", audio_options);
1486: for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
1487: struct audio_driver *d = drvtab[i];
1488: if (d->options) {
1489: audio_process_options (d->name, d->options);
1.1 root 1490: }
1491: }
1492:
1.1.1.2 root 1493: printf ("Audio options:\n");
1494: audio_print_options ("AUDIO", audio_options);
1495: printf ("\n");
1496:
1497: printf ("Available drivers:\n");
1498:
1499: for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
1500: struct audio_driver *d = drvtab[i];
1501:
1502: printf ("Name: %s\n", d->name);
1503: printf ("Description: %s\n", d->descr);
1504:
1505: audio_pp_nb_voices ("playback", d->max_voices_out);
1506: audio_pp_nb_voices ("capture", d->max_voices_in);
1507:
1508: if (d->options) {
1509: printf ("Options:\n");
1510: audio_print_options (d->name, d->options);
1.1 root 1511: }
1512: else {
1.1.1.2 root 1513: printf ("No options\n");
1.1 root 1514: }
1.1.1.2 root 1515: printf ("\n");
1.1 root 1516: }
1517:
1.1.1.2 root 1518: printf (
1519: "Options are settable through environment variables.\n"
1520: "Example:\n"
1521: #ifdef _WIN32
1522: " set QEMU_AUDIO_DRV=wav\n"
1523: " set QEMU_WAV_PATH=c:\\tune.wav\n"
1524: #else
1525: " export QEMU_AUDIO_DRV=wav\n"
1526: " export QEMU_WAV_PATH=$HOME/tune.wav\n"
1527: "(for csh replace export with setenv in the above)\n"
1.1 root 1528: #endif
1.1.1.2 root 1529: " qemu ...\n\n"
1530: );
1531: }
1.1 root 1532:
1.1.1.2 root 1533: static int audio_driver_init (AudioState *s, struct audio_driver *drv)
1.1 root 1534: {
1.1.1.2 root 1535: if (drv->options) {
1536: audio_process_options (drv->name, drv->options);
1.1 root 1537: }
1.1.1.2 root 1538: s->drv_opaque = drv->init ();
1539:
1540: if (s->drv_opaque) {
1541: audio_init_nb_voices_out (s, drv);
1542: audio_init_nb_voices_in (s, drv);
1543: s->drv = drv;
1.1 root 1544: return 0;
1545: }
1.1.1.2 root 1546: else {
1547: dolog ("Could not init `%s' audio driver\n", drv->name);
1548: return -1;
1549: }
1.1 root 1550: }
1551:
1.1.1.2 root 1552: static void audio_vm_change_state_handler (void *opaque, int running)
1.1 root 1553: {
1.1.1.2 root 1554: AudioState *s = opaque;
1555: HWVoiceOut *hwo = NULL;
1556: HWVoiceIn *hwi = NULL;
1557: int op = running ? VOICE_ENABLE : VOICE_DISABLE;
1.1 root 1558:
1.1.1.2 root 1559: while ((hwo = audio_pcm_hw_find_any_enabled_out (s, hwo))) {
1560: hwo->pcm_ops->ctl_out (hwo, op);
1561: }
1.1 root 1562:
1.1.1.2 root 1563: while ((hwi = audio_pcm_hw_find_any_enabled_in (s, hwi))) {
1564: hwi->pcm_ops->ctl_in (hwi, op);
1.1 root 1565: }
1566: }
1567:
1568: static void audio_atexit (void)
1569: {
1.1.1.2 root 1570: AudioState *s = &glob_audio_state;
1571: HWVoiceOut *hwo = NULL;
1572: HWVoiceIn *hwi = NULL;
1.1 root 1573:
1.1.1.2 root 1574: while ((hwo = audio_pcm_hw_find_any_enabled_out (s, hwo))) {
1.1.1.3 ! root 1575: SWVoiceCap *sc;
! 1576:
1.1.1.2 root 1577: hwo->pcm_ops->ctl_out (hwo, VOICE_DISABLE);
1578: hwo->pcm_ops->fini_out (hwo);
1.1.1.3 ! root 1579:
! 1580: for (sc = hwo->cap_head.lh_first; sc; sc = sc->entries.le_next) {
! 1581: CaptureVoiceOut *cap = sc->cap;
! 1582: struct capture_callback *cb;
! 1583:
! 1584: for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) {
! 1585: cb->ops.destroy (cb->opaque);
! 1586: }
! 1587: }
1.1.1.2 root 1588: }
1589:
1590: while ((hwi = audio_pcm_hw_find_any_enabled_in (s, hwi))) {
1591: hwi->pcm_ops->ctl_in (hwi, VOICE_DISABLE);
1592: hwi->pcm_ops->fini_in (hwi);
1593: }
1.1 root 1594:
1.1.1.2 root 1595: if (s->drv) {
1596: s->drv->fini (s->drv_opaque);
1.1 root 1597: }
1598: }
1599:
1600: static void audio_save (QEMUFile *f, void *opaque)
1601: {
1.1.1.2 root 1602: (void) f;
1603: (void) opaque;
1.1 root 1604: }
1605:
1606: static int audio_load (QEMUFile *f, void *opaque, int version_id)
1607: {
1.1.1.2 root 1608: (void) f;
1609: (void) opaque;
1610:
1611: if (version_id != 1) {
1.1 root 1612: return -EINVAL;
1.1.1.2 root 1613: }
1.1 root 1614:
1615: return 0;
1616: }
1617:
1.1.1.2 root 1618: void AUD_register_card (AudioState *s, const char *name, QEMUSoundCard *card)
1619: {
1620: card->audio = s;
1621: card->name = qemu_strdup (name);
1622: memset (&card->entries, 0, sizeof (card->entries));
1623: LIST_INSERT_HEAD (&s->card_head, card, entries);
1624: }
1625:
1626: void AUD_remove_card (QEMUSoundCard *card)
1.1 root 1627: {
1.1.1.2 root 1628: LIST_REMOVE (card, entries);
1629: card->audio = NULL;
1630: qemu_free (card->name);
1631: }
1632:
1633: AudioState *AUD_init (void)
1634: {
1635: size_t i;
1.1 root 1636: int done = 0;
1637: const char *drvname;
1.1.1.2 root 1638: AudioState *s = &glob_audio_state;
1639:
1640: LIST_INIT (&s->hw_head_out);
1641: LIST_INIT (&s->hw_head_in);
1.1.1.3 ! root 1642: LIST_INIT (&s->cap_head);
1.1.1.2 root 1643: atexit (audio_atexit);
1644:
1645: s->ts = qemu_new_timer (vm_clock, audio_timer, s);
1646: if (!s->ts) {
1647: dolog ("Could not create audio timer\n");
1648: return NULL;
1649: }
1650:
1651: audio_process_options ("AUDIO", audio_options);
1652:
1653: s->nb_hw_voices_out = conf.fixed_out.nb_voices;
1654: s->nb_hw_voices_in = conf.fixed_in.nb_voices;
1655:
1656: if (s->nb_hw_voices_out <= 0) {
1657: dolog ("Bogus number of playback voices %d, setting to 1\n",
1658: s->nb_hw_voices_out);
1659: s->nb_hw_voices_out = 1;
1660: }
1.1 root 1661:
1.1.1.2 root 1662: if (s->nb_hw_voices_in <= 0) {
1663: dolog ("Bogus number of capture voices %d, setting to 0\n",
1664: s->nb_hw_voices_in);
1665: s->nb_hw_voices_in = 0;
1666: }
1667:
1668: {
1669: int def;
1670: drvname = audio_get_conf_str ("QEMU_AUDIO_DRV", NULL, &def);
1.1 root 1671: }
1672:
1673: if (drvname) {
1674: int found = 0;
1.1.1.2 root 1675:
1.1 root 1676: for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
1677: if (!strcmp (drvname, drvtab[i]->name)) {
1.1.1.2 root 1678: done = !audio_driver_init (s, drvtab[i]);
1.1 root 1679: found = 1;
1680: break;
1681: }
1682: }
1.1.1.2 root 1683:
1.1 root 1684: if (!found) {
1685: dolog ("Unknown audio driver `%s'\n", drvname);
1.1.1.2 root 1686: dolog ("Run with -audio-help to list available drivers\n");
1.1 root 1687: }
1688: }
1689:
1690: if (!done) {
1691: for (i = 0; !done && i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
1.1.1.2 root 1692: if (drvtab[i]->can_be_default) {
1693: done = !audio_driver_init (s, drvtab[i]);
1694: }
1.1 root 1695: }
1696: }
1697:
1698: if (!done) {
1.1.1.2 root 1699: done = !audio_driver_init (s, &no_audio_driver);
1700: if (!done) {
1701: dolog ("Could not initialize audio subsystem\n");
1702: }
1703: else {
1704: dolog ("warning: Using timer based audio emulation\n");
1705: }
1706: }
1707:
1708: if (done) {
1709: VMChangeStateEntry *e;
1710:
1711: if (conf.period.hz <= 0) {
1712: if (conf.period.hz < 0) {
1713: dolog ("warning: Timer period is negative - %d "
1714: "treating as zero\n",
1715: conf.period.hz);
1716: }
1717: conf.period.ticks = 1;
1718: }
1719: else {
1720: conf.period.ticks = ticks_per_sec / conf.period.hz;
1721: }
1722:
1723: e = qemu_add_vm_change_state_handler (audio_vm_change_state_handler, s);
1724: if (!e) {
1725: dolog ("warning: Could not register change state handler\n"
1726: "(Audio can continue looping even after stopping the VM)\n");
1727: }
1.1 root 1728: }
1.1.1.2 root 1729: else {
1730: qemu_del_timer (s->ts);
1731: return NULL;
1732: }
1733:
1734: LIST_INIT (&s->card_head);
1735: register_savevm ("audio", 0, 1, audio_save, audio_load, s);
1736: qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks);
1737: return s;
1.1 root 1738: }
1.1.1.3 ! root 1739:
! 1740: CaptureVoiceOut *AUD_add_capture (
! 1741: AudioState *s,
! 1742: audsettings_t *as,
! 1743: struct audio_capture_ops *ops,
! 1744: void *cb_opaque
! 1745: )
! 1746: {
! 1747: CaptureVoiceOut *cap;
! 1748: struct capture_callback *cb;
! 1749:
! 1750: if (!s) {
! 1751: /* XXX suppress */
! 1752: s = &glob_audio_state;
! 1753: }
! 1754:
! 1755: if (audio_validate_settings (as)) {
! 1756: dolog ("Invalid settings were passed when trying to add capture\n");
! 1757: audio_print_settings (as);
! 1758: goto err0;
! 1759: }
! 1760:
! 1761: cb = audio_calloc (AUDIO_FUNC, 1, sizeof (*cb));
! 1762: if (!cb) {
! 1763: dolog ("Could not allocate capture callback information, size %zu\n",
! 1764: sizeof (*cb));
! 1765: goto err0;
! 1766: }
! 1767: cb->ops = *ops;
! 1768: cb->opaque = cb_opaque;
! 1769:
! 1770: cap = audio_pcm_capture_find_specific (s, as);
! 1771: if (cap) {
! 1772: LIST_INSERT_HEAD (&cap->cb_head, cb, entries);
! 1773: return cap;
! 1774: }
! 1775: else {
! 1776: HWVoiceOut *hw;
! 1777: CaptureVoiceOut *cap;
! 1778:
! 1779: cap = audio_calloc (AUDIO_FUNC, 1, sizeof (*cap));
! 1780: if (!cap) {
! 1781: dolog ("Could not allocate capture voice, size %zu\n",
! 1782: sizeof (*cap));
! 1783: goto err1;
! 1784: }
! 1785:
! 1786: hw = &cap->hw;
! 1787: LIST_INIT (&hw->sw_head);
! 1788: LIST_INIT (&cap->cb_head);
! 1789:
! 1790: /* XXX find a more elegant way */
! 1791: hw->samples = 4096 * 4;
! 1792: hw->mix_buf = audio_calloc (AUDIO_FUNC, hw->samples,
! 1793: sizeof (st_sample_t));
! 1794: if (!hw->mix_buf) {
! 1795: dolog ("Could not allocate capture mix buffer (%d samples)\n",
! 1796: hw->samples);
! 1797: goto err2;
! 1798: }
! 1799:
! 1800: audio_pcm_init_info (&hw->info, as);
! 1801:
! 1802: cap->buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
! 1803: if (!cap->buf) {
! 1804: dolog ("Could not allocate capture buffer "
! 1805: "(%d samples, each %d bytes)\n",
! 1806: hw->samples, 1 << hw->info.shift);
! 1807: goto err3;
! 1808: }
! 1809:
! 1810: hw->clip = mixeng_clip
! 1811: [hw->info.nchannels == 2]
! 1812: [hw->info.sign]
! 1813: [hw->info.swap_endianness]
! 1814: [hw->info.bits == 16];
! 1815:
! 1816: LIST_INSERT_HEAD (&s->cap_head, cap, entries);
! 1817: LIST_INSERT_HEAD (&cap->cb_head, cb, entries);
! 1818:
! 1819: hw = NULL;
! 1820: while ((hw = audio_pcm_hw_find_any_out (s, hw))) {
! 1821: audio_attach_capture (s, hw);
! 1822: }
! 1823: return cap;
! 1824:
! 1825: err3:
! 1826: qemu_free (cap->hw.mix_buf);
! 1827: err2:
! 1828: qemu_free (cap);
! 1829: err1:
! 1830: qemu_free (cb);
! 1831: err0:
! 1832: return NULL;
! 1833: }
! 1834: }
! 1835:
! 1836: void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque)
! 1837: {
! 1838: struct capture_callback *cb;
! 1839:
! 1840: for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) {
! 1841: if (cb->opaque == cb_opaque) {
! 1842: cb->ops.destroy (cb_opaque);
! 1843: LIST_REMOVE (cb, entries);
! 1844: qemu_free (cb);
! 1845:
! 1846: if (!cap->cb_head.lh_first) {
! 1847: SWVoiceOut *sw = cap->hw.sw_head.lh_first, *sw1;
! 1848:
! 1849: while (sw) {
! 1850: SWVoiceCap *sc = (SWVoiceCap *) sw;
! 1851: #ifdef DEBUG_CAPTURE
! 1852: dolog ("freeing %s\n", sw->name);
! 1853: #endif
! 1854:
! 1855: sw1 = sw->entries.le_next;
! 1856: if (sw->rate) {
! 1857: st_rate_stop (sw->rate);
! 1858: sw->rate = NULL;
! 1859: }
! 1860: LIST_REMOVE (sw, entries);
! 1861: LIST_REMOVE (sc, entries);
! 1862: qemu_free (sc);
! 1863: sw = sw1;
! 1864: }
! 1865: LIST_REMOVE (cap, entries);
! 1866: qemu_free (cap);
! 1867: }
! 1868: return;
! 1869: }
! 1870: }
! 1871: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.