11d14ffa9Sbellard /* 21d14ffa9Sbellard * QEMU DirectSound audio driver header 31d14ffa9Sbellard * 41d14ffa9Sbellard * Copyright (c) 2005 Vassili Karpov (malc) 51d14ffa9Sbellard * 61d14ffa9Sbellard * Permission is hereby granted, free of charge, to any person obtaining a copy 71d14ffa9Sbellard * of this software and associated documentation files (the "Software"), to deal 81d14ffa9Sbellard * in the Software without restriction, including without limitation the rights 91d14ffa9Sbellard * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 101d14ffa9Sbellard * copies of the Software, and to permit persons to whom the Software is 111d14ffa9Sbellard * furnished to do so, subject to the following conditions: 121d14ffa9Sbellard * 131d14ffa9Sbellard * The above copyright notice and this permission notice shall be included in 141d14ffa9Sbellard * all copies or substantial portions of the Software. 151d14ffa9Sbellard * 161d14ffa9Sbellard * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 171d14ffa9Sbellard * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 181d14ffa9Sbellard * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 191d14ffa9Sbellard * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 201d14ffa9Sbellard * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 211d14ffa9Sbellard * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 221d14ffa9Sbellard * THE SOFTWARE. 231d14ffa9Sbellard */ 241d14ffa9Sbellard #ifdef DSBTYPE_IN 251d14ffa9Sbellard #define NAME "capture buffer" 26ca9cc28cSbalrog #define NAME2 "DirectSoundCapture" 271d14ffa9Sbellard #define TYPE in 281d14ffa9Sbellard #define IFACE IDirectSoundCaptureBuffer 291d14ffa9Sbellard #define BUFPTR LPDIRECTSOUNDCAPTUREBUFFER 301d14ffa9Sbellard #define FIELD dsound_capture_buffer 31ca9cc28cSbalrog #define FIELD2 dsound_capture 321d14ffa9Sbellard #else 331d14ffa9Sbellard #define NAME "playback buffer" 34ca9cc28cSbalrog #define NAME2 "DirectSound" 351d14ffa9Sbellard #define TYPE out 361d14ffa9Sbellard #define IFACE IDirectSoundBuffer 371d14ffa9Sbellard #define BUFPTR LPDIRECTSOUNDBUFFER 381d14ffa9Sbellard #define FIELD dsound_buffer 39ca9cc28cSbalrog #define FIELD2 dsound 401d14ffa9Sbellard #endif 411d14ffa9Sbellard 421d14ffa9Sbellard static int glue (dsound_unlock_, TYPE) ( 431d14ffa9Sbellard BUFPTR buf, 441d14ffa9Sbellard LPVOID p1, 451d14ffa9Sbellard LPVOID p2, 461d14ffa9Sbellard DWORD blen1, 471d14ffa9Sbellard DWORD blen2 481d14ffa9Sbellard ) 491d14ffa9Sbellard { 501d14ffa9Sbellard HRESULT hr; 511d14ffa9Sbellard 521d14ffa9Sbellard hr = glue (IFACE, _Unlock) (buf, p1, blen1, p2, blen2); 531d14ffa9Sbellard if (FAILED (hr)) { 54c0fe3827Sbellard dsound_logerr (hr, "Could not unlock " NAME "\n"); 551d14ffa9Sbellard return -1; 561d14ffa9Sbellard } 571d14ffa9Sbellard 581d14ffa9Sbellard return 0; 591d14ffa9Sbellard } 601d14ffa9Sbellard 611d14ffa9Sbellard static int glue (dsound_lock_, TYPE) ( 621d14ffa9Sbellard BUFPTR buf, 631d14ffa9Sbellard struct audio_pcm_info *info, 641d14ffa9Sbellard DWORD pos, 651d14ffa9Sbellard DWORD len, 661d14ffa9Sbellard LPVOID *p1p, 671d14ffa9Sbellard LPVOID *p2p, 681d14ffa9Sbellard DWORD *blen1p, 691d14ffa9Sbellard DWORD *blen2p, 70191e1f0aSKővágó, Zoltán int entire, 71191e1f0aSKővágó, Zoltán dsound *s 721d14ffa9Sbellard ) 731d14ffa9Sbellard { 741d14ffa9Sbellard HRESULT hr; 751d14ffa9Sbellard LPVOID p1 = NULL, p2 = NULL; 761d14ffa9Sbellard DWORD blen1 = 0, blen2 = 0; 778ead62cfSbellard DWORD flag; 781d14ffa9Sbellard 798ead62cfSbellard #ifdef DSBTYPE_IN 808ead62cfSbellard flag = entire ? DSCBLOCK_ENTIREBUFFER : 0; 818ead62cfSbellard #else 828ead62cfSbellard flag = entire ? DSBLOCK_ENTIREBUFFER : 0; 838ead62cfSbellard #endif 84*2762955fSKővágó, Zoltán hr = glue(IFACE, _Lock)(buf, pos, len, &p1, &blen1, &p2, &blen2, flag); 851d14ffa9Sbellard 861d14ffa9Sbellard if (FAILED (hr)) { 871d14ffa9Sbellard #ifndef DSBTYPE_IN 881d14ffa9Sbellard if (hr == DSERR_BUFFERLOST) { 89191e1f0aSKővágó, Zoltán if (glue (dsound_restore_, TYPE) (buf, s)) { 90c0fe3827Sbellard dsound_logerr (hr, "Could not lock " NAME "\n"); 911d14ffa9Sbellard } 92*2762955fSKővágó, Zoltán goto fail; 931d14ffa9Sbellard } 941d14ffa9Sbellard #endif 95c0fe3827Sbellard dsound_logerr (hr, "Could not lock " NAME "\n"); 961d14ffa9Sbellard goto fail; 971d14ffa9Sbellard } 981d14ffa9Sbellard 991d14ffa9Sbellard if ((p1 && (blen1 & info->align)) || (p2 && (blen2 & info->align))) { 1001d14ffa9Sbellard dolog ("DirectSound returned misaligned buffer %ld %ld\n", 1011d14ffa9Sbellard blen1, blen2); 1021d14ffa9Sbellard glue (dsound_unlock_, TYPE) (buf, p1, p2, blen1, blen2); 1031d14ffa9Sbellard goto fail; 1041d14ffa9Sbellard } 1051d14ffa9Sbellard 1061d14ffa9Sbellard if (!p1 && blen1) { 1071d14ffa9Sbellard dolog ("warning: !p1 && blen1=%ld\n", blen1); 1081d14ffa9Sbellard blen1 = 0; 1091d14ffa9Sbellard } 1101d14ffa9Sbellard 1111d14ffa9Sbellard if (!p2 && blen2) { 1121d14ffa9Sbellard dolog ("warning: !p2 && blen2=%ld\n", blen2); 1131d14ffa9Sbellard blen2 = 0; 1141d14ffa9Sbellard } 1151d14ffa9Sbellard 1161d14ffa9Sbellard *p1p = p1; 1171d14ffa9Sbellard *p2p = p2; 1181d14ffa9Sbellard *blen1p = blen1; 1191d14ffa9Sbellard *blen2p = blen2; 1201d14ffa9Sbellard return 0; 1211d14ffa9Sbellard 1221d14ffa9Sbellard fail: 1231d14ffa9Sbellard *p1p = NULL - 1; 1241d14ffa9Sbellard *p2p = NULL - 1; 1251d14ffa9Sbellard *blen1p = -1; 1261d14ffa9Sbellard *blen2p = -1; 1271d14ffa9Sbellard return -1; 1281d14ffa9Sbellard } 1291d14ffa9Sbellard 1301d14ffa9Sbellard #ifdef DSBTYPE_IN 1311d14ffa9Sbellard static void dsound_fini_in (HWVoiceIn *hw) 1321d14ffa9Sbellard #else 1331d14ffa9Sbellard static void dsound_fini_out (HWVoiceOut *hw) 1341d14ffa9Sbellard #endif 1351d14ffa9Sbellard { 1361d14ffa9Sbellard HRESULT hr; 1371d14ffa9Sbellard #ifdef DSBTYPE_IN 1381d14ffa9Sbellard DSoundVoiceIn *ds = (DSoundVoiceIn *) hw; 1391d14ffa9Sbellard #else 1401d14ffa9Sbellard DSoundVoiceOut *ds = (DSoundVoiceOut *) hw; 1411d14ffa9Sbellard #endif 1421d14ffa9Sbellard 1431d14ffa9Sbellard if (ds->FIELD) { 1441d14ffa9Sbellard hr = glue (IFACE, _Stop) (ds->FIELD); 1451d14ffa9Sbellard if (FAILED (hr)) { 146c0fe3827Sbellard dsound_logerr (hr, "Could not stop " NAME "\n"); 1471d14ffa9Sbellard } 1481d14ffa9Sbellard 1491d14ffa9Sbellard hr = glue (IFACE, _Release) (ds->FIELD); 1501d14ffa9Sbellard if (FAILED (hr)) { 151c0fe3827Sbellard dsound_logerr (hr, "Could not release " NAME "\n"); 1521d14ffa9Sbellard } 1531d14ffa9Sbellard ds->FIELD = NULL; 1541d14ffa9Sbellard } 1551d14ffa9Sbellard } 1561d14ffa9Sbellard 1571d14ffa9Sbellard #ifdef DSBTYPE_IN 1585706db1dSKővágó, Zoltán static int dsound_init_in(HWVoiceIn *hw, struct audsettings *as, 1595706db1dSKővágó, Zoltán void *drv_opaque) 1601d14ffa9Sbellard #else 1615706db1dSKővágó, Zoltán static int dsound_init_out(HWVoiceOut *hw, struct audsettings *as, 1625706db1dSKővágó, Zoltán void *drv_opaque) 1631d14ffa9Sbellard #endif 1641d14ffa9Sbellard { 1651d14ffa9Sbellard int err; 1661d14ffa9Sbellard HRESULT hr; 167191e1f0aSKővágó, Zoltán dsound *s = drv_opaque; 1681d14ffa9Sbellard WAVEFORMATEX wfx; 1691ea879e5Smalc struct audsettings obt_as; 170191e1f0aSKővágó, Zoltán DSoundConf *conf = &s->conf; 1711d14ffa9Sbellard #ifdef DSBTYPE_IN 1721d14ffa9Sbellard const char *typ = "ADC"; 1731d14ffa9Sbellard DSoundVoiceIn *ds = (DSoundVoiceIn *) hw; 1741d14ffa9Sbellard DSCBUFFERDESC bd; 1751d14ffa9Sbellard DSCBCAPS bc; 1761d14ffa9Sbellard #else 1771d14ffa9Sbellard const char *typ = "DAC"; 1781d14ffa9Sbellard DSoundVoiceOut *ds = (DSoundVoiceOut *) hw; 1791d14ffa9Sbellard DSBUFFERDESC bd; 1801d14ffa9Sbellard DSBCAPS bc; 1811d14ffa9Sbellard #endif 1821d14ffa9Sbellard 183ca9cc28cSbalrog if (!s->FIELD2) { 18426463dbcSbalrog dolog ("Attempt to initialize voice without " NAME2 " object\n"); 185ca9cc28cSbalrog return -1; 186ca9cc28cSbalrog } 187ca9cc28cSbalrog 188c0fe3827Sbellard err = waveformat_from_audio_settings (&wfx, as); 1891d14ffa9Sbellard if (err) { 1901d14ffa9Sbellard return -1; 1911d14ffa9Sbellard } 1921d14ffa9Sbellard 1931d14ffa9Sbellard memset (&bd, 0, sizeof (bd)); 1941d14ffa9Sbellard bd.dwSize = sizeof (bd); 1951d14ffa9Sbellard bd.lpwfxFormat = &wfx; 1961d14ffa9Sbellard #ifdef DSBTYPE_IN 197191e1f0aSKővágó, Zoltán bd.dwBufferBytes = conf->bufsize_in; 1981d14ffa9Sbellard hr = IDirectSoundCapture_CreateCaptureBuffer ( 1991d14ffa9Sbellard s->dsound_capture, 2001d14ffa9Sbellard &bd, 2011d14ffa9Sbellard &ds->dsound_capture_buffer, 2021d14ffa9Sbellard NULL 2031d14ffa9Sbellard ); 2041d14ffa9Sbellard #else 2051d14ffa9Sbellard bd.dwFlags = DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2; 206191e1f0aSKővágó, Zoltán bd.dwBufferBytes = conf->bufsize_out; 2071d14ffa9Sbellard hr = IDirectSound_CreateSoundBuffer ( 2081d14ffa9Sbellard s->dsound, 2091d14ffa9Sbellard &bd, 2101d14ffa9Sbellard &ds->dsound_buffer, 2111d14ffa9Sbellard NULL 2121d14ffa9Sbellard ); 2131d14ffa9Sbellard #endif 2141d14ffa9Sbellard 2151d14ffa9Sbellard if (FAILED (hr)) { 216c0fe3827Sbellard dsound_logerr2 (hr, typ, "Could not create " NAME "\n"); 2171d14ffa9Sbellard return -1; 2181d14ffa9Sbellard } 2191d14ffa9Sbellard 220c0fe3827Sbellard hr = glue (IFACE, _GetFormat) (ds->FIELD, &wfx, sizeof (wfx), NULL); 2211d14ffa9Sbellard if (FAILED (hr)) { 222c0fe3827Sbellard dsound_logerr2 (hr, typ, "Could not get " NAME " format\n"); 2231d14ffa9Sbellard goto fail0; 2241d14ffa9Sbellard } 2251d14ffa9Sbellard 2261d14ffa9Sbellard #ifdef DEBUG_DSOUND 2271d14ffa9Sbellard dolog (NAME "\n"); 2281d14ffa9Sbellard print_wave_format (&wfx); 2291d14ffa9Sbellard #endif 2301d14ffa9Sbellard 2311d14ffa9Sbellard memset (&bc, 0, sizeof (bc)); 2321d14ffa9Sbellard bc.dwSize = sizeof (bc); 2331d14ffa9Sbellard 2341d14ffa9Sbellard hr = glue (IFACE, _GetCaps) (ds->FIELD, &bc); 2351d14ffa9Sbellard if (FAILED (hr)) { 236c0fe3827Sbellard dsound_logerr2 (hr, typ, "Could not get " NAME " format\n"); 2371d14ffa9Sbellard goto fail0; 2381d14ffa9Sbellard } 2391d14ffa9Sbellard 240c0fe3827Sbellard err = waveformat_to_audio_settings (&wfx, &obt_as); 2411d14ffa9Sbellard if (err) { 2421d14ffa9Sbellard goto fail0; 2431d14ffa9Sbellard } 2441d14ffa9Sbellard 2451d14ffa9Sbellard ds->first_time = 1; 246d929eba5Sbellard obt_as.endianness = 0; 247d929eba5Sbellard audio_pcm_init_info (&hw->info, &obt_as); 248c0fe3827Sbellard 249c0fe3827Sbellard if (bc.dwBufferBytes & hw->info.align) { 250c0fe3827Sbellard dolog ( 251c0fe3827Sbellard "GetCaps returned misaligned buffer size %ld, alignment %d\n", 252c0fe3827Sbellard bc.dwBufferBytes, hw->info.align + 1 2531d14ffa9Sbellard ); 254c0fe3827Sbellard } 255c0fe3827Sbellard hw->samples = bc.dwBufferBytes >> hw->info.shift; 256191e1f0aSKővágó, Zoltán ds->s = s; 2571d14ffa9Sbellard 2581d14ffa9Sbellard #ifdef DEBUG_DSOUND 2591d14ffa9Sbellard dolog ("caps %ld, desc %ld\n", 2601d14ffa9Sbellard bc.dwBufferBytes, bd.dwBufferBytes); 2611d14ffa9Sbellard 2621d14ffa9Sbellard dolog ("bufsize %d, freq %d, chan %d, fmt %d\n", 263c0fe3827Sbellard hw->bufsize, settings.freq, settings.nchannels, settings.fmt); 2641d14ffa9Sbellard #endif 2651d14ffa9Sbellard return 0; 2661d14ffa9Sbellard 2671d14ffa9Sbellard fail0: 2681d14ffa9Sbellard glue (dsound_fini_, TYPE) (hw); 2691d14ffa9Sbellard return -1; 2701d14ffa9Sbellard } 2711d14ffa9Sbellard 2721d14ffa9Sbellard #undef NAME 273832e9079Smalc #undef NAME2 2741d14ffa9Sbellard #undef TYPE 2751d14ffa9Sbellard #undef IFACE 2761d14ffa9Sbellard #undef BUFPTR 2771d14ffa9Sbellard #undef FIELD 278832e9079Smalc #undef FIELD2 279