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