dsound: Tune some parameters for alsa waveout.
[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
1253         /* The kill event should have allowed the timer process to expire
1254          * but try to grab the lock just in case. Can't hold lock because
1255          * IDirectSoundBufferImpl_Destroy also grabs the lock */
1256         RtlAcquireResourceShared(&(device->buffer_list_lock), TRUE);
1257         RtlReleaseResource(&(device->buffer_list_lock));
1258
1259         /* It is allowed to release this object even when buffers are playing */
1260         if (device->buffers) {
1261             WARN("%d secondary buffers not released\n", device->nrofbuffers);
1262             for( i=0;i<device->nrofbuffers;i++)
1263                 IDirectSoundBufferImpl_Destroy(device->buffers[i]);
1264         }
1265
1266         if (device->primary) {
1267             WARN("primary buffer not released\n");
1268             IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)device->primary);
1269         }
1270
1271         hr = DSOUND_PrimaryDestroy(device);
1272         if (hr != DS_OK)
1273             WARN("DSOUND_PrimaryDestroy failed\n");
1274
1275         if (device->driver)
1276             IDsDriver_Close(device->driver);
1277
1278         if (device->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN)
1279             waveOutClose(device->hwo);
1280
1281         if (device->driver)
1282             IDsDriver_Release(device->driver);
1283
1284         DSOUND_renderer[device->drvdesc.dnDevNode] = NULL;
1285
1286         HeapFree(GetProcessHeap(),0,device->tmp_buffer);
1287         HeapFree(GetProcessHeap(),0,device->buffer);
1288         RtlDeleteResource(&device->buffer_list_lock);
1289         device->mixlock.DebugInfo->Spare[0] = 0;
1290         DeleteCriticalSection(&device->mixlock);
1291         HeapFree(GetProcessHeap(),0,device);
1292         TRACE("(%p) released\n", device);
1293     }
1294     return ref;
1295 }
1296
1297 HRESULT DirectSoundDevice_GetCaps(
1298     DirectSoundDevice * device,
1299     LPDSCAPS lpDSCaps)
1300 {
1301     TRACE("(%p,%p)\n",device,lpDSCaps);
1302
1303     if (device == NULL) {
1304         WARN("not initialized\n");
1305         return DSERR_UNINITIALIZED;
1306     }
1307
1308     if (lpDSCaps == NULL) {
1309         WARN("invalid parameter: lpDSCaps = NULL\n");
1310         return DSERR_INVALIDPARAM;
1311     }
1312
1313     /* check if there is enough room */
1314     if (lpDSCaps->dwSize < sizeof(*lpDSCaps)) {
1315         WARN("invalid parameter: lpDSCaps->dwSize = %d\n", lpDSCaps->dwSize);
1316         return DSERR_INVALIDPARAM;
1317     }
1318
1319     lpDSCaps->dwFlags                           = device->drvcaps.dwFlags;
1320     if (TRACE_ON(dsound)) {
1321         TRACE("(flags=0x%08x:\n",lpDSCaps->dwFlags);
1322         _dump_DSCAPS(lpDSCaps->dwFlags);
1323         DPRINTF(")\n");
1324     }
1325     lpDSCaps->dwMinSecondarySampleRate          = device->drvcaps.dwMinSecondarySampleRate;
1326     lpDSCaps->dwMaxSecondarySampleRate          = device->drvcaps.dwMaxSecondarySampleRate;
1327     lpDSCaps->dwPrimaryBuffers                  = device->drvcaps.dwPrimaryBuffers;
1328     lpDSCaps->dwMaxHwMixingAllBuffers           = device->drvcaps.dwMaxHwMixingAllBuffers;
1329     lpDSCaps->dwMaxHwMixingStaticBuffers        = device->drvcaps.dwMaxHwMixingStaticBuffers;
1330     lpDSCaps->dwMaxHwMixingStreamingBuffers     = device->drvcaps.dwMaxHwMixingStreamingBuffers;
1331     lpDSCaps->dwFreeHwMixingAllBuffers          = device->drvcaps.dwFreeHwMixingAllBuffers;
1332     lpDSCaps->dwFreeHwMixingStaticBuffers       = device->drvcaps.dwFreeHwMixingStaticBuffers;
1333     lpDSCaps->dwFreeHwMixingStreamingBuffers    = device->drvcaps.dwFreeHwMixingStreamingBuffers;
1334     lpDSCaps->dwMaxHw3DAllBuffers               = device->drvcaps.dwMaxHw3DAllBuffers;
1335     lpDSCaps->dwMaxHw3DStaticBuffers            = device->drvcaps.dwMaxHw3DStaticBuffers;
1336     lpDSCaps->dwMaxHw3DStreamingBuffers         = device->drvcaps.dwMaxHw3DStreamingBuffers;
1337     lpDSCaps->dwFreeHw3DAllBuffers              = device->drvcaps.dwFreeHw3DAllBuffers;
1338     lpDSCaps->dwFreeHw3DStaticBuffers           = device->drvcaps.dwFreeHw3DStaticBuffers;
1339     lpDSCaps->dwFreeHw3DStreamingBuffers        = device->drvcaps.dwFreeHw3DStreamingBuffers;
1340     lpDSCaps->dwTotalHwMemBytes                 = device->drvcaps.dwTotalHwMemBytes;
1341     lpDSCaps->dwFreeHwMemBytes                  = device->drvcaps.dwFreeHwMemBytes;
1342     lpDSCaps->dwMaxContigFreeHwMemBytes         = device->drvcaps.dwMaxContigFreeHwMemBytes;
1343
1344     /* driver doesn't have these */
1345     lpDSCaps->dwUnlockTransferRateHwBuffers     = 4096; /* But we have none... */
1346     lpDSCaps->dwPlayCpuOverheadSwBuffers        = 1;    /* 1% */
1347
1348     return DS_OK;
1349 }
1350
1351 HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcGUID)
1352 {
1353     HRESULT hr = DS_OK;
1354     unsigned wod, wodn;
1355     BOOLEAN found = FALSE;
1356     GUID devGUID;
1357     DirectSoundDevice * device = *ppDevice;
1358     TRACE("(%p,%s)\n",ppDevice,debugstr_guid(lpcGUID));
1359
1360     if (*ppDevice != NULL) {
1361         WARN("already initialized\n");
1362         return DSERR_ALREADYINITIALIZED;
1363     }
1364
1365     /* Default device? */
1366     if (!lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL))
1367         lpcGUID = &DSDEVID_DefaultPlayback;
1368
1369     if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
1370         WARN("invalid parameter: lpcGUID\n");
1371         return DSERR_INVALIDPARAM;
1372     }
1373
1374     /* Enumerate WINMM audio devices and find the one we want */
1375     wodn = waveOutGetNumDevs();
1376     if (!wodn) {
1377         WARN("no driver\n");
1378         return DSERR_NODRIVER;
1379     }
1380
1381     for (wod=0; wod<wodn; wod++) {
1382         if (IsEqualGUID( &devGUID, &DSOUND_renderer_guids[wod])) {
1383             found = TRUE;
1384             break;
1385         }
1386     }
1387
1388     if (found == FALSE) {
1389         WARN("No device found matching given ID!\n");
1390         return DSERR_NODRIVER;
1391     }
1392
1393     if (DSOUND_renderer[wod]) {
1394         if (IsEqualGUID(&devGUID, &DSOUND_renderer[wod]->guid)) {
1395             device = DSOUND_renderer[wod];
1396             DirectSoundDevice_AddRef(device);
1397             *ppDevice = device;
1398             return DS_OK;
1399         } else {
1400             ERR("device GUID doesn't match\n");
1401             hr = DSERR_GENERIC;
1402             return hr;
1403         }
1404     } else {
1405         hr = DirectSoundDevice_Create(&device);
1406         if (hr != DS_OK) {
1407             WARN("DirectSoundDevice_Create failed\n");
1408             return hr;
1409         }
1410     }
1411
1412     *ppDevice = device;
1413     device->guid = devGUID;
1414
1415     /* DRV_QUERYDSOUNDIFACE is a "Wine extension" to get the DSound interface */
1416     waveOutMessage((HWAVEOUT)wod, DRV_QUERYDSOUNDIFACE, (DWORD_PTR)&device->driver, 0);
1417
1418     /* Disable the direct sound driver to force emulation if requested. */
1419     if (ds_hw_accel == DS_HW_ACCEL_EMULATION)
1420         device->driver = NULL;
1421
1422     /* Get driver description */
1423     if (device->driver) {
1424         hr = IDsDriver_GetDriverDesc(device->driver,&(device->drvdesc));
1425         if (hr != DS_OK) {
1426             WARN("IDsDriver_GetDriverDesc failed\n");
1427             return hr;
1428         }
1429     } else {
1430         /* if no DirectSound interface available, use WINMM API instead */
1431         device->drvdesc.dwFlags = DSDDESC_DOMMSYSTEMOPEN | DSDDESC_DOMMSYSTEMSETFORMAT;
1432     }
1433
1434     device->drvdesc.dnDevNode = wod;
1435
1436     /* If the driver requests being opened through MMSYSTEM
1437      * (which is recommended by the DDK), it is supposed to happen
1438      * before the DirectSound interface is opened */
1439     if (device->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN)
1440     {
1441         DWORD flags = CALLBACK_FUNCTION;
1442
1443         /* disable direct sound if requested */
1444         if (ds_hw_accel != DS_HW_ACCEL_EMULATION)
1445             flags |= WAVE_DIRECTSOUND;
1446
1447         hr = mmErr(waveOutOpen(&(device->hwo),
1448                                 device->drvdesc.dnDevNode, device->pwfx,
1449                                 (DWORD_PTR)DSOUND_callback, (DWORD)device,
1450                                 flags));
1451         if (hr != DS_OK) {
1452             WARN("waveOutOpen failed\n");
1453             return hr;
1454         }
1455     }
1456
1457     if (device->driver) {
1458         hr = IDsDriver_Open(device->driver);
1459         if (hr != DS_OK) {
1460             WARN("IDsDriver_Open failed\n");
1461             return hr;
1462         }
1463
1464         /* the driver is now open, so it's now allowed to call GetCaps */
1465         hr = IDsDriver_GetCaps(device->driver,&(device->drvcaps));
1466         if (hr != DS_OK) {
1467             WARN("IDsDriver_GetCaps failed\n");
1468             return hr;
1469         }
1470     } else {
1471         WAVEOUTCAPSA woc;
1472         hr = mmErr(waveOutGetDevCapsA(device->drvdesc.dnDevNode, &woc, sizeof(woc)));
1473         if (hr != DS_OK) {
1474             WARN("waveOutGetDevCaps failed\n");
1475             return hr;
1476         }
1477         ZeroMemory(&device->drvcaps, sizeof(device->drvcaps));
1478         if ((woc.dwFormats & WAVE_FORMAT_1M08) ||
1479             (woc.dwFormats & WAVE_FORMAT_2M08) ||
1480             (woc.dwFormats & WAVE_FORMAT_4M08) ||
1481             (woc.dwFormats & WAVE_FORMAT_48M08) ||
1482             (woc.dwFormats & WAVE_FORMAT_96M08)) {
1483             device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT;
1484             device->drvcaps.dwFlags |= DSCAPS_PRIMARYMONO;
1485         }
1486         if ((woc.dwFormats & WAVE_FORMAT_1M16) ||
1487             (woc.dwFormats & WAVE_FORMAT_2M16) ||
1488             (woc.dwFormats & WAVE_FORMAT_4M16) ||
1489             (woc.dwFormats & WAVE_FORMAT_48M16) ||
1490             (woc.dwFormats & WAVE_FORMAT_96M16)) {
1491             device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT;
1492             device->drvcaps.dwFlags |= DSCAPS_PRIMARYMONO;
1493         }
1494         if ((woc.dwFormats & WAVE_FORMAT_1S08) ||
1495             (woc.dwFormats & WAVE_FORMAT_2S08) ||
1496             (woc.dwFormats & WAVE_FORMAT_4S08) ||
1497             (woc.dwFormats & WAVE_FORMAT_48S08) ||
1498             (woc.dwFormats & WAVE_FORMAT_96S08)) {
1499             device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT;
1500             device->drvcaps.dwFlags |= DSCAPS_PRIMARYSTEREO;
1501         }
1502         if ((woc.dwFormats & WAVE_FORMAT_1S16) ||
1503             (woc.dwFormats & WAVE_FORMAT_2S16) ||
1504             (woc.dwFormats & WAVE_FORMAT_4S16) ||
1505             (woc.dwFormats & WAVE_FORMAT_48S16) ||
1506             (woc.dwFormats & WAVE_FORMAT_96S16)) {
1507             device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT;
1508             device->drvcaps.dwFlags |= DSCAPS_PRIMARYSTEREO;
1509         }
1510         if (ds_emuldriver)
1511             device->drvcaps.dwFlags |= DSCAPS_EMULDRIVER;
1512         device->drvcaps.dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
1513         device->drvcaps.dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
1514         device->drvcaps.dwPrimaryBuffers = 1;
1515     }
1516
1517     hr = DSOUND_PrimaryCreate(device);
1518     if (hr == DS_OK) {
1519         DSOUND_renderer[device->drvdesc.dnDevNode] = device;
1520         timeBeginPeriod(DS_TIME_RES);
1521         DSOUND_renderer[device->drvdesc.dnDevNode]->timerID = timeSetEvent(DS_TIME_DEL, DS_TIME_RES, DSOUND_timer,
1522             (DWORD_PTR)DSOUND_renderer[device->drvdesc.dnDevNode], TIME_PERIODIC | TIME_CALLBACK_FUNCTION | TIME_KILL_SYNCHRONOUS);
1523     } else {
1524         WARN("DSOUND_PrimaryCreate failed\n");
1525     }
1526
1527     return hr;
1528 }
1529
1530 HRESULT DirectSoundDevice_CreateSoundBuffer(
1531     DirectSoundDevice * device,
1532     LPCDSBUFFERDESC dsbd,
1533     LPLPDIRECTSOUNDBUFFER ppdsb,
1534     LPUNKNOWN lpunk,
1535     BOOL from8)
1536 {
1537     HRESULT hres = DS_OK;
1538     TRACE("(%p,%p,%p,%p)\n",device,dsbd,ppdsb,lpunk);
1539
1540     if (device == NULL) {
1541         WARN("not initialized\n");
1542         return DSERR_UNINITIALIZED;
1543     }
1544
1545     if (dsbd == NULL) {
1546         WARN("invalid parameter: dsbd == NULL\n");
1547         return DSERR_INVALIDPARAM;
1548     }
1549
1550     if (dsbd->dwSize != sizeof(DSBUFFERDESC) &&
1551         dsbd->dwSize != sizeof(DSBUFFERDESC1)) {
1552         WARN("invalid parameter: dsbd\n");
1553         return DSERR_INVALIDPARAM;
1554     }
1555
1556     if (ppdsb == NULL) {
1557         WARN("invalid parameter: ppdsb == NULL\n");
1558         return DSERR_INVALIDPARAM;
1559     }
1560
1561     if (TRACE_ON(dsound)) {
1562         TRACE("(structsize=%d)\n",dsbd->dwSize);
1563         TRACE("(flags=0x%08x:\n",dsbd->dwFlags);
1564         _dump_DSBCAPS(dsbd->dwFlags);
1565         DPRINTF(")\n");
1566         TRACE("(bufferbytes=%d)\n",dsbd->dwBufferBytes);
1567         TRACE("(lpwfxFormat=%p)\n",dsbd->lpwfxFormat);
1568     }
1569
1570     if (dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) {
1571         if (dsbd->lpwfxFormat != NULL) {
1572             WARN("invalid parameter: dsbd->lpwfxFormat must be NULL for "
1573                  "primary buffer\n");
1574             return DSERR_INVALIDPARAM;
1575         }
1576
1577         if (device->primary) {
1578             WARN("Primary Buffer already created\n");
1579             IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(device->primary));
1580             *ppdsb = (LPDIRECTSOUNDBUFFER)(device->primary);
1581         } else {
1582            device->dsbd = *dsbd;
1583            hres = PrimaryBufferImpl_Create(device, (PrimaryBufferImpl**)&(device->primary), &(device->dsbd));
1584            if (device->primary) {
1585                IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(device->primary));
1586                *ppdsb = (LPDIRECTSOUNDBUFFER)(device->primary);
1587            } else
1588                WARN("PrimaryBufferImpl_Create failed\n");
1589         }
1590     } else {
1591         IDirectSoundBufferImpl * dsb;
1592
1593         if (dsbd->lpwfxFormat == NULL) {
1594             WARN("invalid parameter: dsbd->lpwfxFormat can't be NULL for "
1595                  "secondary buffer\n");
1596             return DSERR_INVALIDPARAM;
1597         }
1598
1599         TRACE("(formattag=0x%04x,chans=%d,samplerate=%d,"
1600               "bytespersec=%d,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
1601               dsbd->lpwfxFormat->wFormatTag, dsbd->lpwfxFormat->nChannels,
1602               dsbd->lpwfxFormat->nSamplesPerSec,
1603               dsbd->lpwfxFormat->nAvgBytesPerSec,
1604               dsbd->lpwfxFormat->nBlockAlign,
1605               dsbd->lpwfxFormat->wBitsPerSample, dsbd->lpwfxFormat->cbSize);
1606
1607         if (from8 && (dsbd->dwFlags & DSBCAPS_CTRL3D) && (dsbd->lpwfxFormat->nChannels != 1)) {
1608             WARN("invalid parameter: 3D buffer format must be mono\n");
1609             return DSERR_INVALIDPARAM;
1610         }
1611
1612         hres = IDirectSoundBufferImpl_Create(device, (IDirectSoundBufferImpl**)&dsb, dsbd);
1613         if (dsb) {
1614             hres = SecondaryBufferImpl_Create(dsb, (SecondaryBufferImpl**)ppdsb);
1615             if (*ppdsb) {
1616                 dsb->secondary = (SecondaryBufferImpl*)*ppdsb;
1617                 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)*ppdsb);
1618             } else
1619                 WARN("SecondaryBufferImpl_Create failed\n");
1620         } else
1621            WARN("IDirectSoundBufferImpl_Create failed\n");
1622    }
1623
1624    return hres;
1625 }
1626
1627 HRESULT DirectSoundDevice_DuplicateSoundBuffer(
1628     DirectSoundDevice * device,
1629     LPDIRECTSOUNDBUFFER psb,
1630     LPLPDIRECTSOUNDBUFFER ppdsb)
1631 {
1632     HRESULT hres = DS_OK;
1633     IDirectSoundBufferImpl* dsb;
1634     TRACE("(%p,%p,%p)\n",device,psb,ppdsb);
1635
1636     if (device == NULL) {
1637         WARN("not initialized\n");
1638         return DSERR_UNINITIALIZED;
1639     }
1640
1641     if (psb == NULL) {
1642         WARN("invalid parameter: psb == NULL\n");
1643         return DSERR_INVALIDPARAM;
1644     }
1645
1646     if (ppdsb == NULL) {
1647         WARN("invalid parameter: ppdsb == NULL\n");
1648         return DSERR_INVALIDPARAM;
1649     }
1650
1651     /* make sure we have a secondary buffer */
1652     if ((PrimaryBufferImpl *)psb == device->primary) {
1653         WARN("trying to duplicate primary buffer\n");
1654         *ppdsb = NULL;
1655         return DSERR_INVALIDCALL;
1656     }
1657
1658     /* duplicate the actual buffer implementation */
1659     hres = IDirectSoundBufferImpl_Duplicate(device, &dsb,
1660                                            ((SecondaryBufferImpl *)psb)->dsb);
1661
1662     if (hres == DS_OK) {
1663         /* create a new secondary buffer using the new implementation */
1664         hres = SecondaryBufferImpl_Create(dsb, (SecondaryBufferImpl**)ppdsb);
1665         if (*ppdsb) {
1666             dsb->secondary = (SecondaryBufferImpl*)*ppdsb;
1667             IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)*ppdsb);
1668         } else {
1669             WARN("SecondaryBufferImpl_Create failed\n");
1670             IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)dsb);
1671             IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER8)dsb);
1672         }
1673     }
1674
1675     return hres;
1676 }
1677
1678 HRESULT DirectSoundDevice_SetCooperativeLevel(
1679     DirectSoundDevice * device,
1680     HWND hwnd,
1681     DWORD level)
1682 {
1683     TRACE("(%p,%p,%s)\n",device,hwnd,dumpCooperativeLevel(level));
1684
1685     if (device == NULL) {
1686         WARN("not initialized\n");
1687         return DSERR_UNINITIALIZED;
1688     }
1689
1690     if (level==DSSCL_PRIORITY || level==DSSCL_EXCLUSIVE) {
1691         WARN("level=%s not fully supported\n",
1692              level==DSSCL_PRIORITY ? "DSSCL_PRIORITY" : "DSSCL_EXCLUSIVE");
1693     }
1694
1695     device->priolevel = level;
1696     return DS_OK;
1697 }
1698
1699 HRESULT DirectSoundDevice_Compact(
1700     DirectSoundDevice * device)
1701 {
1702     TRACE("(%p)\n", device);
1703
1704     if (device == NULL) {
1705         WARN("not initialized\n");
1706         return DSERR_UNINITIALIZED;
1707     }
1708
1709     if (device->priolevel < DSSCL_PRIORITY) {
1710         WARN("incorrect priority level\n");
1711         return DSERR_PRIOLEVELNEEDED;
1712     }
1713
1714     return DS_OK;
1715 }
1716
1717 HRESULT DirectSoundDevice_GetSpeakerConfig(
1718     DirectSoundDevice * device,
1719     LPDWORD lpdwSpeakerConfig)
1720 {
1721     TRACE("(%p, %p)\n", device, lpdwSpeakerConfig);
1722
1723     if (device == NULL) {
1724         WARN("not initialized\n");
1725         return DSERR_UNINITIALIZED;
1726     }
1727
1728     if (lpdwSpeakerConfig == NULL) {
1729         WARN("invalid parameter: lpdwSpeakerConfig == NULL\n");
1730         return DSERR_INVALIDPARAM;
1731     }
1732
1733     WARN("not fully functional\n");
1734     *lpdwSpeakerConfig = device->speaker_config;
1735     return DS_OK;
1736 }
1737
1738 HRESULT DirectSoundDevice_SetSpeakerConfig(
1739     DirectSoundDevice * device,
1740     DWORD config)
1741 {
1742     TRACE("(%p,0x%08x)\n",device,config);
1743
1744     if (device == NULL) {
1745         WARN("not initialized\n");
1746         return DSERR_UNINITIALIZED;
1747     }
1748
1749     device->speaker_config = config;
1750     WARN("not fully functional\n");
1751     return DS_OK;
1752 }
1753
1754 static HRESULT DirectSoundDevice_VerifyCertification(
1755     DirectSoundDevice * device,
1756     LPDWORD pdwCertified)
1757 {
1758     TRACE("(%p, %p)\n",device,pdwCertified);
1759
1760     if (device == NULL) {
1761         WARN("not initialized\n");
1762         return DSERR_UNINITIALIZED;
1763     }
1764
1765     if (device->drvcaps.dwFlags & DSCAPS_CERTIFIED)
1766         *pdwCertified = DS_CERTIFIED;
1767     else
1768         *pdwCertified = DS_UNCERTIFIED;
1769
1770     return DS_OK;
1771 }
1772
1773 /*
1774  * Add secondary buffer to buffer list.
1775  * Gets exclusive access to buffer for writing.
1776  */
1777 HRESULT DirectSoundDevice_AddBuffer(
1778     DirectSoundDevice * device,
1779     IDirectSoundBufferImpl * pDSB)
1780 {
1781     IDirectSoundBufferImpl **newbuffers;
1782     HRESULT hr = DS_OK;
1783
1784     TRACE("(%p, %p)\n", device, pDSB);
1785
1786     RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
1787
1788     if (device->buffers)
1789         newbuffers = HeapReAlloc(GetProcessHeap(),0,device->buffers,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
1790     else
1791         newbuffers = HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
1792
1793     if (newbuffers) {
1794         device->buffers = newbuffers;
1795         device->buffers[device->nrofbuffers] = pDSB;
1796         device->nrofbuffers++;
1797         TRACE("buffer count is now %d\n", device->nrofbuffers);
1798     } else {
1799         ERR("out of memory for buffer list! Current buffer count is %d\n", device->nrofbuffers);
1800         hr = DSERR_OUTOFMEMORY;
1801     }
1802
1803     RtlReleaseResource(&(device->buffer_list_lock));
1804
1805     return hr;
1806 }
1807
1808 /*
1809  * Remove secondary buffer from buffer list.
1810  * Gets exclusive access to buffer for writing.
1811  */
1812 HRESULT DirectSoundDevice_RemoveBuffer(
1813     DirectSoundDevice * device,
1814     IDirectSoundBufferImpl * pDSB)
1815 {
1816     int i;
1817     HRESULT hr = DS_OK;
1818
1819     TRACE("(%p, %p)\n", device, pDSB);
1820
1821     RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
1822
1823     for (i = 0; i < device->nrofbuffers; i++)
1824         if (device->buffers[i] == pDSB)
1825             break;
1826
1827     if (i < device->nrofbuffers) {
1828         /* Put the last buffer of the list in the (now empty) position */
1829         device->buffers[i] = device->buffers[device->nrofbuffers - 1];
1830         device->nrofbuffers--;
1831         device->buffers = HeapReAlloc(GetProcessHeap(),0,device->buffers,sizeof(LPDIRECTSOUNDBUFFER8)*device->nrofbuffers);
1832         TRACE("buffer count is now %d\n", device->nrofbuffers);
1833     }
1834
1835     if (device->nrofbuffers == 0) {
1836         HeapFree(GetProcessHeap(),0,device->buffers);
1837         device->buffers = NULL;
1838     }
1839
1840     RtlReleaseResource(&(device->buffer_list_lock));
1841
1842     return hr;
1843 }