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
327fa9754aSKővágó, Zoltán #define HWVOICE HWVoiceIn
337fa9754aSKővágó, Zoltán #define DSOUNDVOICE DSoundVoiceIn
341d14ffa9Sbellard #else
351d14ffa9Sbellard #define NAME "playback buffer"
36ca9cc28cSbalrog #define NAME2 "DirectSound"
371d14ffa9Sbellard #define TYPE out
381d14ffa9Sbellard #define IFACE IDirectSoundBuffer
391d14ffa9Sbellard #define BUFPTR LPDIRECTSOUNDBUFFER
401d14ffa9Sbellard #define FIELD dsound_buffer
41ca9cc28cSbalrog #define FIELD2 dsound
427fa9754aSKővágó, Zoltán #define HWVOICE HWVoiceOut
437fa9754aSKővágó, Zoltán #define DSOUNDVOICE DSoundVoiceOut
441d14ffa9Sbellard #endif
451d14ffa9Sbellard
glue(dsound_unlock_,TYPE)461d14ffa9Sbellard static int glue (dsound_unlock_, TYPE) (
471d14ffa9Sbellard BUFPTR buf,
481d14ffa9Sbellard LPVOID p1,
491d14ffa9Sbellard LPVOID p2,
501d14ffa9Sbellard DWORD blen1,
511d14ffa9Sbellard DWORD blen2
521d14ffa9Sbellard )
531d14ffa9Sbellard {
541d14ffa9Sbellard HRESULT hr;
551d14ffa9Sbellard
561d14ffa9Sbellard hr = glue (IFACE, _Unlock) (buf, p1, blen1, p2, blen2);
571d14ffa9Sbellard if (FAILED (hr)) {
58c0fe3827Sbellard dsound_logerr (hr, "Could not unlock " NAME "\n");
591d14ffa9Sbellard return -1;
601d14ffa9Sbellard }
611d14ffa9Sbellard
621d14ffa9Sbellard return 0;
631d14ffa9Sbellard }
641d14ffa9Sbellard
glue(dsound_lock_,TYPE)651d14ffa9Sbellard static int glue (dsound_lock_, TYPE) (
661d14ffa9Sbellard BUFPTR buf,
671d14ffa9Sbellard struct audio_pcm_info *info,
681d14ffa9Sbellard DWORD pos,
691d14ffa9Sbellard DWORD len,
701d14ffa9Sbellard LPVOID *p1p,
711d14ffa9Sbellard LPVOID *p2p,
721d14ffa9Sbellard DWORD *blen1p,
731d14ffa9Sbellard DWORD *blen2p,
74191e1f0aSKővágó, Zoltán int entire,
75191e1f0aSKővágó, Zoltán dsound *s
761d14ffa9Sbellard )
771d14ffa9Sbellard {
781d14ffa9Sbellard HRESULT hr;
798ead62cfSbellard DWORD flag;
801d14ffa9Sbellard
818ead62cfSbellard #ifdef DSBTYPE_IN
828ead62cfSbellard flag = entire ? DSCBLOCK_ENTIREBUFFER : 0;
838ead62cfSbellard #else
848ead62cfSbellard flag = entire ? DSBLOCK_ENTIREBUFFER : 0;
858ead62cfSbellard #endif
867fa9754aSKővágó, Zoltán hr = glue(IFACE, _Lock)(buf, pos, len, p1p, blen1p, p2p, blen2p, flag);
871d14ffa9Sbellard
881d14ffa9Sbellard if (FAILED (hr)) {
891d14ffa9Sbellard #ifndef DSBTYPE_IN
901d14ffa9Sbellard if (hr == DSERR_BUFFERLOST) {
91191e1f0aSKővágó, Zoltán if (glue (dsound_restore_, TYPE) (buf, s)) {
92c0fe3827Sbellard dsound_logerr (hr, "Could not lock " NAME "\n");
931d14ffa9Sbellard }
942762955fSKővágó, Zoltán goto fail;
951d14ffa9Sbellard }
961d14ffa9Sbellard #endif
97c0fe3827Sbellard dsound_logerr (hr, "Could not lock " NAME "\n");
981d14ffa9Sbellard goto fail;
991d14ffa9Sbellard }
1001d14ffa9Sbellard
1012b9cce8cSKővágó, Zoltán if ((p1p && *p1p && (*blen1p % info->bytes_per_frame)) ||
1022b9cce8cSKővágó, Zoltán (p2p && *p2p && (*blen2p % info->bytes_per_frame))) {
1031d14ffa9Sbellard dolog("DirectSound returned misaligned buffer %ld %ld\n",
1047fa9754aSKővágó, Zoltán *blen1p, *blen2p);
1057fa9754aSKővágó, Zoltán glue(dsound_unlock_, TYPE)(buf, *p1p, p2p ? *p2p : NULL, *blen1p,
1067fa9754aSKővágó, Zoltán blen2p ? *blen2p : 0);
1071d14ffa9Sbellard goto fail;
1081d14ffa9Sbellard }
1091d14ffa9Sbellard
1107fa9754aSKővágó, Zoltán if (p1p && !*p1p && *blen1p) {
1117fa9754aSKővágó, Zoltán dolog("warning: !p1 && blen1=%ld\n", *blen1p);
1127fa9754aSKővágó, Zoltán *blen1p = 0;
1131d14ffa9Sbellard }
1141d14ffa9Sbellard
1157fa9754aSKővágó, Zoltán if (p2p && !*p2p && *blen2p) {
1167fa9754aSKővágó, Zoltán dolog("warning: !p2 && blen2=%ld\n", *blen2p);
1177fa9754aSKővágó, Zoltán *blen2p = 0;
1181d14ffa9Sbellard }
1191d14ffa9Sbellard
1201d14ffa9Sbellard return 0;
1211d14ffa9Sbellard
1221d14ffa9Sbellard fail:
1231d14ffa9Sbellard *p1p = NULL - 1;
1241d14ffa9Sbellard *blen1p = -1;
1257fa9754aSKővágó, Zoltán if (p2p) {
1267fa9754aSKővágó, Zoltán *p2p = NULL - 1;
1271d14ffa9Sbellard *blen2p = -1;
1287fa9754aSKővágó, Zoltán }
1291d14ffa9Sbellard return -1;
1301d14ffa9Sbellard }
1311d14ffa9Sbellard
1321d14ffa9Sbellard #ifdef DSBTYPE_IN
dsound_fini_in(HWVoiceIn * hw)1331d14ffa9Sbellard static void dsound_fini_in (HWVoiceIn *hw)
1341d14ffa9Sbellard #else
1351d14ffa9Sbellard static void dsound_fini_out (HWVoiceOut *hw)
1361d14ffa9Sbellard #endif
1371d14ffa9Sbellard {
1381d14ffa9Sbellard HRESULT hr;
1391d14ffa9Sbellard #ifdef DSBTYPE_IN
1401d14ffa9Sbellard DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
1411d14ffa9Sbellard #else
1421d14ffa9Sbellard DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
1431d14ffa9Sbellard #endif
1441d14ffa9Sbellard
1451d14ffa9Sbellard if (ds->FIELD) {
1461d14ffa9Sbellard hr = glue (IFACE, _Stop) (ds->FIELD);
1471d14ffa9Sbellard if (FAILED (hr)) {
148c0fe3827Sbellard dsound_logerr (hr, "Could not stop " NAME "\n");
1491d14ffa9Sbellard }
1501d14ffa9Sbellard
1511d14ffa9Sbellard hr = glue (IFACE, _Release) (ds->FIELD);
1521d14ffa9Sbellard if (FAILED (hr)) {
153c0fe3827Sbellard dsound_logerr (hr, "Could not release " NAME "\n");
1541d14ffa9Sbellard }
1551d14ffa9Sbellard ds->FIELD = NULL;
1561d14ffa9Sbellard }
1571d14ffa9Sbellard }
1581d14ffa9Sbellard
1591d14ffa9Sbellard #ifdef DSBTYPE_IN
dsound_init_in(HWVoiceIn * hw,struct audsettings * as,void * drv_opaque)1605706db1dSKővágó, Zoltán static int dsound_init_in(HWVoiceIn *hw, struct audsettings *as,
1615706db1dSKővágó, Zoltán void *drv_opaque)
1621d14ffa9Sbellard #else
1635706db1dSKővágó, Zoltán static int dsound_init_out(HWVoiceOut *hw, struct audsettings *as,
1645706db1dSKővágó, Zoltán void *drv_opaque)
1651d14ffa9Sbellard #endif
1661d14ffa9Sbellard {
1671d14ffa9Sbellard int err;
1681d14ffa9Sbellard HRESULT hr;
169191e1f0aSKővágó, Zoltán dsound *s = drv_opaque;
1701d14ffa9Sbellard WAVEFORMATEX wfx;
1711ea879e5Smalc struct audsettings obt_as;
1721d14ffa9Sbellard #ifdef DSBTYPE_IN
1731d14ffa9Sbellard const char *typ = "ADC";
1741d14ffa9Sbellard DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
1751d14ffa9Sbellard DSCBUFFERDESC bd;
1761d14ffa9Sbellard DSCBCAPS bc;
1774a3b8b34SKővágó, Zoltán AudiodevPerDirectionOptions *pdo = s->dev->u.dsound.in;
1781d14ffa9Sbellard #else
1791d14ffa9Sbellard const char *typ = "DAC";
1801d14ffa9Sbellard DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
1811d14ffa9Sbellard DSBUFFERDESC bd;
1821d14ffa9Sbellard DSBCAPS bc;
1834a3b8b34SKővágó, Zoltán AudiodevPerDirectionOptions *pdo = s->dev->u.dsound.out;
1841d14ffa9Sbellard #endif
1851d14ffa9Sbellard
186ca9cc28cSbalrog if (!s->FIELD2) {
18726463dbcSbalrog dolog ("Attempt to initialize voice without " NAME2 " object\n");
188ca9cc28cSbalrog return -1;
189ca9cc28cSbalrog }
190ca9cc28cSbalrog
191c0fe3827Sbellard err = waveformat_from_audio_settings (&wfx, as);
1921d14ffa9Sbellard if (err) {
1931d14ffa9Sbellard return -1;
1941d14ffa9Sbellard }
1951d14ffa9Sbellard
1961d14ffa9Sbellard memset (&bd, 0, sizeof (bd));
1971d14ffa9Sbellard bd.dwSize = sizeof (bd);
1981d14ffa9Sbellard bd.lpwfxFormat = &wfx;
1994a3b8b34SKővágó, Zoltán bd.dwBufferBytes = audio_buffer_bytes(pdo, as, 92880);
2001d14ffa9Sbellard #ifdef DSBTYPE_IN
2011d14ffa9Sbellard hr = IDirectSoundCapture_CreateCaptureBuffer (
2021d14ffa9Sbellard s->dsound_capture,
2031d14ffa9Sbellard &bd,
2041d14ffa9Sbellard &ds->dsound_capture_buffer,
2051d14ffa9Sbellard NULL
2061d14ffa9Sbellard );
2071d14ffa9Sbellard #else
208*401dcf05SVolker Rümelin bd.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2;
2091d14ffa9Sbellard hr = IDirectSound_CreateSoundBuffer (
2101d14ffa9Sbellard s->dsound,
2111d14ffa9Sbellard &bd,
2121d14ffa9Sbellard &ds->dsound_buffer,
2131d14ffa9Sbellard NULL
2141d14ffa9Sbellard );
2151d14ffa9Sbellard #endif
2161d14ffa9Sbellard
2171d14ffa9Sbellard if (FAILED (hr)) {
218c0fe3827Sbellard dsound_logerr2 (hr, typ, "Could not create " NAME "\n");
2191d14ffa9Sbellard return -1;
2201d14ffa9Sbellard }
2211d14ffa9Sbellard
222c0fe3827Sbellard hr = glue (IFACE, _GetFormat) (ds->FIELD, &wfx, sizeof (wfx), NULL);
2231d14ffa9Sbellard if (FAILED (hr)) {
224c0fe3827Sbellard dsound_logerr2 (hr, typ, "Could not get " NAME " format\n");
2251d14ffa9Sbellard goto fail0;
2261d14ffa9Sbellard }
2271d14ffa9Sbellard
2281d14ffa9Sbellard #ifdef DEBUG_DSOUND
2291d14ffa9Sbellard dolog (NAME "\n");
2301d14ffa9Sbellard print_wave_format (&wfx);
2311d14ffa9Sbellard #endif
2321d14ffa9Sbellard
2331d14ffa9Sbellard memset (&bc, 0, sizeof (bc));
2341d14ffa9Sbellard bc.dwSize = sizeof (bc);
2351d14ffa9Sbellard
2361d14ffa9Sbellard hr = glue (IFACE, _GetCaps) (ds->FIELD, &bc);
2371d14ffa9Sbellard if (FAILED (hr)) {
238c0fe3827Sbellard dsound_logerr2 (hr, typ, "Could not get " NAME " format\n");
2391d14ffa9Sbellard goto fail0;
2401d14ffa9Sbellard }
2411d14ffa9Sbellard
242c0fe3827Sbellard err = waveformat_to_audio_settings (&wfx, &obt_as);
2431d14ffa9Sbellard if (err) {
2441d14ffa9Sbellard goto fail0;
2451d14ffa9Sbellard }
2461d14ffa9Sbellard
247fb35c2ceSKővágó, Zoltán ds->first_time = true;
248d929eba5Sbellard obt_as.endianness = 0;
249d929eba5Sbellard audio_pcm_init_info (&hw->info, &obt_as);
250c0fe3827Sbellard
2512b9cce8cSKővágó, Zoltán if (bc.dwBufferBytes % hw->info.bytes_per_frame) {
252c0fe3827Sbellard dolog (
253c0fe3827Sbellard "GetCaps returned misaligned buffer size %ld, alignment %d\n",
2542b9cce8cSKővágó, Zoltán bc.dwBufferBytes, hw->info.bytes_per_frame
2551d14ffa9Sbellard );
256c0fe3827Sbellard }
2577fa9754aSKővágó, Zoltán hw->size_emul = bc.dwBufferBytes;
2582b9cce8cSKővágó, Zoltán hw->samples = bc.dwBufferBytes / hw->info.bytes_per_frame;
259191e1f0aSKővágó, Zoltán ds->s = s;
2601d14ffa9Sbellard
2611d14ffa9Sbellard #ifdef DEBUG_DSOUND
2621d14ffa9Sbellard dolog ("caps %ld, desc %ld\n",
2631d14ffa9Sbellard bc.dwBufferBytes, bd.dwBufferBytes);
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
2797fa9754aSKővágó, Zoltán #undef HWVOICE
2807fa9754aSKővágó, Zoltán #undef DSOUNDVOICE
281