dsound: Merge the two IUnknown/IDirectSound implementations for DirectSound.
[wine/multimedia.git] / dlls / dsound / dsound.c
blob7f5d288f6869317f56bdc04f905a6056ca787887
1 /* DirectSound
3 * Copyright 1998 Marcus Meissner
4 * Copyright 1998 Rob Riggs
5 * Copyright 2000-2002 TransGaming Technologies, Inc.
6 * Copyright 2004 Robert Reif
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.
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.
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
23 #include <stdarg.h>
24 #include <stdio.h>
26 #define COBJMACROS
27 #define NONAMELESSSTRUCT
28 #define NONAMELESSUNION
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winuser.h"
32 #include "winternl.h"
33 #include "mmddk.h"
34 #include "wingdi.h"
35 #include "mmreg.h"
36 #include "ks.h"
37 #include "ksmedia.h"
38 #include "wine/debug.h"
39 #include "dsound.h"
40 #include "dsound_private.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
44 /*****************************************************************************
45 * IDirectSound COM components
47 struct IDirectSound_IUnknown {
48 const IUnknownVtbl *lpVtbl;
49 LONG ref;
50 LPDIRECTSOUND8 pds;
53 static HRESULT IDirectSound_IUnknown_Create(LPDIRECTSOUND8 pds, LPUNKNOWN * ppunk);
55 struct IDirectSound_IDirectSound {
56 const IDirectSoundVtbl *lpVtbl;
57 LONG ref;
58 LPDIRECTSOUND8 pds;
61 static HRESULT IDirectSound_IDirectSound_Create(LPDIRECTSOUND8 pds, LPDIRECTSOUND * ppds);
63 /*****************************************************************************
64 * IDirectSound8 COM components
66 struct IDirectSound8_IDirectSound8 {
67 const IDirectSound8Vtbl *lpVtbl;
68 LONG ref;
69 LPDIRECTSOUND8 pds;
72 static HRESULT IDirectSound8_IDirectSound8_Create(LPDIRECTSOUND8 pds, LPDIRECTSOUND8 * ppds);
73 static ULONG WINAPI IDirectSound8_IDirectSound8_AddRef(LPDIRECTSOUND8 iface);
75 /*****************************************************************************
76 * IDirectSound implementation structure
78 struct IDirectSoundImpl
80 LONG ref;
82 DirectSoundDevice *device;
83 BOOL has_ds8;
84 LPUNKNOWN pUnknown;
85 LPDIRECTSOUND pDS;
86 LPDIRECTSOUND8 pDS8;
89 static HRESULT IDirectSoundImpl_Create(IDirectSound8 **ppds, BOOL has_ds8);
91 static ULONG WINAPI IDirectSound_IUnknown_AddRef(LPUNKNOWN iface);
92 static ULONG WINAPI IDirectSound_IDirectSound_AddRef(LPDIRECTSOUND iface);
94 const char * dumpCooperativeLevel(DWORD level)
96 #define LE(x) case x: return #x
97 switch (level) {
98 LE(DSSCL_NORMAL);
99 LE(DSSCL_PRIORITY);
100 LE(DSSCL_EXCLUSIVE);
101 LE(DSSCL_WRITEPRIMARY);
103 #undef LE
104 return wine_dbg_sprintf("Unknown(%08x)", level);
107 static void _dump_DSCAPS(DWORD xmask) {
108 struct {
109 DWORD mask;
110 const char *name;
111 } flags[] = {
112 #define FE(x) { x, #x },
113 FE(DSCAPS_PRIMARYMONO)
114 FE(DSCAPS_PRIMARYSTEREO)
115 FE(DSCAPS_PRIMARY8BIT)
116 FE(DSCAPS_PRIMARY16BIT)
117 FE(DSCAPS_CONTINUOUSRATE)
118 FE(DSCAPS_EMULDRIVER)
119 FE(DSCAPS_CERTIFIED)
120 FE(DSCAPS_SECONDARYMONO)
121 FE(DSCAPS_SECONDARYSTEREO)
122 FE(DSCAPS_SECONDARY8BIT)
123 FE(DSCAPS_SECONDARY16BIT)
124 #undef FE
126 unsigned int i;
128 for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
129 if ((flags[i].mask & xmask) == flags[i].mask)
130 TRACE("%s ",flags[i].name);
133 static void _dump_DSBCAPS(DWORD xmask) {
134 struct {
135 DWORD mask;
136 const char *name;
137 } flags[] = {
138 #define FE(x) { x, #x },
139 FE(DSBCAPS_PRIMARYBUFFER)
140 FE(DSBCAPS_STATIC)
141 FE(DSBCAPS_LOCHARDWARE)
142 FE(DSBCAPS_LOCSOFTWARE)
143 FE(DSBCAPS_CTRL3D)
144 FE(DSBCAPS_CTRLFREQUENCY)
145 FE(DSBCAPS_CTRLPAN)
146 FE(DSBCAPS_CTRLVOLUME)
147 FE(DSBCAPS_CTRLPOSITIONNOTIFY)
148 FE(DSBCAPS_STICKYFOCUS)
149 FE(DSBCAPS_GLOBALFOCUS)
150 FE(DSBCAPS_GETCURRENTPOSITION2)
151 FE(DSBCAPS_MUTE3DATMAXDISTANCE)
152 #undef FE
154 unsigned int i;
156 for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
157 if ((flags[i].mask & xmask) == flags[i].mask)
158 TRACE("%s ",flags[i].name);
161 /*******************************************************************************
162 * IDirectSoundImpl_DirectSound
164 static HRESULT DSOUND_QueryInterface(
165 LPDIRECTSOUND8 iface,
166 REFIID riid,
167 LPVOID * ppobj)
169 IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
170 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
172 if (ppobj == NULL) {
173 WARN("invalid parameter\n");
174 return E_INVALIDARG;
177 if (IsEqualIID(riid, &IID_IUnknown)) {
178 if (!This->pUnknown) {
179 IDirectSound_IUnknown_Create(iface, &This->pUnknown);
180 if (!This->pUnknown) {
181 WARN("IDirectSound_IUnknown_Create() failed\n");
182 *ppobj = NULL;
183 return E_NOINTERFACE;
186 IDirectSound_IUnknown_AddRef(This->pUnknown);
187 *ppobj = This->pUnknown;
188 return S_OK;
189 } else if (IsEqualIID(riid, &IID_IDirectSound)) {
190 if (!This->pDS) {
191 IDirectSound_IDirectSound_Create(iface, &This->pDS);
192 if (!This->pDS) {
193 WARN("IDirectSound_IDirectSound_Create() failed\n");
194 *ppobj = NULL;
195 return E_NOINTERFACE;
198 IDirectSound_IDirectSound_AddRef(This->pDS);
199 *ppobj = This->pDS;
200 return S_OK;
201 } else if (This->has_ds8 && IsEqualIID(riid, &IID_IDirectSound8)) {
202 if (!This->pDS8) {
203 IDirectSound8_IDirectSound8_Create(iface, &This->pDS8);
204 if (!This->pDS8) {
205 WARN("IDirectSound8_IDirectSound8_Create() failed\n");
206 *ppobj = NULL;
207 return E_NOINTERFACE;
210 IDirectSound8_IDirectSound8_AddRef(This->pDS8);
211 *ppobj = This->pDS8;
212 return S_OK;
215 *ppobj = NULL;
216 WARN("Unknown IID %s\n",debugstr_guid(riid));
217 return E_NOINTERFACE;
220 static ULONG IDirectSoundImpl_AddRef(
221 LPDIRECTSOUND8 iface)
223 IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
224 ULONG ref = InterlockedIncrement(&(This->ref));
225 TRACE("(%p) ref was %d\n", This, ref - 1);
226 return ref;
229 static ULONG IDirectSoundImpl_Release(
230 LPDIRECTSOUND8 iface)
232 IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
233 ULONG ref = InterlockedDecrement(&(This->ref));
234 TRACE("(%p) ref was %d\n", This, ref + 1);
236 if (!ref) {
237 if (This->device)
238 DirectSoundDevice_Release(This->device);
239 HeapFree(GetProcessHeap(),0,This);
240 TRACE("(%p) released\n", This);
242 return ref;
245 static HRESULT IDirectSoundImpl_Create(IDirectSound8 **ppDS, BOOL has_ds8)
247 IDirectSoundImpl* pDS;
248 TRACE("(%p)\n",ppDS);
250 /* Allocate memory */
251 pDS = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundImpl));
252 if (pDS == NULL) {
253 WARN("out of memory\n");
254 *ppDS = NULL;
255 return DSERR_OUTOFMEMORY;
258 pDS->ref = 0;
259 pDS->device = NULL;
260 pDS->has_ds8 = has_ds8;
262 *ppDS = (LPDIRECTSOUND8)pDS;
264 return DS_OK;
267 /*******************************************************************************
268 * IDirectSound_IUnknown
270 static HRESULT WINAPI IDirectSound_IUnknown_QueryInterface(
271 LPUNKNOWN iface,
272 REFIID riid,
273 LPVOID * ppobj)
275 IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
276 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
277 return DSOUND_QueryInterface(This->pds, riid, ppobj);
280 static ULONG WINAPI IDirectSound_IUnknown_AddRef(
281 LPUNKNOWN iface)
283 IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
284 ULONG ref = InterlockedIncrement(&(This->ref));
285 TRACE("(%p) ref was %d\n", This, ref - 1);
286 return ref;
289 static ULONG WINAPI IDirectSound_IUnknown_Release(
290 LPUNKNOWN iface)
292 IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
293 ULONG ref = InterlockedDecrement(&(This->ref));
294 TRACE("(%p) ref was %d\n", This, ref + 1);
295 if (!ref) {
296 ((IDirectSoundImpl*)This->pds)->pUnknown = NULL;
297 IDirectSoundImpl_Release(This->pds);
298 HeapFree(GetProcessHeap(), 0, This);
299 TRACE("(%p) released\n", This);
301 return ref;
304 static const IUnknownVtbl DirectSound_Unknown_Vtbl =
306 IDirectSound_IUnknown_QueryInterface,
307 IDirectSound_IUnknown_AddRef,
308 IDirectSound_IUnknown_Release
311 static HRESULT IDirectSound_IUnknown_Create(
312 LPDIRECTSOUND8 pds,
313 LPUNKNOWN * ppunk)
315 IDirectSound_IUnknown * pdsunk;
316 TRACE("(%p,%p)\n",pds,ppunk);
318 if (ppunk == NULL) {
319 ERR("invalid parameter: ppunk == NULL\n");
320 return DSERR_INVALIDPARAM;
323 if (pds == NULL) {
324 ERR("invalid parameter: pds == NULL\n");
325 *ppunk = NULL;
326 return DSERR_INVALIDPARAM;
329 pdsunk = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsunk));
330 if (pdsunk == NULL) {
331 WARN("out of memory\n");
332 *ppunk = NULL;
333 return DSERR_OUTOFMEMORY;
336 pdsunk->lpVtbl = &DirectSound_Unknown_Vtbl;
337 pdsunk->ref = 0;
338 pdsunk->pds = pds;
340 IDirectSoundImpl_AddRef(pds);
341 *ppunk = (LPUNKNOWN)pdsunk;
343 return DS_OK;
346 /*******************************************************************************
347 * IDirectSound_IDirectSound
349 static HRESULT WINAPI IDirectSound_IDirectSound_QueryInterface(
350 LPDIRECTSOUND iface,
351 REFIID riid,
352 LPVOID * ppobj)
354 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
355 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
356 return DSOUND_QueryInterface(This->pds, riid, ppobj);
359 static ULONG WINAPI IDirectSound_IDirectSound_AddRef(
360 LPDIRECTSOUND iface)
362 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
363 ULONG ref = InterlockedIncrement(&(This->ref));
364 TRACE("(%p) ref was %d\n", This, ref - 1);
365 return ref;
368 static ULONG WINAPI IDirectSound_IDirectSound_Release(
369 LPDIRECTSOUND iface)
371 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
372 ULONG ref = InterlockedDecrement(&(This->ref));
373 TRACE("(%p) ref was %d\n", This, ref + 1);
374 if (!ref) {
375 ((IDirectSoundImpl*)This->pds)->pDS = NULL;
376 IDirectSoundImpl_Release(This->pds);
377 HeapFree(GetProcessHeap(), 0, This);
378 TRACE("(%p) released\n", This);
380 return ref;
383 static HRESULT WINAPI IDirectSound_IDirectSound_CreateSoundBuffer(
384 LPDIRECTSOUND iface,
385 LPCDSBUFFERDESC dsbd,
386 LPLPDIRECTSOUNDBUFFER ppdsb,
387 LPUNKNOWN lpunk)
389 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
390 TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
391 return DirectSoundDevice_CreateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,dsbd,ppdsb,lpunk,((IDirectSoundImpl *)This->pds)->has_ds8);
394 static HRESULT WINAPI IDirectSound_IDirectSound_GetCaps(
395 LPDIRECTSOUND iface,
396 LPDSCAPS lpDSCaps)
398 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
399 TRACE("(%p,%p)\n",This,lpDSCaps);
400 return DirectSoundDevice_GetCaps(((IDirectSoundImpl *)This->pds)->device, lpDSCaps);
403 static HRESULT WINAPI IDirectSound_IDirectSound_DuplicateSoundBuffer(
404 LPDIRECTSOUND iface,
405 LPDIRECTSOUNDBUFFER psb,
406 LPLPDIRECTSOUNDBUFFER ppdsb)
408 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
409 TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
410 return DirectSoundDevice_DuplicateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,psb,ppdsb);
413 static HRESULT WINAPI IDirectSound_IDirectSound_SetCooperativeLevel(
414 LPDIRECTSOUND iface,
415 HWND hwnd,
416 DWORD level)
418 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
419 TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level));
420 return DirectSoundDevice_SetCooperativeLevel(((IDirectSoundImpl *)This->pds)->device, hwnd, level);
423 static HRESULT WINAPI IDirectSound_IDirectSound_Compact(
424 LPDIRECTSOUND iface)
426 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
427 TRACE("(%p)\n", This);
428 return DirectSoundDevice_Compact(((IDirectSoundImpl *)This->pds)->device);
431 static HRESULT WINAPI IDirectSound_IDirectSound_GetSpeakerConfig(
432 LPDIRECTSOUND iface,
433 LPDWORD lpdwSpeakerConfig)
435 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
436 TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
437 return DirectSoundDevice_GetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,lpdwSpeakerConfig);
440 static HRESULT WINAPI IDirectSound_IDirectSound_SetSpeakerConfig(
441 LPDIRECTSOUND iface,
442 DWORD config)
444 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
445 TRACE("(%p,0x%08x)\n",This,config);
446 return DirectSoundDevice_SetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,config);
449 static HRESULT WINAPI IDirectSound_IDirectSound_Initialize(
450 LPDIRECTSOUND iface,
451 LPCGUID lpcGuid)
453 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
454 TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
455 return DirectSoundDevice_Initialize(&((IDirectSoundImpl *)This->pds)->device,lpcGuid);
458 static const IDirectSoundVtbl DirectSound_DirectSound_Vtbl =
460 IDirectSound_IDirectSound_QueryInterface,
461 IDirectSound_IDirectSound_AddRef,
462 IDirectSound_IDirectSound_Release,
463 IDirectSound_IDirectSound_CreateSoundBuffer,
464 IDirectSound_IDirectSound_GetCaps,
465 IDirectSound_IDirectSound_DuplicateSoundBuffer,
466 IDirectSound_IDirectSound_SetCooperativeLevel,
467 IDirectSound_IDirectSound_Compact,
468 IDirectSound_IDirectSound_GetSpeakerConfig,
469 IDirectSound_IDirectSound_SetSpeakerConfig,
470 IDirectSound_IDirectSound_Initialize
473 static HRESULT IDirectSound_IDirectSound_Create(
474 LPDIRECTSOUND8 pds,
475 LPDIRECTSOUND * ppds)
477 IDirectSound_IDirectSound * pdsds;
478 TRACE("(%p,%p)\n",pds,ppds);
480 if (ppds == NULL) {
481 ERR("invalid parameter: ppds == NULL\n");
482 return DSERR_INVALIDPARAM;
485 if (pds == NULL) {
486 ERR("invalid parameter: pds == NULL\n");
487 *ppds = NULL;
488 return DSERR_INVALIDPARAM;
491 pdsds = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsds));
492 if (pdsds == NULL) {
493 WARN("out of memory\n");
494 *ppds = NULL;
495 return DSERR_OUTOFMEMORY;
498 pdsds->lpVtbl = &DirectSound_DirectSound_Vtbl;
499 pdsds->ref = 0;
500 pdsds->pds = pds;
502 IDirectSoundImpl_AddRef(pds);
503 *ppds = (LPDIRECTSOUND)pdsds;
505 return DS_OK;
508 /*******************************************************************************
509 * IDirectSound8_IDirectSound8
511 static HRESULT WINAPI IDirectSound8_IDirectSound8_QueryInterface(
512 LPDIRECTSOUND8 iface,
513 REFIID riid,
514 LPVOID * ppobj)
516 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
517 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
518 return DSOUND_QueryInterface(This->pds, riid, ppobj);
521 static ULONG WINAPI IDirectSound8_IDirectSound8_AddRef(
522 LPDIRECTSOUND8 iface)
524 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
525 ULONG ref = InterlockedIncrement(&(This->ref));
526 TRACE("(%p) ref was %d\n", This, ref - 1);
527 return ref;
530 static ULONG WINAPI IDirectSound8_IDirectSound8_Release(
531 LPDIRECTSOUND8 iface)
533 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
534 ULONG ref = InterlockedDecrement(&(This->ref));
535 TRACE("(%p) ref was %d\n", This, ref + 1);
536 if (!ref) {
537 ((IDirectSoundImpl*)This->pds)->pDS8 = NULL;
538 IDirectSoundImpl_Release(This->pds);
539 HeapFree(GetProcessHeap(), 0, This);
540 TRACE("(%p) released\n", This);
542 return ref;
545 static HRESULT WINAPI IDirectSound8_IDirectSound8_CreateSoundBuffer(
546 LPDIRECTSOUND8 iface,
547 LPCDSBUFFERDESC dsbd,
548 LPLPDIRECTSOUNDBUFFER ppdsb,
549 LPUNKNOWN lpunk)
551 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
552 TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
553 return DirectSoundDevice_CreateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,dsbd,ppdsb,lpunk,TRUE);
556 static HRESULT WINAPI IDirectSound8_IDirectSound8_GetCaps(
557 LPDIRECTSOUND8 iface,
558 LPDSCAPS lpDSCaps)
560 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
561 TRACE("(%p,%p)\n",This,lpDSCaps);
562 return DirectSoundDevice_GetCaps(((IDirectSoundImpl *)This->pds)->device, lpDSCaps);
565 static HRESULT WINAPI IDirectSound8_IDirectSound8_DuplicateSoundBuffer(
566 LPDIRECTSOUND8 iface,
567 LPDIRECTSOUNDBUFFER psb,
568 LPLPDIRECTSOUNDBUFFER ppdsb)
570 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
571 TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
572 return DirectSoundDevice_DuplicateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,psb,ppdsb);
575 static HRESULT WINAPI IDirectSound8_IDirectSound8_SetCooperativeLevel(
576 LPDIRECTSOUND8 iface,
577 HWND hwnd,
578 DWORD level)
580 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
581 TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level));
582 return DirectSoundDevice_SetCooperativeLevel(((IDirectSoundImpl *)This->pds)->device, hwnd, level);
585 static HRESULT WINAPI IDirectSound8_IDirectSound8_Compact(
586 LPDIRECTSOUND8 iface)
588 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
589 TRACE("(%p)\n", This);
590 return DirectSoundDevice_Compact(((IDirectSoundImpl *)This->pds)->device);
593 static HRESULT WINAPI IDirectSound8_IDirectSound8_GetSpeakerConfig(
594 LPDIRECTSOUND8 iface,
595 LPDWORD lpdwSpeakerConfig)
597 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
598 TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
599 return DirectSoundDevice_GetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,lpdwSpeakerConfig);
602 static HRESULT WINAPI IDirectSound8_IDirectSound8_SetSpeakerConfig(
603 LPDIRECTSOUND8 iface,
604 DWORD config)
606 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
607 TRACE("(%p,0x%08x)\n",This,config);
608 return DirectSoundDevice_SetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,config);
611 static HRESULT WINAPI IDirectSound8_IDirectSound8_Initialize(
612 LPDIRECTSOUND8 iface,
613 LPCGUID lpcGuid)
615 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
616 TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
617 return DirectSoundDevice_Initialize(&((IDirectSoundImpl *)This->pds)->device,lpcGuid);
620 static HRESULT WINAPI IDirectSound8_IDirectSound8_VerifyCertification(
621 LPDIRECTSOUND8 iface,
622 LPDWORD pdwCertified)
624 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
625 TRACE("(%p, %p)\n", This, pdwCertified);
626 return DirectSoundDevice_VerifyCertification(((IDirectSoundImpl *)This->pds)->device,pdwCertified);
629 static const IDirectSound8Vtbl DirectSound8_DirectSound8_Vtbl =
631 IDirectSound8_IDirectSound8_QueryInterface,
632 IDirectSound8_IDirectSound8_AddRef,
633 IDirectSound8_IDirectSound8_Release,
634 IDirectSound8_IDirectSound8_CreateSoundBuffer,
635 IDirectSound8_IDirectSound8_GetCaps,
636 IDirectSound8_IDirectSound8_DuplicateSoundBuffer,
637 IDirectSound8_IDirectSound8_SetCooperativeLevel,
638 IDirectSound8_IDirectSound8_Compact,
639 IDirectSound8_IDirectSound8_GetSpeakerConfig,
640 IDirectSound8_IDirectSound8_SetSpeakerConfig,
641 IDirectSound8_IDirectSound8_Initialize,
642 IDirectSound8_IDirectSound8_VerifyCertification
645 static HRESULT IDirectSound8_IDirectSound8_Create(
646 LPDIRECTSOUND8 pds,
647 LPDIRECTSOUND8 * ppds)
649 IDirectSound8_IDirectSound8 * pdsds;
650 TRACE("(%p,%p)\n",pds,ppds);
652 if (ppds == NULL) {
653 ERR("invalid parameter: ppds == NULL\n");
654 return DSERR_INVALIDPARAM;
657 if (pds == NULL) {
658 ERR("invalid parameter: pds == NULL\n");
659 *ppds = NULL;
660 return DSERR_INVALIDPARAM;
663 pdsds = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsds));
664 if (pdsds == NULL) {
665 WARN("out of memory\n");
666 *ppds = NULL;
667 return DSERR_OUTOFMEMORY;
670 pdsds->lpVtbl = &DirectSound8_DirectSound8_Vtbl;
671 pdsds->ref = 0;
672 pdsds->pds = pds;
674 IDirectSoundImpl_AddRef(pds);
675 *ppds = (LPDIRECTSOUND8)pdsds;
677 return DS_OK;
680 HRESULT DSOUND_Create(
681 REFIID riid,
682 LPDIRECTSOUND *ppDS)
684 LPDIRECTSOUND8 pDS;
685 HRESULT hr;
686 TRACE("(%s, %p)\n", debugstr_guid(riid), ppDS);
688 if (!IsEqualIID(riid, &IID_IUnknown) &&
689 !IsEqualIID(riid, &IID_IDirectSound)) {
690 *ppDS = 0;
691 return E_NOINTERFACE;
694 /* Get dsound configuration */
695 setup_dsound_options();
697 hr = IDirectSoundImpl_Create(&pDS, FALSE);
698 if (hr == DS_OK) {
699 hr = IDirectSound_IDirectSound_Create(pDS, ppDS);
700 if (*ppDS)
701 IDirectSound_IDirectSound_AddRef(*ppDS);
702 else {
703 WARN("IDirectSound_IDirectSound_Create failed\n");
704 IDirectSound8_Release(pDS);
706 } else {
707 WARN("IDirectSoundImpl_Create failed\n");
708 *ppDS = 0;
711 return hr;
714 /*******************************************************************************
715 * DirectSoundCreate (DSOUND.1)
717 * Creates and initializes a DirectSound interface.
719 * PARAMS
720 * lpcGUID [I] Address of the GUID that identifies the sound device.
721 * ppDS [O] Address of a variable to receive the interface pointer.
722 * pUnkOuter [I] Must be NULL.
724 * RETURNS
725 * Success: DS_OK
726 * Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
727 * DSERR_NODRIVER, DSERR_OUTOFMEMORY
729 HRESULT WINAPI DirectSoundCreate(
730 LPCGUID lpcGUID,
731 LPDIRECTSOUND *ppDS,
732 IUnknown *pUnkOuter)
734 HRESULT hr;
735 LPDIRECTSOUND pDS;
737 TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
739 if (ppDS == NULL) {
740 WARN("invalid parameter: ppDS == NULL\n");
741 return DSERR_INVALIDPARAM;
744 if (pUnkOuter != NULL) {
745 WARN("invalid parameter: pUnkOuter != NULL\n");
746 *ppDS = 0;
747 return DSERR_INVALIDPARAM;
750 hr = DSOUND_Create(&IID_IDirectSound, &pDS);
751 if (hr == DS_OK) {
752 hr = IDirectSound_Initialize(pDS, lpcGUID);
753 if (hr != DS_OK) {
754 if (hr != DSERR_ALREADYINITIALIZED) {
755 IDirectSound_Release(pDS);
756 pDS = 0;
757 } else
758 hr = DS_OK;
762 *ppDS = pDS;
764 return hr;
767 HRESULT DSOUND_Create8(
768 REFIID riid,
769 LPDIRECTSOUND8 *ppDS)
771 LPDIRECTSOUND8 pDS;
772 HRESULT hr;
773 TRACE("(%s, %p)\n", debugstr_guid(riid), ppDS);
775 if (!IsEqualIID(riid, &IID_IUnknown) &&
776 !IsEqualIID(riid, &IID_IDirectSound) &&
777 !IsEqualIID(riid, &IID_IDirectSound8)) {
778 *ppDS = 0;
779 return E_NOINTERFACE;
782 /* Get dsound configuration */
783 setup_dsound_options();
785 hr = IDirectSoundImpl_Create(&pDS, TRUE);
786 if (hr == DS_OK) {
787 hr = IDirectSound8_IDirectSound8_Create(pDS, ppDS);
788 if (*ppDS)
789 IDirectSound8_IDirectSound8_AddRef(*ppDS);
790 else {
791 WARN("IDirectSound8_IDirectSound8_Create failed\n");
792 IDirectSound8_Release(pDS);
794 } else {
795 WARN("IDirectSoundImpl_Create failed\n");
796 *ppDS = 0;
799 return hr;
802 /*******************************************************************************
803 * DirectSoundCreate8 (DSOUND.11)
805 * Creates and initializes a DirectSound8 interface.
807 * PARAMS
808 * lpcGUID [I] Address of the GUID that identifies the sound device.
809 * ppDS [O] Address of a variable to receive the interface pointer.
810 * pUnkOuter [I] Must be NULL.
812 * RETURNS
813 * Success: DS_OK
814 * Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
815 * DSERR_NODRIVER, DSERR_OUTOFMEMORY
817 HRESULT WINAPI DirectSoundCreate8(
818 LPCGUID lpcGUID,
819 LPDIRECTSOUND8 *ppDS,
820 IUnknown *pUnkOuter)
822 HRESULT hr;
823 LPDIRECTSOUND8 pDS;
825 TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
827 if (ppDS == NULL) {
828 WARN("invalid parameter: ppDS == NULL\n");
829 return DSERR_INVALIDPARAM;
832 if (pUnkOuter != NULL) {
833 WARN("invalid parameter: pUnkOuter != NULL\n");
834 *ppDS = 0;
835 return DSERR_INVALIDPARAM;
838 hr = DSOUND_Create8(&IID_IDirectSound8, &pDS);
839 if (hr == DS_OK) {
840 hr = IDirectSound8_Initialize(pDS, lpcGUID);
841 if (hr != DS_OK) {
842 if (hr != DSERR_ALREADYINITIALIZED) {
843 IDirectSound8_Release(pDS);
844 pDS = 0;
845 } else
846 hr = DS_OK;
850 *ppDS = pDS;
852 return hr;
855 /*******************************************************************************
856 * DirectSoundDevice
858 static HRESULT DirectSoundDevice_Create(DirectSoundDevice ** ppDevice)
860 DirectSoundDevice * device;
861 TRACE("(%p)\n", ppDevice);
863 /* Allocate memory */
864 device = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DirectSoundDevice));
865 if (device == NULL) {
866 WARN("out of memory\n");
867 return DSERR_OUTOFMEMORY;
870 device->ref = 1;
871 device->priolevel = DSSCL_NORMAL;
872 device->state = STATE_STOPPED;
873 device->speaker_config = DSSPEAKER_COMBINED(DSSPEAKER_STEREO, DSSPEAKER_GEOMETRY_WIDE);
875 /* 3D listener initial parameters */
876 device->ds3dl.dwSize = sizeof(DS3DLISTENER);
877 device->ds3dl.vPosition.x = 0.0;
878 device->ds3dl.vPosition.y = 0.0;
879 device->ds3dl.vPosition.z = 0.0;
880 device->ds3dl.vVelocity.x = 0.0;
881 device->ds3dl.vVelocity.y = 0.0;
882 device->ds3dl.vVelocity.z = 0.0;
883 device->ds3dl.vOrientFront.x = 0.0;
884 device->ds3dl.vOrientFront.y = 0.0;
885 device->ds3dl.vOrientFront.z = 1.0;
886 device->ds3dl.vOrientTop.x = 0.0;
887 device->ds3dl.vOrientTop.y = 1.0;
888 device->ds3dl.vOrientTop.z = 0.0;
889 device->ds3dl.flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
890 device->ds3dl.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
891 device->ds3dl.flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
893 device->prebuf = ds_snd_queue_max;
894 device->guid = GUID_NULL;
896 /* Set default wave format (may need it for waveOutOpen) */
897 device->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(WAVEFORMATEX));
898 if (device->pwfx == NULL) {
899 WARN("out of memory\n");
900 HeapFree(GetProcessHeap(),0,device);
901 return DSERR_OUTOFMEMORY;
904 device->pwfx->wFormatTag = WAVE_FORMAT_PCM;
905 device->pwfx->nSamplesPerSec = ds_default_sample_rate;
906 device->pwfx->wBitsPerSample = ds_default_bits_per_sample;
907 device->pwfx->nChannels = 2;
908 device->pwfx->nBlockAlign = device->pwfx->wBitsPerSample * device->pwfx->nChannels / 8;
909 device->pwfx->nAvgBytesPerSec = device->pwfx->nSamplesPerSec * device->pwfx->nBlockAlign;
910 device->pwfx->cbSize = 0;
912 InitializeCriticalSection(&(device->mixlock));
913 device->mixlock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DirectSoundDevice.mixlock");
915 RtlInitializeResource(&(device->buffer_list_lock));
917 *ppDevice = device;
919 return DS_OK;
922 static ULONG DirectSoundDevice_AddRef(DirectSoundDevice * device)
924 ULONG ref = InterlockedIncrement(&(device->ref));
925 TRACE("(%p) ref was %d\n", device, ref - 1);
926 return ref;
929 ULONG DirectSoundDevice_Release(DirectSoundDevice * device)
931 HRESULT hr;
932 ULONG ref = InterlockedDecrement(&(device->ref));
933 TRACE("(%p) ref was %u\n", device, ref + 1);
934 if (!ref) {
935 int i;
936 timeKillEvent(device->timerID);
937 timeEndPeriod(DS_TIME_RES);
939 /* The kill event should have allowed the timer process to expire
940 * but try to grab the lock just in case. Can't hold lock because
941 * secondarybuffer_destroy also grabs the lock */
942 RtlAcquireResourceShared(&(device->buffer_list_lock), TRUE);
943 RtlReleaseResource(&(device->buffer_list_lock));
945 EnterCriticalSection(&DSOUND_renderers_lock);
946 list_remove(&device->entry);
947 LeaveCriticalSection(&DSOUND_renderers_lock);
949 /* It is allowed to release this object even when buffers are playing */
950 if (device->buffers) {
951 WARN("%d secondary buffers not released\n", device->nrofbuffers);
952 for( i=0;i<device->nrofbuffers;i++)
953 secondarybuffer_destroy(device->buffers[i]);
956 hr = DSOUND_PrimaryDestroy(device);
957 if (hr != DS_OK)
958 WARN("DSOUND_PrimaryDestroy failed\n");
960 if(device->client)
961 IAudioClient_Release(device->client);
962 if(device->render)
963 IAudioRenderClient_Release(device->render);
964 if(device->clock)
965 IAudioClock_Release(device->clock);
966 if(device->volume)
967 IAudioStreamVolume_Release(device->volume);
969 HeapFree(GetProcessHeap(), 0, device->tmp_buffer);
970 HeapFree(GetProcessHeap(), 0, device->mix_buffer);
971 HeapFree(GetProcessHeap(), 0, device->buffer);
972 RtlDeleteResource(&device->buffer_list_lock);
973 device->mixlock.DebugInfo->Spare[0] = 0;
974 DeleteCriticalSection(&device->mixlock);
975 HeapFree(GetProcessHeap(),0,device);
976 TRACE("(%p) released\n", device);
978 return ref;
981 HRESULT DirectSoundDevice_GetCaps(
982 DirectSoundDevice * device,
983 LPDSCAPS lpDSCaps)
985 TRACE("(%p,%p)\n",device,lpDSCaps);
987 if (device == NULL) {
988 WARN("not initialized\n");
989 return DSERR_UNINITIALIZED;
992 if (lpDSCaps == NULL) {
993 WARN("invalid parameter: lpDSCaps = NULL\n");
994 return DSERR_INVALIDPARAM;
997 /* check if there is enough room */
998 if (lpDSCaps->dwSize < sizeof(*lpDSCaps)) {
999 WARN("invalid parameter: lpDSCaps->dwSize = %d\n", lpDSCaps->dwSize);
1000 return DSERR_INVALIDPARAM;
1003 lpDSCaps->dwFlags = device->drvcaps.dwFlags;
1004 if (TRACE_ON(dsound)) {
1005 TRACE("(flags=0x%08x:\n",lpDSCaps->dwFlags);
1006 _dump_DSCAPS(lpDSCaps->dwFlags);
1007 TRACE(")\n");
1009 lpDSCaps->dwMinSecondarySampleRate = device->drvcaps.dwMinSecondarySampleRate;
1010 lpDSCaps->dwMaxSecondarySampleRate = device->drvcaps.dwMaxSecondarySampleRate;
1011 lpDSCaps->dwPrimaryBuffers = device->drvcaps.dwPrimaryBuffers;
1012 lpDSCaps->dwMaxHwMixingAllBuffers = device->drvcaps.dwMaxHwMixingAllBuffers;
1013 lpDSCaps->dwMaxHwMixingStaticBuffers = device->drvcaps.dwMaxHwMixingStaticBuffers;
1014 lpDSCaps->dwMaxHwMixingStreamingBuffers = device->drvcaps.dwMaxHwMixingStreamingBuffers;
1015 lpDSCaps->dwFreeHwMixingAllBuffers = device->drvcaps.dwFreeHwMixingAllBuffers;
1016 lpDSCaps->dwFreeHwMixingStaticBuffers = device->drvcaps.dwFreeHwMixingStaticBuffers;
1017 lpDSCaps->dwFreeHwMixingStreamingBuffers = device->drvcaps.dwFreeHwMixingStreamingBuffers;
1018 lpDSCaps->dwMaxHw3DAllBuffers = device->drvcaps.dwMaxHw3DAllBuffers;
1019 lpDSCaps->dwMaxHw3DStaticBuffers = device->drvcaps.dwMaxHw3DStaticBuffers;
1020 lpDSCaps->dwMaxHw3DStreamingBuffers = device->drvcaps.dwMaxHw3DStreamingBuffers;
1021 lpDSCaps->dwFreeHw3DAllBuffers = device->drvcaps.dwFreeHw3DAllBuffers;
1022 lpDSCaps->dwFreeHw3DStaticBuffers = device->drvcaps.dwFreeHw3DStaticBuffers;
1023 lpDSCaps->dwFreeHw3DStreamingBuffers = device->drvcaps.dwFreeHw3DStreamingBuffers;
1024 lpDSCaps->dwTotalHwMemBytes = device->drvcaps.dwTotalHwMemBytes;
1025 lpDSCaps->dwFreeHwMemBytes = device->drvcaps.dwFreeHwMemBytes;
1026 lpDSCaps->dwMaxContigFreeHwMemBytes = device->drvcaps.dwMaxContigFreeHwMemBytes;
1027 lpDSCaps->dwUnlockTransferRateHwBuffers = device->drvcaps.dwUnlockTransferRateHwBuffers;
1028 lpDSCaps->dwPlayCpuOverheadSwBuffers = device->drvcaps.dwPlayCpuOverheadSwBuffers;
1030 return DS_OK;
1033 BOOL DSOUND_check_supported(IAudioClient *client, DWORD rate,
1034 DWORD depth, WORD channels)
1036 WAVEFORMATEX fmt, *junk;
1037 HRESULT hr;
1039 fmt.wFormatTag = WAVE_FORMAT_PCM;
1040 fmt.nChannels = channels;
1041 fmt.nSamplesPerSec = rate;
1042 fmt.wBitsPerSample = depth;
1043 fmt.nBlockAlign = (channels * depth) / 8;
1044 fmt.nAvgBytesPerSec = rate * fmt.nBlockAlign;
1045 fmt.cbSize = 0;
1047 hr = IAudioClient_IsFormatSupported(client, AUDCLNT_SHAREMODE_SHARED, &fmt, &junk);
1048 if(SUCCEEDED(hr))
1049 CoTaskMemFree(junk);
1051 return hr == S_OK;
1054 UINT DSOUND_create_timer(LPTIMECALLBACK cb, DWORD_PTR user)
1056 UINT triggertime = DS_TIME_DEL, res = DS_TIME_RES, id;
1057 TIMECAPS time;
1059 timeGetDevCaps(&time, sizeof(TIMECAPS));
1060 TRACE("Minimum timer resolution: %u, max timer: %u\n", time.wPeriodMin, time.wPeriodMax);
1061 if (triggertime < time.wPeriodMin)
1062 triggertime = time.wPeriodMin;
1063 if (res < time.wPeriodMin)
1064 res = time.wPeriodMin;
1065 if (timeBeginPeriod(res) == TIMERR_NOCANDO)
1066 WARN("Could not set minimum resolution, don't expect sound\n");
1067 id = timeSetEvent(triggertime, res, cb, user, TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
1068 if (!id)
1070 WARN("Timer not created! Retrying without TIME_KILL_SYNCHRONOUS\n");
1071 id = timeSetEvent(triggertime, res, cb, user, TIME_PERIODIC);
1072 if (!id)
1073 ERR("Could not create timer, sound playback will not occur\n");
1075 return id;
1078 HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcGUID)
1080 HRESULT hr = DS_OK;
1081 GUID devGUID;
1082 DirectSoundDevice *device;
1083 IMMDevice *mmdevice;
1085 TRACE("(%p,%s)\n",ppDevice,debugstr_guid(lpcGUID));
1087 if (*ppDevice != NULL) {
1088 WARN("already initialized\n");
1089 return DSERR_ALREADYINITIALIZED;
1092 /* Default device? */
1093 if (!lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL))
1094 lpcGUID = &DSDEVID_DefaultPlayback;
1096 if(IsEqualGUID(lpcGUID, &DSDEVID_DefaultCapture) ||
1097 IsEqualGUID(lpcGUID, &DSDEVID_DefaultVoiceCapture))
1098 return DSERR_NODRIVER;
1100 if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
1101 WARN("invalid parameter: lpcGUID\n");
1102 return DSERR_INVALIDPARAM;
1105 hr = get_mmdevice(eRender, &devGUID, &mmdevice);
1106 if(FAILED(hr))
1107 return hr;
1109 EnterCriticalSection(&DSOUND_renderers_lock);
1111 LIST_FOR_EACH_ENTRY(device, &DSOUND_renderers, DirectSoundDevice, entry){
1112 if(IsEqualGUID(&device->guid, &devGUID)){
1113 IMMDevice_Release(mmdevice);
1114 DirectSoundDevice_AddRef(device);
1115 *ppDevice = device;
1116 LeaveCriticalSection(&DSOUND_renderers_lock);
1117 return DS_OK;
1121 hr = DirectSoundDevice_Create(&device);
1122 if(FAILED(hr)){
1123 WARN("DirectSoundDevice_Create failed\n");
1124 IMMDevice_Release(mmdevice);
1125 LeaveCriticalSection(&DSOUND_renderers_lock);
1126 return hr;
1129 device->mmdevice = mmdevice;
1130 device->guid = devGUID;
1132 hr = DSOUND_ReopenDevice(device, FALSE);
1133 if (FAILED(hr))
1135 HeapFree(GetProcessHeap(), 0, device);
1136 LeaveCriticalSection(&DSOUND_renderers_lock);
1137 IMMDevice_Release(mmdevice);
1138 WARN("DSOUND_ReopenDevice failed: %08x\n", hr);
1139 return hr;
1142 ZeroMemory(&device->drvcaps, sizeof(device->drvcaps));
1144 if(DSOUND_check_supported(device->client, 11025, 8, 1) ||
1145 DSOUND_check_supported(device->client, 22050, 8, 1) ||
1146 DSOUND_check_supported(device->client, 44100, 8, 1) ||
1147 DSOUND_check_supported(device->client, 48000, 8, 1) ||
1148 DSOUND_check_supported(device->client, 96000, 8, 1))
1149 device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT | DSCAPS_PRIMARYMONO;
1151 if(DSOUND_check_supported(device->client, 11025, 16, 1) ||
1152 DSOUND_check_supported(device->client, 22050, 16, 1) ||
1153 DSOUND_check_supported(device->client, 44100, 16, 1) ||
1154 DSOUND_check_supported(device->client, 48000, 16, 1) ||
1155 DSOUND_check_supported(device->client, 96000, 16, 1))
1156 device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT | DSCAPS_PRIMARYMONO;
1158 if(DSOUND_check_supported(device->client, 11025, 8, 2) ||
1159 DSOUND_check_supported(device->client, 22050, 8, 2) ||
1160 DSOUND_check_supported(device->client, 44100, 8, 2) ||
1161 DSOUND_check_supported(device->client, 48000, 8, 2) ||
1162 DSOUND_check_supported(device->client, 96000, 8, 2))
1163 device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT | DSCAPS_PRIMARYSTEREO;
1165 if(DSOUND_check_supported(device->client, 11025, 16, 2) ||
1166 DSOUND_check_supported(device->client, 22050, 16, 2) ||
1167 DSOUND_check_supported(device->client, 44100, 16, 2) ||
1168 DSOUND_check_supported(device->client, 48000, 16, 2) ||
1169 DSOUND_check_supported(device->client, 96000, 16, 2))
1170 device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT | DSCAPS_PRIMARYSTEREO;
1172 /* the dsound mixer supports all of the following */
1173 device->drvcaps.dwFlags |= DSCAPS_SECONDARY8BIT | DSCAPS_SECONDARY16BIT;
1174 device->drvcaps.dwFlags |= DSCAPS_SECONDARYMONO | DSCAPS_SECONDARYSTEREO;
1175 device->drvcaps.dwFlags |= DSCAPS_CONTINUOUSRATE;
1177 device->drvcaps.dwPrimaryBuffers = 1;
1178 device->drvcaps.dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
1179 device->drvcaps.dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
1180 device->drvcaps.dwMaxHwMixingAllBuffers = 1;
1181 device->drvcaps.dwMaxHwMixingStaticBuffers = 1;
1182 device->drvcaps.dwMaxHwMixingStreamingBuffers = 1;
1184 ZeroMemory(&device->volpan, sizeof(device->volpan));
1186 hr = DSOUND_PrimaryCreate(device);
1187 if (hr == DS_OK)
1188 device->timerID = DSOUND_create_timer(DSOUND_timer, (DWORD_PTR)device);
1189 else
1190 WARN("DSOUND_PrimaryCreate failed: %08x\n", hr);
1192 *ppDevice = device;
1193 list_add_tail(&DSOUND_renderers, &device->entry);
1195 LeaveCriticalSection(&DSOUND_renderers_lock);
1197 return hr;
1200 HRESULT DirectSoundDevice_CreateSoundBuffer(
1201 DirectSoundDevice * device,
1202 LPCDSBUFFERDESC dsbd,
1203 LPLPDIRECTSOUNDBUFFER ppdsb,
1204 LPUNKNOWN lpunk,
1205 BOOL from8)
1207 HRESULT hres = DS_OK;
1208 TRACE("(%p,%p,%p,%p)\n",device,dsbd,ppdsb,lpunk);
1210 if (device == NULL) {
1211 WARN("not initialized\n");
1212 return DSERR_UNINITIALIZED;
1215 if (dsbd == NULL) {
1216 WARN("invalid parameter: dsbd == NULL\n");
1217 return DSERR_INVALIDPARAM;
1220 if (dsbd->dwSize != sizeof(DSBUFFERDESC) &&
1221 dsbd->dwSize != sizeof(DSBUFFERDESC1)) {
1222 WARN("invalid parameter: dsbd\n");
1223 return DSERR_INVALIDPARAM;
1226 if (ppdsb == NULL) {
1227 WARN("invalid parameter: ppdsb == NULL\n");
1228 return DSERR_INVALIDPARAM;
1230 *ppdsb = NULL;
1232 if (TRACE_ON(dsound)) {
1233 TRACE("(structsize=%d)\n",dsbd->dwSize);
1234 TRACE("(flags=0x%08x:\n",dsbd->dwFlags);
1235 _dump_DSBCAPS(dsbd->dwFlags);
1236 TRACE(")\n");
1237 TRACE("(bufferbytes=%d)\n",dsbd->dwBufferBytes);
1238 TRACE("(lpwfxFormat=%p)\n",dsbd->lpwfxFormat);
1241 if (dsbd->dwFlags & DSBCAPS_LOCHARDWARE &&
1242 !(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
1243 TRACE("LOCHARDWARE is not supported, returning E_NOTIMPL\n");
1244 return E_NOTIMPL;
1247 if (dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) {
1248 if (dsbd->lpwfxFormat != NULL) {
1249 WARN("invalid parameter: dsbd->lpwfxFormat must be NULL for "
1250 "primary buffer\n");
1251 return DSERR_INVALIDPARAM;
1254 if (device->primary) {
1255 WARN("Primary Buffer already created\n");
1256 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(device->primary));
1257 *ppdsb = (LPDIRECTSOUNDBUFFER)(device->primary);
1258 } else {
1259 hres = primarybuffer_create(device, &device->primary, dsbd);
1260 if (device->primary) {
1261 *ppdsb = (IDirectSoundBuffer*)&device->primary->IDirectSoundBuffer8_iface;
1262 device->primary->dsbd.dwFlags &= ~(DSBCAPS_LOCHARDWARE | DSBCAPS_LOCSOFTWARE);
1263 device->primary->dsbd.dwFlags |= DSBCAPS_LOCSOFTWARE;
1264 } else
1265 WARN("primarybuffer_create() failed\n");
1267 } else {
1268 IDirectSoundBufferImpl * dsb;
1269 WAVEFORMATEXTENSIBLE *pwfxe;
1271 if (dsbd->lpwfxFormat == NULL) {
1272 WARN("invalid parameter: dsbd->lpwfxFormat can't be NULL for "
1273 "secondary buffer\n");
1274 return DSERR_INVALIDPARAM;
1276 pwfxe = (WAVEFORMATEXTENSIBLE*)dsbd->lpwfxFormat;
1278 if (pwfxe->Format.wBitsPerSample != 16 && pwfxe->Format.wBitsPerSample != 8 && pwfxe->Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE)
1280 WARN("wBitsPerSample=%d needs a WAVEFORMATEXTENSIBLE\n", dsbd->lpwfxFormat->wBitsPerSample);
1281 return DSERR_CONTROLUNAVAIL;
1283 if (pwfxe->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE)
1285 /* check if cbSize is at least 22 bytes */
1286 if (pwfxe->Format.cbSize < (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)))
1288 WARN("Too small a cbSize %u\n", pwfxe->Format.cbSize);
1289 return DSERR_INVALIDPARAM;
1292 /* cbSize should be 22 bytes, with one possible exception */
1293 if (pwfxe->Format.cbSize > (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)) &&
1294 !((IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) || IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) &&
1295 pwfxe->Format.cbSize == sizeof(WAVEFORMATEXTENSIBLE)))
1297 WARN("Too big a cbSize %u\n", pwfxe->Format.cbSize);
1298 return DSERR_CONTROLUNAVAIL;
1301 if ((!IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) && (!IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)))
1303 if (!IsEqualGUID(&pwfxe->SubFormat, &GUID_NULL))
1304 FIXME("SubFormat %s not supported right now.\n", debugstr_guid(&pwfxe->SubFormat));
1305 return DSERR_INVALIDPARAM;
1307 if (pwfxe->Samples.wValidBitsPerSample > dsbd->lpwfxFormat->wBitsPerSample)
1309 WARN("Samples.wValidBitsPerSample(%d) > Format.wBitsPerSample (%d)\n", pwfxe->Samples.wValidBitsPerSample, pwfxe->Format.wBitsPerSample);
1310 return DSERR_INVALIDPARAM;
1312 if (pwfxe->Samples.wValidBitsPerSample && pwfxe->Samples.wValidBitsPerSample < dsbd->lpwfxFormat->wBitsPerSample)
1314 FIXME("Non-packed formats not supported right now: %d/%d\n", pwfxe->Samples.wValidBitsPerSample, dsbd->lpwfxFormat->wBitsPerSample);
1315 return DSERR_CONTROLUNAVAIL;
1319 TRACE("(formattag=0x%04x,chans=%d,samplerate=%d,"
1320 "bytespersec=%d,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
1321 dsbd->lpwfxFormat->wFormatTag, dsbd->lpwfxFormat->nChannels,
1322 dsbd->lpwfxFormat->nSamplesPerSec,
1323 dsbd->lpwfxFormat->nAvgBytesPerSec,
1324 dsbd->lpwfxFormat->nBlockAlign,
1325 dsbd->lpwfxFormat->wBitsPerSample, dsbd->lpwfxFormat->cbSize);
1327 if (from8 && (dsbd->dwFlags & DSBCAPS_CTRL3D) && (dsbd->lpwfxFormat->nChannels != 1)) {
1328 WARN("invalid parameter: 3D buffer format must be mono\n");
1329 return DSERR_INVALIDPARAM;
1332 hres = IDirectSoundBufferImpl_Create(device, &dsb, dsbd);
1333 if (dsb)
1334 *ppdsb = (IDirectSoundBuffer*)&dsb->IDirectSoundBuffer8_iface;
1335 else
1336 WARN("IDirectSoundBufferImpl_Create failed\n");
1339 return hres;
1342 HRESULT DirectSoundDevice_DuplicateSoundBuffer(
1343 DirectSoundDevice * device,
1344 LPDIRECTSOUNDBUFFER psb,
1345 LPLPDIRECTSOUNDBUFFER ppdsb)
1347 HRESULT hres = DS_OK;
1348 IDirectSoundBufferImpl* dsb;
1349 TRACE("(%p,%p,%p)\n",device,psb,ppdsb);
1351 if (device == NULL) {
1352 WARN("not initialized\n");
1353 return DSERR_UNINITIALIZED;
1356 if (psb == NULL) {
1357 WARN("invalid parameter: psb == NULL\n");
1358 return DSERR_INVALIDPARAM;
1361 if (ppdsb == NULL) {
1362 WARN("invalid parameter: ppdsb == NULL\n");
1363 return DSERR_INVALIDPARAM;
1366 /* make sure we have a secondary buffer */
1367 if (psb == (IDirectSoundBuffer *)&device->primary->IDirectSoundBuffer8_iface) {
1368 WARN("trying to duplicate primary buffer\n");
1369 *ppdsb = NULL;
1370 return DSERR_INVALIDCALL;
1373 /* duplicate the actual buffer implementation */
1374 hres = IDirectSoundBufferImpl_Duplicate(device, &dsb, (IDirectSoundBufferImpl*)psb);
1375 if (hres == DS_OK)
1376 *ppdsb = (IDirectSoundBuffer*)&dsb->IDirectSoundBuffer8_iface;
1377 else
1378 WARN("IDirectSoundBufferImpl_Duplicate failed\n");
1380 return hres;
1383 HRESULT DirectSoundDevice_SetCooperativeLevel(
1384 DirectSoundDevice * device,
1385 HWND hwnd,
1386 DWORD level)
1388 TRACE("(%p,%p,%s)\n",device,hwnd,dumpCooperativeLevel(level));
1390 if (device == NULL) {
1391 WARN("not initialized\n");
1392 return DSERR_UNINITIALIZED;
1395 if (level==DSSCL_PRIORITY || level==DSSCL_EXCLUSIVE) {
1396 WARN("level=%s not fully supported\n",
1397 level==DSSCL_PRIORITY ? "DSSCL_PRIORITY" : "DSSCL_EXCLUSIVE");
1400 device->priolevel = level;
1401 return DS_OK;
1404 HRESULT DirectSoundDevice_Compact(
1405 DirectSoundDevice * device)
1407 TRACE("(%p)\n", device);
1409 if (device == NULL) {
1410 WARN("not initialized\n");
1411 return DSERR_UNINITIALIZED;
1414 if (device->priolevel < DSSCL_PRIORITY) {
1415 WARN("incorrect priority level\n");
1416 return DSERR_PRIOLEVELNEEDED;
1419 return DS_OK;
1422 HRESULT DirectSoundDevice_GetSpeakerConfig(
1423 DirectSoundDevice * device,
1424 LPDWORD lpdwSpeakerConfig)
1426 TRACE("(%p, %p)\n", device, lpdwSpeakerConfig);
1428 if (device == NULL) {
1429 WARN("not initialized\n");
1430 return DSERR_UNINITIALIZED;
1433 if (lpdwSpeakerConfig == NULL) {
1434 WARN("invalid parameter: lpdwSpeakerConfig == NULL\n");
1435 return DSERR_INVALIDPARAM;
1438 WARN("not fully functional\n");
1439 *lpdwSpeakerConfig = device->speaker_config;
1440 return DS_OK;
1443 HRESULT DirectSoundDevice_SetSpeakerConfig(
1444 DirectSoundDevice * device,
1445 DWORD config)
1447 TRACE("(%p,0x%08x)\n",device,config);
1449 if (device == NULL) {
1450 WARN("not initialized\n");
1451 return DSERR_UNINITIALIZED;
1454 device->speaker_config = config;
1455 WARN("not fully functional\n");
1456 return DS_OK;
1459 HRESULT DirectSoundDevice_VerifyCertification(
1460 DirectSoundDevice * device,
1461 LPDWORD pdwCertified)
1463 TRACE("(%p, %p)\n",device,pdwCertified);
1465 if (device == NULL) {
1466 WARN("not initialized\n");
1467 return DSERR_UNINITIALIZED;
1470 if (device->drvcaps.dwFlags & DSCAPS_CERTIFIED)
1471 *pdwCertified = DS_CERTIFIED;
1472 else
1473 *pdwCertified = DS_UNCERTIFIED;
1475 return DS_OK;
1479 * Add secondary buffer to buffer list.
1480 * Gets exclusive access to buffer for writing.
1482 HRESULT DirectSoundDevice_AddBuffer(
1483 DirectSoundDevice * device,
1484 IDirectSoundBufferImpl * pDSB)
1486 IDirectSoundBufferImpl **newbuffers;
1487 HRESULT hr = DS_OK;
1489 TRACE("(%p, %p)\n", device, pDSB);
1491 RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
1493 if (device->buffers)
1494 newbuffers = HeapReAlloc(GetProcessHeap(),0,device->buffers,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
1495 else
1496 newbuffers = HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
1498 if (newbuffers) {
1499 device->buffers = newbuffers;
1500 device->buffers[device->nrofbuffers] = pDSB;
1501 device->nrofbuffers++;
1502 TRACE("buffer count is now %d\n", device->nrofbuffers);
1503 } else {
1504 ERR("out of memory for buffer list! Current buffer count is %d\n", device->nrofbuffers);
1505 hr = DSERR_OUTOFMEMORY;
1508 RtlReleaseResource(&(device->buffer_list_lock));
1510 return hr;
1514 * Remove secondary buffer from buffer list.
1515 * Gets exclusive access to buffer for writing.
1517 HRESULT DirectSoundDevice_RemoveBuffer(
1518 DirectSoundDevice * device,
1519 IDirectSoundBufferImpl * pDSB)
1521 int i;
1522 HRESULT hr = DS_OK;
1524 TRACE("(%p, %p)\n", device, pDSB);
1526 RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
1528 for (i = 0; i < device->nrofbuffers; i++)
1529 if (device->buffers[i] == pDSB)
1530 break;
1532 if (i < device->nrofbuffers) {
1533 /* Put the last buffer of the list in the (now empty) position */
1534 device->buffers[i] = device->buffers[device->nrofbuffers - 1];
1535 device->nrofbuffers--;
1536 device->buffers = HeapReAlloc(GetProcessHeap(),0,device->buffers,sizeof(LPDIRECTSOUNDBUFFER8)*device->nrofbuffers);
1537 TRACE("buffer count is now %d\n", device->nrofbuffers);
1540 if (device->nrofbuffers == 0) {
1541 HeapFree(GetProcessHeap(),0,device->buffers);
1542 device->buffers = NULL;
1545 RtlReleaseResource(&(device->buffer_list_lock));
1547 return hr;