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