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 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 131 static void dsound_fini_in (HWVoiceIn *hw) 132 #else 133 static 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 158 static int dsound_init_in(HWVoiceIn *hw, struct audsettings *as, 159 void *drv_opaque) 160 #else 161 static 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