3 * Copyright 1998 Marcus Meissner
4 * Copyright 1998 Rob Riggs
5 * Copyright 2000-2002 TransGaming Technologies, Inc.
6 * Copyright 2004 Robert Reif
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #define NONAMELESSSTRUCT
28 #define NONAMELESSUNION
38 #include "wine/debug.h"
40 #include "dsound_private.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
44 typedef struct IDirectSoundImpl {
45 IUnknown IUnknown_inner;
46 IDirectSound8 IDirectSound8_iface;
47 IUnknown *outer_unk; /* internal */
48 LONG ref, refds, numIfaces;
49 DirectSoundDevice *device;
53 const char * dumpCooperativeLevel(DWORD level)
55 #define LE(x) case x: return #x
60 LE(DSSCL_WRITEPRIMARY);
63 return wine_dbg_sprintf("Unknown(%08x)", level);
66 static void _dump_DSCAPS(DWORD xmask) {
71 #define FE(x) { x, #x },
72 FE(DSCAPS_PRIMARYMONO)
73 FE(DSCAPS_PRIMARYSTEREO)
74 FE(DSCAPS_PRIMARY8BIT)
75 FE(DSCAPS_PRIMARY16BIT)
76 FE(DSCAPS_CONTINUOUSRATE)
79 FE(DSCAPS_SECONDARYMONO)
80 FE(DSCAPS_SECONDARYSTEREO)
81 FE(DSCAPS_SECONDARY8BIT)
82 FE(DSCAPS_SECONDARY16BIT)
87 for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
88 if ((flags[i].mask & xmask) == flags[i].mask)
89 TRACE("%s ",flags[i].name);
92 static void _dump_DSBCAPS(DWORD xmask) {
97 #define FE(x) { x, #x },
98 FE(DSBCAPS_PRIMARYBUFFER)
100 FE(DSBCAPS_LOCHARDWARE)
101 FE(DSBCAPS_LOCSOFTWARE)
103 FE(DSBCAPS_CTRLFREQUENCY)
105 FE(DSBCAPS_CTRLVOLUME)
106 FE(DSBCAPS_CTRLPOSITIONNOTIFY)
107 FE(DSBCAPS_STICKYFOCUS)
108 FE(DSBCAPS_GLOBALFOCUS)
109 FE(DSBCAPS_GETCURRENTPOSITION2)
110 FE(DSBCAPS_MUTE3DATMAXDISTANCE)
115 for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
116 if ((flags[i].mask & xmask) == flags[i].mask)
117 TRACE("%s ",flags[i].name);
120 static void directsound_destroy(IDirectSoundImpl *This)
123 DirectSoundDevice_Release(This->device);
124 HeapFree(GetProcessHeap(),0,This);
125 TRACE("(%p) released\n", This);
128 /*******************************************************************************
129 * IUnknown Implementation for DirectSound
131 static inline IDirectSoundImpl *impl_from_IUnknown(IUnknown *iface)
133 return CONTAINING_RECORD(iface, IDirectSoundImpl, IUnknown_inner);
136 static HRESULT WINAPI IUnknownImpl_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
138 IDirectSoundImpl *This = impl_from_IUnknown(iface);
140 TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
143 WARN("invalid parameter\n");
148 if (IsEqualIID(riid, &IID_IUnknown))
149 *ppv = &This->IUnknown_inner;
150 else if (IsEqualIID(riid, &IID_IDirectSound) ||
151 (IsEqualIID(riid, &IID_IDirectSound8) && This->has_ds8))
152 *ppv = &This->IDirectSound8_iface;
154 WARN("unknown IID %s\n", debugstr_guid(riid));
155 return E_NOINTERFACE;
158 IUnknown_AddRef((IUnknown*)*ppv);
162 static ULONG WINAPI IUnknownImpl_AddRef(IUnknown *iface)
164 IDirectSoundImpl *This = impl_from_IUnknown(iface);
165 ULONG ref = InterlockedIncrement(&This->ref);
167 TRACE("(%p) ref=%d\n", This, ref);
170 InterlockedIncrement(&This->numIfaces);
175 static ULONG WINAPI IUnknownImpl_Release(IUnknown *iface)
177 IDirectSoundImpl *This = impl_from_IUnknown(iface);
178 ULONG ref = InterlockedDecrement(&This->ref);
180 TRACE("(%p) ref=%d\n", This, ref);
182 if (!ref && !InterlockedDecrement(&This->numIfaces))
183 directsound_destroy(This);
188 static const IUnknownVtbl unk_vtbl =
190 IUnknownImpl_QueryInterface,
195 /*******************************************************************************
196 * IDirectSound and IDirectSound8 Implementation
198 static inline IDirectSoundImpl *impl_from_IDirectSound8(IDirectSound8 *iface)
200 return CONTAINING_RECORD(iface, IDirectSoundImpl, IDirectSound8_iface);
203 static HRESULT WINAPI IDirectSound8Impl_QueryInterface(IDirectSound8 *iface, REFIID riid,
206 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
207 TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
208 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
211 static ULONG WINAPI IDirectSound8Impl_AddRef(IDirectSound8 *iface)
213 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
214 ULONG ref = InterlockedIncrement(&This->refds);
216 TRACE("(%p) refds=%d\n", This, ref);
219 InterlockedIncrement(&This->numIfaces);
224 static ULONG WINAPI IDirectSound8Impl_Release(IDirectSound8 *iface)
226 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
227 ULONG ref = InterlockedDecrement(&(This->refds));
229 TRACE("(%p) refds=%d\n", This, ref);
231 if (!ref && !InterlockedDecrement(&This->numIfaces))
232 directsound_destroy(This);
237 static HRESULT WINAPI IDirectSound8Impl_CreateSoundBuffer(IDirectSound8 *iface,
238 const DSBUFFERDESC *dsbd, IDirectSoundBuffer **ppdsb, IUnknown *lpunk)
240 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
241 TRACE("(%p,%p,%p,%p)\n", This, dsbd, ppdsb, lpunk);
242 return DirectSoundDevice_CreateSoundBuffer(This->device, dsbd, ppdsb, lpunk, This->has_ds8);
245 static HRESULT WINAPI IDirectSound8Impl_GetCaps(IDirectSound8 *iface, DSCAPS *lpDSCaps)
247 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
248 TRACE("(%p,%p)\n", This, lpDSCaps);
249 return DirectSoundDevice_GetCaps(This->device, lpDSCaps);
252 static HRESULT WINAPI IDirectSound8Impl_DuplicateSoundBuffer(IDirectSound8 *iface,
253 IDirectSoundBuffer *psb, IDirectSoundBuffer **ppdsb)
255 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
256 TRACE("(%p,%p,%p)\n", This, psb, ppdsb);
257 return DirectSoundDevice_DuplicateSoundBuffer(This->device, psb, ppdsb);
260 static HRESULT WINAPI IDirectSound8Impl_SetCooperativeLevel(IDirectSound8 *iface, HWND hwnd,
263 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
264 TRACE("(%p,%p,%s)\n", This, hwnd, dumpCooperativeLevel(level));
265 return DirectSoundDevice_SetCooperativeLevel(This->device, hwnd, level);
268 static HRESULT WINAPI IDirectSound8Impl_Compact(IDirectSound8 *iface)
270 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
271 TRACE("(%p)\n", This);
272 return DirectSoundDevice_Compact(This->device);
275 static HRESULT WINAPI IDirectSound8Impl_GetSpeakerConfig(IDirectSound8 *iface,
276 DWORD *lpdwSpeakerConfig)
278 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
279 TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
280 return DirectSoundDevice_GetSpeakerConfig(This->device, lpdwSpeakerConfig);
283 static HRESULT WINAPI IDirectSound8Impl_SetSpeakerConfig(IDirectSound8 *iface, DWORD config)
285 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
286 TRACE("(%p,0x%08x)\n", This, config);
287 return DirectSoundDevice_SetSpeakerConfig(This->device, config);
290 static HRESULT WINAPI IDirectSound8Impl_Initialize(IDirectSound8 *iface, const GUID *lpcGuid)
292 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
293 TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
294 return DirectSoundDevice_Initialize(&This->device, lpcGuid);
297 static HRESULT WINAPI IDirectSound8Impl_VerifyCertification(IDirectSound8 *iface,
300 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
301 TRACE("(%p, %p)\n", This, pdwCertified);
302 return DirectSoundDevice_VerifyCertification(This->device, pdwCertified);
305 static const IDirectSound8Vtbl ds8_vtbl =
307 IDirectSound8Impl_QueryInterface,
308 IDirectSound8Impl_AddRef,
309 IDirectSound8Impl_Release,
310 IDirectSound8Impl_CreateSoundBuffer,
311 IDirectSound8Impl_GetCaps,
312 IDirectSound8Impl_DuplicateSoundBuffer,
313 IDirectSound8Impl_SetCooperativeLevel,
314 IDirectSound8Impl_Compact,
315 IDirectSound8Impl_GetSpeakerConfig,
316 IDirectSound8Impl_SetSpeakerConfig,
317 IDirectSound8Impl_Initialize,
318 IDirectSound8Impl_VerifyCertification
321 HRESULT IDirectSoundImpl_Create(IUnknown *outer_unk, REFIID riid, void **ppv, BOOL has_ds8)
323 IDirectSoundImpl *obj;
326 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
329 obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*obj));
331 WARN("out of memory\n");
332 return DSERR_OUTOFMEMORY;
335 setup_dsound_options();
337 obj->IUnknown_inner.lpVtbl = &unk_vtbl;
338 obj->IDirectSound8_iface.lpVtbl = &ds8_vtbl;
343 obj->has_ds8 = has_ds8;
345 /* COM aggregation supported only internally */
347 obj->outer_unk = outer_unk;
349 obj->outer_unk = &obj->IUnknown_inner;
351 hr = IUnknown_QueryInterface(&obj->IUnknown_inner, riid, ppv);
352 IUnknown_Release(&obj->IUnknown_inner);
357 HRESULT DSOUND_Create(REFIID riid, void **ppv)
359 return IDirectSoundImpl_Create(NULL, riid, ppv, FALSE);
362 HRESULT DSOUND_Create8(REFIID riid, void **ppv)
364 return IDirectSoundImpl_Create(NULL, riid, ppv, TRUE);
367 /*******************************************************************************
368 * DirectSoundCreate (DSOUND.1)
370 * Creates and initializes a DirectSound interface.
373 * lpcGUID [I] Address of the GUID that identifies the sound device.
374 * ppDS [O] Address of a variable to receive the interface pointer.
375 * pUnkOuter [I] Must be NULL.
379 * Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
380 * DSERR_NODRIVER, DSERR_OUTOFMEMORY
382 HRESULT WINAPI DirectSoundCreate(
390 TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
393 WARN("invalid parameter: ppDS == NULL\n");
394 return DSERR_INVALIDPARAM;
397 if (pUnkOuter != NULL) {
398 WARN("invalid parameter: pUnkOuter != NULL\n");
400 return DSERR_INVALIDPARAM;
403 hr = DSOUND_Create(&IID_IDirectSound, (void **)&pDS);
405 hr = IDirectSound_Initialize(pDS, lpcGUID);
407 if (hr != DSERR_ALREADYINITIALIZED) {
408 IDirectSound_Release(pDS);
420 /*******************************************************************************
421 * DirectSoundCreate8 (DSOUND.11)
423 * Creates and initializes a DirectSound8 interface.
426 * lpcGUID [I] Address of the GUID that identifies the sound device.
427 * ppDS [O] Address of a variable to receive the interface pointer.
428 * pUnkOuter [I] Must be NULL.
432 * Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
433 * DSERR_NODRIVER, DSERR_OUTOFMEMORY
435 HRESULT WINAPI DirectSoundCreate8(
437 LPDIRECTSOUND8 *ppDS,
443 TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
446 WARN("invalid parameter: ppDS == NULL\n");
447 return DSERR_INVALIDPARAM;
450 if (pUnkOuter != NULL) {
451 WARN("invalid parameter: pUnkOuter != NULL\n");
453 return DSERR_INVALIDPARAM;
456 hr = DSOUND_Create8(&IID_IDirectSound8, (void **)&pDS);
458 hr = IDirectSound8_Initialize(pDS, lpcGUID);
460 if (hr != DSERR_ALREADYINITIALIZED) {
461 IDirectSound8_Release(pDS);
473 /*******************************************************************************
476 static HRESULT DirectSoundDevice_Create(DirectSoundDevice ** ppDevice)
478 DirectSoundDevice * device;
479 TRACE("(%p)\n", ppDevice);
481 /* Allocate memory */
482 device = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DirectSoundDevice));
483 if (device == NULL) {
484 WARN("out of memory\n");
485 return DSERR_OUTOFMEMORY;
489 device->priolevel = DSSCL_NORMAL;
490 device->state = STATE_STOPPED;
491 device->speaker_config = DSSPEAKER_COMBINED(DSSPEAKER_STEREO, DSSPEAKER_GEOMETRY_WIDE);
493 /* 3D listener initial parameters */
494 device->ds3dl.dwSize = sizeof(DS3DLISTENER);
495 device->ds3dl.vPosition.x = 0.0;
496 device->ds3dl.vPosition.y = 0.0;
497 device->ds3dl.vPosition.z = 0.0;
498 device->ds3dl.vVelocity.x = 0.0;
499 device->ds3dl.vVelocity.y = 0.0;
500 device->ds3dl.vVelocity.z = 0.0;
501 device->ds3dl.vOrientFront.x = 0.0;
502 device->ds3dl.vOrientFront.y = 0.0;
503 device->ds3dl.vOrientFront.z = 1.0;
504 device->ds3dl.vOrientTop.x = 0.0;
505 device->ds3dl.vOrientTop.y = 1.0;
506 device->ds3dl.vOrientTop.z = 0.0;
507 device->ds3dl.flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
508 device->ds3dl.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
509 device->ds3dl.flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
511 device->prebuf = ds_snd_queue_max;
512 device->guid = GUID_NULL;
514 /* Set default wave format (may need it for waveOutOpen) */
515 device->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(WAVEFORMATEX));
516 if (device->pwfx == NULL) {
517 WARN("out of memory\n");
518 HeapFree(GetProcessHeap(),0,device);
519 return DSERR_OUTOFMEMORY;
522 device->pwfx->wFormatTag = WAVE_FORMAT_PCM;
523 device->pwfx->nSamplesPerSec = ds_default_sample_rate;
524 device->pwfx->wBitsPerSample = ds_default_bits_per_sample;
525 device->pwfx->nChannels = 2;
526 device->pwfx->nBlockAlign = device->pwfx->wBitsPerSample * device->pwfx->nChannels / 8;
527 device->pwfx->nAvgBytesPerSec = device->pwfx->nSamplesPerSec * device->pwfx->nBlockAlign;
528 device->pwfx->cbSize = 0;
530 InitializeCriticalSection(&(device->mixlock));
531 device->mixlock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DirectSoundDevice.mixlock");
533 RtlInitializeResource(&(device->buffer_list_lock));
540 static ULONG DirectSoundDevice_AddRef(DirectSoundDevice * device)
542 ULONG ref = InterlockedIncrement(&(device->ref));
543 TRACE("(%p) ref was %d\n", device, ref - 1);
547 ULONG DirectSoundDevice_Release(DirectSoundDevice * device)
550 ULONG ref = InterlockedDecrement(&(device->ref));
551 TRACE("(%p) ref was %u\n", device, ref + 1);
554 timeKillEvent(device->timerID);
555 timeEndPeriod(DS_TIME_RES);
557 /* The kill event should have allowed the timer process to expire
558 * but try to grab the lock just in case. Can't hold lock because
559 * secondarybuffer_destroy also grabs the lock */
560 RtlAcquireResourceShared(&(device->buffer_list_lock), TRUE);
561 RtlReleaseResource(&(device->buffer_list_lock));
563 EnterCriticalSection(&DSOUND_renderers_lock);
564 list_remove(&device->entry);
565 LeaveCriticalSection(&DSOUND_renderers_lock);
567 /* It is allowed to release this object even when buffers are playing */
568 if (device->buffers) {
569 WARN("%d secondary buffers not released\n", device->nrofbuffers);
570 for( i=0;i<device->nrofbuffers;i++)
571 secondarybuffer_destroy(device->buffers[i]);
574 hr = DSOUND_PrimaryDestroy(device);
576 WARN("DSOUND_PrimaryDestroy failed\n");
579 IAudioClient_Release(device->client);
581 IAudioRenderClient_Release(device->render);
583 IAudioClock_Release(device->clock);
585 IAudioStreamVolume_Release(device->volume);
587 HeapFree(GetProcessHeap(), 0, device->tmp_buffer);
588 HeapFree(GetProcessHeap(), 0, device->mix_buffer);
589 HeapFree(GetProcessHeap(), 0, device->buffer);
590 RtlDeleteResource(&device->buffer_list_lock);
591 device->mixlock.DebugInfo->Spare[0] = 0;
592 DeleteCriticalSection(&device->mixlock);
593 HeapFree(GetProcessHeap(),0,device);
594 TRACE("(%p) released\n", device);
599 HRESULT DirectSoundDevice_GetCaps(
600 DirectSoundDevice * device,
603 TRACE("(%p,%p)\n",device,lpDSCaps);
605 if (device == NULL) {
606 WARN("not initialized\n");
607 return DSERR_UNINITIALIZED;
610 if (lpDSCaps == NULL) {
611 WARN("invalid parameter: lpDSCaps = NULL\n");
612 return DSERR_INVALIDPARAM;
615 /* check if there is enough room */
616 if (lpDSCaps->dwSize < sizeof(*lpDSCaps)) {
617 WARN("invalid parameter: lpDSCaps->dwSize = %d\n", lpDSCaps->dwSize);
618 return DSERR_INVALIDPARAM;
621 lpDSCaps->dwFlags = device->drvcaps.dwFlags;
622 if (TRACE_ON(dsound)) {
623 TRACE("(flags=0x%08x:\n",lpDSCaps->dwFlags);
624 _dump_DSCAPS(lpDSCaps->dwFlags);
627 lpDSCaps->dwMinSecondarySampleRate = device->drvcaps.dwMinSecondarySampleRate;
628 lpDSCaps->dwMaxSecondarySampleRate = device->drvcaps.dwMaxSecondarySampleRate;
629 lpDSCaps->dwPrimaryBuffers = device->drvcaps.dwPrimaryBuffers;
630 lpDSCaps->dwMaxHwMixingAllBuffers = device->drvcaps.dwMaxHwMixingAllBuffers;
631 lpDSCaps->dwMaxHwMixingStaticBuffers = device->drvcaps.dwMaxHwMixingStaticBuffers;
632 lpDSCaps->dwMaxHwMixingStreamingBuffers = device->drvcaps.dwMaxHwMixingStreamingBuffers;
633 lpDSCaps->dwFreeHwMixingAllBuffers = device->drvcaps.dwFreeHwMixingAllBuffers;
634 lpDSCaps->dwFreeHwMixingStaticBuffers = device->drvcaps.dwFreeHwMixingStaticBuffers;
635 lpDSCaps->dwFreeHwMixingStreamingBuffers = device->drvcaps.dwFreeHwMixingStreamingBuffers;
636 lpDSCaps->dwMaxHw3DAllBuffers = device->drvcaps.dwMaxHw3DAllBuffers;
637 lpDSCaps->dwMaxHw3DStaticBuffers = device->drvcaps.dwMaxHw3DStaticBuffers;
638 lpDSCaps->dwMaxHw3DStreamingBuffers = device->drvcaps.dwMaxHw3DStreamingBuffers;
639 lpDSCaps->dwFreeHw3DAllBuffers = device->drvcaps.dwFreeHw3DAllBuffers;
640 lpDSCaps->dwFreeHw3DStaticBuffers = device->drvcaps.dwFreeHw3DStaticBuffers;
641 lpDSCaps->dwFreeHw3DStreamingBuffers = device->drvcaps.dwFreeHw3DStreamingBuffers;
642 lpDSCaps->dwTotalHwMemBytes = device->drvcaps.dwTotalHwMemBytes;
643 lpDSCaps->dwFreeHwMemBytes = device->drvcaps.dwFreeHwMemBytes;
644 lpDSCaps->dwMaxContigFreeHwMemBytes = device->drvcaps.dwMaxContigFreeHwMemBytes;
645 lpDSCaps->dwUnlockTransferRateHwBuffers = device->drvcaps.dwUnlockTransferRateHwBuffers;
646 lpDSCaps->dwPlayCpuOverheadSwBuffers = device->drvcaps.dwPlayCpuOverheadSwBuffers;
651 BOOL DSOUND_check_supported(IAudioClient *client, DWORD rate,
652 DWORD depth, WORD channels)
654 WAVEFORMATEX fmt, *junk;
657 fmt.wFormatTag = WAVE_FORMAT_PCM;
658 fmt.nChannels = channels;
659 fmt.nSamplesPerSec = rate;
660 fmt.wBitsPerSample = depth;
661 fmt.nBlockAlign = (channels * depth) / 8;
662 fmt.nAvgBytesPerSec = rate * fmt.nBlockAlign;
665 hr = IAudioClient_IsFormatSupported(client, AUDCLNT_SHAREMODE_SHARED, &fmt, &junk);
672 UINT DSOUND_create_timer(LPTIMECALLBACK cb, DWORD_PTR user)
674 UINT triggertime = DS_TIME_DEL, res = DS_TIME_RES, id;
677 timeGetDevCaps(&time, sizeof(TIMECAPS));
678 TRACE("Minimum timer resolution: %u, max timer: %u\n", time.wPeriodMin, time.wPeriodMax);
679 if (triggertime < time.wPeriodMin)
680 triggertime = time.wPeriodMin;
681 if (res < time.wPeriodMin)
682 res = time.wPeriodMin;
683 if (timeBeginPeriod(res) == TIMERR_NOCANDO)
684 WARN("Could not set minimum resolution, don't expect sound\n");
685 id = timeSetEvent(triggertime, res, cb, user, TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
688 WARN("Timer not created! Retrying without TIME_KILL_SYNCHRONOUS\n");
689 id = timeSetEvent(triggertime, res, cb, user, TIME_PERIODIC);
691 ERR("Could not create timer, sound playback will not occur\n");
696 HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcGUID)
700 DirectSoundDevice *device;
703 TRACE("(%p,%s)\n",ppDevice,debugstr_guid(lpcGUID));
705 if (*ppDevice != NULL) {
706 WARN("already initialized\n");
707 return DSERR_ALREADYINITIALIZED;
710 /* Default device? */
711 if (!lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL))
712 lpcGUID = &DSDEVID_DefaultPlayback;
714 if(IsEqualGUID(lpcGUID, &DSDEVID_DefaultCapture) ||
715 IsEqualGUID(lpcGUID, &DSDEVID_DefaultVoiceCapture))
716 return DSERR_NODRIVER;
718 if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
719 WARN("invalid parameter: lpcGUID\n");
720 return DSERR_INVALIDPARAM;
723 hr = get_mmdevice(eRender, &devGUID, &mmdevice);
727 EnterCriticalSection(&DSOUND_renderers_lock);
729 LIST_FOR_EACH_ENTRY(device, &DSOUND_renderers, DirectSoundDevice, entry){
730 if(IsEqualGUID(&device->guid, &devGUID)){
731 IMMDevice_Release(mmdevice);
732 DirectSoundDevice_AddRef(device);
734 LeaveCriticalSection(&DSOUND_renderers_lock);
739 hr = DirectSoundDevice_Create(&device);
741 WARN("DirectSoundDevice_Create failed\n");
742 IMMDevice_Release(mmdevice);
743 LeaveCriticalSection(&DSOUND_renderers_lock);
747 device->mmdevice = mmdevice;
748 device->guid = devGUID;
750 hr = DSOUND_ReopenDevice(device, FALSE);
753 HeapFree(GetProcessHeap(), 0, device);
754 LeaveCriticalSection(&DSOUND_renderers_lock);
755 IMMDevice_Release(mmdevice);
756 WARN("DSOUND_ReopenDevice failed: %08x\n", hr);
760 ZeroMemory(&device->drvcaps, sizeof(device->drvcaps));
762 if(DSOUND_check_supported(device->client, 11025, 8, 1) ||
763 DSOUND_check_supported(device->client, 22050, 8, 1) ||
764 DSOUND_check_supported(device->client, 44100, 8, 1) ||
765 DSOUND_check_supported(device->client, 48000, 8, 1) ||
766 DSOUND_check_supported(device->client, 96000, 8, 1))
767 device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT | DSCAPS_PRIMARYMONO;
769 if(DSOUND_check_supported(device->client, 11025, 16, 1) ||
770 DSOUND_check_supported(device->client, 22050, 16, 1) ||
771 DSOUND_check_supported(device->client, 44100, 16, 1) ||
772 DSOUND_check_supported(device->client, 48000, 16, 1) ||
773 DSOUND_check_supported(device->client, 96000, 16, 1))
774 device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT | DSCAPS_PRIMARYMONO;
776 if(DSOUND_check_supported(device->client, 11025, 8, 2) ||
777 DSOUND_check_supported(device->client, 22050, 8, 2) ||
778 DSOUND_check_supported(device->client, 44100, 8, 2) ||
779 DSOUND_check_supported(device->client, 48000, 8, 2) ||
780 DSOUND_check_supported(device->client, 96000, 8, 2))
781 device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT | DSCAPS_PRIMARYSTEREO;
783 if(DSOUND_check_supported(device->client, 11025, 16, 2) ||
784 DSOUND_check_supported(device->client, 22050, 16, 2) ||
785 DSOUND_check_supported(device->client, 44100, 16, 2) ||
786 DSOUND_check_supported(device->client, 48000, 16, 2) ||
787 DSOUND_check_supported(device->client, 96000, 16, 2))
788 device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT | DSCAPS_PRIMARYSTEREO;
790 /* the dsound mixer supports all of the following */
791 device->drvcaps.dwFlags |= DSCAPS_SECONDARY8BIT | DSCAPS_SECONDARY16BIT;
792 device->drvcaps.dwFlags |= DSCAPS_SECONDARYMONO | DSCAPS_SECONDARYSTEREO;
793 device->drvcaps.dwFlags |= DSCAPS_CONTINUOUSRATE;
795 device->drvcaps.dwPrimaryBuffers = 1;
796 device->drvcaps.dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
797 device->drvcaps.dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
798 device->drvcaps.dwMaxHwMixingAllBuffers = 1;
799 device->drvcaps.dwMaxHwMixingStaticBuffers = 1;
800 device->drvcaps.dwMaxHwMixingStreamingBuffers = 1;
802 ZeroMemory(&device->volpan, sizeof(device->volpan));
804 hr = DSOUND_PrimaryCreate(device);
806 device->timerID = DSOUND_create_timer(DSOUND_timer, (DWORD_PTR)device);
808 WARN("DSOUND_PrimaryCreate failed: %08x\n", hr);
811 list_add_tail(&DSOUND_renderers, &device->entry);
813 LeaveCriticalSection(&DSOUND_renderers_lock);
818 HRESULT DirectSoundDevice_CreateSoundBuffer(
819 DirectSoundDevice * device,
820 LPCDSBUFFERDESC dsbd,
821 LPLPDIRECTSOUNDBUFFER ppdsb,
825 HRESULT hres = DS_OK;
826 TRACE("(%p,%p,%p,%p)\n",device,dsbd,ppdsb,lpunk);
828 if (device == NULL) {
829 WARN("not initialized\n");
830 return DSERR_UNINITIALIZED;
834 WARN("invalid parameter: dsbd == NULL\n");
835 return DSERR_INVALIDPARAM;
838 if (dsbd->dwSize != sizeof(DSBUFFERDESC) &&
839 dsbd->dwSize != sizeof(DSBUFFERDESC1)) {
840 WARN("invalid parameter: dsbd\n");
841 return DSERR_INVALIDPARAM;
845 WARN("invalid parameter: ppdsb == NULL\n");
846 return DSERR_INVALIDPARAM;
850 if (TRACE_ON(dsound)) {
851 TRACE("(structsize=%d)\n",dsbd->dwSize);
852 TRACE("(flags=0x%08x:\n",dsbd->dwFlags);
853 _dump_DSBCAPS(dsbd->dwFlags);
855 TRACE("(bufferbytes=%d)\n",dsbd->dwBufferBytes);
856 TRACE("(lpwfxFormat=%p)\n",dsbd->lpwfxFormat);
859 if (dsbd->dwFlags & DSBCAPS_LOCHARDWARE &&
860 !(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
861 TRACE("LOCHARDWARE is not supported, returning E_NOTIMPL\n");
865 if (dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) {
866 if (dsbd->lpwfxFormat != NULL) {
867 WARN("invalid parameter: dsbd->lpwfxFormat must be NULL for "
869 return DSERR_INVALIDPARAM;
872 if (device->primary) {
873 WARN("Primary Buffer already created\n");
874 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(device->primary));
875 *ppdsb = (LPDIRECTSOUNDBUFFER)(device->primary);
877 hres = primarybuffer_create(device, &device->primary, dsbd);
878 if (device->primary) {
879 *ppdsb = (IDirectSoundBuffer*)&device->primary->IDirectSoundBuffer8_iface;
880 device->primary->dsbd.dwFlags &= ~(DSBCAPS_LOCHARDWARE | DSBCAPS_LOCSOFTWARE);
881 device->primary->dsbd.dwFlags |= DSBCAPS_LOCSOFTWARE;
883 WARN("primarybuffer_create() failed\n");
886 IDirectSoundBufferImpl * dsb;
887 WAVEFORMATEXTENSIBLE *pwfxe;
889 if (dsbd->lpwfxFormat == NULL) {
890 WARN("invalid parameter: dsbd->lpwfxFormat can't be NULL for "
891 "secondary buffer\n");
892 return DSERR_INVALIDPARAM;
894 pwfxe = (WAVEFORMATEXTENSIBLE*)dsbd->lpwfxFormat;
896 if (pwfxe->Format.wBitsPerSample != 16 && pwfxe->Format.wBitsPerSample != 8 && pwfxe->Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE)
898 WARN("wBitsPerSample=%d needs a WAVEFORMATEXTENSIBLE\n", dsbd->lpwfxFormat->wBitsPerSample);
899 return DSERR_CONTROLUNAVAIL;
901 if (pwfxe->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE)
903 /* check if cbSize is at least 22 bytes */
904 if (pwfxe->Format.cbSize < (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)))
906 WARN("Too small a cbSize %u\n", pwfxe->Format.cbSize);
907 return DSERR_INVALIDPARAM;
910 /* cbSize should be 22 bytes, with one possible exception */
911 if (pwfxe->Format.cbSize > (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)) &&
912 !((IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) || IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) &&
913 pwfxe->Format.cbSize == sizeof(WAVEFORMATEXTENSIBLE)))
915 WARN("Too big a cbSize %u\n", pwfxe->Format.cbSize);
916 return DSERR_CONTROLUNAVAIL;
919 if ((!IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) && (!IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)))
921 if (!IsEqualGUID(&pwfxe->SubFormat, &GUID_NULL))
922 FIXME("SubFormat %s not supported right now.\n", debugstr_guid(&pwfxe->SubFormat));
923 return DSERR_INVALIDPARAM;
925 if (pwfxe->Samples.wValidBitsPerSample > dsbd->lpwfxFormat->wBitsPerSample)
927 WARN("Samples.wValidBitsPerSample(%d) > Format.wBitsPerSample (%d)\n", pwfxe->Samples.wValidBitsPerSample, pwfxe->Format.wBitsPerSample);
928 return DSERR_INVALIDPARAM;
930 if (pwfxe->Samples.wValidBitsPerSample && pwfxe->Samples.wValidBitsPerSample < dsbd->lpwfxFormat->wBitsPerSample)
932 FIXME("Non-packed formats not supported right now: %d/%d\n", pwfxe->Samples.wValidBitsPerSample, dsbd->lpwfxFormat->wBitsPerSample);
933 return DSERR_CONTROLUNAVAIL;
937 TRACE("(formattag=0x%04x,chans=%d,samplerate=%d,"
938 "bytespersec=%d,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
939 dsbd->lpwfxFormat->wFormatTag, dsbd->lpwfxFormat->nChannels,
940 dsbd->lpwfxFormat->nSamplesPerSec,
941 dsbd->lpwfxFormat->nAvgBytesPerSec,
942 dsbd->lpwfxFormat->nBlockAlign,
943 dsbd->lpwfxFormat->wBitsPerSample, dsbd->lpwfxFormat->cbSize);
945 if (from8 && (dsbd->dwFlags & DSBCAPS_CTRL3D) && (dsbd->lpwfxFormat->nChannels != 1)) {
946 WARN("invalid parameter: 3D buffer format must be mono\n");
947 return DSERR_INVALIDPARAM;
950 hres = IDirectSoundBufferImpl_Create(device, &dsb, dsbd);
952 *ppdsb = (IDirectSoundBuffer*)&dsb->IDirectSoundBuffer8_iface;
954 WARN("IDirectSoundBufferImpl_Create failed\n");
960 HRESULT DirectSoundDevice_DuplicateSoundBuffer(
961 DirectSoundDevice * device,
962 LPDIRECTSOUNDBUFFER psb,
963 LPLPDIRECTSOUNDBUFFER ppdsb)
965 HRESULT hres = DS_OK;
966 IDirectSoundBufferImpl* dsb;
967 TRACE("(%p,%p,%p)\n",device,psb,ppdsb);
969 if (device == NULL) {
970 WARN("not initialized\n");
971 return DSERR_UNINITIALIZED;
975 WARN("invalid parameter: psb == NULL\n");
976 return DSERR_INVALIDPARAM;
980 WARN("invalid parameter: ppdsb == NULL\n");
981 return DSERR_INVALIDPARAM;
984 /* make sure we have a secondary buffer */
985 if (psb == (IDirectSoundBuffer *)&device->primary->IDirectSoundBuffer8_iface) {
986 WARN("trying to duplicate primary buffer\n");
988 return DSERR_INVALIDCALL;
991 /* duplicate the actual buffer implementation */
992 hres = IDirectSoundBufferImpl_Duplicate(device, &dsb, (IDirectSoundBufferImpl*)psb);
994 *ppdsb = (IDirectSoundBuffer*)&dsb->IDirectSoundBuffer8_iface;
996 WARN("IDirectSoundBufferImpl_Duplicate failed\n");
1001 HRESULT DirectSoundDevice_SetCooperativeLevel(
1002 DirectSoundDevice * device,
1006 TRACE("(%p,%p,%s)\n",device,hwnd,dumpCooperativeLevel(level));
1008 if (device == NULL) {
1009 WARN("not initialized\n");
1010 return DSERR_UNINITIALIZED;
1013 if (level==DSSCL_PRIORITY || level==DSSCL_EXCLUSIVE) {
1014 WARN("level=%s not fully supported\n",
1015 level==DSSCL_PRIORITY ? "DSSCL_PRIORITY" : "DSSCL_EXCLUSIVE");
1018 device->priolevel = level;
1022 HRESULT DirectSoundDevice_Compact(
1023 DirectSoundDevice * device)
1025 TRACE("(%p)\n", device);
1027 if (device == NULL) {
1028 WARN("not initialized\n");
1029 return DSERR_UNINITIALIZED;
1032 if (device->priolevel < DSSCL_PRIORITY) {
1033 WARN("incorrect priority level\n");
1034 return DSERR_PRIOLEVELNEEDED;
1040 HRESULT DirectSoundDevice_GetSpeakerConfig(
1041 DirectSoundDevice * device,
1042 LPDWORD lpdwSpeakerConfig)
1044 TRACE("(%p, %p)\n", device, lpdwSpeakerConfig);
1046 if (device == NULL) {
1047 WARN("not initialized\n");
1048 return DSERR_UNINITIALIZED;
1051 if (lpdwSpeakerConfig == NULL) {
1052 WARN("invalid parameter: lpdwSpeakerConfig == NULL\n");
1053 return DSERR_INVALIDPARAM;
1056 WARN("not fully functional\n");
1057 *lpdwSpeakerConfig = device->speaker_config;
1061 HRESULT DirectSoundDevice_SetSpeakerConfig(
1062 DirectSoundDevice * device,
1065 TRACE("(%p,0x%08x)\n",device,config);
1067 if (device == NULL) {
1068 WARN("not initialized\n");
1069 return DSERR_UNINITIALIZED;
1072 device->speaker_config = config;
1073 WARN("not fully functional\n");
1077 HRESULT DirectSoundDevice_VerifyCertification(
1078 DirectSoundDevice * device,
1079 LPDWORD pdwCertified)
1081 TRACE("(%p, %p)\n",device,pdwCertified);
1083 if (device == NULL) {
1084 WARN("not initialized\n");
1085 return DSERR_UNINITIALIZED;
1088 if (device->drvcaps.dwFlags & DSCAPS_CERTIFIED)
1089 *pdwCertified = DS_CERTIFIED;
1091 *pdwCertified = DS_UNCERTIFIED;
1097 * Add secondary buffer to buffer list.
1098 * Gets exclusive access to buffer for writing.
1100 HRESULT DirectSoundDevice_AddBuffer(
1101 DirectSoundDevice * device,
1102 IDirectSoundBufferImpl * pDSB)
1104 IDirectSoundBufferImpl **newbuffers;
1107 TRACE("(%p, %p)\n", device, pDSB);
1109 RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
1111 if (device->buffers)
1112 newbuffers = HeapReAlloc(GetProcessHeap(),0,device->buffers,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
1114 newbuffers = HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
1117 device->buffers = newbuffers;
1118 device->buffers[device->nrofbuffers] = pDSB;
1119 device->nrofbuffers++;
1120 TRACE("buffer count is now %d\n", device->nrofbuffers);
1122 ERR("out of memory for buffer list! Current buffer count is %d\n", device->nrofbuffers);
1123 hr = DSERR_OUTOFMEMORY;
1126 RtlReleaseResource(&(device->buffer_list_lock));
1132 * Remove secondary buffer from buffer list.
1133 * Gets exclusive access to buffer for writing.
1135 HRESULT DirectSoundDevice_RemoveBuffer(
1136 DirectSoundDevice * device,
1137 IDirectSoundBufferImpl * pDSB)
1142 TRACE("(%p, %p)\n", device, pDSB);
1144 RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
1146 for (i = 0; i < device->nrofbuffers; i++)
1147 if (device->buffers[i] == pDSB)
1150 if (i < device->nrofbuffers) {
1151 /* Put the last buffer of the list in the (now empty) position */
1152 device->buffers[i] = device->buffers[device->nrofbuffers - 1];
1153 device->nrofbuffers--;
1154 device->buffers = HeapReAlloc(GetProcessHeap(),0,device->buffers,sizeof(LPDIRECTSOUNDBUFFER8)*device->nrofbuffers);
1155 TRACE("buffer count is now %d\n", device->nrofbuffers);
1158 if (device->nrofbuffers == 0) {
1159 HeapFree(GetProcessHeap(),0,device->buffers);
1160 device->buffers = NULL;
1163 RtlReleaseResource(&(device->buffer_list_lock));