qemu/audio/dsound_template.h
<<
>>
Prefs
   1/*
   2 * QEMU DirectSound audio driver 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#ifdef DSBTYPE_IN
  25#define NAME "capture buffer"
  26#define NAME2 "DirectSoundCapture"
  27#define TYPE in
  28#define IFACE IDirectSoundCaptureBuffer
  29#define BUFPTR LPDIRECTSOUNDCAPTUREBUFFER
  30#define FIELD dsound_capture_buffer
  31#define FIELD2 dsound_capture
  32#else
  33#define NAME "playback buffer"
  34#define NAME2 "DirectSound"
  35#define TYPE out
  36#define IFACE IDirectSoundBuffer
  37#define BUFPTR LPDIRECTSOUNDBUFFER
  38#define FIELD dsound_buffer
  39#define FIELD2 dsound
  40#endif
  41
  42static int glue (dsound_unlock_, TYPE) (
  43    BUFPTR buf,
  44    LPVOID p1,
  45    LPVOID p2,
  46    DWORD blen1,
  47    DWORD blen2
  48    )
  49{
  50    HRESULT hr;
  51
  52    hr = glue (IFACE, _Unlock) (buf, p1, blen1, p2, blen2);
  53    if (FAILED (hr)) {
  54        dsound_logerr (hr, "Could not unlock " NAME "\n");
  55        return -1;
  56    }
  57
  58    return 0;
  59}
  60
  61static int glue (dsound_lock_, TYPE) (
  62    BUFPTR buf,
  63    struct audio_pcm_info *info,
  64    DWORD pos,
  65    DWORD len,
  66    LPVOID *p1p,
  67    LPVOID *p2p,
  68    DWORD *blen1p,
  69    DWORD *blen2p,
  70    int entire
  71    )
  72{
  73    HRESULT hr;
  74    int i;
  75    LPVOID p1 = NULL, p2 = NULL;
  76    DWORD blen1 = 0, blen2 = 0;
  77    DWORD flag;
  78
  79#ifdef DSBTYPE_IN
  80    flag = entire ? DSCBLOCK_ENTIREBUFFER : 0;
  81#else
  82    flag = entire ? DSBLOCK_ENTIREBUFFER : 0;
  83#endif
  84    for (i = 0; i < conf.lock_retries; ++i) {
  85        hr = glue (IFACE, _Lock) (
  86            buf,
  87            pos,
  88            len,
  89            &p1,
  90            &blen1,
  91            &p2,
  92            &blen2,
  93            flag
  94            );
  95
  96        if (FAILED (hr)) {
  97#ifndef DSBTYPE_IN
  98            if (hr == DSERR_BUFFERLOST) {
  99                if (glue (dsound_restore_, TYPE) (buf)) {
 100                    dsound_logerr (hr, "Could not lock " NAME "\n");
 101                    goto fail;
 102                }
 103                continue;
 104            }
 105#endif
 106            dsound_logerr (hr, "Could not lock " NAME "\n");
 107            goto fail;
 108        }
 109
 110        break;
 111    }
 112
 113    if (i == conf.lock_retries) {
 114        dolog ("%d attempts to lock " NAME " failed\n", i);
 115        goto fail;
 116    }
 117
 118    if ((p1 && (blen1 & info->align)) || (p2 && (blen2 & info->align))) {
 119        dolog ("DirectSound returned misaligned buffer %ld %ld\n",
 120               blen1, blen2);
 121        glue (dsound_unlock_, TYPE) (buf, p1, p2, blen1, blen2);
 122        goto fail;
 123    }
 124
 125    if (!p1 && blen1) {
 126        dolog ("warning: !p1 && blen1=%ld\n", blen1);
 127        blen1 = 0;
 128    }
 129
 130    if (!p2 && blen2) {
 131        dolog ("warning: !p2 && blen2=%ld\n", blen2);
 132        blen2 = 0;
 133    }
 134
 135    *p1p = p1;
 136    *p2p = p2;
 137    *blen1p = blen1;
 138    *blen2p = blen2;
 139    return 0;
 140
 141 fail:
 142    *p1p = NULL - 1;
 143    *p2p = NULL - 1;
 144    *blen1p = -1;
 145    *blen2p = -1;
 146    return -1;
 147}
 148
 149#ifdef DSBTYPE_IN
 150static void dsound_fini_in (HWVoiceIn *hw)
 151#else
 152static void dsound_fini_out (HWVoiceOut *hw)
 153#endif
 154{
 155    HRESULT hr;
 156#ifdef DSBTYPE_IN
 157    DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
 158#else
 159    DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
 160#endif
 161
 162    if (ds->FIELD) {
 163        hr = glue (IFACE, _Stop) (ds->FIELD);
 164        if (FAILED (hr)) {
 165            dsound_logerr (hr, "Could not stop " NAME "\n");
 166        }
 167
 168        hr = glue (IFACE, _Release) (ds->FIELD);
 169        if (FAILED (hr)) {
 170            dsound_logerr (hr, "Could not release " NAME "\n");
 171        }
 172        ds->FIELD = NULL;
 173    }
 174}
 175
 176#ifdef DSBTYPE_IN
 177static int dsound_init_in (HWVoiceIn *hw, struct audsettings *as)
 178#else
 179static int dsound_init_out (HWVoiceOut *hw, struct audsettings *as)
 180#endif
 181{
 182    int err;
 183    HRESULT hr;
 184    dsound *s = &glob_dsound;
 185    WAVEFORMATEX wfx;
 186    struct audsettings obt_as;
 187#ifdef DSBTYPE_IN
 188    const char *typ = "ADC";
 189    DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
 190    DSCBUFFERDESC bd;
 191    DSCBCAPS bc;
 192#else
 193    const char *typ = "DAC";
 194    DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
 195    DSBUFFERDESC bd;
 196    DSBCAPS bc;
 197#endif
 198
 199    if (!s->FIELD2) {
 200        dolog ("Attempt to initialize voice without " NAME2 " object\n");
 201        return -1;
 202    }
 203
 204    err = waveformat_from_audio_settings (&wfx, as);
 205    if (err) {
 206        return -1;
 207    }
 208
 209    memset (&bd, 0, sizeof (bd));
 210    bd.dwSize = sizeof (bd);
 211    bd.lpwfxFormat = &wfx;
 212#ifdef DSBTYPE_IN
 213    bd.dwBufferBytes = conf.bufsize_in;
 214    hr = IDirectSoundCapture_CreateCaptureBuffer (
 215        s->dsound_capture,
 216        &bd,
 217        &ds->dsound_capture_buffer,
 218        NULL
 219        );
 220#else
 221    bd.dwFlags = DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2;
 222    bd.dwBufferBytes = conf.bufsize_out;
 223    hr = IDirectSound_CreateSoundBuffer (
 224        s->dsound,
 225        &bd,
 226        &ds->dsound_buffer,
 227        NULL
 228        );
 229#endif
 230
 231    if (FAILED (hr)) {
 232        dsound_logerr2 (hr, typ, "Could not create " NAME "\n");
 233        return -1;
 234    }
 235
 236    hr = glue (IFACE, _GetFormat) (ds->FIELD, &wfx, sizeof (wfx), NULL);
 237    if (FAILED (hr)) {
 238        dsound_logerr2 (hr, typ, "Could not get " NAME " format\n");
 239        goto fail0;
 240    }
 241
 242#ifdef DEBUG_DSOUND
 243    dolog (NAME "\n");
 244    print_wave_format (&wfx);
 245#endif
 246
 247    memset (&bc, 0, sizeof (bc));
 248    bc.dwSize = sizeof (bc);
 249
 250    hr = glue (IFACE, _GetCaps) (ds->FIELD, &bc);
 251    if (FAILED (hr)) {
 252        dsound_logerr2 (hr, typ, "Could not get " NAME " format\n");
 253        goto fail0;
 254    }
 255
 256    err = waveformat_to_audio_settings (&wfx, &obt_as);
 257    if (err) {
 258        goto fail0;
 259    }
 260
 261    ds->first_time = 1;
 262    obt_as.endianness = 0;
 263    audio_pcm_init_info (&hw->info, &obt_as);
 264
 265    if (bc.dwBufferBytes & hw->info.align) {
 266        dolog (
 267            "GetCaps returned misaligned buffer size %ld, alignment %d\n",
 268            bc.dwBufferBytes, hw->info.align + 1
 269            );
 270    }
 271    hw->samples = bc.dwBufferBytes >> hw->info.shift;
 272
 273#ifdef DEBUG_DSOUND
 274    dolog ("caps %ld, desc %ld\n",
 275           bc.dwBufferBytes, bd.dwBufferBytes);
 276
 277    dolog ("bufsize %d, freq %d, chan %d, fmt %d\n",
 278           hw->bufsize, settings.freq, settings.nchannels, settings.fmt);
 279#endif
 280    return 0;
 281
 282 fail0:
 283    glue (dsound_fini_, TYPE) (hw);
 284    return -1;
 285}
 286
 287#undef NAME
 288#undef NAME2
 289#undef TYPE
 290#undef IFACE
 291#undef BUFPTR
 292#undef FIELD
 293#undef FIELD2
 294