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