xref: /openbmc/qemu/audio/dsoundaudio.c (revision 4a3b8b344495cd7e7419604fbf51d8efd088c210)
11d14ffa9Sbellard /*
21d14ffa9Sbellard  * QEMU DirectSound audio driver
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 
251d14ffa9Sbellard /*
261d14ffa9Sbellard  * SEAL 1.07 by Carlos 'pel' Hasan was used as documentation
271d14ffa9Sbellard  */
281d14ffa9Sbellard 
296086a565SPeter Maydell #include "qemu/osdep.h"
30749bc4bfSpbrook #include "qemu-common.h"
31749bc4bfSpbrook #include "audio.h"
321d14ffa9Sbellard 
331d14ffa9Sbellard #define AUDIO_CAP "dsound"
341d14ffa9Sbellard #include "audio_int.h"
35*4a3b8b34SKővágó, Zoltán #include "qemu/host-utils.h"
361d14ffa9Sbellard 
371d14ffa9Sbellard #include <windows.h>
384fddf62aSths #include <mmsystem.h>
391d14ffa9Sbellard #include <objbase.h>
401d14ffa9Sbellard #include <dsound.h>
411d14ffa9Sbellard 
42d5631638Smalc #include "audio_win_int.h"
43d5631638Smalc 
441d14ffa9Sbellard /* #define DEBUG_DSOUND */
451d14ffa9Sbellard 
46191e1f0aSKővágó, Zoltán typedef struct {
471d14ffa9Sbellard     LPDIRECTSOUND dsound;
481d14ffa9Sbellard     LPDIRECTSOUNDCAPTURE dsound_capture;
491ea879e5Smalc     struct audsettings settings;
50*4a3b8b34SKővágó, Zoltán     Audiodev *dev;
511d14ffa9Sbellard } dsound;
521d14ffa9Sbellard 
531d14ffa9Sbellard typedef struct {
541d14ffa9Sbellard     HWVoiceOut hw;
551d14ffa9Sbellard     LPDIRECTSOUNDBUFFER dsound_buffer;
561d14ffa9Sbellard     DWORD old_pos;
571d14ffa9Sbellard     int first_time;
58191e1f0aSKővágó, Zoltán     dsound *s;
591d14ffa9Sbellard #ifdef DEBUG_DSOUND
601d14ffa9Sbellard     DWORD old_ppos;
611d14ffa9Sbellard     DWORD played;
621d14ffa9Sbellard     DWORD mixed;
631d14ffa9Sbellard #endif
641d14ffa9Sbellard } DSoundVoiceOut;
651d14ffa9Sbellard 
661d14ffa9Sbellard typedef struct {
671d14ffa9Sbellard     HWVoiceIn hw;
681d14ffa9Sbellard     int first_time;
691d14ffa9Sbellard     LPDIRECTSOUNDCAPTUREBUFFER dsound_capture_buffer;
70191e1f0aSKővágó, Zoltán     dsound *s;
711d14ffa9Sbellard } DSoundVoiceIn;
721d14ffa9Sbellard 
731d14ffa9Sbellard static void dsound_log_hresult (HRESULT hr)
741d14ffa9Sbellard {
751d14ffa9Sbellard     const char *str = "BUG";
761d14ffa9Sbellard 
771d14ffa9Sbellard     switch (hr) {
781d14ffa9Sbellard     case DS_OK:
791d14ffa9Sbellard         str = "The method succeeded";
801d14ffa9Sbellard         break;
811d14ffa9Sbellard #ifdef DS_NO_VIRTUALIZATION
821d14ffa9Sbellard     case DS_NO_VIRTUALIZATION:
831d14ffa9Sbellard         str = "The buffer was created, but another 3D algorithm was substituted";
841d14ffa9Sbellard         break;
851d14ffa9Sbellard #endif
861d14ffa9Sbellard #ifdef DS_INCOMPLETE
871d14ffa9Sbellard     case DS_INCOMPLETE:
881d14ffa9Sbellard         str = "The method succeeded, but not all the optional effects were obtained";
891d14ffa9Sbellard         break;
901d14ffa9Sbellard #endif
911d14ffa9Sbellard #ifdef DSERR_ACCESSDENIED
921d14ffa9Sbellard     case DSERR_ACCESSDENIED:
931d14ffa9Sbellard         str = "The request failed because access was denied";
941d14ffa9Sbellard         break;
951d14ffa9Sbellard #endif
961d14ffa9Sbellard #ifdef DSERR_ALLOCATED
971d14ffa9Sbellard     case DSERR_ALLOCATED:
981d14ffa9Sbellard         str = "The request failed because resources, such as a priority level, were already in use by another caller";
991d14ffa9Sbellard         break;
1001d14ffa9Sbellard #endif
1011d14ffa9Sbellard #ifdef DSERR_ALREADYINITIALIZED
1021d14ffa9Sbellard     case DSERR_ALREADYINITIALIZED:
1031d14ffa9Sbellard         str = "The object is already initialized";
1041d14ffa9Sbellard         break;
1051d14ffa9Sbellard #endif
1061d14ffa9Sbellard #ifdef DSERR_BADFORMAT
1071d14ffa9Sbellard     case DSERR_BADFORMAT:
1081d14ffa9Sbellard         str = "The specified wave format is not supported";
1091d14ffa9Sbellard         break;
1101d14ffa9Sbellard #endif
1111d14ffa9Sbellard #ifdef DSERR_BADSENDBUFFERGUID
1121d14ffa9Sbellard     case DSERR_BADSENDBUFFERGUID:
1131d14ffa9Sbellard         str = "The GUID specified in an audiopath file does not match a valid mix-in buffer";
1141d14ffa9Sbellard         break;
1151d14ffa9Sbellard #endif
1161d14ffa9Sbellard #ifdef DSERR_BUFFERLOST
1171d14ffa9Sbellard     case DSERR_BUFFERLOST:
1181d14ffa9Sbellard         str = "The buffer memory has been lost and must be restored";
1191d14ffa9Sbellard         break;
1201d14ffa9Sbellard #endif
1211d14ffa9Sbellard #ifdef DSERR_BUFFERTOOSMALL
1221d14ffa9Sbellard     case DSERR_BUFFERTOOSMALL:
1231d14ffa9Sbellard         str = "The buffer size is not great enough to enable effects processing";
1241d14ffa9Sbellard         break;
1251d14ffa9Sbellard #endif
1261d14ffa9Sbellard #ifdef DSERR_CONTROLUNAVAIL
1271d14ffa9Sbellard     case DSERR_CONTROLUNAVAIL:
1281d14ffa9Sbellard         str = "The buffer control (volume, pan, and so on) requested by the caller is not available. Controls must be specified when the buffer is created, using the dwFlags member of DSBUFFERDESC";
1291d14ffa9Sbellard         break;
1301d14ffa9Sbellard #endif
1311d14ffa9Sbellard #ifdef DSERR_DS8_REQUIRED
1321d14ffa9Sbellard     case DSERR_DS8_REQUIRED:
1331d14ffa9Sbellard         str = "A DirectSound object of class CLSID_DirectSound8 or later is required for the requested functionality. For more information, see IDirectSound8 Interface";
1341d14ffa9Sbellard         break;
1351d14ffa9Sbellard #endif
1361d14ffa9Sbellard #ifdef DSERR_FXUNAVAILABLE
1371d14ffa9Sbellard     case DSERR_FXUNAVAILABLE:
1381d14ffa9Sbellard         str = "The effects requested could not be found on the system, or they are in the wrong order or in the wrong location; for example, an effect expected in hardware was found in software";
1391d14ffa9Sbellard         break;
1401d14ffa9Sbellard #endif
1411d14ffa9Sbellard #ifdef DSERR_GENERIC
1421d14ffa9Sbellard     case DSERR_GENERIC :
1431d14ffa9Sbellard         str = "An undetermined error occurred inside the DirectSound subsystem";
1441d14ffa9Sbellard         break;
1451d14ffa9Sbellard #endif
1461d14ffa9Sbellard #ifdef DSERR_INVALIDCALL
1471d14ffa9Sbellard     case DSERR_INVALIDCALL:
1481d14ffa9Sbellard         str = "This function is not valid for the current state of this object";
1491d14ffa9Sbellard         break;
1501d14ffa9Sbellard #endif
1511d14ffa9Sbellard #ifdef DSERR_INVALIDPARAM
1521d14ffa9Sbellard     case DSERR_INVALIDPARAM:
1531d14ffa9Sbellard         str = "An invalid parameter was passed to the returning function";
1541d14ffa9Sbellard         break;
1551d14ffa9Sbellard #endif
1561d14ffa9Sbellard #ifdef DSERR_NOAGGREGATION
1571d14ffa9Sbellard     case DSERR_NOAGGREGATION:
1581d14ffa9Sbellard         str = "The object does not support aggregation";
1591d14ffa9Sbellard         break;
1601d14ffa9Sbellard #endif
1611d14ffa9Sbellard #ifdef DSERR_NODRIVER
1621d14ffa9Sbellard     case DSERR_NODRIVER:
1631d14ffa9Sbellard         str = "No sound driver is available for use, or the given GUID is not a valid DirectSound device ID";
1641d14ffa9Sbellard         break;
1651d14ffa9Sbellard #endif
1661d14ffa9Sbellard #ifdef DSERR_NOINTERFACE
1671d14ffa9Sbellard     case DSERR_NOINTERFACE:
1681d14ffa9Sbellard         str = "The requested COM interface is not available";
1691d14ffa9Sbellard         break;
1701d14ffa9Sbellard #endif
1711d14ffa9Sbellard #ifdef DSERR_OBJECTNOTFOUND
1721d14ffa9Sbellard     case DSERR_OBJECTNOTFOUND:
1731d14ffa9Sbellard         str = "The requested object was not found";
1741d14ffa9Sbellard         break;
1751d14ffa9Sbellard #endif
1761d14ffa9Sbellard #ifdef DSERR_OTHERAPPHASPRIO
1771d14ffa9Sbellard     case DSERR_OTHERAPPHASPRIO:
1781d14ffa9Sbellard         str = "Another application has a higher priority level, preventing this call from succeeding";
1791d14ffa9Sbellard         break;
1801d14ffa9Sbellard #endif
1811d14ffa9Sbellard #ifdef DSERR_OUTOFMEMORY
1821d14ffa9Sbellard     case DSERR_OUTOFMEMORY:
1831d14ffa9Sbellard         str = "The DirectSound subsystem could not allocate sufficient memory to complete the caller's request";
1841d14ffa9Sbellard         break;
1851d14ffa9Sbellard #endif
1861d14ffa9Sbellard #ifdef DSERR_PRIOLEVELNEEDED
1871d14ffa9Sbellard     case DSERR_PRIOLEVELNEEDED:
1881d14ffa9Sbellard         str = "A cooperative level of DSSCL_PRIORITY or higher is required";
1891d14ffa9Sbellard         break;
1901d14ffa9Sbellard #endif
1911d14ffa9Sbellard #ifdef DSERR_SENDLOOP
1921d14ffa9Sbellard     case DSERR_SENDLOOP:
1931d14ffa9Sbellard         str = "A circular loop of send effects was detected";
1941d14ffa9Sbellard         break;
1951d14ffa9Sbellard #endif
1961d14ffa9Sbellard #ifdef DSERR_UNINITIALIZED
1971d14ffa9Sbellard     case DSERR_UNINITIALIZED:
1981d14ffa9Sbellard         str = "The Initialize method has not been called or has not been called successfully before other methods were called";
1991d14ffa9Sbellard         break;
2001d14ffa9Sbellard #endif
2011d14ffa9Sbellard #ifdef DSERR_UNSUPPORTED
2021d14ffa9Sbellard     case DSERR_UNSUPPORTED:
2031d14ffa9Sbellard         str = "The function called is not supported at this time";
2041d14ffa9Sbellard         break;
2051d14ffa9Sbellard #endif
2061d14ffa9Sbellard     default:
2071d14ffa9Sbellard         AUD_log (AUDIO_CAP, "Reason: Unknown (HRESULT %#lx)\n", hr);
2081d14ffa9Sbellard         return;
2091d14ffa9Sbellard     }
2101d14ffa9Sbellard 
2111d14ffa9Sbellard     AUD_log (AUDIO_CAP, "Reason: %s\n", str);
2121d14ffa9Sbellard }
2131d14ffa9Sbellard 
2141d14ffa9Sbellard static void GCC_FMT_ATTR (2, 3) dsound_logerr (
2151d14ffa9Sbellard     HRESULT hr,
2161d14ffa9Sbellard     const char *fmt,
2171d14ffa9Sbellard     ...
2181d14ffa9Sbellard     )
2191d14ffa9Sbellard {
2201d14ffa9Sbellard     va_list ap;
2211d14ffa9Sbellard 
2221d14ffa9Sbellard     va_start (ap, fmt);
2231d14ffa9Sbellard     AUD_vlog (AUDIO_CAP, fmt, ap);
2241d14ffa9Sbellard     va_end (ap);
2251d14ffa9Sbellard 
2261d14ffa9Sbellard     dsound_log_hresult (hr);
2271d14ffa9Sbellard }
2281d14ffa9Sbellard 
2291d14ffa9Sbellard static void GCC_FMT_ATTR (3, 4) dsound_logerr2 (
2301d14ffa9Sbellard     HRESULT hr,
2311d14ffa9Sbellard     const char *typ,
2321d14ffa9Sbellard     const char *fmt,
2331d14ffa9Sbellard     ...
2341d14ffa9Sbellard     )
2351d14ffa9Sbellard {
2361d14ffa9Sbellard     va_list ap;
2371d14ffa9Sbellard 
238c0fe3827Sbellard     AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
2391d14ffa9Sbellard     va_start (ap, fmt);
2401d14ffa9Sbellard     AUD_vlog (AUDIO_CAP, fmt, ap);
2411d14ffa9Sbellard     va_end (ap);
2421d14ffa9Sbellard 
2431d14ffa9Sbellard     dsound_log_hresult (hr);
2441d14ffa9Sbellard }
2451d14ffa9Sbellard 
246*4a3b8b34SKővágó, Zoltán static uint64_t usecs_to_bytes(struct audio_pcm_info *info, uint32_t usecs)
2471d14ffa9Sbellard {
248*4a3b8b34SKővágó, Zoltán     return muldiv64(usecs, info->bytes_per_second, 1000000);
2491d14ffa9Sbellard }
2501d14ffa9Sbellard 
2511d14ffa9Sbellard #ifdef DEBUG_DSOUND
2521d14ffa9Sbellard static void print_wave_format (WAVEFORMATEX *wfx)
2531d14ffa9Sbellard {
2541d14ffa9Sbellard     dolog ("tag             = %d\n", wfx->wFormatTag);
2551d14ffa9Sbellard     dolog ("nChannels       = %d\n", wfx->nChannels);
2561d14ffa9Sbellard     dolog ("nSamplesPerSec  = %ld\n", wfx->nSamplesPerSec);
2571d14ffa9Sbellard     dolog ("nAvgBytesPerSec = %ld\n", wfx->nAvgBytesPerSec);
2581d14ffa9Sbellard     dolog ("nBlockAlign     = %d\n", wfx->nBlockAlign);
2591d14ffa9Sbellard     dolog ("wBitsPerSample  = %d\n", wfx->wBitsPerSample);
2601d14ffa9Sbellard     dolog ("cbSize          = %d\n", wfx->cbSize);
2611d14ffa9Sbellard }
2621d14ffa9Sbellard #endif
2631d14ffa9Sbellard 
264191e1f0aSKővágó, Zoltán static int dsound_restore_out (LPDIRECTSOUNDBUFFER dsb, dsound *s)
2651d14ffa9Sbellard {
2661d14ffa9Sbellard     HRESULT hr;
2671d14ffa9Sbellard 
2681d14ffa9Sbellard     hr = IDirectSoundBuffer_Restore (dsb);
2691d14ffa9Sbellard 
2702762955fSKővágó, Zoltán     if (hr != DS_OK) {
271c0fe3827Sbellard         dsound_logerr (hr, "Could not restore playback buffer\n");
2721d14ffa9Sbellard         return -1;
2731d14ffa9Sbellard     }
2742762955fSKővágó, Zoltán     return 0;
2751d14ffa9Sbellard }
2761d14ffa9Sbellard 
2771d14ffa9Sbellard #include "dsound_template.h"
2781d14ffa9Sbellard #define DSBTYPE_IN
2791d14ffa9Sbellard #include "dsound_template.h"
2801d14ffa9Sbellard #undef DSBTYPE_IN
2811d14ffa9Sbellard 
282191e1f0aSKővágó, Zoltán static int dsound_get_status_out (LPDIRECTSOUNDBUFFER dsb, DWORD *statusp,
283191e1f0aSKővágó, Zoltán                                   dsound *s)
2841d14ffa9Sbellard {
2851d14ffa9Sbellard     HRESULT hr;
2861d14ffa9Sbellard 
2871d14ffa9Sbellard     hr = IDirectSoundBuffer_GetStatus (dsb, statusp);
2881d14ffa9Sbellard     if (FAILED (hr)) {
289c0fe3827Sbellard         dsound_logerr (hr, "Could not get playback buffer status\n");
2901d14ffa9Sbellard         return -1;
2911d14ffa9Sbellard     }
2921d14ffa9Sbellard 
2931d14ffa9Sbellard     if (*statusp & DSERR_BUFFERLOST) {
2942762955fSKővágó, Zoltán         dsound_restore_out(dsb, s);
2951d14ffa9Sbellard         return -1;
2961d14ffa9Sbellard     }
2971d14ffa9Sbellard 
2981d14ffa9Sbellard     return 0;
2991d14ffa9Sbellard }
3001d14ffa9Sbellard 
3011d14ffa9Sbellard static int dsound_get_status_in (LPDIRECTSOUNDCAPTUREBUFFER dscb,
3021d14ffa9Sbellard                                  DWORD *statusp)
3031d14ffa9Sbellard {
3041d14ffa9Sbellard     HRESULT hr;
3051d14ffa9Sbellard 
3061d14ffa9Sbellard     hr = IDirectSoundCaptureBuffer_GetStatus (dscb, statusp);
3071d14ffa9Sbellard     if (FAILED (hr)) {
308c0fe3827Sbellard         dsound_logerr (hr, "Could not get capture buffer status\n");
3091d14ffa9Sbellard         return -1;
3101d14ffa9Sbellard     }
3111d14ffa9Sbellard 
3121d14ffa9Sbellard     return 0;
3131d14ffa9Sbellard }
3141d14ffa9Sbellard 
3151d14ffa9Sbellard static void dsound_write_sample (HWVoiceOut *hw, uint8_t *dst, int dst_len)
3161d14ffa9Sbellard {
3171d14ffa9Sbellard     int src_len1 = dst_len;
3181d14ffa9Sbellard     int src_len2 = 0;
3191d14ffa9Sbellard     int pos = hw->rpos + dst_len;
3201ea879e5Smalc     struct st_sample *src1 = hw->mix_buf + hw->rpos;
3211ea879e5Smalc     struct st_sample *src2 = NULL;
3221d14ffa9Sbellard 
3231d14ffa9Sbellard     if (pos > hw->samples) {
3241d14ffa9Sbellard         src_len1 = hw->samples - hw->rpos;
3251d14ffa9Sbellard         src2 = hw->mix_buf;
3261d14ffa9Sbellard         src_len2 = dst_len - src_len1;
3271d14ffa9Sbellard         pos = src_len2;
3281d14ffa9Sbellard     }
3291d14ffa9Sbellard 
3301d14ffa9Sbellard     if (src_len1) {
3311d14ffa9Sbellard         hw->clip (dst, src1, src_len1);
3321d14ffa9Sbellard     }
3331d14ffa9Sbellard 
3341d14ffa9Sbellard     if (src_len2) {
3351d14ffa9Sbellard         dst = advance (dst, src_len1 << hw->info.shift);
3361d14ffa9Sbellard         hw->clip (dst, src2, src_len2);
3371d14ffa9Sbellard     }
3381d14ffa9Sbellard 
3391d14ffa9Sbellard     hw->rpos = pos % hw->samples;
3401d14ffa9Sbellard }
3411d14ffa9Sbellard 
342191e1f0aSKővágó, Zoltán static void dsound_clear_sample (HWVoiceOut *hw, LPDIRECTSOUNDBUFFER dsb,
343191e1f0aSKővágó, Zoltán                                  dsound *s)
3441d14ffa9Sbellard {
3451d14ffa9Sbellard     int err;
3461d14ffa9Sbellard     LPVOID p1, p2;
3471d14ffa9Sbellard     DWORD blen1, blen2, len1, len2;
3481d14ffa9Sbellard 
3491d14ffa9Sbellard     err = dsound_lock_out (
3501d14ffa9Sbellard         dsb,
3511d14ffa9Sbellard         &hw->info,
3521d14ffa9Sbellard         0,
3531d14ffa9Sbellard         hw->samples << hw->info.shift,
3541d14ffa9Sbellard         &p1, &p2,
3551d14ffa9Sbellard         &blen1, &blen2,
356191e1f0aSKővágó, Zoltán         1,
357191e1f0aSKővágó, Zoltán         s
3581d14ffa9Sbellard         );
3591d14ffa9Sbellard     if (err) {
3601d14ffa9Sbellard         return;
3611d14ffa9Sbellard     }
3621d14ffa9Sbellard 
3631d14ffa9Sbellard     len1 = blen1 >> hw->info.shift;
3641d14ffa9Sbellard     len2 = blen2 >> hw->info.shift;
3651d14ffa9Sbellard 
3661d14ffa9Sbellard #ifdef DEBUG_DSOUND
3671d14ffa9Sbellard     dolog ("clear %p,%ld,%ld %p,%ld,%ld\n",
3681d14ffa9Sbellard            p1, blen1, len1,
3691d14ffa9Sbellard            p2, blen2, len2);
3701d14ffa9Sbellard #endif
3711d14ffa9Sbellard 
3721d14ffa9Sbellard     if (p1 && len1) {
3731d14ffa9Sbellard         audio_pcm_info_clear_buf (&hw->info, p1, len1);
3741d14ffa9Sbellard     }
3751d14ffa9Sbellard 
3761d14ffa9Sbellard     if (p2 && len2) {
3771d14ffa9Sbellard         audio_pcm_info_clear_buf (&hw->info, p2, len2);
3781d14ffa9Sbellard     }
3791d14ffa9Sbellard 
3801d14ffa9Sbellard     dsound_unlock_out (dsb, p1, p2, blen1, blen2);
3811d14ffa9Sbellard }
3821d14ffa9Sbellard 
3831d14ffa9Sbellard static int dsound_open (dsound *s)
3841d14ffa9Sbellard {
3851d14ffa9Sbellard     HRESULT hr;
3861d14ffa9Sbellard     HWND hwnd;
3871d14ffa9Sbellard 
3881d14ffa9Sbellard     hwnd = GetForegroundWindow ();
3891d14ffa9Sbellard     hr = IDirectSound_SetCooperativeLevel (
3901d14ffa9Sbellard         s->dsound,
3911d14ffa9Sbellard         hwnd,
3921d14ffa9Sbellard         DSSCL_PRIORITY
3931d14ffa9Sbellard         );
3941d14ffa9Sbellard 
3951d14ffa9Sbellard     if (FAILED (hr)) {
396c0fe3827Sbellard         dsound_logerr (hr, "Could not set cooperative level for window %p\n",
3971d14ffa9Sbellard                        hwnd);
3981d14ffa9Sbellard         return -1;
3991d14ffa9Sbellard     }
4001d14ffa9Sbellard 
4011d14ffa9Sbellard     return 0;
4021d14ffa9Sbellard }
4031d14ffa9Sbellard 
4041d14ffa9Sbellard static int dsound_ctl_out (HWVoiceOut *hw, int cmd, ...)
4051d14ffa9Sbellard {
4061d14ffa9Sbellard     HRESULT hr;
4071d14ffa9Sbellard     DWORD status;
4081d14ffa9Sbellard     DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
4091d14ffa9Sbellard     LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer;
410191e1f0aSKővágó, Zoltán     dsound *s = ds->s;
4111d14ffa9Sbellard 
4121d14ffa9Sbellard     if (!dsb) {
4131d14ffa9Sbellard         dolog ("Attempt to control voice without a buffer\n");
4141d14ffa9Sbellard         return 0;
4151d14ffa9Sbellard     }
4161d14ffa9Sbellard 
4171d14ffa9Sbellard     switch (cmd) {
4181d14ffa9Sbellard     case VOICE_ENABLE:
419191e1f0aSKővágó, Zoltán         if (dsound_get_status_out (dsb, &status, s)) {
4201d14ffa9Sbellard             return -1;
4211d14ffa9Sbellard         }
4221d14ffa9Sbellard 
4231d14ffa9Sbellard         if (status & DSBSTATUS_PLAYING) {
424c0fe3827Sbellard             dolog ("warning: Voice is already playing\n");
4251d14ffa9Sbellard             return 0;
4261d14ffa9Sbellard         }
4271d14ffa9Sbellard 
428191e1f0aSKővágó, Zoltán         dsound_clear_sample (hw, dsb, s);
4291d14ffa9Sbellard 
4301d14ffa9Sbellard         hr = IDirectSoundBuffer_Play (dsb, 0, 0, DSBPLAY_LOOPING);
4311d14ffa9Sbellard         if (FAILED (hr)) {
432c0fe3827Sbellard             dsound_logerr (hr, "Could not start playing buffer\n");
4331d14ffa9Sbellard             return -1;
4341d14ffa9Sbellard         }
4351d14ffa9Sbellard         break;
4361d14ffa9Sbellard 
4371d14ffa9Sbellard     case VOICE_DISABLE:
438191e1f0aSKővágó, Zoltán         if (dsound_get_status_out (dsb, &status, s)) {
4391d14ffa9Sbellard             return -1;
4401d14ffa9Sbellard         }
4411d14ffa9Sbellard 
4421d14ffa9Sbellard         if (status & DSBSTATUS_PLAYING) {
4431d14ffa9Sbellard             hr = IDirectSoundBuffer_Stop (dsb);
4441d14ffa9Sbellard             if (FAILED (hr)) {
445c0fe3827Sbellard                 dsound_logerr (hr, "Could not stop playing buffer\n");
4461d14ffa9Sbellard                 return -1;
4471d14ffa9Sbellard             }
4481d14ffa9Sbellard         }
4491d14ffa9Sbellard         else {
450c0fe3827Sbellard             dolog ("warning: Voice is not playing\n");
4511d14ffa9Sbellard         }
4521d14ffa9Sbellard         break;
4531d14ffa9Sbellard     }
4541d14ffa9Sbellard     return 0;
4551d14ffa9Sbellard }
4561d14ffa9Sbellard 
4571d14ffa9Sbellard static int dsound_write (SWVoiceOut *sw, void *buf, int len)
4581d14ffa9Sbellard {
4591d14ffa9Sbellard     return audio_pcm_sw_write (sw, buf, len);
4601d14ffa9Sbellard }
4611d14ffa9Sbellard 
462bdff253cSmalc static int dsound_run_out (HWVoiceOut *hw, int live)
4631d14ffa9Sbellard {
4641d14ffa9Sbellard     int err;
4651d14ffa9Sbellard     HRESULT hr;
4661d14ffa9Sbellard     DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
4671d14ffa9Sbellard     LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer;
468bdff253cSmalc     int len, hwshift;
4691d14ffa9Sbellard     DWORD blen1, blen2;
4701d14ffa9Sbellard     DWORD len1, len2;
4711d14ffa9Sbellard     DWORD decr;
4721d14ffa9Sbellard     DWORD wpos, ppos, old_pos;
4731d14ffa9Sbellard     LPVOID p1, p2;
474c0fe3827Sbellard     int bufsize;
475191e1f0aSKővágó, Zoltán     dsound *s = ds->s;
476*4a3b8b34SKővágó, Zoltán     AudiodevDsoundOptions *dso = &s->dev->u.dsound;
4771d14ffa9Sbellard 
4781d14ffa9Sbellard     if (!dsb) {
4791d14ffa9Sbellard         dolog ("Attempt to run empty with playback buffer\n");
4801d14ffa9Sbellard         return 0;
4811d14ffa9Sbellard     }
4821d14ffa9Sbellard 
4831d14ffa9Sbellard     hwshift = hw->info.shift;
484c0fe3827Sbellard     bufsize = hw->samples << hwshift;
4851d14ffa9Sbellard 
4861d14ffa9Sbellard     hr = IDirectSoundBuffer_GetCurrentPosition (
4871d14ffa9Sbellard         dsb,
4881d14ffa9Sbellard         &ppos,
4891d14ffa9Sbellard         ds->first_time ? &wpos : NULL
4901d14ffa9Sbellard         );
4911d14ffa9Sbellard     if (FAILED (hr)) {
492c0fe3827Sbellard         dsound_logerr (hr, "Could not get playback buffer position\n");
4931d14ffa9Sbellard         return 0;
4941d14ffa9Sbellard     }
4951d14ffa9Sbellard 
4961d14ffa9Sbellard     len = live << hwshift;
4971d14ffa9Sbellard 
4981d14ffa9Sbellard     if (ds->first_time) {
499*4a3b8b34SKővágó, Zoltán         if (dso->latency) {
500c0fe3827Sbellard             DWORD cur_blat;
5011d14ffa9Sbellard 
502c0fe3827Sbellard             cur_blat = audio_ring_dist (wpos, ppos, bufsize);
5031d14ffa9Sbellard             ds->first_time = 0;
5041d14ffa9Sbellard             old_pos = wpos;
5051d14ffa9Sbellard             old_pos +=
506*4a3b8b34SKővágó, Zoltán                 usecs_to_bytes(&hw->info, dso->latency) - cur_blat;
507c0fe3827Sbellard             old_pos %= bufsize;
5081d14ffa9Sbellard             old_pos &= ~hw->info.align;
5091d14ffa9Sbellard         }
5101d14ffa9Sbellard         else {
5111d14ffa9Sbellard             old_pos = wpos;
5121d14ffa9Sbellard         }
5131d14ffa9Sbellard #ifdef DEBUG_DSOUND
5141d14ffa9Sbellard         ds->played = 0;
5151d14ffa9Sbellard         ds->mixed = 0;
5161d14ffa9Sbellard #endif
5171d14ffa9Sbellard     }
5181d14ffa9Sbellard     else {
5191d14ffa9Sbellard         if (ds->old_pos == ppos) {
5201d14ffa9Sbellard #ifdef DEBUG_DSOUND
5211d14ffa9Sbellard             dolog ("old_pos == ppos\n");
5221d14ffa9Sbellard #endif
5231d14ffa9Sbellard             return 0;
5241d14ffa9Sbellard         }
5251d14ffa9Sbellard 
5261d14ffa9Sbellard #ifdef DEBUG_DSOUND
5271d14ffa9Sbellard         ds->played += audio_ring_dist (ds->old_pos, ppos, hw->bufsize);
5281d14ffa9Sbellard #endif
5291d14ffa9Sbellard         old_pos = ds->old_pos;
5301d14ffa9Sbellard     }
5311d14ffa9Sbellard 
5321d14ffa9Sbellard     if ((old_pos < ppos) && ((old_pos + len) > ppos)) {
5331d14ffa9Sbellard         len = ppos - old_pos;
5341d14ffa9Sbellard     }
5351d14ffa9Sbellard     else {
536c0fe3827Sbellard         if ((old_pos > ppos) && ((old_pos + len) > (ppos + bufsize))) {
537c0fe3827Sbellard             len = bufsize - old_pos + ppos;
5381d14ffa9Sbellard         }
5391d14ffa9Sbellard     }
5401d14ffa9Sbellard 
541470bcabdSAlistair Francis     if (audio_bug(__func__, len < 0 || len > bufsize)) {
542c0fe3827Sbellard         dolog ("len=%d bufsize=%d old_pos=%ld ppos=%ld\n",
543c0fe3827Sbellard                len, bufsize, old_pos, ppos);
5441d14ffa9Sbellard         return 0;
5451d14ffa9Sbellard     }
5461d14ffa9Sbellard 
5471d14ffa9Sbellard     len &= ~hw->info.align;
5481d14ffa9Sbellard     if (!len) {
5491d14ffa9Sbellard         return 0;
5501d14ffa9Sbellard     }
5511d14ffa9Sbellard 
5521d14ffa9Sbellard #ifdef DEBUG_DSOUND
5531d14ffa9Sbellard     ds->old_ppos = ppos;
5541d14ffa9Sbellard #endif
5551d14ffa9Sbellard     err = dsound_lock_out (
5561d14ffa9Sbellard         dsb,
5571d14ffa9Sbellard         &hw->info,
5581d14ffa9Sbellard         old_pos,
5591d14ffa9Sbellard         len,
5601d14ffa9Sbellard         &p1, &p2,
5611d14ffa9Sbellard         &blen1, &blen2,
562191e1f0aSKővágó, Zoltán         0,
563191e1f0aSKővágó, Zoltán         s
5641d14ffa9Sbellard         );
5651d14ffa9Sbellard     if (err) {
5661d14ffa9Sbellard         return 0;
5671d14ffa9Sbellard     }
5681d14ffa9Sbellard 
5691d14ffa9Sbellard     len1 = blen1 >> hwshift;
5701d14ffa9Sbellard     len2 = blen2 >> hwshift;
5711d14ffa9Sbellard     decr = len1 + len2;
5721d14ffa9Sbellard 
5731d14ffa9Sbellard     if (p1 && len1) {
5741d14ffa9Sbellard         dsound_write_sample (hw, p1, len1);
5751d14ffa9Sbellard     }
5761d14ffa9Sbellard 
5771d14ffa9Sbellard     if (p2 && len2) {
5781d14ffa9Sbellard         dsound_write_sample (hw, p2, len2);
5791d14ffa9Sbellard     }
5801d14ffa9Sbellard 
5811d14ffa9Sbellard     dsound_unlock_out (dsb, p1, p2, blen1, blen2);
582c0fe3827Sbellard     ds->old_pos = (old_pos + (decr << hwshift)) % bufsize;
5831d14ffa9Sbellard 
5841d14ffa9Sbellard #ifdef DEBUG_DSOUND
5851d14ffa9Sbellard     ds->mixed += decr << hwshift;
5861d14ffa9Sbellard 
5871d14ffa9Sbellard     dolog ("played %lu mixed %lu diff %ld sec %f\n",
5881d14ffa9Sbellard            ds->played,
5891d14ffa9Sbellard            ds->mixed,
5901d14ffa9Sbellard            ds->mixed - ds->played,
5911d14ffa9Sbellard            abs (ds->mixed - ds->played) / (double) hw->info.bytes_per_second);
5921d14ffa9Sbellard #endif
5931d14ffa9Sbellard     return decr;
5941d14ffa9Sbellard }
5951d14ffa9Sbellard 
5961d14ffa9Sbellard static int dsound_ctl_in (HWVoiceIn *hw, int cmd, ...)
5971d14ffa9Sbellard {
5981d14ffa9Sbellard     HRESULT hr;
5991d14ffa9Sbellard     DWORD status;
6001d14ffa9Sbellard     DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
6011d14ffa9Sbellard     LPDIRECTSOUNDCAPTUREBUFFER dscb = ds->dsound_capture_buffer;
6021d14ffa9Sbellard 
6031d14ffa9Sbellard     if (!dscb) {
6041d14ffa9Sbellard         dolog ("Attempt to control capture voice without a buffer\n");
6051d14ffa9Sbellard         return -1;
6061d14ffa9Sbellard     }
6071d14ffa9Sbellard 
6081d14ffa9Sbellard     switch (cmd) {
6091d14ffa9Sbellard     case VOICE_ENABLE:
6101d14ffa9Sbellard         if (dsound_get_status_in (dscb, &status)) {
6111d14ffa9Sbellard             return -1;
6121d14ffa9Sbellard         }
6131d14ffa9Sbellard 
6141d14ffa9Sbellard         if (status & DSCBSTATUS_CAPTURING) {
615c0fe3827Sbellard             dolog ("warning: Voice is already capturing\n");
6161d14ffa9Sbellard             return 0;
6171d14ffa9Sbellard         }
6181d14ffa9Sbellard 
6191d14ffa9Sbellard         /* clear ?? */
6201d14ffa9Sbellard 
6211d14ffa9Sbellard         hr = IDirectSoundCaptureBuffer_Start (dscb, DSCBSTART_LOOPING);
6221d14ffa9Sbellard         if (FAILED (hr)) {
623c0fe3827Sbellard             dsound_logerr (hr, "Could not start capturing\n");
6241d14ffa9Sbellard             return -1;
6251d14ffa9Sbellard         }
6261d14ffa9Sbellard         break;
6271d14ffa9Sbellard 
6281d14ffa9Sbellard     case VOICE_DISABLE:
6291d14ffa9Sbellard         if (dsound_get_status_in (dscb, &status)) {
6301d14ffa9Sbellard             return -1;
6311d14ffa9Sbellard         }
6321d14ffa9Sbellard 
6331d14ffa9Sbellard         if (status & DSCBSTATUS_CAPTURING) {
6341d14ffa9Sbellard             hr = IDirectSoundCaptureBuffer_Stop (dscb);
6351d14ffa9Sbellard             if (FAILED (hr)) {
636c0fe3827Sbellard                 dsound_logerr (hr, "Could not stop capturing\n");
6371d14ffa9Sbellard                 return -1;
6381d14ffa9Sbellard             }
6391d14ffa9Sbellard         }
6401d14ffa9Sbellard         else {
641c0fe3827Sbellard             dolog ("warning: Voice is not capturing\n");
6421d14ffa9Sbellard         }
6431d14ffa9Sbellard         break;
6441d14ffa9Sbellard     }
6451d14ffa9Sbellard     return 0;
6461d14ffa9Sbellard }
6471d14ffa9Sbellard 
6481d14ffa9Sbellard static int dsound_read (SWVoiceIn *sw, void *buf, int len)
6491d14ffa9Sbellard {
6501d14ffa9Sbellard     return audio_pcm_sw_read (sw, buf, len);
6511d14ffa9Sbellard }
6521d14ffa9Sbellard 
6531d14ffa9Sbellard static int dsound_run_in (HWVoiceIn *hw)
6541d14ffa9Sbellard {
6551d14ffa9Sbellard     int err;
6561d14ffa9Sbellard     HRESULT hr;
6571d14ffa9Sbellard     DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
6581d14ffa9Sbellard     LPDIRECTSOUNDCAPTUREBUFFER dscb = ds->dsound_capture_buffer;
6591d14ffa9Sbellard     int live, len, dead;
6601d14ffa9Sbellard     DWORD blen1, blen2;
6611d14ffa9Sbellard     DWORD len1, len2;
6621d14ffa9Sbellard     DWORD decr;
6631d14ffa9Sbellard     DWORD cpos, rpos;
6641d14ffa9Sbellard     LPVOID p1, p2;
6651d14ffa9Sbellard     int hwshift;
666191e1f0aSKővágó, Zoltán     dsound *s = ds->s;
6671d14ffa9Sbellard 
6681d14ffa9Sbellard     if (!dscb) {
6691d14ffa9Sbellard         dolog ("Attempt to run without capture buffer\n");
6701d14ffa9Sbellard         return 0;
6711d14ffa9Sbellard     }
6721d14ffa9Sbellard 
6731d14ffa9Sbellard     hwshift = hw->info.shift;
6741d14ffa9Sbellard 
6751d14ffa9Sbellard     live = audio_pcm_hw_get_live_in (hw);
6761d14ffa9Sbellard     dead = hw->samples - live;
6771d14ffa9Sbellard     if (!dead) {
6781d14ffa9Sbellard         return 0;
6791d14ffa9Sbellard     }
6801d14ffa9Sbellard 
6811d14ffa9Sbellard     hr = IDirectSoundCaptureBuffer_GetCurrentPosition (
6821d14ffa9Sbellard         dscb,
6831d14ffa9Sbellard         &cpos,
6841d14ffa9Sbellard         ds->first_time ? &rpos : NULL
6851d14ffa9Sbellard         );
6861d14ffa9Sbellard     if (FAILED (hr)) {
687c0fe3827Sbellard         dsound_logerr (hr, "Could not get capture buffer position\n");
6881d14ffa9Sbellard         return 0;
6891d14ffa9Sbellard     }
6901d14ffa9Sbellard 
6911d14ffa9Sbellard     if (ds->first_time) {
6921d14ffa9Sbellard         ds->first_time = 0;
6931d14ffa9Sbellard         if (rpos & hw->info.align) {
694c0fe3827Sbellard             ldebug ("warning: Misaligned capture read position %ld(%d)\n",
6951d14ffa9Sbellard                     rpos, hw->info.align);
6961d14ffa9Sbellard         }
6971d14ffa9Sbellard         hw->wpos = rpos >> hwshift;
6981d14ffa9Sbellard     }
6991d14ffa9Sbellard 
7001d14ffa9Sbellard     if (cpos & hw->info.align) {
701c0fe3827Sbellard         ldebug ("warning: Misaligned capture position %ld(%d)\n",
7021d14ffa9Sbellard                 cpos, hw->info.align);
7031d14ffa9Sbellard     }
7041d14ffa9Sbellard     cpos >>= hwshift;
7051d14ffa9Sbellard 
7061d14ffa9Sbellard     len = audio_ring_dist (cpos, hw->wpos, hw->samples);
7071d14ffa9Sbellard     if (!len) {
7081d14ffa9Sbellard         return 0;
7091d14ffa9Sbellard     }
7101d14ffa9Sbellard     len = audio_MIN (len, dead);
7111d14ffa9Sbellard 
7121d14ffa9Sbellard     err = dsound_lock_in (
7131d14ffa9Sbellard         dscb,
7141d14ffa9Sbellard         &hw->info,
7151d14ffa9Sbellard         hw->wpos << hwshift,
7161d14ffa9Sbellard         len << hwshift,
7171d14ffa9Sbellard         &p1,
7181d14ffa9Sbellard         &p2,
7191d14ffa9Sbellard         &blen1,
7201d14ffa9Sbellard         &blen2,
721191e1f0aSKővágó, Zoltán         0,
722191e1f0aSKővágó, Zoltán         s
7231d14ffa9Sbellard         );
7241d14ffa9Sbellard     if (err) {
7251d14ffa9Sbellard         return 0;
7261d14ffa9Sbellard     }
7271d14ffa9Sbellard 
7281d14ffa9Sbellard     len1 = blen1 >> hwshift;
7291d14ffa9Sbellard     len2 = blen2 >> hwshift;
7301d14ffa9Sbellard     decr = len1 + len2;
7311d14ffa9Sbellard 
7321d14ffa9Sbellard     if (p1 && len1) {
73300e07679SMichael Walle         hw->conv (hw->conv_buf + hw->wpos, p1, len1);
7341d14ffa9Sbellard     }
7351d14ffa9Sbellard 
7361d14ffa9Sbellard     if (p2 && len2) {
73700e07679SMichael Walle         hw->conv (hw->conv_buf, p2, len2);
7381d14ffa9Sbellard     }
7391d14ffa9Sbellard 
7401d14ffa9Sbellard     dsound_unlock_in (dscb, p1, p2, blen1, blen2);
7411d14ffa9Sbellard     hw->wpos = (hw->wpos + decr) % hw->samples;
7421d14ffa9Sbellard     return decr;
7431d14ffa9Sbellard }
7441d14ffa9Sbellard 
7451d14ffa9Sbellard static void dsound_audio_fini (void *opaque)
7461d14ffa9Sbellard {
7471d14ffa9Sbellard     HRESULT hr;
7481d14ffa9Sbellard     dsound *s = opaque;
7491d14ffa9Sbellard 
7501d14ffa9Sbellard     if (!s->dsound) {
751191e1f0aSKővágó, Zoltán         g_free(s);
7521d14ffa9Sbellard         return;
7531d14ffa9Sbellard     }
7541d14ffa9Sbellard 
7551d14ffa9Sbellard     hr = IDirectSound_Release (s->dsound);
7561d14ffa9Sbellard     if (FAILED (hr)) {
757c0fe3827Sbellard         dsound_logerr (hr, "Could not release DirectSound\n");
7581d14ffa9Sbellard     }
7591d14ffa9Sbellard     s->dsound = NULL;
7601d14ffa9Sbellard 
7611d14ffa9Sbellard     if (!s->dsound_capture) {
762191e1f0aSKővágó, Zoltán         g_free(s);
7631d14ffa9Sbellard         return;
7641d14ffa9Sbellard     }
7651d14ffa9Sbellard 
7661d14ffa9Sbellard     hr = IDirectSoundCapture_Release (s->dsound_capture);
7671d14ffa9Sbellard     if (FAILED (hr)) {
768c0fe3827Sbellard         dsound_logerr (hr, "Could not release DirectSoundCapture\n");
7691d14ffa9Sbellard     }
7701d14ffa9Sbellard     s->dsound_capture = NULL;
771191e1f0aSKővágó, Zoltán 
772191e1f0aSKővágó, Zoltán     g_free(s);
7731d14ffa9Sbellard }
7741d14ffa9Sbellard 
77571830221SKővágó, Zoltán static void *dsound_audio_init(Audiodev *dev)
7761d14ffa9Sbellard {
7771d14ffa9Sbellard     int err;
7781d14ffa9Sbellard     HRESULT hr;
779191e1f0aSKővágó, Zoltán     dsound *s = g_malloc0(sizeof(dsound));
780*4a3b8b34SKővágó, Zoltán     AudiodevDsoundOptions *dso;
7811d14ffa9Sbellard 
782*4a3b8b34SKővágó, Zoltán     assert(dev->driver == AUDIODEV_DRIVER_DSOUND);
783*4a3b8b34SKővágó, Zoltán     s->dev = dev;
784*4a3b8b34SKővágó, Zoltán     dso = &dev->u.dsound;
785*4a3b8b34SKővágó, Zoltán 
786*4a3b8b34SKővágó, Zoltán     if (!dso->has_latency) {
787*4a3b8b34SKővágó, Zoltán         dso->has_latency = true;
788*4a3b8b34SKővágó, Zoltán         dso->latency = 10000; /* 10 ms */
789*4a3b8b34SKővágó, Zoltán     }
790*4a3b8b34SKővágó, Zoltán 
7911d14ffa9Sbellard     hr = CoInitialize (NULL);
7921d14ffa9Sbellard     if (FAILED (hr)) {
793c0fe3827Sbellard         dsound_logerr (hr, "Could not initialize COM\n");
794191e1f0aSKővágó, Zoltán         g_free(s);
7951d14ffa9Sbellard         return NULL;
7961d14ffa9Sbellard     }
7971d14ffa9Sbellard 
7981d14ffa9Sbellard     hr = CoCreateInstance (
7991d14ffa9Sbellard         &CLSID_DirectSound,
8001d14ffa9Sbellard         NULL,
8011d14ffa9Sbellard         CLSCTX_ALL,
8021d14ffa9Sbellard         &IID_IDirectSound,
8031d14ffa9Sbellard         (void **) &s->dsound
8041d14ffa9Sbellard         );
8051d14ffa9Sbellard     if (FAILED (hr)) {
806c0fe3827Sbellard         dsound_logerr (hr, "Could not create DirectSound instance\n");
807191e1f0aSKővágó, Zoltán         g_free(s);
8081d14ffa9Sbellard         return NULL;
8091d14ffa9Sbellard     }
8101d14ffa9Sbellard 
8111d14ffa9Sbellard     hr = IDirectSound_Initialize (s->dsound, NULL);
8121d14ffa9Sbellard     if (FAILED (hr)) {
813c0fe3827Sbellard         dsound_logerr (hr, "Could not initialize DirectSound\n");
8148ead62cfSbellard 
8158ead62cfSbellard         hr = IDirectSound_Release (s->dsound);
8168ead62cfSbellard         if (FAILED (hr)) {
8178ead62cfSbellard             dsound_logerr (hr, "Could not release DirectSound\n");
8188ead62cfSbellard         }
819191e1f0aSKővágó, Zoltán         g_free(s);
8201d14ffa9Sbellard         return NULL;
8211d14ffa9Sbellard     }
8221d14ffa9Sbellard 
8231d14ffa9Sbellard     hr = CoCreateInstance (
8241d14ffa9Sbellard         &CLSID_DirectSoundCapture,
8251d14ffa9Sbellard         NULL,
8261d14ffa9Sbellard         CLSCTX_ALL,
8271d14ffa9Sbellard         &IID_IDirectSoundCapture,
8281d14ffa9Sbellard         (void **) &s->dsound_capture
8291d14ffa9Sbellard         );
8301d14ffa9Sbellard     if (FAILED (hr)) {
831c0fe3827Sbellard         dsound_logerr (hr, "Could not create DirectSoundCapture instance\n");
8321d14ffa9Sbellard     }
8331d14ffa9Sbellard     else {
8341d14ffa9Sbellard         hr = IDirectSoundCapture_Initialize (s->dsound_capture, NULL);
8351d14ffa9Sbellard         if (FAILED (hr)) {
836c0fe3827Sbellard             dsound_logerr (hr, "Could not initialize DirectSoundCapture\n");
8371d14ffa9Sbellard 
8381d14ffa9Sbellard             hr = IDirectSoundCapture_Release (s->dsound_capture);
8391d14ffa9Sbellard             if (FAILED (hr)) {
840c0fe3827Sbellard                 dsound_logerr (hr, "Could not release DirectSoundCapture\n");
8411d14ffa9Sbellard             }
8421d14ffa9Sbellard             s->dsound_capture = NULL;
8431d14ffa9Sbellard         }
8441d14ffa9Sbellard     }
8451d14ffa9Sbellard 
8461d14ffa9Sbellard     err = dsound_open (s);
8471d14ffa9Sbellard     if (err) {
8481d14ffa9Sbellard         dsound_audio_fini (s);
8491d14ffa9Sbellard         return NULL;
8501d14ffa9Sbellard     }
8511d14ffa9Sbellard 
8521d14ffa9Sbellard     return s;
8531d14ffa9Sbellard }
8541d14ffa9Sbellard 
85535f4b58cSblueswir1 static struct audio_pcm_ops dsound_pcm_ops = {
8561dd3e4d1SJuan Quintela     .init_out = dsound_init_out,
8571dd3e4d1SJuan Quintela     .fini_out = dsound_fini_out,
8581dd3e4d1SJuan Quintela     .run_out  = dsound_run_out,
8591dd3e4d1SJuan Quintela     .write    = dsound_write,
8601dd3e4d1SJuan Quintela     .ctl_out  = dsound_ctl_out,
8611d14ffa9Sbellard 
8621dd3e4d1SJuan Quintela     .init_in  = dsound_init_in,
8631dd3e4d1SJuan Quintela     .fini_in  = dsound_fini_in,
8641dd3e4d1SJuan Quintela     .run_in   = dsound_run_in,
8651dd3e4d1SJuan Quintela     .read     = dsound_read,
8661dd3e4d1SJuan Quintela     .ctl_in   = dsound_ctl_in
8671d14ffa9Sbellard };
8681d14ffa9Sbellard 
869d3893a39SGerd Hoffmann static struct audio_driver dsound_audio_driver = {
870bee37f32SJuan Quintela     .name           = "dsound",
871bee37f32SJuan Quintela     .descr          = "DirectSound http://wikipedia.org/wiki/DirectSound",
872bee37f32SJuan Quintela     .init           = dsound_audio_init,
873bee37f32SJuan Quintela     .fini           = dsound_audio_fini,
874bee37f32SJuan Quintela     .pcm_ops        = &dsound_pcm_ops,
875bee37f32SJuan Quintela     .can_be_default = 1,
876bee37f32SJuan Quintela     .max_voices_out = INT_MAX,
877bee37f32SJuan Quintela     .max_voices_in  = 1,
878bee37f32SJuan Quintela     .voice_size_out = sizeof (DSoundVoiceOut),
87915c875a3SConsul     .voice_size_in  = sizeof (DSoundVoiceIn)
8801d14ffa9Sbellard };
881d3893a39SGerd Hoffmann 
882d3893a39SGerd Hoffmann static void register_audio_dsound(void)
883d3893a39SGerd Hoffmann {
884d3893a39SGerd Hoffmann     audio_driver_register(&dsound_audio_driver);
885d3893a39SGerd Hoffmann }
886d3893a39SGerd Hoffmann type_init(register_audio_dsound);
887