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