Fix segmentation fault caused by incorrect referencing of client audio
[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_renderer = 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     HRESULT hr = DS_OK;
688     TRACE("(%p,%s)\n",This,debugstr_guid(lpcGuid));
689
690     if (This->initialized == TRUE) {
691         WARN("already initialized\n");
692         return DSERR_ALREADYINITIALIZED;
693     }
694
695     /* If the driver requests being opened through MMSYSTEM
696      * (which is recommended by the DDK), it is supposed to happen
697      * before the DirectSound interface is opened */
698     if (This->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN)
699     {
700         DWORD flags = CALLBACK_FUNCTION;
701
702         /* disable direct sound if requested */
703         if (ds_hw_accel != DS_HW_ACCEL_EMULATION)
704             flags |= WAVE_DIRECTSOUND;
705
706         hr = mmErr(waveOutOpen(&(This->hwo),
707                                 This->drvdesc.dnDevNode, This->pwfx,
708                                 (DWORD)DSOUND_callback, (DWORD)This,
709                                 flags));
710         if (hr != DS_OK) {
711             WARN("waveOutOpen failed\n");
712             return hr;
713         }
714     }
715
716     if (This->driver) {
717         hr = IDsDriver_Open(This->driver);
718         if (hr != DS_OK) {
719             WARN("IDsDriver_Open failed\n");
720             return hr;
721         }
722
723         /* the driver is now open, so it's now allowed to call GetCaps */
724         hr = IDsDriver_GetCaps(This->driver,&(This->drvcaps));
725         if (hr != DS_OK) {
726             WARN("IDsDriver_GetCaps failed\n");
727             return hr;
728         }
729     } else {
730         WAVEOUTCAPSA woc;
731         hr = mmErr(waveOutGetDevCapsA(This->drvdesc.dnDevNode, &woc, sizeof(woc)));
732         if (hr != DS_OK) {
733             WARN("waveOutGetDevCaps failed\n");
734             return hr;
735         }
736         ZeroMemory(&This->drvcaps, sizeof(This->drvcaps));
737         if ((woc.dwFormats & WAVE_FORMAT_1M08) ||
738             (woc.dwFormats & WAVE_FORMAT_2M08) ||
739             (woc.dwFormats & WAVE_FORMAT_4M08) ||
740             (woc.dwFormats & WAVE_FORMAT_48M08) ||
741             (woc.dwFormats & WAVE_FORMAT_96M08)) {
742             This->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT;
743             This->drvcaps.dwFlags |= DSCAPS_PRIMARYMONO;
744         }
745         if ((woc.dwFormats & WAVE_FORMAT_1M16) ||
746             (woc.dwFormats & WAVE_FORMAT_2M16) ||
747             (woc.dwFormats & WAVE_FORMAT_4M16) ||
748             (woc.dwFormats & WAVE_FORMAT_48M16) ||
749             (woc.dwFormats & WAVE_FORMAT_96M16)) {
750             This->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT;
751             This->drvcaps.dwFlags |= DSCAPS_PRIMARYMONO;
752         }
753         if ((woc.dwFormats & WAVE_FORMAT_1S08) ||
754             (woc.dwFormats & WAVE_FORMAT_2S08) ||
755             (woc.dwFormats & WAVE_FORMAT_4S08) ||
756             (woc.dwFormats & WAVE_FORMAT_48S08) ||
757             (woc.dwFormats & WAVE_FORMAT_96S08)) {
758             This->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT;
759             This->drvcaps.dwFlags |= DSCAPS_PRIMARYSTEREO;
760         }
761         if ((woc.dwFormats & WAVE_FORMAT_1S16) ||
762             (woc.dwFormats & WAVE_FORMAT_2S16) ||
763             (woc.dwFormats & WAVE_FORMAT_4S16) ||
764             (woc.dwFormats & WAVE_FORMAT_48S16) ||
765             (woc.dwFormats & WAVE_FORMAT_96S16)) {
766             This->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT;
767             This->drvcaps.dwFlags |= DSCAPS_PRIMARYSTEREO;
768         }
769         if (ds_emuldriver)
770             This->drvcaps.dwFlags |= DSCAPS_EMULDRIVER;
771         This->drvcaps.dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
772         This->drvcaps.dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
773         This->drvcaps.dwPrimaryBuffers = 1;
774     }
775
776     hr = DSOUND_PrimaryCreate((IDirectSoundImpl*)This);
777     if (hr == DS_OK) {
778         This->initialized = TRUE;
779         DSOUND_renderer = (IDirectSoundImpl*)This;
780         timeBeginPeriod(DS_TIME_RES);
781         DSOUND_renderer->timerID = timeSetEvent(DS_TIME_DEL, DS_TIME_RES, DSOUND_timer,
782             (DWORD)DSOUND_renderer, TIME_PERIODIC | TIME_CALLBACK_FUNCTION);
783     } else {
784         WARN("DSOUND_PrimaryCreate failed\n");
785     }
786
787     return hr;
788 }
789
790 static HRESULT WINAPI IDirectSoundImpl_VerifyCertification(
791     LPDIRECTSOUND8 iface,
792     LPDWORD pdwCertified)
793 {
794     IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
795     TRACE("(%p, %p)\n",This,pdwCertified);
796
797     if (This->initialized == FALSE) {
798         WARN("not initialized\n");
799         return DSERR_UNINITIALIZED;
800     }
801
802     if (This->drvcaps.dwFlags & DSCAPS_CERTIFIED)
803         *pdwCertified = DS_CERTIFIED;
804     else
805         *pdwCertified = DS_UNCERTIFIED;
806     return DS_OK;
807 }
808
809 static IDirectSound8Vtbl IDirectSoundImpl_Vtbl =
810 {
811     IDirectSoundImpl_QueryInterface,
812     IDirectSoundImpl_AddRef,
813     IDirectSoundImpl_Release,
814     IDirectSoundImpl_CreateSoundBuffer,
815     IDirectSoundImpl_GetCaps,
816     IDirectSoundImpl_DuplicateSoundBuffer,
817     IDirectSoundImpl_SetCooperativeLevel,
818     IDirectSoundImpl_Compact,
819     IDirectSoundImpl_GetSpeakerConfig,
820     IDirectSoundImpl_SetSpeakerConfig,
821     IDirectSoundImpl_Initialize,
822     IDirectSoundImpl_VerifyCertification
823 };
824
825 HRESULT WINAPI IDirectSoundImpl_Create(
826     LPCGUID lpcGUID,
827     LPDIRECTSOUND8 * ppDS)
828 {
829     HRESULT err;
830     PIDSDRIVER drv = NULL;
831     IDirectSoundImpl* pDS;
832     unsigned wod, wodn;
833     BOOLEAN found = FALSE;
834     TRACE("(%s,%p)\n",debugstr_guid(lpcGUID),ppDS);
835
836     /* Enumerate WINMM audio devices and find the one we want */
837     wodn = waveOutGetNumDevs();
838     if (!wodn) {
839         WARN("no driver\n");
840         *ppDS = NULL;
841         return DSERR_NODRIVER;
842     }
843
844     TRACE(" expecting GUID %s.\n", debugstr_guid(lpcGUID));
845
846     for (wod=0; wod<wodn; wod++) {
847         if (IsEqualGUID( lpcGUID, &DSOUND_renderer_guids[wod])) {
848             found = TRUE;
849             break;
850         }
851     }
852
853     if (found == FALSE) {
854         WARN("No device found matching given ID!\n");
855         *ppDS = NULL;
856         return DSERR_NODRIVER;
857     }
858
859     /* DRV_QUERYDSOUNDIFACE is a "Wine extension" to get the DSound interface */
860     waveOutMessage((HWAVEOUT)wod, DRV_QUERYDSOUNDIFACE, (DWORD)&drv, 0);
861
862     /* Disable the direct sound driver to force emulation if requested. */
863     if (ds_hw_accel == DS_HW_ACCEL_EMULATION)
864         drv = NULL;
865
866     /* Allocate memory */
867     pDS = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundImpl));
868     if (pDS == NULL) {
869         WARN("out of memory\n");
870         *ppDS = NULL;
871         return DSERR_OUTOFMEMORY;
872     }
873
874     pDS->lpVtbl         = &IDirectSoundImpl_Vtbl;
875     pDS->ref            = 0;
876
877     pDS->driver         = drv;
878     pDS->priolevel      = DSSCL_NORMAL;
879     pDS->fraglen        = 0;
880     pDS->hwbuf          = NULL;
881     pDS->buffer         = NULL;
882     pDS->buflen         = 0;
883     pDS->writelead      = 0;
884     pDS->state          = STATE_STOPPED;
885     pDS->nrofbuffers    = 0;
886     pDS->buffers        = NULL;
887     pDS->primary        = NULL;
888     pDS->speaker_config = DSSPEAKER_STEREO | (DSSPEAKER_GEOMETRY_NARROW << 16);
889     pDS->initialized    = FALSE;
890     pDS->tmp_buffer     = NULL;
891     pDS->tmp_buffer_len = 0;
892
893     /* 3D listener initial parameters */
894     pDS->listener       = NULL;
895     pDS->ds3dl.dwSize   = sizeof(DS3DLISTENER);
896     pDS->ds3dl.vPosition.x = 0.0;
897     pDS->ds3dl.vPosition.y = 0.0;
898     pDS->ds3dl.vPosition.z = 0.0;
899     pDS->ds3dl.vVelocity.x = 0.0;
900     pDS->ds3dl.vVelocity.y = 0.0;
901     pDS->ds3dl.vVelocity.z = 0.0;
902     pDS->ds3dl.vOrientFront.x = 0.0;
903     pDS->ds3dl.vOrientFront.y = 0.0;
904     pDS->ds3dl.vOrientFront.z = 1.0;
905     pDS->ds3dl.vOrientTop.x = 0.0;
906     pDS->ds3dl.vOrientTop.y = 1.0;
907     pDS->ds3dl.vOrientTop.z = 0.0;
908     pDS->ds3dl.flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
909     pDS->ds3dl.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
910     pDS->ds3dl.flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
911
912     pDS->prebuf         = ds_snd_queue_max;
913     pDS->guid           = *lpcGUID;
914
915     /* Get driver description */
916     if (drv) {
917         err = IDsDriver_GetDriverDesc(drv,&(pDS->drvdesc));
918         if (err != DS_OK) {
919             WARN("IDsDriver_GetDriverDesc failed\n");
920             HeapFree(GetProcessHeap(),0,pDS);
921             *ppDS = NULL;
922             return err;
923         }
924     } else {
925         /* if no DirectSound interface available, use WINMM API instead */
926         pDS->drvdesc.dwFlags = DSDDESC_DOMMSYSTEMOPEN | DSDDESC_DOMMSYSTEMSETFORMAT;
927     }
928
929     pDS->drvdesc.dnDevNode = wod;
930
931     /* Set default wave format (may need it for waveOutOpen) */
932     pDS->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(WAVEFORMATEX));
933     if (pDS->pwfx == NULL) {
934         WARN("out of memory\n");
935         HeapFree(GetProcessHeap(),0,pDS);
936         *ppDS = NULL;
937         return DSERR_OUTOFMEMORY;
938     }
939
940     /* We rely on the sound driver to return the actual sound format of
941      * the device if it does not support 22050x8x2 and is given the
942      * WAVE_DIRECTSOUND flag.
943      */
944     pDS->pwfx->wFormatTag = WAVE_FORMAT_PCM;
945     pDS->pwfx->nSamplesPerSec = 22050;
946     pDS->pwfx->wBitsPerSample = 8;
947     pDS->pwfx->nChannels = 2;
948     pDS->pwfx->nBlockAlign = pDS->pwfx->wBitsPerSample * pDS->pwfx->nChannels / 8;
949     pDS->pwfx->nAvgBytesPerSec = pDS->pwfx->nSamplesPerSec * pDS->pwfx->nBlockAlign;
950     pDS->pwfx->cbSize = 0;
951
952     InitializeCriticalSection(&(pDS->mixlock));
953     pDS->mixlock.DebugInfo->Spare[1] = (DWORD)"DSOUND_mixlock";
954
955     RtlInitializeResource(&(pDS->buffer_list_lock));
956
957     *ppDS = (LPDIRECTSOUND8)pDS;
958
959     return DS_OK;
960 }
961 /*******************************************************************************
962  *              IDirectSound_IUnknown
963  */
964 static HRESULT WINAPI IDirectSound_IUnknown_QueryInterface(
965     LPUNKNOWN iface,
966     REFIID riid,
967     LPVOID * ppobj)
968 {
969     IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
970     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
971     return DSOUND_QueryInterface(This->pds, riid, ppobj);
972 }
973
974 static ULONG WINAPI IDirectSound_IUnknown_AddRef(
975     LPUNKNOWN iface)
976 {
977     IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
978     ULONG ref = InterlockedIncrement(&(This->ref));
979     TRACE("(%p) ref was %ld\n", This, ref - 1);
980     return ref;
981 }
982
983 static ULONG WINAPI IDirectSound_IUnknown_Release(
984     LPUNKNOWN iface)
985 {
986     IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
987     ULONG ref = InterlockedDecrement(&(This->ref));
988     TRACE("(%p) ref was %ld\n", This, ref + 1);
989     if (!ref) {
990         IDirectSoundImpl_Release(This->pds);
991         HeapFree(GetProcessHeap(), 0, This);
992         TRACE("(%p) released\n", This);
993     }
994     return ref;
995 }
996
997 static IUnknownVtbl DirectSound_Unknown_Vtbl =
998 {
999     IDirectSound_IUnknown_QueryInterface,
1000     IDirectSound_IUnknown_AddRef,
1001     IDirectSound_IUnknown_Release
1002 };
1003
1004 HRESULT WINAPI IDirectSound_IUnknown_Create(
1005     LPDIRECTSOUND8 pds,
1006     LPUNKNOWN * ppunk)
1007 {
1008     IDirectSound_IUnknown * pdsunk;
1009     TRACE("(%p,%p)\n",pds,ppunk);
1010
1011     if (ppunk == NULL) {
1012         ERR("invalid parameter: ppunk == NULL\n");
1013         return DSERR_INVALIDPARAM;
1014     }
1015
1016     if (pds == NULL) {
1017         ERR("invalid parameter: pds == NULL\n");
1018         *ppunk = NULL;
1019         return DSERR_INVALIDPARAM;
1020     }
1021
1022     pdsunk = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsunk));
1023     if (pdsunk == NULL) {
1024         WARN("out of memory\n");
1025         *ppunk = NULL;
1026         return DSERR_OUTOFMEMORY;
1027     }
1028
1029     pdsunk->lpVtbl = &DirectSound_Unknown_Vtbl;
1030     pdsunk->ref = 0;
1031     pdsunk->pds = pds;
1032
1033     IDirectSoundImpl_AddRef(pds);
1034     *ppunk = (LPUNKNOWN)pdsunk;
1035
1036     return DS_OK;
1037 }
1038
1039 /*******************************************************************************
1040  *              IDirectSound_IDirectSound
1041  */
1042 static HRESULT WINAPI IDirectSound_IDirectSound_QueryInterface(
1043     LPDIRECTSOUND iface,
1044     REFIID riid,
1045     LPVOID * ppobj)
1046 {
1047     IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
1048     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
1049     return DSOUND_QueryInterface(This->pds, riid, ppobj);
1050 }
1051
1052 static ULONG WINAPI IDirectSound_IDirectSound_AddRef(
1053     LPDIRECTSOUND iface)
1054 {
1055     IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
1056     ULONG ref = InterlockedIncrement(&(This->ref));
1057     TRACE("(%p) ref was %ld\n", This, ref - 1);
1058     return ref;
1059 }
1060
1061 static ULONG WINAPI IDirectSound_IDirectSound_Release(
1062     LPDIRECTSOUND iface)
1063 {
1064     IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
1065     ULONG ref = InterlockedDecrement(&(This->ref));
1066     TRACE("(%p) ref was %ld\n", This, ref + 1);
1067     if (!ref) {
1068         IDirectSoundImpl_Release(This->pds);
1069         HeapFree(GetProcessHeap(), 0, This);
1070         TRACE("(%p) released\n", This);
1071     }
1072     return ref;
1073 }
1074
1075 static HRESULT WINAPI IDirectSound_IDirectSound_CreateSoundBuffer(
1076     LPDIRECTSOUND iface,
1077     LPCDSBUFFERDESC dsbd,
1078     LPLPDIRECTSOUNDBUFFER ppdsb,
1079     LPUNKNOWN lpunk)
1080 {
1081     IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
1082     TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
1083     return DSOUND_CreateSoundBuffer(This->pds,dsbd,ppdsb,lpunk,FALSE);
1084 }
1085
1086 static HRESULT WINAPI IDirectSound_IDirectSound_GetCaps(
1087     LPDIRECTSOUND iface,
1088     LPDSCAPS lpDSCaps)
1089 {
1090     IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
1091     TRACE("(%p,%p)\n",This,lpDSCaps);
1092     return IDirectSoundImpl_GetCaps(This->pds, lpDSCaps);
1093 }
1094
1095 static HRESULT WINAPI IDirectSound_IDirectSound_DuplicateSoundBuffer(
1096     LPDIRECTSOUND iface,
1097     LPDIRECTSOUNDBUFFER psb,
1098     LPLPDIRECTSOUNDBUFFER ppdsb)
1099 {
1100     IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
1101     TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
1102     return IDirectSoundImpl_DuplicateSoundBuffer(This->pds,psb,ppdsb);
1103 }
1104
1105 static HRESULT WINAPI IDirectSound_IDirectSound_SetCooperativeLevel(
1106     LPDIRECTSOUND iface,
1107     HWND hwnd,
1108     DWORD level)
1109 {
1110     IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
1111     TRACE("(%p,%08lx,%s)\n",This,(DWORD)hwnd,dumpCooperativeLevel(level));
1112     return IDirectSoundImpl_SetCooperativeLevel(This->pds,hwnd,level);
1113 }
1114
1115 static HRESULT WINAPI IDirectSound_IDirectSound_Compact(
1116     LPDIRECTSOUND iface)
1117 {
1118     IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
1119     TRACE("(%p)\n", This);
1120     return IDirectSoundImpl_Compact(This->pds);
1121 }
1122
1123 static HRESULT WINAPI IDirectSound_IDirectSound_GetSpeakerConfig(
1124     LPDIRECTSOUND iface,
1125     LPDWORD lpdwSpeakerConfig)
1126 {
1127     IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
1128     TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
1129     return IDirectSoundImpl_GetSpeakerConfig(This->pds,lpdwSpeakerConfig);
1130 }
1131
1132 static HRESULT WINAPI IDirectSound_IDirectSound_SetSpeakerConfig(
1133     LPDIRECTSOUND iface,
1134     DWORD config)
1135 {
1136     IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
1137     TRACE("(%p,0x%08lx)\n",This,config);
1138     return IDirectSoundImpl_SetSpeakerConfig(This->pds,config);
1139 }
1140
1141 static HRESULT WINAPI IDirectSound_IDirectSound_Initialize(
1142     LPDIRECTSOUND iface,
1143     LPCGUID lpcGuid)
1144 {
1145     IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
1146     TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
1147     return IDirectSoundImpl_Initialize(This->pds,lpcGuid);
1148 }
1149
1150 static IDirectSoundVtbl DirectSound_DirectSound_Vtbl =
1151 {
1152     IDirectSound_IDirectSound_QueryInterface,
1153     IDirectSound_IDirectSound_AddRef,
1154     IDirectSound_IDirectSound_Release,
1155     IDirectSound_IDirectSound_CreateSoundBuffer,
1156     IDirectSound_IDirectSound_GetCaps,
1157     IDirectSound_IDirectSound_DuplicateSoundBuffer,
1158     IDirectSound_IDirectSound_SetCooperativeLevel,
1159     IDirectSound_IDirectSound_Compact,
1160     IDirectSound_IDirectSound_GetSpeakerConfig,
1161     IDirectSound_IDirectSound_SetSpeakerConfig,
1162     IDirectSound_IDirectSound_Initialize
1163 };
1164
1165 HRESULT WINAPI IDirectSound_IDirectSound_Create(
1166     LPDIRECTSOUND8  pds,
1167     LPDIRECTSOUND * ppds)
1168 {
1169     IDirectSound_IDirectSound * pdsds;
1170     TRACE("(%p,%p)\n",pds,ppds);
1171
1172     if (ppds == NULL) {
1173         ERR("invalid parameter: ppds == NULL\n");
1174         return DSERR_INVALIDPARAM;
1175     }
1176
1177     if (pds == NULL) {
1178         ERR("invalid parameter: pds == NULL\n");
1179         *ppds = NULL;
1180         return DSERR_INVALIDPARAM;
1181     }
1182
1183     pdsds = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsds));
1184     if (pdsds == NULL) {
1185         WARN("out of memory\n");
1186         *ppds = NULL;
1187         return DSERR_OUTOFMEMORY;
1188     }
1189
1190     pdsds->lpVtbl = &DirectSound_DirectSound_Vtbl;
1191     pdsds->ref = 0;
1192     pdsds->pds = pds;
1193
1194     IDirectSoundImpl_AddRef(pds);
1195     *ppds = (LPDIRECTSOUND)pdsds;
1196
1197     return DS_OK;
1198 }
1199
1200 /*******************************************************************************
1201  *              IDirectSound8_IUnknown
1202  */
1203 static HRESULT WINAPI IDirectSound8_IUnknown_QueryInterface(
1204     LPUNKNOWN iface,
1205     REFIID riid,
1206     LPVOID * ppobj)
1207 {
1208     IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
1209     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
1210     return DSOUND_QueryInterface8(This->pds, riid, ppobj);
1211 }
1212
1213 static ULONG WINAPI IDirectSound8_IUnknown_AddRef(
1214     LPUNKNOWN iface)
1215 {
1216     IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
1217     ULONG ref = InterlockedIncrement(&(This->ref));
1218     TRACE("(%p) ref was %ld\n", This, ref - 1);
1219     return ref;
1220 }
1221
1222 static ULONG WINAPI IDirectSound8_IUnknown_Release(
1223     LPUNKNOWN iface)
1224 {
1225     IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
1226     ULONG ref = InterlockedDecrement(&(This->ref));
1227     TRACE("(%p) ref was %ld\n", This, ref + 1);
1228     if (!ref) {
1229         IDirectSoundImpl_Release(This->pds);
1230         HeapFree(GetProcessHeap(), 0, This);
1231         TRACE("(%p) released\n", This);
1232     }
1233     return ref;
1234 }
1235
1236 static IUnknownVtbl DirectSound8_Unknown_Vtbl =
1237 {
1238     IDirectSound8_IUnknown_QueryInterface,
1239     IDirectSound8_IUnknown_AddRef,
1240     IDirectSound8_IUnknown_Release
1241 };
1242
1243 HRESULT WINAPI IDirectSound8_IUnknown_Create(
1244     LPDIRECTSOUND8 pds,
1245     LPUNKNOWN * ppunk)
1246 {
1247     IDirectSound8_IUnknown * pdsunk;
1248     TRACE("(%p,%p)\n",pds,ppunk);
1249
1250     if (ppunk == NULL) {
1251         ERR("invalid parameter: ppunk == NULL\n");
1252         return DSERR_INVALIDPARAM;
1253     }
1254
1255     if (pds == NULL) {
1256         ERR("invalid parameter: pds == NULL\n");
1257         *ppunk = NULL;
1258         return DSERR_INVALIDPARAM;
1259     }
1260
1261     pdsunk = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsunk));
1262     if (pdsunk == NULL) {
1263         WARN("out of memory\n");
1264         *ppunk = NULL;
1265         return DSERR_OUTOFMEMORY;
1266     }
1267
1268     pdsunk->lpVtbl = &DirectSound8_Unknown_Vtbl;
1269     pdsunk->ref = 0;
1270     pdsunk->pds = pds;
1271
1272     IDirectSoundImpl_AddRef(pds);
1273     *ppunk = (LPUNKNOWN)pdsunk;
1274
1275     return DS_OK;
1276 }
1277
1278 /*******************************************************************************
1279  *              IDirectSound8_IDirectSound
1280  */
1281 static HRESULT WINAPI IDirectSound8_IDirectSound_QueryInterface(
1282     LPDIRECTSOUND iface,
1283     REFIID riid,
1284     LPVOID * ppobj)
1285 {
1286     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
1287     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
1288     return DSOUND_QueryInterface8(This->pds, riid, ppobj);
1289 }
1290
1291 static ULONG WINAPI IDirectSound8_IDirectSound_AddRef(
1292     LPDIRECTSOUND iface)
1293 {
1294     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
1295     ULONG ref = InterlockedIncrement(&(This->ref));
1296     TRACE("(%p) ref was %ld\n", This, ref - 1);
1297     return ref;
1298 }
1299
1300 static ULONG WINAPI IDirectSound8_IDirectSound_Release(
1301     LPDIRECTSOUND iface)
1302 {
1303     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
1304     ULONG ref = InterlockedDecrement(&(This->ref));
1305     TRACE("(%p) ref was %ld\n", This, ref + 1);
1306     if (!ref) {
1307         IDirectSoundImpl_Release(This->pds);
1308         HeapFree(GetProcessHeap(), 0, This);
1309         TRACE("(%p) released\n", This);
1310     }
1311     return ref;
1312 }
1313
1314 static HRESULT WINAPI IDirectSound8_IDirectSound_CreateSoundBuffer(
1315     LPDIRECTSOUND iface,
1316     LPCDSBUFFERDESC dsbd,
1317     LPLPDIRECTSOUNDBUFFER ppdsb,
1318     LPUNKNOWN lpunk)
1319 {
1320     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
1321     TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
1322     return DSOUND_CreateSoundBuffer(This->pds,dsbd,ppdsb,lpunk,TRUE);
1323 }
1324
1325 static HRESULT WINAPI IDirectSound8_IDirectSound_GetCaps(
1326     LPDIRECTSOUND iface,
1327     LPDSCAPS lpDSCaps)
1328 {
1329     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
1330     TRACE("(%p,%p)\n",This,lpDSCaps);
1331     return IDirectSoundImpl_GetCaps(This->pds, lpDSCaps);
1332 }
1333
1334 static HRESULT WINAPI IDirectSound8_IDirectSound_DuplicateSoundBuffer(
1335     LPDIRECTSOUND iface,
1336     LPDIRECTSOUNDBUFFER psb,
1337     LPLPDIRECTSOUNDBUFFER ppdsb)
1338 {
1339     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
1340     TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
1341     return IDirectSoundImpl_DuplicateSoundBuffer(This->pds,psb,ppdsb);
1342 }
1343
1344 static HRESULT WINAPI IDirectSound8_IDirectSound_SetCooperativeLevel(
1345     LPDIRECTSOUND iface,
1346     HWND hwnd,
1347     DWORD level)
1348 {
1349     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
1350     TRACE("(%p,%08lx,%s)\n",This,(DWORD)hwnd,dumpCooperativeLevel(level));
1351     return IDirectSoundImpl_SetCooperativeLevel(This->pds,hwnd,level);
1352 }
1353
1354 static HRESULT WINAPI IDirectSound8_IDirectSound_Compact(
1355     LPDIRECTSOUND iface)
1356 {
1357     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
1358     TRACE("(%p)\n", This);
1359     return IDirectSoundImpl_Compact(This->pds);
1360 }
1361
1362 static HRESULT WINAPI IDirectSound8_IDirectSound_GetSpeakerConfig(
1363     LPDIRECTSOUND iface,
1364     LPDWORD lpdwSpeakerConfig)
1365 {
1366     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
1367     TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
1368     return IDirectSoundImpl_GetSpeakerConfig(This->pds,lpdwSpeakerConfig);
1369 }
1370
1371 static HRESULT WINAPI IDirectSound8_IDirectSound_SetSpeakerConfig(
1372     LPDIRECTSOUND iface,
1373     DWORD config)
1374 {
1375     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
1376     TRACE("(%p,0x%08lx)\n",This,config);
1377     return IDirectSoundImpl_SetSpeakerConfig(This->pds,config);
1378 }
1379
1380 static HRESULT WINAPI IDirectSound8_IDirectSound_Initialize(
1381     LPDIRECTSOUND iface,
1382     LPCGUID lpcGuid)
1383 {
1384     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
1385     TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
1386     return IDirectSoundImpl_Initialize(This->pds,lpcGuid);
1387 }
1388
1389 static IDirectSoundVtbl DirectSound8_DirectSound_Vtbl =
1390 {
1391     IDirectSound8_IDirectSound_QueryInterface,
1392     IDirectSound8_IDirectSound_AddRef,
1393     IDirectSound8_IDirectSound_Release,
1394     IDirectSound8_IDirectSound_CreateSoundBuffer,
1395     IDirectSound8_IDirectSound_GetCaps,
1396     IDirectSound8_IDirectSound_DuplicateSoundBuffer,
1397     IDirectSound8_IDirectSound_SetCooperativeLevel,
1398     IDirectSound8_IDirectSound_Compact,
1399     IDirectSound8_IDirectSound_GetSpeakerConfig,
1400     IDirectSound8_IDirectSound_SetSpeakerConfig,
1401     IDirectSound8_IDirectSound_Initialize
1402 };
1403
1404 HRESULT WINAPI IDirectSound8_IDirectSound_Create(
1405     LPDIRECTSOUND8 pds,
1406     LPDIRECTSOUND * ppds)
1407 {
1408     IDirectSound8_IDirectSound * pdsds;
1409     TRACE("(%p,%p)\n",pds,ppds);
1410
1411     if (ppds == NULL) {
1412         ERR("invalid parameter: ppds == NULL\n");
1413         return DSERR_INVALIDPARAM;
1414     }
1415
1416     if (pds == NULL) {
1417         ERR("invalid parameter: pds == NULL\n");
1418         *ppds = NULL;
1419         return DSERR_INVALIDPARAM;
1420     }
1421
1422     pdsds = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsds));
1423     if (pdsds == NULL) {
1424         WARN("out of memory\n");
1425         *ppds = NULL;
1426         return DSERR_OUTOFMEMORY;
1427     }
1428
1429     pdsds->lpVtbl = &DirectSound8_DirectSound_Vtbl;
1430     pdsds->ref = 0;
1431     pdsds->pds = pds;
1432
1433     IDirectSoundImpl_AddRef(pds);
1434     *ppds = (LPDIRECTSOUND)pdsds;
1435
1436     return DS_OK;
1437 }
1438
1439 /*******************************************************************************
1440  *              IDirectSound8_IDirectSound8
1441  */
1442 static HRESULT WINAPI IDirectSound8_IDirectSound8_QueryInterface(
1443     LPDIRECTSOUND8 iface,
1444     REFIID riid,
1445     LPVOID * ppobj)
1446 {
1447     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
1448     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
1449     return DSOUND_QueryInterface8(This->pds, riid, ppobj);
1450 }
1451
1452 static ULONG WINAPI IDirectSound8_IDirectSound8_AddRef(
1453     LPDIRECTSOUND8 iface)
1454 {
1455     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
1456     ULONG ref = InterlockedIncrement(&(This->ref));
1457     TRACE("(%p) ref was %ld\n", This, ref - 1);
1458     return ref;
1459 }
1460
1461 static ULONG WINAPI IDirectSound8_IDirectSound8_Release(
1462     LPDIRECTSOUND8 iface)
1463 {
1464     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
1465     ULONG ref = InterlockedDecrement(&(This->ref));
1466     TRACE("(%p) ref was %ld\n", This, ref + 1);
1467     if (!ref) {
1468         IDirectSoundImpl_Release(This->pds);
1469         HeapFree(GetProcessHeap(), 0, This);
1470         TRACE("(%p) released\n", This);
1471     }
1472     return ref;
1473 }
1474
1475 static HRESULT WINAPI IDirectSound8_IDirectSound8_CreateSoundBuffer(
1476     LPDIRECTSOUND8 iface,
1477     LPCDSBUFFERDESC dsbd,
1478     LPLPDIRECTSOUNDBUFFER ppdsb,
1479     LPUNKNOWN lpunk)
1480 {
1481     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
1482     TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
1483     return DSOUND_CreateSoundBuffer(This->pds,dsbd,ppdsb,lpunk,TRUE);
1484 }
1485
1486 static HRESULT WINAPI IDirectSound8_IDirectSound8_GetCaps(
1487     LPDIRECTSOUND8 iface,
1488     LPDSCAPS lpDSCaps)
1489 {
1490     IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
1491     TRACE("(%p,%p)\n",This,lpDSCaps);
1492     return IDirectSoundImpl_GetCaps(This->pds, lpDSCaps);
1493 }
1494
1495 static HRESULT WINAPI IDirectSound8_IDirectSound8_DuplicateSoundBuffer(
1496     LPDIRECTSOUND8 iface,
1497     LPDIRECTSOUNDBUFFER psb,
1498     LPLPDIRECTSOUNDBUFFER ppdsb)
1499 {
1500     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
1501     TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
1502     return IDirectSoundImpl_DuplicateSoundBuffer(This->pds,psb,ppdsb);
1503 }
1504
1505 static HRESULT WINAPI IDirectSound8_IDirectSound8_SetCooperativeLevel(
1506     LPDIRECTSOUND8 iface,
1507     HWND hwnd,
1508     DWORD level)
1509 {
1510     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
1511     TRACE("(%p,%08lx,%s)\n",This,(DWORD)hwnd,dumpCooperativeLevel(level));
1512     return IDirectSoundImpl_SetCooperativeLevel(This->pds,hwnd,level);
1513 }
1514
1515 static HRESULT WINAPI IDirectSound8_IDirectSound8_Compact(
1516     LPDIRECTSOUND8 iface)
1517 {
1518     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
1519     TRACE("(%p)\n", This);
1520     return IDirectSoundImpl_Compact(This->pds);
1521 }
1522
1523 static HRESULT WINAPI IDirectSound8_IDirectSound8_GetSpeakerConfig(
1524     LPDIRECTSOUND8 iface,
1525     LPDWORD lpdwSpeakerConfig)
1526 {
1527     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
1528     TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
1529     return IDirectSoundImpl_GetSpeakerConfig(This->pds,lpdwSpeakerConfig);
1530 }
1531
1532 static HRESULT WINAPI IDirectSound8_IDirectSound8_SetSpeakerConfig(
1533     LPDIRECTSOUND8 iface,
1534     DWORD config)
1535 {
1536     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
1537     TRACE("(%p,0x%08lx)\n",This,config);
1538     return IDirectSoundImpl_SetSpeakerConfig(This->pds,config);
1539 }
1540
1541 static HRESULT WINAPI IDirectSound8_IDirectSound8_Initialize(
1542     LPDIRECTSOUND8 iface,
1543     LPCGUID lpcGuid)
1544 {
1545     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
1546     TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
1547     return IDirectSoundImpl_Initialize(This->pds,lpcGuid);
1548 }
1549
1550 static HRESULT WINAPI IDirectSound8_IDirectSound8_VerifyCertification(
1551     LPDIRECTSOUND8 iface,
1552     LPDWORD pdwCertified)
1553 {
1554     IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
1555     TRACE("(%p, %p)\n", This, pdwCertified);
1556     return IDirectSoundImpl_VerifyCertification(This->pds,pdwCertified);
1557 }
1558
1559 static IDirectSound8Vtbl DirectSound8_DirectSound8_Vtbl =
1560 {
1561     IDirectSound8_IDirectSound8_QueryInterface,
1562     IDirectSound8_IDirectSound8_AddRef,
1563     IDirectSound8_IDirectSound8_Release,
1564     IDirectSound8_IDirectSound8_CreateSoundBuffer,
1565     IDirectSound8_IDirectSound8_GetCaps,
1566     IDirectSound8_IDirectSound8_DuplicateSoundBuffer,
1567     IDirectSound8_IDirectSound8_SetCooperativeLevel,
1568     IDirectSound8_IDirectSound8_Compact,
1569     IDirectSound8_IDirectSound8_GetSpeakerConfig,
1570     IDirectSound8_IDirectSound8_SetSpeakerConfig,
1571     IDirectSound8_IDirectSound8_Initialize,
1572     IDirectSound8_IDirectSound8_VerifyCertification
1573 };
1574
1575 HRESULT WINAPI IDirectSound8_IDirectSound8_Create(
1576     LPDIRECTSOUND8 pds,
1577     LPDIRECTSOUND8 * ppds)
1578 {
1579     IDirectSound8_IDirectSound8 * pdsds;
1580     TRACE("(%p,%p)\n",pds,ppds);
1581
1582     if (ppds == NULL) {
1583         ERR("invalid parameter: ppds == NULL\n");
1584         return DSERR_INVALIDPARAM;
1585     }
1586
1587     if (pds == NULL) {
1588         ERR("invalid parameter: pds == NULL\n");
1589         *ppds = NULL;
1590         return DSERR_INVALIDPARAM;
1591     }
1592
1593     pdsds = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsds));
1594     if (pdsds == NULL) {
1595         WARN("out of memory\n");
1596         *ppds = NULL;
1597         return DSERR_OUTOFMEMORY;
1598     }
1599
1600     pdsds->lpVtbl = &DirectSound8_DirectSound8_Vtbl;
1601     pdsds->ref = 0;
1602     pdsds->pds = pds;
1603
1604     IDirectSoundImpl_AddRef(pds);
1605     *ppds = (LPDIRECTSOUND8)pdsds;
1606
1607     return DS_OK;
1608 }
1609
1610 HRESULT WINAPI DSOUND_Create(
1611     LPCGUID lpcGUID,
1612     LPDIRECTSOUND *ppDS,
1613     IUnknown *pUnkOuter)
1614 {
1615     HRESULT hr;
1616     GUID devGuid;
1617
1618     TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
1619
1620     /* Get dsound configuration */
1621     setup_dsound_options();
1622
1623     /* Default device? */
1624     if (!lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL))
1625         lpcGUID = &DSDEVID_DefaultPlayback;
1626
1627     if (GetDeviceID(lpcGUID, &devGuid) != DS_OK) {
1628         WARN("invalid parameter: lpcGUID\n");
1629         *ppDS = NULL;
1630         return DSERR_INVALIDPARAM;
1631     }
1632
1633     if (DSOUND_renderer) {
1634         if (IsEqualGUID(&devGuid, &DSOUND_renderer->guid)) {
1635             hr = IDirectSound_IDirectSound_Create((LPDIRECTSOUND8)DSOUND_renderer, ppDS);
1636             if (*ppDS)
1637                 IDirectSound_IDirectSound_AddRef(*ppDS);
1638             else
1639                 WARN("IDirectSound_IDirectSound_Create failed\n");
1640         } else {
1641             ERR("different dsound already opened (only support one sound card at a time now)\n");
1642             *ppDS = NULL;
1643             hr = DSERR_ALLOCATED;
1644         }
1645     } else {
1646         LPDIRECTSOUND8 pDS;
1647         hr = IDirectSoundImpl_Create(&devGuid, &pDS);
1648         if (hr == DS_OK) {
1649             hr = IDirectSound_IDirectSound_Create(pDS, ppDS);
1650             if (*ppDS)
1651                 IDirectSound_IDirectSound_AddRef(*ppDS);
1652             else {
1653                 WARN("IDirectSound_IDirectSound_Create failed\n");
1654                 IDirectSound8_Release(pDS);
1655             }
1656         } else
1657             WARN("IDirectSoundImpl_Create failed\n");
1658     }
1659
1660     return hr;
1661 }
1662
1663 /*******************************************************************************
1664  *              DirectSoundCreate (DSOUND.1)
1665  *
1666  *  Creates and initializes a DirectSound interface.
1667  *
1668  *  PARAMS
1669  *     lpcGUID   [I] Address of the GUID that identifies the sound device.
1670  *     ppDS      [O] Address of a variable to receive the interface pointer.
1671  *     pUnkOuter [I] Must be NULL.
1672  *
1673  *  RETURNS
1674  *     Success: DS_OK
1675  *     Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
1676  *              DSERR_NODRIVER, DSERR_OUTOFMEMORY
1677  */
1678 HRESULT WINAPI DirectSoundCreate(
1679     LPCGUID lpcGUID,
1680     LPDIRECTSOUND *ppDS,
1681     IUnknown *pUnkOuter)
1682 {
1683     HRESULT hr;
1684     LPDIRECTSOUND pDS;
1685
1686     TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
1687
1688     if (ppDS == NULL) {
1689         WARN("invalid parameter: ppDS == NULL\n");
1690         return DSERR_INVALIDPARAM;
1691     }
1692
1693     if (pUnkOuter != NULL) {
1694         WARN("invalid parameter: pUnkOuter != NULL\n");
1695         *ppDS = 0;
1696         return DSERR_INVALIDPARAM;
1697     }
1698
1699     hr = DSOUND_Create(lpcGUID, &pDS, pUnkOuter);
1700     if (hr == DS_OK) {
1701         IDirectSound_IDirectSound * pp = (IDirectSound_IDirectSound *)pDS;
1702         IDirectSoundImpl * p = (IDirectSoundImpl *)(pp->pds);
1703         if (!(p->initialized)) {
1704             hr = IDirectSound_Initialize(pDS, lpcGUID);
1705             if (hr != DS_OK)
1706                 IDirectSound_Release(pDS);
1707         }
1708     }
1709
1710     *ppDS = pDS;
1711
1712     return hr;
1713 }
1714
1715 HRESULT WINAPI DSOUND_Create8(
1716     LPCGUID lpcGUID,
1717     LPDIRECTSOUND8 *ppDS,
1718     IUnknown *pUnkOuter)
1719 {
1720     HRESULT hr;
1721     GUID devGuid;
1722
1723     TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
1724
1725     /* Get dsound configuration */
1726     setup_dsound_options();
1727
1728     /* Default device? */
1729     if (!lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL))
1730         lpcGUID = &DSDEVID_DefaultPlayback;
1731
1732     if (GetDeviceID(lpcGUID, &devGuid) != DS_OK) {
1733         WARN("invalid parameter: lpcGUID\n");
1734         *ppDS = NULL;
1735         return DSERR_INVALIDPARAM;
1736     }
1737
1738     if (DSOUND_renderer) {
1739         if (IsEqualGUID(&devGuid, &DSOUND_renderer->guid)) {
1740             hr = IDirectSound8_IDirectSound8_Create((LPDIRECTSOUND8)DSOUND_renderer, ppDS);
1741             if (*ppDS)
1742                 IDirectSound8_IDirectSound8_AddRef(*ppDS);
1743             else
1744                 WARN("IDirectSound8_IDirectSound8_Create failed\n");
1745         } else {
1746             ERR("different dsound already opened (only support one sound card at a time now)\n");
1747             *ppDS = NULL;
1748             hr = DSERR_ALLOCATED;
1749         }
1750     } else {
1751         LPDIRECTSOUND8 pDS;
1752         hr = IDirectSoundImpl_Create(&devGuid, &pDS);
1753         if (hr == DS_OK) {
1754             hr = IDirectSound8_IDirectSound8_Create(pDS, ppDS);
1755             if (*ppDS)
1756                 IDirectSound8_IDirectSound8_AddRef(*ppDS);
1757             else {
1758                 WARN("IDirectSound8_IDirectSound8_Create failed\n");
1759                 IDirectSound8_Release(pDS);
1760             }
1761         } else
1762             WARN("IDirectSoundImpl_Create failed\n");
1763     }
1764
1765     return hr;
1766 }
1767
1768 /*******************************************************************************
1769  *        DirectSoundCreate8 (DSOUND.11)
1770  *
1771  *  Creates and initializes a DirectSound8 interface.
1772  *
1773  *  PARAMS
1774  *     lpcGUID   [I] Address of the GUID that identifies the sound device.
1775  *     ppDS      [O] Address of a variable to receive the interface pointer.
1776  *     pUnkOuter [I] Must be NULL.
1777  *
1778  *  RETURNS
1779  *     Success: DS_OK
1780  *     Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
1781  *              DSERR_NODRIVER, DSERR_OUTOFMEMORY
1782  */
1783 HRESULT WINAPI DirectSoundCreate8(
1784     LPCGUID lpcGUID,
1785     LPDIRECTSOUND8 *ppDS,
1786     IUnknown *pUnkOuter)
1787 {
1788     HRESULT hr;
1789     LPDIRECTSOUND8 pDS;
1790
1791     TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
1792
1793     if (ppDS == NULL) {
1794         WARN("invalid parameter: ppDS == NULL\n");
1795         return DSERR_INVALIDPARAM;
1796     }
1797
1798     if (pUnkOuter != NULL) {
1799         WARN("invalid parameter: pUnkOuter != NULL\n");
1800         *ppDS = 0;
1801         return DSERR_INVALIDPARAM;
1802     }
1803
1804     hr = DSOUND_Create8(lpcGUID, &pDS, pUnkOuter);
1805     if (hr == DS_OK) {
1806         IDirectSound8_IDirectSound8 * pp = (IDirectSound8_IDirectSound8 *)pDS;
1807         IDirectSoundImpl * p = (IDirectSoundImpl *)(pp->pds);
1808         if (!(p->initialized)) {
1809             hr = IDirectSound8_Initialize(pDS, lpcGUID);
1810             if (hr != DS_OK)
1811                 IDirectSound8_Release(pDS);
1812         }
1813     }
1814
1815     *ppDS = pDS;
1816
1817     return hr;
1818 }
1819
1820 /*
1821  * Add secondary buffer to buffer list.
1822  * Gets exclusive access to buffer for writing.
1823  */
1824 HRESULT DSOUND_AddBuffer(
1825     IDirectSoundImpl * pDS,
1826     IDirectSoundBufferImpl * pDSB)
1827 {
1828     IDirectSoundBufferImpl **newbuffers;
1829     HRESULT hr = DS_OK;
1830
1831     TRACE("(%p, %p)\n", pDS, pDSB);
1832
1833     RtlAcquireResourceExclusive(&(pDS->buffer_list_lock), TRUE);
1834
1835     if (pDS->buffers)
1836         newbuffers = HeapReAlloc(GetProcessHeap(),0,pDS->buffers,sizeof(IDirectSoundBufferImpl*)*(pDS->nrofbuffers+1));
1837     else
1838         newbuffers = HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundBufferImpl*)*(pDS->nrofbuffers+1));
1839
1840     if (newbuffers) {
1841         pDS->buffers = newbuffers;
1842         pDS->buffers[pDS->nrofbuffers] = pDSB;
1843         pDS->nrofbuffers++;
1844         TRACE("buffer count is now %d\n", pDS->nrofbuffers);
1845     } else {
1846         ERR("out of memory for buffer list! Current buffer count is %d\n", pDS->nrofbuffers);
1847         hr = DSERR_OUTOFMEMORY;
1848     }
1849
1850     RtlReleaseResource(&(pDS->buffer_list_lock));
1851
1852     return hr;
1853 }
1854
1855 /*
1856  * Remove secondary buffer from buffer list.
1857  * Gets exclusive access to buffer for writing.
1858  */
1859 HRESULT DSOUND_RemoveBuffer(
1860     IDirectSoundImpl * pDS,
1861     IDirectSoundBufferImpl * pDSB)
1862 {
1863     int i;
1864     HRESULT hr = DS_OK;
1865
1866     TRACE("(%p, %p)\n", pDS, pDSB);
1867
1868     RtlAcquireResourceExclusive(&(pDS->buffer_list_lock), TRUE);
1869
1870     for (i = 0; i < pDS->nrofbuffers; i++)
1871         if (pDS->buffers[i] == pDSB)
1872             break;
1873
1874     if (i < pDS->nrofbuffers) {
1875         /* Put the last buffer of the list in the (now empty) position */
1876         pDS->buffers[i] = pDS->buffers[pDS->nrofbuffers - 1];
1877         pDS->nrofbuffers--;
1878         pDS->buffers = HeapReAlloc(GetProcessHeap(),0,pDS->buffers,sizeof(LPDIRECTSOUNDBUFFER8)*pDS->nrofbuffers);
1879         TRACE("buffer count is now %d\n", pDS->nrofbuffers);
1880     }
1881
1882     if (pDS->nrofbuffers == 0) {
1883         HeapFree(GetProcessHeap(),0,pDS->buffers);
1884         pDS->buffers = NULL;
1885     }
1886
1887     RtlReleaseResource(&(pDS->buffer_list_lock));
1888
1889     return hr;
1890 }