|
|
1.1 ! root 1: /* ! 2: * QEMU Audio subsystem header ! 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: ! 25: #ifdef DAC ! 26: #define NAME "playback" ! 27: #define HWBUF hw->mix_buf ! 28: #define TYPE out ! 29: #define HW HWVoiceOut ! 30: #define SW SWVoiceOut ! 31: #else ! 32: #define NAME "capture" ! 33: #define TYPE in ! 34: #define HW HWVoiceIn ! 35: #define SW SWVoiceIn ! 36: #define HWBUF hw->conv_buf ! 37: #endif ! 38: ! 39: static void glue (audio_init_nb_voices_, TYPE) ( ! 40: AudioState *s, ! 41: struct audio_driver *drv ! 42: ) ! 43: { ! 44: int max_voices = glue (drv->max_voices_, TYPE); ! 45: int voice_size = glue (drv->voice_size_, TYPE); ! 46: ! 47: if (glue (s->nb_hw_voices_, TYPE) > max_voices) { ! 48: if (!max_voices) { ! 49: #ifdef DAC ! 50: dolog ("Driver `%s' does not support " NAME "\n", drv->name); ! 51: #endif ! 52: } ! 53: else { ! 54: dolog ("Driver `%s' does not support %d " NAME " voices, max %d\n", ! 55: drv->name, ! 56: glue (s->nb_hw_voices_, TYPE), ! 57: max_voices); ! 58: } ! 59: glue (s->nb_hw_voices_, TYPE) = max_voices; ! 60: } ! 61: ! 62: if (audio_bug (AUDIO_FUNC, !voice_size && max_voices)) { ! 63: dolog ("drv=`%s' voice_size=0 max_voices=%d\n", ! 64: drv->name, max_voices); ! 65: glue (s->nb_hw_voices_, TYPE) = 0; ! 66: } ! 67: ! 68: if (audio_bug (AUDIO_FUNC, voice_size && !max_voices)) { ! 69: dolog ("drv=`%s' voice_size=%d max_voices=0\n", ! 70: drv->name, voice_size); ! 71: } ! 72: } ! 73: ! 74: static void glue (audio_pcm_hw_free_resources_, TYPE) (HW *hw) ! 75: { ! 76: if (HWBUF) { ! 77: qemu_free (HWBUF); ! 78: } ! 79: ! 80: HWBUF = NULL; ! 81: } ! 82: ! 83: static int glue (audio_pcm_hw_alloc_resources_, TYPE) (HW *hw) ! 84: { ! 85: HWBUF = audio_calloc (AUDIO_FUNC, hw->samples, sizeof (st_sample_t)); ! 86: if (!HWBUF) { ! 87: dolog ("Could not allocate " NAME " buffer (%d samples)\n", ! 88: hw->samples); ! 89: return -1; ! 90: } ! 91: ! 92: return 0; ! 93: } ! 94: ! 95: static void glue (audio_pcm_sw_free_resources_, TYPE) (SW *sw) ! 96: { ! 97: if (sw->buf) { ! 98: qemu_free (sw->buf); ! 99: } ! 100: ! 101: if (sw->rate) { ! 102: st_rate_stop (sw->rate); ! 103: } ! 104: ! 105: sw->buf = NULL; ! 106: sw->rate = NULL; ! 107: } ! 108: ! 109: static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw) ! 110: { ! 111: int samples; ! 112: ! 113: #ifdef DAC ! 114: samples = sw->hw->samples; ! 115: #else ! 116: samples = ((int64_t) sw->hw->samples << 32) / sw->ratio; ! 117: #endif ! 118: ! 119: sw->buf = audio_calloc (AUDIO_FUNC, samples, sizeof (st_sample_t)); ! 120: if (!sw->buf) { ! 121: dolog ("Could not allocate buffer for `%s' (%d samples)\n", ! 122: SW_NAME (sw), samples); ! 123: return -1; ! 124: } ! 125: ! 126: #ifdef DAC ! 127: sw->rate = st_rate_start (sw->info.freq, sw->hw->info.freq); ! 128: #else ! 129: sw->rate = st_rate_start (sw->hw->info.freq, sw->info.freq); ! 130: #endif ! 131: if (!sw->rate) { ! 132: qemu_free (sw->buf); ! 133: sw->buf = NULL; ! 134: return -1; ! 135: } ! 136: return 0; ! 137: } ! 138: ! 139: static int glue (audio_pcm_sw_init_, TYPE) ( ! 140: SW *sw, ! 141: HW *hw, ! 142: const char *name, ! 143: audsettings_t *as, ! 144: int endian ! 145: ) ! 146: { ! 147: int err; ! 148: ! 149: audio_pcm_init_info (&sw->info, as, audio_need_to_swap_endian (endian)); ! 150: sw->hw = hw; ! 151: sw->active = 0; ! 152: #ifdef DAC ! 153: sw->ratio = ((int64_t) sw->hw->info.freq << 32) / sw->info.freq; ! 154: sw->total_hw_samples_mixed = 0; ! 155: sw->empty = 1; ! 156: #else ! 157: sw->ratio = ((int64_t) sw->info.freq << 32) / sw->hw->info.freq; ! 158: #endif ! 159: ! 160: #ifdef DAC ! 161: sw->conv = mixeng_conv ! 162: #else ! 163: sw->clip = mixeng_clip ! 164: #endif ! 165: [sw->info.nchannels == 2] ! 166: [sw->info.sign] ! 167: [sw->info.swap_endian] ! 168: [sw->info.bits == 16]; ! 169: ! 170: sw->name = qemu_strdup (name); ! 171: err = glue (audio_pcm_sw_alloc_resources_, TYPE) (sw); ! 172: if (err) { ! 173: qemu_free (sw->name); ! 174: sw->name = NULL; ! 175: } ! 176: return err; ! 177: } ! 178: ! 179: static void glue (audio_pcm_sw_fini_, TYPE) (SW *sw) ! 180: { ! 181: glue (audio_pcm_sw_free_resources_, TYPE) (sw); ! 182: if (sw->name) { ! 183: qemu_free (sw->name); ! 184: sw->name = NULL; ! 185: } ! 186: } ! 187: ! 188: static void glue (audio_pcm_hw_add_sw_, TYPE) (HW *hw, SW *sw) ! 189: { ! 190: LIST_INSERT_HEAD (&hw->sw_head, sw, entries); ! 191: } ! 192: ! 193: static void glue (audio_pcm_hw_del_sw_, TYPE) (SW *sw) ! 194: { ! 195: LIST_REMOVE (sw, entries); ! 196: } ! 197: ! 198: static void glue (audio_pcm_hw_gc_, TYPE) (AudioState *s, HW **hwp) ! 199: { ! 200: HW *hw = *hwp; ! 201: ! 202: if (!hw->sw_head.lh_first) { ! 203: LIST_REMOVE (hw, entries); ! 204: glue (s->nb_hw_voices_, TYPE) += 1; ! 205: glue (audio_pcm_hw_free_resources_ ,TYPE) (hw); ! 206: glue (hw->pcm_ops->fini_, TYPE) (hw); ! 207: qemu_free (hw); ! 208: *hwp = NULL; ! 209: } ! 210: } ! 211: ! 212: static HW *glue (audio_pcm_hw_find_any_, TYPE) (AudioState *s, HW *hw) ! 213: { ! 214: return hw ? hw->entries.le_next : s->glue (hw_head_, TYPE).lh_first; ! 215: } ! 216: ! 217: static HW *glue (audio_pcm_hw_find_any_enabled_, TYPE) (AudioState *s, HW *hw) ! 218: { ! 219: while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (s, hw))) { ! 220: if (hw->enabled) { ! 221: return hw; ! 222: } ! 223: } ! 224: return NULL; ! 225: } ! 226: ! 227: static HW *glue (audio_pcm_hw_find_specific_, TYPE) ( ! 228: AudioState *s, ! 229: HW *hw, ! 230: audsettings_t *as ! 231: ) ! 232: { ! 233: while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (s, hw))) { ! 234: if (audio_pcm_info_eq (&hw->info, as)) { ! 235: return hw; ! 236: } ! 237: } ! 238: return NULL; ! 239: } ! 240: ! 241: static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s, audsettings_t *as) ! 242: { ! 243: HW *hw; ! 244: struct audio_driver *drv = s->drv; ! 245: ! 246: if (!glue (s->nb_hw_voices_, TYPE)) { ! 247: return NULL; ! 248: } ! 249: ! 250: if (audio_bug (AUDIO_FUNC, !drv)) { ! 251: dolog ("No host audio driver\n"); ! 252: return NULL; ! 253: } ! 254: ! 255: if (audio_bug (AUDIO_FUNC, !drv->pcm_ops)) { ! 256: dolog ("Host audio driver without pcm_ops\n"); ! 257: return NULL; ! 258: } ! 259: ! 260: hw = audio_calloc (AUDIO_FUNC, 1, glue (drv->voice_size_, TYPE)); ! 261: if (!hw) { ! 262: dolog ("Can not allocate voice `%s' size %d\n", ! 263: drv->name, glue (drv->voice_size_, TYPE)); ! 264: return NULL; ! 265: } ! 266: ! 267: hw->pcm_ops = drv->pcm_ops; ! 268: LIST_INIT (&hw->sw_head); ! 269: ! 270: if (glue (hw->pcm_ops->init_, TYPE) (hw, as)) { ! 271: goto err0; ! 272: } ! 273: ! 274: if (audio_bug (AUDIO_FUNC, hw->samples <= 0)) { ! 275: dolog ("hw->samples=%d\n", hw->samples); ! 276: goto err1; ! 277: } ! 278: ! 279: #ifdef DAC ! 280: hw->clip = mixeng_clip ! 281: #else ! 282: hw->conv = mixeng_conv ! 283: #endif ! 284: [hw->info.nchannels == 2] ! 285: [hw->info.sign] ! 286: [hw->info.swap_endian] ! 287: [hw->info.bits == 16]; ! 288: ! 289: if (glue (audio_pcm_hw_alloc_resources_, TYPE) (hw)) { ! 290: goto err1; ! 291: } ! 292: ! 293: LIST_INSERT_HEAD (&s->glue (hw_head_, TYPE), hw, entries); ! 294: glue (s->nb_hw_voices_, TYPE) -= 1; ! 295: return hw; ! 296: ! 297: err1: ! 298: glue (hw->pcm_ops->fini_, TYPE) (hw); ! 299: err0: ! 300: qemu_free (hw); ! 301: return NULL; ! 302: } ! 303: ! 304: static HW *glue (audio_pcm_hw_add_, TYPE) (AudioState *s, audsettings_t *as) ! 305: { ! 306: HW *hw; ! 307: ! 308: if (glue (conf.fixed_, TYPE).enabled && glue (conf.fixed_, TYPE).greedy) { ! 309: hw = glue (audio_pcm_hw_add_new_, TYPE) (s, as); ! 310: if (hw) { ! 311: return hw; ! 312: } ! 313: } ! 314: ! 315: hw = glue (audio_pcm_hw_find_specific_, TYPE) (s, NULL, as); ! 316: if (hw) { ! 317: return hw; ! 318: } ! 319: ! 320: hw = glue (audio_pcm_hw_add_new_, TYPE) (s, as); ! 321: if (hw) { ! 322: return hw; ! 323: } ! 324: ! 325: return glue (audio_pcm_hw_find_any_, TYPE) (s, NULL); ! 326: } ! 327: ! 328: static SW *glue (audio_pcm_create_voice_pair_, TYPE) ( ! 329: AudioState *s, ! 330: const char *sw_name, ! 331: audsettings_t *as, ! 332: int sw_endian ! 333: ) ! 334: { ! 335: SW *sw; ! 336: HW *hw; ! 337: audsettings_t hw_as; ! 338: ! 339: if (glue (conf.fixed_, TYPE).enabled) { ! 340: hw_as = glue (conf.fixed_, TYPE).settings; ! 341: } ! 342: else { ! 343: hw_as = *as; ! 344: } ! 345: ! 346: sw = audio_calloc (AUDIO_FUNC, 1, sizeof (*sw)); ! 347: if (!sw) { ! 348: dolog ("Could not allocate soft voice `%s' (%zu bytes)\n", ! 349: sw_name ? sw_name : "unknown", sizeof (*sw)); ! 350: goto err1; ! 351: } ! 352: ! 353: hw = glue (audio_pcm_hw_add_, TYPE) (s, &hw_as); ! 354: if (!hw) { ! 355: goto err2; ! 356: } ! 357: ! 358: glue (audio_pcm_hw_add_sw_, TYPE) (hw, sw); ! 359: ! 360: if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, sw_name, as, sw_endian)) { ! 361: goto err3; ! 362: } ! 363: ! 364: return sw; ! 365: ! 366: err3: ! 367: glue (audio_pcm_hw_del_sw_, TYPE) (sw); ! 368: glue (audio_pcm_hw_gc_, TYPE) (s, &hw); ! 369: err2: ! 370: qemu_free (sw); ! 371: err1: ! 372: return NULL; ! 373: } ! 374: ! 375: static void glue (audio_close_, TYPE) (AudioState *s, SW *sw) ! 376: { ! 377: glue (audio_pcm_sw_fini_, TYPE) (sw); ! 378: glue (audio_pcm_hw_del_sw_, TYPE) (sw); ! 379: glue (audio_pcm_hw_gc_, TYPE) (s, &sw->hw); ! 380: qemu_free (sw); ! 381: } ! 382: ! 383: void glue (AUD_close_, TYPE) (QEMUSoundCard *card, SW *sw) ! 384: { ! 385: if (sw) { ! 386: if (audio_bug (AUDIO_FUNC, !card || !card->audio)) { ! 387: dolog ("card=%p card->audio=%p\n", ! 388: card, card ? card->audio : NULL); ! 389: return; ! 390: } ! 391: ! 392: glue (audio_close_, TYPE) (card->audio, sw); ! 393: } ! 394: } ! 395: ! 396: SW *glue (AUD_open_, TYPE) ( ! 397: QEMUSoundCard *card, ! 398: SW *sw, ! 399: const char *name, ! 400: void *callback_opaque , ! 401: audio_callback_fn_t callback_fn, ! 402: audsettings_t *as, ! 403: int sw_endian ! 404: ) ! 405: { ! 406: AudioState *s; ! 407: #ifdef DAC ! 408: int live = 0; ! 409: SW *old_sw = NULL; ! 410: #endif ! 411: ! 412: ldebug ("open %s, freq %d, nchannels %d, fmt %d\n", ! 413: name, as->freq, as->nchannels, as->fmt); ! 414: ! 415: if (audio_bug (AUDIO_FUNC, ! 416: !card || !card->audio || !name || !callback_fn || !as)) { ! 417: dolog ("card=%p card->audio=%p name=%p callback_fn=%p as=%p\n", ! 418: card, card ? card->audio : NULL, name, callback_fn, as); ! 419: goto fail; ! 420: } ! 421: ! 422: s = card->audio; ! 423: ! 424: if (audio_bug (AUDIO_FUNC, audio_validate_settigs (as))) { ! 425: audio_print_settings (as); ! 426: goto fail; ! 427: } ! 428: ! 429: if (audio_bug (AUDIO_FUNC, !s->drv)) { ! 430: dolog ("Can not open `%s' (no host audio driver)\n", name); ! 431: goto fail; ! 432: } ! 433: ! 434: if (sw && audio_pcm_info_eq (&sw->info, as)) { ! 435: return sw; ! 436: } ! 437: ! 438: #ifdef DAC ! 439: if (conf.plive && sw && (!sw->active && !sw->empty)) { ! 440: live = sw->total_hw_samples_mixed; ! 441: ! 442: #ifdef DEBUG_PLIVE ! 443: dolog ("Replacing voice %s with %d live samples\n", SW_NAME (sw), live); ! 444: dolog ("Old %s freq %d, bits %d, channels %d\n", ! 445: SW_NAME (sw), sw->info.freq, sw->info.bits, sw->info.nchannels); ! 446: dolog ("New %s freq %d, bits %d, channels %d\n", ! 447: name, ! 448: freq, ! 449: (fmt == AUD_FMT_S16 || fmt == AUD_FMT_U16) ? 16 : 8, ! 450: nchannels); ! 451: #endif ! 452: ! 453: if (live) { ! 454: old_sw = sw; ! 455: old_sw->callback.fn = NULL; ! 456: sw = NULL; ! 457: } ! 458: } ! 459: #endif ! 460: ! 461: if (!glue (conf.fixed_, TYPE).enabled && sw) { ! 462: glue (AUD_close_, TYPE) (card, sw); ! 463: sw = NULL; ! 464: } ! 465: ! 466: if (sw) { ! 467: HW *hw = sw->hw; ! 468: ! 469: if (!hw) { ! 470: dolog ("Internal logic error voice `%s' has no hardware store\n", ! 471: SW_NAME (sw)); ! 472: goto fail; ! 473: } ! 474: ! 475: glue (audio_pcm_sw_fini_, TYPE) (sw); ! 476: if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, name, as, sw_endian)) { ! 477: goto fail; ! 478: } ! 479: } ! 480: else { ! 481: sw = glue (audio_pcm_create_voice_pair_, TYPE) (s, name, as, sw_endian); ! 482: if (!sw) { ! 483: dolog ("Failed to create voice `%s'\n", name); ! 484: return NULL; ! 485: } ! 486: } ! 487: ! 488: if (sw) { ! 489: sw->vol = nominal_volume; ! 490: sw->callback.fn = callback_fn; ! 491: sw->callback.opaque = callback_opaque; ! 492: ! 493: #ifdef DAC ! 494: if (live) { ! 495: int mixed = ! 496: (live << old_sw->info.shift) ! 497: * old_sw->info.bytes_per_second ! 498: / sw->info.bytes_per_second; ! 499: ! 500: #ifdef DEBUG_PLIVE ! 501: dolog ("Silence will be mixed %d\n", mixed); ! 502: #endif ! 503: sw->total_hw_samples_mixed += mixed; ! 504: } ! 505: #endif ! 506: ! 507: #ifdef DEBUG_AUDIO ! 508: dolog ("%s\n", name); ! 509: audio_pcm_print_info ("hw", &sw->hw->info); ! 510: audio_pcm_print_info ("sw", &sw->info); ! 511: #endif ! 512: } ! 513: ! 514: return sw; ! 515: ! 516: fail: ! 517: glue (AUD_close_, TYPE) (card, sw); ! 518: return NULL; ! 519: } ! 520: ! 521: int glue (AUD_is_active_, TYPE) (SW *sw) ! 522: { ! 523: return sw ? sw->active : 0; ! 524: } ! 525: ! 526: void glue (AUD_init_time_stamp_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts) ! 527: { ! 528: if (!sw) { ! 529: return; ! 530: } ! 531: ! 532: ts->old_ts = sw->hw->ts_helper; ! 533: } ! 534: ! 535: uint64_t glue (AUD_get_elapsed_usec_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts) ! 536: { ! 537: uint64_t delta, cur_ts, old_ts; ! 538: ! 539: if (!sw) { ! 540: return 0; ! 541: } ! 542: ! 543: cur_ts = sw->hw->ts_helper; ! 544: old_ts = ts->old_ts; ! 545: /* dolog ("cur %lld old %lld\n", cur_ts, old_ts); */ ! 546: ! 547: if (cur_ts >= old_ts) { ! 548: delta = cur_ts - old_ts; ! 549: } ! 550: else { ! 551: delta = UINT64_MAX - old_ts + cur_ts; ! 552: } ! 553: ! 554: if (!delta) { ! 555: return 0; ! 556: } ! 557: ! 558: return (delta * sw->hw->info.freq) / 1000000; ! 559: } ! 560: ! 561: #undef TYPE ! 562: #undef HW ! 563: #undef SW ! 564: #undef HWBUF ! 565: #undef NAME
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.