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