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    dsound *s
  72    )
  73{
  74    HRESULT hr;
  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    hr = glue(IFACE, _Lock)(buf, pos, len, &p1, &blen1, &p2, &blen2, flag);
  85
  86    if (FAILED (hr)) {
  87#ifndef DSBTYPE_IN
  88        if (hr == DSERR_BUFFERLOST) {
  89            if (glue (dsound_restore_, TYPE) (buf, s)) {
  90                dsound_logerr (hr, "Could not lock " NAME "\n");
  91            }
  92            goto fail;
  93        }
  94#endif
  95        dsound_logerr (hr, "Could not lock " NAME "\n");
  96        goto fail;
  97    }
  98
  99    if ((p1 && (blen1 & info->align)) || (p2 && (blen2 & info->align))) {
 100        dolog ("DirectSound returned misaligned buffer %ld %ld\n",
 101               blen1, blen2);
 102        glue (dsound_unlock_, TYPE) (buf, p1, p2, blen1, blen2);
 103        goto fail;
 104    }
 105
 106    if (!p1 && blen1) {
 107        dolog ("warning: !p1 && blen1=%ld\n", blen1);
 108        blen1 = 0;
 109    }
 110
 111    if (!p2 && blen2) {
 112        dolog ("warning: !p2 && blen2=%ld\n", blen2);
 113        blen2 = 0;
 114    }
 115
 116    *p1p = p1;
 117    *p2p = p2;
 118    *blen1p = blen1;
 119    *blen2p = blen2;
 120    return 0;
 121
 122 fail:
 123    *p1p = NULL - 1;
 124    *p2p = NULL - 1;
 125    *blen1p = -1;
 126    *blen2p = -1;
 127    return -1;
 128}
 129
 130#ifdef DSBTYPE_IN
 131static void dsound_fini_in (HWVoiceIn *hw)
 132#else
 133static void dsound_fini_out (HWVoiceOut *hw)
 134#endif
 135{
 136    HRESULT hr;
 137#ifdef DSBTYPE_IN
 138    DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
 139#else
 140    DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
 141#endif
 142
 143    if (ds->FIELD) {
 144        hr = glue (IFACE, _Stop) (ds->FIELD);
 145        if (FAILED (hr)) {
 146            dsound_logerr (hr, "Could not stop " NAME "\n");
 147        }
 148
 149        hr = glue (IFACE, _Release) (ds->FIELD);
 150        if (FAILED (hr)) {
 151            dsound_logerr (hr, "Could not release " NAME "\n");
 152        }
 153        ds->FIELD = NULL;
 154    }
 155}
 156
 157#ifdef DSBTYPE_IN
 158static int dsound_init_in(HWVoiceIn *hw, struct audsettings *as,
 159                          void *drv_opaque)
 160#else
 161static int dsound_init_out(HWVoiceOut *hw, struct audsettings *as,
 162                           void *drv_opaque)
 163#endif
 164{
 165    int err;
 166    HRESULT hr;
 167    dsound *s = drv_opaque;
 168    WAVEFORMATEX wfx;
 169    struct audsettings obt_as;
 170    DSoundConf *conf = &s->conf;
 171#ifdef DSBTYPE_IN
 172    const char *typ = "ADC";
 173    DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
 174    DSCBUFFERDESC bd;
 175    DSCBCAPS bc;
 176#else
 177    const char *typ = "DAC";
 178    DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
 179    DSBUFFERDESC bd;
 180    DSBCAPS bc;
 181#endif
 182
 183    if (!s->FIELD2) {
 184        dolog ("Attempt to initialize voice without " NAME2 " object\n");
 185        return -1;
 186    }
 187
 188    err = waveformat_from_audio_settings (&wfx, as);
 189    if (err) {
 190        return -1;
 191    }
 192
 193    memset (&bd, 0, sizeof (bd));
 194    bd.dwSize = sizeof (bd);
 195    bd.lpwfxFormat = &wfx;
 196#ifdef DSBTYPE_IN
 197    bd.dwBufferBytes = conf->bufsize_in;
 198    hr = IDirectSoundCapture_CreateCaptureBuffer (
 199        s->dsound_capture,
 200        &bd,
 201        &ds->dsound_capture_buffer,
 202        NULL
 203        );
 204#else
 205    bd.dwFlags = DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2;
 206    bd.dwBufferBytes = conf->bufsize_out;
 207    hr = IDirectSound_CreateSoundBuffer (
 208        s->dsound,
 209        &bd,
 210        &ds->dsound_buffer,
 211        NULL
 212        );
 213#endif
 214
 215    if (FAILED (hr)) {
 216        dsound_logerr2 (hr, typ, "Could not create " NAME "\n");
 217        return -1;
 218    }
 219
 220    hr = glue (IFACE, _GetFormat) (ds->FIELD, &wfx, sizeof (wfx), NULL);
 221    if (FAILED (hr)) {
 222        dsound_logerr2 (hr, typ, "Could not get " NAME " format\n");
 223        goto fail0;
 224    }
 225
 226#ifdef DEBUG_DSOUND
 227    dolog (NAME "\n");
 228    print_wave_format (&wfx);
 229#endif
 230
 231    memset (&bc, 0, sizeof (bc));
 232    bc.dwSize = sizeof (bc);
 233
 234    hr = glue (IFACE, _GetCaps) (ds->FIELD, &bc);
 235    if (FAILED (hr)) {
 236        dsound_logerr2 (hr, typ, "Could not get " NAME " format\n");
 237        goto fail0;
 238    }
 239
 240    err = waveformat_to_audio_settings (&wfx, &obt_as);
 241    if (err) {
 242        goto fail0;
 243    }
 244
 245    ds->first_time = 1;
 246    obt_as.endianness = 0;
 247    audio_pcm_init_info (&hw->info, &obt_as);
 248
 249    if (bc.dwBufferBytes & hw->info.align) {
 250        dolog (
 251            "GetCaps returned misaligned buffer size %ld, alignment %d\n",
 252            bc.dwBufferBytes, hw->info.align + 1
 253            );
 254    }
 255    hw->samples = bc.dwBufferBytes >> hw->info.shift;
 256    ds->s = s;
 257
 258#ifdef DEBUG_DSOUND
 259    dolog ("caps %ld, desc %ld\n",
 260           bc.dwBufferBytes, bd.dwBufferBytes);
 261
 262    dolog ("bufsize %d, freq %d, chan %d, fmt %d\n",
 263           hw->bufsize, settings.freq, settings.nchannels, settings.fmt);
 264#endif
 265    return 0;
 266
 267 fail0:
 268    glue (dsound_fini_, TYPE) (hw);
 269    return -1;
 270}
 271
 272#undef NAME
 273#undef NAME2
 274#undef TYPE
 275#undef IFACE
 276#undef BUFPTR
 277#undef FIELD
 278#undef FIELD2
 279