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