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 46 static 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 65 static 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 133 static void dsound_fini_in (HWVoiceIn *hw) 134 #else 135 static 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 160 static int dsound_init_in(HWVoiceIn *hw, struct audsettings *as, 161 void *drv_opaque) 162 #else 163 static 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