mshtml: Added IHTMLWindow6::get_sessionStorage implementation.
[wine] / dlls / dsound / dsound.c
1 /* DirectSound
2  *
3  * Copyright 1998 Marcus Meissner
4  * Copyright 1998 Rob Riggs
5  * Copyright 2000-2002 TransGaming Technologies, Inc.
6  * Copyright 2004 Robert Reif
7  *
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.
12  *
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.
17  *
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
21  */
22
23 #include <stdarg.h>
24 #include <stdio.h>
25
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"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
43
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;
50     BOOL                has_ds8;
51 } IDirectSoundImpl;
52
53 const char * dumpCooperativeLevel(DWORD level)
54 {
55 #define LE(x) case x: return #x
56     switch (level) {
57         LE(DSSCL_NORMAL);
58         LE(DSSCL_PRIORITY);
59         LE(DSSCL_EXCLUSIVE);
60         LE(DSSCL_WRITEPRIMARY);
61     }
62 #undef LE
63     return wine_dbg_sprintf("Unknown(%08x)", level);
64 }
65
66 static void _dump_DSCAPS(DWORD xmask) {
67     struct {
68         DWORD   mask;
69         const char    *name;
70     } flags[] = {
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)
77         FE(DSCAPS_EMULDRIVER)
78         FE(DSCAPS_CERTIFIED)
79         FE(DSCAPS_SECONDARYMONO)
80         FE(DSCAPS_SECONDARYSTEREO)
81         FE(DSCAPS_SECONDARY8BIT)
82         FE(DSCAPS_SECONDARY16BIT)
83 #undef FE
84     };
85     unsigned int     i;
86
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);
90 }
91
92 static void _dump_DSBCAPS(DWORD xmask) {
93     struct {
94         DWORD   mask;
95         const char    *name;
96     } flags[] = {
97 #define FE(x) { x, #x },
98         FE(DSBCAPS_PRIMARYBUFFER)
99         FE(DSBCAPS_STATIC)
100         FE(DSBCAPS_LOCHARDWARE)
101         FE(DSBCAPS_LOCSOFTWARE)
102         FE(DSBCAPS_CTRL3D)
103         FE(DSBCAPS_CTRLFREQUENCY)
104         FE(DSBCAPS_CTRLPAN)
105         FE(DSBCAPS_CTRLVOLUME)
106         FE(DSBCAPS_CTRLPOSITIONNOTIFY)
107         FE(DSBCAPS_STICKYFOCUS)
108         FE(DSBCAPS_GLOBALFOCUS)
109         FE(DSBCAPS_GETCURRENTPOSITION2)
110         FE(DSBCAPS_MUTE3DATMAXDISTANCE)
111 #undef FE
112     };
113     unsigned int     i;
114
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);
118 }
119
120 static void directsound_destroy(IDirectSoundImpl *This)
121 {
122     if (This->device)
123         DirectSoundDevice_Release(This->device);
124     HeapFree(GetProcessHeap(),0,This);
125     TRACE("(%p) released\n", This);
126 }
127
128 /*******************************************************************************
129  *      IUnknown Implementation for DirectSound
130  */
131 static inline IDirectSoundImpl *impl_from_IUnknown(IUnknown *iface)
132 {
133     return CONTAINING_RECORD(iface, IDirectSoundImpl, IUnknown_inner);
134 }
135
136 static HRESULT WINAPI IUnknownImpl_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
137 {
138     IDirectSoundImpl *This = impl_from_IUnknown(iface);
139
140     TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
141
142     if (!ppv) {
143         WARN("invalid parameter\n");
144         return E_INVALIDARG;
145     }
146     *ppv = NULL;
147
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;
153     else {
154         WARN("unknown IID %s\n", debugstr_guid(riid));
155         return E_NOINTERFACE;
156     }
157
158     IUnknown_AddRef((IUnknown*)*ppv);
159     return S_OK;
160 }
161
162 static ULONG WINAPI IUnknownImpl_AddRef(IUnknown *iface)
163 {
164     IDirectSoundImpl *This = impl_from_IUnknown(iface);
165     ULONG ref = InterlockedIncrement(&This->ref);
166
167     TRACE("(%p) ref=%d\n", This, ref);
168
169     if(ref == 1)
170         InterlockedIncrement(&This->numIfaces);
171
172     return ref;
173 }
174
175 static ULONG WINAPI IUnknownImpl_Release(IUnknown *iface)
176 {
177     IDirectSoundImpl *This = impl_from_IUnknown(iface);
178     ULONG ref = InterlockedDecrement(&This->ref);
179
180     TRACE("(%p) ref=%d\n", This, ref);
181
182     if (!ref && !InterlockedDecrement(&This->numIfaces))
183         directsound_destroy(This);
184
185     return ref;
186 }
187
188 static const IUnknownVtbl unk_vtbl =
189 {
190     IUnknownImpl_QueryInterface,
191     IUnknownImpl_AddRef,
192     IUnknownImpl_Release
193 };
194
195 /*******************************************************************************
196  *      IDirectSound and IDirectSound8 Implementation
197  */
198 static inline IDirectSoundImpl *impl_from_IDirectSound8(IDirectSound8 *iface)
199 {
200     return CONTAINING_RECORD(iface, IDirectSoundImpl, IDirectSound8_iface);
201 }
202
203 static HRESULT WINAPI IDirectSound8Impl_QueryInterface(IDirectSound8 *iface, REFIID riid,
204         void **ppv)
205 {
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);
209 }
210
211 static ULONG WINAPI IDirectSound8Impl_AddRef(IDirectSound8 *iface)
212 {
213     IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
214     ULONG ref = InterlockedIncrement(&This->refds);
215
216     TRACE("(%p) refds=%d\n", This, ref);
217
218     if(ref == 1)
219         InterlockedIncrement(&This->numIfaces);
220
221     return ref;
222 }
223
224 static ULONG WINAPI IDirectSound8Impl_Release(IDirectSound8 *iface)
225 {
226     IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
227     ULONG ref = InterlockedDecrement(&(This->refds));
228
229     TRACE("(%p) refds=%d\n", This, ref);
230
231     if (!ref && !InterlockedDecrement(&This->numIfaces))
232         directsound_destroy(This);
233
234     return ref;
235 }
236
237 static HRESULT WINAPI IDirectSound8Impl_CreateSoundBuffer(IDirectSound8 *iface,
238         const DSBUFFERDESC *dsbd, IDirectSoundBuffer **ppdsb, IUnknown *lpunk)
239 {
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);
243 }
244
245 static HRESULT WINAPI IDirectSound8Impl_GetCaps(IDirectSound8 *iface, DSCAPS *lpDSCaps)
246 {
247     IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
248     TRACE("(%p,%p)\n", This, lpDSCaps);
249     return DirectSoundDevice_GetCaps(This->device, lpDSCaps);
250 }
251
252 static HRESULT WINAPI IDirectSound8Impl_DuplicateSoundBuffer(IDirectSound8 *iface,
253         IDirectSoundBuffer *psb, IDirectSoundBuffer **ppdsb)
254 {
255     IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
256     TRACE("(%p,%p,%p)\n", This, psb, ppdsb);
257     return DirectSoundDevice_DuplicateSoundBuffer(This->device, psb, ppdsb);
258 }
259
260 static HRESULT WINAPI IDirectSound8Impl_SetCooperativeLevel(IDirectSound8 *iface, HWND hwnd,
261         DWORD level)
262 {
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);
266 }
267
268 static HRESULT WINAPI IDirectSound8Impl_Compact(IDirectSound8 *iface)
269 {
270     IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
271     TRACE("(%p)\n", This);
272     return DirectSoundDevice_Compact(This->device);
273 }
274
275 static HRESULT WINAPI IDirectSound8Impl_GetSpeakerConfig(IDirectSound8 *iface,
276         DWORD *lpdwSpeakerConfig)
277 {
278     IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
279     TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
280     return DirectSoundDevice_GetSpeakerConfig(This->device, lpdwSpeakerConfig);
281 }
282
283 static HRESULT WINAPI IDirectSound8Impl_SetSpeakerConfig(IDirectSound8 *iface, DWORD config)
284 {
285     IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
286     TRACE("(%p,0x%08x)\n", This, config);
287     return DirectSoundDevice_SetSpeakerConfig(This->device, config);
288 }
289
290 static HRESULT WINAPI IDirectSound8Impl_Initialize(IDirectSound8 *iface, const GUID *lpcGuid)
291 {
292     IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
293     TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
294     return DirectSoundDevice_Initialize(&This->device, lpcGuid);
295 }
296
297 static HRESULT WINAPI IDirectSound8Impl_VerifyCertification(IDirectSound8 *iface,
298         DWORD *pdwCertified)
299 {
300     IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
301     TRACE("(%p, %p)\n", This, pdwCertified);
302     return DirectSoundDevice_VerifyCertification(This->device, pdwCertified);
303 }
304
305 static const IDirectSound8Vtbl ds8_vtbl =
306 {
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
319 };
320
321 HRESULT IDirectSoundImpl_Create(IUnknown *outer_unk, REFIID riid, void **ppv, BOOL has_ds8)
322 {
323     IDirectSoundImpl *obj;
324     HRESULT hr;
325
326     TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
327
328     *ppv = NULL;
329     obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*obj));
330     if (!obj) {
331         WARN("out of memory\n");
332         return DSERR_OUTOFMEMORY;
333     }
334
335     setup_dsound_options();
336
337     obj->IUnknown_inner.lpVtbl = &unk_vtbl;
338     obj->IDirectSound8_iface.lpVtbl = &ds8_vtbl;
339     obj->ref = 1;
340     obj->refds = 0;
341     obj->numIfaces = 1;
342     obj->device = NULL;
343     obj->has_ds8 = has_ds8;
344
345     /* COM aggregation supported only internally */
346     if (outer_unk)
347         obj->outer_unk = outer_unk;
348     else
349         obj->outer_unk = &obj->IUnknown_inner;
350
351     hr = IUnknown_QueryInterface(&obj->IUnknown_inner, riid, ppv);
352     IUnknown_Release(&obj->IUnknown_inner);
353
354     return hr;
355 }
356
357 HRESULT DSOUND_Create(REFIID riid, void **ppv)
358 {
359     return IDirectSoundImpl_Create(NULL, riid, ppv, FALSE);
360 }
361
362 HRESULT DSOUND_Create8(REFIID riid, void **ppv)
363 {
364     return IDirectSoundImpl_Create(NULL, riid, ppv, TRUE);
365 }
366
367 /*******************************************************************************
368  *              DirectSoundCreate (DSOUND.1)
369  *
370  *  Creates and initializes a DirectSound interface.
371  *
372  *  PARAMS
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.
376  *
377  *  RETURNS
378  *     Success: DS_OK
379  *     Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
380  *              DSERR_NODRIVER, DSERR_OUTOFMEMORY
381  */
382 HRESULT WINAPI DirectSoundCreate(
383     LPCGUID lpcGUID,
384     LPDIRECTSOUND *ppDS,
385     IUnknown *pUnkOuter)
386 {
387     HRESULT hr;
388     LPDIRECTSOUND pDS;
389
390     TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
391
392     if (ppDS == NULL) {
393         WARN("invalid parameter: ppDS == NULL\n");
394         return DSERR_INVALIDPARAM;
395     }
396
397     if (pUnkOuter != NULL) {
398         WARN("invalid parameter: pUnkOuter != NULL\n");
399         *ppDS = 0;
400         return DSERR_INVALIDPARAM;
401     }
402
403     hr = DSOUND_Create(&IID_IDirectSound, (void **)&pDS);
404     if (hr == DS_OK) {
405         hr = IDirectSound_Initialize(pDS, lpcGUID);
406         if (hr != DS_OK) {
407             if (hr != DSERR_ALREADYINITIALIZED) {
408                 IDirectSound_Release(pDS);
409                 pDS = 0;
410             } else
411                 hr = DS_OK;
412         }
413     }
414
415     *ppDS = pDS;
416
417     return hr;
418 }
419
420 /*******************************************************************************
421  *        DirectSoundCreate8 (DSOUND.11)
422  *
423  *  Creates and initializes a DirectSound8 interface.
424  *
425  *  PARAMS
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.
429  *
430  *  RETURNS
431  *     Success: DS_OK
432  *     Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
433  *              DSERR_NODRIVER, DSERR_OUTOFMEMORY
434  */
435 HRESULT WINAPI DirectSoundCreate8(
436     LPCGUID lpcGUID,
437     LPDIRECTSOUND8 *ppDS,
438     IUnknown *pUnkOuter)
439 {
440     HRESULT hr;
441     LPDIRECTSOUND8 pDS;
442
443     TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
444
445     if (ppDS == NULL) {
446         WARN("invalid parameter: ppDS == NULL\n");
447         return DSERR_INVALIDPARAM;
448     }
449
450     if (pUnkOuter != NULL) {
451         WARN("invalid parameter: pUnkOuter != NULL\n");
452         *ppDS = 0;
453         return DSERR_INVALIDPARAM;
454     }
455
456     hr = DSOUND_Create8(&IID_IDirectSound8, (void **)&pDS);
457     if (hr == DS_OK) {
458         hr = IDirectSound8_Initialize(pDS, lpcGUID);
459         if (hr != DS_OK) {
460             if (hr != DSERR_ALREADYINITIALIZED) {
461                 IDirectSound8_Release(pDS);
462                 pDS = 0;
463             } else
464                 hr = DS_OK;
465         }
466     }
467
468     *ppDS = pDS;
469
470     return hr;
471 }
472
473 /*******************************************************************************
474  *        DirectSoundDevice
475  */
476 static HRESULT DirectSoundDevice_Create(DirectSoundDevice ** ppDevice)
477 {
478     DirectSoundDevice * device;
479     TRACE("(%p)\n", ppDevice);
480
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;
486     }
487
488     device->ref            = 1;
489     device->priolevel      = DSSCL_NORMAL;
490     device->state          = STATE_STOPPED;
491     device->speaker_config = DSSPEAKER_COMBINED(DSSPEAKER_STEREO, DSSPEAKER_GEOMETRY_WIDE);
492
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;
510
511     device->prebuf = ds_snd_queue_max;
512     device->guid = GUID_NULL;
513
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;
520     }
521
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;
529
530     InitializeCriticalSection(&(device->mixlock));
531     device->mixlock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DirectSoundDevice.mixlock");
532
533     RtlInitializeResource(&(device->buffer_list_lock));
534
535    *ppDevice = device;
536
537     return DS_OK;
538 }
539
540 static ULONG DirectSoundDevice_AddRef(DirectSoundDevice * device)
541 {
542     ULONG ref = InterlockedIncrement(&(device->ref));
543     TRACE("(%p) ref was %d\n", device, ref - 1);
544     return ref;
545 }
546
547 ULONG DirectSoundDevice_Release(DirectSoundDevice * device)
548 {
549     HRESULT hr;
550     ULONG ref = InterlockedDecrement(&(device->ref));
551     TRACE("(%p) ref was %u\n", device, ref + 1);
552     if (!ref) {
553         int i;
554         timeKillEvent(device->timerID);
555         timeEndPeriod(DS_TIME_RES);
556
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));
562
563         EnterCriticalSection(&DSOUND_renderers_lock);
564         list_remove(&device->entry);
565         LeaveCriticalSection(&DSOUND_renderers_lock);
566
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]);
572         }
573
574         hr = DSOUND_PrimaryDestroy(device);
575         if (hr != DS_OK)
576             WARN("DSOUND_PrimaryDestroy failed\n");
577
578         if(device->client)
579             IAudioClient_Release(device->client);
580         if(device->render)
581             IAudioRenderClient_Release(device->render);
582         if(device->clock)
583             IAudioClock_Release(device->clock);
584         if(device->volume)
585             IAudioStreamVolume_Release(device->volume);
586
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);
595     }
596     return ref;
597 }
598
599 HRESULT DirectSoundDevice_GetCaps(
600     DirectSoundDevice * device,
601     LPDSCAPS lpDSCaps)
602 {
603     TRACE("(%p,%p)\n",device,lpDSCaps);
604
605     if (device == NULL) {
606         WARN("not initialized\n");
607         return DSERR_UNINITIALIZED;
608     }
609
610     if (lpDSCaps == NULL) {
611         WARN("invalid parameter: lpDSCaps = NULL\n");
612         return DSERR_INVALIDPARAM;
613     }
614
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;
619     }
620
621     lpDSCaps->dwFlags                           = device->drvcaps.dwFlags;
622     if (TRACE_ON(dsound)) {
623         TRACE("(flags=0x%08x:\n",lpDSCaps->dwFlags);
624         _dump_DSCAPS(lpDSCaps->dwFlags);
625         TRACE(")\n");
626     }
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;
647
648     return DS_OK;
649 }
650
651 BOOL DSOUND_check_supported(IAudioClient *client, DWORD rate,
652         DWORD depth, WORD channels)
653 {
654     WAVEFORMATEX fmt, *junk;
655     HRESULT hr;
656
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;
663     fmt.cbSize = 0;
664
665     hr = IAudioClient_IsFormatSupported(client, AUDCLNT_SHAREMODE_SHARED, &fmt, &junk);
666     if(SUCCEEDED(hr))
667         CoTaskMemFree(junk);
668
669     return hr == S_OK;
670 }
671
672 UINT DSOUND_create_timer(LPTIMECALLBACK cb, DWORD_PTR user)
673 {
674     UINT triggertime = DS_TIME_DEL, res = DS_TIME_RES, id;
675     TIMECAPS time;
676
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);
686     if (!id)
687     {
688         WARN("Timer not created! Retrying without TIME_KILL_SYNCHRONOUS\n");
689         id = timeSetEvent(triggertime, res, cb, user, TIME_PERIODIC);
690         if (!id)
691             ERR("Could not create timer, sound playback will not occur\n");
692     }
693     return id;
694 }
695
696 HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcGUID)
697 {
698     HRESULT hr = DS_OK;
699     GUID devGUID;
700     DirectSoundDevice *device;
701     IMMDevice *mmdevice;
702
703     TRACE("(%p,%s)\n",ppDevice,debugstr_guid(lpcGUID));
704
705     if (*ppDevice != NULL) {
706         WARN("already initialized\n");
707         return DSERR_ALREADYINITIALIZED;
708     }
709
710     /* Default device? */
711     if (!lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL))
712         lpcGUID = &DSDEVID_DefaultPlayback;
713
714     if(IsEqualGUID(lpcGUID, &DSDEVID_DefaultCapture) ||
715             IsEqualGUID(lpcGUID, &DSDEVID_DefaultVoiceCapture))
716         return DSERR_NODRIVER;
717
718     if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
719         WARN("invalid parameter: lpcGUID\n");
720         return DSERR_INVALIDPARAM;
721     }
722
723     hr = get_mmdevice(eRender, &devGUID, &mmdevice);
724     if(FAILED(hr))
725         return hr;
726
727     EnterCriticalSection(&DSOUND_renderers_lock);
728
729     LIST_FOR_EACH_ENTRY(device, &DSOUND_renderers, DirectSoundDevice, entry){
730         if(IsEqualGUID(&device->guid, &devGUID)){
731             IMMDevice_Release(mmdevice);
732             DirectSoundDevice_AddRef(device);
733             *ppDevice = device;
734             LeaveCriticalSection(&DSOUND_renderers_lock);
735             return DS_OK;
736         }
737     }
738
739     hr = DirectSoundDevice_Create(&device);
740     if(FAILED(hr)){
741         WARN("DirectSoundDevice_Create failed\n");
742         IMMDevice_Release(mmdevice);
743         LeaveCriticalSection(&DSOUND_renderers_lock);
744         return hr;
745     }
746
747     device->mmdevice = mmdevice;
748     device->guid = devGUID;
749
750     hr = DSOUND_ReopenDevice(device, FALSE);
751     if (FAILED(hr))
752     {
753         HeapFree(GetProcessHeap(), 0, device);
754         LeaveCriticalSection(&DSOUND_renderers_lock);
755         IMMDevice_Release(mmdevice);
756         WARN("DSOUND_ReopenDevice failed: %08x\n", hr);
757         return hr;
758     }
759
760     ZeroMemory(&device->drvcaps, sizeof(device->drvcaps));
761
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;
768
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;
775
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;
782
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;
789
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;
794
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;
801
802     ZeroMemory(&device->volpan, sizeof(device->volpan));
803
804     hr = DSOUND_PrimaryCreate(device);
805     if (hr == DS_OK)
806         device->timerID = DSOUND_create_timer(DSOUND_timer, (DWORD_PTR)device);
807     else
808         WARN("DSOUND_PrimaryCreate failed: %08x\n", hr);
809
810     *ppDevice = device;
811     list_add_tail(&DSOUND_renderers, &device->entry);
812
813     LeaveCriticalSection(&DSOUND_renderers_lock);
814
815     return hr;
816 }
817
818 HRESULT DirectSoundDevice_CreateSoundBuffer(
819     DirectSoundDevice * device,
820     LPCDSBUFFERDESC dsbd,
821     LPLPDIRECTSOUNDBUFFER ppdsb,
822     LPUNKNOWN lpunk,
823     BOOL from8)
824 {
825     HRESULT hres = DS_OK;
826     TRACE("(%p,%p,%p,%p)\n",device,dsbd,ppdsb,lpunk);
827
828     if (device == NULL) {
829         WARN("not initialized\n");
830         return DSERR_UNINITIALIZED;
831     }
832
833     if (dsbd == NULL) {
834         WARN("invalid parameter: dsbd == NULL\n");
835         return DSERR_INVALIDPARAM;
836     }
837
838     if (dsbd->dwSize != sizeof(DSBUFFERDESC) &&
839         dsbd->dwSize != sizeof(DSBUFFERDESC1)) {
840         WARN("invalid parameter: dsbd\n");
841         return DSERR_INVALIDPARAM;
842     }
843
844     if (ppdsb == NULL) {
845         WARN("invalid parameter: ppdsb == NULL\n");
846         return DSERR_INVALIDPARAM;
847     }
848     *ppdsb = NULL;
849
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);
854         TRACE(")\n");
855         TRACE("(bufferbytes=%d)\n",dsbd->dwBufferBytes);
856         TRACE("(lpwfxFormat=%p)\n",dsbd->lpwfxFormat);
857     }
858
859     if (dsbd->dwFlags & DSBCAPS_LOCHARDWARE &&
860             !(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
861         TRACE("LOCHARDWARE is not supported, returning E_NOTIMPL\n");
862         return E_NOTIMPL;
863     }
864
865     if (dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) {
866         if (dsbd->lpwfxFormat != NULL) {
867             WARN("invalid parameter: dsbd->lpwfxFormat must be NULL for "
868                  "primary buffer\n");
869             return DSERR_INVALIDPARAM;
870         }
871
872         if (device->primary) {
873             WARN("Primary Buffer already created\n");
874             IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(device->primary));
875             *ppdsb = (LPDIRECTSOUNDBUFFER)(device->primary);
876         } else {
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;
882             } else
883                 WARN("primarybuffer_create() failed\n");
884         }
885     } else {
886         IDirectSoundBufferImpl * dsb;
887         WAVEFORMATEXTENSIBLE *pwfxe;
888
889         if (dsbd->lpwfxFormat == NULL) {
890             WARN("invalid parameter: dsbd->lpwfxFormat can't be NULL for "
891                  "secondary buffer\n");
892             return DSERR_INVALIDPARAM;
893         }
894         pwfxe = (WAVEFORMATEXTENSIBLE*)dsbd->lpwfxFormat;
895
896         if (pwfxe->Format.wBitsPerSample != 16 && pwfxe->Format.wBitsPerSample != 8 && pwfxe->Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE)
897         {
898             WARN("wBitsPerSample=%d needs a WAVEFORMATEXTENSIBLE\n", dsbd->lpwfxFormat->wBitsPerSample);
899             return DSERR_CONTROLUNAVAIL;
900         }
901         if (pwfxe->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE)
902         {
903             /* check if cbSize is at least 22 bytes */
904             if (pwfxe->Format.cbSize < (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)))
905             {
906                 WARN("Too small a cbSize %u\n", pwfxe->Format.cbSize);
907                 return DSERR_INVALIDPARAM;
908             }
909
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)))
914             {
915                 WARN("Too big a cbSize %u\n", pwfxe->Format.cbSize);
916                 return DSERR_CONTROLUNAVAIL;
917             }
918
919             if ((!IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) && (!IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)))
920             {
921                 if (!IsEqualGUID(&pwfxe->SubFormat, &GUID_NULL))
922                     FIXME("SubFormat %s not supported right now.\n", debugstr_guid(&pwfxe->SubFormat));
923                 return DSERR_INVALIDPARAM;
924             }
925             if (pwfxe->Samples.wValidBitsPerSample > dsbd->lpwfxFormat->wBitsPerSample)
926             {
927                 WARN("Samples.wValidBitsPerSample(%d) > Format.wBitsPerSample (%d)\n", pwfxe->Samples.wValidBitsPerSample, pwfxe->Format.wBitsPerSample);
928                 return DSERR_INVALIDPARAM;
929             }
930             if (pwfxe->Samples.wValidBitsPerSample && pwfxe->Samples.wValidBitsPerSample < dsbd->lpwfxFormat->wBitsPerSample)
931             {
932                 FIXME("Non-packed formats not supported right now: %d/%d\n", pwfxe->Samples.wValidBitsPerSample, dsbd->lpwfxFormat->wBitsPerSample);
933                 return DSERR_CONTROLUNAVAIL;
934             }
935         }
936
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);
944
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;
948         }
949
950         hres = IDirectSoundBufferImpl_Create(device, &dsb, dsbd);
951         if (dsb)
952             *ppdsb = (IDirectSoundBuffer*)&dsb->IDirectSoundBuffer8_iface;
953         else
954             WARN("IDirectSoundBufferImpl_Create failed\n");
955    }
956
957    return hres;
958 }
959
960 HRESULT DirectSoundDevice_DuplicateSoundBuffer(
961     DirectSoundDevice * device,
962     LPDIRECTSOUNDBUFFER psb,
963     LPLPDIRECTSOUNDBUFFER ppdsb)
964 {
965     HRESULT hres = DS_OK;
966     IDirectSoundBufferImpl* dsb;
967     TRACE("(%p,%p,%p)\n",device,psb,ppdsb);
968
969     if (device == NULL) {
970         WARN("not initialized\n");
971         return DSERR_UNINITIALIZED;
972     }
973
974     if (psb == NULL) {
975         WARN("invalid parameter: psb == NULL\n");
976         return DSERR_INVALIDPARAM;
977     }
978
979     if (ppdsb == NULL) {
980         WARN("invalid parameter: ppdsb == NULL\n");
981         return DSERR_INVALIDPARAM;
982     }
983
984     /* make sure we have a secondary buffer */
985     if (psb == (IDirectSoundBuffer *)&device->primary->IDirectSoundBuffer8_iface) {
986         WARN("trying to duplicate primary buffer\n");
987         *ppdsb = NULL;
988         return DSERR_INVALIDCALL;
989     }
990
991     /* duplicate the actual buffer implementation */
992     hres = IDirectSoundBufferImpl_Duplicate(device, &dsb, (IDirectSoundBufferImpl*)psb);
993     if (hres == DS_OK)
994         *ppdsb = (IDirectSoundBuffer*)&dsb->IDirectSoundBuffer8_iface;
995     else
996         WARN("IDirectSoundBufferImpl_Duplicate failed\n");
997
998     return hres;
999 }
1000
1001 HRESULT DirectSoundDevice_SetCooperativeLevel(
1002     DirectSoundDevice * device,
1003     HWND hwnd,
1004     DWORD level)
1005 {
1006     TRACE("(%p,%p,%s)\n",device,hwnd,dumpCooperativeLevel(level));
1007
1008     if (device == NULL) {
1009         WARN("not initialized\n");
1010         return DSERR_UNINITIALIZED;
1011     }
1012
1013     if (level==DSSCL_PRIORITY || level==DSSCL_EXCLUSIVE) {
1014         WARN("level=%s not fully supported\n",
1015              level==DSSCL_PRIORITY ? "DSSCL_PRIORITY" : "DSSCL_EXCLUSIVE");
1016     }
1017
1018     device->priolevel = level;
1019     return DS_OK;
1020 }
1021
1022 HRESULT DirectSoundDevice_Compact(
1023     DirectSoundDevice * device)
1024 {
1025     TRACE("(%p)\n", device);
1026
1027     if (device == NULL) {
1028         WARN("not initialized\n");
1029         return DSERR_UNINITIALIZED;
1030     }
1031
1032     if (device->priolevel < DSSCL_PRIORITY) {
1033         WARN("incorrect priority level\n");
1034         return DSERR_PRIOLEVELNEEDED;
1035     }
1036
1037     return DS_OK;
1038 }
1039
1040 HRESULT DirectSoundDevice_GetSpeakerConfig(
1041     DirectSoundDevice * device,
1042     LPDWORD lpdwSpeakerConfig)
1043 {
1044     TRACE("(%p, %p)\n", device, lpdwSpeakerConfig);
1045
1046     if (device == NULL) {
1047         WARN("not initialized\n");
1048         return DSERR_UNINITIALIZED;
1049     }
1050
1051     if (lpdwSpeakerConfig == NULL) {
1052         WARN("invalid parameter: lpdwSpeakerConfig == NULL\n");
1053         return DSERR_INVALIDPARAM;
1054     }
1055
1056     WARN("not fully functional\n");
1057     *lpdwSpeakerConfig = device->speaker_config;
1058     return DS_OK;
1059 }
1060
1061 HRESULT DirectSoundDevice_SetSpeakerConfig(
1062     DirectSoundDevice * device,
1063     DWORD config)
1064 {
1065     TRACE("(%p,0x%08x)\n",device,config);
1066
1067     if (device == NULL) {
1068         WARN("not initialized\n");
1069         return DSERR_UNINITIALIZED;
1070     }
1071
1072     device->speaker_config = config;
1073     WARN("not fully functional\n");
1074     return DS_OK;
1075 }
1076
1077 HRESULT DirectSoundDevice_VerifyCertification(
1078     DirectSoundDevice * device,
1079     LPDWORD pdwCertified)
1080 {
1081     TRACE("(%p, %p)\n",device,pdwCertified);
1082
1083     if (device == NULL) {
1084         WARN("not initialized\n");
1085         return DSERR_UNINITIALIZED;
1086     }
1087
1088     if (device->drvcaps.dwFlags & DSCAPS_CERTIFIED)
1089         *pdwCertified = DS_CERTIFIED;
1090     else
1091         *pdwCertified = DS_UNCERTIFIED;
1092
1093     return DS_OK;
1094 }
1095
1096 /*
1097  * Add secondary buffer to buffer list.
1098  * Gets exclusive access to buffer for writing.
1099  */
1100 HRESULT DirectSoundDevice_AddBuffer(
1101     DirectSoundDevice * device,
1102     IDirectSoundBufferImpl * pDSB)
1103 {
1104     IDirectSoundBufferImpl **newbuffers;
1105     HRESULT hr = DS_OK;
1106
1107     TRACE("(%p, %p)\n", device, pDSB);
1108
1109     RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
1110
1111     if (device->buffers)
1112         newbuffers = HeapReAlloc(GetProcessHeap(),0,device->buffers,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
1113     else
1114         newbuffers = HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
1115
1116     if (newbuffers) {
1117         device->buffers = newbuffers;
1118         device->buffers[device->nrofbuffers] = pDSB;
1119         device->nrofbuffers++;
1120         TRACE("buffer count is now %d\n", device->nrofbuffers);
1121     } else {
1122         ERR("out of memory for buffer list! Current buffer count is %d\n", device->nrofbuffers);
1123         hr = DSERR_OUTOFMEMORY;
1124     }
1125
1126     RtlReleaseResource(&(device->buffer_list_lock));
1127
1128     return hr;
1129 }
1130
1131 /*
1132  * Remove secondary buffer from buffer list.
1133  * Gets exclusive access to buffer for writing.
1134  */
1135 HRESULT DirectSoundDevice_RemoveBuffer(
1136     DirectSoundDevice * device,
1137     IDirectSoundBufferImpl * pDSB)
1138 {
1139     int i;
1140     HRESULT hr = DS_OK;
1141
1142     TRACE("(%p, %p)\n", device, pDSB);
1143
1144     RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
1145
1146     for (i = 0; i < device->nrofbuffers; i++)
1147         if (device->buffers[i] == pDSB)
1148             break;
1149
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);
1156     }
1157
1158     if (device->nrofbuffers == 0) {
1159         HeapFree(GetProcessHeap(),0,device->buffers);
1160         device->buffers = NULL;
1161     }
1162
1163     RtlReleaseResource(&(device->buffer_list_lock));
1164
1165     return hr;
1166 }