audio_template.h 13.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/*
 * QEMU Audio subsystem header
 *
 * Copyright (c) 2005 Vassili Karpov (malc)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#ifdef DAC
B
bellard 已提交
26 27
#define NAME "playback"
#define HWBUF hw->mix_buf
28
#define TYPE out
B
bellard 已提交
29 30
#define HW HWVoiceOut
#define SW SWVoiceOut
31
#else
B
bellard 已提交
32
#define NAME "capture"
33
#define TYPE in
B
bellard 已提交
34 35 36
#define HW HWVoiceIn
#define SW SWVoiceIn
#define HWBUF hw->conv_buf
37 38
#endif

39
static void glue (audio_init_nb_voices_, TYPE) (struct audio_driver *drv)
B
bellard 已提交
40
{
41
    AudioState *s = &glob_audio_state;
B
bellard 已提交
42 43
    int max_voices = glue (drv->max_voices_, TYPE);
    int voice_size = glue (drv->voice_size_, TYPE);
B
bellard 已提交
44

B
bellard 已提交
45 46 47 48 49 50 51 52 53 54 55 56 57
    if (glue (s->nb_hw_voices_, TYPE) > max_voices) {
        if (!max_voices) {
#ifdef DAC
            dolog ("Driver `%s' does not support " NAME "\n", drv->name);
#endif
        }
        else {
            dolog ("Driver `%s' does not support %d " NAME " voices, max %d\n",
                   drv->name,
                   glue (s->nb_hw_voices_, TYPE),
                   max_voices);
        }
        glue (s->nb_hw_voices_, TYPE) = max_voices;
B
bellard 已提交
58 59
    }

B
bellard 已提交
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
    if (audio_bug (AUDIO_FUNC, !voice_size && max_voices)) {
        dolog ("drv=`%s' voice_size=0 max_voices=%d\n",
               drv->name, max_voices);
        glue (s->nb_hw_voices_, TYPE) = 0;
    }

    if (audio_bug (AUDIO_FUNC, voice_size && !max_voices)) {
        dolog ("drv=`%s' voice_size=%d max_voices=0\n",
               drv->name, voice_size);
    }
}

static void glue (audio_pcm_hw_free_resources_, TYPE) (HW *hw)
{
    if (HWBUF) {
        qemu_free (HWBUF);
    }

    HWBUF = NULL;
}

static int glue (audio_pcm_hw_alloc_resources_, TYPE) (HW *hw)
{
M
malc 已提交
83
    HWBUF = audio_calloc (AUDIO_FUNC, hw->samples, sizeof (struct st_sample));
B
bellard 已提交
84 85 86
    if (!HWBUF) {
        dolog ("Could not allocate " NAME " buffer (%d samples)\n",
               hw->samples);
B
bellard 已提交
87 88 89
        return -1;
    }

B
bellard 已提交
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
    return 0;
}

static void glue (audio_pcm_sw_free_resources_, TYPE) (SW *sw)
{
    if (sw->buf) {
        qemu_free (sw->buf);
    }

    if (sw->rate) {
        st_rate_stop (sw->rate);
    }

    sw->buf = NULL;
    sw->rate = NULL;
}

static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
{
    int samples;

    samples = ((int64_t) sw->hw->samples << 32) / sw->ratio;
B
bellard 已提交
112

M
malc 已提交
113
    sw->buf = audio_calloc (AUDIO_FUNC, samples, sizeof (struct st_sample));
B
bellard 已提交
114 115 116
    if (!sw->buf) {
        dolog ("Could not allocate buffer for `%s' (%d samples)\n",
               SW_NAME (sw), samples);
B
bellard 已提交
117 118 119
        return -1;
    }

B
bellard 已提交
120 121 122 123 124 125 126 127 128 129
#ifdef DAC
    sw->rate = st_rate_start (sw->info.freq, sw->hw->info.freq);
#else
    sw->rate = st_rate_start (sw->hw->info.freq, sw->info.freq);
#endif
    if (!sw->rate) {
        qemu_free (sw->buf);
        sw->buf = NULL;
        return -1;
    }
B
bellard 已提交
130 131 132
    return 0;
}

B
bellard 已提交
133 134 135 136
static int glue (audio_pcm_sw_init_, TYPE) (
    SW *sw,
    HW *hw,
    const char *name,
M
malc 已提交
137
    struct audsettings *as
B
bellard 已提交
138 139 140 141
    )
{
    int err;

B
bellard 已提交
142
    audio_pcm_init_info (&sw->info, as);
B
bellard 已提交
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
    sw->hw = hw;
    sw->active = 0;
#ifdef DAC
    sw->ratio = ((int64_t) sw->hw->info.freq << 32) / sw->info.freq;
    sw->total_hw_samples_mixed = 0;
    sw->empty = 1;
#else
    sw->ratio = ((int64_t) sw->info.freq << 32) / sw->hw->info.freq;
#endif

#ifdef DAC
    sw->conv = mixeng_conv
#else
    sw->clip = mixeng_clip
#endif
        [sw->info.nchannels == 2]
        [sw->info.sign]
B
bellard 已提交
160
        [sw->info.swap_endianness]
161
        [audio_bits_to_index (sw->info.bits)];
B
bellard 已提交
162 163 164 165 166 167 168 169 170 171

    sw->name = qemu_strdup (name);
    err = glue (audio_pcm_sw_alloc_resources_, TYPE) (sw);
    if (err) {
        qemu_free (sw->name);
        sw->name = NULL;
    }
    return err;
}

172 173 174 175 176 177 178 179 180 181 182
static void glue (audio_pcm_sw_fini_, TYPE) (SW *sw)
{
    glue (audio_pcm_sw_free_resources_, TYPE) (sw);
    if (sw->name) {
        qemu_free (sw->name);
        sw->name = NULL;
    }
}

static void glue (audio_pcm_hw_add_sw_, TYPE) (HW *hw, SW *sw)
{
B
Blue Swirl 已提交
183
    QLIST_INSERT_HEAD (&hw->sw_head, sw, entries);
184 185 186 187
}

static void glue (audio_pcm_hw_del_sw_, TYPE) (SW *sw)
{
B
Blue Swirl 已提交
188
    QLIST_REMOVE (sw, entries);
189 190
}

191
static void glue (audio_pcm_hw_gc_, TYPE) (HW **hwp)
192
{
193
    AudioState *s = &glob_audio_state;
B
bellard 已提交
194
    HW *hw = *hwp;
195 196

    if (!hw->sw_head.lh_first) {
197 198 199
#ifdef DAC
        audio_detach_capture (hw);
#endif
B
Blue Swirl 已提交
200
        QLIST_REMOVE (hw, entries);
B
bellard 已提交
201 202 203 204 205
        glue (s->nb_hw_voices_, TYPE) += 1;
        glue (audio_pcm_hw_free_resources_ ,TYPE) (hw);
        glue (hw->pcm_ops->fini_, TYPE) (hw);
        qemu_free (hw);
        *hwp = NULL;
206 207 208
    }
}

209
static HW *glue (audio_pcm_hw_find_any_, TYPE) (HW *hw)
210
{
211 212
    AudioState *s = &glob_audio_state;
    return hw ? hw->entries.le_next : glue (s->hw_head_, TYPE).lh_first;
213 214
}

215
static HW *glue (audio_pcm_hw_find_any_enabled_, TYPE) (HW *hw)
216
{
217
    while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (hw))) {
B
bellard 已提交
218
        if (hw->enabled) {
219 220 221 222 223 224 225 226
            return hw;
        }
    }
    return NULL;
}

static HW *glue (audio_pcm_hw_find_specific_, TYPE) (
    HW *hw,
M
malc 已提交
227
    struct audsettings *as
228 229
    )
{
230
    while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (hw))) {
B
bellard 已提交
231
        if (audio_pcm_info_eq (&hw->info, as)) {
232 233 234 235 236 237
            return hw;
        }
    }
    return NULL;
}

238
static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct audsettings *as)
239 240
{
    HW *hw;
241
    AudioState *s = &glob_audio_state;
B
bellard 已提交
242
    struct audio_driver *drv = s->drv;
243

B
bellard 已提交
244 245 246
    if (!glue (s->nb_hw_voices_, TYPE)) {
        return NULL;
    }
247

B
bellard 已提交
248 249 250
    if (audio_bug (AUDIO_FUNC, !drv)) {
        dolog ("No host audio driver\n");
        return NULL;
251 252
    }

B
bellard 已提交
253 254 255 256 257 258 259 260 261 262 263 264 265
    if (audio_bug (AUDIO_FUNC, !drv->pcm_ops)) {
        dolog ("Host audio driver without pcm_ops\n");
        return NULL;
    }

    hw = audio_calloc (AUDIO_FUNC, 1, glue (drv->voice_size_, TYPE));
    if (!hw) {
        dolog ("Can not allocate voice `%s' size %d\n",
               drv->name, glue (drv->voice_size_, TYPE));
        return NULL;
    }

    hw->pcm_ops = drv->pcm_ops;
B
Blue Swirl 已提交
266
    QLIST_INIT (&hw->sw_head);
267
#ifdef DAC
B
Blue Swirl 已提交
268
    QLIST_INIT (&hw->cap_head);
269
#endif
B
bellard 已提交
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
    if (glue (hw->pcm_ops->init_, TYPE) (hw, as)) {
        goto err0;
    }

    if (audio_bug (AUDIO_FUNC, hw->samples <= 0)) {
        dolog ("hw->samples=%d\n", hw->samples);
        goto err1;
    }

#ifdef DAC
    hw->clip = mixeng_clip
#else
    hw->conv = mixeng_conv
#endif
        [hw->info.nchannels == 2]
        [hw->info.sign]
B
bellard 已提交
286
        [hw->info.swap_endianness]
287
        [audio_bits_to_index (hw->info.bits)];
B
bellard 已提交
288 289 290 291 292

    if (glue (audio_pcm_hw_alloc_resources_, TYPE) (hw)) {
        goto err1;
    }

B
Blue Swirl 已提交
293
    QLIST_INSERT_HEAD (&s->glue (hw_head_, TYPE), hw, entries);
B
bellard 已提交
294
    glue (s->nb_hw_voices_, TYPE) -= 1;
295
#ifdef DAC
296
    audio_attach_capture (hw);
297
#endif
B
bellard 已提交
298 299 300 301 302 303
    return hw;

 err1:
    glue (hw->pcm_ops->fini_, TYPE) (hw);
 err0:
    qemu_free (hw);
304 305 306
    return NULL;
}

307
static HW *glue (audio_pcm_hw_add_, TYPE) (struct audsettings *as)
308 309 310
{
    HW *hw;

B
bellard 已提交
311
    if (glue (conf.fixed_, TYPE).enabled && glue (conf.fixed_, TYPE).greedy) {
312
        hw = glue (audio_pcm_hw_add_new_, TYPE) (as);
313 314 315 316 317
        if (hw) {
            return hw;
        }
    }

318
    hw = glue (audio_pcm_hw_find_specific_, TYPE) (NULL, as);
319 320 321 322
    if (hw) {
        return hw;
    }

323
    hw = glue (audio_pcm_hw_add_new_, TYPE) (as);
324 325 326 327
    if (hw) {
        return hw;
    }

328
    return glue (audio_pcm_hw_find_any_, TYPE) (NULL);
329 330 331
}

static SW *glue (audio_pcm_create_voice_pair_, TYPE) (
B
bellard 已提交
332
    const char *sw_name,
M
malc 已提交
333
    struct audsettings *as
334 335 336 337
    )
{
    SW *sw;
    HW *hw;
M
malc 已提交
338
    struct audsettings hw_as;
339

B
bellard 已提交
340 341 342 343 344
    if (glue (conf.fixed_, TYPE).enabled) {
        hw_as = glue (conf.fixed_, TYPE).settings;
    }
    else {
        hw_as = *as;
345 346
    }

B
bellard 已提交
347
    sw = audio_calloc (AUDIO_FUNC, 1, sizeof (*sw));
348
    if (!sw) {
B
bellard 已提交
349
        dolog ("Could not allocate soft voice `%s' (%zu bytes)\n",
B
bellard 已提交
350
               sw_name ? sw_name : "unknown", sizeof (*sw));
351 352 353
        goto err1;
    }

354
    hw = glue (audio_pcm_hw_add_, TYPE) (&hw_as);
355 356 357 358 359 360
    if (!hw) {
        goto err2;
    }

    glue (audio_pcm_hw_add_sw_, TYPE) (hw, sw);

B
bellard 已提交
361
    if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, sw_name, as)) {
362 363 364 365 366 367 368
        goto err3;
    }

    return sw;

err3:
    glue (audio_pcm_hw_del_sw_, TYPE) (sw);
369
    glue (audio_pcm_hw_gc_, TYPE) (&hw);
370 371 372 373 374 375
err2:
    qemu_free (sw);
err1:
    return NULL;
}

376
static void glue (audio_close_, TYPE) (SW *sw)
B
bellard 已提交
377 378 379
{
    glue (audio_pcm_sw_fini_, TYPE) (sw);
    glue (audio_pcm_hw_del_sw_, TYPE) (sw);
380
    glue (audio_pcm_hw_gc_, TYPE) (&sw->hw);
B
bellard 已提交
381 382
    qemu_free (sw);
}
B
bellard 已提交
383

B
bellard 已提交
384
void glue (AUD_close_, TYPE) (QEMUSoundCard *card, SW *sw)
385 386
{
    if (sw) {
387 388
        if (audio_bug (AUDIO_FUNC, !card)) {
            dolog ("card=%p\n", card);
B
bellard 已提交
389 390 391
            return;
        }

392
        glue (audio_close_, TYPE) (sw);
393 394 395 396
    }
}

SW *glue (AUD_open_, TYPE) (
B
bellard 已提交
397
    QEMUSoundCard *card,
398 399 400
    SW *sw,
    const char *name,
    void *callback_opaque ,
M
malc 已提交
401
    audio_callback_fn callback_fn,
M
malc 已提交
402
    struct audsettings *as
403 404
    )
{
405
    AudioState *s = &glob_audio_state;
406 407 408 409 410
#ifdef DAC
    int live = 0;
    SW *old_sw = NULL;
#endif

B
bellard 已提交
411 412 413
    ldebug ("open %s, freq %d, nchannels %d, fmt %d\n",
            name, as->freq, as->nchannels, as->fmt);

414 415 416
    if (audio_bug (AUDIO_FUNC, !card || !name || !callback_fn || !as)) {
        dolog ("card=%p name=%p callback_fn=%p as=%p\n",
               card, name, callback_fn, as);
417 418 419
        goto fail;
    }

B
bellard 已提交
420
    if (audio_bug (AUDIO_FUNC, audio_validate_settings (as))) {
B
bellard 已提交
421
        audio_print_settings (as);
422 423 424
        goto fail;
    }

B
bellard 已提交
425 426
    if (audio_bug (AUDIO_FUNC, !s->drv)) {
        dolog ("Can not open `%s' (no host audio driver)\n", name);
427 428 429
        goto fail;
    }

B
bellard 已提交
430
    if (sw && audio_pcm_info_eq (&sw->info, as)) {
431 432 433 434
        return sw;
    }

#ifdef DAC
B
bellard 已提交
435
    if (conf.plive && sw && (!sw->active && !sw->empty)) {
436 437 438
        live = sw->total_hw_samples_mixed;

#ifdef DEBUG_PLIVE
B
bellard 已提交
439
        dolog ("Replacing voice %s with %d live samples\n", SW_NAME (sw), live);
440
        dolog ("Old %s freq %d, bits %d, channels %d\n",
B
bellard 已提交
441
               SW_NAME (sw), sw->info.freq, sw->info.bits, sw->info.nchannels);
442
        dolog ("New %s freq %d, bits %d, channels %d\n",
B
bellard 已提交
443
               name,
444 445 446
               as->freq,
               (as->fmt == AUD_FMT_S16 || as->fmt == AUD_FMT_U16) ? 16 : 8,
               as->nchannels);
447 448 449 450 451 452 453 454 455 456
#endif

        if (live) {
            old_sw = sw;
            old_sw->callback.fn = NULL;
            sw = NULL;
        }
    }
#endif

B
bellard 已提交
457 458
    if (!glue (conf.fixed_, TYPE).enabled && sw) {
        glue (AUD_close_, TYPE) (card, sw);
459 460 461 462 463 464 465
        sw = NULL;
    }

    if (sw) {
        HW *hw = sw->hw;

        if (!hw) {
B
bellard 已提交
466 467
            dolog ("Internal logic error voice `%s' has no hardware store\n",
                   SW_NAME (sw));
468 469 470
            goto fail;
        }

B
bellard 已提交
471
        glue (audio_pcm_sw_fini_, TYPE) (sw);
B
bellard 已提交
472
        if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, name, as)) {
473 474 475 476
            goto fail;
        }
    }
    else {
477
        sw = glue (audio_pcm_create_voice_pair_, TYPE) (name, as);
478
        if (!sw) {
B
bellard 已提交
479
            dolog ("Failed to create voice `%s'\n", name);
B
bellard 已提交
480
            return NULL;
481 482 483
        }
    }

484 485 486 487
    sw->card = card;
    sw->vol = nominal_volume;
    sw->callback.fn = callback_fn;
    sw->callback.opaque = callback_opaque;
488 489

#ifdef DAC
490 491 492 493 494
    if (live) {
        int mixed =
            (live << old_sw->info.shift)
            * old_sw->info.bytes_per_second
            / sw->info.bytes_per_second;
495 496

#ifdef DEBUG_PLIVE
497
        dolog ("Silence will be mixed %d\n", mixed);
498
#endif
499 500
        sw->total_hw_samples_mixed += mixed;
    }
501 502 503
#endif

#ifdef DEBUG_AUDIO
504 505 506
    dolog ("%s\n", name);
    audio_pcm_print_info ("hw", &sw->hw->info);
    audio_pcm_print_info ("sw", &sw->info);
507 508 509 510 511
#endif

    return sw;

 fail:
B
bellard 已提交
512
    glue (AUD_close_, TYPE) (card, sw);
513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529
    return NULL;
}

int glue (AUD_is_active_, TYPE) (SW *sw)
{
    return sw ? sw->active : 0;
}

void glue (AUD_init_time_stamp_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts)
{
    if (!sw) {
        return;
    }

    ts->old_ts = sw->hw->ts_helper;
}

B
bellard 已提交
530
uint64_t glue (AUD_get_elapsed_usec_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts)
531 532 533 534 535 536 537 538 539
{
    uint64_t delta, cur_ts, old_ts;

    if (!sw) {
        return 0;
    }

    cur_ts = sw->hw->ts_helper;
    old_ts = ts->old_ts;
B
Blue Swirl 已提交
540
    /* dolog ("cur %" PRId64 " old %" PRId64 "\n", cur_ts, old_ts); */
541 542 543 544 545 546 547 548 549 550 551 552

    if (cur_ts >= old_ts) {
        delta = cur_ts - old_ts;
    }
    else {
        delta = UINT64_MAX - old_ts + cur_ts;
    }

    if (!delta) {
        return 0;
    }

M
malc 已提交
553
    return muldiv64 (delta, sw->hw->info.freq, 1000000);
554 555 556 557 558
}

#undef TYPE
#undef HW
#undef SW
B
bellard 已提交
559 560
#undef HWBUF
#undef NAME