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, 70*191e1f0aSKővágó, Zoltán int entire, 71*191e1f0aSKővágó, Zoltán dsound *s 721d14ffa9Sbellard ) 731d14ffa9Sbellard { 741d14ffa9Sbellard HRESULT hr; 751d14ffa9Sbellard int i; 761d14ffa9Sbellard LPVOID p1 = NULL, p2 = NULL; 771d14ffa9Sbellard DWORD blen1 = 0, blen2 = 0; 788ead62cfSbellard DWORD flag; 79*191e1f0aSKővágó, Zoltán DSoundConf *conf = &s->conf; 801d14ffa9Sbellard 818ead62cfSbellard #ifdef DSBTYPE_IN 828ead62cfSbellard flag = entire ? DSCBLOCK_ENTIREBUFFER : 0; 838ead62cfSbellard #else 848ead62cfSbellard flag = entire ? DSBLOCK_ENTIREBUFFER : 0; 858ead62cfSbellard #endif 86*191e1f0aSKővágó, Zoltán for (i = 0; i < conf->lock_retries; ++i) { 871d14ffa9Sbellard hr = glue (IFACE, _Lock) ( 881d14ffa9Sbellard buf, 891d14ffa9Sbellard pos, 901d14ffa9Sbellard len, 911d14ffa9Sbellard &p1, 921d14ffa9Sbellard &blen1, 931d14ffa9Sbellard &p2, 941d14ffa9Sbellard &blen2, 958ead62cfSbellard flag 961d14ffa9Sbellard ); 971d14ffa9Sbellard 981d14ffa9Sbellard if (FAILED (hr)) { 991d14ffa9Sbellard #ifndef DSBTYPE_IN 1001d14ffa9Sbellard if (hr == DSERR_BUFFERLOST) { 101*191e1f0aSKővágó, Zoltán if (glue (dsound_restore_, TYPE) (buf, s)) { 102c0fe3827Sbellard dsound_logerr (hr, "Could not lock " NAME "\n"); 1031d14ffa9Sbellard goto fail; 1041d14ffa9Sbellard } 1051d14ffa9Sbellard continue; 1061d14ffa9Sbellard } 1071d14ffa9Sbellard #endif 108c0fe3827Sbellard dsound_logerr (hr, "Could not lock " NAME "\n"); 1091d14ffa9Sbellard goto fail; 1101d14ffa9Sbellard } 1111d14ffa9Sbellard 1121d14ffa9Sbellard break; 1131d14ffa9Sbellard } 1141d14ffa9Sbellard 115*191e1f0aSKővágó, Zoltán if (i == conf->lock_retries) { 1161d14ffa9Sbellard dolog ("%d attempts to lock " NAME " failed\n", i); 1171d14ffa9Sbellard goto fail; 1181d14ffa9Sbellard } 1191d14ffa9Sbellard 1201d14ffa9Sbellard if ((p1 && (blen1 & info->align)) || (p2 && (blen2 & info->align))) { 1211d14ffa9Sbellard dolog ("DirectSound returned misaligned buffer %ld %ld\n", 1221d14ffa9Sbellard blen1, blen2); 1231d14ffa9Sbellard glue (dsound_unlock_, TYPE) (buf, p1, p2, blen1, blen2); 1241d14ffa9Sbellard goto fail; 1251d14ffa9Sbellard } 1261d14ffa9Sbellard 1271d14ffa9Sbellard if (!p1 && blen1) { 1281d14ffa9Sbellard dolog ("warning: !p1 && blen1=%ld\n", blen1); 1291d14ffa9Sbellard blen1 = 0; 1301d14ffa9Sbellard } 1311d14ffa9Sbellard 1321d14ffa9Sbellard if (!p2 && blen2) { 1331d14ffa9Sbellard dolog ("warning: !p2 && blen2=%ld\n", blen2); 1341d14ffa9Sbellard blen2 = 0; 1351d14ffa9Sbellard } 1361d14ffa9Sbellard 1371d14ffa9Sbellard *p1p = p1; 1381d14ffa9Sbellard *p2p = p2; 1391d14ffa9Sbellard *blen1p = blen1; 1401d14ffa9Sbellard *blen2p = blen2; 1411d14ffa9Sbellard return 0; 1421d14ffa9Sbellard 1431d14ffa9Sbellard fail: 1441d14ffa9Sbellard *p1p = NULL - 1; 1451d14ffa9Sbellard *p2p = NULL - 1; 1461d14ffa9Sbellard *blen1p = -1; 1471d14ffa9Sbellard *blen2p = -1; 1481d14ffa9Sbellard return -1; 1491d14ffa9Sbellard } 1501d14ffa9Sbellard 1511d14ffa9Sbellard #ifdef DSBTYPE_IN 1521d14ffa9Sbellard static void dsound_fini_in (HWVoiceIn *hw) 1531d14ffa9Sbellard #else 1541d14ffa9Sbellard static void dsound_fini_out (HWVoiceOut *hw) 1551d14ffa9Sbellard #endif 1561d14ffa9Sbellard { 1571d14ffa9Sbellard HRESULT hr; 1581d14ffa9Sbellard #ifdef DSBTYPE_IN 1591d14ffa9Sbellard DSoundVoiceIn *ds = (DSoundVoiceIn *) hw; 1601d14ffa9Sbellard #else 1611d14ffa9Sbellard DSoundVoiceOut *ds = (DSoundVoiceOut *) hw; 1621d14ffa9Sbellard #endif 1631d14ffa9Sbellard 1641d14ffa9Sbellard if (ds->FIELD) { 1651d14ffa9Sbellard hr = glue (IFACE, _Stop) (ds->FIELD); 1661d14ffa9Sbellard if (FAILED (hr)) { 167c0fe3827Sbellard dsound_logerr (hr, "Could not stop " NAME "\n"); 1681d14ffa9Sbellard } 1691d14ffa9Sbellard 1701d14ffa9Sbellard hr = glue (IFACE, _Release) (ds->FIELD); 1711d14ffa9Sbellard if (FAILED (hr)) { 172c0fe3827Sbellard dsound_logerr (hr, "Could not release " NAME "\n"); 1731d14ffa9Sbellard } 1741d14ffa9Sbellard ds->FIELD = NULL; 1751d14ffa9Sbellard } 1761d14ffa9Sbellard } 1771d14ffa9Sbellard 1781d14ffa9Sbellard #ifdef DSBTYPE_IN 1795706db1dSKővágó, Zoltán static int dsound_init_in(HWVoiceIn *hw, struct audsettings *as, 1805706db1dSKővágó, Zoltán void *drv_opaque) 1811d14ffa9Sbellard #else 1825706db1dSKővágó, Zoltán static int dsound_init_out(HWVoiceOut *hw, struct audsettings *as, 1835706db1dSKővágó, Zoltán void *drv_opaque) 1841d14ffa9Sbellard #endif 1851d14ffa9Sbellard { 1861d14ffa9Sbellard int err; 1871d14ffa9Sbellard HRESULT hr; 188*191e1f0aSKővágó, Zoltán dsound *s = drv_opaque; 1891d14ffa9Sbellard WAVEFORMATEX wfx; 1901ea879e5Smalc struct audsettings obt_as; 191*191e1f0aSKővágó, Zoltán DSoundConf *conf = &s->conf; 1921d14ffa9Sbellard #ifdef DSBTYPE_IN 1931d14ffa9Sbellard const char *typ = "ADC"; 1941d14ffa9Sbellard DSoundVoiceIn *ds = (DSoundVoiceIn *) hw; 1951d14ffa9Sbellard DSCBUFFERDESC bd; 1961d14ffa9Sbellard DSCBCAPS bc; 1971d14ffa9Sbellard #else 1981d14ffa9Sbellard const char *typ = "DAC"; 1991d14ffa9Sbellard DSoundVoiceOut *ds = (DSoundVoiceOut *) hw; 2001d14ffa9Sbellard DSBUFFERDESC bd; 2011d14ffa9Sbellard DSBCAPS bc; 2021d14ffa9Sbellard #endif 2031d14ffa9Sbellard 204ca9cc28cSbalrog if (!s->FIELD2) { 20526463dbcSbalrog dolog ("Attempt to initialize voice without " NAME2 " object\n"); 206ca9cc28cSbalrog return -1; 207ca9cc28cSbalrog } 208ca9cc28cSbalrog 209c0fe3827Sbellard err = waveformat_from_audio_settings (&wfx, as); 2101d14ffa9Sbellard if (err) { 2111d14ffa9Sbellard return -1; 2121d14ffa9Sbellard } 2131d14ffa9Sbellard 2141d14ffa9Sbellard memset (&bd, 0, sizeof (bd)); 2151d14ffa9Sbellard bd.dwSize = sizeof (bd); 2161d14ffa9Sbellard bd.lpwfxFormat = &wfx; 2171d14ffa9Sbellard #ifdef DSBTYPE_IN 218*191e1f0aSKővágó, Zoltán bd.dwBufferBytes = conf->bufsize_in; 2191d14ffa9Sbellard hr = IDirectSoundCapture_CreateCaptureBuffer ( 2201d14ffa9Sbellard s->dsound_capture, 2211d14ffa9Sbellard &bd, 2221d14ffa9Sbellard &ds->dsound_capture_buffer, 2231d14ffa9Sbellard NULL 2241d14ffa9Sbellard ); 2251d14ffa9Sbellard #else 2261d14ffa9Sbellard bd.dwFlags = DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2; 227*191e1f0aSKővágó, Zoltán bd.dwBufferBytes = conf->bufsize_out; 2281d14ffa9Sbellard hr = IDirectSound_CreateSoundBuffer ( 2291d14ffa9Sbellard s->dsound, 2301d14ffa9Sbellard &bd, 2311d14ffa9Sbellard &ds->dsound_buffer, 2321d14ffa9Sbellard NULL 2331d14ffa9Sbellard ); 2341d14ffa9Sbellard #endif 2351d14ffa9Sbellard 2361d14ffa9Sbellard if (FAILED (hr)) { 237c0fe3827Sbellard dsound_logerr2 (hr, typ, "Could not create " NAME "\n"); 2381d14ffa9Sbellard return -1; 2391d14ffa9Sbellard } 2401d14ffa9Sbellard 241c0fe3827Sbellard hr = glue (IFACE, _GetFormat) (ds->FIELD, &wfx, sizeof (wfx), NULL); 2421d14ffa9Sbellard if (FAILED (hr)) { 243c0fe3827Sbellard dsound_logerr2 (hr, typ, "Could not get " NAME " format\n"); 2441d14ffa9Sbellard goto fail0; 2451d14ffa9Sbellard } 2461d14ffa9Sbellard 2471d14ffa9Sbellard #ifdef DEBUG_DSOUND 2481d14ffa9Sbellard dolog (NAME "\n"); 2491d14ffa9Sbellard print_wave_format (&wfx); 2501d14ffa9Sbellard #endif 2511d14ffa9Sbellard 2521d14ffa9Sbellard memset (&bc, 0, sizeof (bc)); 2531d14ffa9Sbellard bc.dwSize = sizeof (bc); 2541d14ffa9Sbellard 2551d14ffa9Sbellard hr = glue (IFACE, _GetCaps) (ds->FIELD, &bc); 2561d14ffa9Sbellard if (FAILED (hr)) { 257c0fe3827Sbellard dsound_logerr2 (hr, typ, "Could not get " NAME " format\n"); 2581d14ffa9Sbellard goto fail0; 2591d14ffa9Sbellard } 2601d14ffa9Sbellard 261c0fe3827Sbellard err = waveformat_to_audio_settings (&wfx, &obt_as); 2621d14ffa9Sbellard if (err) { 2631d14ffa9Sbellard goto fail0; 2641d14ffa9Sbellard } 2651d14ffa9Sbellard 2661d14ffa9Sbellard ds->first_time = 1; 267d929eba5Sbellard obt_as.endianness = 0; 268d929eba5Sbellard audio_pcm_init_info (&hw->info, &obt_as); 269c0fe3827Sbellard 270c0fe3827Sbellard if (bc.dwBufferBytes & hw->info.align) { 271c0fe3827Sbellard dolog ( 272c0fe3827Sbellard "GetCaps returned misaligned buffer size %ld, alignment %d\n", 273c0fe3827Sbellard bc.dwBufferBytes, hw->info.align + 1 2741d14ffa9Sbellard ); 275c0fe3827Sbellard } 276c0fe3827Sbellard hw->samples = bc.dwBufferBytes >> hw->info.shift; 277*191e1f0aSKővágó, Zoltán ds->s = s; 2781d14ffa9Sbellard 2791d14ffa9Sbellard #ifdef DEBUG_DSOUND 2801d14ffa9Sbellard dolog ("caps %ld, desc %ld\n", 2811d14ffa9Sbellard bc.dwBufferBytes, bd.dwBufferBytes); 2821d14ffa9Sbellard 2831d14ffa9Sbellard dolog ("bufsize %d, freq %d, chan %d, fmt %d\n", 284c0fe3827Sbellard hw->bufsize, settings.freq, settings.nchannels, settings.fmt); 2851d14ffa9Sbellard #endif 2861d14ffa9Sbellard return 0; 2871d14ffa9Sbellard 2881d14ffa9Sbellard fail0: 2891d14ffa9Sbellard glue (dsound_fini_, TYPE) (hw); 2901d14ffa9Sbellard return -1; 2911d14ffa9Sbellard } 2921d14ffa9Sbellard 2931d14ffa9Sbellard #undef NAME 294832e9079Smalc #undef NAME2 2951d14ffa9Sbellard #undef TYPE 2961d14ffa9Sbellard #undef IFACE 2971d14ffa9Sbellard #undef BUFPTR 2981d14ffa9Sbellard #undef FIELD 299832e9079Smalc #undef FIELD2 300