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