xref: /qemu/audio/dsound_template.h (revision 4a3b8b344495cd7e7419604fbf51d8efd088c210)
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,
70191e1f0aSKővágó, Zoltán     int entire,
71191e1f0aSKővágó, Zoltán     dsound *s
721d14ffa9Sbellard     )
731d14ffa9Sbellard {
741d14ffa9Sbellard     HRESULT hr;
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
842762955fSKővágó, Zoltán     hr = glue(IFACE, _Lock)(buf, pos, len, &p1, &blen1, &p2, &blen2, flag);
851d14ffa9Sbellard 
861d14ffa9Sbellard     if (FAILED (hr)) {
871d14ffa9Sbellard #ifndef DSBTYPE_IN
881d14ffa9Sbellard         if (hr == DSERR_BUFFERLOST) {
89191e1f0aSKővágó, Zoltán             if (glue (dsound_restore_, TYPE) (buf, s)) {
90c0fe3827Sbellard                 dsound_logerr (hr, "Could not lock " NAME "\n");
911d14ffa9Sbellard             }
922762955fSKővágó, Zoltán             goto fail;
931d14ffa9Sbellard         }
941d14ffa9Sbellard #endif
95c0fe3827Sbellard         dsound_logerr (hr, "Could not lock " NAME "\n");
961d14ffa9Sbellard         goto fail;
971d14ffa9Sbellard     }
981d14ffa9Sbellard 
991d14ffa9Sbellard     if ((p1 && (blen1 & info->align)) || (p2 && (blen2 & info->align))) {
1001d14ffa9Sbellard         dolog ("DirectSound returned misaligned buffer %ld %ld\n",
1011d14ffa9Sbellard                blen1, blen2);
1021d14ffa9Sbellard         glue (dsound_unlock_, TYPE) (buf, p1, p2, blen1, blen2);
1031d14ffa9Sbellard         goto fail;
1041d14ffa9Sbellard     }
1051d14ffa9Sbellard 
1061d14ffa9Sbellard     if (!p1 && blen1) {
1071d14ffa9Sbellard         dolog ("warning: !p1 && blen1=%ld\n", blen1);
1081d14ffa9Sbellard         blen1 = 0;
1091d14ffa9Sbellard     }
1101d14ffa9Sbellard 
1111d14ffa9Sbellard     if (!p2 && blen2) {
1121d14ffa9Sbellard         dolog ("warning: !p2 && blen2=%ld\n", blen2);
1131d14ffa9Sbellard         blen2 = 0;
1141d14ffa9Sbellard     }
1151d14ffa9Sbellard 
1161d14ffa9Sbellard     *p1p = p1;
1171d14ffa9Sbellard     *p2p = p2;
1181d14ffa9Sbellard     *blen1p = blen1;
1191d14ffa9Sbellard     *blen2p = blen2;
1201d14ffa9Sbellard     return 0;
1211d14ffa9Sbellard 
1221d14ffa9Sbellard  fail:
1231d14ffa9Sbellard     *p1p = NULL - 1;
1241d14ffa9Sbellard     *p2p = NULL - 1;
1251d14ffa9Sbellard     *blen1p = -1;
1261d14ffa9Sbellard     *blen2p = -1;
1271d14ffa9Sbellard     return -1;
1281d14ffa9Sbellard }
1291d14ffa9Sbellard 
1301d14ffa9Sbellard #ifdef DSBTYPE_IN
1311d14ffa9Sbellard static void dsound_fini_in (HWVoiceIn *hw)
1321d14ffa9Sbellard #else
1331d14ffa9Sbellard static void dsound_fini_out (HWVoiceOut *hw)
1341d14ffa9Sbellard #endif
1351d14ffa9Sbellard {
1361d14ffa9Sbellard     HRESULT hr;
1371d14ffa9Sbellard #ifdef DSBTYPE_IN
1381d14ffa9Sbellard     DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
1391d14ffa9Sbellard #else
1401d14ffa9Sbellard     DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
1411d14ffa9Sbellard #endif
1421d14ffa9Sbellard 
1431d14ffa9Sbellard     if (ds->FIELD) {
1441d14ffa9Sbellard         hr = glue (IFACE, _Stop) (ds->FIELD);
1451d14ffa9Sbellard         if (FAILED (hr)) {
146c0fe3827Sbellard             dsound_logerr (hr, "Could not stop " NAME "\n");
1471d14ffa9Sbellard         }
1481d14ffa9Sbellard 
1491d14ffa9Sbellard         hr = glue (IFACE, _Release) (ds->FIELD);
1501d14ffa9Sbellard         if (FAILED (hr)) {
151c0fe3827Sbellard             dsound_logerr (hr, "Could not release " NAME "\n");
1521d14ffa9Sbellard         }
1531d14ffa9Sbellard         ds->FIELD = NULL;
1541d14ffa9Sbellard     }
1551d14ffa9Sbellard }
1561d14ffa9Sbellard 
1571d14ffa9Sbellard #ifdef DSBTYPE_IN
1585706db1dSKővágó, Zoltán static int dsound_init_in(HWVoiceIn *hw, struct audsettings *as,
1595706db1dSKővágó, Zoltán                           void *drv_opaque)
1601d14ffa9Sbellard #else
1615706db1dSKővágó, Zoltán static int dsound_init_out(HWVoiceOut *hw, struct audsettings *as,
1625706db1dSKővágó, Zoltán                            void *drv_opaque)
1631d14ffa9Sbellard #endif
1641d14ffa9Sbellard {
1651d14ffa9Sbellard     int err;
1661d14ffa9Sbellard     HRESULT hr;
167191e1f0aSKővágó, Zoltán     dsound *s = drv_opaque;
1681d14ffa9Sbellard     WAVEFORMATEX wfx;
1691ea879e5Smalc     struct audsettings obt_as;
1701d14ffa9Sbellard #ifdef DSBTYPE_IN
1711d14ffa9Sbellard     const char *typ = "ADC";
1721d14ffa9Sbellard     DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
1731d14ffa9Sbellard     DSCBUFFERDESC bd;
1741d14ffa9Sbellard     DSCBCAPS bc;
175*4a3b8b34SKővágó, Zoltán     AudiodevPerDirectionOptions *pdo = s->dev->u.dsound.in;
1761d14ffa9Sbellard #else
1771d14ffa9Sbellard     const char *typ = "DAC";
1781d14ffa9Sbellard     DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
1791d14ffa9Sbellard     DSBUFFERDESC bd;
1801d14ffa9Sbellard     DSBCAPS bc;
181*4a3b8b34SKővágó, Zoltán     AudiodevPerDirectionOptions *pdo = s->dev->u.dsound.out;
1821d14ffa9Sbellard #endif
1831d14ffa9Sbellard 
184ca9cc28cSbalrog     if (!s->FIELD2) {
18526463dbcSbalrog         dolog ("Attempt to initialize voice without " NAME2 " object\n");
186ca9cc28cSbalrog         return -1;
187ca9cc28cSbalrog     }
188ca9cc28cSbalrog 
189c0fe3827Sbellard     err = waveformat_from_audio_settings (&wfx, as);
1901d14ffa9Sbellard     if (err) {
1911d14ffa9Sbellard         return -1;
1921d14ffa9Sbellard     }
1931d14ffa9Sbellard 
1941d14ffa9Sbellard     memset (&bd, 0, sizeof (bd));
1951d14ffa9Sbellard     bd.dwSize = sizeof (bd);
1961d14ffa9Sbellard     bd.lpwfxFormat = &wfx;
197*4a3b8b34SKővágó, Zoltán     bd.dwBufferBytes = audio_buffer_bytes(pdo, as, 92880);
1981d14ffa9Sbellard #ifdef DSBTYPE_IN
1991d14ffa9Sbellard     hr = IDirectSoundCapture_CreateCaptureBuffer (
2001d14ffa9Sbellard         s->dsound_capture,
2011d14ffa9Sbellard         &bd,
2021d14ffa9Sbellard         &ds->dsound_capture_buffer,
2031d14ffa9Sbellard         NULL
2041d14ffa9Sbellard         );
2051d14ffa9Sbellard #else
2061d14ffa9Sbellard     bd.dwFlags = DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2;
2071d14ffa9Sbellard     hr = IDirectSound_CreateSoundBuffer (
2081d14ffa9Sbellard         s->dsound,
2091d14ffa9Sbellard         &bd,
2101d14ffa9Sbellard         &ds->dsound_buffer,
2111d14ffa9Sbellard         NULL
2121d14ffa9Sbellard         );
2131d14ffa9Sbellard #endif
2141d14ffa9Sbellard 
2151d14ffa9Sbellard     if (FAILED (hr)) {
216c0fe3827Sbellard         dsound_logerr2 (hr, typ, "Could not create " NAME "\n");
2171d14ffa9Sbellard         return -1;
2181d14ffa9Sbellard     }
2191d14ffa9Sbellard 
220c0fe3827Sbellard     hr = glue (IFACE, _GetFormat) (ds->FIELD, &wfx, sizeof (wfx), NULL);
2211d14ffa9Sbellard     if (FAILED (hr)) {
222c0fe3827Sbellard         dsound_logerr2 (hr, typ, "Could not get " NAME " format\n");
2231d14ffa9Sbellard         goto fail0;
2241d14ffa9Sbellard     }
2251d14ffa9Sbellard 
2261d14ffa9Sbellard #ifdef DEBUG_DSOUND
2271d14ffa9Sbellard     dolog (NAME "\n");
2281d14ffa9Sbellard     print_wave_format (&wfx);
2291d14ffa9Sbellard #endif
2301d14ffa9Sbellard 
2311d14ffa9Sbellard     memset (&bc, 0, sizeof (bc));
2321d14ffa9Sbellard     bc.dwSize = sizeof (bc);
2331d14ffa9Sbellard 
2341d14ffa9Sbellard     hr = glue (IFACE, _GetCaps) (ds->FIELD, &bc);
2351d14ffa9Sbellard     if (FAILED (hr)) {
236c0fe3827Sbellard         dsound_logerr2 (hr, typ, "Could not get " NAME " format\n");
2371d14ffa9Sbellard         goto fail0;
2381d14ffa9Sbellard     }
2391d14ffa9Sbellard 
240c0fe3827Sbellard     err = waveformat_to_audio_settings (&wfx, &obt_as);
2411d14ffa9Sbellard     if (err) {
2421d14ffa9Sbellard         goto fail0;
2431d14ffa9Sbellard     }
2441d14ffa9Sbellard 
2451d14ffa9Sbellard     ds->first_time = 1;
246d929eba5Sbellard     obt_as.endianness = 0;
247d929eba5Sbellard     audio_pcm_init_info (&hw->info, &obt_as);
248c0fe3827Sbellard 
249c0fe3827Sbellard     if (bc.dwBufferBytes & hw->info.align) {
250c0fe3827Sbellard         dolog (
251c0fe3827Sbellard             "GetCaps returned misaligned buffer size %ld, alignment %d\n",
252c0fe3827Sbellard             bc.dwBufferBytes, hw->info.align + 1
2531d14ffa9Sbellard             );
254c0fe3827Sbellard     }
255c0fe3827Sbellard     hw->samples = bc.dwBufferBytes >> hw->info.shift;
256191e1f0aSKővágó, Zoltán     ds->s = s;
2571d14ffa9Sbellard 
2581d14ffa9Sbellard #ifdef DEBUG_DSOUND
2591d14ffa9Sbellard     dolog ("caps %ld, desc %ld\n",
2601d14ffa9Sbellard            bc.dwBufferBytes, bd.dwBufferBytes);
2611d14ffa9Sbellard 
2621d14ffa9Sbellard     dolog ("bufsize %d, freq %d, chan %d, fmt %d\n",
263c0fe3827Sbellard            hw->bufsize, settings.freq, settings.nchannels, settings.fmt);
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
279