qemu/audio/winwaveaudio.c
<<
>>
Prefs
   1/* public domain */
   2
   3#include "qemu-common.h"
   4#include "sysemu/sysemu.h"
   5#include "audio.h"
   6
   7#define AUDIO_CAP "winwave"
   8#include "audio_int.h"
   9
  10#include <windows.h>
  11#include <mmsystem.h>
  12
  13#include "audio_win_int.h"
  14
  15static struct {
  16    int dac_headers;
  17    int dac_samples;
  18    int adc_headers;
  19    int adc_samples;
  20} conf = {
  21    .dac_headers = 4,
  22    .dac_samples = 1024,
  23    .adc_headers = 4,
  24    .adc_samples = 1024
  25};
  26
  27typedef struct {
  28    HWVoiceOut hw;
  29    HWAVEOUT hwo;
  30    WAVEHDR *hdrs;
  31    HANDLE event;
  32    void *pcm_buf;
  33    int avail;
  34    int pending;
  35    int curhdr;
  36    int paused;
  37    CRITICAL_SECTION crit_sect;
  38} WaveVoiceOut;
  39
  40typedef struct {
  41    HWVoiceIn hw;
  42    HWAVEIN hwi;
  43    WAVEHDR *hdrs;
  44    HANDLE event;
  45    void *pcm_buf;
  46    int curhdr;
  47    int paused;
  48    int rpos;
  49    int avail;
  50    CRITICAL_SECTION crit_sect;
  51} WaveVoiceIn;
  52
  53static void winwave_log_mmresult (MMRESULT mr)
  54{
  55    const char *str = "BUG";
  56
  57    switch (mr) {
  58    case MMSYSERR_NOERROR:
  59        str = "Success";
  60        break;
  61
  62    case MMSYSERR_INVALHANDLE:
  63        str = "Specified device handle is invalid";
  64        break;
  65
  66    case MMSYSERR_BADDEVICEID:
  67        str = "Specified device id is out of range";
  68        break;
  69
  70    case MMSYSERR_NODRIVER:
  71        str = "No device driver is present";
  72        break;
  73
  74    case MMSYSERR_NOMEM:
  75        str = "Unable to allocate or lock memory";
  76        break;
  77
  78    case WAVERR_SYNC:
  79        str = "Device is synchronous but waveOutOpen was called "
  80            "without using the WINWAVE_ALLOWSYNC flag";
  81        break;
  82
  83    case WAVERR_UNPREPARED:
  84        str = "The data block pointed to by the pwh parameter "
  85            "hasn't been prepared";
  86        break;
  87
  88    case WAVERR_STILLPLAYING:
  89        str = "There are still buffers in the queue";
  90        break;
  91
  92    default:
  93        dolog ("Reason: Unknown (MMRESULT %#x)\n", mr);
  94        return;
  95    }
  96
  97    dolog ("Reason: %s\n", str);
  98}
  99
 100static void GCC_FMT_ATTR (2, 3) winwave_logerr (
 101    MMRESULT mr,
 102    const char *fmt,
 103    ...
 104    )
 105{
 106    va_list ap;
 107
 108    va_start (ap, fmt);
 109    AUD_vlog (AUDIO_CAP, fmt, ap);
 110    va_end (ap);
 111
 112    AUD_log (NULL, " failed\n");
 113    winwave_log_mmresult (mr);
 114}
 115
 116static void winwave_anal_close_out (WaveVoiceOut *wave)
 117{
 118    MMRESULT mr;
 119
 120    mr = waveOutClose (wave->hwo);
 121    if (mr != MMSYSERR_NOERROR) {
 122        winwave_logerr (mr, "waveOutClose");
 123    }
 124    wave->hwo = NULL;
 125}
 126
 127static void CALLBACK winwave_callback_out (
 128    HWAVEOUT hwo,
 129    UINT msg,
 130    DWORD_PTR dwInstance,
 131    DWORD_PTR dwParam1,
 132    DWORD_PTR dwParam2
 133    )
 134{
 135    WaveVoiceOut *wave = (WaveVoiceOut *) dwInstance;
 136
 137    switch (msg) {
 138    case WOM_DONE:
 139        {
 140            WAVEHDR *h = (WAVEHDR *) dwParam1;
 141            if (!h->dwUser) {
 142                h->dwUser = 1;
 143                EnterCriticalSection (&wave->crit_sect);
 144                {
 145                    wave->avail += conf.dac_samples;
 146                }
 147                LeaveCriticalSection (&wave->crit_sect);
 148                if (wave->hw.poll_mode) {
 149                    if (!SetEvent (wave->event)) {
 150                        dolog ("DAC SetEvent failed %lx\n", GetLastError ());
 151                    }
 152                }
 153            }
 154        }
 155        break;
 156
 157    case WOM_CLOSE:
 158    case WOM_OPEN:
 159        break;
 160
 161    default:
 162        dolog ("unknown wave out callback msg %x\n", msg);
 163    }
 164}
 165
 166static int winwave_init_out (HWVoiceOut *hw, struct audsettings *as)
 167{
 168    int i;
 169    int err;
 170    MMRESULT mr;
 171    WAVEFORMATEX wfx;
 172    WaveVoiceOut *wave;
 173
 174    wave = (WaveVoiceOut *) hw;
 175
 176    InitializeCriticalSection (&wave->crit_sect);
 177
 178    err = waveformat_from_audio_settings (&wfx, as);
 179    if (err) {
 180        goto err0;
 181    }
 182
 183    mr = waveOutOpen (&wave->hwo, WAVE_MAPPER, &wfx,
 184                      (DWORD_PTR) winwave_callback_out,
 185                      (DWORD_PTR) wave, CALLBACK_FUNCTION);
 186    if (mr != MMSYSERR_NOERROR) {
 187        winwave_logerr (mr, "waveOutOpen");
 188        goto err1;
 189    }
 190
 191    wave->hdrs = audio_calloc (AUDIO_FUNC, conf.dac_headers,
 192                               sizeof (*wave->hdrs));
 193    if (!wave->hdrs) {
 194        goto err2;
 195    }
 196
 197    audio_pcm_init_info (&hw->info, as);
 198    hw->samples = conf.dac_samples * conf.dac_headers;
 199    wave->avail = hw->samples;
 200
 201    wave->pcm_buf = audio_calloc (AUDIO_FUNC, conf.dac_samples,
 202                                  conf.dac_headers << hw->info.shift);
 203    if (!wave->pcm_buf) {
 204        goto err3;
 205    }
 206
 207    for (i = 0; i < conf.dac_headers; ++i) {
 208        WAVEHDR *h = &wave->hdrs[i];
 209
 210        h->dwUser = 0;
 211        h->dwBufferLength = conf.dac_samples << hw->info.shift;
 212        h->lpData = advance (wave->pcm_buf, i * h->dwBufferLength);
 213        h->dwFlags = 0;
 214
 215        mr = waveOutPrepareHeader (wave->hwo, h, sizeof (*h));
 216        if (mr != MMSYSERR_NOERROR) {
 217            winwave_logerr (mr, "waveOutPrepareHeader(%d)", i);
 218            goto err4;
 219        }
 220    }
 221
 222    return 0;
 223
 224 err4:
 225    g_free (wave->pcm_buf);
 226 err3:
 227    g_free (wave->hdrs);
 228 err2:
 229    winwave_anal_close_out (wave);
 230 err1:
 231 err0:
 232    return -1;
 233}
 234
 235static int winwave_write (SWVoiceOut *sw, void *buf, int len)
 236{
 237    return audio_pcm_sw_write (sw, buf, len);
 238}
 239
 240static int winwave_run_out (HWVoiceOut *hw, int live)
 241{
 242    WaveVoiceOut *wave = (WaveVoiceOut *) hw;
 243    int decr;
 244    int doreset;
 245
 246    EnterCriticalSection (&wave->crit_sect);
 247    {
 248        decr = audio_MIN (live, wave->avail);
 249        decr = audio_pcm_hw_clip_out (hw, wave->pcm_buf, decr, wave->pending);
 250        wave->pending += decr;
 251        wave->avail -= decr;
 252    }
 253    LeaveCriticalSection (&wave->crit_sect);
 254
 255    doreset = hw->poll_mode && (wave->pending >= conf.dac_samples);
 256    if (doreset && !ResetEvent (wave->event)) {
 257        dolog ("DAC ResetEvent failed %lx\n", GetLastError ());
 258    }
 259
 260    while (wave->pending >= conf.dac_samples) {
 261        MMRESULT mr;
 262        WAVEHDR *h = &wave->hdrs[wave->curhdr];
 263
 264        h->dwUser = 0;
 265        mr = waveOutWrite (wave->hwo, h, sizeof (*h));
 266        if (mr != MMSYSERR_NOERROR) {
 267            winwave_logerr (mr, "waveOutWrite(%d)", wave->curhdr);
 268            break;
 269        }
 270
 271        wave->pending -= conf.dac_samples;
 272        wave->curhdr = (wave->curhdr + 1) % conf.dac_headers;
 273    }
 274
 275    return decr;
 276}
 277
 278static void winwave_poll (void *opaque)
 279{
 280    (void) opaque;
 281    audio_run ("winwave_poll");
 282}
 283
 284static void winwave_fini_out (HWVoiceOut *hw)
 285{
 286    int i;
 287    MMRESULT mr;
 288    WaveVoiceOut *wave = (WaveVoiceOut *) hw;
 289
 290    mr = waveOutReset (wave->hwo);
 291    if (mr != MMSYSERR_NOERROR) {
 292        winwave_logerr (mr, "waveOutReset");
 293    }
 294
 295    for (i = 0; i < conf.dac_headers; ++i) {
 296        mr = waveOutUnprepareHeader (wave->hwo, &wave->hdrs[i],
 297                                     sizeof (wave->hdrs[i]));
 298        if (mr != MMSYSERR_NOERROR) {
 299            winwave_logerr (mr, "waveOutUnprepareHeader(%d)", i);
 300        }
 301    }
 302
 303    winwave_anal_close_out (wave);
 304
 305    if (wave->event) {
 306        qemu_del_wait_object (wave->event, winwave_poll, wave);
 307        if (!CloseHandle (wave->event)) {
 308            dolog ("DAC CloseHandle failed %lx\n", GetLastError ());
 309        }
 310        wave->event = NULL;
 311    }
 312
 313    g_free (wave->pcm_buf);
 314    wave->pcm_buf = NULL;
 315
 316    g_free (wave->hdrs);
 317    wave->hdrs = NULL;
 318}
 319
 320static int winwave_ctl_out (HWVoiceOut *hw, int cmd, ...)
 321{
 322    MMRESULT mr;
 323    WaveVoiceOut *wave = (WaveVoiceOut *) hw;
 324
 325    switch (cmd) {
 326    case VOICE_ENABLE:
 327        {
 328            va_list ap;
 329            int poll_mode;
 330
 331            va_start (ap, cmd);
 332            poll_mode = va_arg (ap, int);
 333            va_end (ap);
 334
 335            if (poll_mode && !wave->event) {
 336                wave->event = CreateEvent (NULL, TRUE, TRUE, NULL);
 337                if (!wave->event) {
 338                    dolog ("DAC CreateEvent: %lx, poll mode will be disabled\n",
 339                           GetLastError ());
 340                }
 341            }
 342
 343            if (wave->event) {
 344                int ret;
 345
 346                ret = qemu_add_wait_object (wave->event, winwave_poll, wave);
 347                hw->poll_mode = (ret == 0);
 348            }
 349            else {
 350                hw->poll_mode = 0;
 351            }
 352            wave->paused = 0;
 353        }
 354        return 0;
 355
 356    case VOICE_DISABLE:
 357        if (!wave->paused) {
 358            mr = waveOutReset (wave->hwo);
 359            if (mr != MMSYSERR_NOERROR) {
 360                winwave_logerr (mr, "waveOutReset");
 361            }
 362            else {
 363                wave->paused = 1;
 364            }
 365        }
 366        if (wave->event) {
 367            qemu_del_wait_object (wave->event, winwave_poll, wave);
 368        }
 369        return 0;
 370    }
 371    return -1;
 372}
 373
 374static void winwave_anal_close_in (WaveVoiceIn *wave)
 375{
 376    MMRESULT mr;
 377
 378    mr = waveInClose (wave->hwi);
 379    if (mr != MMSYSERR_NOERROR) {
 380        winwave_logerr (mr, "waveInClose");
 381    }
 382    wave->hwi = NULL;
 383}
 384
 385static void CALLBACK winwave_callback_in (
 386    HWAVEIN *hwi,
 387    UINT msg,
 388    DWORD_PTR dwInstance,
 389    DWORD_PTR dwParam1,
 390    DWORD_PTR dwParam2
 391    )
 392{
 393    WaveVoiceIn *wave = (WaveVoiceIn *) dwInstance;
 394
 395    switch (msg) {
 396    case WIM_DATA:
 397        {
 398            WAVEHDR *h = (WAVEHDR *) dwParam1;
 399            if (!h->dwUser) {
 400                h->dwUser = 1;
 401                EnterCriticalSection (&wave->crit_sect);
 402                {
 403                    wave->avail += conf.adc_samples;
 404                }
 405                LeaveCriticalSection (&wave->crit_sect);
 406                if (wave->hw.poll_mode) {
 407                    if (!SetEvent (wave->event)) {
 408                        dolog ("ADC SetEvent failed %lx\n", GetLastError ());
 409                    }
 410                }
 411            }
 412        }
 413        break;
 414
 415    case WIM_CLOSE:
 416    case WIM_OPEN:
 417        break;
 418
 419    default:
 420        dolog ("unknown wave in callback msg %x\n", msg);
 421    }
 422}
 423
 424static void winwave_add_buffers (WaveVoiceIn *wave, int samples)
 425{
 426    int doreset;
 427
 428    doreset = wave->hw.poll_mode && (samples >= conf.adc_samples);
 429    if (doreset && !ResetEvent (wave->event)) {
 430        dolog ("ADC ResetEvent failed %lx\n", GetLastError ());
 431    }
 432
 433    while (samples >= conf.adc_samples) {
 434        MMRESULT mr;
 435        WAVEHDR *h = &wave->hdrs[wave->curhdr];
 436
 437        h->dwUser = 0;
 438        mr = waveInAddBuffer (wave->hwi, h, sizeof (*h));
 439        if (mr != MMSYSERR_NOERROR) {
 440            winwave_logerr (mr, "waveInAddBuffer(%d)", wave->curhdr);
 441        }
 442        wave->curhdr = (wave->curhdr + 1) % conf.adc_headers;
 443        samples -= conf.adc_samples;
 444    }
 445}
 446
 447static int winwave_init_in (HWVoiceIn *hw, struct audsettings *as)
 448{
 449    int i;
 450    int err;
 451    MMRESULT mr;
 452    WAVEFORMATEX wfx;
 453    WaveVoiceIn *wave;
 454
 455    wave = (WaveVoiceIn *) hw;
 456
 457    InitializeCriticalSection (&wave->crit_sect);
 458
 459    err = waveformat_from_audio_settings (&wfx, as);
 460    if (err) {
 461        goto err0;
 462    }
 463
 464    mr = waveInOpen (&wave->hwi, WAVE_MAPPER, &wfx,
 465                     (DWORD_PTR) winwave_callback_in,
 466                     (DWORD_PTR) wave, CALLBACK_FUNCTION);
 467    if (mr != MMSYSERR_NOERROR) {
 468        winwave_logerr (mr, "waveInOpen");
 469        goto err1;
 470    }
 471
 472    wave->hdrs = audio_calloc (AUDIO_FUNC, conf.dac_headers,
 473                               sizeof (*wave->hdrs));
 474    if (!wave->hdrs) {
 475        goto err2;
 476    }
 477
 478    audio_pcm_init_info (&hw->info, as);
 479    hw->samples = conf.adc_samples * conf.adc_headers;
 480    wave->avail = 0;
 481
 482    wave->pcm_buf = audio_calloc (AUDIO_FUNC, conf.adc_samples,
 483                                  conf.adc_headers << hw->info.shift);
 484    if (!wave->pcm_buf) {
 485        goto err3;
 486    }
 487
 488    for (i = 0; i < conf.adc_headers; ++i) {
 489        WAVEHDR *h = &wave->hdrs[i];
 490
 491        h->dwUser = 0;
 492        h->dwBufferLength = conf.adc_samples << hw->info.shift;
 493        h->lpData = advance (wave->pcm_buf, i * h->dwBufferLength);
 494        h->dwFlags = 0;
 495
 496        mr = waveInPrepareHeader (wave->hwi, h, sizeof (*h));
 497        if (mr != MMSYSERR_NOERROR) {
 498            winwave_logerr (mr, "waveInPrepareHeader(%d)", i);
 499            goto err4;
 500        }
 501    }
 502
 503    wave->paused = 1;
 504    winwave_add_buffers (wave, hw->samples);
 505    return 0;
 506
 507 err4:
 508    g_free (wave->pcm_buf);
 509 err3:
 510    g_free (wave->hdrs);
 511 err2:
 512    winwave_anal_close_in (wave);
 513 err1:
 514 err0:
 515    return -1;
 516}
 517
 518static void winwave_fini_in (HWVoiceIn *hw)
 519{
 520    int i;
 521    MMRESULT mr;
 522    WaveVoiceIn *wave = (WaveVoiceIn *) hw;
 523
 524    mr = waveInReset (wave->hwi);
 525    if (mr != MMSYSERR_NOERROR) {
 526        winwave_logerr (mr, "waveInReset");
 527    }
 528
 529    for (i = 0; i < conf.adc_headers; ++i) {
 530        mr = waveInUnprepareHeader (wave->hwi, &wave->hdrs[i],
 531                                     sizeof (wave->hdrs[i]));
 532        if (mr != MMSYSERR_NOERROR) {
 533            winwave_logerr (mr, "waveInUnprepareHeader(%d)", i);
 534        }
 535    }
 536
 537    winwave_anal_close_in (wave);
 538
 539    if (wave->event) {
 540        qemu_del_wait_object (wave->event, winwave_poll, wave);
 541        if (!CloseHandle (wave->event)) {
 542            dolog ("ADC CloseHandle failed %lx\n", GetLastError ());
 543        }
 544        wave->event = NULL;
 545    }
 546
 547    g_free (wave->pcm_buf);
 548    wave->pcm_buf = NULL;
 549
 550    g_free (wave->hdrs);
 551    wave->hdrs = NULL;
 552}
 553
 554static int winwave_run_in (HWVoiceIn *hw)
 555{
 556    WaveVoiceIn *wave = (WaveVoiceIn *) hw;
 557    int live = audio_pcm_hw_get_live_in (hw);
 558    int dead = hw->samples - live;
 559    int decr, ret;
 560
 561    if (!dead) {
 562        return 0;
 563    }
 564
 565    EnterCriticalSection (&wave->crit_sect);
 566    {
 567        decr = audio_MIN (dead, wave->avail);
 568        wave->avail -= decr;
 569    }
 570    LeaveCriticalSection (&wave->crit_sect);
 571
 572    ret = decr;
 573    while (decr) {
 574        int left = hw->samples - hw->wpos;
 575        int conv = audio_MIN (left, decr);
 576        hw->conv (hw->conv_buf + hw->wpos,
 577                  advance (wave->pcm_buf, wave->rpos << hw->info.shift),
 578                  conv);
 579
 580        wave->rpos = (wave->rpos + conv) % hw->samples;
 581        hw->wpos = (hw->wpos + conv) % hw->samples;
 582        decr -= conv;
 583    }
 584
 585    winwave_add_buffers (wave, ret);
 586    return ret;
 587}
 588
 589static int winwave_read (SWVoiceIn *sw, void *buf, int size)
 590{
 591    return audio_pcm_sw_read (sw, buf, size);
 592}
 593
 594static int winwave_ctl_in (HWVoiceIn *hw, int cmd, ...)
 595{
 596    MMRESULT mr;
 597    WaveVoiceIn *wave = (WaveVoiceIn *) hw;
 598
 599    switch (cmd) {
 600    case VOICE_ENABLE:
 601        {
 602            va_list ap;
 603            int poll_mode;
 604
 605            va_start (ap, cmd);
 606            poll_mode = va_arg (ap, int);
 607            va_end (ap);
 608
 609            if (poll_mode && !wave->event) {
 610                wave->event = CreateEvent (NULL, TRUE, TRUE, NULL);
 611                if (!wave->event) {
 612                    dolog ("ADC CreateEvent: %lx, poll mode will be disabled\n",
 613                           GetLastError ());
 614                }
 615            }
 616
 617            if (wave->event) {
 618                int ret;
 619
 620                ret = qemu_add_wait_object (wave->event, winwave_poll, wave);
 621                hw->poll_mode = (ret == 0);
 622            }
 623            else {
 624                hw->poll_mode = 0;
 625            }
 626            if (wave->paused) {
 627                mr = waveInStart (wave->hwi);
 628                if (mr != MMSYSERR_NOERROR) {
 629                    winwave_logerr (mr, "waveInStart");
 630                }
 631                wave->paused = 0;
 632            }
 633        }
 634        return 0;
 635
 636    case VOICE_DISABLE:
 637        if (!wave->paused) {
 638            mr = waveInStop (wave->hwi);
 639            if (mr != MMSYSERR_NOERROR) {
 640                winwave_logerr (mr, "waveInStop");
 641            }
 642            else {
 643                wave->paused = 1;
 644            }
 645        }
 646        if (wave->event) {
 647            qemu_del_wait_object (wave->event, winwave_poll, wave);
 648        }
 649        return 0;
 650    }
 651    return 0;
 652}
 653
 654static void *winwave_audio_init (void)
 655{
 656    return &conf;
 657}
 658
 659static void winwave_audio_fini (void *opaque)
 660{
 661    (void) opaque;
 662}
 663
 664static struct audio_option winwave_options[] = {
 665    {
 666        .name        = "DAC_HEADERS",
 667        .tag         = AUD_OPT_INT,
 668        .valp        = &conf.dac_headers,
 669        .descr       = "DAC number of headers",
 670    },
 671    {
 672        .name        = "DAC_SAMPLES",
 673        .tag         = AUD_OPT_INT,
 674        .valp        = &conf.dac_samples,
 675        .descr       = "DAC number of samples per header",
 676    },
 677    {
 678        .name        = "ADC_HEADERS",
 679        .tag         = AUD_OPT_INT,
 680        .valp        = &conf.adc_headers,
 681        .descr       = "ADC number of headers",
 682    },
 683    {
 684        .name        = "ADC_SAMPLES",
 685        .tag         = AUD_OPT_INT,
 686        .valp        = &conf.adc_samples,
 687        .descr       = "ADC number of samples per header",
 688    },
 689    { /* End of list */ }
 690};
 691
 692static struct audio_pcm_ops winwave_pcm_ops = {
 693    .init_out = winwave_init_out,
 694    .fini_out = winwave_fini_out,
 695    .run_out  = winwave_run_out,
 696    .write    = winwave_write,
 697    .ctl_out  = winwave_ctl_out,
 698    .init_in  = winwave_init_in,
 699    .fini_in  = winwave_fini_in,
 700    .run_in   = winwave_run_in,
 701    .read     = winwave_read,
 702    .ctl_in   = winwave_ctl_in
 703};
 704
 705struct audio_driver winwave_audio_driver = {
 706    .name           = "winwave",
 707    .descr          = "Windows Waveform Audio http://msdn.microsoft.com",
 708    .options        = winwave_options,
 709    .init           = winwave_audio_init,
 710    .fini           = winwave_audio_fini,
 711    .pcm_ops        = &winwave_pcm_ops,
 712    .can_be_default = 1,
 713    .max_voices_out = INT_MAX,
 714    .max_voices_in  = INT_MAX,
 715    .voice_size_out = sizeof (WaveVoiceOut),
 716    .voice_size_in  = sizeof (WaveVoiceIn)
 717};
 718