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