1*1d14ffa9Sbellard /* 2*1d14ffa9Sbellard * QEMU DirectSound audio driver header 3*1d14ffa9Sbellard * 4*1d14ffa9Sbellard * Copyright (c) 2005 Vassili Karpov (malc) 5*1d14ffa9Sbellard * 6*1d14ffa9Sbellard * Permission is hereby granted, free of charge, to any person obtaining a copy 7*1d14ffa9Sbellard * of this software and associated documentation files (the "Software"), to deal 8*1d14ffa9Sbellard * in the Software without restriction, including without limitation the rights 9*1d14ffa9Sbellard * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10*1d14ffa9Sbellard * copies of the Software, and to permit persons to whom the Software is 11*1d14ffa9Sbellard * furnished to do so, subject to the following conditions: 12*1d14ffa9Sbellard * 13*1d14ffa9Sbellard * The above copyright notice and this permission notice shall be included in 14*1d14ffa9Sbellard * all copies or substantial portions of the Software. 15*1d14ffa9Sbellard * 16*1d14ffa9Sbellard * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17*1d14ffa9Sbellard * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18*1d14ffa9Sbellard * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19*1d14ffa9Sbellard * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20*1d14ffa9Sbellard * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21*1d14ffa9Sbellard * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22*1d14ffa9Sbellard * THE SOFTWARE. 23*1d14ffa9Sbellard */ 24*1d14ffa9Sbellard #ifdef DSBTYPE_IN 25*1d14ffa9Sbellard #define NAME "capture buffer" 26*1d14ffa9Sbellard #define TYPE in 27*1d14ffa9Sbellard #define IFACE IDirectSoundCaptureBuffer 28*1d14ffa9Sbellard #define BUFPTR LPDIRECTSOUNDCAPTUREBUFFER 29*1d14ffa9Sbellard #define FIELD dsound_capture_buffer 30*1d14ffa9Sbellard #else 31*1d14ffa9Sbellard #define NAME "playback buffer" 32*1d14ffa9Sbellard #define TYPE out 33*1d14ffa9Sbellard #define IFACE IDirectSoundBuffer 34*1d14ffa9Sbellard #define BUFPTR LPDIRECTSOUNDBUFFER 35*1d14ffa9Sbellard #define FIELD dsound_buffer 36*1d14ffa9Sbellard #endif 37*1d14ffa9Sbellard 38*1d14ffa9Sbellard static int glue (dsound_unlock_, TYPE) ( 39*1d14ffa9Sbellard BUFPTR buf, 40*1d14ffa9Sbellard LPVOID p1, 41*1d14ffa9Sbellard LPVOID p2, 42*1d14ffa9Sbellard DWORD blen1, 43*1d14ffa9Sbellard DWORD blen2 44*1d14ffa9Sbellard ) 45*1d14ffa9Sbellard { 46*1d14ffa9Sbellard HRESULT hr; 47*1d14ffa9Sbellard 48*1d14ffa9Sbellard hr = glue (IFACE, _Unlock) (buf, p1, blen1, p2, blen2); 49*1d14ffa9Sbellard if (FAILED (hr)) { 50*1d14ffa9Sbellard dsound_logerr (hr, "Can not unlock " NAME "\n"); 51*1d14ffa9Sbellard return -1; 52*1d14ffa9Sbellard } 53*1d14ffa9Sbellard 54*1d14ffa9Sbellard return 0; 55*1d14ffa9Sbellard } 56*1d14ffa9Sbellard 57*1d14ffa9Sbellard static int glue (dsound_lock_, TYPE) ( 58*1d14ffa9Sbellard BUFPTR buf, 59*1d14ffa9Sbellard struct audio_pcm_info *info, 60*1d14ffa9Sbellard DWORD pos, 61*1d14ffa9Sbellard DWORD len, 62*1d14ffa9Sbellard LPVOID *p1p, 63*1d14ffa9Sbellard LPVOID *p2p, 64*1d14ffa9Sbellard DWORD *blen1p, 65*1d14ffa9Sbellard DWORD *blen2p, 66*1d14ffa9Sbellard int entire 67*1d14ffa9Sbellard ) 68*1d14ffa9Sbellard { 69*1d14ffa9Sbellard HRESULT hr; 70*1d14ffa9Sbellard int i; 71*1d14ffa9Sbellard LPVOID p1 = NULL, p2 = NULL; 72*1d14ffa9Sbellard DWORD blen1 = 0, blen2 = 0; 73*1d14ffa9Sbellard 74*1d14ffa9Sbellard for (i = 0; i < conf.lock_retries; ++i) { 75*1d14ffa9Sbellard hr = glue (IFACE, _Lock) ( 76*1d14ffa9Sbellard buf, 77*1d14ffa9Sbellard pos, 78*1d14ffa9Sbellard len, 79*1d14ffa9Sbellard &p1, 80*1d14ffa9Sbellard &blen1, 81*1d14ffa9Sbellard &p2, 82*1d14ffa9Sbellard &blen2, 83*1d14ffa9Sbellard (entire 84*1d14ffa9Sbellard #ifdef DSBTYPE_IN 85*1d14ffa9Sbellard ? DSCBLOCK_ENTIREBUFFER 86*1d14ffa9Sbellard #else 87*1d14ffa9Sbellard ? DSBLOCK_ENTIREBUFFER 88*1d14ffa9Sbellard #endif 89*1d14ffa9Sbellard : 0) 90*1d14ffa9Sbellard ); 91*1d14ffa9Sbellard 92*1d14ffa9Sbellard if (FAILED (hr)) { 93*1d14ffa9Sbellard #ifndef DSBTYPE_IN 94*1d14ffa9Sbellard if (hr == DSERR_BUFFERLOST) { 95*1d14ffa9Sbellard if (glue (dsound_restore_, TYPE) (buf)) { 96*1d14ffa9Sbellard dsound_logerr (hr, "Can not lock " NAME "\n"); 97*1d14ffa9Sbellard goto fail; 98*1d14ffa9Sbellard } 99*1d14ffa9Sbellard continue; 100*1d14ffa9Sbellard } 101*1d14ffa9Sbellard #endif 102*1d14ffa9Sbellard dsound_logerr (hr, "Can not lock " NAME "\n"); 103*1d14ffa9Sbellard goto fail; 104*1d14ffa9Sbellard } 105*1d14ffa9Sbellard 106*1d14ffa9Sbellard break; 107*1d14ffa9Sbellard } 108*1d14ffa9Sbellard 109*1d14ffa9Sbellard if (i == conf.lock_retries) { 110*1d14ffa9Sbellard dolog ("%d attempts to lock " NAME " failed\n", i); 111*1d14ffa9Sbellard goto fail; 112*1d14ffa9Sbellard } 113*1d14ffa9Sbellard 114*1d14ffa9Sbellard if ((p1 && (blen1 & info->align)) || (p2 && (blen2 & info->align))) { 115*1d14ffa9Sbellard dolog ("DirectSound returned misaligned buffer %ld %ld\n", 116*1d14ffa9Sbellard blen1, blen2); 117*1d14ffa9Sbellard glue (dsound_unlock_, TYPE) (buf, p1, p2, blen1, blen2); 118*1d14ffa9Sbellard goto fail; 119*1d14ffa9Sbellard } 120*1d14ffa9Sbellard 121*1d14ffa9Sbellard if (!p1 && blen1) { 122*1d14ffa9Sbellard dolog ("warning: !p1 && blen1=%ld\n", blen1); 123*1d14ffa9Sbellard blen1 = 0; 124*1d14ffa9Sbellard } 125*1d14ffa9Sbellard 126*1d14ffa9Sbellard if (!p2 && blen2) { 127*1d14ffa9Sbellard dolog ("warning: !p2 && blen2=%ld\n", blen2); 128*1d14ffa9Sbellard blen2 = 0; 129*1d14ffa9Sbellard } 130*1d14ffa9Sbellard 131*1d14ffa9Sbellard *p1p = p1; 132*1d14ffa9Sbellard *p2p = p2; 133*1d14ffa9Sbellard *blen1p = blen1; 134*1d14ffa9Sbellard *blen2p = blen2; 135*1d14ffa9Sbellard return 0; 136*1d14ffa9Sbellard 137*1d14ffa9Sbellard fail: 138*1d14ffa9Sbellard *p1p = NULL - 1; 139*1d14ffa9Sbellard *p2p = NULL - 1; 140*1d14ffa9Sbellard *blen1p = -1; 141*1d14ffa9Sbellard *blen2p = -1; 142*1d14ffa9Sbellard return -1; 143*1d14ffa9Sbellard } 144*1d14ffa9Sbellard 145*1d14ffa9Sbellard #ifdef DSBTYPE_IN 146*1d14ffa9Sbellard static void dsound_fini_in (HWVoiceIn *hw) 147*1d14ffa9Sbellard #else 148*1d14ffa9Sbellard static void dsound_fini_out (HWVoiceOut *hw) 149*1d14ffa9Sbellard #endif 150*1d14ffa9Sbellard { 151*1d14ffa9Sbellard HRESULT hr; 152*1d14ffa9Sbellard #ifdef DSBTYPE_IN 153*1d14ffa9Sbellard DSoundVoiceIn *ds = (DSoundVoiceIn *) hw; 154*1d14ffa9Sbellard #else 155*1d14ffa9Sbellard DSoundVoiceOut *ds = (DSoundVoiceOut *) hw; 156*1d14ffa9Sbellard #endif 157*1d14ffa9Sbellard 158*1d14ffa9Sbellard if (ds->FIELD) { 159*1d14ffa9Sbellard hr = glue (IFACE, _Stop) (ds->FIELD); 160*1d14ffa9Sbellard if (FAILED (hr)) { 161*1d14ffa9Sbellard dsound_logerr (hr, "Can not stop " NAME "\n"); 162*1d14ffa9Sbellard } 163*1d14ffa9Sbellard 164*1d14ffa9Sbellard hr = glue (IFACE, _Release) (ds->FIELD); 165*1d14ffa9Sbellard if (FAILED (hr)) { 166*1d14ffa9Sbellard dsound_logerr (hr, "Can not release " NAME "\n"); 167*1d14ffa9Sbellard } 168*1d14ffa9Sbellard ds->FIELD = NULL; 169*1d14ffa9Sbellard } 170*1d14ffa9Sbellard } 171*1d14ffa9Sbellard 172*1d14ffa9Sbellard #ifdef DSBTYPE_IN 173*1d14ffa9Sbellard static int dsound_init_in ( 174*1d14ffa9Sbellard HWVoiceIn *hw, 175*1d14ffa9Sbellard int freq, 176*1d14ffa9Sbellard int nchannels, 177*1d14ffa9Sbellard audfmt_e fmt 178*1d14ffa9Sbellard ) 179*1d14ffa9Sbellard #else 180*1d14ffa9Sbellard static int dsound_init_out ( 181*1d14ffa9Sbellard HWVoiceOut *hw, 182*1d14ffa9Sbellard int freq, 183*1d14ffa9Sbellard int nchannels, 184*1d14ffa9Sbellard audfmt_e fmt 185*1d14ffa9Sbellard ) 186*1d14ffa9Sbellard #endif 187*1d14ffa9Sbellard { 188*1d14ffa9Sbellard int err; 189*1d14ffa9Sbellard HRESULT hr; 190*1d14ffa9Sbellard dsound *s = &glob_dsound; 191*1d14ffa9Sbellard WAVEFORMATEX wfx; 192*1d14ffa9Sbellard struct full_fmt full_fmt; 193*1d14ffa9Sbellard #ifdef DSBTYPE_IN 194*1d14ffa9Sbellard const char *typ = "ADC"; 195*1d14ffa9Sbellard DSoundVoiceIn *ds = (DSoundVoiceIn *) hw; 196*1d14ffa9Sbellard DSCBUFFERDESC bd; 197*1d14ffa9Sbellard DSCBCAPS bc; 198*1d14ffa9Sbellard #else 199*1d14ffa9Sbellard const char *typ = "DAC"; 200*1d14ffa9Sbellard DSoundVoiceOut *ds = (DSoundVoiceOut *) hw; 201*1d14ffa9Sbellard DSBUFFERDESC bd; 202*1d14ffa9Sbellard DSBCAPS bc; 203*1d14ffa9Sbellard #endif 204*1d14ffa9Sbellard 205*1d14ffa9Sbellard full_fmt.freq = freq; 206*1d14ffa9Sbellard full_fmt.nchannels = nchannels; 207*1d14ffa9Sbellard full_fmt.fmt = fmt; 208*1d14ffa9Sbellard err = waveformat_from_full_fmt (&wfx, &full_fmt); 209*1d14ffa9Sbellard if (err) { 210*1d14ffa9Sbellard return -1; 211*1d14ffa9Sbellard } 212*1d14ffa9Sbellard 213*1d14ffa9Sbellard memset (&bd, 0, sizeof (bd)); 214*1d14ffa9Sbellard bd.dwSize = sizeof (bd); 215*1d14ffa9Sbellard bd.lpwfxFormat = &wfx; 216*1d14ffa9Sbellard #ifdef DSBTYPE_IN 217*1d14ffa9Sbellard bd.dwBufferBytes = conf.bufsize_in; 218*1d14ffa9Sbellard hr = IDirectSoundCapture_CreateCaptureBuffer ( 219*1d14ffa9Sbellard s->dsound_capture, 220*1d14ffa9Sbellard &bd, 221*1d14ffa9Sbellard &ds->dsound_capture_buffer, 222*1d14ffa9Sbellard NULL 223*1d14ffa9Sbellard ); 224*1d14ffa9Sbellard #else 225*1d14ffa9Sbellard bd.dwFlags = DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2; 226*1d14ffa9Sbellard bd.dwBufferBytes = conf.bufsize_out; 227*1d14ffa9Sbellard hr = IDirectSound_CreateSoundBuffer ( 228*1d14ffa9Sbellard s->dsound, 229*1d14ffa9Sbellard &bd, 230*1d14ffa9Sbellard &ds->dsound_buffer, 231*1d14ffa9Sbellard NULL 232*1d14ffa9Sbellard ); 233*1d14ffa9Sbellard #endif 234*1d14ffa9Sbellard 235*1d14ffa9Sbellard if (FAILED (hr)) { 236*1d14ffa9Sbellard dsound_logerr2 (hr, typ, "Can not create " NAME "\n"); 237*1d14ffa9Sbellard return -1; 238*1d14ffa9Sbellard } 239*1d14ffa9Sbellard 240*1d14ffa9Sbellard hr = glue (IFACE, _GetFormat) ( 241*1d14ffa9Sbellard ds->FIELD, 242*1d14ffa9Sbellard &wfx, 243*1d14ffa9Sbellard sizeof (wfx), 244*1d14ffa9Sbellard NULL 245*1d14ffa9Sbellard ); 246*1d14ffa9Sbellard if (FAILED (hr)) { 247*1d14ffa9Sbellard dsound_logerr2 (hr, typ, "Can not get " NAME " format\n"); 248*1d14ffa9Sbellard goto fail0; 249*1d14ffa9Sbellard } 250*1d14ffa9Sbellard 251*1d14ffa9Sbellard #ifdef DEBUG_DSOUND 252*1d14ffa9Sbellard dolog (NAME "\n"); 253*1d14ffa9Sbellard print_wave_format (&wfx); 254*1d14ffa9Sbellard #endif 255*1d14ffa9Sbellard 256*1d14ffa9Sbellard memset (&bc, 0, sizeof (bc)); 257*1d14ffa9Sbellard bc.dwSize = sizeof (bc); 258*1d14ffa9Sbellard 259*1d14ffa9Sbellard hr = glue (IFACE, _GetCaps) (ds->FIELD, &bc); 260*1d14ffa9Sbellard if (FAILED (hr)) { 261*1d14ffa9Sbellard dsound_logerr2 (hr, typ, "Can not get " NAME " format\n"); 262*1d14ffa9Sbellard goto fail0; 263*1d14ffa9Sbellard } 264*1d14ffa9Sbellard 265*1d14ffa9Sbellard err = waveformat_to_full_fmt (&wfx, &full_fmt); 266*1d14ffa9Sbellard if (err) { 267*1d14ffa9Sbellard goto fail0; 268*1d14ffa9Sbellard } 269*1d14ffa9Sbellard 270*1d14ffa9Sbellard ds->first_time = 1; 271*1d14ffa9Sbellard hw->bufsize = bc.dwBufferBytes; 272*1d14ffa9Sbellard audio_pcm_init_info ( 273*1d14ffa9Sbellard &hw->info, 274*1d14ffa9Sbellard full_fmt.freq, 275*1d14ffa9Sbellard full_fmt.nchannels, 276*1d14ffa9Sbellard full_fmt.fmt, 277*1d14ffa9Sbellard audio_need_to_swap_endian (0) 278*1d14ffa9Sbellard ); 279*1d14ffa9Sbellard 280*1d14ffa9Sbellard #ifdef DEBUG_DSOUND 281*1d14ffa9Sbellard dolog ("caps %ld, desc %ld\n", 282*1d14ffa9Sbellard bc.dwBufferBytes, bd.dwBufferBytes); 283*1d14ffa9Sbellard 284*1d14ffa9Sbellard dolog ("bufsize %d, freq %d, chan %d, fmt %d\n", 285*1d14ffa9Sbellard hw->bufsize, full_fmt.freq, full_fmt.nchannels, full_fmt.fmt); 286*1d14ffa9Sbellard #endif 287*1d14ffa9Sbellard return 0; 288*1d14ffa9Sbellard 289*1d14ffa9Sbellard fail0: 290*1d14ffa9Sbellard glue (dsound_fini_, TYPE) (hw); 291*1d14ffa9Sbellard return -1; 292*1d14ffa9Sbellard } 293*1d14ffa9Sbellard 294*1d14ffa9Sbellard #undef NAME 295*1d14ffa9Sbellard #undef TYPE 296*1d14ffa9Sbellard #undef IFACE 297*1d14ffa9Sbellard #undef BUFPTR 298*1d14ffa9Sbellard #undef FIELD 299