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