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