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