kernel32: Print a fixme only once.
[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 "winreg.h"
32 #include "mmsystem.h"
33 #include "winternl.h"
34 #include "mmddk.h"
35 #include "wine/debug.h"
36 #include "dsound.h"
37 #include "dsdriver.h"
38 #include "dsound_private.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
41
42 /*****************************************************************************
43  * IDirectSound COM components
44  */
45 struct IDirectSound_IUnknown {
46     const IUnknownVtbl         *lpVtbl;
47     LONG                        ref;
48     LPDIRECTSOUND8              pds;
49 };
50
51 static HRESULT IDirectSound_IUnknown_Create(LPDIRECTSOUND8 pds, LPUNKNOWN * ppunk);
52
53 struct IDirectSound_IDirectSound {
54     const IDirectSoundVtbl     *lpVtbl;
55     LONG                        ref;
56     LPDIRECTSOUND8              pds;
57 };
58
59 static HRESULT IDirectSound_IDirectSound_Create(LPDIRECTSOUND8 pds, LPDIRECTSOUND * ppds);
60
61 /*****************************************************************************
62  * IDirectSound8 COM components
63  */
64 struct IDirectSound8_IUnknown {
65     const IUnknownVtbl         *lpVtbl;
66     LONG                        ref;
67     LPDIRECTSOUND8              pds;
68 };
69
70 static HRESULT IDirectSound8_IUnknown_Create(LPDIRECTSOUND8 pds, LPUNKNOWN * ppunk);
71 static ULONG WINAPI IDirectSound8_IUnknown_AddRef(LPUNKNOWN iface);
72
73 struct IDirectSound8_IDirectSound {
74     const IDirectSoundVtbl     *lpVtbl;
75     LONG                        ref;
76     LPDIRECTSOUND8              pds;
77 };
78
79 static HRESULT IDirectSound8_IDirectSound_Create(LPDIRECTSOUND8 pds, LPDIRECTSOUND * ppds);
80 static ULONG WINAPI IDirectSound8_IDirectSound_AddRef(LPDIRECTSOUND iface);
81
82 struct IDirectSound8_IDirectSound8 {
83     const IDirectSound8Vtbl    *lpVtbl;
84     LONG                        ref;
85     LPDIRECTSOUND8              pds;
86 };
87
88 static HRESULT IDirectSound8_IDirectSound8_Create(LPDIRECTSOUND8 pds, LPDIRECTSOUND8 * ppds);
89 static ULONG WINAPI IDirectSound8_IDirectSound8_AddRef(LPDIRECTSOUND8 iface);
90
91 /*****************************************************************************
92  * IDirectSound implementation structure
93  */
94 struct IDirectSoundImpl
95 {
96     LONG                        ref;
97
98     DirectSoundDevice          *device;
99     LPUNKNOWN                   pUnknown;
100     LPDIRECTSOUND               pDS;
101     LPDIRECTSOUND8              pDS8;
102 };
103
104 static HRESULT IDirectSoundImpl_Create(LPDIRECTSOUND8 * ppds);
105
106 static ULONG WINAPI IDirectSound_IUnknown_AddRef(LPUNKNOWN iface);
107 static ULONG WINAPI IDirectSound_IDirectSound_AddRef(LPDIRECTSOUND iface);
108
109 static HRESULT DirectSoundDevice_VerifyCertification(DirectSoundDevice * device, LPDWORD pdwCertified);
110
111 const char * dumpCooperativeLevel(DWORD level)
112 {
113     static char unknown[32];
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     sprintf(unknown, "Unknown(%08x)", level);
123     return unknown;
124 }
125
126 static void _dump_DSCAPS(DWORD xmask) {
127     struct {
128         DWORD   mask;
129         const char    *name;
130     } flags[] = {
131 #define FE(x) { x, #x },
132         FE(DSCAPS_PRIMARYMONO)
133         FE(DSCAPS_PRIMARYSTEREO)
134         FE(DSCAPS_PRIMARY8BIT)
135         FE(DSCAPS_PRIMARY16BIT)
136         FE(DSCAPS_CONTINUOUSRATE)
137         FE(DSCAPS_EMULDRIVER)
138         FE(DSCAPS_CERTIFIED)
139         FE(DSCAPS_SECONDARYMONO)
140         FE(DSCAPS_SECONDARYSTEREO)
141         FE(DSCAPS_SECONDARY8BIT)
142         FE(DSCAPS_SECONDARY16BIT)
143 #undef FE
144     };
145     unsigned int     i;
146
147     for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
148         if ((flags[i].mask & xmask) == flags[i].mask)
149             DPRINTF("%s ",flags[i].name);
150 }
151
152 static void _dump_DSBCAPS(DWORD xmask) {
153     struct {
154         DWORD   mask;
155         const char    *name;
156     } flags[] = {
157 #define FE(x) { x, #x },
158         FE(DSBCAPS_PRIMARYBUFFER)
159         FE(DSBCAPS_STATIC)
160         FE(DSBCAPS_LOCHARDWARE)
161         FE(DSBCAPS_LOCSOFTWARE)
162         FE(DSBCAPS_CTRL3D)
163         FE(DSBCAPS_CTRLFREQUENCY)
164         FE(DSBCAPS_CTRLPAN)
165         FE(DSBCAPS_CTRLVOLUME)
166         FE(DSBCAPS_CTRLPOSITIONNOTIFY)
167         FE(DSBCAPS_STICKYFOCUS)
168         FE(DSBCAPS_GLOBALFOCUS)
169         FE(DSBCAPS_GETCURRENTPOSITION2)
170         FE(DSBCAPS_MUTE3DATMAXDISTANCE)
171 #undef FE
172     };
173     unsigned int     i;
174
175     for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
176         if ((flags[i].mask & xmask) == flags[i].mask)
177             DPRINTF("%s ",flags[i].name);
178 }
179
180 /*******************************************************************************
181  *              IDirectSoundImpl_DirectSound
182  */
183 static HRESULT DSOUND_QueryInterface(
184     LPDIRECTSOUND8 iface,
185     REFIID riid,
186     LPVOID * ppobj)
187 {
188     IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
189     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
190
191     if (ppobj == NULL) {
192         WARN("invalid parameter\n");
193         return E_INVALIDARG;
194     }
195
196     if (IsEqualIID(riid, &IID_IUnknown)) {
197         if (!This->pUnknown) {
198             IDirectSound_IUnknown_Create(iface, &This->pUnknown);
199             if (!This->pUnknown) {
200                 WARN("IDirectSound_IUnknown_Create() failed\n");
201                 *ppobj = NULL;
202                 return E_NOINTERFACE;
203             }
204         }
205         IDirectSound_IUnknown_AddRef(This->pUnknown);
206         *ppobj = This->pUnknown;
207         return S_OK;
208     } else if (IsEqualIID(riid, &IID_IDirectSound)) {
209         if (!This->pDS) {
210             IDirectSound_IDirectSound_Create(iface, &This->pDS);
211             if (!This->pDS) {
212                 WARN("IDirectSound_IDirectSound_Create() failed\n");
213                 *ppobj = NULL;
214                 return E_NOINTERFACE;
215             }
216         }
217         IDirectSound_IDirectSound_AddRef(This->pDS);
218         *ppobj = This->pDS;
219         return S_OK;
220     }
221
222     *ppobj = NULL;
223     WARN("Unknown IID %s\n",debugstr_guid(riid));
224     return E_NOINTERFACE;
225 }
226
227 static HRESULT DSOUND_QueryInterface8(
228     LPDIRECTSOUND8 iface,
229     REFIID riid,
230     LPVOID * ppobj)
231 {
232     IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
233     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
234
235     if (ppobj == NULL) {
236         WARN("invalid parameter\n");
237         return E_INVALIDARG;
238     }
239
240     if (IsEqualIID(riid, &IID_IUnknown)) {
241         if (!This->pUnknown) {
242             IDirectSound8_IUnknown_Create(iface, &This->pUnknown);
243             if (!This->pUnknown) {
244                 WARN("IDirectSound8_IUnknown_Create() failed\n");
245                 *ppobj = NULL;
246                 return E_NOINTERFACE;
247             }
248         }
249         IDirectSound8_IUnknown_AddRef(This->pUnknown);
250         *ppobj = This->pUnknown;
251         return S_OK;
252     } else if (IsEqualIID(riid, &IID_IDirectSound)) {
253         if (!This->pDS) {
254             IDirectSound8_IDirectSound_Create(iface, &This->pDS);
255             if (!This->pDS) {
256                 WARN("IDirectSound8_IDirectSound_Create() failed\n");
257                 *ppobj = NULL;
258                 return E_NOINTERFACE;
259             }
260         }
261         IDirectSound8_IDirectSound_AddRef(This->pDS);
262         *ppobj = This->pDS;
263         return S_OK;
264     } else if (IsEqualIID(riid, &IID_IDirectSound8)) {
265         if (!This->pDS8) {
266             IDirectSound8_IDirectSound8_Create(iface, &This->pDS8);
267             if (!This->pDS8) {
268                 WARN("IDirectSound8_IDirectSound8_Create() failed\n");
269                 *ppobj = NULL;
270                 return E_NOINTERFACE;
271             }
272         }
273         IDirectSound8_IDirectSound8_AddRef(This->pDS8);
274         *ppobj = This->pDS8;
275         return S_OK;
276     }
277
278     *ppobj = NULL;
279     WARN("Unknown IID %s\n",debugstr_guid(riid));
280     return E_NOINTERFACE;
281 }
282
283 static ULONG IDirectSoundImpl_AddRef(
284     LPDIRECTSOUND8 iface)
285 {
286     IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
287     ULONG ref = InterlockedIncrement(&(This->ref));
288     TRACE("(%p) ref was %d\n", This, ref - 1);
289     return ref;
290 }
291
292 static ULONG IDirectSoundImpl_Release(
293     LPDIRECTSOUND8 iface)
294 {
295     IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
296     ULONG ref = InterlockedDecrement(&(This->ref));
297     TRACE("(%p) ref was %d\n", This, ref + 1);
298
299     if (!ref) {
300         if (This->device)
301             DirectSoundDevice_Release(This->device);
302         HeapFree(GetProcessHeap(),0,This);
303         TRACE("(%p) released\n", This);
304     }
305     return ref;
306 }
307
308 static HRESULT IDirectSoundImpl_Create(
309     LPDIRECTSOUND8 * ppDS)
310 {
311     IDirectSoundImpl* pDS;
312     TRACE("(%p)\n",ppDS);
313
314     /* Allocate memory */
315     pDS = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundImpl));
316     if (pDS == NULL) {
317         WARN("out of memory\n");
318         *ppDS = NULL;
319         return DSERR_OUTOFMEMORY;
320     }
321
322     pDS->ref    = 0;
323     pDS->device = NULL;
324
325     *ppDS = (LPDIRECTSOUND8)pDS;
326
327     return DS_OK;
328 }
329
330 /*******************************************************************************
331  *              IDirectSound_IUnknown
332  */
333 static HRESULT WINAPI IDirectSound_IUnknown_QueryInterface(
334     LPUNKNOWN iface,
335     REFIID riid,
336     LPVOID * ppobj)
337 {
338     IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
339     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
340     return DSOUND_QueryInterface(This->pds, riid, ppobj);
341 }
342
343 static ULONG WINAPI IDirectSound_IUnknown_AddRef(
344     LPUNKNOWN iface)
345 {
346     IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
347     ULONG ref = InterlockedIncrement(&(This->ref));
348     TRACE("(%p) ref was %d\n", This, ref - 1);
349     return ref;
350 }
351
352 static ULONG WINAPI IDirectSound_IUnknown_Release(
353     LPUNKNOWN iface)
354 {
355     IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
356     ULONG ref = InterlockedDecrement(&(This->ref));
357     TRACE("(%p) ref was %d\n", This, ref + 1);
358     if (!ref) {
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_Release(This->pds);
438         HeapFree(GetProcessHeap(), 0, This);
439         TRACE("(%p) released\n", This);
440     }
441     return ref;
442 }
443
444 static HRESULT WINAPI IDirectSound_IDirectSound_CreateSoundBuffer(
445     LPDIRECTSOUND iface,
446     LPCDSBUFFERDESC dsbd,
447     LPLPDIRECTSOUNDBUFFER ppdsb,
448     LPUNKNOWN lpunk)
449 {
450     IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
451     TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
452     return DirectSoundDevice_CreateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,dsbd,ppdsb,lpunk,FALSE);
453 }
454
455 static HRESULT WINAPI IDirectSound_IDirectSound_GetCaps(
456     LPDIRECTSOUND iface,
457     LPDSCAPS lpDSCaps)
458 {
459     IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
460     TRACE("(%p,%p)\n",This,lpDSCaps);
461     return DirectSoundDevice_GetCaps(((IDirectSoundImpl *)This->pds)->device, lpDSCaps);
462 }
463
464 static HRESULT WINAPI IDirectSound_IDirectSound_DuplicateSoundBuffer(
465     LPDIRECTSOUND iface,
466     LPDIRECTSOUNDBUFFER psb,
467     LPLPDIRECTSOUNDBUFFER ppdsb)
468 {
469     IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
470     TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
471     return DirectSoundDevice_DuplicateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,psb,ppdsb);
472 }
473
474 static HRESULT WINAPI IDirectSound_IDirectSound_SetCooperativeLevel(
475     LPDIRECTSOUND iface,
476     HWND hwnd,
477     DWORD level)
478 {
479     IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
480     TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level));
481     return DirectSoundDevice_SetCooperativeLevel(((IDirectSoundImpl *)This->pds)->device, hwnd, level);
482 }
483
484 static HRESULT WINAPI IDirectSound_IDirectSound_Compact(
485     LPDIRECTSOUND iface)
486 {
487     IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
488     TRACE("(%p)\n", This);
489     return DirectSoundDevice_Compact(((IDirectSoundImpl *)This->pds)->device);
490 }
491
492 static HRESULT WINAPI IDirectSound_IDirectSound_GetSpeakerConfig(
493     LPDIRECTSOUND iface,
494     LPDWORD lpdwSpeakerConfig)
495 {
496     IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
497     TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
498     return DirectSoundDevice_GetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,lpdwSpeakerConfig);
499 }
500
501 static HRESULT WINAPI IDirectSound_IDirectSound_SetSpeakerConfig(
502     LPDIRECTSOUND iface,
503     DWORD config)
504 {
505     IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
506     TRACE("(%p,0x%08x)\n",This,config);
507     return DirectSoundDevice_SetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,config);
508 }
509
510 static HRESULT WINAPI IDirectSound_IDirectSound_Initialize(
511     LPDIRECTSOUND iface,
512     LPCGUID lpcGuid)
513 {
514     IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
515     TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
516     return DirectSoundDevice_Initialize(&((IDirectSoundImpl *)This->pds)->device,lpcGuid);
517 }
518
519 static const IDirectSoundVtbl DirectSound_DirectSound_Vtbl =
520 {
521     IDirectSound_IDirectSound_QueryInterface,
522     IDirectSound_IDirectSound_AddRef,
523     IDirectSound_IDirectSound_Release,
524     IDirectSound_IDirectSound_CreateSoundBuffer,
525     IDirectSound_IDirectSound_GetCaps,
526     IDirectSound_IDirectSound_DuplicateSoundBuffer,
527     IDirectSound_IDirectSound_SetCooperativeLevel,
528     IDirectSound_IDirectSound_Compact,
529     IDirectSound_IDirectSound_GetSpeakerConfig,
530     IDirectSound_IDirectSound_SetSpeakerConfig,
531     IDirectSound_IDirectSound_Initialize
532 };
533
534 static HRESULT IDirectSound_IDirectSound_Create(
535     LPDIRECTSOUND8  pds,
536     LPDIRECTSOUND * ppds)
537 {
538     IDirectSound_IDirectSound * pdsds;
539     TRACE("(%p,%p)\n",pds,ppds);
540
541     if (ppds == NULL) {
542         ERR("invalid parameter: ppds == NULL\n");
543         return DSERR_INVALIDPARAM;
544     }
545
546     if (pds == NULL) {
547         ERR("invalid parameter: pds == NULL\n");
548         *ppds = NULL;
549         return DSERR_INVALIDPARAM;
550     }
551
552     pdsds = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsds));
553     if (pdsds == NULL) {
554         WARN("out of memory\n");
555         *ppds = NULL;
556         return DSERR_OUTOFMEMORY;
557     }
558
559     pdsds->lpVtbl = &DirectSound_DirectSound_Vtbl;
560     pdsds->ref = 0;
561     pdsds->pds = pds;
562
563     IDirectSoundImpl_AddRef(pds);
564     *ppds = (LPDIRECTSOUND)pdsds;
565
566     return DS_OK;
567 }
568
569 /*******************************************************************************
570  *              IDirectSound8_IUnknown
571  */
572 static HRESULT WINAPI IDirectSound8_IUnknown_QueryInterface(
573     LPUNKNOWN iface,
574     REFIID riid,
575     LPVOID * ppobj)
576 {
577     IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
578     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
579     return DSOUND_QueryInterface8(This->pds, riid, ppobj);
580 }
581
582 static ULONG WINAPI IDirectSound8_IUnknown_AddRef(
583     LPUNKNOWN iface)
584 {
585     IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
586     ULONG ref = InterlockedIncrement(&(This->ref));
587     TRACE("(%p) ref was %d\n", This, ref - 1);
588     return ref;
589 }
590
591 static ULONG WINAPI IDirectSound8_IUnknown_Release(
592     LPUNKNOWN iface)
593 {
594     IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
595     ULONG ref = InterlockedDecrement(&(This->ref));
596     TRACE("(%p) ref was %d\n", This, ref + 1);
597     if (!ref) {
598         IDirectSoundImpl_Release(This->pds);
599         HeapFree(GetProcessHeap(), 0, This);
600         TRACE("(%p) released\n", This);
601     }
602     return ref;
603 }
604
605 static const IUnknownVtbl DirectSound8_Unknown_Vtbl =
606 {
607     IDirectSound8_IUnknown_QueryInterface,
608     IDirectSound8_IUnknown_AddRef,
609     IDirectSound8_IUnknown_Release
610 };
611
612 static HRESULT IDirectSound8_IUnknown_Create(
613     LPDIRECTSOUND8 pds,
614     LPUNKNOWN * ppunk)
615 {
616     IDirectSound8_IUnknown * pdsunk;
617     TRACE("(%p,%p)\n",pds,ppunk);
618
619     if (ppunk == NULL) {
620         ERR("invalid parameter: ppunk == NULL\n");
621         return DSERR_INVALIDPARAM;
622     }
623
624     if (pds == NULL) {
625         ERR("invalid parameter: pds == NULL\n");
626         *ppunk = NULL;
627         return DSERR_INVALIDPARAM;
628     }
629
630     pdsunk = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsunk));
631     if (pdsunk == NULL) {
632         WARN("out of memory\n");
633         *ppunk = NULL;
634         return DSERR_OUTOFMEMORY;
635     }
636
637     pdsunk->lpVtbl = &DirectSound8_Unknown_Vtbl;
638     pdsunk->ref = 0;
639     pdsunk->pds = pds;
640
641     IDirectSoundImpl_AddRef(pds);
642     *ppunk = (LPUNKNOWN)pdsunk;
643
644     return DS_OK;
645 }
646
647 /*******************************************************************************
648  *              IDirectSound8_IDirectSound
649  */
650 static HRESULT WINAPI IDirectSound8_IDirectSound_QueryInterface(
651     LPDIRECTSOUND iface,
652     REFIID riid,
653     LPVOID * ppobj)
654 {
655     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
656     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
657     return DSOUND_QueryInterface8(This->pds, riid, ppobj);
658 }
659
660 static ULONG WINAPI IDirectSound8_IDirectSound_AddRef(
661     LPDIRECTSOUND iface)
662 {
663     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
664     ULONG ref = InterlockedIncrement(&(This->ref));
665     TRACE("(%p) ref was %d\n", This, ref - 1);
666     return ref;
667 }
668
669 static ULONG WINAPI IDirectSound8_IDirectSound_Release(
670     LPDIRECTSOUND iface)
671 {
672     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
673     ULONG ref = InterlockedDecrement(&(This->ref));
674     TRACE("(%p) ref was %d\n", This, ref + 1);
675     if (!ref) {
676         IDirectSoundImpl_Release(This->pds);
677         HeapFree(GetProcessHeap(), 0, This);
678         TRACE("(%p) released\n", This);
679     }
680     return ref;
681 }
682
683 static HRESULT WINAPI IDirectSound8_IDirectSound_CreateSoundBuffer(
684     LPDIRECTSOUND iface,
685     LPCDSBUFFERDESC dsbd,
686     LPLPDIRECTSOUNDBUFFER ppdsb,
687     LPUNKNOWN lpunk)
688 {
689     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
690     TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
691     return DirectSoundDevice_CreateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,dsbd,ppdsb,lpunk,TRUE);
692 }
693
694 static HRESULT WINAPI IDirectSound8_IDirectSound_GetCaps(
695     LPDIRECTSOUND iface,
696     LPDSCAPS lpDSCaps)
697 {
698     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
699     TRACE("(%p,%p)\n",This,lpDSCaps);
700     return DirectSoundDevice_GetCaps(((IDirectSoundImpl *)This->pds)->device, lpDSCaps);
701 }
702
703 static HRESULT WINAPI IDirectSound8_IDirectSound_DuplicateSoundBuffer(
704     LPDIRECTSOUND iface,
705     LPDIRECTSOUNDBUFFER psb,
706     LPLPDIRECTSOUNDBUFFER ppdsb)
707 {
708     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
709     TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
710     return DirectSoundDevice_DuplicateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,psb,ppdsb);
711 }
712
713 static HRESULT WINAPI IDirectSound8_IDirectSound_SetCooperativeLevel(
714     LPDIRECTSOUND iface,
715     HWND hwnd,
716     DWORD level)
717 {
718     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
719     TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level));
720     return DirectSoundDevice_SetCooperativeLevel(((IDirectSoundImpl *)This->pds)->device, hwnd, level);
721 }
722
723 static HRESULT WINAPI IDirectSound8_IDirectSound_Compact(
724     LPDIRECTSOUND iface)
725 {
726     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
727     TRACE("(%p)\n", This);
728     return DirectSoundDevice_Compact(((IDirectSoundImpl *)This->pds)->device);
729 }
730
731 static HRESULT WINAPI IDirectSound8_IDirectSound_GetSpeakerConfig(
732     LPDIRECTSOUND iface,
733     LPDWORD lpdwSpeakerConfig)
734 {
735     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
736     TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
737     return DirectSoundDevice_GetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,lpdwSpeakerConfig);
738 }
739
740 static HRESULT WINAPI IDirectSound8_IDirectSound_SetSpeakerConfig(
741     LPDIRECTSOUND iface,
742     DWORD config)
743 {
744     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
745     TRACE("(%p,0x%08x)\n",This,config);
746     return DirectSoundDevice_SetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,config);
747 }
748
749 static HRESULT WINAPI IDirectSound8_IDirectSound_Initialize(
750     LPDIRECTSOUND iface,
751     LPCGUID lpcGuid)
752 {
753     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
754     TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
755     return DirectSoundDevice_Initialize(&((IDirectSoundImpl *)This->pds)->device,lpcGuid);
756 }
757
758 static const IDirectSoundVtbl DirectSound8_DirectSound_Vtbl =
759 {
760     IDirectSound8_IDirectSound_QueryInterface,
761     IDirectSound8_IDirectSound_AddRef,
762     IDirectSound8_IDirectSound_Release,
763     IDirectSound8_IDirectSound_CreateSoundBuffer,
764     IDirectSound8_IDirectSound_GetCaps,
765     IDirectSound8_IDirectSound_DuplicateSoundBuffer,
766     IDirectSound8_IDirectSound_SetCooperativeLevel,
767     IDirectSound8_IDirectSound_Compact,
768     IDirectSound8_IDirectSound_GetSpeakerConfig,
769     IDirectSound8_IDirectSound_SetSpeakerConfig,
770     IDirectSound8_IDirectSound_Initialize
771 };
772
773 static HRESULT IDirectSound8_IDirectSound_Create(
774     LPDIRECTSOUND8 pds,
775     LPDIRECTSOUND * ppds)
776 {
777     IDirectSound8_IDirectSound * pdsds;
778     TRACE("(%p,%p)\n",pds,ppds);
779
780     if (ppds == NULL) {
781         ERR("invalid parameter: ppds == NULL\n");
782         return DSERR_INVALIDPARAM;
783     }
784
785     if (pds == NULL) {
786         ERR("invalid parameter: pds == NULL\n");
787         *ppds = NULL;
788         return DSERR_INVALIDPARAM;
789     }
790
791     pdsds = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsds));
792     if (pdsds == NULL) {
793         WARN("out of memory\n");
794         *ppds = NULL;
795         return DSERR_OUTOFMEMORY;
796     }
797
798     pdsds->lpVtbl = &DirectSound8_DirectSound_Vtbl;
799     pdsds->ref = 0;
800     pdsds->pds = pds;
801
802     IDirectSoundImpl_AddRef(pds);
803     *ppds = (LPDIRECTSOUND)pdsds;
804
805     return DS_OK;
806 }
807
808 /*******************************************************************************
809  *              IDirectSound8_IDirectSound8
810  */
811 static HRESULT WINAPI IDirectSound8_IDirectSound8_QueryInterface(
812     LPDIRECTSOUND8 iface,
813     REFIID riid,
814     LPVOID * ppobj)
815 {
816     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
817     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
818     return DSOUND_QueryInterface8(This->pds, riid, ppobj);
819 }
820
821 static ULONG WINAPI IDirectSound8_IDirectSound8_AddRef(
822     LPDIRECTSOUND8 iface)
823 {
824     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
825     ULONG ref = InterlockedIncrement(&(This->ref));
826     TRACE("(%p) ref was %d\n", This, ref - 1);
827     return ref;
828 }
829
830 static ULONG WINAPI IDirectSound8_IDirectSound8_Release(
831     LPDIRECTSOUND8 iface)
832 {
833     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
834     ULONG ref = InterlockedDecrement(&(This->ref));
835     TRACE("(%p) ref was %d\n", This, ref + 1);
836     if (!ref) {
837         IDirectSoundImpl_Release(This->pds);
838         HeapFree(GetProcessHeap(), 0, This);
839         TRACE("(%p) released\n", This);
840     }
841     return ref;
842 }
843
844 static HRESULT WINAPI IDirectSound8_IDirectSound8_CreateSoundBuffer(
845     LPDIRECTSOUND8 iface,
846     LPCDSBUFFERDESC dsbd,
847     LPLPDIRECTSOUNDBUFFER ppdsb,
848     LPUNKNOWN lpunk)
849 {
850     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
851     TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
852     return DirectSoundDevice_CreateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,dsbd,ppdsb,lpunk,TRUE);
853 }
854
855 static HRESULT WINAPI IDirectSound8_IDirectSound8_GetCaps(
856     LPDIRECTSOUND8 iface,
857     LPDSCAPS lpDSCaps)
858 {
859     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
860     TRACE("(%p,%p)\n",This,lpDSCaps);
861     return DirectSoundDevice_GetCaps(((IDirectSoundImpl *)This->pds)->device, lpDSCaps);
862 }
863
864 static HRESULT WINAPI IDirectSound8_IDirectSound8_DuplicateSoundBuffer(
865     LPDIRECTSOUND8 iface,
866     LPDIRECTSOUNDBUFFER psb,
867     LPLPDIRECTSOUNDBUFFER ppdsb)
868 {
869     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
870     TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
871     return DirectSoundDevice_DuplicateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,psb,ppdsb);
872 }
873
874 static HRESULT WINAPI IDirectSound8_IDirectSound8_SetCooperativeLevel(
875     LPDIRECTSOUND8 iface,
876     HWND hwnd,
877     DWORD level)
878 {
879     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
880     TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level));
881     return DirectSoundDevice_SetCooperativeLevel(((IDirectSoundImpl *)This->pds)->device, hwnd, level);
882 }
883
884 static HRESULT WINAPI IDirectSound8_IDirectSound8_Compact(
885     LPDIRECTSOUND8 iface)
886 {
887     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
888     TRACE("(%p)\n", This);
889     return DirectSoundDevice_Compact(((IDirectSoundImpl *)This->pds)->device);
890 }
891
892 static HRESULT WINAPI IDirectSound8_IDirectSound8_GetSpeakerConfig(
893     LPDIRECTSOUND8 iface,
894     LPDWORD lpdwSpeakerConfig)
895 {
896     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
897     TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
898     return DirectSoundDevice_GetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,lpdwSpeakerConfig);
899 }
900
901 static HRESULT WINAPI IDirectSound8_IDirectSound8_SetSpeakerConfig(
902     LPDIRECTSOUND8 iface,
903     DWORD config)
904 {
905     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
906     TRACE("(%p,0x%08x)\n",This,config);
907     return DirectSoundDevice_SetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,config);
908 }
909
910 static HRESULT WINAPI IDirectSound8_IDirectSound8_Initialize(
911     LPDIRECTSOUND8 iface,
912     LPCGUID lpcGuid)
913 {
914     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
915     TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
916     return DirectSoundDevice_Initialize(&((IDirectSoundImpl *)This->pds)->device,lpcGuid);
917 }
918
919 static HRESULT WINAPI IDirectSound8_IDirectSound8_VerifyCertification(
920     LPDIRECTSOUND8 iface,
921     LPDWORD pdwCertified)
922 {
923     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
924     TRACE("(%p, %p)\n", This, pdwCertified);
925     return DirectSoundDevice_VerifyCertification(((IDirectSoundImpl *)This->pds)->device,pdwCertified);
926 }
927
928 static const IDirectSound8Vtbl DirectSound8_DirectSound8_Vtbl =
929 {
930     IDirectSound8_IDirectSound8_QueryInterface,
931     IDirectSound8_IDirectSound8_AddRef,
932     IDirectSound8_IDirectSound8_Release,
933     IDirectSound8_IDirectSound8_CreateSoundBuffer,
934     IDirectSound8_IDirectSound8_GetCaps,
935     IDirectSound8_IDirectSound8_DuplicateSoundBuffer,
936     IDirectSound8_IDirectSound8_SetCooperativeLevel,
937     IDirectSound8_IDirectSound8_Compact,
938     IDirectSound8_IDirectSound8_GetSpeakerConfig,
939     IDirectSound8_IDirectSound8_SetSpeakerConfig,
940     IDirectSound8_IDirectSound8_Initialize,
941     IDirectSound8_IDirectSound8_VerifyCertification
942 };
943
944 static HRESULT IDirectSound8_IDirectSound8_Create(
945     LPDIRECTSOUND8 pds,
946     LPDIRECTSOUND8 * ppds)
947 {
948     IDirectSound8_IDirectSound8 * pdsds;
949     TRACE("(%p,%p)\n",pds,ppds);
950
951     if (ppds == NULL) {
952         ERR("invalid parameter: ppds == NULL\n");
953         return DSERR_INVALIDPARAM;
954     }
955
956     if (pds == NULL) {
957         ERR("invalid parameter: pds == NULL\n");
958         *ppds = NULL;
959         return DSERR_INVALIDPARAM;
960     }
961
962     pdsds = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsds));
963     if (pdsds == NULL) {
964         WARN("out of memory\n");
965         *ppds = NULL;
966         return DSERR_OUTOFMEMORY;
967     }
968
969     pdsds->lpVtbl = &DirectSound8_DirectSound8_Vtbl;
970     pdsds->ref = 0;
971     pdsds->pds = pds;
972
973     IDirectSoundImpl_AddRef(pds);
974     *ppds = (LPDIRECTSOUND8)pdsds;
975
976     return DS_OK;
977 }
978
979 HRESULT DSOUND_Create(
980     REFIID riid,
981     LPDIRECTSOUND *ppDS)
982 {
983     LPDIRECTSOUND8 pDS;
984     HRESULT hr;
985     TRACE("(%s, %p)\n", debugstr_guid(riid), ppDS);
986
987     if (!IsEqualIID(riid, &IID_IUnknown) &&
988         !IsEqualIID(riid, &IID_IDirectSound)) {
989         *ppDS = 0;
990         return E_NOINTERFACE;
991     }
992
993     /* Get dsound configuration */
994     setup_dsound_options();
995
996     hr = IDirectSoundImpl_Create(&pDS);
997     if (hr == DS_OK) {
998         hr = IDirectSound_IDirectSound_Create(pDS, ppDS);
999         if (*ppDS)
1000             IDirectSound_IDirectSound_AddRef(*ppDS);
1001         else {
1002             WARN("IDirectSound_IDirectSound_Create failed\n");
1003             IDirectSound8_Release(pDS);
1004         }
1005     } else {
1006         WARN("IDirectSoundImpl_Create failed\n");
1007         *ppDS = 0;
1008     }
1009
1010     return hr;
1011 }
1012
1013 /*******************************************************************************
1014  *              DirectSoundCreate (DSOUND.1)
1015  *
1016  *  Creates and initializes a DirectSound interface.
1017  *
1018  *  PARAMS
1019  *     lpcGUID   [I] Address of the GUID that identifies the sound device.
1020  *     ppDS      [O] Address of a variable to receive the interface pointer.
1021  *     pUnkOuter [I] Must be NULL.
1022  *
1023  *  RETURNS
1024  *     Success: DS_OK
1025  *     Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
1026  *              DSERR_NODRIVER, DSERR_OUTOFMEMORY
1027  */
1028 HRESULT WINAPI DirectSoundCreate(
1029     LPCGUID lpcGUID,
1030     LPDIRECTSOUND *ppDS,
1031     IUnknown *pUnkOuter)
1032 {
1033     HRESULT hr;
1034     LPDIRECTSOUND pDS;
1035
1036     TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
1037
1038     if (ppDS == NULL) {
1039         WARN("invalid parameter: ppDS == NULL\n");
1040         return DSERR_INVALIDPARAM;
1041     }
1042
1043     if (pUnkOuter != NULL) {
1044         WARN("invalid parameter: pUnkOuter != NULL\n");
1045         *ppDS = 0;
1046         return DSERR_INVALIDPARAM;
1047     }
1048
1049     hr = DSOUND_Create(&IID_IDirectSound, &pDS);
1050     if (hr == DS_OK) {
1051         hr = IDirectSound_Initialize(pDS, lpcGUID);
1052         if (hr != DS_OK) {
1053             if (hr != DSERR_ALREADYINITIALIZED) {
1054                 IDirectSound_Release(pDS);
1055                 pDS = 0;
1056             } else
1057                 hr = DS_OK;
1058         }
1059     }
1060
1061     *ppDS = pDS;
1062
1063     return hr;
1064 }
1065
1066 HRESULT DSOUND_Create8(
1067     REFIID riid,
1068     LPDIRECTSOUND8 *ppDS)
1069 {
1070     LPDIRECTSOUND8 pDS;
1071     HRESULT hr;
1072     TRACE("(%s, %p)\n", debugstr_guid(riid), ppDS);
1073
1074     if (!IsEqualIID(riid, &IID_IUnknown) &&
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 }