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