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