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