dsound-fixup-loop
[wine/multimedia.git] / dlls / dsound / dsound.c
blobfddc97a910367605201d3cc5d5a15a71d27d7916
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 static void directsound_destroy(IDirectSoundImpl *This)
121 if (This->device)
122 DirectSoundDevice_Release(This->device);
123 HeapFree(GetProcessHeap(),0,This);
124 TRACE("(%p) released\n", This);
127 /*******************************************************************************
128 * IUnknown Implementation for DirectSound
130 static inline IDirectSoundImpl *impl_from_IUnknown(IUnknown *iface)
132 return CONTAINING_RECORD(iface, IDirectSoundImpl, IUnknown_iface);
135 static HRESULT WINAPI IUnknownImpl_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
137 IDirectSoundImpl *This = impl_from_IUnknown(iface);
139 TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
141 if (!ppv) {
142 WARN("invalid parameter\n");
143 return E_INVALIDARG;
145 *ppv = NULL;
147 if (IsEqualIID(riid, &IID_IUnknown))
148 *ppv = &This->IUnknown_iface;
149 else if (IsEqualIID(riid, &IID_IDirectSound) ||
150 (IsEqualIID(riid, &IID_IDirectSound8) && This->has_ds8))
151 *ppv = &This->IDirectSound8_iface;
152 else {
153 WARN("unknown IID %s\n", debugstr_guid(riid));
154 return E_NOINTERFACE;
157 IUnknown_AddRef((IUnknown*)*ppv);
158 return S_OK;
161 static ULONG WINAPI IUnknownImpl_AddRef(IUnknown *iface)
163 IDirectSoundImpl *This = impl_from_IUnknown(iface);
164 ULONG ref = InterlockedIncrement(&This->ref);
166 TRACE("(%p) ref=%d\n", This, ref);
168 if(ref == 1)
169 InterlockedIncrement(&This->numIfaces);
171 return ref;
174 static ULONG WINAPI IUnknownImpl_Release(IUnknown *iface)
176 IDirectSoundImpl *This = impl_from_IUnknown(iface);
177 ULONG ref = InterlockedDecrement(&This->ref);
179 TRACE("(%p) ref=%d\n", This, ref);
181 if (!ref && !InterlockedDecrement(&This->numIfaces))
182 directsound_destroy(This);
184 return ref;
187 static const IUnknownVtbl unk_vtbl =
189 IUnknownImpl_QueryInterface,
190 IUnknownImpl_AddRef,
191 IUnknownImpl_Release
194 /*******************************************************************************
195 * IDirectSound and IDirectSound8 Implementation
197 static inline IDirectSoundImpl *impl_from_IDirectSound8(IDirectSound8 *iface)
199 return CONTAINING_RECORD(iface, IDirectSoundImpl, IDirectSound8_iface);
202 static HRESULT WINAPI IDirectSound8Impl_QueryInterface(IDirectSound8 *iface, REFIID riid,
203 void **ppv)
205 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
206 TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
207 return IUnknown_QueryInterface(&This->IUnknown_iface, riid, ppv);
210 static ULONG WINAPI IDirectSound8Impl_AddRef(IDirectSound8 *iface)
212 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
213 ULONG ref = InterlockedIncrement(&This->refds);
215 TRACE("(%p) refds=%d\n", This, ref);
217 if(ref == 1)
218 InterlockedIncrement(&This->numIfaces);
220 return ref;
223 static ULONG WINAPI IDirectSound8Impl_Release(IDirectSound8 *iface)
225 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
226 ULONG ref = InterlockedDecrement(&(This->refds));
228 TRACE("(%p) refds=%d\n", This, ref);
230 if (!ref && !InterlockedDecrement(&This->numIfaces))
231 directsound_destroy(This);
233 return ref;
236 static HRESULT WINAPI IDirectSound8Impl_CreateSoundBuffer(IDirectSound8 *iface,
237 const DSBUFFERDESC *dsbd, IDirectSoundBuffer **ppdsb, IUnknown *lpunk)
239 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
240 TRACE("(%p,%p,%p,%p)\n", This, dsbd, ppdsb, lpunk);
241 return DirectSoundDevice_CreateSoundBuffer(This->device, dsbd, ppdsb, lpunk, This->has_ds8);
244 static HRESULT WINAPI IDirectSound8Impl_GetCaps(IDirectSound8 *iface, DSCAPS *lpDSCaps)
246 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
247 TRACE("(%p,%p)\n", This, lpDSCaps);
248 return DirectSoundDevice_GetCaps(This->device, lpDSCaps);
251 static HRESULT WINAPI IDirectSound8Impl_DuplicateSoundBuffer(IDirectSound8 *iface,
252 IDirectSoundBuffer *psb, IDirectSoundBuffer **ppdsb)
254 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
255 TRACE("(%p,%p,%p)\n", This, psb, ppdsb);
256 return DirectSoundDevice_DuplicateSoundBuffer(This->device, psb, ppdsb);
259 static HRESULT WINAPI IDirectSound8Impl_SetCooperativeLevel(IDirectSound8 *iface, HWND hwnd,
260 DWORD level)
262 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
263 TRACE("(%p,%p,%s)\n", This, hwnd, dumpCooperativeLevel(level));
264 return DirectSoundDevice_SetCooperativeLevel(This->device, hwnd, level);
267 static HRESULT WINAPI IDirectSound8Impl_Compact(IDirectSound8 *iface)
269 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
270 TRACE("(%p)\n", This);
271 return DirectSoundDevice_Compact(This->device);
274 static HRESULT WINAPI IDirectSound8Impl_GetSpeakerConfig(IDirectSound8 *iface,
275 DWORD *lpdwSpeakerConfig)
277 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
278 TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
279 return DirectSoundDevice_GetSpeakerConfig(This->device, lpdwSpeakerConfig);
282 static HRESULT WINAPI IDirectSound8Impl_SetSpeakerConfig(IDirectSound8 *iface, DWORD config)
284 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
285 TRACE("(%p,0x%08x)\n", This, config);
286 return DirectSoundDevice_SetSpeakerConfig(This->device, config);
289 static HRESULT WINAPI IDirectSound8Impl_Initialize(IDirectSound8 *iface, const GUID *lpcGuid)
291 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
292 TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
293 return DirectSoundDevice_Initialize(&This->device, lpcGuid);
296 static HRESULT WINAPI IDirectSound8Impl_VerifyCertification(IDirectSound8 *iface,
297 DWORD *pdwCertified)
299 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
300 TRACE("(%p, %p)\n", This, pdwCertified);
301 return DirectSoundDevice_VerifyCertification(This->device, pdwCertified);
304 static const IDirectSound8Vtbl ds8_vtbl =
306 IDirectSound8Impl_QueryInterface,
307 IDirectSound8Impl_AddRef,
308 IDirectSound8Impl_Release,
309 IDirectSound8Impl_CreateSoundBuffer,
310 IDirectSound8Impl_GetCaps,
311 IDirectSound8Impl_DuplicateSoundBuffer,
312 IDirectSound8Impl_SetCooperativeLevel,
313 IDirectSound8Impl_Compact,
314 IDirectSound8Impl_GetSpeakerConfig,
315 IDirectSound8Impl_SetSpeakerConfig,
316 IDirectSound8Impl_Initialize,
317 IDirectSound8Impl_VerifyCertification
320 static HRESULT IDirectSoundImpl_Create(REFIID riid, void **ppv, BOOL has_ds8)
322 IDirectSoundImpl *obj;
323 HRESULT hr;
325 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
327 *ppv = NULL;
328 obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*obj));
329 if (!obj) {
330 WARN("out of memory\n");
331 return DSERR_OUTOFMEMORY;
334 setup_dsound_options();
336 obj->IUnknown_iface.lpVtbl = &unk_vtbl;
337 obj->IDirectSound8_iface.lpVtbl = &ds8_vtbl;
338 obj->ref = 1;
339 obj->refds = 0;
340 obj->numIfaces = 1;
341 obj->device = NULL;
342 obj->has_ds8 = has_ds8;
344 hr = IUnknown_QueryInterface(&obj->IUnknown_iface, riid, ppv);
345 IUnknown_Release(&obj->IUnknown_iface);
347 return hr;
350 HRESULT DSOUND_Create(REFIID riid, void **ppv)
352 return IDirectSoundImpl_Create(riid, ppv, FALSE);
355 HRESULT DSOUND_Create8(REFIID riid, void **ppv)
357 return IDirectSoundImpl_Create(riid, ppv, TRUE);
360 /*******************************************************************************
361 * DirectSoundCreate (DSOUND.1)
363 * Creates and initializes a DirectSound interface.
365 * PARAMS
366 * lpcGUID [I] Address of the GUID that identifies the sound device.
367 * ppDS [O] Address of a variable to receive the interface pointer.
368 * pUnkOuter [I] Must be NULL.
370 * RETURNS
371 * Success: DS_OK
372 * Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
373 * DSERR_NODRIVER, DSERR_OUTOFMEMORY
375 HRESULT WINAPI DirectSoundCreate(
376 LPCGUID lpcGUID,
377 LPDIRECTSOUND *ppDS,
378 IUnknown *pUnkOuter)
380 HRESULT hr;
381 LPDIRECTSOUND pDS;
383 TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
385 if (ppDS == NULL) {
386 WARN("invalid parameter: ppDS == NULL\n");
387 return DSERR_INVALIDPARAM;
390 if (pUnkOuter != NULL) {
391 WARN("invalid parameter: pUnkOuter != NULL\n");
392 *ppDS = 0;
393 return DSERR_INVALIDPARAM;
396 hr = DSOUND_Create(&IID_IDirectSound, (void **)&pDS);
397 if (hr == DS_OK) {
398 hr = IDirectSound_Initialize(pDS, lpcGUID);
399 if (hr != DS_OK) {
400 if (hr != DSERR_ALREADYINITIALIZED) {
401 IDirectSound_Release(pDS);
402 pDS = 0;
403 } else
404 hr = DS_OK;
408 *ppDS = pDS;
410 return hr;
413 /*******************************************************************************
414 * DirectSoundCreate8 (DSOUND.11)
416 * Creates and initializes a DirectSound8 interface.
418 * PARAMS
419 * lpcGUID [I] Address of the GUID that identifies the sound device.
420 * ppDS [O] Address of a variable to receive the interface pointer.
421 * pUnkOuter [I] Must be NULL.
423 * RETURNS
424 * Success: DS_OK
425 * Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
426 * DSERR_NODRIVER, DSERR_OUTOFMEMORY
428 HRESULT WINAPI DirectSoundCreate8(
429 LPCGUID lpcGUID,
430 LPDIRECTSOUND8 *ppDS,
431 IUnknown *pUnkOuter)
433 HRESULT hr;
434 LPDIRECTSOUND8 pDS;
436 TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
438 if (ppDS == NULL) {
439 WARN("invalid parameter: ppDS == NULL\n");
440 return DSERR_INVALIDPARAM;
443 if (pUnkOuter != NULL) {
444 WARN("invalid parameter: pUnkOuter != NULL\n");
445 *ppDS = 0;
446 return DSERR_INVALIDPARAM;
449 hr = DSOUND_Create8(&IID_IDirectSound8, (void **)&pDS);
450 if (hr == DS_OK) {
451 hr = IDirectSound8_Initialize(pDS, lpcGUID);
452 if (hr != DS_OK) {
453 if (hr != DSERR_ALREADYINITIALIZED) {
454 IDirectSound8_Release(pDS);
455 pDS = 0;
456 } else
457 hr = DS_OK;
461 *ppDS = pDS;
463 return hr;
466 /*******************************************************************************
467 * DirectSoundDevice
469 static HRESULT DirectSoundDevice_Create(DirectSoundDevice ** ppDevice)
471 DirectSoundDevice * device;
472 TRACE("(%p)\n", ppDevice);
474 /* Allocate memory */
475 device = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DirectSoundDevice));
476 if (device == NULL) {
477 WARN("out of memory\n");
478 return DSERR_OUTOFMEMORY;
481 device->ref = 1;
482 device->priolevel = DSSCL_NORMAL;
483 device->state = STATE_STOPPED;
484 device->speaker_config = DSSPEAKER_COMBINED(DSSPEAKER_STEREO, DSSPEAKER_GEOMETRY_WIDE);
486 /* 3D listener initial parameters */
487 device->ds3dl.dwSize = sizeof(DS3DLISTENER);
488 device->ds3dl.vPosition.x = 0.0;
489 device->ds3dl.vPosition.y = 0.0;
490 device->ds3dl.vPosition.z = 0.0;
491 device->ds3dl.vVelocity.x = 0.0;
492 device->ds3dl.vVelocity.y = 0.0;
493 device->ds3dl.vVelocity.z = 0.0;
494 device->ds3dl.vOrientFront.x = 0.0;
495 device->ds3dl.vOrientFront.y = 0.0;
496 device->ds3dl.vOrientFront.z = 1.0;
497 device->ds3dl.vOrientTop.x = 0.0;
498 device->ds3dl.vOrientTop.y = 1.0;
499 device->ds3dl.vOrientTop.z = 0.0;
500 device->ds3dl.flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
501 device->ds3dl.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
502 device->ds3dl.flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
504 device->guid = GUID_NULL;
506 /* Set default wave format (may need it for waveOutOpen) */
507 device->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(WAVEFORMATEXTENSIBLE));
508 device->primary_pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(WAVEFORMATEX));
509 if (!device->pwfx || !device->primary_pwfx) {
510 WARN("out of memory\n");
511 HeapFree(GetProcessHeap(),0,device->primary_pwfx);
512 HeapFree(GetProcessHeap(),0,device->pwfx);
513 HeapFree(GetProcessHeap(),0,device);
514 return DSERR_OUTOFMEMORY;
517 device->pwfx->wFormatTag = WAVE_FORMAT_PCM;
518 device->pwfx->nSamplesPerSec = 22050;
519 device->pwfx->wBitsPerSample = 8;
520 device->pwfx->nChannels = 2;
521 device->pwfx->nBlockAlign = device->pwfx->wBitsPerSample * device->pwfx->nChannels / 8;
522 device->pwfx->nAvgBytesPerSec = device->pwfx->nSamplesPerSec * device->pwfx->nBlockAlign;
523 device->pwfx->cbSize = 0;
524 memcpy(device->primary_pwfx, device->pwfx, sizeof(*device->pwfx));
526 InitializeCriticalSection(&(device->mixlock));
527 device->mixlock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DirectSoundDevice.mixlock");
529 RtlInitializeResource(&(device->buffer_list_lock));
531 *ppDevice = device;
533 return DS_OK;
536 static ULONG DirectSoundDevice_AddRef(DirectSoundDevice * device)
538 ULONG ref = InterlockedIncrement(&(device->ref));
539 TRACE("(%p) ref was %d\n", device, ref - 1);
540 return ref;
543 ULONG DirectSoundDevice_Release(DirectSoundDevice * device)
545 HRESULT hr;
546 ULONG ref = InterlockedDecrement(&(device->ref));
547 TRACE("(%p) ref was %u\n", device, ref + 1);
548 if (!ref) {
549 int i;
551 SetEvent(device->sleepev);
552 CloseHandle(device->sleepev);
553 if (device->thread) {
554 WaitForSingleObject(device->thread, INFINITE);
555 CloseHandle(device->thread);
558 EnterCriticalSection(&DSOUND_renderers_lock);
559 list_remove(&device->entry);
560 LeaveCriticalSection(&DSOUND_renderers_lock);
562 /* It is allowed to release this object even when buffers are playing */
563 if (device->buffers) {
564 WARN("%d secondary buffers not released\n", device->nrofbuffers);
565 for( i=0;i<device->nrofbuffers;i++)
566 secondarybuffer_destroy(device->buffers[i]);
569 hr = DSOUND_PrimaryDestroy(device);
570 if (hr != DS_OK)
571 WARN("DSOUND_PrimaryDestroy failed\n");
573 if(device->client)
574 IAudioClient_Release(device->client);
575 if(device->render)
576 IAudioRenderClient_Release(device->render);
577 if(device->clock)
578 IAudioClock_Release(device->clock);
579 if(device->volume)
580 IAudioStreamVolume_Release(device->volume);
582 HeapFree(GetProcessHeap(), 0, device->tmp_buffer);
583 HeapFree(GetProcessHeap(), 0, device->mix_buffer);
584 HeapFree(GetProcessHeap(), 0, device->buffer);
585 RtlDeleteResource(&device->buffer_list_lock);
586 device->mixlock.DebugInfo->Spare[0] = 0;
587 DeleteCriticalSection(&device->mixlock);
588 HeapFree(GetProcessHeap(),0,device);
589 TRACE("(%p) released\n", device);
591 return ref;
594 HRESULT DirectSoundDevice_GetCaps(
595 DirectSoundDevice * device,
596 LPDSCAPS lpDSCaps)
598 TRACE("(%p,%p)\n",device,lpDSCaps);
600 if (device == NULL) {
601 WARN("not initialized\n");
602 return DSERR_UNINITIALIZED;
605 if (lpDSCaps == NULL) {
606 WARN("invalid parameter: lpDSCaps = NULL\n");
607 return DSERR_INVALIDPARAM;
610 /* check if there is enough room */
611 if (lpDSCaps->dwSize < sizeof(*lpDSCaps)) {
612 WARN("invalid parameter: lpDSCaps->dwSize = %d\n", lpDSCaps->dwSize);
613 return DSERR_INVALIDPARAM;
616 lpDSCaps->dwFlags = device->drvcaps.dwFlags;
617 if (TRACE_ON(dsound)) {
618 TRACE("(flags=0x%08x:\n",lpDSCaps->dwFlags);
619 _dump_DSCAPS(lpDSCaps->dwFlags);
620 TRACE(")\n");
622 lpDSCaps->dwMinSecondarySampleRate = device->drvcaps.dwMinSecondarySampleRate;
623 lpDSCaps->dwMaxSecondarySampleRate = device->drvcaps.dwMaxSecondarySampleRate;
624 lpDSCaps->dwPrimaryBuffers = device->drvcaps.dwPrimaryBuffers;
625 lpDSCaps->dwMaxHwMixingAllBuffers = device->drvcaps.dwMaxHwMixingAllBuffers;
626 lpDSCaps->dwMaxHwMixingStaticBuffers = device->drvcaps.dwMaxHwMixingStaticBuffers;
627 lpDSCaps->dwMaxHwMixingStreamingBuffers = device->drvcaps.dwMaxHwMixingStreamingBuffers;
628 lpDSCaps->dwFreeHwMixingAllBuffers = device->drvcaps.dwFreeHwMixingAllBuffers;
629 lpDSCaps->dwFreeHwMixingStaticBuffers = device->drvcaps.dwFreeHwMixingStaticBuffers;
630 lpDSCaps->dwFreeHwMixingStreamingBuffers = device->drvcaps.dwFreeHwMixingStreamingBuffers;
631 lpDSCaps->dwMaxHw3DAllBuffers = device->drvcaps.dwMaxHw3DAllBuffers;
632 lpDSCaps->dwMaxHw3DStaticBuffers = device->drvcaps.dwMaxHw3DStaticBuffers;
633 lpDSCaps->dwMaxHw3DStreamingBuffers = device->drvcaps.dwMaxHw3DStreamingBuffers;
634 lpDSCaps->dwFreeHw3DAllBuffers = device->drvcaps.dwFreeHw3DAllBuffers;
635 lpDSCaps->dwFreeHw3DStaticBuffers = device->drvcaps.dwFreeHw3DStaticBuffers;
636 lpDSCaps->dwFreeHw3DStreamingBuffers = device->drvcaps.dwFreeHw3DStreamingBuffers;
637 lpDSCaps->dwTotalHwMemBytes = device->drvcaps.dwTotalHwMemBytes;
638 lpDSCaps->dwFreeHwMemBytes = device->drvcaps.dwFreeHwMemBytes;
639 lpDSCaps->dwMaxContigFreeHwMemBytes = device->drvcaps.dwMaxContigFreeHwMemBytes;
640 lpDSCaps->dwUnlockTransferRateHwBuffers = device->drvcaps.dwUnlockTransferRateHwBuffers;
641 lpDSCaps->dwPlayCpuOverheadSwBuffers = device->drvcaps.dwPlayCpuOverheadSwBuffers;
643 return DS_OK;
646 BOOL DSOUND_check_supported(IAudioClient *client, DWORD rate,
647 DWORD depth, WORD channels)
649 WAVEFORMATEX fmt, *junk;
650 HRESULT hr;
652 fmt.wFormatTag = WAVE_FORMAT_PCM;
653 fmt.nChannels = channels;
654 fmt.nSamplesPerSec = rate;
655 fmt.wBitsPerSample = depth;
656 fmt.nBlockAlign = (channels * depth) / 8;
657 fmt.nAvgBytesPerSec = rate * fmt.nBlockAlign;
658 fmt.cbSize = 0;
660 hr = IAudioClient_IsFormatSupported(client, AUDCLNT_SHAREMODE_SHARED, &fmt, &junk);
661 if(SUCCEEDED(hr))
662 CoTaskMemFree(junk);
664 return hr == S_OK;
667 UINT DSOUND_create_timer(LPTIMECALLBACK cb, DWORD_PTR user)
669 UINT triggertime = DS_TIME_DEL, res = DS_TIME_RES, id;
670 TIMECAPS time;
672 timeGetDevCaps(&time, sizeof(TIMECAPS));
673 TRACE("Minimum timer resolution: %u, max timer: %u\n", time.wPeriodMin, time.wPeriodMax);
674 if (triggertime < time.wPeriodMin)
675 triggertime = time.wPeriodMin;
676 if (res < time.wPeriodMin)
677 res = time.wPeriodMin;
678 if (timeBeginPeriod(res) == TIMERR_NOCANDO)
679 WARN("Could not set minimum resolution, don't expect sound\n");
680 id = timeSetEvent(triggertime, res, cb, user, TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
681 if (!id)
683 WARN("Timer not created! Retrying without TIME_KILL_SYNCHRONOUS\n");
684 id = timeSetEvent(triggertime, res, cb, user, TIME_PERIODIC);
685 if (!id)
686 ERR("Could not create timer, sound playback will not occur\n");
688 return id;
691 HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcGUID)
693 HRESULT hr = DS_OK;
694 GUID devGUID;
695 DirectSoundDevice *device;
696 IMMDevice *mmdevice;
698 TRACE("(%p,%s)\n",ppDevice,debugstr_guid(lpcGUID));
700 if (*ppDevice != NULL) {
701 WARN("already initialized\n");
702 return DSERR_ALREADYINITIALIZED;
705 /* Default device? */
706 if (!lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL))
707 lpcGUID = &DSDEVID_DefaultPlayback;
709 if(IsEqualGUID(lpcGUID, &DSDEVID_DefaultCapture) ||
710 IsEqualGUID(lpcGUID, &DSDEVID_DefaultVoiceCapture))
711 return DSERR_NODRIVER;
713 if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
714 WARN("invalid parameter: lpcGUID\n");
715 return DSERR_INVALIDPARAM;
718 hr = get_mmdevice(eRender, &devGUID, &mmdevice);
719 if(FAILED(hr))
720 return hr;
722 EnterCriticalSection(&DSOUND_renderers_lock);
724 LIST_FOR_EACH_ENTRY(device, &DSOUND_renderers, DirectSoundDevice, entry){
725 if(IsEqualGUID(&device->guid, &devGUID)){
726 IMMDevice_Release(mmdevice);
727 DirectSoundDevice_AddRef(device);
728 *ppDevice = device;
729 LeaveCriticalSection(&DSOUND_renderers_lock);
730 return DS_OK;
734 hr = DirectSoundDevice_Create(&device);
735 if(FAILED(hr)){
736 WARN("DirectSoundDevice_Create failed\n");
737 IMMDevice_Release(mmdevice);
738 LeaveCriticalSection(&DSOUND_renderers_lock);
739 return hr;
742 device->mmdevice = mmdevice;
743 device->guid = devGUID;
744 device->sleepev = CreateEventW(0, 0, 0, 0);
746 hr = DSOUND_ReopenDevice(device, FALSE);
747 if (FAILED(hr))
749 HeapFree(GetProcessHeap(), 0, device);
750 LeaveCriticalSection(&DSOUND_renderers_lock);
751 IMMDevice_Release(mmdevice);
752 WARN("DSOUND_ReopenDevice failed: %08x\n", hr);
753 return hr;
756 ZeroMemory(&device->drvcaps, sizeof(device->drvcaps));
758 if(DSOUND_check_supported(device->client, 11025, 8, 1) ||
759 DSOUND_check_supported(device->client, 22050, 8, 1) ||
760 DSOUND_check_supported(device->client, 44100, 8, 1) ||
761 DSOUND_check_supported(device->client, 48000, 8, 1) ||
762 DSOUND_check_supported(device->client, 96000, 8, 1))
763 device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT | DSCAPS_PRIMARYMONO;
765 if(DSOUND_check_supported(device->client, 11025, 16, 1) ||
766 DSOUND_check_supported(device->client, 22050, 16, 1) ||
767 DSOUND_check_supported(device->client, 44100, 16, 1) ||
768 DSOUND_check_supported(device->client, 48000, 16, 1) ||
769 DSOUND_check_supported(device->client, 96000, 16, 1))
770 device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT | DSCAPS_PRIMARYMONO;
772 if(DSOUND_check_supported(device->client, 11025, 8, 2) ||
773 DSOUND_check_supported(device->client, 22050, 8, 2) ||
774 DSOUND_check_supported(device->client, 44100, 8, 2) ||
775 DSOUND_check_supported(device->client, 48000, 8, 2) ||
776 DSOUND_check_supported(device->client, 96000, 8, 2))
777 device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT | DSCAPS_PRIMARYSTEREO;
779 if(DSOUND_check_supported(device->client, 11025, 16, 2) ||
780 DSOUND_check_supported(device->client, 22050, 16, 2) ||
781 DSOUND_check_supported(device->client, 44100, 16, 2) ||
782 DSOUND_check_supported(device->client, 48000, 16, 2) ||
783 DSOUND_check_supported(device->client, 96000, 16, 2))
784 device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT | DSCAPS_PRIMARYSTEREO;
786 /* the dsound mixer supports all of the following */
787 device->drvcaps.dwFlags |= DSCAPS_SECONDARY8BIT | DSCAPS_SECONDARY16BIT;
788 device->drvcaps.dwFlags |= DSCAPS_SECONDARYMONO | DSCAPS_SECONDARYSTEREO;
789 device->drvcaps.dwFlags |= DSCAPS_CONTINUOUSRATE;
791 device->drvcaps.dwPrimaryBuffers = 1;
792 device->drvcaps.dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
793 device->drvcaps.dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
794 device->drvcaps.dwMaxHwMixingAllBuffers = 1;
795 device->drvcaps.dwMaxHwMixingStaticBuffers = 1;
796 device->drvcaps.dwMaxHwMixingStreamingBuffers = 1;
798 ZeroMemory(&device->volpan, sizeof(device->volpan));
800 hr = DSOUND_PrimaryCreate(device);
801 if (hr == DS_OK) {
802 device->thread = CreateThread(0, 0, DSOUND_mixthread, device, 0, 0);
803 SetThreadPriority(device->thread, THREAD_PRIORITY_TIME_CRITICAL);
804 } else
805 WARN("DSOUND_PrimaryCreate failed: %08x\n", hr);
807 *ppDevice = device;
808 list_add_tail(&DSOUND_renderers, &device->entry);
810 LeaveCriticalSection(&DSOUND_renderers_lock);
812 return hr;
815 HRESULT DirectSoundDevice_CreateSoundBuffer(
816 DirectSoundDevice * device,
817 LPCDSBUFFERDESC dsbd,
818 LPLPDIRECTSOUNDBUFFER ppdsb,
819 LPUNKNOWN lpunk,
820 BOOL from8)
822 HRESULT hres = DS_OK;
823 TRACE("(%p,%p,%p,%p)\n",device,dsbd,ppdsb,lpunk);
825 if (device == NULL) {
826 WARN("not initialized\n");
827 return DSERR_UNINITIALIZED;
830 if (dsbd == NULL) {
831 WARN("invalid parameter: dsbd == NULL\n");
832 return DSERR_INVALIDPARAM;
835 if (dsbd->dwSize != sizeof(DSBUFFERDESC) &&
836 dsbd->dwSize != sizeof(DSBUFFERDESC1)) {
837 WARN("invalid parameter: dsbd\n");
838 return DSERR_INVALIDPARAM;
841 if (ppdsb == NULL) {
842 WARN("invalid parameter: ppdsb == NULL\n");
843 return DSERR_INVALIDPARAM;
845 *ppdsb = NULL;
847 if (TRACE_ON(dsound)) {
848 TRACE("(structsize=%d)\n",dsbd->dwSize);
849 TRACE("(flags=0x%08x:\n",dsbd->dwFlags);
850 _dump_DSBCAPS(dsbd->dwFlags);
851 TRACE(")\n");
852 TRACE("(bufferbytes=%d)\n",dsbd->dwBufferBytes);
853 TRACE("(lpwfxFormat=%p)\n",dsbd->lpwfxFormat);
856 if (dsbd->dwFlags & DSBCAPS_LOCHARDWARE &&
857 !(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
858 TRACE("LOCHARDWARE is not supported, returning E_NOTIMPL\n");
859 return E_NOTIMPL;
862 if (dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) {
863 if (dsbd->lpwfxFormat != NULL) {
864 WARN("invalid parameter: dsbd->lpwfxFormat must be NULL for "
865 "primary buffer\n");
866 return DSERR_INVALIDPARAM;
869 if (device->primary) {
870 WARN("Primary Buffer already created\n");
871 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(device->primary));
872 *ppdsb = (LPDIRECTSOUNDBUFFER)(device->primary);
873 } else {
874 hres = primarybuffer_create(device, &device->primary, dsbd);
875 if (device->primary) {
876 *ppdsb = (IDirectSoundBuffer*)&device->primary->IDirectSoundBuffer8_iface;
877 device->primary->dsbd.dwFlags &= ~(DSBCAPS_LOCHARDWARE | DSBCAPS_LOCSOFTWARE);
878 device->primary->dsbd.dwFlags |= DSBCAPS_LOCSOFTWARE;
879 } else
880 WARN("primarybuffer_create() failed\n");
882 } else {
883 IDirectSoundBufferImpl * dsb;
884 WAVEFORMATEXTENSIBLE *pwfxe;
886 if (dsbd->lpwfxFormat == NULL) {
887 WARN("invalid parameter: dsbd->lpwfxFormat can't be NULL for "
888 "secondary buffer\n");
889 return DSERR_INVALIDPARAM;
891 pwfxe = (WAVEFORMATEXTENSIBLE*)dsbd->lpwfxFormat;
893 if (pwfxe->Format.wBitsPerSample != 16 && pwfxe->Format.wBitsPerSample != 8 && pwfxe->Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE)
895 WARN("wBitsPerSample=%d needs a WAVEFORMATEXTENSIBLE\n", dsbd->lpwfxFormat->wBitsPerSample);
896 return DSERR_CONTROLUNAVAIL;
898 if (pwfxe->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE)
900 /* check if cbSize is at least 22 bytes */
901 if (pwfxe->Format.cbSize < (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)))
903 WARN("Too small a cbSize %u\n", pwfxe->Format.cbSize);
904 return DSERR_INVALIDPARAM;
907 /* cbSize should be 22 bytes, with one possible exception */
908 if (pwfxe->Format.cbSize > (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)) &&
909 !((IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) || IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) &&
910 pwfxe->Format.cbSize == sizeof(WAVEFORMATEXTENSIBLE)))
912 WARN("Too big a cbSize %u\n", pwfxe->Format.cbSize);
913 return DSERR_CONTROLUNAVAIL;
916 if ((!IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) && (!IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)))
918 if (!IsEqualGUID(&pwfxe->SubFormat, &GUID_NULL))
919 FIXME("SubFormat %s not supported right now.\n", debugstr_guid(&pwfxe->SubFormat));
920 return DSERR_INVALIDPARAM;
922 if (pwfxe->Samples.wValidBitsPerSample > dsbd->lpwfxFormat->wBitsPerSample)
924 WARN("Samples.wValidBitsPerSample(%d) > Format.wBitsPerSample (%d)\n", pwfxe->Samples.wValidBitsPerSample, pwfxe->Format.wBitsPerSample);
925 return DSERR_INVALIDPARAM;
927 if (pwfxe->Samples.wValidBitsPerSample && pwfxe->Samples.wValidBitsPerSample < dsbd->lpwfxFormat->wBitsPerSample)
929 FIXME("Non-packed formats not supported right now: %d/%d\n", pwfxe->Samples.wValidBitsPerSample, dsbd->lpwfxFormat->wBitsPerSample);
930 return DSERR_CONTROLUNAVAIL;
934 TRACE("(formattag=0x%04x,chans=%d,samplerate=%d,"
935 "bytespersec=%d,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
936 dsbd->lpwfxFormat->wFormatTag, dsbd->lpwfxFormat->nChannels,
937 dsbd->lpwfxFormat->nSamplesPerSec,
938 dsbd->lpwfxFormat->nAvgBytesPerSec,
939 dsbd->lpwfxFormat->nBlockAlign,
940 dsbd->lpwfxFormat->wBitsPerSample, dsbd->lpwfxFormat->cbSize);
942 if (from8 && (dsbd->dwFlags & DSBCAPS_CTRL3D) && (dsbd->lpwfxFormat->nChannels != 1)) {
943 WARN("invalid parameter: 3D buffer format must be mono\n");
944 return DSERR_INVALIDPARAM;
947 hres = IDirectSoundBufferImpl_Create(device, &dsb, dsbd);
948 if (dsb)
949 *ppdsb = (IDirectSoundBuffer*)&dsb->IDirectSoundBuffer8_iface;
950 else
951 WARN("IDirectSoundBufferImpl_Create failed\n");
954 return hres;
957 HRESULT DirectSoundDevice_DuplicateSoundBuffer(
958 DirectSoundDevice * device,
959 LPDIRECTSOUNDBUFFER psb,
960 LPLPDIRECTSOUNDBUFFER ppdsb)
962 HRESULT hres = DS_OK;
963 IDirectSoundBufferImpl* dsb;
964 TRACE("(%p,%p,%p)\n",device,psb,ppdsb);
966 if (device == NULL) {
967 WARN("not initialized\n");
968 return DSERR_UNINITIALIZED;
971 if (psb == NULL) {
972 WARN("invalid parameter: psb == NULL\n");
973 return DSERR_INVALIDPARAM;
976 if (ppdsb == NULL) {
977 WARN("invalid parameter: ppdsb == NULL\n");
978 return DSERR_INVALIDPARAM;
981 /* make sure we have a secondary buffer */
982 if (psb == (IDirectSoundBuffer *)&device->primary->IDirectSoundBuffer8_iface) {
983 WARN("trying to duplicate primary buffer\n");
984 *ppdsb = NULL;
985 return DSERR_INVALIDCALL;
988 /* duplicate the actual buffer implementation */
989 hres = IDirectSoundBufferImpl_Duplicate(device, &dsb, (IDirectSoundBufferImpl*)psb);
990 if (hres == DS_OK)
991 *ppdsb = (IDirectSoundBuffer*)&dsb->IDirectSoundBuffer8_iface;
992 else
993 WARN("IDirectSoundBufferImpl_Duplicate failed\n");
995 return hres;
998 HRESULT DirectSoundDevice_SetCooperativeLevel(
999 DirectSoundDevice * device,
1000 HWND hwnd,
1001 DWORD level)
1003 HRESULT hr = S_OK;
1004 DWORD oldlevel;
1005 TRACE("(%p,%p,%s)\n",device,hwnd,dumpCooperativeLevel(level));
1007 if (device == NULL) {
1008 WARN("not initialized\n");
1009 return DSERR_UNINITIALIZED;
1012 if (level==DSSCL_PRIORITY || level==DSSCL_EXCLUSIVE) {
1013 WARN("level=%s not fully supported\n",
1014 level==DSSCL_PRIORITY ? "DSSCL_PRIORITY" : "DSSCL_EXCLUSIVE");
1017 RtlAcquireResourceExclusive(&device->buffer_list_lock, TRUE);
1018 EnterCriticalSection(&device->mixlock);
1019 oldlevel = device->priolevel;
1020 device->priolevel = level;
1021 if ((level == DSSCL_WRITEPRIMARY) != (oldlevel == DSSCL_WRITEPRIMARY)) {
1022 hr = DSOUND_ReopenDevice(device, 0);
1023 if (FAILED(hr))
1024 device->priolevel = oldlevel;
1025 else
1026 DSOUND_PrimaryOpen(device);
1028 LeaveCriticalSection(&device->mixlock);
1029 RtlReleaseResource(&device->buffer_list_lock);
1030 return hr;
1033 HRESULT DirectSoundDevice_Compact(
1034 DirectSoundDevice * device)
1036 TRACE("(%p)\n", device);
1038 if (device == NULL) {
1039 WARN("not initialized\n");
1040 return DSERR_UNINITIALIZED;
1043 if (device->priolevel < DSSCL_PRIORITY) {
1044 WARN("incorrect priority level\n");
1045 return DSERR_PRIOLEVELNEEDED;
1048 return DS_OK;
1051 HRESULT DirectSoundDevice_GetSpeakerConfig(
1052 DirectSoundDevice * device,
1053 LPDWORD lpdwSpeakerConfig)
1055 TRACE("(%p, %p)\n", device, lpdwSpeakerConfig);
1057 if (device == NULL) {
1058 WARN("not initialized\n");
1059 return DSERR_UNINITIALIZED;
1062 if (lpdwSpeakerConfig == NULL) {
1063 WARN("invalid parameter: lpdwSpeakerConfig == NULL\n");
1064 return DSERR_INVALIDPARAM;
1067 WARN("not fully functional\n");
1068 *lpdwSpeakerConfig = device->speaker_config;
1069 return DS_OK;
1072 HRESULT DirectSoundDevice_SetSpeakerConfig(
1073 DirectSoundDevice * device,
1074 DWORD config)
1076 TRACE("(%p,0x%08x)\n",device,config);
1078 if (device == NULL) {
1079 WARN("not initialized\n");
1080 return DSERR_UNINITIALIZED;
1083 device->speaker_config = config;
1084 WARN("not fully functional\n");
1085 return DS_OK;
1088 HRESULT DirectSoundDevice_VerifyCertification(
1089 DirectSoundDevice * device,
1090 LPDWORD pdwCertified)
1092 TRACE("(%p, %p)\n",device,pdwCertified);
1094 if (device == NULL) {
1095 WARN("not initialized\n");
1096 return DSERR_UNINITIALIZED;
1099 if (device->drvcaps.dwFlags & DSCAPS_CERTIFIED)
1100 *pdwCertified = DS_CERTIFIED;
1101 else
1102 *pdwCertified = DS_UNCERTIFIED;
1104 return DS_OK;
1108 * Add secondary buffer to buffer list.
1109 * Gets exclusive access to buffer for writing.
1111 HRESULT DirectSoundDevice_AddBuffer(
1112 DirectSoundDevice * device,
1113 IDirectSoundBufferImpl * pDSB)
1115 IDirectSoundBufferImpl **newbuffers;
1116 HRESULT hr = DS_OK;
1118 TRACE("(%p, %p)\n", device, pDSB);
1120 RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
1122 if (device->buffers)
1123 newbuffers = HeapReAlloc(GetProcessHeap(),0,device->buffers,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
1124 else
1125 newbuffers = HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
1127 if (newbuffers) {
1128 device->buffers = newbuffers;
1129 device->buffers[device->nrofbuffers] = pDSB;
1130 device->nrofbuffers++;
1131 TRACE("buffer count is now %d\n", device->nrofbuffers);
1132 } else {
1133 ERR("out of memory for buffer list! Current buffer count is %d\n", device->nrofbuffers);
1134 hr = DSERR_OUTOFMEMORY;
1137 RtlReleaseResource(&(device->buffer_list_lock));
1139 return hr;
1143 * Remove secondary buffer from buffer list.
1144 * Gets exclusive access to buffer for writing.
1146 HRESULT DirectSoundDevice_RemoveBuffer(
1147 DirectSoundDevice * device,
1148 IDirectSoundBufferImpl * pDSB)
1150 int i;
1151 HRESULT hr = DS_OK;
1153 TRACE("(%p, %p)\n", device, pDSB);
1155 RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
1157 for (i = 0; i < device->nrofbuffers; i++)
1158 if (device->buffers[i] == pDSB)
1159 break;
1161 if (i < device->nrofbuffers) {
1162 /* Put the last buffer of the list in the (now empty) position */
1163 device->buffers[i] = device->buffers[device->nrofbuffers - 1];
1164 device->nrofbuffers--;
1165 device->buffers = HeapReAlloc(GetProcessHeap(),0,device->buffers,sizeof(LPDIRECTSOUNDBUFFER8)*device->nrofbuffers);
1166 TRACE("buffer count is now %d\n", device->nrofbuffers);
1169 if (device->nrofbuffers == 0) {
1170 HeapFree(GetProcessHeap(),0,device->buffers);
1171 device->buffers = NULL;
1174 RtlReleaseResource(&(device->buffer_list_lock));
1176 return hr;