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" 26*ca9cc28cSbalrog #define NAME2 "DirectSoundCapture" 271d14ffa9Sbellard #define TYPE in 281d14ffa9Sbellard #define IFACE IDirectSoundCaptureBuffer 291d14ffa9Sbellard #define BUFPTR LPDIRECTSOUNDCAPTUREBUFFER 301d14ffa9Sbellard #define FIELD dsound_capture_buffer 31*ca9cc28cSbalrog #define FIELD2 dsound_capture 321d14ffa9Sbellard #else 331d14ffa9Sbellard #define NAME "playback buffer" 34*ca9cc28cSbalrog #define NAME2 "DirectSound" 351d14ffa9Sbellard #define TYPE out 361d14ffa9Sbellard #define IFACE IDirectSoundBuffer 371d14ffa9Sbellard #define BUFPTR LPDIRECTSOUNDBUFFER 381d14ffa9Sbellard #define FIELD dsound_buffer 39*ca9cc28cSbalrog #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, 701d14ffa9Sbellard int entire 711d14ffa9Sbellard ) 721d14ffa9Sbellard { 731d14ffa9Sbellard HRESULT hr; 741d14ffa9Sbellard int i; 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 841d14ffa9Sbellard for (i = 0; i < conf.lock_retries; ++i) { 851d14ffa9Sbellard hr = glue (IFACE, _Lock) ( 861d14ffa9Sbellard buf, 871d14ffa9Sbellard pos, 881d14ffa9Sbellard len, 891d14ffa9Sbellard &p1, 901d14ffa9Sbellard &blen1, 911d14ffa9Sbellard &p2, 921d14ffa9Sbellard &blen2, 938ead62cfSbellard flag 941d14ffa9Sbellard ); 951d14ffa9Sbellard 961d14ffa9Sbellard if (FAILED (hr)) { 971d14ffa9Sbellard #ifndef DSBTYPE_IN 981d14ffa9Sbellard if (hr == DSERR_BUFFERLOST) { 991d14ffa9Sbellard if (glue (dsound_restore_, TYPE) (buf)) { 100c0fe3827Sbellard dsound_logerr (hr, "Could not lock " NAME "\n"); 1011d14ffa9Sbellard goto fail; 1021d14ffa9Sbellard } 1031d14ffa9Sbellard continue; 1041d14ffa9Sbellard } 1051d14ffa9Sbellard #endif 106c0fe3827Sbellard dsound_logerr (hr, "Could not lock " NAME "\n"); 1071d14ffa9Sbellard goto fail; 1081d14ffa9Sbellard } 1091d14ffa9Sbellard 1101d14ffa9Sbellard break; 1111d14ffa9Sbellard } 1121d14ffa9Sbellard 1131d14ffa9Sbellard if (i == conf.lock_retries) { 1141d14ffa9Sbellard dolog ("%d attempts to lock " NAME " failed\n", i); 1151d14ffa9Sbellard goto fail; 1161d14ffa9Sbellard } 1171d14ffa9Sbellard 1181d14ffa9Sbellard if ((p1 && (blen1 & info->align)) || (p2 && (blen2 & info->align))) { 1191d14ffa9Sbellard dolog ("DirectSound returned misaligned buffer %ld %ld\n", 1201d14ffa9Sbellard blen1, blen2); 1211d14ffa9Sbellard glue (dsound_unlock_, TYPE) (buf, p1, p2, blen1, blen2); 1221d14ffa9Sbellard goto fail; 1231d14ffa9Sbellard } 1241d14ffa9Sbellard 1251d14ffa9Sbellard if (!p1 && blen1) { 1261d14ffa9Sbellard dolog ("warning: !p1 && blen1=%ld\n", blen1); 1271d14ffa9Sbellard blen1 = 0; 1281d14ffa9Sbellard } 1291d14ffa9Sbellard 1301d14ffa9Sbellard if (!p2 && blen2) { 1311d14ffa9Sbellard dolog ("warning: !p2 && blen2=%ld\n", blen2); 1321d14ffa9Sbellard blen2 = 0; 1331d14ffa9Sbellard } 1341d14ffa9Sbellard 1351d14ffa9Sbellard *p1p = p1; 1361d14ffa9Sbellard *p2p = p2; 1371d14ffa9Sbellard *blen1p = blen1; 1381d14ffa9Sbellard *blen2p = blen2; 1391d14ffa9Sbellard return 0; 1401d14ffa9Sbellard 1411d14ffa9Sbellard fail: 1421d14ffa9Sbellard *p1p = NULL - 1; 1431d14ffa9Sbellard *p2p = NULL - 1; 1441d14ffa9Sbellard *blen1p = -1; 1451d14ffa9Sbellard *blen2p = -1; 1461d14ffa9Sbellard return -1; 1471d14ffa9Sbellard } 1481d14ffa9Sbellard 1491d14ffa9Sbellard #ifdef DSBTYPE_IN 1501d14ffa9Sbellard static void dsound_fini_in (HWVoiceIn *hw) 1511d14ffa9Sbellard #else 1521d14ffa9Sbellard static void dsound_fini_out (HWVoiceOut *hw) 1531d14ffa9Sbellard #endif 1541d14ffa9Sbellard { 1551d14ffa9Sbellard HRESULT hr; 1561d14ffa9Sbellard #ifdef DSBTYPE_IN 1571d14ffa9Sbellard DSoundVoiceIn *ds = (DSoundVoiceIn *) hw; 1581d14ffa9Sbellard #else 1591d14ffa9Sbellard DSoundVoiceOut *ds = (DSoundVoiceOut *) hw; 1601d14ffa9Sbellard #endif 1611d14ffa9Sbellard 1621d14ffa9Sbellard if (ds->FIELD) { 1631d14ffa9Sbellard hr = glue (IFACE, _Stop) (ds->FIELD); 1641d14ffa9Sbellard if (FAILED (hr)) { 165c0fe3827Sbellard dsound_logerr (hr, "Could not stop " NAME "\n"); 1661d14ffa9Sbellard } 1671d14ffa9Sbellard 1681d14ffa9Sbellard hr = glue (IFACE, _Release) (ds->FIELD); 1691d14ffa9Sbellard if (FAILED (hr)) { 170c0fe3827Sbellard dsound_logerr (hr, "Could not release " NAME "\n"); 1711d14ffa9Sbellard } 1721d14ffa9Sbellard ds->FIELD = NULL; 1731d14ffa9Sbellard } 1741d14ffa9Sbellard } 1751d14ffa9Sbellard 1761d14ffa9Sbellard #ifdef DSBTYPE_IN 177c0fe3827Sbellard static int dsound_init_in (HWVoiceIn *hw, audsettings_t *as) 1781d14ffa9Sbellard #else 179c0fe3827Sbellard static int dsound_init_out (HWVoiceOut *hw, audsettings_t *as) 1801d14ffa9Sbellard #endif 1811d14ffa9Sbellard { 1821d14ffa9Sbellard int err; 1831d14ffa9Sbellard HRESULT hr; 1841d14ffa9Sbellard dsound *s = &glob_dsound; 1851d14ffa9Sbellard WAVEFORMATEX wfx; 186c0fe3827Sbellard audsettings_t obt_as; 1871d14ffa9Sbellard #ifdef DSBTYPE_IN 1881d14ffa9Sbellard const char *typ = "ADC"; 1891d14ffa9Sbellard DSoundVoiceIn *ds = (DSoundVoiceIn *) hw; 1901d14ffa9Sbellard DSCBUFFERDESC bd; 1911d14ffa9Sbellard DSCBCAPS bc; 1921d14ffa9Sbellard #else 1931d14ffa9Sbellard const char *typ = "DAC"; 1941d14ffa9Sbellard DSoundVoiceOut *ds = (DSoundVoiceOut *) hw; 1951d14ffa9Sbellard DSBUFFERDESC bd; 1961d14ffa9Sbellard DSBCAPS bc; 1971d14ffa9Sbellard #endif 1981d14ffa9Sbellard 199*ca9cc28cSbalrog if (!s->FIELD2) { 200*ca9cc28cSbalrog dsound_logerr ("Attempt to initialize voice without " NAME2 " object"); 201*ca9cc28cSbalrog return -1; 202*ca9cc28cSbalrog } 203*ca9cc28cSbalrog 204c0fe3827Sbellard err = waveformat_from_audio_settings (&wfx, as); 2051d14ffa9Sbellard if (err) { 2061d14ffa9Sbellard return -1; 2071d14ffa9Sbellard } 2081d14ffa9Sbellard 2091d14ffa9Sbellard memset (&bd, 0, sizeof (bd)); 2101d14ffa9Sbellard bd.dwSize = sizeof (bd); 2111d14ffa9Sbellard bd.lpwfxFormat = &wfx; 2121d14ffa9Sbellard #ifdef DSBTYPE_IN 2131d14ffa9Sbellard bd.dwBufferBytes = conf.bufsize_in; 2141d14ffa9Sbellard hr = IDirectSoundCapture_CreateCaptureBuffer ( 2151d14ffa9Sbellard s->dsound_capture, 2161d14ffa9Sbellard &bd, 2171d14ffa9Sbellard &ds->dsound_capture_buffer, 2181d14ffa9Sbellard NULL 2191d14ffa9Sbellard ); 2201d14ffa9Sbellard #else 2211d14ffa9Sbellard bd.dwFlags = DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2; 2221d14ffa9Sbellard bd.dwBufferBytes = conf.bufsize_out; 2231d14ffa9Sbellard hr = IDirectSound_CreateSoundBuffer ( 2241d14ffa9Sbellard s->dsound, 2251d14ffa9Sbellard &bd, 2261d14ffa9Sbellard &ds->dsound_buffer, 2271d14ffa9Sbellard NULL 2281d14ffa9Sbellard ); 2291d14ffa9Sbellard #endif 2301d14ffa9Sbellard 2311d14ffa9Sbellard if (FAILED (hr)) { 232c0fe3827Sbellard dsound_logerr2 (hr, typ, "Could not create " NAME "\n"); 2331d14ffa9Sbellard return -1; 2341d14ffa9Sbellard } 2351d14ffa9Sbellard 236c0fe3827Sbellard hr = glue (IFACE, _GetFormat) (ds->FIELD, &wfx, sizeof (wfx), NULL); 2371d14ffa9Sbellard if (FAILED (hr)) { 238c0fe3827Sbellard dsound_logerr2 (hr, typ, "Could not get " NAME " format\n"); 2391d14ffa9Sbellard goto fail0; 2401d14ffa9Sbellard } 2411d14ffa9Sbellard 2421d14ffa9Sbellard #ifdef DEBUG_DSOUND 2431d14ffa9Sbellard dolog (NAME "\n"); 2441d14ffa9Sbellard print_wave_format (&wfx); 2451d14ffa9Sbellard #endif 2461d14ffa9Sbellard 2471d14ffa9Sbellard memset (&bc, 0, sizeof (bc)); 2481d14ffa9Sbellard bc.dwSize = sizeof (bc); 2491d14ffa9Sbellard 2501d14ffa9Sbellard hr = glue (IFACE, _GetCaps) (ds->FIELD, &bc); 2511d14ffa9Sbellard if (FAILED (hr)) { 252c0fe3827Sbellard dsound_logerr2 (hr, typ, "Could not get " NAME " format\n"); 2531d14ffa9Sbellard goto fail0; 2541d14ffa9Sbellard } 2551d14ffa9Sbellard 256c0fe3827Sbellard err = waveformat_to_audio_settings (&wfx, &obt_as); 2571d14ffa9Sbellard if (err) { 2581d14ffa9Sbellard goto fail0; 2591d14ffa9Sbellard } 2601d14ffa9Sbellard 2611d14ffa9Sbellard ds->first_time = 1; 262d929eba5Sbellard obt_as.endianness = 0; 263d929eba5Sbellard audio_pcm_init_info (&hw->info, &obt_as); 264c0fe3827Sbellard 265c0fe3827Sbellard if (bc.dwBufferBytes & hw->info.align) { 266c0fe3827Sbellard dolog ( 267c0fe3827Sbellard "GetCaps returned misaligned buffer size %ld, alignment %d\n", 268c0fe3827Sbellard bc.dwBufferBytes, hw->info.align + 1 2691d14ffa9Sbellard ); 270c0fe3827Sbellard } 271c0fe3827Sbellard hw->samples = bc.dwBufferBytes >> hw->info.shift; 2721d14ffa9Sbellard 2731d14ffa9Sbellard #ifdef DEBUG_DSOUND 2741d14ffa9Sbellard dolog ("caps %ld, desc %ld\n", 2751d14ffa9Sbellard bc.dwBufferBytes, bd.dwBufferBytes); 2761d14ffa9Sbellard 2771d14ffa9Sbellard dolog ("bufsize %d, freq %d, chan %d, fmt %d\n", 278c0fe3827Sbellard hw->bufsize, settings.freq, settings.nchannels, settings.fmt); 2791d14ffa9Sbellard #endif 2801d14ffa9Sbellard return 0; 2811d14ffa9Sbellard 2821d14ffa9Sbellard fail0: 2831d14ffa9Sbellard glue (dsound_fini_, TYPE) (hw); 2841d14ffa9Sbellard return -1; 2851d14ffa9Sbellard } 2861d14ffa9Sbellard 2871d14ffa9Sbellard #undef NAME 2881d14ffa9Sbellard #undef TYPE 2891d14ffa9Sbellard #undef IFACE 2901d14ffa9Sbellard #undef BUFPTR 2911d14ffa9Sbellard #undef FIELD 292