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