xref: /qemu/audio/dsound_template.h (revision 8ead62cfc21f61a32677892c721674e06e9f6153)
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;
73*8ead62cfSbellard     DWORD flag;
741d14ffa9Sbellard 
75*8ead62cfSbellard #ifdef DSBTYPE_IN
76*8ead62cfSbellard     flag = entire ? DSCBLOCK_ENTIREBUFFER : 0;
77*8ead62cfSbellard #else
78*8ead62cfSbellard     flag = entire ? DSBLOCK_ENTIREBUFFER : 0;
79*8ead62cfSbellard #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,
89*8ead62cfSbellard             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;
253c0fe3827Sbellard 
254c0fe3827Sbellard     audio_pcm_init_info (&hw->info, &obt_as, audio_need_to_swap_endian (0));
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