kernel32: FindExSearchLimitToDirectories has no effect on FindFirstFileEx.
[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 NONAMELESSSTRUCT
27 #define NONAMELESSUNION
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winuser.h"
31 #include "mmsystem.h"
32 #include "winternl.h"
33 #include "mmddk.h"
34 #include "wine/debug.h"
35 #include "dsound.h"
36 #include "dsdriver.h"
37 #include "dsound_private.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
40
41 /*****************************************************************************
42  * IDirectSound COM components
43  */
44 struct IDirectSound_IUnknown {
45     const IUnknownVtbl         *lpVtbl;
46     LONG                        ref;
47     LPDIRECTSOUND8              pds;
48 };
49
50 static HRESULT IDirectSound_IUnknown_Create(LPDIRECTSOUND8 pds, LPUNKNOWN * ppunk);
51
52 struct IDirectSound_IDirectSound {
53     const IDirectSoundVtbl     *lpVtbl;
54     LONG                        ref;
55     LPDIRECTSOUND8              pds;
56 };
57
58 static HRESULT IDirectSound_IDirectSound_Create(LPDIRECTSOUND8 pds, LPDIRECTSOUND * ppds);
59
60 /*****************************************************************************
61  * IDirectSound8 COM components
62  */
63 struct IDirectSound8_IUnknown {
64     const IUnknownVtbl         *lpVtbl;
65     LONG                        ref;
66     LPDIRECTSOUND8              pds;
67 };
68
69 static HRESULT IDirectSound8_IUnknown_Create(LPDIRECTSOUND8 pds, LPUNKNOWN * ppunk);
70 static ULONG WINAPI IDirectSound8_IUnknown_AddRef(LPUNKNOWN iface);
71
72 struct IDirectSound8_IDirectSound {
73     const IDirectSoundVtbl     *lpVtbl;
74     LONG                        ref;
75     LPDIRECTSOUND8              pds;
76 };
77
78 static HRESULT IDirectSound8_IDirectSound_Create(LPDIRECTSOUND8 pds, LPDIRECTSOUND * ppds);
79 static ULONG WINAPI IDirectSound8_IDirectSound_AddRef(LPDIRECTSOUND iface);
80
81 struct IDirectSound8_IDirectSound8 {
82     const IDirectSound8Vtbl    *lpVtbl;
83     LONG                        ref;
84     LPDIRECTSOUND8              pds;
85 };
86
87 static HRESULT IDirectSound8_IDirectSound8_Create(LPDIRECTSOUND8 pds, LPDIRECTSOUND8 * ppds);
88 static ULONG WINAPI IDirectSound8_IDirectSound8_AddRef(LPDIRECTSOUND8 iface);
89
90 /*****************************************************************************
91  * IDirectSound implementation structure
92  */
93 struct IDirectSoundImpl
94 {
95     LONG                        ref;
96
97     DirectSoundDevice          *device;
98     LPUNKNOWN                   pUnknown;
99     LPDIRECTSOUND               pDS;
100     LPDIRECTSOUND8              pDS8;
101 };
102
103 static HRESULT IDirectSoundImpl_Create(LPDIRECTSOUND8 * ppds);
104
105 static ULONG WINAPI IDirectSound_IUnknown_AddRef(LPUNKNOWN iface);
106 static ULONG WINAPI IDirectSound_IDirectSound_AddRef(LPDIRECTSOUND iface);
107
108 static HRESULT DirectSoundDevice_VerifyCertification(DirectSoundDevice * device, LPDWORD pdwCertified);
109
110 const char * dumpCooperativeLevel(DWORD level)
111 {
112     static char unknown[32];
113 #define LE(x) case x: return #x
114     switch (level) {
115         LE(DSSCL_NORMAL);
116         LE(DSSCL_PRIORITY);
117         LE(DSSCL_EXCLUSIVE);
118         LE(DSSCL_WRITEPRIMARY);
119     }
120 #undef LE
121     sprintf(unknown, "Unknown(%08x)", level);
122     return unknown;
123 }
124
125 static void _dump_DSCAPS(DWORD xmask) {
126     struct {
127         DWORD   mask;
128         const char    *name;
129     } flags[] = {
130 #define FE(x) { x, #x },
131         FE(DSCAPS_PRIMARYMONO)
132         FE(DSCAPS_PRIMARYSTEREO)
133         FE(DSCAPS_PRIMARY8BIT)
134         FE(DSCAPS_PRIMARY16BIT)
135         FE(DSCAPS_CONTINUOUSRATE)
136         FE(DSCAPS_EMULDRIVER)
137         FE(DSCAPS_CERTIFIED)
138         FE(DSCAPS_SECONDARYMONO)
139         FE(DSCAPS_SECONDARYSTEREO)
140         FE(DSCAPS_SECONDARY8BIT)
141         FE(DSCAPS_SECONDARY16BIT)
142 #undef FE
143     };
144     unsigned int     i;
145
146     for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
147         if ((flags[i].mask & xmask) == flags[i].mask)
148             TRACE("%s ",flags[i].name);
149 }
150
151 static void _dump_DSBCAPS(DWORD xmask) {
152     struct {
153         DWORD   mask;
154         const char    *name;
155     } flags[] = {
156 #define FE(x) { x, #x },
157         FE(DSBCAPS_PRIMARYBUFFER)
158         FE(DSBCAPS_STATIC)
159         FE(DSBCAPS_LOCHARDWARE)
160         FE(DSBCAPS_LOCSOFTWARE)
161         FE(DSBCAPS_CTRL3D)
162         FE(DSBCAPS_CTRLFREQUENCY)
163         FE(DSBCAPS_CTRLPAN)
164         FE(DSBCAPS_CTRLVOLUME)
165         FE(DSBCAPS_CTRLPOSITIONNOTIFY)
166         FE(DSBCAPS_STICKYFOCUS)
167         FE(DSBCAPS_GLOBALFOCUS)
168         FE(DSBCAPS_GETCURRENTPOSITION2)
169         FE(DSBCAPS_MUTE3DATMAXDISTANCE)
170 #undef FE
171     };
172     unsigned int     i;
173
174     for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
175         if ((flags[i].mask & xmask) == flags[i].mask)
176             TRACE("%s ",flags[i].name);
177 }
178
179 /*******************************************************************************
180  *              IDirectSoundImpl_DirectSound
181  */
182 static HRESULT DSOUND_QueryInterface(
183     LPDIRECTSOUND8 iface,
184     REFIID riid,
185     LPVOID * ppobj)
186 {
187     IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
188     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
189
190     if (ppobj == NULL) {
191         WARN("invalid parameter\n");
192         return E_INVALIDARG;
193     }
194
195     if (IsEqualIID(riid, &IID_IUnknown)) {
196         if (!This->pUnknown) {
197             IDirectSound_IUnknown_Create(iface, &This->pUnknown);
198             if (!This->pUnknown) {
199                 WARN("IDirectSound_IUnknown_Create() failed\n");
200                 *ppobj = NULL;
201                 return E_NOINTERFACE;
202             }
203         }
204         IDirectSound_IUnknown_AddRef(This->pUnknown);
205         *ppobj = This->pUnknown;
206         return S_OK;
207     } else if (IsEqualIID(riid, &IID_IDirectSound)) {
208         if (!This->pDS) {
209             IDirectSound_IDirectSound_Create(iface, &This->pDS);
210             if (!This->pDS) {
211                 WARN("IDirectSound_IDirectSound_Create() failed\n");
212                 *ppobj = NULL;
213                 return E_NOINTERFACE;
214             }
215         }
216         IDirectSound_IDirectSound_AddRef(This->pDS);
217         *ppobj = This->pDS;
218         return S_OK;
219     }
220
221     *ppobj = NULL;
222     WARN("Unknown IID %s\n",debugstr_guid(riid));
223     return E_NOINTERFACE;
224 }
225
226 static HRESULT DSOUND_QueryInterface8(
227     LPDIRECTSOUND8 iface,
228     REFIID riid,
229     LPVOID * ppobj)
230 {
231     IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
232     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
233
234     if (ppobj == NULL) {
235         WARN("invalid parameter\n");
236         return E_INVALIDARG;
237     }
238
239     if (IsEqualIID(riid, &IID_IUnknown)) {
240         if (!This->pUnknown) {
241             IDirectSound8_IUnknown_Create(iface, &This->pUnknown);
242             if (!This->pUnknown) {
243                 WARN("IDirectSound8_IUnknown_Create() failed\n");
244                 *ppobj = NULL;
245                 return E_NOINTERFACE;
246             }
247         }
248         IDirectSound8_IUnknown_AddRef(This->pUnknown);
249         *ppobj = This->pUnknown;
250         return S_OK;
251     } else if (IsEqualIID(riid, &IID_IDirectSound)) {
252         if (!This->pDS) {
253             IDirectSound8_IDirectSound_Create(iface, &This->pDS);
254             if (!This->pDS) {
255                 WARN("IDirectSound8_IDirectSound_Create() failed\n");
256                 *ppobj = NULL;
257                 return E_NOINTERFACE;
258             }
259         }
260         IDirectSound8_IDirectSound_AddRef(This->pDS);
261         *ppobj = This->pDS;
262         return S_OK;
263     } else if (IsEqualIID(riid, &IID_IDirectSound8)) {
264         if (!This->pDS8) {
265             IDirectSound8_IDirectSound8_Create(iface, &This->pDS8);
266             if (!This->pDS8) {
267                 WARN("IDirectSound8_IDirectSound8_Create() failed\n");
268                 *ppobj = NULL;
269                 return E_NOINTERFACE;
270             }
271         }
272         IDirectSound8_IDirectSound8_AddRef(This->pDS8);
273         *ppobj = This->pDS8;
274         return S_OK;
275     }
276
277     *ppobj = NULL;
278     WARN("Unknown IID %s\n",debugstr_guid(riid));
279     return E_NOINTERFACE;
280 }
281
282 static ULONG IDirectSoundImpl_AddRef(
283     LPDIRECTSOUND8 iface)
284 {
285     IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
286     ULONG ref = InterlockedIncrement(&(This->ref));
287     TRACE("(%p) ref was %d\n", This, ref - 1);
288     return ref;
289 }
290
291 static ULONG IDirectSoundImpl_Release(
292     LPDIRECTSOUND8 iface)
293 {
294     IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
295     ULONG ref = InterlockedDecrement(&(This->ref));
296     TRACE("(%p) ref was %d\n", This, ref + 1);
297
298     if (!ref) {
299         if (This->device)
300             DirectSoundDevice_Release(This->device);
301         HeapFree(GetProcessHeap(),0,This);
302         TRACE("(%p) released\n", This);
303     }
304     return ref;
305 }
306
307 static HRESULT IDirectSoundImpl_Create(
308     LPDIRECTSOUND8 * ppDS)
309 {
310     IDirectSoundImpl* pDS;
311     TRACE("(%p)\n",ppDS);
312
313     /* Allocate memory */
314     pDS = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundImpl));
315     if (pDS == NULL) {
316         WARN("out of memory\n");
317         *ppDS = NULL;
318         return DSERR_OUTOFMEMORY;
319     }
320
321     pDS->ref    = 0;
322     pDS->device = NULL;
323
324     *ppDS = (LPDIRECTSOUND8)pDS;
325
326     return DS_OK;
327 }
328
329 /*******************************************************************************
330  *              IDirectSound_IUnknown
331  */
332 static HRESULT WINAPI IDirectSound_IUnknown_QueryInterface(
333     LPUNKNOWN iface,
334     REFIID riid,
335     LPVOID * ppobj)
336 {
337     IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
338     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
339     return DSOUND_QueryInterface(This->pds, riid, ppobj);
340 }
341
342 static ULONG WINAPI IDirectSound_IUnknown_AddRef(
343     LPUNKNOWN iface)
344 {
345     IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
346     ULONG ref = InterlockedIncrement(&(This->ref));
347     TRACE("(%p) ref was %d\n", This, ref - 1);
348     return ref;
349 }
350
351 static ULONG WINAPI IDirectSound_IUnknown_Release(
352     LPUNKNOWN iface)
353 {
354     IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
355     ULONG ref = InterlockedDecrement(&(This->ref));
356     TRACE("(%p) ref was %d\n", This, ref + 1);
357     if (!ref) {
358         IDirectSoundImpl_Release(This->pds);
359         HeapFree(GetProcessHeap(), 0, This);
360         TRACE("(%p) released\n", This);
361     }
362     return ref;
363 }
364
365 static const IUnknownVtbl DirectSound_Unknown_Vtbl =
366 {
367     IDirectSound_IUnknown_QueryInterface,
368     IDirectSound_IUnknown_AddRef,
369     IDirectSound_IUnknown_Release
370 };
371
372 static HRESULT IDirectSound_IUnknown_Create(
373     LPDIRECTSOUND8 pds,
374     LPUNKNOWN * ppunk)
375 {
376     IDirectSound_IUnknown * pdsunk;
377     TRACE("(%p,%p)\n",pds,ppunk);
378
379     if (ppunk == NULL) {
380         ERR("invalid parameter: ppunk == NULL\n");
381         return DSERR_INVALIDPARAM;
382     }
383
384     if (pds == NULL) {
385         ERR("invalid parameter: pds == NULL\n");
386         *ppunk = NULL;
387         return DSERR_INVALIDPARAM;
388     }
389
390     pdsunk = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsunk));
391     if (pdsunk == NULL) {
392         WARN("out of memory\n");
393         *ppunk = NULL;
394         return DSERR_OUTOFMEMORY;
395     }
396
397     pdsunk->lpVtbl = &DirectSound_Unknown_Vtbl;
398     pdsunk->ref = 0;
399     pdsunk->pds = pds;
400
401     IDirectSoundImpl_AddRef(pds);
402     *ppunk = (LPUNKNOWN)pdsunk;
403
404     return DS_OK;
405 }
406
407 /*******************************************************************************
408  *              IDirectSound_IDirectSound
409  */
410 static HRESULT WINAPI IDirectSound_IDirectSound_QueryInterface(
411     LPDIRECTSOUND iface,
412     REFIID riid,
413     LPVOID * ppobj)
414 {
415     IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
416     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
417     return DSOUND_QueryInterface(This->pds, riid, ppobj);
418 }
419
420 static ULONG WINAPI IDirectSound_IDirectSound_AddRef(
421     LPDIRECTSOUND iface)
422 {
423     IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
424     ULONG ref = InterlockedIncrement(&(This->ref));
425     TRACE("(%p) ref was %d\n", This, ref - 1);
426     return ref;
427 }
428
429 static ULONG WINAPI IDirectSound_IDirectSound_Release(
430     LPDIRECTSOUND iface)
431 {
432     IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
433     ULONG ref = InterlockedDecrement(&(This->ref));
434     TRACE("(%p) ref was %d\n", This, ref + 1);
435     if (!ref) {
436         IDirectSoundImpl_Release(This->pds);
437         HeapFree(GetProcessHeap(), 0, This);
438         TRACE("(%p) released\n", This);
439     }
440     return ref;
441 }
442
443 static HRESULT WINAPI IDirectSound_IDirectSound_CreateSoundBuffer(
444     LPDIRECTSOUND iface,
445     LPCDSBUFFERDESC dsbd,
446     LPLPDIRECTSOUNDBUFFER ppdsb,
447     LPUNKNOWN lpunk)
448 {
449     IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
450     TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
451     return DirectSoundDevice_CreateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,dsbd,ppdsb,lpunk,FALSE);
452 }
453
454 static HRESULT WINAPI IDirectSound_IDirectSound_GetCaps(
455     LPDIRECTSOUND iface,
456     LPDSCAPS lpDSCaps)
457 {
458     IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
459     TRACE("(%p,%p)\n",This,lpDSCaps);
460     return DirectSoundDevice_GetCaps(((IDirectSoundImpl *)This->pds)->device, lpDSCaps);
461 }
462
463 static HRESULT WINAPI IDirectSound_IDirectSound_DuplicateSoundBuffer(
464     LPDIRECTSOUND iface,
465     LPDIRECTSOUNDBUFFER psb,
466     LPLPDIRECTSOUNDBUFFER ppdsb)
467 {
468     IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
469     TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
470     return DirectSoundDevice_DuplicateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,psb,ppdsb);
471 }
472
473 static HRESULT WINAPI IDirectSound_IDirectSound_SetCooperativeLevel(
474     LPDIRECTSOUND iface,
475     HWND hwnd,
476     DWORD level)
477 {
478     IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
479     TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level));
480     return DirectSoundDevice_SetCooperativeLevel(((IDirectSoundImpl *)This->pds)->device, hwnd, level);
481 }
482
483 static HRESULT WINAPI IDirectSound_IDirectSound_Compact(
484     LPDIRECTSOUND iface)
485 {
486     IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
487     TRACE("(%p)\n", This);
488     return DirectSoundDevice_Compact(((IDirectSoundImpl *)This->pds)->device);
489 }
490
491 static HRESULT WINAPI IDirectSound_IDirectSound_GetSpeakerConfig(
492     LPDIRECTSOUND iface,
493     LPDWORD lpdwSpeakerConfig)
494 {
495     IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
496     TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
497     return DirectSoundDevice_GetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,lpdwSpeakerConfig);
498 }
499
500 static HRESULT WINAPI IDirectSound_IDirectSound_SetSpeakerConfig(
501     LPDIRECTSOUND iface,
502     DWORD config)
503 {
504     IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
505     TRACE("(%p,0x%08x)\n",This,config);
506     return DirectSoundDevice_SetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,config);
507 }
508
509 static HRESULT WINAPI IDirectSound_IDirectSound_Initialize(
510     LPDIRECTSOUND iface,
511     LPCGUID lpcGuid)
512 {
513     IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
514     TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
515     return DirectSoundDevice_Initialize(&((IDirectSoundImpl *)This->pds)->device,lpcGuid);
516 }
517
518 static const IDirectSoundVtbl DirectSound_DirectSound_Vtbl =
519 {
520     IDirectSound_IDirectSound_QueryInterface,
521     IDirectSound_IDirectSound_AddRef,
522     IDirectSound_IDirectSound_Release,
523     IDirectSound_IDirectSound_CreateSoundBuffer,
524     IDirectSound_IDirectSound_GetCaps,
525     IDirectSound_IDirectSound_DuplicateSoundBuffer,
526     IDirectSound_IDirectSound_SetCooperativeLevel,
527     IDirectSound_IDirectSound_Compact,
528     IDirectSound_IDirectSound_GetSpeakerConfig,
529     IDirectSound_IDirectSound_SetSpeakerConfig,
530     IDirectSound_IDirectSound_Initialize
531 };
532
533 static HRESULT IDirectSound_IDirectSound_Create(
534     LPDIRECTSOUND8  pds,
535     LPDIRECTSOUND * ppds)
536 {
537     IDirectSound_IDirectSound * pdsds;
538     TRACE("(%p,%p)\n",pds,ppds);
539
540     if (ppds == NULL) {
541         ERR("invalid parameter: ppds == NULL\n");
542         return DSERR_INVALIDPARAM;
543     }
544
545     if (pds == NULL) {
546         ERR("invalid parameter: pds == NULL\n");
547         *ppds = NULL;
548         return DSERR_INVALIDPARAM;
549     }
550
551     pdsds = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsds));
552     if (pdsds == NULL) {
553         WARN("out of memory\n");
554         *ppds = NULL;
555         return DSERR_OUTOFMEMORY;
556     }
557
558     pdsds->lpVtbl = &DirectSound_DirectSound_Vtbl;
559     pdsds->ref = 0;
560     pdsds->pds = pds;
561
562     IDirectSoundImpl_AddRef(pds);
563     *ppds = (LPDIRECTSOUND)pdsds;
564
565     return DS_OK;
566 }
567
568 /*******************************************************************************
569  *              IDirectSound8_IUnknown
570  */
571 static HRESULT WINAPI IDirectSound8_IUnknown_QueryInterface(
572     LPUNKNOWN iface,
573     REFIID riid,
574     LPVOID * ppobj)
575 {
576     IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
577     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
578     return DSOUND_QueryInterface8(This->pds, riid, ppobj);
579 }
580
581 static ULONG WINAPI IDirectSound8_IUnknown_AddRef(
582     LPUNKNOWN iface)
583 {
584     IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
585     ULONG ref = InterlockedIncrement(&(This->ref));
586     TRACE("(%p) ref was %d\n", This, ref - 1);
587     return ref;
588 }
589
590 static ULONG WINAPI IDirectSound8_IUnknown_Release(
591     LPUNKNOWN iface)
592 {
593     IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
594     ULONG ref = InterlockedDecrement(&(This->ref));
595     TRACE("(%p) ref was %d\n", This, ref + 1);
596     if (!ref) {
597         IDirectSoundImpl_Release(This->pds);
598         HeapFree(GetProcessHeap(), 0, This);
599         TRACE("(%p) released\n", This);
600     }
601     return ref;
602 }
603
604 static const IUnknownVtbl DirectSound8_Unknown_Vtbl =
605 {
606     IDirectSound8_IUnknown_QueryInterface,
607     IDirectSound8_IUnknown_AddRef,
608     IDirectSound8_IUnknown_Release
609 };
610
611 static HRESULT IDirectSound8_IUnknown_Create(
612     LPDIRECTSOUND8 pds,
613     LPUNKNOWN * ppunk)
614 {
615     IDirectSound8_IUnknown * pdsunk;
616     TRACE("(%p,%p)\n",pds,ppunk);
617
618     if (ppunk == NULL) {
619         ERR("invalid parameter: ppunk == NULL\n");
620         return DSERR_INVALIDPARAM;
621     }
622
623     if (pds == NULL) {
624         ERR("invalid parameter: pds == NULL\n");
625         *ppunk = NULL;
626         return DSERR_INVALIDPARAM;
627     }
628
629     pdsunk = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsunk));
630     if (pdsunk == NULL) {
631         WARN("out of memory\n");
632         *ppunk = NULL;
633         return DSERR_OUTOFMEMORY;
634     }
635
636     pdsunk->lpVtbl = &DirectSound8_Unknown_Vtbl;
637     pdsunk->ref = 0;
638     pdsunk->pds = pds;
639
640     IDirectSoundImpl_AddRef(pds);
641     *ppunk = (LPUNKNOWN)pdsunk;
642
643     return DS_OK;
644 }
645
646 /*******************************************************************************
647  *              IDirectSound8_IDirectSound
648  */
649 static HRESULT WINAPI IDirectSound8_IDirectSound_QueryInterface(
650     LPDIRECTSOUND iface,
651     REFIID riid,
652     LPVOID * ppobj)
653 {
654     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
655     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
656     return DSOUND_QueryInterface8(This->pds, riid, ppobj);
657 }
658
659 static ULONG WINAPI IDirectSound8_IDirectSound_AddRef(
660     LPDIRECTSOUND iface)
661 {
662     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
663     ULONG ref = InterlockedIncrement(&(This->ref));
664     TRACE("(%p) ref was %d\n", This, ref - 1);
665     return ref;
666 }
667
668 static ULONG WINAPI IDirectSound8_IDirectSound_Release(
669     LPDIRECTSOUND iface)
670 {
671     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
672     ULONG ref = InterlockedDecrement(&(This->ref));
673     TRACE("(%p) ref was %d\n", This, ref + 1);
674     if (!ref) {
675         IDirectSoundImpl_Release(This->pds);
676         HeapFree(GetProcessHeap(), 0, This);
677         TRACE("(%p) released\n", This);
678     }
679     return ref;
680 }
681
682 static HRESULT WINAPI IDirectSound8_IDirectSound_CreateSoundBuffer(
683     LPDIRECTSOUND iface,
684     LPCDSBUFFERDESC dsbd,
685     LPLPDIRECTSOUNDBUFFER ppdsb,
686     LPUNKNOWN lpunk)
687 {
688     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
689     TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
690     return DirectSoundDevice_CreateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,dsbd,ppdsb,lpunk,TRUE);
691 }
692
693 static HRESULT WINAPI IDirectSound8_IDirectSound_GetCaps(
694     LPDIRECTSOUND iface,
695     LPDSCAPS lpDSCaps)
696 {
697     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
698     TRACE("(%p,%p)\n",This,lpDSCaps);
699     return DirectSoundDevice_GetCaps(((IDirectSoundImpl *)This->pds)->device, lpDSCaps);
700 }
701
702 static HRESULT WINAPI IDirectSound8_IDirectSound_DuplicateSoundBuffer(
703     LPDIRECTSOUND iface,
704     LPDIRECTSOUNDBUFFER psb,
705     LPLPDIRECTSOUNDBUFFER ppdsb)
706 {
707     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
708     TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
709     return DirectSoundDevice_DuplicateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,psb,ppdsb);
710 }
711
712 static HRESULT WINAPI IDirectSound8_IDirectSound_SetCooperativeLevel(
713     LPDIRECTSOUND iface,
714     HWND hwnd,
715     DWORD level)
716 {
717     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
718     TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level));
719     return DirectSoundDevice_SetCooperativeLevel(((IDirectSoundImpl *)This->pds)->device, hwnd, level);
720 }
721
722 static HRESULT WINAPI IDirectSound8_IDirectSound_Compact(
723     LPDIRECTSOUND iface)
724 {
725     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
726     TRACE("(%p)\n", This);
727     return DirectSoundDevice_Compact(((IDirectSoundImpl *)This->pds)->device);
728 }
729
730 static HRESULT WINAPI IDirectSound8_IDirectSound_GetSpeakerConfig(
731     LPDIRECTSOUND iface,
732     LPDWORD lpdwSpeakerConfig)
733 {
734     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
735     TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
736     return DirectSoundDevice_GetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,lpdwSpeakerConfig);
737 }
738
739 static HRESULT WINAPI IDirectSound8_IDirectSound_SetSpeakerConfig(
740     LPDIRECTSOUND iface,
741     DWORD config)
742 {
743     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
744     TRACE("(%p,0x%08x)\n",This,config);
745     return DirectSoundDevice_SetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,config);
746 }
747
748 static HRESULT WINAPI IDirectSound8_IDirectSound_Initialize(
749     LPDIRECTSOUND iface,
750     LPCGUID lpcGuid)
751 {
752     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
753     TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
754     return DirectSoundDevice_Initialize(&((IDirectSoundImpl *)This->pds)->device,lpcGuid);
755 }
756
757 static const IDirectSoundVtbl DirectSound8_DirectSound_Vtbl =
758 {
759     IDirectSound8_IDirectSound_QueryInterface,
760     IDirectSound8_IDirectSound_AddRef,
761     IDirectSound8_IDirectSound_Release,
762     IDirectSound8_IDirectSound_CreateSoundBuffer,
763     IDirectSound8_IDirectSound_GetCaps,
764     IDirectSound8_IDirectSound_DuplicateSoundBuffer,
765     IDirectSound8_IDirectSound_SetCooperativeLevel,
766     IDirectSound8_IDirectSound_Compact,
767     IDirectSound8_IDirectSound_GetSpeakerConfig,
768     IDirectSound8_IDirectSound_SetSpeakerConfig,
769     IDirectSound8_IDirectSound_Initialize
770 };
771
772 static HRESULT IDirectSound8_IDirectSound_Create(
773     LPDIRECTSOUND8 pds,
774     LPDIRECTSOUND * ppds)
775 {
776     IDirectSound8_IDirectSound * pdsds;
777     TRACE("(%p,%p)\n",pds,ppds);
778
779     if (ppds == NULL) {
780         ERR("invalid parameter: ppds == NULL\n");
781         return DSERR_INVALIDPARAM;
782     }
783
784     if (pds == NULL) {
785         ERR("invalid parameter: pds == NULL\n");
786         *ppds = NULL;
787         return DSERR_INVALIDPARAM;
788     }
789
790     pdsds = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsds));
791     if (pdsds == NULL) {
792         WARN("out of memory\n");
793         *ppds = NULL;
794         return DSERR_OUTOFMEMORY;
795     }
796
797     pdsds->lpVtbl = &DirectSound8_DirectSound_Vtbl;
798     pdsds->ref = 0;
799     pdsds->pds = pds;
800
801     IDirectSoundImpl_AddRef(pds);
802     *ppds = (LPDIRECTSOUND)pdsds;
803
804     return DS_OK;
805 }
806
807 /*******************************************************************************
808  *              IDirectSound8_IDirectSound8
809  */
810 static HRESULT WINAPI IDirectSound8_IDirectSound8_QueryInterface(
811     LPDIRECTSOUND8 iface,
812     REFIID riid,
813     LPVOID * ppobj)
814 {
815     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
816     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
817     return DSOUND_QueryInterface8(This->pds, riid, ppobj);
818 }
819
820 static ULONG WINAPI IDirectSound8_IDirectSound8_AddRef(
821     LPDIRECTSOUND8 iface)
822 {
823     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
824     ULONG ref = InterlockedIncrement(&(This->ref));
825     TRACE("(%p) ref was %d\n", This, ref - 1);
826     return ref;
827 }
828
829 static ULONG WINAPI IDirectSound8_IDirectSound8_Release(
830     LPDIRECTSOUND8 iface)
831 {
832     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
833     ULONG ref = InterlockedDecrement(&(This->ref));
834     TRACE("(%p) ref was %d\n", This, ref + 1);
835     if (!ref) {
836         IDirectSoundImpl_Release(This->pds);
837         HeapFree(GetProcessHeap(), 0, This);
838         TRACE("(%p) released\n", This);
839     }
840     return ref;
841 }
842
843 static HRESULT WINAPI IDirectSound8_IDirectSound8_CreateSoundBuffer(
844     LPDIRECTSOUND8 iface,
845     LPCDSBUFFERDESC dsbd,
846     LPLPDIRECTSOUNDBUFFER ppdsb,
847     LPUNKNOWN lpunk)
848 {
849     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
850     TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
851     return DirectSoundDevice_CreateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,dsbd,ppdsb,lpunk,TRUE);
852 }
853
854 static HRESULT WINAPI IDirectSound8_IDirectSound8_GetCaps(
855     LPDIRECTSOUND8 iface,
856     LPDSCAPS lpDSCaps)
857 {
858     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
859     TRACE("(%p,%p)\n",This,lpDSCaps);
860     return DirectSoundDevice_GetCaps(((IDirectSoundImpl *)This->pds)->device, lpDSCaps);
861 }
862
863 static HRESULT WINAPI IDirectSound8_IDirectSound8_DuplicateSoundBuffer(
864     LPDIRECTSOUND8 iface,
865     LPDIRECTSOUNDBUFFER psb,
866     LPLPDIRECTSOUNDBUFFER ppdsb)
867 {
868     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
869     TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
870     return DirectSoundDevice_DuplicateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,psb,ppdsb);
871 }
872
873 static HRESULT WINAPI IDirectSound8_IDirectSound8_SetCooperativeLevel(
874     LPDIRECTSOUND8 iface,
875     HWND hwnd,
876     DWORD level)
877 {
878     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
879     TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level));
880     return DirectSoundDevice_SetCooperativeLevel(((IDirectSoundImpl *)This->pds)->device, hwnd, level);
881 }
882
883 static HRESULT WINAPI IDirectSound8_IDirectSound8_Compact(
884     LPDIRECTSOUND8 iface)
885 {
886     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
887     TRACE("(%p)\n", This);
888     return DirectSoundDevice_Compact(((IDirectSoundImpl *)This->pds)->device);
889 }
890
891 static HRESULT WINAPI IDirectSound8_IDirectSound8_GetSpeakerConfig(
892     LPDIRECTSOUND8 iface,
893     LPDWORD lpdwSpeakerConfig)
894 {
895     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
896     TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
897     return DirectSoundDevice_GetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,lpdwSpeakerConfig);
898 }
899
900 static HRESULT WINAPI IDirectSound8_IDirectSound8_SetSpeakerConfig(
901     LPDIRECTSOUND8 iface,
902     DWORD config)
903 {
904     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
905     TRACE("(%p,0x%08x)\n",This,config);
906     return DirectSoundDevice_SetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,config);
907 }
908
909 static HRESULT WINAPI IDirectSound8_IDirectSound8_Initialize(
910     LPDIRECTSOUND8 iface,
911     LPCGUID lpcGuid)
912 {
913     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
914     TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
915     return DirectSoundDevice_Initialize(&((IDirectSoundImpl *)This->pds)->device,lpcGuid);
916 }
917
918 static HRESULT WINAPI IDirectSound8_IDirectSound8_VerifyCertification(
919     LPDIRECTSOUND8 iface,
920     LPDWORD pdwCertified)
921 {
922     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
923     TRACE("(%p, %p)\n", This, pdwCertified);
924     return DirectSoundDevice_VerifyCertification(((IDirectSoundImpl *)This->pds)->device,pdwCertified);
925 }
926
927 static const IDirectSound8Vtbl DirectSound8_DirectSound8_Vtbl =
928 {
929     IDirectSound8_IDirectSound8_QueryInterface,
930     IDirectSound8_IDirectSound8_AddRef,
931     IDirectSound8_IDirectSound8_Release,
932     IDirectSound8_IDirectSound8_CreateSoundBuffer,
933     IDirectSound8_IDirectSound8_GetCaps,
934     IDirectSound8_IDirectSound8_DuplicateSoundBuffer,
935     IDirectSound8_IDirectSound8_SetCooperativeLevel,
936     IDirectSound8_IDirectSound8_Compact,
937     IDirectSound8_IDirectSound8_GetSpeakerConfig,
938     IDirectSound8_IDirectSound8_SetSpeakerConfig,
939     IDirectSound8_IDirectSound8_Initialize,
940     IDirectSound8_IDirectSound8_VerifyCertification
941 };
942
943 static HRESULT IDirectSound8_IDirectSound8_Create(
944     LPDIRECTSOUND8 pds,
945     LPDIRECTSOUND8 * ppds)
946 {
947     IDirectSound8_IDirectSound8 * pdsds;
948     TRACE("(%p,%p)\n",pds,ppds);
949
950     if (ppds == NULL) {
951         ERR("invalid parameter: ppds == NULL\n");
952         return DSERR_INVALIDPARAM;
953     }
954
955     if (pds == NULL) {
956         ERR("invalid parameter: pds == NULL\n");
957         *ppds = NULL;
958         return DSERR_INVALIDPARAM;
959     }
960
961     pdsds = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsds));
962     if (pdsds == NULL) {
963         WARN("out of memory\n");
964         *ppds = NULL;
965         return DSERR_OUTOFMEMORY;
966     }
967
968     pdsds->lpVtbl = &DirectSound8_DirectSound8_Vtbl;
969     pdsds->ref = 0;
970     pdsds->pds = pds;
971
972     IDirectSoundImpl_AddRef(pds);
973     *ppds = (LPDIRECTSOUND8)pdsds;
974
975     return DS_OK;
976 }
977
978 HRESULT DSOUND_Create(
979     REFIID riid,
980     LPDIRECTSOUND *ppDS)
981 {
982     LPDIRECTSOUND8 pDS;
983     HRESULT hr;
984     TRACE("(%s, %p)\n", debugstr_guid(riid), ppDS);
985
986     if (!IsEqualIID(riid, &IID_IUnknown) &&
987         !IsEqualIID(riid, &IID_IDirectSound)) {
988         *ppDS = 0;
989         return E_NOINTERFACE;
990     }
991
992     /* Get dsound configuration */
993     setup_dsound_options();
994
995     hr = IDirectSoundImpl_Create(&pDS);
996     if (hr == DS_OK) {
997         hr = IDirectSound_IDirectSound_Create(pDS, ppDS);
998         if (*ppDS)
999             IDirectSound_IDirectSound_AddRef(*ppDS);
1000         else {
1001             WARN("IDirectSound_IDirectSound_Create failed\n");
1002             IDirectSound8_Release(pDS);
1003         }
1004     } else {
1005         WARN("IDirectSoundImpl_Create failed\n");
1006         *ppDS = 0;
1007     }
1008
1009     return hr;
1010 }
1011
1012 /*******************************************************************************
1013  *              DirectSoundCreate (DSOUND.1)
1014  *
1015  *  Creates and initializes a DirectSound interface.
1016  *
1017  *  PARAMS
1018  *     lpcGUID   [I] Address of the GUID that identifies the sound device.
1019  *     ppDS      [O] Address of a variable to receive the interface pointer.
1020  *     pUnkOuter [I] Must be NULL.
1021  *
1022  *  RETURNS
1023  *     Success: DS_OK
1024  *     Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
1025  *              DSERR_NODRIVER, DSERR_OUTOFMEMORY
1026  */
1027 HRESULT WINAPI DirectSoundCreate(
1028     LPCGUID lpcGUID,
1029     LPDIRECTSOUND *ppDS,
1030     IUnknown *pUnkOuter)
1031 {
1032     HRESULT hr;
1033     LPDIRECTSOUND pDS;
1034
1035     TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
1036
1037     if (ppDS == NULL) {
1038         WARN("invalid parameter: ppDS == NULL\n");
1039         return DSERR_INVALIDPARAM;
1040     }
1041
1042     if (pUnkOuter != NULL) {
1043         WARN("invalid parameter: pUnkOuter != NULL\n");
1044         *ppDS = 0;
1045         return DSERR_INVALIDPARAM;
1046     }
1047
1048     hr = DSOUND_Create(&IID_IDirectSound, &pDS);
1049     if (hr == DS_OK) {
1050         hr = IDirectSound_Initialize(pDS, lpcGUID);
1051         if (hr != DS_OK) {
1052             if (hr != DSERR_ALREADYINITIALIZED) {
1053                 IDirectSound_Release(pDS);
1054                 pDS = 0;
1055             } else
1056                 hr = DS_OK;
1057         }
1058     }
1059
1060     *ppDS = pDS;
1061
1062     return hr;
1063 }
1064
1065 HRESULT DSOUND_Create8(
1066     REFIID riid,
1067     LPDIRECTSOUND8 *ppDS)
1068 {
1069     LPDIRECTSOUND8 pDS;
1070     HRESULT hr;
1071     TRACE("(%s, %p)\n", debugstr_guid(riid), ppDS);
1072
1073     if (!IsEqualIID(riid, &IID_IUnknown) &&
1074         !IsEqualIID(riid, &IID_IDirectSound) &&
1075         !IsEqualIID(riid, &IID_IDirectSound8)) {
1076         *ppDS = 0;
1077         return E_NOINTERFACE;
1078     }
1079
1080     /* Get dsound configuration */
1081     setup_dsound_options();
1082
1083     hr = IDirectSoundImpl_Create(&pDS);
1084     if (hr == DS_OK) {
1085         hr = IDirectSound8_IDirectSound8_Create(pDS, ppDS);
1086         if (*ppDS)
1087             IDirectSound8_IDirectSound8_AddRef(*ppDS);
1088         else {
1089             WARN("IDirectSound8_IDirectSound8_Create failed\n");
1090             IDirectSound8_Release(pDS);
1091         }
1092     } else {
1093         WARN("IDirectSoundImpl_Create failed\n");
1094         *ppDS = 0;
1095     }
1096
1097     return hr;
1098 }
1099
1100 /*******************************************************************************
1101  *        DirectSoundCreate8 (DSOUND.11)
1102  *
1103  *  Creates and initializes a DirectSound8 interface.
1104  *
1105  *  PARAMS
1106  *     lpcGUID   [I] Address of the GUID that identifies the sound device.
1107  *     ppDS      [O] Address of a variable to receive the interface pointer.
1108  *     pUnkOuter [I] Must be NULL.
1109  *
1110  *  RETURNS
1111  *     Success: DS_OK
1112  *     Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
1113  *              DSERR_NODRIVER, DSERR_OUTOFMEMORY
1114  */
1115 HRESULT WINAPI DirectSoundCreate8(
1116     LPCGUID lpcGUID,
1117     LPDIRECTSOUND8 *ppDS,
1118     IUnknown *pUnkOuter)
1119 {
1120     HRESULT hr;
1121     LPDIRECTSOUND8 pDS;
1122
1123     TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
1124
1125     if (ppDS == NULL) {
1126         WARN("invalid parameter: ppDS == NULL\n");
1127         return DSERR_INVALIDPARAM;
1128     }
1129
1130     if (pUnkOuter != NULL) {
1131         WARN("invalid parameter: pUnkOuter != NULL\n");
1132         *ppDS = 0;
1133         return DSERR_INVALIDPARAM;
1134     }
1135
1136     hr = DSOUND_Create8(&IID_IDirectSound8, &pDS);
1137     if (hr == DS_OK) {
1138         hr = IDirectSound8_Initialize(pDS, lpcGUID);
1139         if (hr != DS_OK) {
1140             if (hr != DSERR_ALREADYINITIALIZED) {
1141                 IDirectSound8_Release(pDS);
1142                 pDS = 0;
1143             } else
1144                 hr = DS_OK;
1145         }
1146     }
1147
1148     *ppDS = pDS;
1149
1150     return hr;
1151 }
1152
1153 /*******************************************************************************
1154  *        DirectSoundDevice
1155  */
1156 static HRESULT DirectSoundDevice_Create(DirectSoundDevice ** ppDevice)
1157 {
1158     DirectSoundDevice * device;
1159     TRACE("(%p)\n", ppDevice);
1160
1161     /* Allocate memory */
1162     device = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DirectSoundDevice));
1163     if (device == NULL) {
1164         WARN("out of memory\n");
1165         return DSERR_OUTOFMEMORY;
1166     }
1167
1168     device->ref            = 1;
1169     device->priolevel      = DSSCL_NORMAL;
1170     device->state          = STATE_STOPPED;
1171     device->speaker_config = DSSPEAKER_STEREO | (DSSPEAKER_GEOMETRY_NARROW << 16);
1172
1173     /* 3D listener initial parameters */
1174     device->ds3dl.dwSize   = sizeof(DS3DLISTENER);
1175     device->ds3dl.vPosition.x = 0.0;
1176     device->ds3dl.vPosition.y = 0.0;
1177     device->ds3dl.vPosition.z = 0.0;
1178     device->ds3dl.vVelocity.x = 0.0;
1179     device->ds3dl.vVelocity.y = 0.0;
1180     device->ds3dl.vVelocity.z = 0.0;
1181     device->ds3dl.vOrientFront.x = 0.0;
1182     device->ds3dl.vOrientFront.y = 0.0;
1183     device->ds3dl.vOrientFront.z = 1.0;
1184     device->ds3dl.vOrientTop.x = 0.0;
1185     device->ds3dl.vOrientTop.y = 1.0;
1186     device->ds3dl.vOrientTop.z = 0.0;
1187     device->ds3dl.flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
1188     device->ds3dl.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
1189     device->ds3dl.flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
1190
1191     device->prebuf = ds_snd_queue_max;
1192     device->guid = GUID_NULL;
1193
1194     /* Set default wave format (may need it for waveOutOpen) */
1195     device->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(WAVEFORMATEX));
1196     if (device->pwfx == NULL) {
1197         WARN("out of memory\n");
1198         HeapFree(GetProcessHeap(),0,device);
1199         return DSERR_OUTOFMEMORY;
1200     }
1201
1202     /* We rely on the sound driver to return the actual sound format of
1203      * the device if it does not support 22050x8x2 and is given the
1204      * WAVE_DIRECTSOUND flag.
1205      */
1206     device->pwfx->wFormatTag = WAVE_FORMAT_PCM;
1207     device->pwfx->nSamplesPerSec = ds_default_sample_rate;
1208     device->pwfx->wBitsPerSample = ds_default_bits_per_sample;
1209     device->pwfx->nChannels = 2;
1210     device->pwfx->nBlockAlign = device->pwfx->wBitsPerSample * device->pwfx->nChannels / 8;
1211     device->pwfx->nAvgBytesPerSec = device->pwfx->nSamplesPerSec * device->pwfx->nBlockAlign;
1212     device->pwfx->cbSize = 0;
1213
1214     InitializeCriticalSection(&(device->mixlock));
1215     device->mixlock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DirectSoundDevice.mixlock");
1216
1217     RtlInitializeResource(&(device->buffer_list_lock));
1218
1219    *ppDevice = device;
1220
1221     return DS_OK;
1222 }
1223
1224 static ULONG DirectSoundDevice_AddRef(DirectSoundDevice * device)
1225 {
1226     ULONG ref = InterlockedIncrement(&(device->ref));
1227     TRACE("(%p) ref was %d\n", device, ref - 1);
1228     return ref;
1229 }
1230
1231 ULONG DirectSoundDevice_Release(DirectSoundDevice * device)
1232 {
1233     HRESULT hr;
1234     ULONG ref = InterlockedDecrement(&(device->ref));
1235     TRACE("(%p) ref was %u\n", device, ref + 1);
1236     if (!ref) {
1237         int i;
1238         timeKillEvent(device->timerID);
1239         timeEndPeriod(DS_TIME_RES);
1240
1241         /* The kill event should have allowed the timer process to expire
1242          * but try to grab the lock just in case. Can't hold lock because
1243          * IDirectSoundBufferImpl_Destroy also grabs the lock */
1244         RtlAcquireResourceShared(&(device->buffer_list_lock), TRUE);
1245         RtlReleaseResource(&(device->buffer_list_lock));
1246
1247         /* It is allowed to release this object even when buffers are playing */
1248         if (device->buffers) {
1249             WARN("%d secondary buffers not released\n", device->nrofbuffers);
1250             for( i=0;i<device->nrofbuffers;i++)
1251                 IDirectSoundBufferImpl_Destroy(device->buffers[i]);
1252         }
1253
1254         if (device->primary) {
1255             WARN("primary buffer not released\n");
1256             IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)device->primary);
1257         }
1258
1259         hr = DSOUND_PrimaryDestroy(device);
1260         if (hr != DS_OK)
1261             WARN("DSOUND_PrimaryDestroy failed\n");
1262
1263         if (device->driver)
1264             IDsDriver_Close(device->driver);
1265
1266         if (device->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN)
1267             waveOutClose(device->hwo);
1268
1269         if (device->driver)
1270             IDsDriver_Release(device->driver);
1271
1272         DSOUND_renderer[device->drvdesc.dnDevNode] = NULL;
1273
1274         HeapFree(GetProcessHeap(),0,device->tmp_buffer);
1275         HeapFree(GetProcessHeap(),0,device->buffer);
1276         RtlDeleteResource(&device->buffer_list_lock);
1277         device->mixlock.DebugInfo->Spare[0] = 0;
1278         DeleteCriticalSection(&device->mixlock);
1279         HeapFree(GetProcessHeap(),0,device);
1280         TRACE("(%p) released\n", device);
1281     }
1282     return ref;
1283 }
1284
1285 HRESULT DirectSoundDevice_GetCaps(
1286     DirectSoundDevice * device,
1287     LPDSCAPS lpDSCaps)
1288 {
1289     TRACE("(%p,%p)\n",device,lpDSCaps);
1290
1291     if (device == NULL) {
1292         WARN("not initialized\n");
1293         return DSERR_UNINITIALIZED;
1294     }
1295
1296     if (lpDSCaps == NULL) {
1297         WARN("invalid parameter: lpDSCaps = NULL\n");
1298         return DSERR_INVALIDPARAM;
1299     }
1300
1301     /* check if there is enough room */
1302     if (lpDSCaps->dwSize < sizeof(*lpDSCaps)) {
1303         WARN("invalid parameter: lpDSCaps->dwSize = %d\n", lpDSCaps->dwSize);
1304         return DSERR_INVALIDPARAM;
1305     }
1306
1307     lpDSCaps->dwFlags                           = device->drvcaps.dwFlags;
1308     if (TRACE_ON(dsound)) {
1309         TRACE("(flags=0x%08x:\n",lpDSCaps->dwFlags);
1310         _dump_DSCAPS(lpDSCaps->dwFlags);
1311         DPRINTF(")\n");
1312     }
1313     lpDSCaps->dwMinSecondarySampleRate          = device->drvcaps.dwMinSecondarySampleRate;
1314     lpDSCaps->dwMaxSecondarySampleRate          = device->drvcaps.dwMaxSecondarySampleRate;
1315     lpDSCaps->dwPrimaryBuffers                  = device->drvcaps.dwPrimaryBuffers;
1316     lpDSCaps->dwMaxHwMixingAllBuffers           = device->drvcaps.dwMaxHwMixingAllBuffers;
1317     lpDSCaps->dwMaxHwMixingStaticBuffers        = device->drvcaps.dwMaxHwMixingStaticBuffers;
1318     lpDSCaps->dwMaxHwMixingStreamingBuffers     = device->drvcaps.dwMaxHwMixingStreamingBuffers;
1319     lpDSCaps->dwFreeHwMixingAllBuffers          = device->drvcaps.dwFreeHwMixingAllBuffers;
1320     lpDSCaps->dwFreeHwMixingStaticBuffers       = device->drvcaps.dwFreeHwMixingStaticBuffers;
1321     lpDSCaps->dwFreeHwMixingStreamingBuffers    = device->drvcaps.dwFreeHwMixingStreamingBuffers;
1322     lpDSCaps->dwMaxHw3DAllBuffers               = device->drvcaps.dwMaxHw3DAllBuffers;
1323     lpDSCaps->dwMaxHw3DStaticBuffers            = device->drvcaps.dwMaxHw3DStaticBuffers;
1324     lpDSCaps->dwMaxHw3DStreamingBuffers         = device->drvcaps.dwMaxHw3DStreamingBuffers;
1325     lpDSCaps->dwFreeHw3DAllBuffers              = device->drvcaps.dwFreeHw3DAllBuffers;
1326     lpDSCaps->dwFreeHw3DStaticBuffers           = device->drvcaps.dwFreeHw3DStaticBuffers;
1327     lpDSCaps->dwFreeHw3DStreamingBuffers        = device->drvcaps.dwFreeHw3DStreamingBuffers;
1328     lpDSCaps->dwTotalHwMemBytes                 = device->drvcaps.dwTotalHwMemBytes;
1329     lpDSCaps->dwFreeHwMemBytes                  = device->drvcaps.dwFreeHwMemBytes;
1330     lpDSCaps->dwMaxContigFreeHwMemBytes         = device->drvcaps.dwMaxContigFreeHwMemBytes;
1331
1332     /* driver doesn't have these */
1333     lpDSCaps->dwUnlockTransferRateHwBuffers     = 4096; /* But we have none... */
1334     lpDSCaps->dwPlayCpuOverheadSwBuffers        = 1;    /* 1% */
1335
1336     return DS_OK;
1337 }
1338
1339 HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcGUID)
1340 {
1341     HRESULT hr = DS_OK;
1342     unsigned wod, wodn;
1343     BOOLEAN found = FALSE;
1344     GUID devGUID;
1345     DirectSoundDevice * device = *ppDevice;
1346     TRACE("(%p,%s)\n",ppDevice,debugstr_guid(lpcGUID));
1347
1348     if (*ppDevice != NULL) {
1349         WARN("already initialized\n");
1350         return DSERR_ALREADYINITIALIZED;
1351     }
1352
1353     /* Default device? */
1354     if (!lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL))
1355         lpcGUID = &DSDEVID_DefaultPlayback;
1356
1357     if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
1358         WARN("invalid parameter: lpcGUID\n");
1359         return DSERR_INVALIDPARAM;
1360     }
1361
1362     /* Enumerate WINMM audio devices and find the one we want */
1363     wodn = waveOutGetNumDevs();
1364     if (!wodn) {
1365         WARN("no driver\n");
1366         return DSERR_NODRIVER;
1367     }
1368
1369     for (wod=0; wod<wodn; wod++) {
1370         if (IsEqualGUID( &devGUID, &DSOUND_renderer_guids[wod])) {
1371             found = TRUE;
1372             break;
1373         }
1374     }
1375
1376     if (found == FALSE) {
1377         WARN("No device found matching given ID!\n");
1378         return DSERR_NODRIVER;
1379     }
1380
1381     if (DSOUND_renderer[wod]) {
1382         if (IsEqualGUID(&devGUID, &DSOUND_renderer[wod]->guid)) {
1383             device = DSOUND_renderer[wod];
1384             DirectSoundDevice_AddRef(device);
1385             *ppDevice = device;
1386             return DS_OK;
1387         } else {
1388             ERR("device GUID doesn't match\n");
1389             hr = DSERR_GENERIC;
1390             return hr;
1391         }
1392     } else {
1393         hr = DirectSoundDevice_Create(&device);
1394         if (hr != DS_OK) {
1395             WARN("DirectSoundDevice_Create failed\n");
1396             return hr;
1397         }
1398     }
1399
1400     *ppDevice = device;
1401     device->guid = devGUID;
1402     device->driver = NULL;
1403
1404     device->drvdesc.dnDevNode = wod;
1405     hr = DSOUND_ReopenDevice(device, FALSE);
1406     if (FAILED(hr))
1407     {
1408         WARN("DSOUND_ReopenDevice failed: %08x\n", hr);
1409         return hr;
1410     }
1411
1412     if (device->driver) {
1413         /* the driver is now open, so it's now allowed to call GetCaps */
1414         hr = IDsDriver_GetCaps(device->driver,&(device->drvcaps));
1415         if (hr != DS_OK) {
1416             WARN("IDsDriver_GetCaps failed\n");
1417             return hr;
1418         }
1419     } else {
1420         WAVEOUTCAPSA woc;
1421         hr = mmErr(waveOutGetDevCapsA(device->drvdesc.dnDevNode, &woc, sizeof(woc)));
1422         if (hr != DS_OK) {
1423             WARN("waveOutGetDevCaps failed\n");
1424             return hr;
1425         }
1426         ZeroMemory(&device->drvcaps, sizeof(device->drvcaps));
1427         if ((woc.dwFormats & WAVE_FORMAT_1M08) ||
1428             (woc.dwFormats & WAVE_FORMAT_2M08) ||
1429             (woc.dwFormats & WAVE_FORMAT_4M08) ||
1430             (woc.dwFormats & WAVE_FORMAT_48M08) ||
1431             (woc.dwFormats & WAVE_FORMAT_96M08)) {
1432             device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT;
1433             device->drvcaps.dwFlags |= DSCAPS_PRIMARYMONO;
1434         }
1435         if ((woc.dwFormats & WAVE_FORMAT_1M16) ||
1436             (woc.dwFormats & WAVE_FORMAT_2M16) ||
1437             (woc.dwFormats & WAVE_FORMAT_4M16) ||
1438             (woc.dwFormats & WAVE_FORMAT_48M16) ||
1439             (woc.dwFormats & WAVE_FORMAT_96M16)) {
1440             device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT;
1441             device->drvcaps.dwFlags |= DSCAPS_PRIMARYMONO;
1442         }
1443         if ((woc.dwFormats & WAVE_FORMAT_1S08) ||
1444             (woc.dwFormats & WAVE_FORMAT_2S08) ||
1445             (woc.dwFormats & WAVE_FORMAT_4S08) ||
1446             (woc.dwFormats & WAVE_FORMAT_48S08) ||
1447             (woc.dwFormats & WAVE_FORMAT_96S08)) {
1448             device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT;
1449             device->drvcaps.dwFlags |= DSCAPS_PRIMARYSTEREO;
1450         }
1451         if ((woc.dwFormats & WAVE_FORMAT_1S16) ||
1452             (woc.dwFormats & WAVE_FORMAT_2S16) ||
1453             (woc.dwFormats & WAVE_FORMAT_4S16) ||
1454             (woc.dwFormats & WAVE_FORMAT_48S16) ||
1455             (woc.dwFormats & WAVE_FORMAT_96S16)) {
1456             device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT;
1457             device->drvcaps.dwFlags |= DSCAPS_PRIMARYSTEREO;
1458         }
1459         if (ds_emuldriver)
1460             device->drvcaps.dwFlags |= DSCAPS_EMULDRIVER;
1461         device->drvcaps.dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
1462         device->drvcaps.dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
1463         device->drvcaps.dwPrimaryBuffers = 1;
1464     }
1465
1466     hr = DSOUND_PrimaryCreate(device);
1467     if (hr == DS_OK) {
1468         UINT triggertime = DS_TIME_DEL, res = DS_TIME_RES, id;
1469         TIMECAPS time;
1470
1471         DSOUND_renderer[device->drvdesc.dnDevNode] = device;
1472         timeGetDevCaps(&time, sizeof(TIMECAPS));
1473         TRACE("Minimum timer resolution: %u, max timer: %u\n", time.wPeriodMin, time.wPeriodMax);
1474         if (triggertime < time.wPeriodMin)
1475             triggertime = time.wPeriodMin;
1476         if (res < time.wPeriodMin)
1477             res = time.wPeriodMin;
1478         if (timeBeginPeriod(res) == TIMERR_NOCANDO)
1479             WARN("Could not set minimum resolution, don't expect sound\n");
1480         id = timeSetEvent(triggertime, res, DSOUND_timer, (DWORD_PTR)device, TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
1481         if (!id)
1482         {
1483             WARN("Timer not created! Retrying without TIME_KILL_SYNCHRONOUS\n");
1484             id = timeSetEvent(triggertime, res, DSOUND_timer, (DWORD_PTR)device, TIME_PERIODIC);
1485             if (!id) ERR("Could not create timer, sound playback will not occur\n");
1486         }
1487         DSOUND_renderer[device->drvdesc.dnDevNode]->timerID = id;
1488     } else {
1489         WARN("DSOUND_PrimaryCreate failed\n");
1490     }
1491
1492     return hr;
1493 }
1494
1495 HRESULT DirectSoundDevice_CreateSoundBuffer(
1496     DirectSoundDevice * device,
1497     LPCDSBUFFERDESC dsbd,
1498     LPLPDIRECTSOUNDBUFFER ppdsb,
1499     LPUNKNOWN lpunk,
1500     BOOL from8)
1501 {
1502     HRESULT hres = DS_OK;
1503     TRACE("(%p,%p,%p,%p)\n",device,dsbd,ppdsb,lpunk);
1504
1505     if (device == NULL) {
1506         WARN("not initialized\n");
1507         return DSERR_UNINITIALIZED;
1508     }
1509
1510     if (dsbd == NULL) {
1511         WARN("invalid parameter: dsbd == NULL\n");
1512         return DSERR_INVALIDPARAM;
1513     }
1514
1515     if (dsbd->dwSize != sizeof(DSBUFFERDESC) &&
1516         dsbd->dwSize != sizeof(DSBUFFERDESC1)) {
1517         WARN("invalid parameter: dsbd\n");
1518         return DSERR_INVALIDPARAM;
1519     }
1520
1521     if (ppdsb == NULL) {
1522         WARN("invalid parameter: ppdsb == NULL\n");
1523         return DSERR_INVALIDPARAM;
1524     }
1525
1526     if (TRACE_ON(dsound)) {
1527         TRACE("(structsize=%d)\n",dsbd->dwSize);
1528         TRACE("(flags=0x%08x:\n",dsbd->dwFlags);
1529         _dump_DSBCAPS(dsbd->dwFlags);
1530         DPRINTF(")\n");
1531         TRACE("(bufferbytes=%d)\n",dsbd->dwBufferBytes);
1532         TRACE("(lpwfxFormat=%p)\n",dsbd->lpwfxFormat);
1533     }
1534
1535     if (dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) {
1536         if (dsbd->lpwfxFormat != NULL) {
1537             WARN("invalid parameter: dsbd->lpwfxFormat must be NULL for "
1538                  "primary buffer\n");
1539             return DSERR_INVALIDPARAM;
1540         }
1541
1542         if (device->primary) {
1543             WARN("Primary Buffer already created\n");
1544             IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(device->primary));
1545             *ppdsb = (LPDIRECTSOUNDBUFFER)(device->primary);
1546         } else {
1547            device->dsbd = *dsbd;
1548            device->dsbd.dwFlags &= ~(DSBCAPS_LOCHARDWARE | DSBCAPS_LOCSOFTWARE);
1549            if (device->hwbuf)
1550                device->dsbd.dwFlags |= DSBCAPS_LOCHARDWARE;
1551            else device->dsbd.dwFlags |= DSBCAPS_LOCSOFTWARE;
1552            hres = PrimaryBufferImpl_Create(device, (PrimaryBufferImpl**)&(device->primary), &(device->dsbd));
1553            if (device->primary) {
1554                IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(device->primary));
1555                *ppdsb = (LPDIRECTSOUNDBUFFER)(device->primary);
1556            } else
1557                WARN("PrimaryBufferImpl_Create failed\n");
1558         }
1559     } else {
1560         IDirectSoundBufferImpl * dsb;
1561
1562         if (dsbd->lpwfxFormat == NULL) {
1563             WARN("invalid parameter: dsbd->lpwfxFormat can't be NULL for "
1564                  "secondary buffer\n");
1565             return DSERR_INVALIDPARAM;
1566         }
1567
1568         TRACE("(formattag=0x%04x,chans=%d,samplerate=%d,"
1569               "bytespersec=%d,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
1570               dsbd->lpwfxFormat->wFormatTag, dsbd->lpwfxFormat->nChannels,
1571               dsbd->lpwfxFormat->nSamplesPerSec,
1572               dsbd->lpwfxFormat->nAvgBytesPerSec,
1573               dsbd->lpwfxFormat->nBlockAlign,
1574               dsbd->lpwfxFormat->wBitsPerSample, dsbd->lpwfxFormat->cbSize);
1575
1576         if (from8 && (dsbd->dwFlags & DSBCAPS_CTRL3D) && (dsbd->lpwfxFormat->nChannels != 1)) {
1577             WARN("invalid parameter: 3D buffer format must be mono\n");
1578             return DSERR_INVALIDPARAM;
1579         }
1580
1581         hres = IDirectSoundBufferImpl_Create(device, (IDirectSoundBufferImpl**)&dsb, dsbd);
1582         if (dsb) {
1583             hres = SecondaryBufferImpl_Create(dsb, (SecondaryBufferImpl**)ppdsb);
1584             if (*ppdsb) {
1585                 dsb->secondary = (SecondaryBufferImpl*)*ppdsb;
1586                 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)*ppdsb);
1587             } else
1588                 WARN("SecondaryBufferImpl_Create failed\n");
1589         } else
1590            WARN("IDirectSoundBufferImpl_Create failed\n");
1591    }
1592
1593    return hres;
1594 }
1595
1596 HRESULT DirectSoundDevice_DuplicateSoundBuffer(
1597     DirectSoundDevice * device,
1598     LPDIRECTSOUNDBUFFER psb,
1599     LPLPDIRECTSOUNDBUFFER ppdsb)
1600 {
1601     HRESULT hres = DS_OK;
1602     IDirectSoundBufferImpl* dsb;
1603     TRACE("(%p,%p,%p)\n",device,psb,ppdsb);
1604
1605     if (device == NULL) {
1606         WARN("not initialized\n");
1607         return DSERR_UNINITIALIZED;
1608     }
1609
1610     if (psb == NULL) {
1611         WARN("invalid parameter: psb == NULL\n");
1612         return DSERR_INVALIDPARAM;
1613     }
1614
1615     if (ppdsb == NULL) {
1616         WARN("invalid parameter: ppdsb == NULL\n");
1617         return DSERR_INVALIDPARAM;
1618     }
1619
1620     /* make sure we have a secondary buffer */
1621     if ((PrimaryBufferImpl *)psb == device->primary) {
1622         WARN("trying to duplicate primary buffer\n");
1623         *ppdsb = NULL;
1624         return DSERR_INVALIDCALL;
1625     }
1626
1627     /* duplicate the actual buffer implementation */
1628     hres = IDirectSoundBufferImpl_Duplicate(device, &dsb,
1629                                            ((SecondaryBufferImpl *)psb)->dsb);
1630
1631     if (hres == DS_OK) {
1632         /* create a new secondary buffer using the new implementation */
1633         hres = SecondaryBufferImpl_Create(dsb, (SecondaryBufferImpl**)ppdsb);
1634         if (*ppdsb) {
1635             dsb->secondary = (SecondaryBufferImpl*)*ppdsb;
1636             IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)*ppdsb);
1637         } else {
1638             WARN("SecondaryBufferImpl_Create failed\n");
1639             IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)dsb);
1640             IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER8)dsb);
1641         }
1642     }
1643
1644     return hres;
1645 }
1646
1647 HRESULT DirectSoundDevice_SetCooperativeLevel(
1648     DirectSoundDevice * device,
1649     HWND hwnd,
1650     DWORD level)
1651 {
1652     TRACE("(%p,%p,%s)\n",device,hwnd,dumpCooperativeLevel(level));
1653
1654     if (device == NULL) {
1655         WARN("not initialized\n");
1656         return DSERR_UNINITIALIZED;
1657     }
1658
1659     if (level==DSSCL_PRIORITY || level==DSSCL_EXCLUSIVE) {
1660         WARN("level=%s not fully supported\n",
1661              level==DSSCL_PRIORITY ? "DSSCL_PRIORITY" : "DSSCL_EXCLUSIVE");
1662     }
1663
1664     device->priolevel = level;
1665     return DS_OK;
1666 }
1667
1668 HRESULT DirectSoundDevice_Compact(
1669     DirectSoundDevice * device)
1670 {
1671     TRACE("(%p)\n", device);
1672
1673     if (device == NULL) {
1674         WARN("not initialized\n");
1675         return DSERR_UNINITIALIZED;
1676     }
1677
1678     if (device->priolevel < DSSCL_PRIORITY) {
1679         WARN("incorrect priority level\n");
1680         return DSERR_PRIOLEVELNEEDED;
1681     }
1682
1683     return DS_OK;
1684 }
1685
1686 HRESULT DirectSoundDevice_GetSpeakerConfig(
1687     DirectSoundDevice * device,
1688     LPDWORD lpdwSpeakerConfig)
1689 {
1690     TRACE("(%p, %p)\n", device, lpdwSpeakerConfig);
1691
1692     if (device == NULL) {
1693         WARN("not initialized\n");
1694         return DSERR_UNINITIALIZED;
1695     }
1696
1697     if (lpdwSpeakerConfig == NULL) {
1698         WARN("invalid parameter: lpdwSpeakerConfig == NULL\n");
1699         return DSERR_INVALIDPARAM;
1700     }
1701
1702     WARN("not fully functional\n");
1703     *lpdwSpeakerConfig = device->speaker_config;
1704     return DS_OK;
1705 }
1706
1707 HRESULT DirectSoundDevice_SetSpeakerConfig(
1708     DirectSoundDevice * device,
1709     DWORD config)
1710 {
1711     TRACE("(%p,0x%08x)\n",device,config);
1712
1713     if (device == NULL) {
1714         WARN("not initialized\n");
1715         return DSERR_UNINITIALIZED;
1716     }
1717
1718     device->speaker_config = config;
1719     WARN("not fully functional\n");
1720     return DS_OK;
1721 }
1722
1723 static HRESULT DirectSoundDevice_VerifyCertification(
1724     DirectSoundDevice * device,
1725     LPDWORD pdwCertified)
1726 {
1727     TRACE("(%p, %p)\n",device,pdwCertified);
1728
1729     if (device == NULL) {
1730         WARN("not initialized\n");
1731         return DSERR_UNINITIALIZED;
1732     }
1733
1734     if (device->drvcaps.dwFlags & DSCAPS_CERTIFIED)
1735         *pdwCertified = DS_CERTIFIED;
1736     else
1737         *pdwCertified = DS_UNCERTIFIED;
1738
1739     return DS_OK;
1740 }
1741
1742 /*
1743  * Add secondary buffer to buffer list.
1744  * Gets exclusive access to buffer for writing.
1745  */
1746 HRESULT DirectSoundDevice_AddBuffer(
1747     DirectSoundDevice * device,
1748     IDirectSoundBufferImpl * pDSB)
1749 {
1750     IDirectSoundBufferImpl **newbuffers;
1751     HRESULT hr = DS_OK;
1752
1753     TRACE("(%p, %p)\n", device, pDSB);
1754
1755     RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
1756
1757     if (device->buffers)
1758         newbuffers = HeapReAlloc(GetProcessHeap(),0,device->buffers,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
1759     else
1760         newbuffers = HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
1761
1762     if (newbuffers) {
1763         device->buffers = newbuffers;
1764         device->buffers[device->nrofbuffers] = pDSB;
1765         device->nrofbuffers++;
1766         TRACE("buffer count is now %d\n", device->nrofbuffers);
1767     } else {
1768         ERR("out of memory for buffer list! Current buffer count is %d\n", device->nrofbuffers);
1769         hr = DSERR_OUTOFMEMORY;
1770     }
1771
1772     RtlReleaseResource(&(device->buffer_list_lock));
1773
1774     return hr;
1775 }
1776
1777 /*
1778  * Remove secondary buffer from buffer list.
1779  * Gets exclusive access to buffer for writing.
1780  */
1781 HRESULT DirectSoundDevice_RemoveBuffer(
1782     DirectSoundDevice * device,
1783     IDirectSoundBufferImpl * pDSB)
1784 {
1785     int i;
1786     HRESULT hr = DS_OK;
1787
1788     TRACE("(%p, %p)\n", device, pDSB);
1789
1790     RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
1791
1792     for (i = 0; i < device->nrofbuffers; i++)
1793         if (device->buffers[i] == pDSB)
1794             break;
1795
1796     if (i < device->nrofbuffers) {
1797         /* Put the last buffer of the list in the (now empty) position */
1798         device->buffers[i] = device->buffers[device->nrofbuffers - 1];
1799         device->nrofbuffers--;
1800         device->buffers = HeapReAlloc(GetProcessHeap(),0,device->buffers,sizeof(LPDIRECTSOUNDBUFFER8)*device->nrofbuffers);
1801         TRACE("buffer count is now %d\n", device->nrofbuffers);
1802     }
1803
1804     if (device->nrofbuffers == 0) {
1805         HeapFree(GetProcessHeap(),0,device->buffers);
1806         device->buffers = NULL;
1807     }
1808
1809     RtlReleaseResource(&(device->buffer_list_lock));
1810
1811     return hr;
1812 }