mcicda: Exclude unused headers.
[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_IDirectSound8)) {
1075         *ppDS = 0;
1076         return E_NOINTERFACE;
1077     }
1078
1079     /* Get dsound configuration */
1080     setup_dsound_options();
1081
1082     hr = IDirectSoundImpl_Create(&pDS);
1083     if (hr == DS_OK) {
1084         hr = IDirectSound8_IDirectSound8_Create(pDS, ppDS);
1085         if (*ppDS)
1086             IDirectSound8_IDirectSound8_AddRef(*ppDS);
1087         else {
1088             WARN("IDirectSound8_IDirectSound8_Create failed\n");
1089             IDirectSound8_Release(pDS);
1090         }
1091     } else {
1092         WARN("IDirectSoundImpl_Create failed\n");
1093         *ppDS = 0;
1094     }
1095
1096     return hr;
1097 }
1098
1099 /*******************************************************************************
1100  *        DirectSoundCreate8 (DSOUND.11)
1101  *
1102  *  Creates and initializes a DirectSound8 interface.
1103  *
1104  *  PARAMS
1105  *     lpcGUID   [I] Address of the GUID that identifies the sound device.
1106  *     ppDS      [O] Address of a variable to receive the interface pointer.
1107  *     pUnkOuter [I] Must be NULL.
1108  *
1109  *  RETURNS
1110  *     Success: DS_OK
1111  *     Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
1112  *              DSERR_NODRIVER, DSERR_OUTOFMEMORY
1113  */
1114 HRESULT WINAPI DirectSoundCreate8(
1115     LPCGUID lpcGUID,
1116     LPDIRECTSOUND8 *ppDS,
1117     IUnknown *pUnkOuter)
1118 {
1119     HRESULT hr;
1120     LPDIRECTSOUND8 pDS;
1121
1122     TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
1123
1124     if (ppDS == NULL) {
1125         WARN("invalid parameter: ppDS == NULL\n");
1126         return DSERR_INVALIDPARAM;
1127     }
1128
1129     if (pUnkOuter != NULL) {
1130         WARN("invalid parameter: pUnkOuter != NULL\n");
1131         *ppDS = 0;
1132         return DSERR_INVALIDPARAM;
1133     }
1134
1135     hr = DSOUND_Create8(&IID_IDirectSound8, &pDS);
1136     if (hr == DS_OK) {
1137         hr = IDirectSound8_Initialize(pDS, lpcGUID);
1138         if (hr != DS_OK) {
1139             if (hr != DSERR_ALREADYINITIALIZED) {
1140                 IDirectSound8_Release(pDS);
1141                 pDS = 0;
1142             } else
1143                 hr = DS_OK;
1144         }
1145     }
1146
1147     *ppDS = pDS;
1148
1149     return hr;
1150 }
1151
1152 /*******************************************************************************
1153  *        DirectSoundDevice
1154  */
1155 static HRESULT DirectSoundDevice_Create(DirectSoundDevice ** ppDevice)
1156 {
1157     DirectSoundDevice * device;
1158     TRACE("(%p)\n", ppDevice);
1159
1160     /* Allocate memory */
1161     device = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DirectSoundDevice));
1162     if (device == NULL) {
1163         WARN("out of memory\n");
1164         return DSERR_OUTOFMEMORY;
1165     }
1166
1167     device->ref            = 1;
1168     device->driver         = NULL;
1169     device->priolevel      = DSSCL_NORMAL;
1170     device->fraglen        = 0;
1171     device->hwbuf          = NULL;
1172     device->buffer         = NULL;
1173     device->buflen         = 0;
1174     device->writelead      = 0;
1175     device->state          = STATE_STOPPED;
1176     device->nrofbuffers    = 0;
1177     device->buffers        = NULL;
1178     device->primary        = NULL;
1179     device->speaker_config = DSSPEAKER_STEREO | (DSSPEAKER_GEOMETRY_NARROW << 16);
1180     device->tmp_buffer     = NULL;
1181     device->tmp_buffer_len = 0;
1182
1183     /* 3D listener initial parameters */
1184     device->listener       = NULL;
1185     device->ds3dl.dwSize   = sizeof(DS3DLISTENER);
1186     device->ds3dl.vPosition.x = 0.0;
1187     device->ds3dl.vPosition.y = 0.0;
1188     device->ds3dl.vPosition.z = 0.0;
1189     device->ds3dl.vVelocity.x = 0.0;
1190     device->ds3dl.vVelocity.y = 0.0;
1191     device->ds3dl.vVelocity.z = 0.0;
1192     device->ds3dl.vOrientFront.x = 0.0;
1193     device->ds3dl.vOrientFront.y = 0.0;
1194     device->ds3dl.vOrientFront.z = 1.0;
1195     device->ds3dl.vOrientTop.x = 0.0;
1196     device->ds3dl.vOrientTop.y = 1.0;
1197     device->ds3dl.vOrientTop.z = 0.0;
1198     device->ds3dl.flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
1199     device->ds3dl.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
1200     device->ds3dl.flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
1201
1202     device->prebuf         = ds_snd_queue_max;
1203     device->guid           = GUID_NULL;
1204
1205     /* Set default wave format (may need it for waveOutOpen) */
1206     device->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(WAVEFORMATEX));
1207     if (device->pwfx == NULL) {
1208         WARN("out of memory\n");
1209         HeapFree(GetProcessHeap(),0,device);
1210         return DSERR_OUTOFMEMORY;
1211     }
1212
1213     /* We rely on the sound driver to return the actual sound format of
1214      * the device if it does not support 22050x8x2 and is given the
1215      * WAVE_DIRECTSOUND flag.
1216      */
1217     device->pwfx->wFormatTag = WAVE_FORMAT_PCM;
1218     device->pwfx->nSamplesPerSec = ds_default_sample_rate;
1219     device->pwfx->wBitsPerSample = ds_default_bits_per_sample;
1220     device->pwfx->nChannels = 2;
1221     device->pwfx->nBlockAlign = device->pwfx->wBitsPerSample * device->pwfx->nChannels / 8;
1222     device->pwfx->nAvgBytesPerSec = device->pwfx->nSamplesPerSec * device->pwfx->nBlockAlign;
1223     device->pwfx->cbSize = 0;
1224
1225     InitializeCriticalSection(&(device->mixlock));
1226     device->mixlock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DirectSoundDevice.mixlock");
1227
1228     RtlInitializeResource(&(device->buffer_list_lock));
1229
1230    *ppDevice = device;
1231
1232     return DS_OK;
1233 }
1234
1235 static ULONG DirectSoundDevice_AddRef(DirectSoundDevice * device)
1236 {
1237     ULONG ref = InterlockedIncrement(&(device->ref));
1238     TRACE("(%p) ref was %d\n", device, ref - 1);
1239     return ref;
1240 }
1241
1242 ULONG DirectSoundDevice_Release(DirectSoundDevice * device)
1243 {
1244     HRESULT hr;
1245     ULONG ref = InterlockedDecrement(&(device->ref));
1246     TRACE("(%p) ref was %u\n", device, ref + 1);
1247     if (!ref) {
1248         int i;
1249         timeKillEvent(device->timerID);
1250         timeEndPeriod(DS_TIME_RES);
1251         /* wait for timer to expire */
1252         Sleep(DS_TIME_RES+1);
1253
1254         /* The sleep above should have allowed the timer process to expire
1255          * but try to grab the lock just in case. Can't hold lock because
1256          * IDirectSoundBufferImpl_Destroy also grabs the lock */
1257         RtlAcquireResourceShared(&(device->buffer_list_lock), TRUE);
1258         RtlReleaseResource(&(device->buffer_list_lock));
1259
1260         /* It is allowed to release this object even when buffers are playing */
1261         if (device->buffers) {
1262             WARN("%d secondary buffers not released\n", device->nrofbuffers);
1263             for( i=0;i<device->nrofbuffers;i++)
1264                 IDirectSoundBufferImpl_Destroy(device->buffers[i]);
1265         }
1266
1267         if (device->primary) {
1268             WARN("primary buffer not released\n");
1269             IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)device->primary);
1270         }
1271
1272         hr = DSOUND_PrimaryDestroy(device);
1273         if (hr != DS_OK)
1274             WARN("DSOUND_PrimaryDestroy failed\n");
1275
1276         if (device->driver)
1277             IDsDriver_Close(device->driver);
1278
1279         if (device->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN)
1280             waveOutClose(device->hwo);
1281
1282         if (device->driver)
1283             IDsDriver_Release(device->driver);
1284
1285         DSOUND_renderer[device->drvdesc.dnDevNode] = NULL;
1286
1287         HeapFree(GetProcessHeap(),0,device->tmp_buffer);
1288         HeapFree(GetProcessHeap(),0,device->buffer);
1289         RtlDeleteResource(&device->buffer_list_lock);
1290         device->mixlock.DebugInfo->Spare[0] = 0;
1291         DeleteCriticalSection(&device->mixlock);
1292         HeapFree(GetProcessHeap(),0,device);
1293         TRACE("(%p) released\n", device);
1294     }
1295     return ref;
1296 }
1297
1298 HRESULT DirectSoundDevice_GetCaps(
1299     DirectSoundDevice * device,
1300     LPDSCAPS lpDSCaps)
1301 {
1302     TRACE("(%p,%p)\n",device,lpDSCaps);
1303
1304     if (device == NULL) {
1305         WARN("not initialized\n");
1306         return DSERR_UNINITIALIZED;
1307     }
1308
1309     if (lpDSCaps == NULL) {
1310         WARN("invalid parameter: lpDSCaps = NULL\n");
1311         return DSERR_INVALIDPARAM;
1312     }
1313
1314     /* check if there is enough room */
1315     if (lpDSCaps->dwSize < sizeof(*lpDSCaps)) {
1316         WARN("invalid parameter: lpDSCaps->dwSize = %d\n", lpDSCaps->dwSize);
1317         return DSERR_INVALIDPARAM;
1318     }
1319
1320     lpDSCaps->dwFlags                           = device->drvcaps.dwFlags;
1321     if (TRACE_ON(dsound)) {
1322         TRACE("(flags=0x%08x:\n",lpDSCaps->dwFlags);
1323         _dump_DSCAPS(lpDSCaps->dwFlags);
1324         DPRINTF(")\n");
1325     }
1326     lpDSCaps->dwMinSecondarySampleRate          = device->drvcaps.dwMinSecondarySampleRate;
1327     lpDSCaps->dwMaxSecondarySampleRate          = device->drvcaps.dwMaxSecondarySampleRate;
1328     lpDSCaps->dwPrimaryBuffers                  = device->drvcaps.dwPrimaryBuffers;
1329     lpDSCaps->dwMaxHwMixingAllBuffers           = device->drvcaps.dwMaxHwMixingAllBuffers;
1330     lpDSCaps->dwMaxHwMixingStaticBuffers        = device->drvcaps.dwMaxHwMixingStaticBuffers;
1331     lpDSCaps->dwMaxHwMixingStreamingBuffers     = device->drvcaps.dwMaxHwMixingStreamingBuffers;
1332     lpDSCaps->dwFreeHwMixingAllBuffers          = device->drvcaps.dwFreeHwMixingAllBuffers;
1333     lpDSCaps->dwFreeHwMixingStaticBuffers       = device->drvcaps.dwFreeHwMixingStaticBuffers;
1334     lpDSCaps->dwFreeHwMixingStreamingBuffers    = device->drvcaps.dwFreeHwMixingStreamingBuffers;
1335     lpDSCaps->dwMaxHw3DAllBuffers               = device->drvcaps.dwMaxHw3DAllBuffers;
1336     lpDSCaps->dwMaxHw3DStaticBuffers            = device->drvcaps.dwMaxHw3DStaticBuffers;
1337     lpDSCaps->dwMaxHw3DStreamingBuffers         = device->drvcaps.dwMaxHw3DStreamingBuffers;
1338     lpDSCaps->dwFreeHw3DAllBuffers              = device->drvcaps.dwFreeHw3DAllBuffers;
1339     lpDSCaps->dwFreeHw3DStaticBuffers           = device->drvcaps.dwFreeHw3DStaticBuffers;
1340     lpDSCaps->dwFreeHw3DStreamingBuffers        = device->drvcaps.dwFreeHw3DStreamingBuffers;
1341     lpDSCaps->dwTotalHwMemBytes                 = device->drvcaps.dwTotalHwMemBytes;
1342     lpDSCaps->dwFreeHwMemBytes                  = device->drvcaps.dwFreeHwMemBytes;
1343     lpDSCaps->dwMaxContigFreeHwMemBytes         = device->drvcaps.dwMaxContigFreeHwMemBytes;
1344
1345     /* driver doesn't have these */
1346     lpDSCaps->dwUnlockTransferRateHwBuffers     = 4096; /* But we have none... */
1347     lpDSCaps->dwPlayCpuOverheadSwBuffers        = 1;    /* 1% */
1348
1349     return DS_OK;
1350 }
1351
1352 HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcGUID)
1353 {
1354     HRESULT hr = DS_OK;
1355     unsigned wod, wodn;
1356     BOOLEAN found = FALSE;
1357     GUID devGUID;
1358     DirectSoundDevice * device = *ppDevice;
1359     TRACE("(%p,%s)\n",ppDevice,debugstr_guid(lpcGUID));
1360
1361     if (*ppDevice != NULL) {
1362         WARN("already initialized\n");
1363         return DSERR_ALREADYINITIALIZED;
1364     }
1365
1366     /* Default device? */
1367     if (!lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL))
1368         lpcGUID = &DSDEVID_DefaultPlayback;
1369
1370     if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
1371         WARN("invalid parameter: lpcGUID\n");
1372         return DSERR_INVALIDPARAM;
1373     }
1374
1375     /* Enumerate WINMM audio devices and find the one we want */
1376     wodn = waveOutGetNumDevs();
1377     if (!wodn) {
1378         WARN("no driver\n");
1379         return DSERR_NODRIVER;
1380     }
1381
1382     for (wod=0; wod<wodn; wod++) {
1383         if (IsEqualGUID( &devGUID, &DSOUND_renderer_guids[wod])) {
1384             found = TRUE;
1385             break;
1386         }
1387     }
1388
1389     if (found == FALSE) {
1390         WARN("No device found matching given ID!\n");
1391         return DSERR_NODRIVER;
1392     }
1393
1394     if (DSOUND_renderer[wod]) {
1395         if (IsEqualGUID(&devGUID, &DSOUND_renderer[wod]->guid)) {
1396             device = DSOUND_renderer[wod];
1397             DirectSoundDevice_AddRef(device);
1398             *ppDevice = device;
1399             return DS_OK;
1400         } else {
1401             ERR("device GUID doesn't match\n");
1402             hr = DSERR_GENERIC;
1403             return hr;
1404         }
1405     } else {
1406         hr = DirectSoundDevice_Create(&device);
1407         if (hr != DS_OK) {
1408             WARN("DirectSoundDevice_Create failed\n");
1409             return hr;
1410         }
1411     }
1412
1413     *ppDevice = device;
1414     device->guid = devGUID;
1415
1416     /* DRV_QUERYDSOUNDIFACE is a "Wine extension" to get the DSound interface */
1417     waveOutMessage((HWAVEOUT)wod, DRV_QUERYDSOUNDIFACE, (DWORD_PTR)&device->driver, 0);
1418
1419     /* Disable the direct sound driver to force emulation if requested. */
1420     if (ds_hw_accel == DS_HW_ACCEL_EMULATION)
1421         device->driver = NULL;
1422
1423     /* Get driver description */
1424     if (device->driver) {
1425         hr = IDsDriver_GetDriverDesc(device->driver,&(device->drvdesc));
1426         if (hr != DS_OK) {
1427             WARN("IDsDriver_GetDriverDesc failed\n");
1428             return hr;
1429         }
1430     } else {
1431         /* if no DirectSound interface available, use WINMM API instead */
1432         device->drvdesc.dwFlags = DSDDESC_DOMMSYSTEMOPEN | DSDDESC_DOMMSYSTEMSETFORMAT;
1433     }
1434
1435     device->drvdesc.dnDevNode = wod;
1436
1437     /* If the driver requests being opened through MMSYSTEM
1438      * (which is recommended by the DDK), it is supposed to happen
1439      * before the DirectSound interface is opened */
1440     if (device->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN)
1441     {
1442         DWORD flags = CALLBACK_FUNCTION;
1443
1444         /* disable direct sound if requested */
1445         if (ds_hw_accel != DS_HW_ACCEL_EMULATION)
1446             flags |= WAVE_DIRECTSOUND;
1447
1448         hr = mmErr(waveOutOpen(&(device->hwo),
1449                                 device->drvdesc.dnDevNode, device->pwfx,
1450                                 (DWORD_PTR)DSOUND_callback, (DWORD)device,
1451                                 flags));
1452         if (hr != DS_OK) {
1453             WARN("waveOutOpen failed\n");
1454             return hr;
1455         }
1456     }
1457
1458     if (device->driver) {
1459         hr = IDsDriver_Open(device->driver);
1460         if (hr != DS_OK) {
1461             WARN("IDsDriver_Open failed\n");
1462             return hr;
1463         }
1464
1465         /* the driver is now open, so it's now allowed to call GetCaps */
1466         hr = IDsDriver_GetCaps(device->driver,&(device->drvcaps));
1467         if (hr != DS_OK) {
1468             WARN("IDsDriver_GetCaps failed\n");
1469             return hr;
1470         }
1471     } else {
1472         WAVEOUTCAPSA woc;
1473         hr = mmErr(waveOutGetDevCapsA(device->drvdesc.dnDevNode, &woc, sizeof(woc)));
1474         if (hr != DS_OK) {
1475             WARN("waveOutGetDevCaps failed\n");
1476             return hr;
1477         }
1478         ZeroMemory(&device->drvcaps, sizeof(device->drvcaps));
1479         if ((woc.dwFormats & WAVE_FORMAT_1M08) ||
1480             (woc.dwFormats & WAVE_FORMAT_2M08) ||
1481             (woc.dwFormats & WAVE_FORMAT_4M08) ||
1482             (woc.dwFormats & WAVE_FORMAT_48M08) ||
1483             (woc.dwFormats & WAVE_FORMAT_96M08)) {
1484             device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT;
1485             device->drvcaps.dwFlags |= DSCAPS_PRIMARYMONO;
1486         }
1487         if ((woc.dwFormats & WAVE_FORMAT_1M16) ||
1488             (woc.dwFormats & WAVE_FORMAT_2M16) ||
1489             (woc.dwFormats & WAVE_FORMAT_4M16) ||
1490             (woc.dwFormats & WAVE_FORMAT_48M16) ||
1491             (woc.dwFormats & WAVE_FORMAT_96M16)) {
1492             device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT;
1493             device->drvcaps.dwFlags |= DSCAPS_PRIMARYMONO;
1494         }
1495         if ((woc.dwFormats & WAVE_FORMAT_1S08) ||
1496             (woc.dwFormats & WAVE_FORMAT_2S08) ||
1497             (woc.dwFormats & WAVE_FORMAT_4S08) ||
1498             (woc.dwFormats & WAVE_FORMAT_48S08) ||
1499             (woc.dwFormats & WAVE_FORMAT_96S08)) {
1500             device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT;
1501             device->drvcaps.dwFlags |= DSCAPS_PRIMARYSTEREO;
1502         }
1503         if ((woc.dwFormats & WAVE_FORMAT_1S16) ||
1504             (woc.dwFormats & WAVE_FORMAT_2S16) ||
1505             (woc.dwFormats & WAVE_FORMAT_4S16) ||
1506             (woc.dwFormats & WAVE_FORMAT_48S16) ||
1507             (woc.dwFormats & WAVE_FORMAT_96S16)) {
1508             device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT;
1509             device->drvcaps.dwFlags |= DSCAPS_PRIMARYSTEREO;
1510         }
1511         if (ds_emuldriver)
1512             device->drvcaps.dwFlags |= DSCAPS_EMULDRIVER;
1513         device->drvcaps.dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
1514         device->drvcaps.dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
1515         device->drvcaps.dwPrimaryBuffers = 1;
1516     }
1517
1518     hr = DSOUND_PrimaryCreate(device);
1519     if (hr == DS_OK) {
1520         DSOUND_renderer[device->drvdesc.dnDevNode] = device;
1521         timeBeginPeriod(DS_TIME_RES);
1522         DSOUND_renderer[device->drvdesc.dnDevNode]->timerID = timeSetEvent(DS_TIME_DEL, DS_TIME_RES, DSOUND_timer,
1523             (DWORD_PTR)DSOUND_renderer[device->drvdesc.dnDevNode], TIME_PERIODIC | TIME_CALLBACK_FUNCTION);
1524     } else {
1525         WARN("DSOUND_PrimaryCreate failed\n");
1526     }
1527
1528     return hr;
1529 }
1530
1531 HRESULT DirectSoundDevice_CreateSoundBuffer(
1532     DirectSoundDevice * device,
1533     LPCDSBUFFERDESC dsbd,
1534     LPLPDIRECTSOUNDBUFFER ppdsb,
1535     LPUNKNOWN lpunk,
1536     BOOL from8)
1537 {
1538     HRESULT hres = DS_OK;
1539     TRACE("(%p,%p,%p,%p)\n",device,dsbd,ppdsb,lpunk);
1540
1541     if (device == NULL) {
1542         WARN("not initialized\n");
1543         return DSERR_UNINITIALIZED;
1544     }
1545
1546     if (dsbd == NULL) {
1547         WARN("invalid parameter: dsbd == NULL\n");
1548         return DSERR_INVALIDPARAM;
1549     }
1550
1551     if (dsbd->dwSize != sizeof(DSBUFFERDESC) &&
1552         dsbd->dwSize != sizeof(DSBUFFERDESC1)) {
1553         WARN("invalid parameter: dsbd\n");
1554         return DSERR_INVALIDPARAM;
1555     }
1556
1557     if (ppdsb == NULL) {
1558         WARN("invalid parameter: ppdsb == NULL\n");
1559         return DSERR_INVALIDPARAM;
1560     }
1561
1562     if (TRACE_ON(dsound)) {
1563         TRACE("(structsize=%d)\n",dsbd->dwSize);
1564         TRACE("(flags=0x%08x:\n",dsbd->dwFlags);
1565         _dump_DSBCAPS(dsbd->dwFlags);
1566         DPRINTF(")\n");
1567         TRACE("(bufferbytes=%d)\n",dsbd->dwBufferBytes);
1568         TRACE("(lpwfxFormat=%p)\n",dsbd->lpwfxFormat);
1569     }
1570
1571     if (dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) {
1572         if (dsbd->lpwfxFormat != NULL) {
1573             WARN("invalid parameter: dsbd->lpwfxFormat must be NULL for "
1574                  "primary buffer\n");
1575             return DSERR_INVALIDPARAM;
1576         }
1577
1578         if (device->primary) {
1579             WARN("Primary Buffer already created\n");
1580             IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(device->primary));
1581             *ppdsb = (LPDIRECTSOUNDBUFFER)(device->primary);
1582         } else {
1583            device->dsbd = *dsbd;
1584            hres = PrimaryBufferImpl_Create(device, (PrimaryBufferImpl**)&(device->primary), &(device->dsbd));
1585            if (device->primary) {
1586                IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(device->primary));
1587                *ppdsb = (LPDIRECTSOUNDBUFFER)(device->primary);
1588            } else
1589                WARN("PrimaryBufferImpl_Create failed\n");
1590         }
1591     } else {
1592         IDirectSoundBufferImpl * dsb;
1593
1594         if (dsbd->lpwfxFormat == NULL) {
1595             WARN("invalid parameter: dsbd->lpwfxFormat can't be NULL for "
1596                  "secondary buffer\n");
1597             return DSERR_INVALIDPARAM;
1598         }
1599
1600         TRACE("(formattag=0x%04x,chans=%d,samplerate=%d,"
1601               "bytespersec=%d,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
1602               dsbd->lpwfxFormat->wFormatTag, dsbd->lpwfxFormat->nChannels,
1603               dsbd->lpwfxFormat->nSamplesPerSec,
1604               dsbd->lpwfxFormat->nAvgBytesPerSec,
1605               dsbd->lpwfxFormat->nBlockAlign,
1606               dsbd->lpwfxFormat->wBitsPerSample, dsbd->lpwfxFormat->cbSize);
1607
1608         if (from8 && (dsbd->dwFlags & DSBCAPS_CTRL3D) && (dsbd->lpwfxFormat->nChannels != 1)) {
1609             WARN("invalid parameter: 3D buffer format must be mono\n");
1610             return DSERR_INVALIDPARAM;
1611         }
1612
1613         hres = IDirectSoundBufferImpl_Create(device, (IDirectSoundBufferImpl**)&dsb, dsbd);
1614         if (dsb) {
1615             hres = SecondaryBufferImpl_Create(dsb, (SecondaryBufferImpl**)ppdsb);
1616             if (*ppdsb) {
1617                 dsb->secondary = (SecondaryBufferImpl*)*ppdsb;
1618                 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)*ppdsb);
1619             } else
1620                 WARN("SecondaryBufferImpl_Create failed\n");
1621         } else
1622            WARN("IDirectSoundBufferImpl_Create failed\n");
1623    }
1624
1625    return hres;
1626 }
1627
1628 HRESULT DirectSoundDevice_DuplicateSoundBuffer(
1629     DirectSoundDevice * device,
1630     LPDIRECTSOUNDBUFFER psb,
1631     LPLPDIRECTSOUNDBUFFER ppdsb)
1632 {
1633     HRESULT hres = DS_OK;
1634     IDirectSoundBufferImpl* dsb;
1635     TRACE("(%p,%p,%p)\n",device,psb,ppdsb);
1636
1637     if (device == NULL) {
1638         WARN("not initialized\n");
1639         return DSERR_UNINITIALIZED;
1640     }
1641
1642     if (psb == NULL) {
1643         WARN("invalid parameter: psb == NULL\n");
1644         return DSERR_INVALIDPARAM;
1645     }
1646
1647     if (ppdsb == NULL) {
1648         WARN("invalid parameter: ppdsb == NULL\n");
1649         return DSERR_INVALIDPARAM;
1650     }
1651
1652     /* make sure we have a secondary buffer */
1653     if ((PrimaryBufferImpl *)psb == device->primary) {
1654         WARN("trying to duplicate primary buffer\n");
1655         *ppdsb = NULL;
1656         return DSERR_INVALIDCALL;
1657     }
1658
1659     /* duplicate the actual buffer implementation */
1660     hres = IDirectSoundBufferImpl_Duplicate(device, &dsb,
1661                                            ((SecondaryBufferImpl *)psb)->dsb);
1662
1663     if (hres == DS_OK) {
1664         /* create a new secondary buffer using the new implementation */
1665         hres = SecondaryBufferImpl_Create(dsb, (SecondaryBufferImpl**)ppdsb);
1666         if (*ppdsb) {
1667             dsb->secondary = (SecondaryBufferImpl*)*ppdsb;
1668             IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)*ppdsb);
1669         } else {
1670             WARN("SecondaryBufferImpl_Create failed\n");
1671             IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)dsb);
1672             IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER8)dsb);
1673         }
1674     }
1675
1676     return hres;
1677 }
1678
1679 HRESULT DirectSoundDevice_SetCooperativeLevel(
1680     DirectSoundDevice * device,
1681     HWND hwnd,
1682     DWORD level)
1683 {
1684     TRACE("(%p,%p,%s)\n",device,hwnd,dumpCooperativeLevel(level));
1685
1686     if (device == NULL) {
1687         WARN("not initialized\n");
1688         return DSERR_UNINITIALIZED;
1689     }
1690
1691     if (level==DSSCL_PRIORITY || level==DSSCL_EXCLUSIVE) {
1692         WARN("level=%s not fully supported\n",
1693              level==DSSCL_PRIORITY ? "DSSCL_PRIORITY" : "DSSCL_EXCLUSIVE");
1694     }
1695
1696     device->priolevel = level;
1697     return DS_OK;
1698 }
1699
1700 HRESULT DirectSoundDevice_Compact(
1701     DirectSoundDevice * device)
1702 {
1703     TRACE("(%p)\n", device);
1704
1705     if (device == NULL) {
1706         WARN("not initialized\n");
1707         return DSERR_UNINITIALIZED;
1708     }
1709
1710     if (device->priolevel != DSSCL_PRIORITY) {
1711         WARN("incorrect priority level\n");
1712         return DSERR_PRIOLEVELNEEDED;
1713     }
1714
1715     return DS_OK;
1716 }
1717
1718 HRESULT DirectSoundDevice_GetSpeakerConfig(
1719     DirectSoundDevice * device,
1720     LPDWORD lpdwSpeakerConfig)
1721 {
1722     TRACE("(%p, %p)\n", device, lpdwSpeakerConfig);
1723
1724     if (device == NULL) {
1725         WARN("not initialized\n");
1726         return DSERR_UNINITIALIZED;
1727     }
1728
1729     if (lpdwSpeakerConfig == NULL) {
1730         WARN("invalid parameter: lpdwSpeakerConfig == NULL\n");
1731         return DSERR_INVALIDPARAM;
1732     }
1733
1734     WARN("not fully functional\n");
1735     *lpdwSpeakerConfig = device->speaker_config;
1736     return DS_OK;
1737 }
1738
1739 HRESULT DirectSoundDevice_SetSpeakerConfig(
1740     DirectSoundDevice * device,
1741     DWORD config)
1742 {
1743     TRACE("(%p,0x%08x)\n",device,config);
1744
1745     if (device == NULL) {
1746         WARN("not initialized\n");
1747         return DSERR_UNINITIALIZED;
1748     }
1749
1750     device->speaker_config = config;
1751     WARN("not fully functional\n");
1752     return DS_OK;
1753 }
1754
1755 static HRESULT DirectSoundDevice_VerifyCertification(
1756     DirectSoundDevice * device,
1757     LPDWORD pdwCertified)
1758 {
1759     TRACE("(%p, %p)\n",device,pdwCertified);
1760
1761     if (device == NULL) {
1762         WARN("not initialized\n");
1763         return DSERR_UNINITIALIZED;
1764     }
1765
1766     if (device->drvcaps.dwFlags & DSCAPS_CERTIFIED)
1767         *pdwCertified = DS_CERTIFIED;
1768     else
1769         *pdwCertified = DS_UNCERTIFIED;
1770
1771     return DS_OK;
1772 }
1773
1774 /*
1775  * Add secondary buffer to buffer list.
1776  * Gets exclusive access to buffer for writing.
1777  */
1778 HRESULT DirectSoundDevice_AddBuffer(
1779     DirectSoundDevice * device,
1780     IDirectSoundBufferImpl * pDSB)
1781 {
1782     IDirectSoundBufferImpl **newbuffers;
1783     HRESULT hr = DS_OK;
1784
1785     TRACE("(%p, %p)\n", device, pDSB);
1786
1787     RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
1788
1789     if (device->buffers)
1790         newbuffers = HeapReAlloc(GetProcessHeap(),0,device->buffers,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
1791     else
1792         newbuffers = HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
1793
1794     if (newbuffers) {
1795         device->buffers = newbuffers;
1796         device->buffers[device->nrofbuffers] = pDSB;
1797         device->nrofbuffers++;
1798         TRACE("buffer count is now %d\n", device->nrofbuffers);
1799     } else {
1800         ERR("out of memory for buffer list! Current buffer count is %d\n", device->nrofbuffers);
1801         hr = DSERR_OUTOFMEMORY;
1802     }
1803
1804     RtlReleaseResource(&(device->buffer_list_lock));
1805
1806     return hr;
1807 }
1808
1809 /*
1810  * Remove secondary buffer from buffer list.
1811  * Gets exclusive access to buffer for writing.
1812  */
1813 HRESULT DirectSoundDevice_RemoveBuffer(
1814     DirectSoundDevice * device,
1815     IDirectSoundBufferImpl * pDSB)
1816 {
1817     int i;
1818     HRESULT hr = DS_OK;
1819
1820     TRACE("(%p, %p)\n", device, pDSB);
1821
1822     RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
1823
1824     for (i = 0; i < device->nrofbuffers; i++)
1825         if (device->buffers[i] == pDSB)
1826             break;
1827
1828     if (i < device->nrofbuffers) {
1829         /* Put the last buffer of the list in the (now empty) position */
1830         device->buffers[i] = device->buffers[device->nrofbuffers - 1];
1831         device->nrofbuffers--;
1832         device->buffers = HeapReAlloc(GetProcessHeap(),0,device->buffers,sizeof(LPDIRECTSOUNDBUFFER8)*device->nrofbuffers);
1833         TRACE("buffer count is now %d\n", device->nrofbuffers);
1834     }
1835
1836     if (device->nrofbuffers == 0) {
1837         HeapFree(GetProcessHeap(),0,device->buffers);
1838         device->buffers = NULL;
1839     }
1840
1841     RtlReleaseResource(&(device->buffer_list_lock));
1842
1843     return hr;
1844 }