dsound: Implement DirectSoundEnumerateA on top of DirectSoundEnumerateW.
[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             /* check if cbSize is at least 22 bytes */
1590             if (pwfxe->Format.cbSize < (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)))
1591             {
1592                 WARN("Too small a cbSize %u\n", pwfxe->Format.cbSize);
1593                 return DSERR_INVALIDPARAM;
1594             }
1595
1596             /* cbSize should be 22 bytes, with one possible exception */
1597             if (pwfxe->Format.cbSize > (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)) &&
1598                 !(IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) &&
1599                 pwfxe->Format.cbSize == sizeof(WAVEFORMATEXTENSIBLE)))
1600             {
1601                 WARN("Too big a cbSize %u\n", pwfxe->Format.cbSize);
1602                 return DSERR_CONTROLUNAVAIL;
1603             }
1604
1605             if (!IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))
1606             {
1607                 if (!IsEqualGUID(&pwfxe->SubFormat, &GUID_NULL))
1608                     FIXME("SubFormat %s not supported right now.\n", debugstr_guid(&pwfxe->SubFormat));
1609                 return DSERR_INVALIDPARAM;
1610             }
1611             if (pwfxe->Samples.wValidBitsPerSample > dsbd->lpwfxFormat->wBitsPerSample)
1612             {
1613                 WARN("Samples.wValidBitsPerSample(%d) > Format.wBitsPerSample (%d)\n", pwfxe->Samples.wValidBitsPerSample, pwfxe->Format.wBitsPerSample);
1614                 return DSERR_INVALIDPARAM;
1615             }
1616             if (pwfxe->Samples.wValidBitsPerSample && pwfxe->Samples.wValidBitsPerSample < dsbd->lpwfxFormat->wBitsPerSample)
1617             {
1618                 FIXME("Non-packed formats not supported right now: %d/%d\n", pwfxe->Samples.wValidBitsPerSample, dsbd->lpwfxFormat->wBitsPerSample);
1619                 return DSERR_CONTROLUNAVAIL;
1620             }
1621         }
1622
1623         TRACE("(formattag=0x%04x,chans=%d,samplerate=%d,"
1624               "bytespersec=%d,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
1625               dsbd->lpwfxFormat->wFormatTag, dsbd->lpwfxFormat->nChannels,
1626               dsbd->lpwfxFormat->nSamplesPerSec,
1627               dsbd->lpwfxFormat->nAvgBytesPerSec,
1628               dsbd->lpwfxFormat->nBlockAlign,
1629               dsbd->lpwfxFormat->wBitsPerSample, dsbd->lpwfxFormat->cbSize);
1630
1631         if (from8 && (dsbd->dwFlags & DSBCAPS_CTRL3D) && (dsbd->lpwfxFormat->nChannels != 1)) {
1632             WARN("invalid parameter: 3D buffer format must be mono\n");
1633             return DSERR_INVALIDPARAM;
1634         }
1635
1636         hres = IDirectSoundBufferImpl_Create(device, &dsb, dsbd);
1637         if (dsb) {
1638             hres = SecondaryBufferImpl_Create(dsb, (SecondaryBufferImpl**)ppdsb);
1639             if (*ppdsb) {
1640                 dsb->secondary = (SecondaryBufferImpl*)*ppdsb;
1641                 IDirectSoundBuffer_AddRef(*ppdsb);
1642             } else
1643                 WARN("SecondaryBufferImpl_Create failed\n");
1644         } else
1645            WARN("IDirectSoundBufferImpl_Create failed\n");
1646    }
1647
1648    return hres;
1649 }
1650
1651 HRESULT DirectSoundDevice_DuplicateSoundBuffer(
1652     DirectSoundDevice * device,
1653     LPDIRECTSOUNDBUFFER psb,
1654     LPLPDIRECTSOUNDBUFFER ppdsb)
1655 {
1656     HRESULT hres = DS_OK;
1657     IDirectSoundBufferImpl* dsb;
1658     TRACE("(%p,%p,%p)\n",device,psb,ppdsb);
1659
1660     if (device == NULL) {
1661         WARN("not initialized\n");
1662         return DSERR_UNINITIALIZED;
1663     }
1664
1665     if (psb == NULL) {
1666         WARN("invalid parameter: psb == NULL\n");
1667         return DSERR_INVALIDPARAM;
1668     }
1669
1670     if (ppdsb == NULL) {
1671         WARN("invalid parameter: ppdsb == NULL\n");
1672         return DSERR_INVALIDPARAM;
1673     }
1674
1675     /* make sure we have a secondary buffer */
1676     if ((PrimaryBufferImpl *)psb == device->primary) {
1677         WARN("trying to duplicate primary buffer\n");
1678         *ppdsb = NULL;
1679         return DSERR_INVALIDCALL;
1680     }
1681
1682     /* duplicate the actual buffer implementation */
1683     hres = IDirectSoundBufferImpl_Duplicate(device, &dsb,
1684                                            ((SecondaryBufferImpl *)psb)->dsb);
1685
1686     if (hres == DS_OK) {
1687         /* create a new secondary buffer using the new implementation */
1688         hres = SecondaryBufferImpl_Create(dsb, (SecondaryBufferImpl**)ppdsb);
1689         if (*ppdsb) {
1690             dsb->secondary = (SecondaryBufferImpl*)*ppdsb;
1691             IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)*ppdsb);
1692         } else {
1693             WARN("SecondaryBufferImpl_Create failed\n");
1694             IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)dsb);
1695             IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER8)dsb);
1696         }
1697     }
1698
1699     return hres;
1700 }
1701
1702 HRESULT DirectSoundDevice_SetCooperativeLevel(
1703     DirectSoundDevice * device,
1704     HWND hwnd,
1705     DWORD level)
1706 {
1707     TRACE("(%p,%p,%s)\n",device,hwnd,dumpCooperativeLevel(level));
1708
1709     if (device == NULL) {
1710         WARN("not initialized\n");
1711         return DSERR_UNINITIALIZED;
1712     }
1713
1714     if (level==DSSCL_PRIORITY || level==DSSCL_EXCLUSIVE) {
1715         WARN("level=%s not fully supported\n",
1716              level==DSSCL_PRIORITY ? "DSSCL_PRIORITY" : "DSSCL_EXCLUSIVE");
1717     }
1718
1719     device->priolevel = level;
1720     return DS_OK;
1721 }
1722
1723 HRESULT DirectSoundDevice_Compact(
1724     DirectSoundDevice * device)
1725 {
1726     TRACE("(%p)\n", device);
1727
1728     if (device == NULL) {
1729         WARN("not initialized\n");
1730         return DSERR_UNINITIALIZED;
1731     }
1732
1733     if (device->priolevel < DSSCL_PRIORITY) {
1734         WARN("incorrect priority level\n");
1735         return DSERR_PRIOLEVELNEEDED;
1736     }
1737
1738     return DS_OK;
1739 }
1740
1741 HRESULT DirectSoundDevice_GetSpeakerConfig(
1742     DirectSoundDevice * device,
1743     LPDWORD lpdwSpeakerConfig)
1744 {
1745     TRACE("(%p, %p)\n", device, lpdwSpeakerConfig);
1746
1747     if (device == NULL) {
1748         WARN("not initialized\n");
1749         return DSERR_UNINITIALIZED;
1750     }
1751
1752     if (lpdwSpeakerConfig == NULL) {
1753         WARN("invalid parameter: lpdwSpeakerConfig == NULL\n");
1754         return DSERR_INVALIDPARAM;
1755     }
1756
1757     WARN("not fully functional\n");
1758     *lpdwSpeakerConfig = device->speaker_config;
1759     return DS_OK;
1760 }
1761
1762 HRESULT DirectSoundDevice_SetSpeakerConfig(
1763     DirectSoundDevice * device,
1764     DWORD config)
1765 {
1766     TRACE("(%p,0x%08x)\n",device,config);
1767
1768     if (device == NULL) {
1769         WARN("not initialized\n");
1770         return DSERR_UNINITIALIZED;
1771     }
1772
1773     device->speaker_config = config;
1774     WARN("not fully functional\n");
1775     return DS_OK;
1776 }
1777
1778 static HRESULT DirectSoundDevice_VerifyCertification(
1779     DirectSoundDevice * device,
1780     LPDWORD pdwCertified)
1781 {
1782     TRACE("(%p, %p)\n",device,pdwCertified);
1783
1784     if (device == NULL) {
1785         WARN("not initialized\n");
1786         return DSERR_UNINITIALIZED;
1787     }
1788
1789     if (device->drvcaps.dwFlags & DSCAPS_CERTIFIED)
1790         *pdwCertified = DS_CERTIFIED;
1791     else
1792         *pdwCertified = DS_UNCERTIFIED;
1793
1794     return DS_OK;
1795 }
1796
1797 /*
1798  * Add secondary buffer to buffer list.
1799  * Gets exclusive access to buffer for writing.
1800  */
1801 HRESULT DirectSoundDevice_AddBuffer(
1802     DirectSoundDevice * device,
1803     IDirectSoundBufferImpl * pDSB)
1804 {
1805     IDirectSoundBufferImpl **newbuffers;
1806     HRESULT hr = DS_OK;
1807
1808     TRACE("(%p, %p)\n", device, pDSB);
1809
1810     RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
1811
1812     if (device->buffers)
1813         newbuffers = HeapReAlloc(GetProcessHeap(),0,device->buffers,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
1814     else
1815         newbuffers = HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
1816
1817     if (newbuffers) {
1818         device->buffers = newbuffers;
1819         device->buffers[device->nrofbuffers] = pDSB;
1820         device->nrofbuffers++;
1821         TRACE("buffer count is now %d\n", device->nrofbuffers);
1822     } else {
1823         ERR("out of memory for buffer list! Current buffer count is %d\n", device->nrofbuffers);
1824         hr = DSERR_OUTOFMEMORY;
1825     }
1826
1827     RtlReleaseResource(&(device->buffer_list_lock));
1828
1829     return hr;
1830 }
1831
1832 /*
1833  * Remove secondary buffer from buffer list.
1834  * Gets exclusive access to buffer for writing.
1835  */
1836 HRESULT DirectSoundDevice_RemoveBuffer(
1837     DirectSoundDevice * device,
1838     IDirectSoundBufferImpl * pDSB)
1839 {
1840     int i;
1841     HRESULT hr = DS_OK;
1842
1843     TRACE("(%p, %p)\n", device, pDSB);
1844
1845     RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
1846
1847     for (i = 0; i < device->nrofbuffers; i++)
1848         if (device->buffers[i] == pDSB)
1849             break;
1850
1851     if (i < device->nrofbuffers) {
1852         /* Put the last buffer of the list in the (now empty) position */
1853         device->buffers[i] = device->buffers[device->nrofbuffers - 1];
1854         device->nrofbuffers--;
1855         device->buffers = HeapReAlloc(GetProcessHeap(),0,device->buffers,sizeof(LPDIRECTSOUNDBUFFER8)*device->nrofbuffers);
1856         TRACE("buffer count is now %d\n", device->nrofbuffers);
1857     }
1858
1859     if (device->nrofbuffers == 0) {
1860         HeapFree(GetProcessHeap(),0,device->buffers);
1861         device->buffers = NULL;
1862     }
1863
1864     RtlReleaseResource(&(device->buffer_list_lock));
1865
1866     return hr;
1867 }