winspool.drv: Replace WINSPOOL_SHDeleteKeyW with RegDeleteTreeW.
[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 "wine/debug.h"
35 #include "dsound.h"
36 #include "dsdriver.h"
37 #include "dsound_private.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
40
41 /*****************************************************************************
42  * IDirectSound COM components
43  */
44 struct IDirectSound_IUnknown {
45     const IUnknownVtbl         *lpVtbl;
46     LONG                        ref;
47     LPDIRECTSOUND8              pds;
48 };
49
50 static HRESULT IDirectSound_IUnknown_Create(LPDIRECTSOUND8 pds, LPUNKNOWN * ppunk);
51
52 struct IDirectSound_IDirectSound {
53     const IDirectSoundVtbl     *lpVtbl;
54     LONG                        ref;
55     LPDIRECTSOUND8              pds;
56 };
57
58 static HRESULT IDirectSound_IDirectSound_Create(LPDIRECTSOUND8 pds, LPDIRECTSOUND * ppds);
59
60 /*****************************************************************************
61  * IDirectSound8 COM components
62  */
63 struct IDirectSound8_IUnknown {
64     const IUnknownVtbl         *lpVtbl;
65     LONG                        ref;
66     LPDIRECTSOUND8              pds;
67 };
68
69 static HRESULT IDirectSound8_IUnknown_Create(LPDIRECTSOUND8 pds, LPUNKNOWN * ppunk);
70 static ULONG WINAPI IDirectSound8_IUnknown_AddRef(LPUNKNOWN iface);
71
72 struct IDirectSound8_IDirectSound {
73     const IDirectSoundVtbl     *lpVtbl;
74     LONG                        ref;
75     LPDIRECTSOUND8              pds;
76 };
77
78 static HRESULT IDirectSound8_IDirectSound_Create(LPDIRECTSOUND8 pds, LPDIRECTSOUND * ppds);
79 static ULONG WINAPI IDirectSound8_IDirectSound_AddRef(LPDIRECTSOUND iface);
80
81 struct IDirectSound8_IDirectSound8 {
82     const IDirectSound8Vtbl    *lpVtbl;
83     LONG                        ref;
84     LPDIRECTSOUND8              pds;
85 };
86
87 static HRESULT IDirectSound8_IDirectSound8_Create(LPDIRECTSOUND8 pds, LPDIRECTSOUND8 * ppds);
88 static ULONG WINAPI IDirectSound8_IDirectSound8_AddRef(LPDIRECTSOUND8 iface);
89
90 /*****************************************************************************
91  * IDirectSound implementation structure
92  */
93 struct IDirectSoundImpl
94 {
95     LONG                        ref;
96
97     DirectSoundDevice          *device;
98     LPUNKNOWN                   pUnknown;
99     LPDIRECTSOUND               pDS;
100     LPDIRECTSOUND8              pDS8;
101 };
102
103 static HRESULT IDirectSoundImpl_Create(LPDIRECTSOUND8 * ppds);
104
105 static ULONG WINAPI IDirectSound_IUnknown_AddRef(LPUNKNOWN iface);
106 static ULONG WINAPI IDirectSound_IDirectSound_AddRef(LPDIRECTSOUND iface);
107
108 static HRESULT DirectSoundDevice_VerifyCertification(DirectSoundDevice * device, LPDWORD pdwCertified);
109
110 const char * dumpCooperativeLevel(DWORD level)
111 {
112     static char unknown[32];
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     sprintf(unknown, "Unknown(%08x)", level);
122     return unknown;
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_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_Release(This->pds);
437         HeapFree(GetProcessHeap(), 0, This);
438         TRACE("(%p) released\n", This);
439     }
440     return ref;
441 }
442
443 static HRESULT WINAPI IDirectSound_IDirectSound_CreateSoundBuffer(
444     LPDIRECTSOUND iface,
445     LPCDSBUFFERDESC dsbd,
446     LPLPDIRECTSOUNDBUFFER ppdsb,
447     LPUNKNOWN lpunk)
448 {
449     IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
450     TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
451     return DirectSoundDevice_CreateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,dsbd,ppdsb,lpunk,FALSE);
452 }
453
454 static HRESULT WINAPI IDirectSound_IDirectSound_GetCaps(
455     LPDIRECTSOUND iface,
456     LPDSCAPS lpDSCaps)
457 {
458     IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
459     TRACE("(%p,%p)\n",This,lpDSCaps);
460     return DirectSoundDevice_GetCaps(((IDirectSoundImpl *)This->pds)->device, lpDSCaps);
461 }
462
463 static HRESULT WINAPI IDirectSound_IDirectSound_DuplicateSoundBuffer(
464     LPDIRECTSOUND iface,
465     LPDIRECTSOUNDBUFFER psb,
466     LPLPDIRECTSOUNDBUFFER ppdsb)
467 {
468     IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
469     TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
470     return DirectSoundDevice_DuplicateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,psb,ppdsb);
471 }
472
473 static HRESULT WINAPI IDirectSound_IDirectSound_SetCooperativeLevel(
474     LPDIRECTSOUND iface,
475     HWND hwnd,
476     DWORD level)
477 {
478     IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
479     TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level));
480     return DirectSoundDevice_SetCooperativeLevel(((IDirectSoundImpl *)This->pds)->device, hwnd, level);
481 }
482
483 static HRESULT WINAPI IDirectSound_IDirectSound_Compact(
484     LPDIRECTSOUND iface)
485 {
486     IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
487     TRACE("(%p)\n", This);
488     return DirectSoundDevice_Compact(((IDirectSoundImpl *)This->pds)->device);
489 }
490
491 static HRESULT WINAPI IDirectSound_IDirectSound_GetSpeakerConfig(
492     LPDIRECTSOUND iface,
493     LPDWORD lpdwSpeakerConfig)
494 {
495     IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
496     TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
497     return DirectSoundDevice_GetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,lpdwSpeakerConfig);
498 }
499
500 static HRESULT WINAPI IDirectSound_IDirectSound_SetSpeakerConfig(
501     LPDIRECTSOUND iface,
502     DWORD config)
503 {
504     IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
505     TRACE("(%p,0x%08x)\n",This,config);
506     return DirectSoundDevice_SetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,config);
507 }
508
509 static HRESULT WINAPI IDirectSound_IDirectSound_Initialize(
510     LPDIRECTSOUND iface,
511     LPCGUID lpcGuid)
512 {
513     IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
514     TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
515     return DirectSoundDevice_Initialize(&((IDirectSoundImpl *)This->pds)->device,lpcGuid);
516 }
517
518 static const IDirectSoundVtbl DirectSound_DirectSound_Vtbl =
519 {
520     IDirectSound_IDirectSound_QueryInterface,
521     IDirectSound_IDirectSound_AddRef,
522     IDirectSound_IDirectSound_Release,
523     IDirectSound_IDirectSound_CreateSoundBuffer,
524     IDirectSound_IDirectSound_GetCaps,
525     IDirectSound_IDirectSound_DuplicateSoundBuffer,
526     IDirectSound_IDirectSound_SetCooperativeLevel,
527     IDirectSound_IDirectSound_Compact,
528     IDirectSound_IDirectSound_GetSpeakerConfig,
529     IDirectSound_IDirectSound_SetSpeakerConfig,
530     IDirectSound_IDirectSound_Initialize
531 };
532
533 static HRESULT IDirectSound_IDirectSound_Create(
534     LPDIRECTSOUND8  pds,
535     LPDIRECTSOUND * ppds)
536 {
537     IDirectSound_IDirectSound * pdsds;
538     TRACE("(%p,%p)\n",pds,ppds);
539
540     if (ppds == NULL) {
541         ERR("invalid parameter: ppds == NULL\n");
542         return DSERR_INVALIDPARAM;
543     }
544
545     if (pds == NULL) {
546         ERR("invalid parameter: pds == NULL\n");
547         *ppds = NULL;
548         return DSERR_INVALIDPARAM;
549     }
550
551     pdsds = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsds));
552     if (pdsds == NULL) {
553         WARN("out of memory\n");
554         *ppds = NULL;
555         return DSERR_OUTOFMEMORY;
556     }
557
558     pdsds->lpVtbl = &DirectSound_DirectSound_Vtbl;
559     pdsds->ref = 0;
560     pdsds->pds = pds;
561
562     IDirectSoundImpl_AddRef(pds);
563     *ppds = (LPDIRECTSOUND)pdsds;
564
565     return DS_OK;
566 }
567
568 /*******************************************************************************
569  *              IDirectSound8_IUnknown
570  */
571 static HRESULT WINAPI IDirectSound8_IUnknown_QueryInterface(
572     LPUNKNOWN iface,
573     REFIID riid,
574     LPVOID * ppobj)
575 {
576     IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
577     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
578     return DSOUND_QueryInterface8(This->pds, riid, ppobj);
579 }
580
581 static ULONG WINAPI IDirectSound8_IUnknown_AddRef(
582     LPUNKNOWN iface)
583 {
584     IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
585     ULONG ref = InterlockedIncrement(&(This->ref));
586     TRACE("(%p) ref was %d\n", This, ref - 1);
587     return ref;
588 }
589
590 static ULONG WINAPI IDirectSound8_IUnknown_Release(
591     LPUNKNOWN iface)
592 {
593     IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
594     ULONG ref = InterlockedDecrement(&(This->ref));
595     TRACE("(%p) ref was %d\n", This, ref + 1);
596     if (!ref) {
597         IDirectSoundImpl_Release(This->pds);
598         HeapFree(GetProcessHeap(), 0, This);
599         TRACE("(%p) released\n", This);
600     }
601     return ref;
602 }
603
604 static const IUnknownVtbl DirectSound8_Unknown_Vtbl =
605 {
606     IDirectSound8_IUnknown_QueryInterface,
607     IDirectSound8_IUnknown_AddRef,
608     IDirectSound8_IUnknown_Release
609 };
610
611 static HRESULT IDirectSound8_IUnknown_Create(
612     LPDIRECTSOUND8 pds,
613     LPUNKNOWN * ppunk)
614 {
615     IDirectSound8_IUnknown * pdsunk;
616     TRACE("(%p,%p)\n",pds,ppunk);
617
618     if (ppunk == NULL) {
619         ERR("invalid parameter: ppunk == NULL\n");
620         return DSERR_INVALIDPARAM;
621     }
622
623     if (pds == NULL) {
624         ERR("invalid parameter: pds == NULL\n");
625         *ppunk = NULL;
626         return DSERR_INVALIDPARAM;
627     }
628
629     pdsunk = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsunk));
630     if (pdsunk == NULL) {
631         WARN("out of memory\n");
632         *ppunk = NULL;
633         return DSERR_OUTOFMEMORY;
634     }
635
636     pdsunk->lpVtbl = &DirectSound8_Unknown_Vtbl;
637     pdsunk->ref = 0;
638     pdsunk->pds = pds;
639
640     IDirectSoundImpl_AddRef(pds);
641     *ppunk = (LPUNKNOWN)pdsunk;
642
643     return DS_OK;
644 }
645
646 /*******************************************************************************
647  *              IDirectSound8_IDirectSound
648  */
649 static HRESULT WINAPI IDirectSound8_IDirectSound_QueryInterface(
650     LPDIRECTSOUND iface,
651     REFIID riid,
652     LPVOID * ppobj)
653 {
654     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
655     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
656     return DSOUND_QueryInterface8(This->pds, riid, ppobj);
657 }
658
659 static ULONG WINAPI IDirectSound8_IDirectSound_AddRef(
660     LPDIRECTSOUND iface)
661 {
662     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
663     ULONG ref = InterlockedIncrement(&(This->ref));
664     TRACE("(%p) ref was %d\n", This, ref - 1);
665     return ref;
666 }
667
668 static ULONG WINAPI IDirectSound8_IDirectSound_Release(
669     LPDIRECTSOUND iface)
670 {
671     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
672     ULONG ref = InterlockedDecrement(&(This->ref));
673     TRACE("(%p) ref was %d\n", This, ref + 1);
674     if (!ref) {
675         IDirectSoundImpl_Release(This->pds);
676         HeapFree(GetProcessHeap(), 0, This);
677         TRACE("(%p) released\n", This);
678     }
679     return ref;
680 }
681
682 static HRESULT WINAPI IDirectSound8_IDirectSound_CreateSoundBuffer(
683     LPDIRECTSOUND iface,
684     LPCDSBUFFERDESC dsbd,
685     LPLPDIRECTSOUNDBUFFER ppdsb,
686     LPUNKNOWN lpunk)
687 {
688     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
689     TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
690     return DirectSoundDevice_CreateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,dsbd,ppdsb,lpunk,TRUE);
691 }
692
693 static HRESULT WINAPI IDirectSound8_IDirectSound_GetCaps(
694     LPDIRECTSOUND iface,
695     LPDSCAPS lpDSCaps)
696 {
697     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
698     TRACE("(%p,%p)\n",This,lpDSCaps);
699     return DirectSoundDevice_GetCaps(((IDirectSoundImpl *)This->pds)->device, lpDSCaps);
700 }
701
702 static HRESULT WINAPI IDirectSound8_IDirectSound_DuplicateSoundBuffer(
703     LPDIRECTSOUND iface,
704     LPDIRECTSOUNDBUFFER psb,
705     LPLPDIRECTSOUNDBUFFER ppdsb)
706 {
707     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
708     TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
709     return DirectSoundDevice_DuplicateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,psb,ppdsb);
710 }
711
712 static HRESULT WINAPI IDirectSound8_IDirectSound_SetCooperativeLevel(
713     LPDIRECTSOUND iface,
714     HWND hwnd,
715     DWORD level)
716 {
717     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
718     TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level));
719     return DirectSoundDevice_SetCooperativeLevel(((IDirectSoundImpl *)This->pds)->device, hwnd, level);
720 }
721
722 static HRESULT WINAPI IDirectSound8_IDirectSound_Compact(
723     LPDIRECTSOUND iface)
724 {
725     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
726     TRACE("(%p)\n", This);
727     return DirectSoundDevice_Compact(((IDirectSoundImpl *)This->pds)->device);
728 }
729
730 static HRESULT WINAPI IDirectSound8_IDirectSound_GetSpeakerConfig(
731     LPDIRECTSOUND iface,
732     LPDWORD lpdwSpeakerConfig)
733 {
734     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
735     TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
736     return DirectSoundDevice_GetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,lpdwSpeakerConfig);
737 }
738
739 static HRESULT WINAPI IDirectSound8_IDirectSound_SetSpeakerConfig(
740     LPDIRECTSOUND iface,
741     DWORD config)
742 {
743     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
744     TRACE("(%p,0x%08x)\n",This,config);
745     return DirectSoundDevice_SetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,config);
746 }
747
748 static HRESULT WINAPI IDirectSound8_IDirectSound_Initialize(
749     LPDIRECTSOUND iface,
750     LPCGUID lpcGuid)
751 {
752     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
753     TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
754     return DirectSoundDevice_Initialize(&((IDirectSoundImpl *)This->pds)->device,lpcGuid);
755 }
756
757 static const IDirectSoundVtbl DirectSound8_DirectSound_Vtbl =
758 {
759     IDirectSound8_IDirectSound_QueryInterface,
760     IDirectSound8_IDirectSound_AddRef,
761     IDirectSound8_IDirectSound_Release,
762     IDirectSound8_IDirectSound_CreateSoundBuffer,
763     IDirectSound8_IDirectSound_GetCaps,
764     IDirectSound8_IDirectSound_DuplicateSoundBuffer,
765     IDirectSound8_IDirectSound_SetCooperativeLevel,
766     IDirectSound8_IDirectSound_Compact,
767     IDirectSound8_IDirectSound_GetSpeakerConfig,
768     IDirectSound8_IDirectSound_SetSpeakerConfig,
769     IDirectSound8_IDirectSound_Initialize
770 };
771
772 static HRESULT IDirectSound8_IDirectSound_Create(
773     LPDIRECTSOUND8 pds,
774     LPDIRECTSOUND * ppds)
775 {
776     IDirectSound8_IDirectSound * pdsds;
777     TRACE("(%p,%p)\n",pds,ppds);
778
779     if (ppds == NULL) {
780         ERR("invalid parameter: ppds == NULL\n");
781         return DSERR_INVALIDPARAM;
782     }
783
784     if (pds == NULL) {
785         ERR("invalid parameter: pds == NULL\n");
786         *ppds = NULL;
787         return DSERR_INVALIDPARAM;
788     }
789
790     pdsds = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsds));
791     if (pdsds == NULL) {
792         WARN("out of memory\n");
793         *ppds = NULL;
794         return DSERR_OUTOFMEMORY;
795     }
796
797     pdsds->lpVtbl = &DirectSound8_DirectSound_Vtbl;
798     pdsds->ref = 0;
799     pdsds->pds = pds;
800
801     IDirectSoundImpl_AddRef(pds);
802     *ppds = (LPDIRECTSOUND)pdsds;
803
804     return DS_OK;
805 }
806
807 /*******************************************************************************
808  *              IDirectSound8_IDirectSound8
809  */
810 static HRESULT WINAPI IDirectSound8_IDirectSound8_QueryInterface(
811     LPDIRECTSOUND8 iface,
812     REFIID riid,
813     LPVOID * ppobj)
814 {
815     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
816     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
817     return DSOUND_QueryInterface8(This->pds, riid, ppobj);
818 }
819
820 static ULONG WINAPI IDirectSound8_IDirectSound8_AddRef(
821     LPDIRECTSOUND8 iface)
822 {
823     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
824     ULONG ref = InterlockedIncrement(&(This->ref));
825     TRACE("(%p) ref was %d\n", This, ref - 1);
826     return ref;
827 }
828
829 static ULONG WINAPI IDirectSound8_IDirectSound8_Release(
830     LPDIRECTSOUND8 iface)
831 {
832     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
833     ULONG ref = InterlockedDecrement(&(This->ref));
834     TRACE("(%p) ref was %d\n", This, ref + 1);
835     if (!ref) {
836         IDirectSoundImpl_Release(This->pds);
837         HeapFree(GetProcessHeap(), 0, This);
838         TRACE("(%p) released\n", This);
839     }
840     return ref;
841 }
842
843 static HRESULT WINAPI IDirectSound8_IDirectSound8_CreateSoundBuffer(
844     LPDIRECTSOUND8 iface,
845     LPCDSBUFFERDESC dsbd,
846     LPLPDIRECTSOUNDBUFFER ppdsb,
847     LPUNKNOWN lpunk)
848 {
849     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
850     TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
851     return DirectSoundDevice_CreateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,dsbd,ppdsb,lpunk,TRUE);
852 }
853
854 static HRESULT WINAPI IDirectSound8_IDirectSound8_GetCaps(
855     LPDIRECTSOUND8 iface,
856     LPDSCAPS lpDSCaps)
857 {
858     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
859     TRACE("(%p,%p)\n",This,lpDSCaps);
860     return DirectSoundDevice_GetCaps(((IDirectSoundImpl *)This->pds)->device, lpDSCaps);
861 }
862
863 static HRESULT WINAPI IDirectSound8_IDirectSound8_DuplicateSoundBuffer(
864     LPDIRECTSOUND8 iface,
865     LPDIRECTSOUNDBUFFER psb,
866     LPLPDIRECTSOUNDBUFFER ppdsb)
867 {
868     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
869     TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
870     return DirectSoundDevice_DuplicateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,psb,ppdsb);
871 }
872
873 static HRESULT WINAPI IDirectSound8_IDirectSound8_SetCooperativeLevel(
874     LPDIRECTSOUND8 iface,
875     HWND hwnd,
876     DWORD level)
877 {
878     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
879     TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level));
880     return DirectSoundDevice_SetCooperativeLevel(((IDirectSoundImpl *)This->pds)->device, hwnd, level);
881 }
882
883 static HRESULT WINAPI IDirectSound8_IDirectSound8_Compact(
884     LPDIRECTSOUND8 iface)
885 {
886     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
887     TRACE("(%p)\n", This);
888     return DirectSoundDevice_Compact(((IDirectSoundImpl *)This->pds)->device);
889 }
890
891 static HRESULT WINAPI IDirectSound8_IDirectSound8_GetSpeakerConfig(
892     LPDIRECTSOUND8 iface,
893     LPDWORD lpdwSpeakerConfig)
894 {
895     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
896     TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
897     return DirectSoundDevice_GetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,lpdwSpeakerConfig);
898 }
899
900 static HRESULT WINAPI IDirectSound8_IDirectSound8_SetSpeakerConfig(
901     LPDIRECTSOUND8 iface,
902     DWORD config)
903 {
904     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
905     TRACE("(%p,0x%08x)\n",This,config);
906     return DirectSoundDevice_SetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,config);
907 }
908
909 static HRESULT WINAPI IDirectSound8_IDirectSound8_Initialize(
910     LPDIRECTSOUND8 iface,
911     LPCGUID lpcGuid)
912 {
913     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
914     TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
915     return DirectSoundDevice_Initialize(&((IDirectSoundImpl *)This->pds)->device,lpcGuid);
916 }
917
918 static HRESULT WINAPI IDirectSound8_IDirectSound8_VerifyCertification(
919     LPDIRECTSOUND8 iface,
920     LPDWORD pdwCertified)
921 {
922     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
923     TRACE("(%p, %p)\n", This, pdwCertified);
924     return DirectSoundDevice_VerifyCertification(((IDirectSoundImpl *)This->pds)->device,pdwCertified);
925 }
926
927 static const IDirectSound8Vtbl DirectSound8_DirectSound8_Vtbl =
928 {
929     IDirectSound8_IDirectSound8_QueryInterface,
930     IDirectSound8_IDirectSound8_AddRef,
931     IDirectSound8_IDirectSound8_Release,
932     IDirectSound8_IDirectSound8_CreateSoundBuffer,
933     IDirectSound8_IDirectSound8_GetCaps,
934     IDirectSound8_IDirectSound8_DuplicateSoundBuffer,
935     IDirectSound8_IDirectSound8_SetCooperativeLevel,
936     IDirectSound8_IDirectSound8_Compact,
937     IDirectSound8_IDirectSound8_GetSpeakerConfig,
938     IDirectSound8_IDirectSound8_SetSpeakerConfig,
939     IDirectSound8_IDirectSound8_Initialize,
940     IDirectSound8_IDirectSound8_VerifyCertification
941 };
942
943 static HRESULT IDirectSound8_IDirectSound8_Create(
944     LPDIRECTSOUND8 pds,
945     LPDIRECTSOUND8 * ppds)
946 {
947     IDirectSound8_IDirectSound8 * pdsds;
948     TRACE("(%p,%p)\n",pds,ppds);
949
950     if (ppds == NULL) {
951         ERR("invalid parameter: ppds == NULL\n");
952         return DSERR_INVALIDPARAM;
953     }
954
955     if (pds == NULL) {
956         ERR("invalid parameter: pds == NULL\n");
957         *ppds = NULL;
958         return DSERR_INVALIDPARAM;
959     }
960
961     pdsds = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsds));
962     if (pdsds == NULL) {
963         WARN("out of memory\n");
964         *ppds = NULL;
965         return DSERR_OUTOFMEMORY;
966     }
967
968     pdsds->lpVtbl = &DirectSound8_DirectSound8_Vtbl;
969     pdsds->ref = 0;
970     pdsds->pds = pds;
971
972     IDirectSoundImpl_AddRef(pds);
973     *ppds = (LPDIRECTSOUND8)pdsds;
974
975     return DS_OK;
976 }
977
978 HRESULT DSOUND_Create(
979     REFIID riid,
980     LPDIRECTSOUND *ppDS)
981 {
982     LPDIRECTSOUND8 pDS;
983     HRESULT hr;
984     TRACE("(%s, %p)\n", debugstr_guid(riid), ppDS);
985
986     if (!IsEqualIID(riid, &IID_IUnknown) &&
987         !IsEqualIID(riid, &IID_IDirectSound)) {
988         *ppDS = 0;
989         return E_NOINTERFACE;
990     }
991
992     /* Get dsound configuration */
993     setup_dsound_options();
994
995     hr = IDirectSoundImpl_Create(&pDS);
996     if (hr == DS_OK) {
997         hr = IDirectSound_IDirectSound_Create(pDS, ppDS);
998         if (*ppDS)
999             IDirectSound_IDirectSound_AddRef(*ppDS);
1000         else {
1001             WARN("IDirectSound_IDirectSound_Create failed\n");
1002             IDirectSound8_Release(pDS);
1003         }
1004     } else {
1005         WARN("IDirectSoundImpl_Create failed\n");
1006         *ppDS = 0;
1007     }
1008
1009     return hr;
1010 }
1011
1012 /*******************************************************************************
1013  *              DirectSoundCreate (DSOUND.1)
1014  *
1015  *  Creates and initializes a DirectSound interface.
1016  *
1017  *  PARAMS
1018  *     lpcGUID   [I] Address of the GUID that identifies the sound device.
1019  *     ppDS      [O] Address of a variable to receive the interface pointer.
1020  *     pUnkOuter [I] Must be NULL.
1021  *
1022  *  RETURNS
1023  *     Success: DS_OK
1024  *     Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
1025  *              DSERR_NODRIVER, DSERR_OUTOFMEMORY
1026  */
1027 HRESULT WINAPI DirectSoundCreate(
1028     LPCGUID lpcGUID,
1029     LPDIRECTSOUND *ppDS,
1030     IUnknown *pUnkOuter)
1031 {
1032     HRESULT hr;
1033     LPDIRECTSOUND pDS;
1034
1035     TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
1036
1037     if (ppDS == NULL) {
1038         WARN("invalid parameter: ppDS == NULL\n");
1039         return DSERR_INVALIDPARAM;
1040     }
1041
1042     if (pUnkOuter != NULL) {
1043         WARN("invalid parameter: pUnkOuter != NULL\n");
1044         *ppDS = 0;
1045         return DSERR_INVALIDPARAM;
1046     }
1047
1048     hr = DSOUND_Create(&IID_IDirectSound, &pDS);
1049     if (hr == DS_OK) {
1050         hr = IDirectSound_Initialize(pDS, lpcGUID);
1051         if (hr != DS_OK) {
1052             if (hr != DSERR_ALREADYINITIALIZED) {
1053                 IDirectSound_Release(pDS);
1054                 pDS = 0;
1055             } else
1056                 hr = DS_OK;
1057         }
1058     }
1059
1060     *ppDS = pDS;
1061
1062     return hr;
1063 }
1064
1065 HRESULT DSOUND_Create8(
1066     REFIID riid,
1067     LPDIRECTSOUND8 *ppDS)
1068 {
1069     LPDIRECTSOUND8 pDS;
1070     HRESULT hr;
1071     TRACE("(%s, %p)\n", debugstr_guid(riid), ppDS);
1072
1073     if (!IsEqualIID(riid, &IID_IUnknown) &&
1074         !IsEqualIID(riid, &IID_IDirectSound) &&
1075         !IsEqualIID(riid, &IID_IDirectSound8)) {
1076         *ppDS = 0;
1077         return E_NOINTERFACE;
1078     }
1079
1080     /* Get dsound configuration */
1081     setup_dsound_options();
1082
1083     hr = IDirectSoundImpl_Create(&pDS);
1084     if (hr == DS_OK) {
1085         hr = IDirectSound8_IDirectSound8_Create(pDS, ppDS);
1086         if (*ppDS)
1087             IDirectSound8_IDirectSound8_AddRef(*ppDS);
1088         else {
1089             WARN("IDirectSound8_IDirectSound8_Create failed\n");
1090             IDirectSound8_Release(pDS);
1091         }
1092     } else {
1093         WARN("IDirectSoundImpl_Create failed\n");
1094         *ppDS = 0;
1095     }
1096
1097     return hr;
1098 }
1099
1100 /*******************************************************************************
1101  *        DirectSoundCreate8 (DSOUND.11)
1102  *
1103  *  Creates and initializes a DirectSound8 interface.
1104  *
1105  *  PARAMS
1106  *     lpcGUID   [I] Address of the GUID that identifies the sound device.
1107  *     ppDS      [O] Address of a variable to receive the interface pointer.
1108  *     pUnkOuter [I] Must be NULL.
1109  *
1110  *  RETURNS
1111  *     Success: DS_OK
1112  *     Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
1113  *              DSERR_NODRIVER, DSERR_OUTOFMEMORY
1114  */
1115 HRESULT WINAPI DirectSoundCreate8(
1116     LPCGUID lpcGUID,
1117     LPDIRECTSOUND8 *ppDS,
1118     IUnknown *pUnkOuter)
1119 {
1120     HRESULT hr;
1121     LPDIRECTSOUND8 pDS;
1122
1123     TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
1124
1125     if (ppDS == NULL) {
1126         WARN("invalid parameter: ppDS == NULL\n");
1127         return DSERR_INVALIDPARAM;
1128     }
1129
1130     if (pUnkOuter != NULL) {
1131         WARN("invalid parameter: pUnkOuter != NULL\n");
1132         *ppDS = 0;
1133         return DSERR_INVALIDPARAM;
1134     }
1135
1136     hr = DSOUND_Create8(&IID_IDirectSound8, &pDS);
1137     if (hr == DS_OK) {
1138         hr = IDirectSound8_Initialize(pDS, lpcGUID);
1139         if (hr != DS_OK) {
1140             if (hr != DSERR_ALREADYINITIALIZED) {
1141                 IDirectSound8_Release(pDS);
1142                 pDS = 0;
1143             } else
1144                 hr = DS_OK;
1145         }
1146     }
1147
1148     *ppDS = pDS;
1149
1150     return hr;
1151 }
1152
1153 /*******************************************************************************
1154  *        DirectSoundDevice
1155  */
1156 static HRESULT DirectSoundDevice_Create(DirectSoundDevice ** ppDevice)
1157 {
1158     DirectSoundDevice * device;
1159     TRACE("(%p)\n", ppDevice);
1160
1161     /* Allocate memory */
1162     device = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DirectSoundDevice));
1163     if (device == NULL) {
1164         WARN("out of memory\n");
1165         return DSERR_OUTOFMEMORY;
1166     }
1167
1168     device->ref            = 1;
1169     device->driver         = NULL;
1170     device->priolevel      = DSSCL_NORMAL;
1171     device->fraglen        = 0;
1172     device->hwbuf          = NULL;
1173     device->buffer         = NULL;
1174     device->buflen         = 0;
1175     device->writelead      = 0;
1176     device->state          = STATE_STOPPED;
1177     device->nrofbuffers    = 0;
1178     device->buffers        = NULL;
1179     device->primary        = NULL;
1180     device->speaker_config = DSSPEAKER_STEREO | (DSSPEAKER_GEOMETRY_NARROW << 16);
1181     device->tmp_buffer     = NULL;
1182     device->tmp_buffer_len = 0;
1183
1184     /* 3D listener initial parameters */
1185     device->listener       = NULL;
1186     device->ds3dl.dwSize   = sizeof(DS3DLISTENER);
1187     device->ds3dl.vPosition.x = 0.0;
1188     device->ds3dl.vPosition.y = 0.0;
1189     device->ds3dl.vPosition.z = 0.0;
1190     device->ds3dl.vVelocity.x = 0.0;
1191     device->ds3dl.vVelocity.y = 0.0;
1192     device->ds3dl.vVelocity.z = 0.0;
1193     device->ds3dl.vOrientFront.x = 0.0;
1194     device->ds3dl.vOrientFront.y = 0.0;
1195     device->ds3dl.vOrientFront.z = 1.0;
1196     device->ds3dl.vOrientTop.x = 0.0;
1197     device->ds3dl.vOrientTop.y = 1.0;
1198     device->ds3dl.vOrientTop.z = 0.0;
1199     device->ds3dl.flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
1200     device->ds3dl.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
1201     device->ds3dl.flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
1202
1203     device->prebuf         = ds_snd_queue_max;
1204     device->guid           = GUID_NULL;
1205
1206     /* Set default wave format (may need it for waveOutOpen) */
1207     device->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(WAVEFORMATEX));
1208     if (device->pwfx == NULL) {
1209         WARN("out of memory\n");
1210         HeapFree(GetProcessHeap(),0,device);
1211         return DSERR_OUTOFMEMORY;
1212     }
1213
1214     /* We rely on the sound driver to return the actual sound format of
1215      * the device if it does not support 22050x8x2 and is given the
1216      * WAVE_DIRECTSOUND flag.
1217      */
1218     device->pwfx->wFormatTag = WAVE_FORMAT_PCM;
1219     device->pwfx->nSamplesPerSec = ds_default_sample_rate;
1220     device->pwfx->wBitsPerSample = ds_default_bits_per_sample;
1221     device->pwfx->nChannels = 2;
1222     device->pwfx->nBlockAlign = device->pwfx->wBitsPerSample * device->pwfx->nChannels / 8;
1223     device->pwfx->nAvgBytesPerSec = device->pwfx->nSamplesPerSec * device->pwfx->nBlockAlign;
1224     device->pwfx->cbSize = 0;
1225
1226     InitializeCriticalSection(&(device->mixlock));
1227     device->mixlock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DirectSoundDevice.mixlock");
1228
1229     RtlInitializeResource(&(device->buffer_list_lock));
1230
1231    *ppDevice = device;
1232
1233     return DS_OK;
1234 }
1235
1236 static ULONG DirectSoundDevice_AddRef(DirectSoundDevice * device)
1237 {
1238     ULONG ref = InterlockedIncrement(&(device->ref));
1239     TRACE("(%p) ref was %d\n", device, ref - 1);
1240     return ref;
1241 }
1242
1243 ULONG DirectSoundDevice_Release(DirectSoundDevice * device)
1244 {
1245     HRESULT hr;
1246     ULONG ref = InterlockedDecrement(&(device->ref));
1247     TRACE("(%p) ref was %u\n", device, ref + 1);
1248     if (!ref) {
1249         int i;
1250         timeKillEvent(device->timerID);
1251         timeEndPeriod(DS_TIME_RES);
1252         /* wait for timer to expire */
1253         Sleep(DS_TIME_RES+1);
1254
1255         /* The sleep above should have allowed the timer process to expire
1256          * but try to grab the lock just in case. Can't hold lock because
1257          * IDirectSoundBufferImpl_Destroy also grabs the lock */
1258         RtlAcquireResourceShared(&(device->buffer_list_lock), TRUE);
1259         RtlReleaseResource(&(device->buffer_list_lock));
1260
1261         /* It is allowed to release this object even when buffers are playing */
1262         if (device->buffers) {
1263             WARN("%d secondary buffers not released\n", device->nrofbuffers);
1264             for( i=0;i<device->nrofbuffers;i++)
1265                 IDirectSoundBufferImpl_Destroy(device->buffers[i]);
1266         }
1267
1268         if (device->primary) {
1269             WARN("primary buffer not released\n");
1270             IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)device->primary);
1271         }
1272
1273         hr = DSOUND_PrimaryDestroy(device);
1274         if (hr != DS_OK)
1275             WARN("DSOUND_PrimaryDestroy failed\n");
1276
1277         if (device->driver)
1278             IDsDriver_Close(device->driver);
1279
1280         if (device->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN)
1281             waveOutClose(device->hwo);
1282
1283         if (device->driver)
1284             IDsDriver_Release(device->driver);
1285
1286         DSOUND_renderer[device->drvdesc.dnDevNode] = NULL;
1287
1288         HeapFree(GetProcessHeap(),0,device->tmp_buffer);
1289         HeapFree(GetProcessHeap(),0,device->buffer);
1290         RtlDeleteResource(&device->buffer_list_lock);
1291         device->mixlock.DebugInfo->Spare[0] = 0;
1292         DeleteCriticalSection(&device->mixlock);
1293         HeapFree(GetProcessHeap(),0,device);
1294         TRACE("(%p) released\n", device);
1295     }
1296     return ref;
1297 }
1298
1299 HRESULT DirectSoundDevice_GetCaps(
1300     DirectSoundDevice * device,
1301     LPDSCAPS lpDSCaps)
1302 {
1303     TRACE("(%p,%p)\n",device,lpDSCaps);
1304
1305     if (device == NULL) {
1306         WARN("not initialized\n");
1307         return DSERR_UNINITIALIZED;
1308     }
1309
1310     if (lpDSCaps == NULL) {
1311         WARN("invalid parameter: lpDSCaps = NULL\n");
1312         return DSERR_INVALIDPARAM;
1313     }
1314
1315     /* check if there is enough room */
1316     if (lpDSCaps->dwSize < sizeof(*lpDSCaps)) {
1317         WARN("invalid parameter: lpDSCaps->dwSize = %d\n", lpDSCaps->dwSize);
1318         return DSERR_INVALIDPARAM;
1319     }
1320
1321     lpDSCaps->dwFlags                           = device->drvcaps.dwFlags;
1322     if (TRACE_ON(dsound)) {
1323         TRACE("(flags=0x%08x:\n",lpDSCaps->dwFlags);
1324         _dump_DSCAPS(lpDSCaps->dwFlags);
1325         DPRINTF(")\n");
1326     }
1327     lpDSCaps->dwMinSecondarySampleRate          = device->drvcaps.dwMinSecondarySampleRate;
1328     lpDSCaps->dwMaxSecondarySampleRate          = device->drvcaps.dwMaxSecondarySampleRate;
1329     lpDSCaps->dwPrimaryBuffers                  = device->drvcaps.dwPrimaryBuffers;
1330     lpDSCaps->dwMaxHwMixingAllBuffers           = device->drvcaps.dwMaxHwMixingAllBuffers;
1331     lpDSCaps->dwMaxHwMixingStaticBuffers        = device->drvcaps.dwMaxHwMixingStaticBuffers;
1332     lpDSCaps->dwMaxHwMixingStreamingBuffers     = device->drvcaps.dwMaxHwMixingStreamingBuffers;
1333     lpDSCaps->dwFreeHwMixingAllBuffers          = device->drvcaps.dwFreeHwMixingAllBuffers;
1334     lpDSCaps->dwFreeHwMixingStaticBuffers       = device->drvcaps.dwFreeHwMixingStaticBuffers;
1335     lpDSCaps->dwFreeHwMixingStreamingBuffers    = device->drvcaps.dwFreeHwMixingStreamingBuffers;
1336     lpDSCaps->dwMaxHw3DAllBuffers               = device->drvcaps.dwMaxHw3DAllBuffers;
1337     lpDSCaps->dwMaxHw3DStaticBuffers            = device->drvcaps.dwMaxHw3DStaticBuffers;
1338     lpDSCaps->dwMaxHw3DStreamingBuffers         = device->drvcaps.dwMaxHw3DStreamingBuffers;
1339     lpDSCaps->dwFreeHw3DAllBuffers              = device->drvcaps.dwFreeHw3DAllBuffers;
1340     lpDSCaps->dwFreeHw3DStaticBuffers           = device->drvcaps.dwFreeHw3DStaticBuffers;
1341     lpDSCaps->dwFreeHw3DStreamingBuffers        = device->drvcaps.dwFreeHw3DStreamingBuffers;
1342     lpDSCaps->dwTotalHwMemBytes                 = device->drvcaps.dwTotalHwMemBytes;
1343     lpDSCaps->dwFreeHwMemBytes                  = device->drvcaps.dwFreeHwMemBytes;
1344     lpDSCaps->dwMaxContigFreeHwMemBytes         = device->drvcaps.dwMaxContigFreeHwMemBytes;
1345
1346     /* driver doesn't have these */
1347     lpDSCaps->dwUnlockTransferRateHwBuffers     = 4096; /* But we have none... */
1348     lpDSCaps->dwPlayCpuOverheadSwBuffers        = 1;    /* 1% */
1349
1350     return DS_OK;
1351 }
1352
1353 HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcGUID)
1354 {
1355     HRESULT hr = DS_OK;
1356     unsigned wod, wodn;
1357     BOOLEAN found = FALSE;
1358     GUID devGUID;
1359     DirectSoundDevice * device = *ppDevice;
1360     TRACE("(%p,%s)\n",ppDevice,debugstr_guid(lpcGUID));
1361
1362     if (*ppDevice != NULL) {
1363         WARN("already initialized\n");
1364         return DSERR_ALREADYINITIALIZED;
1365     }
1366
1367     /* Default device? */
1368     if (!lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL))
1369         lpcGUID = &DSDEVID_DefaultPlayback;
1370
1371     if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
1372         WARN("invalid parameter: lpcGUID\n");
1373         return DSERR_INVALIDPARAM;
1374     }
1375
1376     /* Enumerate WINMM audio devices and find the one we want */
1377     wodn = waveOutGetNumDevs();
1378     if (!wodn) {
1379         WARN("no driver\n");
1380         return DSERR_NODRIVER;
1381     }
1382
1383     for (wod=0; wod<wodn; wod++) {
1384         if (IsEqualGUID( &devGUID, &DSOUND_renderer_guids[wod])) {
1385             found = TRUE;
1386             break;
1387         }
1388     }
1389
1390     if (found == FALSE) {
1391         WARN("No device found matching given ID!\n");
1392         return DSERR_NODRIVER;
1393     }
1394
1395     if (DSOUND_renderer[wod]) {
1396         if (IsEqualGUID(&devGUID, &DSOUND_renderer[wod]->guid)) {
1397             device = DSOUND_renderer[wod];
1398             DirectSoundDevice_AddRef(device);
1399             *ppDevice = device;
1400             return DS_OK;
1401         } else {
1402             ERR("device GUID doesn't match\n");
1403             hr = DSERR_GENERIC;
1404             return hr;
1405         }
1406     } else {
1407         hr = DirectSoundDevice_Create(&device);
1408         if (hr != DS_OK) {
1409             WARN("DirectSoundDevice_Create failed\n");
1410             return hr;
1411         }
1412     }
1413
1414     *ppDevice = device;
1415     device->guid = devGUID;
1416
1417     /* DRV_QUERYDSOUNDIFACE is a "Wine extension" to get the DSound interface */
1418     waveOutMessage((HWAVEOUT)wod, DRV_QUERYDSOUNDIFACE, (DWORD_PTR)&device->driver, 0);
1419
1420     /* Disable the direct sound driver to force emulation if requested. */
1421     if (ds_hw_accel == DS_HW_ACCEL_EMULATION)
1422         device->driver = NULL;
1423
1424     /* Get driver description */
1425     if (device->driver) {
1426         hr = IDsDriver_GetDriverDesc(device->driver,&(device->drvdesc));
1427         if (hr != DS_OK) {
1428             WARN("IDsDriver_GetDriverDesc failed\n");
1429             return hr;
1430         }
1431     } else {
1432         /* if no DirectSound interface available, use WINMM API instead */
1433         device->drvdesc.dwFlags = DSDDESC_DOMMSYSTEMOPEN | DSDDESC_DOMMSYSTEMSETFORMAT;
1434     }
1435
1436     device->drvdesc.dnDevNode = wod;
1437
1438     /* If the driver requests being opened through MMSYSTEM
1439      * (which is recommended by the DDK), it is supposed to happen
1440      * before the DirectSound interface is opened */
1441     if (device->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN)
1442     {
1443         DWORD flags = CALLBACK_FUNCTION;
1444
1445         /* disable direct sound if requested */
1446         if (ds_hw_accel != DS_HW_ACCEL_EMULATION)
1447             flags |= WAVE_DIRECTSOUND;
1448
1449         hr = mmErr(waveOutOpen(&(device->hwo),
1450                                 device->drvdesc.dnDevNode, device->pwfx,
1451                                 (DWORD_PTR)DSOUND_callback, (DWORD)device,
1452                                 flags));
1453         if (hr != DS_OK) {
1454             WARN("waveOutOpen failed\n");
1455             return hr;
1456         }
1457     }
1458
1459     if (device->driver) {
1460         hr = IDsDriver_Open(device->driver);
1461         if (hr != DS_OK) {
1462             WARN("IDsDriver_Open failed\n");
1463             return hr;
1464         }
1465
1466         /* the driver is now open, so it's now allowed to call GetCaps */
1467         hr = IDsDriver_GetCaps(device->driver,&(device->drvcaps));
1468         if (hr != DS_OK) {
1469             WARN("IDsDriver_GetCaps failed\n");
1470             return hr;
1471         }
1472     } else {
1473         WAVEOUTCAPSA woc;
1474         hr = mmErr(waveOutGetDevCapsA(device->drvdesc.dnDevNode, &woc, sizeof(woc)));
1475         if (hr != DS_OK) {
1476             WARN("waveOutGetDevCaps failed\n");
1477             return hr;
1478         }
1479         ZeroMemory(&device->drvcaps, sizeof(device->drvcaps));
1480         if ((woc.dwFormats & WAVE_FORMAT_1M08) ||
1481             (woc.dwFormats & WAVE_FORMAT_2M08) ||
1482             (woc.dwFormats & WAVE_FORMAT_4M08) ||
1483             (woc.dwFormats & WAVE_FORMAT_48M08) ||
1484             (woc.dwFormats & WAVE_FORMAT_96M08)) {
1485             device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT;
1486             device->drvcaps.dwFlags |= DSCAPS_PRIMARYMONO;
1487         }
1488         if ((woc.dwFormats & WAVE_FORMAT_1M16) ||
1489             (woc.dwFormats & WAVE_FORMAT_2M16) ||
1490             (woc.dwFormats & WAVE_FORMAT_4M16) ||
1491             (woc.dwFormats & WAVE_FORMAT_48M16) ||
1492             (woc.dwFormats & WAVE_FORMAT_96M16)) {
1493             device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT;
1494             device->drvcaps.dwFlags |= DSCAPS_PRIMARYMONO;
1495         }
1496         if ((woc.dwFormats & WAVE_FORMAT_1S08) ||
1497             (woc.dwFormats & WAVE_FORMAT_2S08) ||
1498             (woc.dwFormats & WAVE_FORMAT_4S08) ||
1499             (woc.dwFormats & WAVE_FORMAT_48S08) ||
1500             (woc.dwFormats & WAVE_FORMAT_96S08)) {
1501             device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT;
1502             device->drvcaps.dwFlags |= DSCAPS_PRIMARYSTEREO;
1503         }
1504         if ((woc.dwFormats & WAVE_FORMAT_1S16) ||
1505             (woc.dwFormats & WAVE_FORMAT_2S16) ||
1506             (woc.dwFormats & WAVE_FORMAT_4S16) ||
1507             (woc.dwFormats & WAVE_FORMAT_48S16) ||
1508             (woc.dwFormats & WAVE_FORMAT_96S16)) {
1509             device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT;
1510             device->drvcaps.dwFlags |= DSCAPS_PRIMARYSTEREO;
1511         }
1512         if (ds_emuldriver)
1513             device->drvcaps.dwFlags |= DSCAPS_EMULDRIVER;
1514         device->drvcaps.dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
1515         device->drvcaps.dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
1516         device->drvcaps.dwPrimaryBuffers = 1;
1517     }
1518
1519     hr = DSOUND_PrimaryCreate(device);
1520     if (hr == DS_OK) {
1521         DSOUND_renderer[device->drvdesc.dnDevNode] = device;
1522         timeBeginPeriod(DS_TIME_RES);
1523         DSOUND_renderer[device->drvdesc.dnDevNode]->timerID = timeSetEvent(DS_TIME_DEL, DS_TIME_RES, DSOUND_timer,
1524             (DWORD_PTR)DSOUND_renderer[device->drvdesc.dnDevNode], TIME_PERIODIC | TIME_CALLBACK_FUNCTION);
1525     } else {
1526         WARN("DSOUND_PrimaryCreate failed\n");
1527     }
1528
1529     return hr;
1530 }
1531
1532 HRESULT DirectSoundDevice_CreateSoundBuffer(
1533     DirectSoundDevice * device,
1534     LPCDSBUFFERDESC dsbd,
1535     LPLPDIRECTSOUNDBUFFER ppdsb,
1536     LPUNKNOWN lpunk,
1537     BOOL from8)
1538 {
1539     HRESULT hres = DS_OK;
1540     TRACE("(%p,%p,%p,%p)\n",device,dsbd,ppdsb,lpunk);
1541
1542     if (device == NULL) {
1543         WARN("not initialized\n");
1544         return DSERR_UNINITIALIZED;
1545     }
1546
1547     if (dsbd == NULL) {
1548         WARN("invalid parameter: dsbd == NULL\n");
1549         return DSERR_INVALIDPARAM;
1550     }
1551
1552     if (dsbd->dwSize != sizeof(DSBUFFERDESC) &&
1553         dsbd->dwSize != sizeof(DSBUFFERDESC1)) {
1554         WARN("invalid parameter: dsbd\n");
1555         return DSERR_INVALIDPARAM;
1556     }
1557
1558     if (ppdsb == NULL) {
1559         WARN("invalid parameter: ppdsb == NULL\n");
1560         return DSERR_INVALIDPARAM;
1561     }
1562
1563     if (TRACE_ON(dsound)) {
1564         TRACE("(structsize=%d)\n",dsbd->dwSize);
1565         TRACE("(flags=0x%08x:\n",dsbd->dwFlags);
1566         _dump_DSBCAPS(dsbd->dwFlags);
1567         DPRINTF(")\n");
1568         TRACE("(bufferbytes=%d)\n",dsbd->dwBufferBytes);
1569         TRACE("(lpwfxFormat=%p)\n",dsbd->lpwfxFormat);
1570     }
1571
1572     if (dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) {
1573         if (dsbd->lpwfxFormat != NULL) {
1574             WARN("invalid parameter: dsbd->lpwfxFormat must be NULL for "
1575                  "primary buffer\n");
1576             return DSERR_INVALIDPARAM;
1577         }
1578
1579         if (device->primary) {
1580             WARN("Primary Buffer already created\n");
1581             IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(device->primary));
1582             *ppdsb = (LPDIRECTSOUNDBUFFER)(device->primary);
1583         } else {
1584            device->dsbd = *dsbd;
1585            hres = PrimaryBufferImpl_Create(device, (PrimaryBufferImpl**)&(device->primary), &(device->dsbd));
1586            if (device->primary) {
1587                IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(device->primary));
1588                *ppdsb = (LPDIRECTSOUNDBUFFER)(device->primary);
1589            } else
1590                WARN("PrimaryBufferImpl_Create failed\n");
1591         }
1592     } else {
1593         IDirectSoundBufferImpl * dsb;
1594
1595         if (dsbd->lpwfxFormat == NULL) {
1596             WARN("invalid parameter: dsbd->lpwfxFormat can't be NULL for "
1597                  "secondary buffer\n");
1598             return DSERR_INVALIDPARAM;
1599         }
1600
1601         TRACE("(formattag=0x%04x,chans=%d,samplerate=%d,"
1602               "bytespersec=%d,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
1603               dsbd->lpwfxFormat->wFormatTag, dsbd->lpwfxFormat->nChannels,
1604               dsbd->lpwfxFormat->nSamplesPerSec,
1605               dsbd->lpwfxFormat->nAvgBytesPerSec,
1606               dsbd->lpwfxFormat->nBlockAlign,
1607               dsbd->lpwfxFormat->wBitsPerSample, dsbd->lpwfxFormat->cbSize);
1608
1609         if (from8 && (dsbd->dwFlags & DSBCAPS_CTRL3D) && (dsbd->lpwfxFormat->nChannels != 1)) {
1610             WARN("invalid parameter: 3D buffer format must be mono\n");
1611             return DSERR_INVALIDPARAM;
1612         }
1613
1614         hres = IDirectSoundBufferImpl_Create(device, (IDirectSoundBufferImpl**)&dsb, dsbd);
1615         if (dsb) {
1616             hres = SecondaryBufferImpl_Create(dsb, (SecondaryBufferImpl**)ppdsb);
1617             if (*ppdsb) {
1618                 dsb->secondary = (SecondaryBufferImpl*)*ppdsb;
1619                 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)*ppdsb);
1620             } else
1621                 WARN("SecondaryBufferImpl_Create failed\n");
1622         } else
1623            WARN("IDirectSoundBufferImpl_Create failed\n");
1624    }
1625
1626    return hres;
1627 }
1628
1629 HRESULT DirectSoundDevice_DuplicateSoundBuffer(
1630     DirectSoundDevice * device,
1631     LPDIRECTSOUNDBUFFER psb,
1632     LPLPDIRECTSOUNDBUFFER ppdsb)
1633 {
1634     HRESULT hres = DS_OK;
1635     IDirectSoundBufferImpl* dsb;
1636     TRACE("(%p,%p,%p)\n",device,psb,ppdsb);
1637
1638     if (device == NULL) {
1639         WARN("not initialized\n");
1640         return DSERR_UNINITIALIZED;
1641     }
1642
1643     if (psb == NULL) {
1644         WARN("invalid parameter: psb == NULL\n");
1645         return DSERR_INVALIDPARAM;
1646     }
1647
1648     if (ppdsb == NULL) {
1649         WARN("invalid parameter: ppdsb == NULL\n");
1650         return DSERR_INVALIDPARAM;
1651     }
1652
1653     /* make sure we have a secondary buffer */
1654     if ((PrimaryBufferImpl *)psb == device->primary) {
1655         WARN("trying to duplicate primary buffer\n");
1656         *ppdsb = NULL;
1657         return DSERR_INVALIDCALL;
1658     }
1659
1660     /* duplicate the actual buffer implementation */
1661     hres = IDirectSoundBufferImpl_Duplicate(device, &dsb,
1662                                            ((SecondaryBufferImpl *)psb)->dsb);
1663
1664     if (hres == DS_OK) {
1665         /* create a new secondary buffer using the new implementation */
1666         hres = SecondaryBufferImpl_Create(dsb, (SecondaryBufferImpl**)ppdsb);
1667         if (*ppdsb) {
1668             dsb->secondary = (SecondaryBufferImpl*)*ppdsb;
1669             IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)*ppdsb);
1670         } else {
1671             WARN("SecondaryBufferImpl_Create failed\n");
1672             IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)dsb);
1673             IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER8)dsb);
1674         }
1675     }
1676
1677     return hres;
1678 }
1679
1680 HRESULT DirectSoundDevice_SetCooperativeLevel(
1681     DirectSoundDevice * device,
1682     HWND hwnd,
1683     DWORD level)
1684 {
1685     TRACE("(%p,%p,%s)\n",device,hwnd,dumpCooperativeLevel(level));
1686
1687     if (device == NULL) {
1688         WARN("not initialized\n");
1689         return DSERR_UNINITIALIZED;
1690     }
1691
1692     if (level==DSSCL_PRIORITY || level==DSSCL_EXCLUSIVE) {
1693         WARN("level=%s not fully supported\n",
1694              level==DSSCL_PRIORITY ? "DSSCL_PRIORITY" : "DSSCL_EXCLUSIVE");
1695     }
1696
1697     device->priolevel = level;
1698     return DS_OK;
1699 }
1700
1701 HRESULT DirectSoundDevice_Compact(
1702     DirectSoundDevice * device)
1703 {
1704     TRACE("(%p)\n", device);
1705
1706     if (device == NULL) {
1707         WARN("not initialized\n");
1708         return DSERR_UNINITIALIZED;
1709     }
1710
1711     if (device->priolevel < DSSCL_PRIORITY) {
1712         WARN("incorrect priority level\n");
1713         return DSERR_PRIOLEVELNEEDED;
1714     }
1715
1716     return DS_OK;
1717 }
1718
1719 HRESULT DirectSoundDevice_GetSpeakerConfig(
1720     DirectSoundDevice * device,
1721     LPDWORD lpdwSpeakerConfig)
1722 {
1723     TRACE("(%p, %p)\n", device, lpdwSpeakerConfig);
1724
1725     if (device == NULL) {
1726         WARN("not initialized\n");
1727         return DSERR_UNINITIALIZED;
1728     }
1729
1730     if (lpdwSpeakerConfig == NULL) {
1731         WARN("invalid parameter: lpdwSpeakerConfig == NULL\n");
1732         return DSERR_INVALIDPARAM;
1733     }
1734
1735     WARN("not fully functional\n");
1736     *lpdwSpeakerConfig = device->speaker_config;
1737     return DS_OK;
1738 }
1739
1740 HRESULT DirectSoundDevice_SetSpeakerConfig(
1741     DirectSoundDevice * device,
1742     DWORD config)
1743 {
1744     TRACE("(%p,0x%08x)\n",device,config);
1745
1746     if (device == NULL) {
1747         WARN("not initialized\n");
1748         return DSERR_UNINITIALIZED;
1749     }
1750
1751     device->speaker_config = config;
1752     WARN("not fully functional\n");
1753     return DS_OK;
1754 }
1755
1756 static HRESULT DirectSoundDevice_VerifyCertification(
1757     DirectSoundDevice * device,
1758     LPDWORD pdwCertified)
1759 {
1760     TRACE("(%p, %p)\n",device,pdwCertified);
1761
1762     if (device == NULL) {
1763         WARN("not initialized\n");
1764         return DSERR_UNINITIALIZED;
1765     }
1766
1767     if (device->drvcaps.dwFlags & DSCAPS_CERTIFIED)
1768         *pdwCertified = DS_CERTIFIED;
1769     else
1770         *pdwCertified = DS_UNCERTIFIED;
1771
1772     return DS_OK;
1773 }
1774
1775 /*
1776  * Add secondary buffer to buffer list.
1777  * Gets exclusive access to buffer for writing.
1778  */
1779 HRESULT DirectSoundDevice_AddBuffer(
1780     DirectSoundDevice * device,
1781     IDirectSoundBufferImpl * pDSB)
1782 {
1783     IDirectSoundBufferImpl **newbuffers;
1784     HRESULT hr = DS_OK;
1785
1786     TRACE("(%p, %p)\n", device, pDSB);
1787
1788     RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
1789
1790     if (device->buffers)
1791         newbuffers = HeapReAlloc(GetProcessHeap(),0,device->buffers,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
1792     else
1793         newbuffers = HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
1794
1795     if (newbuffers) {
1796         device->buffers = newbuffers;
1797         device->buffers[device->nrofbuffers] = pDSB;
1798         device->nrofbuffers++;
1799         TRACE("buffer count is now %d\n", device->nrofbuffers);
1800     } else {
1801         ERR("out of memory for buffer list! Current buffer count is %d\n", device->nrofbuffers);
1802         hr = DSERR_OUTOFMEMORY;
1803     }
1804
1805     RtlReleaseResource(&(device->buffer_list_lock));
1806
1807     return hr;
1808 }
1809
1810 /*
1811  * Remove secondary buffer from buffer list.
1812  * Gets exclusive access to buffer for writing.
1813  */
1814 HRESULT DirectSoundDevice_RemoveBuffer(
1815     DirectSoundDevice * device,
1816     IDirectSoundBufferImpl * pDSB)
1817 {
1818     int i;
1819     HRESULT hr = DS_OK;
1820
1821     TRACE("(%p, %p)\n", device, pDSB);
1822
1823     RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
1824
1825     for (i = 0; i < device->nrofbuffers; i++)
1826         if (device->buffers[i] == pDSB)
1827             break;
1828
1829     if (i < device->nrofbuffers) {
1830         /* Put the last buffer of the list in the (now empty) position */
1831         device->buffers[i] = device->buffers[device->nrofbuffers - 1];
1832         device->nrofbuffers--;
1833         device->buffers = HeapReAlloc(GetProcessHeap(),0,device->buffers,sizeof(LPDIRECTSOUNDBUFFER8)*device->nrofbuffers);
1834         TRACE("buffer count is now %d\n", device->nrofbuffers);
1835     }
1836
1837     if (device->nrofbuffers == 0) {
1838         HeapFree(GetProcessHeap(),0,device->buffers);
1839         device->buffers = NULL;
1840     }
1841
1842     RtlReleaseResource(&(device->buffer_list_lock));
1843
1844     return hr;
1845 }