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" 261d14ffa9Sbellard #define TYPE in 271d14ffa9Sbellard #define IFACE IDirectSoundCaptureBuffer 281d14ffa9Sbellard #define BUFPTR LPDIRECTSOUNDCAPTUREBUFFER 291d14ffa9Sbellard #define FIELD dsound_capture_buffer 301d14ffa9Sbellard #else 311d14ffa9Sbellard #define NAME "playback buffer" 321d14ffa9Sbellard #define TYPE out 331d14ffa9Sbellard #define IFACE IDirectSoundBuffer 341d14ffa9Sbellard #define BUFPTR LPDIRECTSOUNDBUFFER 351d14ffa9Sbellard #define FIELD dsound_buffer 361d14ffa9Sbellard #endif 371d14ffa9Sbellard 381d14ffa9Sbellard static int glue (dsound_unlock_, TYPE) ( 391d14ffa9Sbellard BUFPTR buf, 401d14ffa9Sbellard LPVOID p1, 411d14ffa9Sbellard LPVOID p2, 421d14ffa9Sbellard DWORD blen1, 431d14ffa9Sbellard DWORD blen2 441d14ffa9Sbellard ) 451d14ffa9Sbellard { 461d14ffa9Sbellard HRESULT hr; 471d14ffa9Sbellard 481d14ffa9Sbellard hr = glue (IFACE, _Unlock) (buf, p1, blen1, p2, blen2); 491d14ffa9Sbellard if (FAILED (hr)) { 50c0fe3827Sbellard dsound_logerr (hr, "Could not unlock " NAME "\n"); 511d14ffa9Sbellard return -1; 521d14ffa9Sbellard } 531d14ffa9Sbellard 541d14ffa9Sbellard return 0; 551d14ffa9Sbellard } 561d14ffa9Sbellard 571d14ffa9Sbellard static int glue (dsound_lock_, TYPE) ( 581d14ffa9Sbellard BUFPTR buf, 591d14ffa9Sbellard struct audio_pcm_info *info, 601d14ffa9Sbellard DWORD pos, 611d14ffa9Sbellard DWORD len, 621d14ffa9Sbellard LPVOID *p1p, 631d14ffa9Sbellard LPVOID *p2p, 641d14ffa9Sbellard DWORD *blen1p, 651d14ffa9Sbellard DWORD *blen2p, 661d14ffa9Sbellard int entire 671d14ffa9Sbellard ) 681d14ffa9Sbellard { 691d14ffa9Sbellard HRESULT hr; 701d14ffa9Sbellard int i; 711d14ffa9Sbellard LPVOID p1 = NULL, p2 = NULL; 721d14ffa9Sbellard DWORD blen1 = 0, blen2 = 0; 738ead62cfSbellard DWORD flag; 741d14ffa9Sbellard 758ead62cfSbellard #ifdef DSBTYPE_IN 768ead62cfSbellard flag = entire ? DSCBLOCK_ENTIREBUFFER : 0; 778ead62cfSbellard #else 788ead62cfSbellard flag = entire ? DSBLOCK_ENTIREBUFFER : 0; 798ead62cfSbellard #endif 801d14ffa9Sbellard for (i = 0; i < conf.lock_retries; ++i) { 811d14ffa9Sbellard hr = glue (IFACE, _Lock) ( 821d14ffa9Sbellard buf, 831d14ffa9Sbellard pos, 841d14ffa9Sbellard len, 851d14ffa9Sbellard &p1, 861d14ffa9Sbellard &blen1, 871d14ffa9Sbellard &p2, 881d14ffa9Sbellard &blen2, 898ead62cfSbellard flag 901d14ffa9Sbellard ); 911d14ffa9Sbellard 921d14ffa9Sbellard if (FAILED (hr)) { 931d14ffa9Sbellard #ifndef DSBTYPE_IN 941d14ffa9Sbellard if (hr == DSERR_BUFFERLOST) { 951d14ffa9Sbellard if (glue (dsound_restore_, TYPE) (buf)) { 96c0fe3827Sbellard dsound_logerr (hr, "Could not lock " NAME "\n"); 971d14ffa9Sbellard goto fail; 981d14ffa9Sbellard } 991d14ffa9Sbellard continue; 1001d14ffa9Sbellard } 1011d14ffa9Sbellard #endif 102c0fe3827Sbellard dsound_logerr (hr, "Could not lock " NAME "\n"); 1031d14ffa9Sbellard goto fail; 1041d14ffa9Sbellard } 1051d14ffa9Sbellard 1061d14ffa9Sbellard break; 1071d14ffa9Sbellard } 1081d14ffa9Sbellard 1091d14ffa9Sbellard if (i == conf.lock_retries) { 1101d14ffa9Sbellard dolog ("%d attempts to lock " NAME " failed\n", i); 1111d14ffa9Sbellard goto fail; 1121d14ffa9Sbellard } 1131d14ffa9Sbellard 1141d14ffa9Sbellard if ((p1 && (blen1 & info->align)) || (p2 && (blen2 & info->align))) { 1151d14ffa9Sbellard dolog ("DirectSound returned misaligned buffer %ld %ld\n", 1161d14ffa9Sbellard blen1, blen2); 1171d14ffa9Sbellard glue (dsound_unlock_, TYPE) (buf, p1, p2, blen1, blen2); 1181d14ffa9Sbellard goto fail; 1191d14ffa9Sbellard } 1201d14ffa9Sbellard 1211d14ffa9Sbellard if (!p1 && blen1) { 1221d14ffa9Sbellard dolog ("warning: !p1 && blen1=%ld\n", blen1); 1231d14ffa9Sbellard blen1 = 0; 1241d14ffa9Sbellard } 1251d14ffa9Sbellard 1261d14ffa9Sbellard if (!p2 && blen2) { 1271d14ffa9Sbellard dolog ("warning: !p2 && blen2=%ld\n", blen2); 1281d14ffa9Sbellard blen2 = 0; 1291d14ffa9Sbellard } 1301d14ffa9Sbellard 1311d14ffa9Sbellard *p1p = p1; 1321d14ffa9Sbellard *p2p = p2; 1331d14ffa9Sbellard *blen1p = blen1; 1341d14ffa9Sbellard *blen2p = blen2; 1351d14ffa9Sbellard return 0; 1361d14ffa9Sbellard 1371d14ffa9Sbellard fail: 1381d14ffa9Sbellard *p1p = NULL - 1; 1391d14ffa9Sbellard *p2p = NULL - 1; 1401d14ffa9Sbellard *blen1p = -1; 1411d14ffa9Sbellard *blen2p = -1; 1421d14ffa9Sbellard return -1; 1431d14ffa9Sbellard } 1441d14ffa9Sbellard 1451d14ffa9Sbellard #ifdef DSBTYPE_IN 1461d14ffa9Sbellard static void dsound_fini_in (HWVoiceIn *hw) 1471d14ffa9Sbellard #else 1481d14ffa9Sbellard static void dsound_fini_out (HWVoiceOut *hw) 1491d14ffa9Sbellard #endif 1501d14ffa9Sbellard { 1511d14ffa9Sbellard HRESULT hr; 1521d14ffa9Sbellard #ifdef DSBTYPE_IN 1531d14ffa9Sbellard DSoundVoiceIn *ds = (DSoundVoiceIn *) hw; 1541d14ffa9Sbellard #else 1551d14ffa9Sbellard DSoundVoiceOut *ds = (DSoundVoiceOut *) hw; 1561d14ffa9Sbellard #endif 1571d14ffa9Sbellard 1581d14ffa9Sbellard if (ds->FIELD) { 1591d14ffa9Sbellard hr = glue (IFACE, _Stop) (ds->FIELD); 1601d14ffa9Sbellard if (FAILED (hr)) { 161c0fe3827Sbellard dsound_logerr (hr, "Could not stop " NAME "\n"); 1621d14ffa9Sbellard } 1631d14ffa9Sbellard 1641d14ffa9Sbellard hr = glue (IFACE, _Release) (ds->FIELD); 1651d14ffa9Sbellard if (FAILED (hr)) { 166c0fe3827Sbellard dsound_logerr (hr, "Could not release " NAME "\n"); 1671d14ffa9Sbellard } 1681d14ffa9Sbellard ds->FIELD = NULL; 1691d14ffa9Sbellard } 1701d14ffa9Sbellard } 1711d14ffa9Sbellard 1721d14ffa9Sbellard #ifdef DSBTYPE_IN 173c0fe3827Sbellard static int dsound_init_in (HWVoiceIn *hw, audsettings_t *as) 1741d14ffa9Sbellard #else 175c0fe3827Sbellard static int dsound_init_out (HWVoiceOut *hw, audsettings_t *as) 1761d14ffa9Sbellard #endif 1771d14ffa9Sbellard { 1781d14ffa9Sbellard int err; 1791d14ffa9Sbellard HRESULT hr; 1801d14ffa9Sbellard dsound *s = &glob_dsound; 1811d14ffa9Sbellard WAVEFORMATEX wfx; 182c0fe3827Sbellard audsettings_t obt_as; 1831d14ffa9Sbellard #ifdef DSBTYPE_IN 1841d14ffa9Sbellard const char *typ = "ADC"; 1851d14ffa9Sbellard DSoundVoiceIn *ds = (DSoundVoiceIn *) hw; 1861d14ffa9Sbellard DSCBUFFERDESC bd; 1871d14ffa9Sbellard DSCBCAPS bc; 1881d14ffa9Sbellard #else 1891d14ffa9Sbellard const char *typ = "DAC"; 1901d14ffa9Sbellard DSoundVoiceOut *ds = (DSoundVoiceOut *) hw; 1911d14ffa9Sbellard DSBUFFERDESC bd; 1921d14ffa9Sbellard DSBCAPS bc; 1931d14ffa9Sbellard #endif 1941d14ffa9Sbellard 195c0fe3827Sbellard err = waveformat_from_audio_settings (&wfx, as); 1961d14ffa9Sbellard if (err) { 1971d14ffa9Sbellard return -1; 1981d14ffa9Sbellard } 1991d14ffa9Sbellard 2001d14ffa9Sbellard memset (&bd, 0, sizeof (bd)); 2011d14ffa9Sbellard bd.dwSize = sizeof (bd); 2021d14ffa9Sbellard bd.lpwfxFormat = &wfx; 2031d14ffa9Sbellard #ifdef DSBTYPE_IN 2041d14ffa9Sbellard bd.dwBufferBytes = conf.bufsize_in; 2051d14ffa9Sbellard hr = IDirectSoundCapture_CreateCaptureBuffer ( 2061d14ffa9Sbellard s->dsound_capture, 2071d14ffa9Sbellard &bd, 2081d14ffa9Sbellard &ds->dsound_capture_buffer, 2091d14ffa9Sbellard NULL 2101d14ffa9Sbellard ); 2111d14ffa9Sbellard #else 2121d14ffa9Sbellard bd.dwFlags = DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2; 2131d14ffa9Sbellard bd.dwBufferBytes = conf.bufsize_out; 2141d14ffa9Sbellard hr = IDirectSound_CreateSoundBuffer ( 2151d14ffa9Sbellard s->dsound, 2161d14ffa9Sbellard &bd, 2171d14ffa9Sbellard &ds->dsound_buffer, 2181d14ffa9Sbellard NULL 2191d14ffa9Sbellard ); 2201d14ffa9Sbellard #endif 2211d14ffa9Sbellard 2221d14ffa9Sbellard if (FAILED (hr)) { 223c0fe3827Sbellard dsound_logerr2 (hr, typ, "Could not create " NAME "\n"); 2241d14ffa9Sbellard return -1; 2251d14ffa9Sbellard } 2261d14ffa9Sbellard 227c0fe3827Sbellard hr = glue (IFACE, _GetFormat) (ds->FIELD, &wfx, sizeof (wfx), NULL); 2281d14ffa9Sbellard if (FAILED (hr)) { 229c0fe3827Sbellard dsound_logerr2 (hr, typ, "Could not get " NAME " format\n"); 2301d14ffa9Sbellard goto fail0; 2311d14ffa9Sbellard } 2321d14ffa9Sbellard 2331d14ffa9Sbellard #ifdef DEBUG_DSOUND 2341d14ffa9Sbellard dolog (NAME "\n"); 2351d14ffa9Sbellard print_wave_format (&wfx); 2361d14ffa9Sbellard #endif 2371d14ffa9Sbellard 2381d14ffa9Sbellard memset (&bc, 0, sizeof (bc)); 2391d14ffa9Sbellard bc.dwSize = sizeof (bc); 2401d14ffa9Sbellard 2411d14ffa9Sbellard hr = glue (IFACE, _GetCaps) (ds->FIELD, &bc); 2421d14ffa9Sbellard if (FAILED (hr)) { 243c0fe3827Sbellard dsound_logerr2 (hr, typ, "Could not get " NAME " format\n"); 2441d14ffa9Sbellard goto fail0; 2451d14ffa9Sbellard } 2461d14ffa9Sbellard 247c0fe3827Sbellard err = waveformat_to_audio_settings (&wfx, &obt_as); 2481d14ffa9Sbellard if (err) { 2491d14ffa9Sbellard goto fail0; 2501d14ffa9Sbellard } 2511d14ffa9Sbellard 2521d14ffa9Sbellard ds->first_time = 1; 253*d929eba5Sbellard obt_as.endianness = 0; 254*d929eba5Sbellard audio_pcm_init_info (&hw->info, &obt_as); 255c0fe3827Sbellard 256c0fe3827Sbellard if (bc.dwBufferBytes & hw->info.align) { 257c0fe3827Sbellard dolog ( 258c0fe3827Sbellard "GetCaps returned misaligned buffer size %ld, alignment %d\n", 259c0fe3827Sbellard bc.dwBufferBytes, hw->info.align + 1 2601d14ffa9Sbellard ); 261c0fe3827Sbellard } 262c0fe3827Sbellard hw->samples = bc.dwBufferBytes >> hw->info.shift; 2631d14ffa9Sbellard 2641d14ffa9Sbellard #ifdef DEBUG_DSOUND 2651d14ffa9Sbellard dolog ("caps %ld, desc %ld\n", 2661d14ffa9Sbellard bc.dwBufferBytes, bd.dwBufferBytes); 2671d14ffa9Sbellard 2681d14ffa9Sbellard dolog ("bufsize %d, freq %d, chan %d, fmt %d\n", 269c0fe3827Sbellard hw->bufsize, settings.freq, settings.nchannels, settings.fmt); 2701d14ffa9Sbellard #endif 2711d14ffa9Sbellard return 0; 2721d14ffa9Sbellard 2731d14ffa9Sbellard fail0: 2741d14ffa9Sbellard glue (dsound_fini_, TYPE) (hw); 2751d14ffa9Sbellard return -1; 2761d14ffa9Sbellard } 2771d14ffa9Sbellard 2781d14ffa9Sbellard #undef NAME 2791d14ffa9Sbellard #undef TYPE 2801d14ffa9Sbellard #undef IFACE 2811d14ffa9Sbellard #undef BUFPTR 2821d14ffa9Sbellard #undef FIELD 283