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