xref: /qemu/audio/dsound_template.h (revision 832e9079319c17d528c5b33e285efba9b6e742b4)
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,
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
1771ea879e5Smalc static int dsound_init_in (HWVoiceIn *hw, struct audsettings *as)
1781d14ffa9Sbellard #else
1791ea879e5Smalc static int dsound_init_out (HWVoiceOut *hw, struct audsettings *as)
1801d14ffa9Sbellard #endif
1811d14ffa9Sbellard {
1821d14ffa9Sbellard     int err;
1831d14ffa9Sbellard     HRESULT hr;
1841d14ffa9Sbellard     dsound *s = &glob_dsound;
1851d14ffa9Sbellard     WAVEFORMATEX wfx;
1861ea879e5Smalc     struct audsettings 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 
199ca9cc28cSbalrog     if (!s->FIELD2) {
20026463dbcSbalrog         dolog ("Attempt to initialize voice without " NAME2 " object\n");
201ca9cc28cSbalrog         return -1;
202ca9cc28cSbalrog     }
203ca9cc28cSbalrog 
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
288*832e9079Smalc #undef NAME2
2891d14ffa9Sbellard #undef TYPE
2901d14ffa9Sbellard #undef IFACE
2911d14ffa9Sbellard #undef BUFPTR
2921d14ffa9Sbellard #undef FIELD
293*832e9079Smalc #undef FIELD2
294