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