dsound: Memory allocation sizes fix.
[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         HeapFree(GetProcessHeap(), 0, device->buffer);
1286         RtlDeleteResource(&device->buffer_list_lock);
1287         device->mixlock.DebugInfo->Spare[0] = 0;
1288         DeleteCriticalSection(&device->mixlock);
1289         HeapFree(GetProcessHeap(),0,device);
1290         TRACE("(%p) released\n", device);
1291     }
1292     return ref;
1293 }
1294
1295 HRESULT DirectSoundDevice_GetCaps(
1296     DirectSoundDevice * device,
1297     LPDSCAPS lpDSCaps)
1298 {
1299     TRACE("(%p,%p)\n",device,lpDSCaps);
1300
1301     if (device == NULL) {
1302         WARN("not initialized\n");
1303         return DSERR_UNINITIALIZED;
1304     }
1305
1306     if (lpDSCaps == NULL) {
1307         WARN("invalid parameter: lpDSCaps = NULL\n");
1308         return DSERR_INVALIDPARAM;
1309     }
1310
1311     /* check if there is enough room */
1312     if (lpDSCaps->dwSize < sizeof(*lpDSCaps)) {
1313         WARN("invalid parameter: lpDSCaps->dwSize = %d\n", lpDSCaps->dwSize);
1314         return DSERR_INVALIDPARAM;
1315     }
1316
1317     lpDSCaps->dwFlags                           = device->drvcaps.dwFlags;
1318     if (TRACE_ON(dsound)) {
1319         TRACE("(flags=0x%08x:\n",lpDSCaps->dwFlags);
1320         _dump_DSCAPS(lpDSCaps->dwFlags);
1321         TRACE(")\n");
1322     }
1323     lpDSCaps->dwMinSecondarySampleRate          = device->drvcaps.dwMinSecondarySampleRate;
1324     lpDSCaps->dwMaxSecondarySampleRate          = device->drvcaps.dwMaxSecondarySampleRate;
1325     lpDSCaps->dwPrimaryBuffers                  = device->drvcaps.dwPrimaryBuffers;
1326     lpDSCaps->dwMaxHwMixingAllBuffers           = device->drvcaps.dwMaxHwMixingAllBuffers;
1327     lpDSCaps->dwMaxHwMixingStaticBuffers        = device->drvcaps.dwMaxHwMixingStaticBuffers;
1328     lpDSCaps->dwMaxHwMixingStreamingBuffers     = device->drvcaps.dwMaxHwMixingStreamingBuffers;
1329     lpDSCaps->dwFreeHwMixingAllBuffers          = device->drvcaps.dwFreeHwMixingAllBuffers;
1330     lpDSCaps->dwFreeHwMixingStaticBuffers       = device->drvcaps.dwFreeHwMixingStaticBuffers;
1331     lpDSCaps->dwFreeHwMixingStreamingBuffers    = device->drvcaps.dwFreeHwMixingStreamingBuffers;
1332     lpDSCaps->dwMaxHw3DAllBuffers               = device->drvcaps.dwMaxHw3DAllBuffers;
1333     lpDSCaps->dwMaxHw3DStaticBuffers            = device->drvcaps.dwMaxHw3DStaticBuffers;
1334     lpDSCaps->dwMaxHw3DStreamingBuffers         = device->drvcaps.dwMaxHw3DStreamingBuffers;
1335     lpDSCaps->dwFreeHw3DAllBuffers              = device->drvcaps.dwFreeHw3DAllBuffers;
1336     lpDSCaps->dwFreeHw3DStaticBuffers           = device->drvcaps.dwFreeHw3DStaticBuffers;
1337     lpDSCaps->dwFreeHw3DStreamingBuffers        = device->drvcaps.dwFreeHw3DStreamingBuffers;
1338     lpDSCaps->dwTotalHwMemBytes                 = device->drvcaps.dwTotalHwMemBytes;
1339     lpDSCaps->dwFreeHwMemBytes                  = device->drvcaps.dwFreeHwMemBytes;
1340     lpDSCaps->dwMaxContigFreeHwMemBytes         = device->drvcaps.dwMaxContigFreeHwMemBytes;
1341
1342     /* driver doesn't have these */
1343     lpDSCaps->dwUnlockTransferRateHwBuffers     = 4096; /* But we have none... */
1344     lpDSCaps->dwPlayCpuOverheadSwBuffers        = 1;    /* 1% */
1345
1346     return DS_OK;
1347 }
1348
1349 HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcGUID)
1350 {
1351     HRESULT hr = DS_OK;
1352     unsigned wod, wodn;
1353     BOOLEAN found = FALSE;
1354     GUID devGUID;
1355     DirectSoundDevice * device = *ppDevice;
1356     TRACE("(%p,%s)\n",ppDevice,debugstr_guid(lpcGUID));
1357
1358     if (*ppDevice != NULL) {
1359         WARN("already initialized\n");
1360         return DSERR_ALREADYINITIALIZED;
1361     }
1362
1363     /* Default device? */
1364     if (!lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL))
1365         lpcGUID = &DSDEVID_DefaultPlayback;
1366
1367     if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
1368         WARN("invalid parameter: lpcGUID\n");
1369         return DSERR_INVALIDPARAM;
1370     }
1371
1372     /* Enumerate WINMM audio devices and find the one we want */
1373     wodn = waveOutGetNumDevs();
1374     if (!wodn) {
1375         WARN("no driver\n");
1376         return DSERR_NODRIVER;
1377     }
1378
1379     for (wod=0; wod<wodn; wod++) {
1380         if (IsEqualGUID( &devGUID, &DSOUND_renderer_guids[wod])) {
1381             found = TRUE;
1382             break;
1383         }
1384     }
1385
1386     if (found == FALSE) {
1387         WARN("No device found matching given ID!\n");
1388         return DSERR_NODRIVER;
1389     }
1390
1391     if (DSOUND_renderer[wod]) {
1392         if (IsEqualGUID(&devGUID, &DSOUND_renderer[wod]->guid)) {
1393             device = DSOUND_renderer[wod];
1394             DirectSoundDevice_AddRef(device);
1395             *ppDevice = device;
1396             return DS_OK;
1397         } else {
1398             ERR("device GUID doesn't match\n");
1399             hr = DSERR_GENERIC;
1400             return hr;
1401         }
1402     } else {
1403         hr = DirectSoundDevice_Create(&device);
1404         if (hr != DS_OK) {
1405             WARN("DirectSoundDevice_Create failed\n");
1406             return hr;
1407         }
1408     }
1409
1410     *ppDevice = device;
1411     device->guid = devGUID;
1412     device->driver = NULL;
1413
1414     device->drvdesc.dnDevNode = wod;
1415     hr = DSOUND_ReopenDevice(device, FALSE);
1416     if (FAILED(hr))
1417     {
1418         WARN("DSOUND_ReopenDevice failed: %08x\n", hr);
1419         return hr;
1420     }
1421
1422     if (device->driver) {
1423         /* the driver is now open, so it's now allowed to call GetCaps */
1424         hr = IDsDriver_GetCaps(device->driver,&(device->drvcaps));
1425         if (hr != DS_OK) {
1426             WARN("IDsDriver_GetCaps failed\n");
1427             return hr;
1428         }
1429     } else {
1430         WAVEOUTCAPSA woc;
1431         hr = mmErr(waveOutGetDevCapsA(device->drvdesc.dnDevNode, &woc, sizeof(woc)));
1432         if (hr != DS_OK) {
1433             WARN("waveOutGetDevCaps failed\n");
1434             return hr;
1435         }
1436         ZeroMemory(&device->drvcaps, sizeof(device->drvcaps));
1437         if ((woc.dwFormats & WAVE_FORMAT_1M08) ||
1438             (woc.dwFormats & WAVE_FORMAT_2M08) ||
1439             (woc.dwFormats & WAVE_FORMAT_4M08) ||
1440             (woc.dwFormats & WAVE_FORMAT_48M08) ||
1441             (woc.dwFormats & WAVE_FORMAT_96M08)) {
1442             device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT;
1443             device->drvcaps.dwFlags |= DSCAPS_PRIMARYMONO;
1444         }
1445         if ((woc.dwFormats & WAVE_FORMAT_1M16) ||
1446             (woc.dwFormats & WAVE_FORMAT_2M16) ||
1447             (woc.dwFormats & WAVE_FORMAT_4M16) ||
1448             (woc.dwFormats & WAVE_FORMAT_48M16) ||
1449             (woc.dwFormats & WAVE_FORMAT_96M16)) {
1450             device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT;
1451             device->drvcaps.dwFlags |= DSCAPS_PRIMARYMONO;
1452         }
1453         if ((woc.dwFormats & WAVE_FORMAT_1S08) ||
1454             (woc.dwFormats & WAVE_FORMAT_2S08) ||
1455             (woc.dwFormats & WAVE_FORMAT_4S08) ||
1456             (woc.dwFormats & WAVE_FORMAT_48S08) ||
1457             (woc.dwFormats & WAVE_FORMAT_96S08)) {
1458             device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT;
1459             device->drvcaps.dwFlags |= DSCAPS_PRIMARYSTEREO;
1460         }
1461         if ((woc.dwFormats & WAVE_FORMAT_1S16) ||
1462             (woc.dwFormats & WAVE_FORMAT_2S16) ||
1463             (woc.dwFormats & WAVE_FORMAT_4S16) ||
1464             (woc.dwFormats & WAVE_FORMAT_48S16) ||
1465             (woc.dwFormats & WAVE_FORMAT_96S16)) {
1466             device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT;
1467             device->drvcaps.dwFlags |= DSCAPS_PRIMARYSTEREO;
1468         }
1469         if (ds_emuldriver)
1470             device->drvcaps.dwFlags |= DSCAPS_EMULDRIVER;
1471         device->drvcaps.dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
1472         device->drvcaps.dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
1473         device->drvcaps.dwPrimaryBuffers = 1;
1474     }
1475
1476     hr = DSOUND_PrimaryCreate(device);
1477     if (hr == DS_OK) {
1478         UINT triggertime = DS_TIME_DEL, res = DS_TIME_RES, id;
1479         TIMECAPS time;
1480
1481         DSOUND_renderer[device->drvdesc.dnDevNode] = device;
1482         timeGetDevCaps(&time, sizeof(TIMECAPS));
1483         TRACE("Minimum timer resolution: %u, max timer: %u\n", time.wPeriodMin, time.wPeriodMax);
1484         if (triggertime < time.wPeriodMin)
1485             triggertime = time.wPeriodMin;
1486         if (res < time.wPeriodMin)
1487             res = time.wPeriodMin;
1488         if (timeBeginPeriod(res) == TIMERR_NOCANDO)
1489             WARN("Could not set minimum resolution, don't expect sound\n");
1490         id = timeSetEvent(triggertime, res, DSOUND_timer, (DWORD_PTR)device, TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
1491         if (!id)
1492         {
1493             WARN("Timer not created! Retrying without TIME_KILL_SYNCHRONOUS\n");
1494             id = timeSetEvent(triggertime, res, DSOUND_timer, (DWORD_PTR)device, TIME_PERIODIC);
1495             if (!id) ERR("Could not create timer, sound playback will not occur\n");
1496         }
1497         DSOUND_renderer[device->drvdesc.dnDevNode]->timerID = id;
1498     } else {
1499         WARN("DSOUND_PrimaryCreate failed\n");
1500     }
1501
1502     return hr;
1503 }
1504
1505 HRESULT DirectSoundDevice_CreateSoundBuffer(
1506     DirectSoundDevice * device,
1507     LPCDSBUFFERDESC dsbd,
1508     LPLPDIRECTSOUNDBUFFER ppdsb,
1509     LPUNKNOWN lpunk,
1510     BOOL from8)
1511 {
1512     HRESULT hres = DS_OK;
1513     TRACE("(%p,%p,%p,%p)\n",device,dsbd,ppdsb,lpunk);
1514
1515     if (device == NULL) {
1516         WARN("not initialized\n");
1517         return DSERR_UNINITIALIZED;
1518     }
1519
1520     if (dsbd == NULL) {
1521         WARN("invalid parameter: dsbd == NULL\n");
1522         return DSERR_INVALIDPARAM;
1523     }
1524
1525     if (dsbd->dwSize != sizeof(DSBUFFERDESC) &&
1526         dsbd->dwSize != sizeof(DSBUFFERDESC1)) {
1527         WARN("invalid parameter: dsbd\n");
1528         return DSERR_INVALIDPARAM;
1529     }
1530
1531     if (ppdsb == NULL) {
1532         WARN("invalid parameter: ppdsb == NULL\n");
1533         return DSERR_INVALIDPARAM;
1534     }
1535     *ppdsb = NULL;
1536
1537     if (TRACE_ON(dsound)) {
1538         TRACE("(structsize=%d)\n",dsbd->dwSize);
1539         TRACE("(flags=0x%08x:\n",dsbd->dwFlags);
1540         _dump_DSBCAPS(dsbd->dwFlags);
1541         TRACE(")\n");
1542         TRACE("(bufferbytes=%d)\n",dsbd->dwBufferBytes);
1543         TRACE("(lpwfxFormat=%p)\n",dsbd->lpwfxFormat);
1544     }
1545
1546     if (dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) {
1547         if (dsbd->lpwfxFormat != NULL) {
1548             WARN("invalid parameter: dsbd->lpwfxFormat must be NULL for "
1549                  "primary buffer\n");
1550             return DSERR_INVALIDPARAM;
1551         }
1552
1553         if (device->primary) {
1554             WARN("Primary Buffer already created\n");
1555             IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(device->primary));
1556             *ppdsb = (LPDIRECTSOUNDBUFFER)(device->primary);
1557         } else {
1558            device->dsbd = *dsbd;
1559            device->dsbd.dwFlags &= ~(DSBCAPS_LOCHARDWARE | DSBCAPS_LOCSOFTWARE);
1560            if (device->hwbuf)
1561                device->dsbd.dwFlags |= DSBCAPS_LOCHARDWARE;
1562            else device->dsbd.dwFlags |= DSBCAPS_LOCSOFTWARE;
1563            hres = PrimaryBufferImpl_Create(device, &(device->primary), &(device->dsbd));
1564            if (device->primary) {
1565                IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(device->primary));
1566                *ppdsb = (LPDIRECTSOUNDBUFFER)(device->primary);
1567            } else
1568                WARN("PrimaryBufferImpl_Create failed\n");
1569         }
1570     } else {
1571         IDirectSoundBufferImpl * dsb;
1572         WAVEFORMATEXTENSIBLE *pwfxe;
1573
1574         if (dsbd->lpwfxFormat == NULL) {
1575             WARN("invalid parameter: dsbd->lpwfxFormat can't be NULL for "
1576                  "secondary buffer\n");
1577             return DSERR_INVALIDPARAM;
1578         }
1579         pwfxe = (WAVEFORMATEXTENSIBLE*)dsbd->lpwfxFormat;
1580
1581         if (pwfxe->Format.wBitsPerSample != 16 && pwfxe->Format.wBitsPerSample != 8 && pwfxe->Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE)
1582         {
1583             WARN("wBitsPerSample=%d needs a WAVEFORMATEXTENSIBLE\n", dsbd->lpwfxFormat->wBitsPerSample);
1584             return DSERR_CONTROLUNAVAIL;
1585         }
1586         if (pwfxe->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE)
1587         {
1588             if (pwfxe->Format.cbSize < (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)))
1589             {
1590                 WARN("Too small a cbSize %u\n", pwfxe->Format.cbSize);
1591                 return DSERR_INVALIDPARAM;
1592             }
1593
1594             if (pwfxe->Format.cbSize > (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)))
1595             {
1596                 WARN("Too big a cbSize %u\n", pwfxe->Format.cbSize);
1597                 return DSERR_CONTROLUNAVAIL;
1598             }
1599
1600             if (!IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))
1601             {
1602                 if (!IsEqualGUID(&pwfxe->SubFormat, &GUID_NULL))
1603                     FIXME("SubFormat %s not supported right now.\n", debugstr_guid(&pwfxe->SubFormat));
1604                 return DSERR_INVALIDPARAM;
1605             }
1606             if (pwfxe->Samples.wValidBitsPerSample > dsbd->lpwfxFormat->wBitsPerSample)
1607             {
1608                 WARN("Samples.wValidBitsPerSample(%d) > Format.wBitsPerSample (%d)\n", pwfxe->Samples.wValidBitsPerSample, pwfxe->Format.wBitsPerSample);
1609                 return DSERR_INVALIDPARAM;
1610             }
1611             if (pwfxe->Samples.wValidBitsPerSample && pwfxe->Samples.wValidBitsPerSample < dsbd->lpwfxFormat->wBitsPerSample)
1612             {
1613                 FIXME("Non-packed formats not supported right now: %d/%d\n", pwfxe->Samples.wValidBitsPerSample, dsbd->lpwfxFormat->wBitsPerSample);
1614                 return DSERR_CONTROLUNAVAIL;
1615             }
1616         }
1617
1618         TRACE("(formattag=0x%04x,chans=%d,samplerate=%d,"
1619               "bytespersec=%d,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
1620               dsbd->lpwfxFormat->wFormatTag, dsbd->lpwfxFormat->nChannels,
1621               dsbd->lpwfxFormat->nSamplesPerSec,
1622               dsbd->lpwfxFormat->nAvgBytesPerSec,
1623               dsbd->lpwfxFormat->nBlockAlign,
1624               dsbd->lpwfxFormat->wBitsPerSample, dsbd->lpwfxFormat->cbSize);
1625
1626         if (from8 && (dsbd->dwFlags & DSBCAPS_CTRL3D) && (dsbd->lpwfxFormat->nChannels != 1)) {
1627             WARN("invalid parameter: 3D buffer format must be mono\n");
1628             return DSERR_INVALIDPARAM;
1629         }
1630
1631         hres = IDirectSoundBufferImpl_Create(device, &dsb, dsbd);
1632         if (dsb) {
1633             hres = SecondaryBufferImpl_Create(dsb, (SecondaryBufferImpl**)ppdsb);
1634             if (*ppdsb) {
1635                 dsb->secondary = (SecondaryBufferImpl*)*ppdsb;
1636                 IDirectSoundBuffer_AddRef(*ppdsb);
1637             } else
1638                 WARN("SecondaryBufferImpl_Create failed\n");
1639         } else
1640            WARN("IDirectSoundBufferImpl_Create failed\n");
1641    }
1642
1643    return hres;
1644 }
1645
1646 HRESULT DirectSoundDevice_DuplicateSoundBuffer(
1647     DirectSoundDevice * device,
1648     LPDIRECTSOUNDBUFFER psb,
1649     LPLPDIRECTSOUNDBUFFER ppdsb)
1650 {
1651     HRESULT hres = DS_OK;
1652     IDirectSoundBufferImpl* dsb;
1653     TRACE("(%p,%p,%p)\n",device,psb,ppdsb);
1654
1655     if (device == NULL) {
1656         WARN("not initialized\n");
1657         return DSERR_UNINITIALIZED;
1658     }
1659
1660     if (psb == NULL) {
1661         WARN("invalid parameter: psb == NULL\n");
1662         return DSERR_INVALIDPARAM;
1663     }
1664
1665     if (ppdsb == NULL) {
1666         WARN("invalid parameter: ppdsb == NULL\n");
1667         return DSERR_INVALIDPARAM;
1668     }
1669
1670     /* make sure we have a secondary buffer */
1671     if ((PrimaryBufferImpl *)psb == device->primary) {
1672         WARN("trying to duplicate primary buffer\n");
1673         *ppdsb = NULL;
1674         return DSERR_INVALIDCALL;
1675     }
1676
1677     /* duplicate the actual buffer implementation */
1678     hres = IDirectSoundBufferImpl_Duplicate(device, &dsb,
1679                                            ((SecondaryBufferImpl *)psb)->dsb);
1680
1681     if (hres == DS_OK) {
1682         /* create a new secondary buffer using the new implementation */
1683         hres = SecondaryBufferImpl_Create(dsb, (SecondaryBufferImpl**)ppdsb);
1684         if (*ppdsb) {
1685             dsb->secondary = (SecondaryBufferImpl*)*ppdsb;
1686             IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)*ppdsb);
1687         } else {
1688             WARN("SecondaryBufferImpl_Create failed\n");
1689             IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)dsb);
1690             IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER8)dsb);
1691         }
1692     }
1693
1694     return hres;
1695 }
1696
1697 HRESULT DirectSoundDevice_SetCooperativeLevel(
1698     DirectSoundDevice * device,
1699     HWND hwnd,
1700     DWORD level)
1701 {
1702     TRACE("(%p,%p,%s)\n",device,hwnd,dumpCooperativeLevel(level));
1703
1704     if (device == NULL) {
1705         WARN("not initialized\n");
1706         return DSERR_UNINITIALIZED;
1707     }
1708
1709     if (level==DSSCL_PRIORITY || level==DSSCL_EXCLUSIVE) {
1710         WARN("level=%s not fully supported\n",
1711              level==DSSCL_PRIORITY ? "DSSCL_PRIORITY" : "DSSCL_EXCLUSIVE");
1712     }
1713
1714     device->priolevel = level;
1715     return DS_OK;
1716 }
1717
1718 HRESULT DirectSoundDevice_Compact(
1719     DirectSoundDevice * device)
1720 {
1721     TRACE("(%p)\n", device);
1722
1723     if (device == NULL) {
1724         WARN("not initialized\n");
1725         return DSERR_UNINITIALIZED;
1726     }
1727
1728     if (device->priolevel < DSSCL_PRIORITY) {
1729         WARN("incorrect priority level\n");
1730         return DSERR_PRIOLEVELNEEDED;
1731     }
1732
1733     return DS_OK;
1734 }
1735
1736 HRESULT DirectSoundDevice_GetSpeakerConfig(
1737     DirectSoundDevice * device,
1738     LPDWORD lpdwSpeakerConfig)
1739 {
1740     TRACE("(%p, %p)\n", device, lpdwSpeakerConfig);
1741
1742     if (device == NULL) {
1743         WARN("not initialized\n");
1744         return DSERR_UNINITIALIZED;
1745     }
1746
1747     if (lpdwSpeakerConfig == NULL) {
1748         WARN("invalid parameter: lpdwSpeakerConfig == NULL\n");
1749         return DSERR_INVALIDPARAM;
1750     }
1751
1752     WARN("not fully functional\n");
1753     *lpdwSpeakerConfig = device->speaker_config;
1754     return DS_OK;
1755 }
1756
1757 HRESULT DirectSoundDevice_SetSpeakerConfig(
1758     DirectSoundDevice * device,
1759     DWORD config)
1760 {
1761     TRACE("(%p,0x%08x)\n",device,config);
1762
1763     if (device == NULL) {
1764         WARN("not initialized\n");
1765         return DSERR_UNINITIALIZED;
1766     }
1767
1768     device->speaker_config = config;
1769     WARN("not fully functional\n");
1770     return DS_OK;
1771 }
1772
1773 static HRESULT DirectSoundDevice_VerifyCertification(
1774     DirectSoundDevice * device,
1775     LPDWORD pdwCertified)
1776 {
1777     TRACE("(%p, %p)\n",device,pdwCertified);
1778
1779     if (device == NULL) {
1780         WARN("not initialized\n");
1781         return DSERR_UNINITIALIZED;
1782     }
1783
1784     if (device->drvcaps.dwFlags & DSCAPS_CERTIFIED)
1785         *pdwCertified = DS_CERTIFIED;
1786     else
1787         *pdwCertified = DS_UNCERTIFIED;
1788
1789     return DS_OK;
1790 }
1791
1792 /*
1793  * Add secondary buffer to buffer list.
1794  * Gets exclusive access to buffer for writing.
1795  */
1796 HRESULT DirectSoundDevice_AddBuffer(
1797     DirectSoundDevice * device,
1798     IDirectSoundBufferImpl * pDSB)
1799 {
1800     IDirectSoundBufferImpl **newbuffers;
1801     HRESULT hr = DS_OK;
1802
1803     TRACE("(%p, %p)\n", device, pDSB);
1804
1805     RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
1806
1807     if (device->buffers)
1808         newbuffers = HeapReAlloc(GetProcessHeap(),0,device->buffers,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
1809     else
1810         newbuffers = HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
1811
1812     if (newbuffers) {
1813         device->buffers = newbuffers;
1814         device->buffers[device->nrofbuffers] = pDSB;
1815         device->nrofbuffers++;
1816         TRACE("buffer count is now %d\n", device->nrofbuffers);
1817     } else {
1818         ERR("out of memory for buffer list! Current buffer count is %d\n", device->nrofbuffers);
1819         hr = DSERR_OUTOFMEMORY;
1820     }
1821
1822     RtlReleaseResource(&(device->buffer_list_lock));
1823
1824     return hr;
1825 }
1826
1827 /*
1828  * Remove secondary buffer from buffer list.
1829  * Gets exclusive access to buffer for writing.
1830  */
1831 HRESULT DirectSoundDevice_RemoveBuffer(
1832     DirectSoundDevice * device,
1833     IDirectSoundBufferImpl * pDSB)
1834 {
1835     int i;
1836     HRESULT hr = DS_OK;
1837
1838     TRACE("(%p, %p)\n", device, pDSB);
1839
1840     RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
1841
1842     for (i = 0; i < device->nrofbuffers; i++)
1843         if (device->buffers[i] == pDSB)
1844             break;
1845
1846     if (i < device->nrofbuffers) {
1847         /* Put the last buffer of the list in the (now empty) position */
1848         device->buffers[i] = device->buffers[device->nrofbuffers - 1];
1849         device->nrofbuffers--;
1850         device->buffers = HeapReAlloc(GetProcessHeap(),0,device->buffers,sizeof(LPDIRECTSOUNDBUFFER8)*device->nrofbuffers);
1851         TRACE("buffer count is now %d\n", device->nrofbuffers);
1852     }
1853
1854     if (device->nrofbuffers == 0) {
1855         HeapFree(GetProcessHeap(),0,device->buffers);
1856         device->buffers = NULL;
1857     }
1858
1859     RtlReleaseResource(&(device->buffer_list_lock));
1860
1861     return hr;
1862 }