dsound: Handle IDirectSound by the IDirectSound8 implementation.
[wine/multimedia.git] / dlls / dsound / dsound.c
blob3d748217f4824c63706e56dd8541d8e44c678cbf
1 /* DirectSound
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
23 #include <stdarg.h>
24 #include <stdio.h>
26 #define COBJMACROS
27 #define NONAMELESSSTRUCT
28 #define NONAMELESSUNION
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winuser.h"
32 #include "winternl.h"
33 #include "mmddk.h"
34 #include "wingdi.h"
35 #include "mmreg.h"
36 #include "ks.h"
37 #include "ksmedia.h"
38 #include "wine/debug.h"
39 #include "dsound.h"
40 #include "dsound_private.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
44 typedef struct IDirectSoundImpl {
45 IUnknown IUnknown_iface; /* Separate refcount, not for COM aggregation */
46 IDirectSound8 IDirectSound8_iface;
47 LONG ref, refds, numIfaces;
48 DirectSoundDevice *device;
49 BOOL has_ds8;
50 } IDirectSoundImpl;
52 const char * dumpCooperativeLevel(DWORD level)
54 #define LE(x) case x: return #x
55 switch (level) {
56 LE(DSSCL_NORMAL);
57 LE(DSSCL_PRIORITY);
58 LE(DSSCL_EXCLUSIVE);
59 LE(DSSCL_WRITEPRIMARY);
61 #undef LE
62 return wine_dbg_sprintf("Unknown(%08x)", level);
65 static void _dump_DSCAPS(DWORD xmask) {
66 struct {
67 DWORD mask;
68 const char *name;
69 } flags[] = {
70 #define FE(x) { x, #x },
71 FE(DSCAPS_PRIMARYMONO)
72 FE(DSCAPS_PRIMARYSTEREO)
73 FE(DSCAPS_PRIMARY8BIT)
74 FE(DSCAPS_PRIMARY16BIT)
75 FE(DSCAPS_CONTINUOUSRATE)
76 FE(DSCAPS_EMULDRIVER)
77 FE(DSCAPS_CERTIFIED)
78 FE(DSCAPS_SECONDARYMONO)
79 FE(DSCAPS_SECONDARYSTEREO)
80 FE(DSCAPS_SECONDARY8BIT)
81 FE(DSCAPS_SECONDARY16BIT)
82 #undef FE
84 unsigned int i;
86 for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
87 if ((flags[i].mask & xmask) == flags[i].mask)
88 TRACE("%s ",flags[i].name);
91 static void _dump_DSBCAPS(DWORD xmask) {
92 struct {
93 DWORD mask;
94 const char *name;
95 } flags[] = {
96 #define FE(x) { x, #x },
97 FE(DSBCAPS_PRIMARYBUFFER)
98 FE(DSBCAPS_STATIC)
99 FE(DSBCAPS_LOCHARDWARE)
100 FE(DSBCAPS_LOCSOFTWARE)
101 FE(DSBCAPS_CTRL3D)
102 FE(DSBCAPS_CTRLFREQUENCY)
103 FE(DSBCAPS_CTRLPAN)
104 FE(DSBCAPS_CTRLVOLUME)
105 FE(DSBCAPS_CTRLPOSITIONNOTIFY)
106 FE(DSBCAPS_STICKYFOCUS)
107 FE(DSBCAPS_GLOBALFOCUS)
108 FE(DSBCAPS_GETCURRENTPOSITION2)
109 FE(DSBCAPS_MUTE3DATMAXDISTANCE)
110 #undef FE
112 unsigned int i;
114 for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
115 if ((flags[i].mask & xmask) == flags[i].mask)
116 TRACE("%s ",flags[i].name);
119 /*******************************************************************************
120 * IDirectSoundImpl_DirectSound
122 static HRESULT DSOUND_QueryInterface(
123 LPDIRECTSOUND8 iface,
124 REFIID riid,
125 LPVOID * ppobj)
127 IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
128 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
130 if (ppobj == NULL) {
131 WARN("invalid parameter\n");
132 return E_INVALIDARG;
135 if (IsEqualIID(riid, &IID_IUnknown)) {
136 IUnknown_AddRef(&This->IUnknown_iface);
137 *ppobj = &This->IUnknown_iface;
138 return S_OK;
139 } else if (IsEqualIID(riid, &IID_IDirectSound) || (This->has_ds8 && IsEqualIID(riid, &IID_IDirectSound8))) {
140 IDirectSound8_AddRef(&This->IDirectSound8_iface);
141 *ppobj = &This->IDirectSound8_iface;
142 return S_OK;
145 *ppobj = NULL;
146 WARN("Unknown IID %s\n",debugstr_guid(riid));
147 return E_NOINTERFACE;
150 static void directsound_destroy(IDirectSoundImpl *This)
152 if (This->device)
153 DirectSoundDevice_Release(This->device);
154 HeapFree(GetProcessHeap(),0,This);
155 TRACE("(%p) released\n", This);
158 /*******************************************************************************
159 * IUnknown Implementation for DirectSound
161 static inline IDirectSoundImpl *impl_from_IUnknown(IUnknown *iface)
163 return CONTAINING_RECORD(iface, IDirectSoundImpl, IUnknown_iface);
166 static HRESULT WINAPI IUnknownImpl_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
168 IDirectSoundImpl *This = impl_from_IUnknown(iface);
169 TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
170 return DSOUND_QueryInterface((IDirectSound8 *)This, riid, ppv);
173 static ULONG WINAPI IUnknownImpl_AddRef(IUnknown *iface)
175 IDirectSoundImpl *This = impl_from_IUnknown(iface);
176 ULONG ref = InterlockedIncrement(&This->ref);
178 TRACE("(%p) ref=%d\n", This, ref);
180 if(ref == 1)
181 InterlockedIncrement(&This->numIfaces);
183 return ref;
186 static ULONG WINAPI IUnknownImpl_Release(IUnknown *iface)
188 IDirectSoundImpl *This = impl_from_IUnknown(iface);
189 ULONG ref = InterlockedDecrement(&This->ref);
191 TRACE("(%p) ref=%d\n", This, ref);
193 if (!ref && !InterlockedDecrement(&This->numIfaces))
194 directsound_destroy(This);
196 return ref;
199 static const IUnknownVtbl unk_vtbl =
201 IUnknownImpl_QueryInterface,
202 IUnknownImpl_AddRef,
203 IUnknownImpl_Release
206 /*******************************************************************************
207 * IDirectSound and IDirectSound8 Implementation
209 static inline IDirectSoundImpl *impl_from_IDirectSound8(IDirectSound8 *iface)
211 return CONTAINING_RECORD(iface, IDirectSoundImpl, IDirectSound8_iface);
214 static HRESULT WINAPI IDirectSound8Impl_QueryInterface(IDirectSound8 *iface, REFIID riid,
215 void **ppv)
217 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
218 TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
219 return IUnknown_QueryInterface(&This->IUnknown_iface, riid, ppv);
222 static ULONG WINAPI IDirectSound8Impl_AddRef(IDirectSound8 *iface)
224 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
225 ULONG ref = InterlockedIncrement(&This->refds);
227 TRACE("(%p) refds=%d\n", This, ref);
229 if(ref == 1)
230 InterlockedIncrement(&This->numIfaces);
232 return ref;
235 static ULONG WINAPI IDirectSound8Impl_Release(IDirectSound8 *iface)
237 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
238 ULONG ref = InterlockedDecrement(&(This->refds));
240 TRACE("(%p) refds=%d\n", This, ref);
242 if (!ref && !InterlockedDecrement(&This->numIfaces))
243 directsound_destroy(This);
245 return ref;
248 static HRESULT WINAPI IDirectSound8Impl_CreateSoundBuffer(IDirectSound8 *iface,
249 const DSBUFFERDESC *dsbd, IDirectSoundBuffer **ppdsb, IUnknown *lpunk)
251 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
252 TRACE("(%p,%p,%p,%p)\n", This, dsbd, ppdsb, lpunk);
253 return DirectSoundDevice_CreateSoundBuffer(This->device, dsbd, ppdsb, lpunk, This->has_ds8);
256 static HRESULT WINAPI IDirectSound8Impl_GetCaps(IDirectSound8 *iface, DSCAPS *lpDSCaps)
258 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
259 TRACE("(%p,%p)\n", This, lpDSCaps);
260 return DirectSoundDevice_GetCaps(This->device, lpDSCaps);
263 static HRESULT WINAPI IDirectSound8Impl_DuplicateSoundBuffer(IDirectSound8 *iface,
264 IDirectSoundBuffer *psb, IDirectSoundBuffer **ppdsb)
266 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
267 TRACE("(%p,%p,%p)\n", This, psb, ppdsb);
268 return DirectSoundDevice_DuplicateSoundBuffer(This->device, psb, ppdsb);
271 static HRESULT WINAPI IDirectSound8Impl_SetCooperativeLevel(IDirectSound8 *iface, HWND hwnd,
272 DWORD level)
274 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
275 TRACE("(%p,%p,%s)\n", This, hwnd, dumpCooperativeLevel(level));
276 return DirectSoundDevice_SetCooperativeLevel(This->device, hwnd, level);
279 static HRESULT WINAPI IDirectSound8Impl_Compact(IDirectSound8 *iface)
281 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
282 TRACE("(%p)\n", This);
283 return DirectSoundDevice_Compact(This->device);
286 static HRESULT WINAPI IDirectSound8Impl_GetSpeakerConfig(IDirectSound8 *iface,
287 DWORD *lpdwSpeakerConfig)
289 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
290 TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
291 return DirectSoundDevice_GetSpeakerConfig(This->device, lpdwSpeakerConfig);
294 static HRESULT WINAPI IDirectSound8Impl_SetSpeakerConfig(IDirectSound8 *iface, DWORD config)
296 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
297 TRACE("(%p,0x%08x)\n", This, config);
298 return DirectSoundDevice_SetSpeakerConfig(This->device, config);
301 static HRESULT WINAPI IDirectSound8Impl_Initialize(IDirectSound8 *iface, const GUID *lpcGuid)
303 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
304 TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
305 return DirectSoundDevice_Initialize(&This->device, lpcGuid);
308 static HRESULT WINAPI IDirectSound8Impl_VerifyCertification(IDirectSound8 *iface,
309 DWORD *pdwCertified)
311 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
312 TRACE("(%p, %p)\n", This, pdwCertified);
313 return DirectSoundDevice_VerifyCertification(This->device, pdwCertified);
316 static const IDirectSound8Vtbl ds8_vtbl =
318 IDirectSound8Impl_QueryInterface,
319 IDirectSound8Impl_AddRef,
320 IDirectSound8Impl_Release,
321 IDirectSound8Impl_CreateSoundBuffer,
322 IDirectSound8Impl_GetCaps,
323 IDirectSound8Impl_DuplicateSoundBuffer,
324 IDirectSound8Impl_SetCooperativeLevel,
325 IDirectSound8Impl_Compact,
326 IDirectSound8Impl_GetSpeakerConfig,
327 IDirectSound8Impl_SetSpeakerConfig,
328 IDirectSound8Impl_Initialize,
329 IDirectSound8Impl_VerifyCertification
332 static HRESULT IDirectSoundImpl_Create(REFIID riid, void **ppv, BOOL has_ds8)
334 IDirectSoundImpl *obj;
335 HRESULT hr;
337 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
339 *ppv = NULL;
340 obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*obj));
341 if (!obj) {
342 WARN("out of memory\n");
343 return DSERR_OUTOFMEMORY;
346 setup_dsound_options();
348 obj->IUnknown_iface.lpVtbl = &unk_vtbl;
349 obj->IDirectSound8_iface.lpVtbl = &ds8_vtbl;
350 obj->ref = 1;
351 obj->refds = 0;
352 obj->numIfaces = 1;
353 obj->device = NULL;
354 obj->has_ds8 = has_ds8;
356 hr = IUnknown_QueryInterface(&obj->IUnknown_iface, riid, ppv);
357 IUnknown_Release(&obj->IUnknown_iface);
359 return hr;
362 HRESULT DSOUND_Create(REFIID riid, void **ppv)
364 return IDirectSoundImpl_Create(riid, ppv, FALSE);
367 HRESULT DSOUND_Create8(REFIID riid, void **ppv)
369 return IDirectSoundImpl_Create(riid, ppv, TRUE);
372 /*******************************************************************************
373 * DirectSoundCreate (DSOUND.1)
375 * Creates and initializes a DirectSound interface.
377 * PARAMS
378 * lpcGUID [I] Address of the GUID that identifies the sound device.
379 * ppDS [O] Address of a variable to receive the interface pointer.
380 * pUnkOuter [I] Must be NULL.
382 * RETURNS
383 * Success: DS_OK
384 * Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
385 * DSERR_NODRIVER, DSERR_OUTOFMEMORY
387 HRESULT WINAPI DirectSoundCreate(
388 LPCGUID lpcGUID,
389 LPDIRECTSOUND *ppDS,
390 IUnknown *pUnkOuter)
392 HRESULT hr;
393 LPDIRECTSOUND pDS;
395 TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
397 if (ppDS == NULL) {
398 WARN("invalid parameter: ppDS == NULL\n");
399 return DSERR_INVALIDPARAM;
402 if (pUnkOuter != NULL) {
403 WARN("invalid parameter: pUnkOuter != NULL\n");
404 *ppDS = 0;
405 return DSERR_INVALIDPARAM;
408 hr = DSOUND_Create(&IID_IDirectSound, (void **)&pDS);
409 if (hr == DS_OK) {
410 hr = IDirectSound_Initialize(pDS, lpcGUID);
411 if (hr != DS_OK) {
412 if (hr != DSERR_ALREADYINITIALIZED) {
413 IDirectSound_Release(pDS);
414 pDS = 0;
415 } else
416 hr = DS_OK;
420 *ppDS = pDS;
422 return hr;
425 /*******************************************************************************
426 * DirectSoundCreate8 (DSOUND.11)
428 * Creates and initializes a DirectSound8 interface.
430 * PARAMS
431 * lpcGUID [I] Address of the GUID that identifies the sound device.
432 * ppDS [O] Address of a variable to receive the interface pointer.
433 * pUnkOuter [I] Must be NULL.
435 * RETURNS
436 * Success: DS_OK
437 * Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
438 * DSERR_NODRIVER, DSERR_OUTOFMEMORY
440 HRESULT WINAPI DirectSoundCreate8(
441 LPCGUID lpcGUID,
442 LPDIRECTSOUND8 *ppDS,
443 IUnknown *pUnkOuter)
445 HRESULT hr;
446 LPDIRECTSOUND8 pDS;
448 TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
450 if (ppDS == NULL) {
451 WARN("invalid parameter: ppDS == NULL\n");
452 return DSERR_INVALIDPARAM;
455 if (pUnkOuter != NULL) {
456 WARN("invalid parameter: pUnkOuter != NULL\n");
457 *ppDS = 0;
458 return DSERR_INVALIDPARAM;
461 hr = DSOUND_Create8(&IID_IDirectSound8, (void **)&pDS);
462 if (hr == DS_OK) {
463 hr = IDirectSound8_Initialize(pDS, lpcGUID);
464 if (hr != DS_OK) {
465 if (hr != DSERR_ALREADYINITIALIZED) {
466 IDirectSound8_Release(pDS);
467 pDS = 0;
468 } else
469 hr = DS_OK;
473 *ppDS = pDS;
475 return hr;
478 /*******************************************************************************
479 * DirectSoundDevice
481 static HRESULT DirectSoundDevice_Create(DirectSoundDevice ** ppDevice)
483 DirectSoundDevice * device;
484 TRACE("(%p)\n", ppDevice);
486 /* Allocate memory */
487 device = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DirectSoundDevice));
488 if (device == NULL) {
489 WARN("out of memory\n");
490 return DSERR_OUTOFMEMORY;
493 device->ref = 1;
494 device->priolevel = DSSCL_NORMAL;
495 device->state = STATE_STOPPED;
496 device->speaker_config = DSSPEAKER_COMBINED(DSSPEAKER_STEREO, DSSPEAKER_GEOMETRY_WIDE);
498 /* 3D listener initial parameters */
499 device->ds3dl.dwSize = sizeof(DS3DLISTENER);
500 device->ds3dl.vPosition.x = 0.0;
501 device->ds3dl.vPosition.y = 0.0;
502 device->ds3dl.vPosition.z = 0.0;
503 device->ds3dl.vVelocity.x = 0.0;
504 device->ds3dl.vVelocity.y = 0.0;
505 device->ds3dl.vVelocity.z = 0.0;
506 device->ds3dl.vOrientFront.x = 0.0;
507 device->ds3dl.vOrientFront.y = 0.0;
508 device->ds3dl.vOrientFront.z = 1.0;
509 device->ds3dl.vOrientTop.x = 0.0;
510 device->ds3dl.vOrientTop.y = 1.0;
511 device->ds3dl.vOrientTop.z = 0.0;
512 device->ds3dl.flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
513 device->ds3dl.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
514 device->ds3dl.flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
516 device->prebuf = ds_snd_queue_max;
517 device->guid = GUID_NULL;
519 /* Set default wave format (may need it for waveOutOpen) */
520 device->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(WAVEFORMATEX));
521 if (device->pwfx == NULL) {
522 WARN("out of memory\n");
523 HeapFree(GetProcessHeap(),0,device);
524 return DSERR_OUTOFMEMORY;
527 device->pwfx->wFormatTag = WAVE_FORMAT_PCM;
528 device->pwfx->nSamplesPerSec = ds_default_sample_rate;
529 device->pwfx->wBitsPerSample = ds_default_bits_per_sample;
530 device->pwfx->nChannels = 2;
531 device->pwfx->nBlockAlign = device->pwfx->wBitsPerSample * device->pwfx->nChannels / 8;
532 device->pwfx->nAvgBytesPerSec = device->pwfx->nSamplesPerSec * device->pwfx->nBlockAlign;
533 device->pwfx->cbSize = 0;
535 InitializeCriticalSection(&(device->mixlock));
536 device->mixlock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DirectSoundDevice.mixlock");
538 RtlInitializeResource(&(device->buffer_list_lock));
540 *ppDevice = device;
542 return DS_OK;
545 static ULONG DirectSoundDevice_AddRef(DirectSoundDevice * device)
547 ULONG ref = InterlockedIncrement(&(device->ref));
548 TRACE("(%p) ref was %d\n", device, ref - 1);
549 return ref;
552 ULONG DirectSoundDevice_Release(DirectSoundDevice * device)
554 HRESULT hr;
555 ULONG ref = InterlockedDecrement(&(device->ref));
556 TRACE("(%p) ref was %u\n", device, ref + 1);
557 if (!ref) {
558 int i;
559 timeKillEvent(device->timerID);
560 timeEndPeriod(DS_TIME_RES);
562 /* The kill event should have allowed the timer process to expire
563 * but try to grab the lock just in case. Can't hold lock because
564 * secondarybuffer_destroy also grabs the lock */
565 RtlAcquireResourceShared(&(device->buffer_list_lock), TRUE);
566 RtlReleaseResource(&(device->buffer_list_lock));
568 EnterCriticalSection(&DSOUND_renderers_lock);
569 list_remove(&device->entry);
570 LeaveCriticalSection(&DSOUND_renderers_lock);
572 /* It is allowed to release this object even when buffers are playing */
573 if (device->buffers) {
574 WARN("%d secondary buffers not released\n", device->nrofbuffers);
575 for( i=0;i<device->nrofbuffers;i++)
576 secondarybuffer_destroy(device->buffers[i]);
579 hr = DSOUND_PrimaryDestroy(device);
580 if (hr != DS_OK)
581 WARN("DSOUND_PrimaryDestroy failed\n");
583 if(device->client)
584 IAudioClient_Release(device->client);
585 if(device->render)
586 IAudioRenderClient_Release(device->render);
587 if(device->clock)
588 IAudioClock_Release(device->clock);
589 if(device->volume)
590 IAudioStreamVolume_Release(device->volume);
592 HeapFree(GetProcessHeap(), 0, device->tmp_buffer);
593 HeapFree(GetProcessHeap(), 0, device->mix_buffer);
594 HeapFree(GetProcessHeap(), 0, device->buffer);
595 RtlDeleteResource(&device->buffer_list_lock);
596 device->mixlock.DebugInfo->Spare[0] = 0;
597 DeleteCriticalSection(&device->mixlock);
598 HeapFree(GetProcessHeap(),0,device);
599 TRACE("(%p) released\n", device);
601 return ref;
604 HRESULT DirectSoundDevice_GetCaps(
605 DirectSoundDevice * device,
606 LPDSCAPS lpDSCaps)
608 TRACE("(%p,%p)\n",device,lpDSCaps);
610 if (device == NULL) {
611 WARN("not initialized\n");
612 return DSERR_UNINITIALIZED;
615 if (lpDSCaps == NULL) {
616 WARN("invalid parameter: lpDSCaps = NULL\n");
617 return DSERR_INVALIDPARAM;
620 /* check if there is enough room */
621 if (lpDSCaps->dwSize < sizeof(*lpDSCaps)) {
622 WARN("invalid parameter: lpDSCaps->dwSize = %d\n", lpDSCaps->dwSize);
623 return DSERR_INVALIDPARAM;
626 lpDSCaps->dwFlags = device->drvcaps.dwFlags;
627 if (TRACE_ON(dsound)) {
628 TRACE("(flags=0x%08x:\n",lpDSCaps->dwFlags);
629 _dump_DSCAPS(lpDSCaps->dwFlags);
630 TRACE(")\n");
632 lpDSCaps->dwMinSecondarySampleRate = device->drvcaps.dwMinSecondarySampleRate;
633 lpDSCaps->dwMaxSecondarySampleRate = device->drvcaps.dwMaxSecondarySampleRate;
634 lpDSCaps->dwPrimaryBuffers = device->drvcaps.dwPrimaryBuffers;
635 lpDSCaps->dwMaxHwMixingAllBuffers = device->drvcaps.dwMaxHwMixingAllBuffers;
636 lpDSCaps->dwMaxHwMixingStaticBuffers = device->drvcaps.dwMaxHwMixingStaticBuffers;
637 lpDSCaps->dwMaxHwMixingStreamingBuffers = device->drvcaps.dwMaxHwMixingStreamingBuffers;
638 lpDSCaps->dwFreeHwMixingAllBuffers = device->drvcaps.dwFreeHwMixingAllBuffers;
639 lpDSCaps->dwFreeHwMixingStaticBuffers = device->drvcaps.dwFreeHwMixingStaticBuffers;
640 lpDSCaps->dwFreeHwMixingStreamingBuffers = device->drvcaps.dwFreeHwMixingStreamingBuffers;
641 lpDSCaps->dwMaxHw3DAllBuffers = device->drvcaps.dwMaxHw3DAllBuffers;
642 lpDSCaps->dwMaxHw3DStaticBuffers = device->drvcaps.dwMaxHw3DStaticBuffers;
643 lpDSCaps->dwMaxHw3DStreamingBuffers = device->drvcaps.dwMaxHw3DStreamingBuffers;
644 lpDSCaps->dwFreeHw3DAllBuffers = device->drvcaps.dwFreeHw3DAllBuffers;
645 lpDSCaps->dwFreeHw3DStaticBuffers = device->drvcaps.dwFreeHw3DStaticBuffers;
646 lpDSCaps->dwFreeHw3DStreamingBuffers = device->drvcaps.dwFreeHw3DStreamingBuffers;
647 lpDSCaps->dwTotalHwMemBytes = device->drvcaps.dwTotalHwMemBytes;
648 lpDSCaps->dwFreeHwMemBytes = device->drvcaps.dwFreeHwMemBytes;
649 lpDSCaps->dwMaxContigFreeHwMemBytes = device->drvcaps.dwMaxContigFreeHwMemBytes;
650 lpDSCaps->dwUnlockTransferRateHwBuffers = device->drvcaps.dwUnlockTransferRateHwBuffers;
651 lpDSCaps->dwPlayCpuOverheadSwBuffers = device->drvcaps.dwPlayCpuOverheadSwBuffers;
653 return DS_OK;
656 BOOL DSOUND_check_supported(IAudioClient *client, DWORD rate,
657 DWORD depth, WORD channels)
659 WAVEFORMATEX fmt, *junk;
660 HRESULT hr;
662 fmt.wFormatTag = WAVE_FORMAT_PCM;
663 fmt.nChannels = channels;
664 fmt.nSamplesPerSec = rate;
665 fmt.wBitsPerSample = depth;
666 fmt.nBlockAlign = (channels * depth) / 8;
667 fmt.nAvgBytesPerSec = rate * fmt.nBlockAlign;
668 fmt.cbSize = 0;
670 hr = IAudioClient_IsFormatSupported(client, AUDCLNT_SHAREMODE_SHARED, &fmt, &junk);
671 if(SUCCEEDED(hr))
672 CoTaskMemFree(junk);
674 return hr == S_OK;
677 UINT DSOUND_create_timer(LPTIMECALLBACK cb, DWORD_PTR user)
679 UINT triggertime = DS_TIME_DEL, res = DS_TIME_RES, id;
680 TIMECAPS time;
682 timeGetDevCaps(&time, sizeof(TIMECAPS));
683 TRACE("Minimum timer resolution: %u, max timer: %u\n", time.wPeriodMin, time.wPeriodMax);
684 if (triggertime < time.wPeriodMin)
685 triggertime = time.wPeriodMin;
686 if (res < time.wPeriodMin)
687 res = time.wPeriodMin;
688 if (timeBeginPeriod(res) == TIMERR_NOCANDO)
689 WARN("Could not set minimum resolution, don't expect sound\n");
690 id = timeSetEvent(triggertime, res, cb, user, TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
691 if (!id)
693 WARN("Timer not created! Retrying without TIME_KILL_SYNCHRONOUS\n");
694 id = timeSetEvent(triggertime, res, cb, user, TIME_PERIODIC);
695 if (!id)
696 ERR("Could not create timer, sound playback will not occur\n");
698 return id;
701 HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcGUID)
703 HRESULT hr = DS_OK;
704 GUID devGUID;
705 DirectSoundDevice *device;
706 IMMDevice *mmdevice;
708 TRACE("(%p,%s)\n",ppDevice,debugstr_guid(lpcGUID));
710 if (*ppDevice != NULL) {
711 WARN("already initialized\n");
712 return DSERR_ALREADYINITIALIZED;
715 /* Default device? */
716 if (!lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL))
717 lpcGUID = &DSDEVID_DefaultPlayback;
719 if(IsEqualGUID(lpcGUID, &DSDEVID_DefaultCapture) ||
720 IsEqualGUID(lpcGUID, &DSDEVID_DefaultVoiceCapture))
721 return DSERR_NODRIVER;
723 if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
724 WARN("invalid parameter: lpcGUID\n");
725 return DSERR_INVALIDPARAM;
728 hr = get_mmdevice(eRender, &devGUID, &mmdevice);
729 if(FAILED(hr))
730 return hr;
732 EnterCriticalSection(&DSOUND_renderers_lock);
734 LIST_FOR_EACH_ENTRY(device, &DSOUND_renderers, DirectSoundDevice, entry){
735 if(IsEqualGUID(&device->guid, &devGUID)){
736 IMMDevice_Release(mmdevice);
737 DirectSoundDevice_AddRef(device);
738 *ppDevice = device;
739 LeaveCriticalSection(&DSOUND_renderers_lock);
740 return DS_OK;
744 hr = DirectSoundDevice_Create(&device);
745 if(FAILED(hr)){
746 WARN("DirectSoundDevice_Create failed\n");
747 IMMDevice_Release(mmdevice);
748 LeaveCriticalSection(&DSOUND_renderers_lock);
749 return hr;
752 device->mmdevice = mmdevice;
753 device->guid = devGUID;
755 hr = DSOUND_ReopenDevice(device, FALSE);
756 if (FAILED(hr))
758 HeapFree(GetProcessHeap(), 0, device);
759 LeaveCriticalSection(&DSOUND_renderers_lock);
760 IMMDevice_Release(mmdevice);
761 WARN("DSOUND_ReopenDevice failed: %08x\n", hr);
762 return hr;
765 ZeroMemory(&device->drvcaps, sizeof(device->drvcaps));
767 if(DSOUND_check_supported(device->client, 11025, 8, 1) ||
768 DSOUND_check_supported(device->client, 22050, 8, 1) ||
769 DSOUND_check_supported(device->client, 44100, 8, 1) ||
770 DSOUND_check_supported(device->client, 48000, 8, 1) ||
771 DSOUND_check_supported(device->client, 96000, 8, 1))
772 device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT | DSCAPS_PRIMARYMONO;
774 if(DSOUND_check_supported(device->client, 11025, 16, 1) ||
775 DSOUND_check_supported(device->client, 22050, 16, 1) ||
776 DSOUND_check_supported(device->client, 44100, 16, 1) ||
777 DSOUND_check_supported(device->client, 48000, 16, 1) ||
778 DSOUND_check_supported(device->client, 96000, 16, 1))
779 device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT | DSCAPS_PRIMARYMONO;
781 if(DSOUND_check_supported(device->client, 11025, 8, 2) ||
782 DSOUND_check_supported(device->client, 22050, 8, 2) ||
783 DSOUND_check_supported(device->client, 44100, 8, 2) ||
784 DSOUND_check_supported(device->client, 48000, 8, 2) ||
785 DSOUND_check_supported(device->client, 96000, 8, 2))
786 device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT | DSCAPS_PRIMARYSTEREO;
788 if(DSOUND_check_supported(device->client, 11025, 16, 2) ||
789 DSOUND_check_supported(device->client, 22050, 16, 2) ||
790 DSOUND_check_supported(device->client, 44100, 16, 2) ||
791 DSOUND_check_supported(device->client, 48000, 16, 2) ||
792 DSOUND_check_supported(device->client, 96000, 16, 2))
793 device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT | DSCAPS_PRIMARYSTEREO;
795 /* the dsound mixer supports all of the following */
796 device->drvcaps.dwFlags |= DSCAPS_SECONDARY8BIT | DSCAPS_SECONDARY16BIT;
797 device->drvcaps.dwFlags |= DSCAPS_SECONDARYMONO | DSCAPS_SECONDARYSTEREO;
798 device->drvcaps.dwFlags |= DSCAPS_CONTINUOUSRATE;
800 device->drvcaps.dwPrimaryBuffers = 1;
801 device->drvcaps.dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
802 device->drvcaps.dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
803 device->drvcaps.dwMaxHwMixingAllBuffers = 1;
804 device->drvcaps.dwMaxHwMixingStaticBuffers = 1;
805 device->drvcaps.dwMaxHwMixingStreamingBuffers = 1;
807 ZeroMemory(&device->volpan, sizeof(device->volpan));
809 hr = DSOUND_PrimaryCreate(device);
810 if (hr == DS_OK)
811 device->timerID = DSOUND_create_timer(DSOUND_timer, (DWORD_PTR)device);
812 else
813 WARN("DSOUND_PrimaryCreate failed: %08x\n", hr);
815 *ppDevice = device;
816 list_add_tail(&DSOUND_renderers, &device->entry);
818 LeaveCriticalSection(&DSOUND_renderers_lock);
820 return hr;
823 HRESULT DirectSoundDevice_CreateSoundBuffer(
824 DirectSoundDevice * device,
825 LPCDSBUFFERDESC dsbd,
826 LPLPDIRECTSOUNDBUFFER ppdsb,
827 LPUNKNOWN lpunk,
828 BOOL from8)
830 HRESULT hres = DS_OK;
831 TRACE("(%p,%p,%p,%p)\n",device,dsbd,ppdsb,lpunk);
833 if (device == NULL) {
834 WARN("not initialized\n");
835 return DSERR_UNINITIALIZED;
838 if (dsbd == NULL) {
839 WARN("invalid parameter: dsbd == NULL\n");
840 return DSERR_INVALIDPARAM;
843 if (dsbd->dwSize != sizeof(DSBUFFERDESC) &&
844 dsbd->dwSize != sizeof(DSBUFFERDESC1)) {
845 WARN("invalid parameter: dsbd\n");
846 return DSERR_INVALIDPARAM;
849 if (ppdsb == NULL) {
850 WARN("invalid parameter: ppdsb == NULL\n");
851 return DSERR_INVALIDPARAM;
853 *ppdsb = NULL;
855 if (TRACE_ON(dsound)) {
856 TRACE("(structsize=%d)\n",dsbd->dwSize);
857 TRACE("(flags=0x%08x:\n",dsbd->dwFlags);
858 _dump_DSBCAPS(dsbd->dwFlags);
859 TRACE(")\n");
860 TRACE("(bufferbytes=%d)\n",dsbd->dwBufferBytes);
861 TRACE("(lpwfxFormat=%p)\n",dsbd->lpwfxFormat);
864 if (dsbd->dwFlags & DSBCAPS_LOCHARDWARE &&
865 !(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
866 TRACE("LOCHARDWARE is not supported, returning E_NOTIMPL\n");
867 return E_NOTIMPL;
870 if (dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) {
871 if (dsbd->lpwfxFormat != NULL) {
872 WARN("invalid parameter: dsbd->lpwfxFormat must be NULL for "
873 "primary buffer\n");
874 return DSERR_INVALIDPARAM;
877 if (device->primary) {
878 WARN("Primary Buffer already created\n");
879 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(device->primary));
880 *ppdsb = (LPDIRECTSOUNDBUFFER)(device->primary);
881 } else {
882 hres = primarybuffer_create(device, &device->primary, dsbd);
883 if (device->primary) {
884 *ppdsb = (IDirectSoundBuffer*)&device->primary->IDirectSoundBuffer8_iface;
885 device->primary->dsbd.dwFlags &= ~(DSBCAPS_LOCHARDWARE | DSBCAPS_LOCSOFTWARE);
886 device->primary->dsbd.dwFlags |= DSBCAPS_LOCSOFTWARE;
887 } else
888 WARN("primarybuffer_create() failed\n");
890 } else {
891 IDirectSoundBufferImpl * dsb;
892 WAVEFORMATEXTENSIBLE *pwfxe;
894 if (dsbd->lpwfxFormat == NULL) {
895 WARN("invalid parameter: dsbd->lpwfxFormat can't be NULL for "
896 "secondary buffer\n");
897 return DSERR_INVALIDPARAM;
899 pwfxe = (WAVEFORMATEXTENSIBLE*)dsbd->lpwfxFormat;
901 if (pwfxe->Format.wBitsPerSample != 16 && pwfxe->Format.wBitsPerSample != 8 && pwfxe->Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE)
903 WARN("wBitsPerSample=%d needs a WAVEFORMATEXTENSIBLE\n", dsbd->lpwfxFormat->wBitsPerSample);
904 return DSERR_CONTROLUNAVAIL;
906 if (pwfxe->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE)
908 /* check if cbSize is at least 22 bytes */
909 if (pwfxe->Format.cbSize < (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)))
911 WARN("Too small a cbSize %u\n", pwfxe->Format.cbSize);
912 return DSERR_INVALIDPARAM;
915 /* cbSize should be 22 bytes, with one possible exception */
916 if (pwfxe->Format.cbSize > (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)) &&
917 !((IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) || IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) &&
918 pwfxe->Format.cbSize == sizeof(WAVEFORMATEXTENSIBLE)))
920 WARN("Too big a cbSize %u\n", pwfxe->Format.cbSize);
921 return DSERR_CONTROLUNAVAIL;
924 if ((!IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) && (!IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)))
926 if (!IsEqualGUID(&pwfxe->SubFormat, &GUID_NULL))
927 FIXME("SubFormat %s not supported right now.\n", debugstr_guid(&pwfxe->SubFormat));
928 return DSERR_INVALIDPARAM;
930 if (pwfxe->Samples.wValidBitsPerSample > dsbd->lpwfxFormat->wBitsPerSample)
932 WARN("Samples.wValidBitsPerSample(%d) > Format.wBitsPerSample (%d)\n", pwfxe->Samples.wValidBitsPerSample, pwfxe->Format.wBitsPerSample);
933 return DSERR_INVALIDPARAM;
935 if (pwfxe->Samples.wValidBitsPerSample && pwfxe->Samples.wValidBitsPerSample < dsbd->lpwfxFormat->wBitsPerSample)
937 FIXME("Non-packed formats not supported right now: %d/%d\n", pwfxe->Samples.wValidBitsPerSample, dsbd->lpwfxFormat->wBitsPerSample);
938 return DSERR_CONTROLUNAVAIL;
942 TRACE("(formattag=0x%04x,chans=%d,samplerate=%d,"
943 "bytespersec=%d,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
944 dsbd->lpwfxFormat->wFormatTag, dsbd->lpwfxFormat->nChannels,
945 dsbd->lpwfxFormat->nSamplesPerSec,
946 dsbd->lpwfxFormat->nAvgBytesPerSec,
947 dsbd->lpwfxFormat->nBlockAlign,
948 dsbd->lpwfxFormat->wBitsPerSample, dsbd->lpwfxFormat->cbSize);
950 if (from8 && (dsbd->dwFlags & DSBCAPS_CTRL3D) && (dsbd->lpwfxFormat->nChannels != 1)) {
951 WARN("invalid parameter: 3D buffer format must be mono\n");
952 return DSERR_INVALIDPARAM;
955 hres = IDirectSoundBufferImpl_Create(device, &dsb, dsbd);
956 if (dsb)
957 *ppdsb = (IDirectSoundBuffer*)&dsb->IDirectSoundBuffer8_iface;
958 else
959 WARN("IDirectSoundBufferImpl_Create failed\n");
962 return hres;
965 HRESULT DirectSoundDevice_DuplicateSoundBuffer(
966 DirectSoundDevice * device,
967 LPDIRECTSOUNDBUFFER psb,
968 LPLPDIRECTSOUNDBUFFER ppdsb)
970 HRESULT hres = DS_OK;
971 IDirectSoundBufferImpl* dsb;
972 TRACE("(%p,%p,%p)\n",device,psb,ppdsb);
974 if (device == NULL) {
975 WARN("not initialized\n");
976 return DSERR_UNINITIALIZED;
979 if (psb == NULL) {
980 WARN("invalid parameter: psb == NULL\n");
981 return DSERR_INVALIDPARAM;
984 if (ppdsb == NULL) {
985 WARN("invalid parameter: ppdsb == NULL\n");
986 return DSERR_INVALIDPARAM;
989 /* make sure we have a secondary buffer */
990 if (psb == (IDirectSoundBuffer *)&device->primary->IDirectSoundBuffer8_iface) {
991 WARN("trying to duplicate primary buffer\n");
992 *ppdsb = NULL;
993 return DSERR_INVALIDCALL;
996 /* duplicate the actual buffer implementation */
997 hres = IDirectSoundBufferImpl_Duplicate(device, &dsb, (IDirectSoundBufferImpl*)psb);
998 if (hres == DS_OK)
999 *ppdsb = (IDirectSoundBuffer*)&dsb->IDirectSoundBuffer8_iface;
1000 else
1001 WARN("IDirectSoundBufferImpl_Duplicate failed\n");
1003 return hres;
1006 HRESULT DirectSoundDevice_SetCooperativeLevel(
1007 DirectSoundDevice * device,
1008 HWND hwnd,
1009 DWORD level)
1011 TRACE("(%p,%p,%s)\n",device,hwnd,dumpCooperativeLevel(level));
1013 if (device == NULL) {
1014 WARN("not initialized\n");
1015 return DSERR_UNINITIALIZED;
1018 if (level==DSSCL_PRIORITY || level==DSSCL_EXCLUSIVE) {
1019 WARN("level=%s not fully supported\n",
1020 level==DSSCL_PRIORITY ? "DSSCL_PRIORITY" : "DSSCL_EXCLUSIVE");
1023 device->priolevel = level;
1024 return DS_OK;
1027 HRESULT DirectSoundDevice_Compact(
1028 DirectSoundDevice * device)
1030 TRACE("(%p)\n", device);
1032 if (device == NULL) {
1033 WARN("not initialized\n");
1034 return DSERR_UNINITIALIZED;
1037 if (device->priolevel < DSSCL_PRIORITY) {
1038 WARN("incorrect priority level\n");
1039 return DSERR_PRIOLEVELNEEDED;
1042 return DS_OK;
1045 HRESULT DirectSoundDevice_GetSpeakerConfig(
1046 DirectSoundDevice * device,
1047 LPDWORD lpdwSpeakerConfig)
1049 TRACE("(%p, %p)\n", device, lpdwSpeakerConfig);
1051 if (device == NULL) {
1052 WARN("not initialized\n");
1053 return DSERR_UNINITIALIZED;
1056 if (lpdwSpeakerConfig == NULL) {
1057 WARN("invalid parameter: lpdwSpeakerConfig == NULL\n");
1058 return DSERR_INVALIDPARAM;
1061 WARN("not fully functional\n");
1062 *lpdwSpeakerConfig = device->speaker_config;
1063 return DS_OK;
1066 HRESULT DirectSoundDevice_SetSpeakerConfig(
1067 DirectSoundDevice * device,
1068 DWORD config)
1070 TRACE("(%p,0x%08x)\n",device,config);
1072 if (device == NULL) {
1073 WARN("not initialized\n");
1074 return DSERR_UNINITIALIZED;
1077 device->speaker_config = config;
1078 WARN("not fully functional\n");
1079 return DS_OK;
1082 HRESULT DirectSoundDevice_VerifyCertification(
1083 DirectSoundDevice * device,
1084 LPDWORD pdwCertified)
1086 TRACE("(%p, %p)\n",device,pdwCertified);
1088 if (device == NULL) {
1089 WARN("not initialized\n");
1090 return DSERR_UNINITIALIZED;
1093 if (device->drvcaps.dwFlags & DSCAPS_CERTIFIED)
1094 *pdwCertified = DS_CERTIFIED;
1095 else
1096 *pdwCertified = DS_UNCERTIFIED;
1098 return DS_OK;
1102 * Add secondary buffer to buffer list.
1103 * Gets exclusive access to buffer for writing.
1105 HRESULT DirectSoundDevice_AddBuffer(
1106 DirectSoundDevice * device,
1107 IDirectSoundBufferImpl * pDSB)
1109 IDirectSoundBufferImpl **newbuffers;
1110 HRESULT hr = DS_OK;
1112 TRACE("(%p, %p)\n", device, pDSB);
1114 RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
1116 if (device->buffers)
1117 newbuffers = HeapReAlloc(GetProcessHeap(),0,device->buffers,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
1118 else
1119 newbuffers = HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
1121 if (newbuffers) {
1122 device->buffers = newbuffers;
1123 device->buffers[device->nrofbuffers] = pDSB;
1124 device->nrofbuffers++;
1125 TRACE("buffer count is now %d\n", device->nrofbuffers);
1126 } else {
1127 ERR("out of memory for buffer list! Current buffer count is %d\n", device->nrofbuffers);
1128 hr = DSERR_OUTOFMEMORY;
1131 RtlReleaseResource(&(device->buffer_list_lock));
1133 return hr;
1137 * Remove secondary buffer from buffer list.
1138 * Gets exclusive access to buffer for writing.
1140 HRESULT DirectSoundDevice_RemoveBuffer(
1141 DirectSoundDevice * device,
1142 IDirectSoundBufferImpl * pDSB)
1144 int i;
1145 HRESULT hr = DS_OK;
1147 TRACE("(%p, %p)\n", device, pDSB);
1149 RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
1151 for (i = 0; i < device->nrofbuffers; i++)
1152 if (device->buffers[i] == pDSB)
1153 break;
1155 if (i < device->nrofbuffers) {
1156 /* Put the last buffer of the list in the (now empty) position */
1157 device->buffers[i] = device->buffers[device->nrofbuffers - 1];
1158 device->nrofbuffers--;
1159 device->buffers = HeapReAlloc(GetProcessHeap(),0,device->buffers,sizeof(LPDIRECTSOUNDBUFFER8)*device->nrofbuffers);
1160 TRACE("buffer count is now %d\n", device->nrofbuffers);
1163 if (device->nrofbuffers == 0) {
1164 HeapFree(GetProcessHeap(),0,device->buffers);
1165 device->buffers = NULL;
1168 RtlReleaseResource(&(device->buffer_list_lock));
1170 return hr;