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 42 static 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 61 static 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 150 static void dsound_fini_in (HWVoiceIn *hw) 151 #else 152 static 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 177 static int dsound_init_in (HWVoiceIn *hw, struct audsettings *as) 178 #else 179 static 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