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