dsound: Drop a redundant 'IDirectSound8' from the method names.
[wine/multimedia.git] / dlls / dsound / dsound.c
blob55af7544c575e4a36e02388ee528bab9c0fcad5c
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_IDirectSound {
48 const IDirectSoundVtbl *lpVtbl;
49 LONG ref;
50 LPDIRECTSOUND8 pds;
53 static HRESULT IDirectSound_IDirectSound_Create(LPDIRECTSOUND8 pds, LPDIRECTSOUND * ppds);
55 /*****************************************************************************
56 * IDirectSound8 COM components
58 struct IDirectSound8_IDirectSound8 {
59 const IDirectSound8Vtbl *lpVtbl;
60 LONG ref;
61 LPDIRECTSOUND8 pds;
64 static HRESULT IDirectSound8_IDirectSound8_Create(LPDIRECTSOUND8 pds, LPDIRECTSOUND8 * ppds);
66 typedef struct IDirectSoundImpl {
67 IUnknown IUnknown_iface; /* Separate refcount, not for COM aggregation */
68 LONG ref, numIfaces;
69 DirectSoundDevice *device;
70 BOOL has_ds8;
71 LPDIRECTSOUND pDS;
72 LPDIRECTSOUND8 pDS8;
73 } IDirectSoundImpl;
75 static ULONG WINAPI IDirectSound_IDirectSound_AddRef(LPDIRECTSOUND iface);
77 const char * dumpCooperativeLevel(DWORD level)
79 #define LE(x) case x: return #x
80 switch (level) {
81 LE(DSSCL_NORMAL);
82 LE(DSSCL_PRIORITY);
83 LE(DSSCL_EXCLUSIVE);
84 LE(DSSCL_WRITEPRIMARY);
86 #undef LE
87 return wine_dbg_sprintf("Unknown(%08x)", level);
90 static void _dump_DSCAPS(DWORD xmask) {
91 struct {
92 DWORD mask;
93 const char *name;
94 } flags[] = {
95 #define FE(x) { x, #x },
96 FE(DSCAPS_PRIMARYMONO)
97 FE(DSCAPS_PRIMARYSTEREO)
98 FE(DSCAPS_PRIMARY8BIT)
99 FE(DSCAPS_PRIMARY16BIT)
100 FE(DSCAPS_CONTINUOUSRATE)
101 FE(DSCAPS_EMULDRIVER)
102 FE(DSCAPS_CERTIFIED)
103 FE(DSCAPS_SECONDARYMONO)
104 FE(DSCAPS_SECONDARYSTEREO)
105 FE(DSCAPS_SECONDARY8BIT)
106 FE(DSCAPS_SECONDARY16BIT)
107 #undef FE
109 unsigned int i;
111 for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
112 if ((flags[i].mask & xmask) == flags[i].mask)
113 TRACE("%s ",flags[i].name);
116 static void _dump_DSBCAPS(DWORD xmask) {
117 struct {
118 DWORD mask;
119 const char *name;
120 } flags[] = {
121 #define FE(x) { x, #x },
122 FE(DSBCAPS_PRIMARYBUFFER)
123 FE(DSBCAPS_STATIC)
124 FE(DSBCAPS_LOCHARDWARE)
125 FE(DSBCAPS_LOCSOFTWARE)
126 FE(DSBCAPS_CTRL3D)
127 FE(DSBCAPS_CTRLFREQUENCY)
128 FE(DSBCAPS_CTRLPAN)
129 FE(DSBCAPS_CTRLVOLUME)
130 FE(DSBCAPS_CTRLPOSITIONNOTIFY)
131 FE(DSBCAPS_STICKYFOCUS)
132 FE(DSBCAPS_GLOBALFOCUS)
133 FE(DSBCAPS_GETCURRENTPOSITION2)
134 FE(DSBCAPS_MUTE3DATMAXDISTANCE)
135 #undef FE
137 unsigned int i;
139 for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
140 if ((flags[i].mask & xmask) == flags[i].mask)
141 TRACE("%s ",flags[i].name);
144 /*******************************************************************************
145 * IDirectSoundImpl_DirectSound
147 static HRESULT DSOUND_QueryInterface(
148 LPDIRECTSOUND8 iface,
149 REFIID riid,
150 LPVOID * ppobj)
152 IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
153 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
155 if (ppobj == NULL) {
156 WARN("invalid parameter\n");
157 return E_INVALIDARG;
160 if (IsEqualIID(riid, &IID_IUnknown)) {
161 IUnknown_AddRef(&This->IUnknown_iface);
162 *ppobj = &This->IUnknown_iface;
163 return S_OK;
164 } else if (IsEqualIID(riid, &IID_IDirectSound)) {
165 if (!This->pDS) {
166 IDirectSound_IDirectSound_Create(iface, &This->pDS);
167 if (!This->pDS) {
168 WARN("IDirectSound_IDirectSound_Create() failed\n");
169 *ppobj = NULL;
170 return E_NOINTERFACE;
173 IDirectSound_IDirectSound_AddRef(This->pDS);
174 *ppobj = This->pDS;
175 return S_OK;
176 } else if (This->has_ds8 && IsEqualIID(riid, &IID_IDirectSound8)) {
177 if (!This->pDS8) {
178 IDirectSound8_IDirectSound8_Create(iface, &This->pDS8);
179 if (!This->pDS8) {
180 WARN("IDirectSound8_IDirectSound8_Create() failed\n");
181 *ppobj = NULL;
182 return E_NOINTERFACE;
185 IDirectSound8_AddRef(This->pDS8);
186 *ppobj = This->pDS8;
187 return S_OK;
190 *ppobj = NULL;
191 WARN("Unknown IID %s\n",debugstr_guid(riid));
192 return E_NOINTERFACE;
195 static void directsound_destroy(IDirectSoundImpl *This)
197 if (This->device)
198 DirectSoundDevice_Release(This->device);
199 HeapFree(GetProcessHeap(),0,This);
200 TRACE("(%p) released\n", This);
203 /*******************************************************************************
204 * IUnknown Implementation for DirectSound
206 static inline IDirectSoundImpl *impl_from_IUnknown(IUnknown *iface)
208 return CONTAINING_RECORD(iface, IDirectSoundImpl, IUnknown_iface);
211 static HRESULT WINAPI IUnknownImpl_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
213 IDirectSoundImpl *This = impl_from_IUnknown(iface);
214 TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
215 return DSOUND_QueryInterface((IDirectSound8 *)This, riid, ppv);
218 static ULONG WINAPI IUnknownImpl_AddRef(IUnknown *iface)
220 IDirectSoundImpl *This = impl_from_IUnknown(iface);
221 ULONG ref = InterlockedIncrement(&This->ref);
223 TRACE("(%p) ref=%d\n", This, ref);
225 if(ref == 1)
226 InterlockedIncrement(&This->numIfaces);
228 return ref;
231 static ULONG WINAPI IUnknownImpl_Release(IUnknown *iface)
233 IDirectSoundImpl *This = impl_from_IUnknown(iface);
234 ULONG ref = InterlockedDecrement(&This->ref);
236 TRACE("(%p) ref=%d\n", This, ref);
238 if (!ref && !InterlockedDecrement(&This->numIfaces))
239 directsound_destroy(This);
241 return ref;
244 static const IUnknownVtbl unk_vtbl =
246 IUnknownImpl_QueryInterface,
247 IUnknownImpl_AddRef,
248 IUnknownImpl_Release
251 /*******************************************************************************
252 * IDirectSound_IDirectSound
254 static HRESULT WINAPI IDirectSound_IDirectSound_QueryInterface(
255 LPDIRECTSOUND iface,
256 REFIID riid,
257 LPVOID * ppobj)
259 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
260 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
261 return DSOUND_QueryInterface(This->pds, riid, ppobj);
264 static ULONG WINAPI IDirectSound_IDirectSound_AddRef(
265 LPDIRECTSOUND iface)
267 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
268 ULONG ref = InterlockedIncrement(&(This->ref));
269 TRACE("(%p) ref was %d\n", This, ref - 1);
270 return ref;
273 static ULONG WINAPI IDirectSound_IDirectSound_Release(
274 LPDIRECTSOUND iface)
276 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
277 ULONG ref = InterlockedDecrement(&(This->ref));
278 TRACE("(%p) ref was %d\n", This, ref + 1);
279 if (!ref && !InterlockedDecrement(&((IDirectSoundImpl *)This->pds)->numIfaces)) {
280 ((IDirectSoundImpl*)This->pds)->pDS = NULL;
281 directsound_destroy((IDirectSoundImpl*)This->pds);
282 HeapFree(GetProcessHeap(), 0, This);
283 TRACE("(%p) released\n", This);
285 return ref;
288 static HRESULT WINAPI IDirectSound_IDirectSound_CreateSoundBuffer(
289 LPDIRECTSOUND iface,
290 LPCDSBUFFERDESC dsbd,
291 LPLPDIRECTSOUNDBUFFER ppdsb,
292 LPUNKNOWN lpunk)
294 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
295 TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
296 return DirectSoundDevice_CreateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,dsbd,ppdsb,lpunk,((IDirectSoundImpl *)This->pds)->has_ds8);
299 static HRESULT WINAPI IDirectSound_IDirectSound_GetCaps(
300 LPDIRECTSOUND iface,
301 LPDSCAPS lpDSCaps)
303 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
304 TRACE("(%p,%p)\n",This,lpDSCaps);
305 return DirectSoundDevice_GetCaps(((IDirectSoundImpl *)This->pds)->device, lpDSCaps);
308 static HRESULT WINAPI IDirectSound_IDirectSound_DuplicateSoundBuffer(
309 LPDIRECTSOUND iface,
310 LPDIRECTSOUNDBUFFER psb,
311 LPLPDIRECTSOUNDBUFFER ppdsb)
313 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
314 TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
315 return DirectSoundDevice_DuplicateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,psb,ppdsb);
318 static HRESULT WINAPI IDirectSound_IDirectSound_SetCooperativeLevel(
319 LPDIRECTSOUND iface,
320 HWND hwnd,
321 DWORD level)
323 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
324 TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level));
325 return DirectSoundDevice_SetCooperativeLevel(((IDirectSoundImpl *)This->pds)->device, hwnd, level);
328 static HRESULT WINAPI IDirectSound_IDirectSound_Compact(
329 LPDIRECTSOUND iface)
331 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
332 TRACE("(%p)\n", This);
333 return DirectSoundDevice_Compact(((IDirectSoundImpl *)This->pds)->device);
336 static HRESULT WINAPI IDirectSound_IDirectSound_GetSpeakerConfig(
337 LPDIRECTSOUND iface,
338 LPDWORD lpdwSpeakerConfig)
340 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
341 TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
342 return DirectSoundDevice_GetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,lpdwSpeakerConfig);
345 static HRESULT WINAPI IDirectSound_IDirectSound_SetSpeakerConfig(
346 LPDIRECTSOUND iface,
347 DWORD config)
349 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
350 TRACE("(%p,0x%08x)\n",This,config);
351 return DirectSoundDevice_SetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,config);
354 static HRESULT WINAPI IDirectSound_IDirectSound_Initialize(
355 LPDIRECTSOUND iface,
356 LPCGUID lpcGuid)
358 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
359 TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
360 return DirectSoundDevice_Initialize(&((IDirectSoundImpl *)This->pds)->device,lpcGuid);
363 static const IDirectSoundVtbl DirectSound_DirectSound_Vtbl =
365 IDirectSound_IDirectSound_QueryInterface,
366 IDirectSound_IDirectSound_AddRef,
367 IDirectSound_IDirectSound_Release,
368 IDirectSound_IDirectSound_CreateSoundBuffer,
369 IDirectSound_IDirectSound_GetCaps,
370 IDirectSound_IDirectSound_DuplicateSoundBuffer,
371 IDirectSound_IDirectSound_SetCooperativeLevel,
372 IDirectSound_IDirectSound_Compact,
373 IDirectSound_IDirectSound_GetSpeakerConfig,
374 IDirectSound_IDirectSound_SetSpeakerConfig,
375 IDirectSound_IDirectSound_Initialize
378 static HRESULT IDirectSound_IDirectSound_Create(
379 LPDIRECTSOUND8 pds,
380 LPDIRECTSOUND * ppds)
382 IDirectSound_IDirectSound * pdsds;
383 TRACE("(%p,%p)\n",pds,ppds);
385 if (ppds == NULL) {
386 ERR("invalid parameter: ppds == NULL\n");
387 return DSERR_INVALIDPARAM;
390 if (pds == NULL) {
391 ERR("invalid parameter: pds == NULL\n");
392 *ppds = NULL;
393 return DSERR_INVALIDPARAM;
396 pdsds = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsds));
397 if (pdsds == NULL) {
398 WARN("out of memory\n");
399 *ppds = NULL;
400 return DSERR_OUTOFMEMORY;
403 pdsds->lpVtbl = &DirectSound_DirectSound_Vtbl;
404 pdsds->ref = 0;
405 pdsds->pds = pds;
407 InterlockedIncrement(&((IDirectSoundImpl *)pds)->numIfaces);
408 *ppds = (LPDIRECTSOUND)pdsds;
410 return DS_OK;
413 /*******************************************************************************
414 * IDirectSound8 Implementation
416 static HRESULT WINAPI IDirectSound8Impl_QueryInterface(IDirectSound8 *iface, REFIID riid,
417 void **ppobj)
419 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
420 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
421 return DSOUND_QueryInterface(This->pds, riid, ppobj);
424 static ULONG WINAPI IDirectSound8Impl_AddRef(IDirectSound8 *iface)
426 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
427 ULONG ref = InterlockedIncrement(&(This->ref));
428 TRACE("(%p) ref was %d\n", This, ref - 1);
429 return ref;
432 static ULONG WINAPI IDirectSound8Impl_Release(IDirectSound8 *iface)
434 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
435 ULONG ref = InterlockedDecrement(&(This->ref));
436 TRACE("(%p) ref was %d\n", This, ref + 1);
437 if (!ref && !InterlockedDecrement(&((IDirectSoundImpl *)This->pds)->numIfaces)) {
438 ((IDirectSoundImpl*)This->pds)->pDS8 = NULL;
439 directsound_destroy((IDirectSoundImpl*)This->pds);
440 HeapFree(GetProcessHeap(), 0, This);
441 TRACE("(%p) released\n", This);
443 return ref;
446 static HRESULT WINAPI IDirectSound8Impl_CreateSoundBuffer(IDirectSound8 *iface,
447 const DSBUFFERDESC *dsbd, IDirectSoundBuffer **ppdsb, IUnknown *lpunk)
449 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
450 TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
451 return DirectSoundDevice_CreateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,dsbd,ppdsb,lpunk,TRUE);
454 static HRESULT WINAPI IDirectSound8Impl_GetCaps(IDirectSound8 *iface, DSCAPS *lpDSCaps)
456 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
457 TRACE("(%p,%p)\n",This,lpDSCaps);
458 return DirectSoundDevice_GetCaps(((IDirectSoundImpl *)This->pds)->device, lpDSCaps);
461 static HRESULT WINAPI IDirectSound8Impl_DuplicateSoundBuffer(IDirectSound8 *iface,
462 IDirectSoundBuffer *psb, IDirectSoundBuffer **ppdsb)
464 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
465 TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
466 return DirectSoundDevice_DuplicateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,psb,ppdsb);
469 static HRESULT WINAPI IDirectSound8Impl_SetCooperativeLevel(IDirectSound8 *iface, HWND hwnd,
470 DWORD level)
472 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
473 TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level));
474 return DirectSoundDevice_SetCooperativeLevel(((IDirectSoundImpl *)This->pds)->device, hwnd, level);
477 static HRESULT WINAPI IDirectSound8Impl_Compact(IDirectSound8 *iface)
479 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
480 TRACE("(%p)\n", This);
481 return DirectSoundDevice_Compact(((IDirectSoundImpl *)This->pds)->device);
484 static HRESULT WINAPI IDirectSound8Impl_GetSpeakerConfig(IDirectSound8 *iface,
485 DWORD *lpdwSpeakerConfig)
487 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
488 TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
489 return DirectSoundDevice_GetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,lpdwSpeakerConfig);
492 static HRESULT WINAPI IDirectSound8Impl_SetSpeakerConfig(IDirectSound8 *iface, DWORD config)
494 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
495 TRACE("(%p,0x%08x)\n",This,config);
496 return DirectSoundDevice_SetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,config);
499 static HRESULT WINAPI IDirectSound8Impl_Initialize(IDirectSound8 *iface, const GUID *lpcGuid)
501 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
502 TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
503 return DirectSoundDevice_Initialize(&((IDirectSoundImpl *)This->pds)->device,lpcGuid);
506 static HRESULT WINAPI IDirectSound8Impl_VerifyCertification(IDirectSound8 *iface,
507 DWORD *pdwCertified)
509 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
510 TRACE("(%p, %p)\n", This, pdwCertified);
511 return DirectSoundDevice_VerifyCertification(((IDirectSoundImpl *)This->pds)->device,pdwCertified);
514 static const IDirectSound8Vtbl ds8_vtbl =
516 IDirectSound8Impl_QueryInterface,
517 IDirectSound8Impl_AddRef,
518 IDirectSound8Impl_Release,
519 IDirectSound8Impl_CreateSoundBuffer,
520 IDirectSound8Impl_GetCaps,
521 IDirectSound8Impl_DuplicateSoundBuffer,
522 IDirectSound8Impl_SetCooperativeLevel,
523 IDirectSound8Impl_Compact,
524 IDirectSound8Impl_GetSpeakerConfig,
525 IDirectSound8Impl_SetSpeakerConfig,
526 IDirectSound8Impl_Initialize,
527 IDirectSound8Impl_VerifyCertification
530 static HRESULT IDirectSound8_IDirectSound8_Create(
531 LPDIRECTSOUND8 pds,
532 LPDIRECTSOUND8 * ppds)
534 IDirectSound8_IDirectSound8 * pdsds;
535 TRACE("(%p,%p)\n",pds,ppds);
537 if (ppds == NULL) {
538 ERR("invalid parameter: ppds == NULL\n");
539 return DSERR_INVALIDPARAM;
542 if (pds == NULL) {
543 ERR("invalid parameter: pds == NULL\n");
544 *ppds = NULL;
545 return DSERR_INVALIDPARAM;
548 pdsds = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsds));
549 if (pdsds == NULL) {
550 WARN("out of memory\n");
551 *ppds = NULL;
552 return DSERR_OUTOFMEMORY;
555 pdsds->lpVtbl = &ds8_vtbl;
556 pdsds->ref = 0;
557 pdsds->pds = pds;
559 InterlockedIncrement(&((IDirectSoundImpl *)pds)->numIfaces);
560 *ppds = (LPDIRECTSOUND8)pdsds;
562 return DS_OK;
565 static HRESULT IDirectSoundImpl_Create(REFIID riid, void **ppv, BOOL has_ds8)
567 IDirectSoundImpl *obj;
568 HRESULT hr;
570 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
572 *ppv = NULL;
573 obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*obj));
574 if (!obj) {
575 WARN("out of memory\n");
576 return DSERR_OUTOFMEMORY;
579 setup_dsound_options();
581 obj->IUnknown_iface.lpVtbl = &unk_vtbl;
582 obj->ref = 1;
583 obj->numIfaces = 1;
584 obj->device = NULL;
585 obj->has_ds8 = has_ds8;
587 hr = IUnknown_QueryInterface(&obj->IUnknown_iface, riid, ppv);
588 IUnknown_Release(&obj->IUnknown_iface);
590 return hr;
593 HRESULT DSOUND_Create(REFIID riid, void **ppv)
595 return IDirectSoundImpl_Create(riid, ppv, FALSE);
598 HRESULT DSOUND_Create8(REFIID riid, void **ppv)
600 return IDirectSoundImpl_Create(riid, ppv, TRUE);
603 /*******************************************************************************
604 * DirectSoundCreate (DSOUND.1)
606 * Creates and initializes a DirectSound interface.
608 * PARAMS
609 * lpcGUID [I] Address of the GUID that identifies the sound device.
610 * ppDS [O] Address of a variable to receive the interface pointer.
611 * pUnkOuter [I] Must be NULL.
613 * RETURNS
614 * Success: DS_OK
615 * Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
616 * DSERR_NODRIVER, DSERR_OUTOFMEMORY
618 HRESULT WINAPI DirectSoundCreate(
619 LPCGUID lpcGUID,
620 LPDIRECTSOUND *ppDS,
621 IUnknown *pUnkOuter)
623 HRESULT hr;
624 LPDIRECTSOUND pDS;
626 TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
628 if (ppDS == NULL) {
629 WARN("invalid parameter: ppDS == NULL\n");
630 return DSERR_INVALIDPARAM;
633 if (pUnkOuter != NULL) {
634 WARN("invalid parameter: pUnkOuter != NULL\n");
635 *ppDS = 0;
636 return DSERR_INVALIDPARAM;
639 hr = DSOUND_Create(&IID_IDirectSound, (void **)&pDS);
640 if (hr == DS_OK) {
641 hr = IDirectSound_Initialize(pDS, lpcGUID);
642 if (hr != DS_OK) {
643 if (hr != DSERR_ALREADYINITIALIZED) {
644 IDirectSound_Release(pDS);
645 pDS = 0;
646 } else
647 hr = DS_OK;
651 *ppDS = pDS;
653 return hr;
656 /*******************************************************************************
657 * DirectSoundCreate8 (DSOUND.11)
659 * Creates and initializes a DirectSound8 interface.
661 * PARAMS
662 * lpcGUID [I] Address of the GUID that identifies the sound device.
663 * ppDS [O] Address of a variable to receive the interface pointer.
664 * pUnkOuter [I] Must be NULL.
666 * RETURNS
667 * Success: DS_OK
668 * Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
669 * DSERR_NODRIVER, DSERR_OUTOFMEMORY
671 HRESULT WINAPI DirectSoundCreate8(
672 LPCGUID lpcGUID,
673 LPDIRECTSOUND8 *ppDS,
674 IUnknown *pUnkOuter)
676 HRESULT hr;
677 LPDIRECTSOUND8 pDS;
679 TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
681 if (ppDS == NULL) {
682 WARN("invalid parameter: ppDS == NULL\n");
683 return DSERR_INVALIDPARAM;
686 if (pUnkOuter != NULL) {
687 WARN("invalid parameter: pUnkOuter != NULL\n");
688 *ppDS = 0;
689 return DSERR_INVALIDPARAM;
692 hr = DSOUND_Create8(&IID_IDirectSound8, (void **)&pDS);
693 if (hr == DS_OK) {
694 hr = IDirectSound8_Initialize(pDS, lpcGUID);
695 if (hr != DS_OK) {
696 if (hr != DSERR_ALREADYINITIALIZED) {
697 IDirectSound8_Release(pDS);
698 pDS = 0;
699 } else
700 hr = DS_OK;
704 *ppDS = pDS;
706 return hr;
709 /*******************************************************************************
710 * DirectSoundDevice
712 static HRESULT DirectSoundDevice_Create(DirectSoundDevice ** ppDevice)
714 DirectSoundDevice * device;
715 TRACE("(%p)\n", ppDevice);
717 /* Allocate memory */
718 device = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DirectSoundDevice));
719 if (device == NULL) {
720 WARN("out of memory\n");
721 return DSERR_OUTOFMEMORY;
724 device->ref = 1;
725 device->priolevel = DSSCL_NORMAL;
726 device->state = STATE_STOPPED;
727 device->speaker_config = DSSPEAKER_COMBINED(DSSPEAKER_STEREO, DSSPEAKER_GEOMETRY_WIDE);
729 /* 3D listener initial parameters */
730 device->ds3dl.dwSize = sizeof(DS3DLISTENER);
731 device->ds3dl.vPosition.x = 0.0;
732 device->ds3dl.vPosition.y = 0.0;
733 device->ds3dl.vPosition.z = 0.0;
734 device->ds3dl.vVelocity.x = 0.0;
735 device->ds3dl.vVelocity.y = 0.0;
736 device->ds3dl.vVelocity.z = 0.0;
737 device->ds3dl.vOrientFront.x = 0.0;
738 device->ds3dl.vOrientFront.y = 0.0;
739 device->ds3dl.vOrientFront.z = 1.0;
740 device->ds3dl.vOrientTop.x = 0.0;
741 device->ds3dl.vOrientTop.y = 1.0;
742 device->ds3dl.vOrientTop.z = 0.0;
743 device->ds3dl.flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
744 device->ds3dl.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
745 device->ds3dl.flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
747 device->prebuf = ds_snd_queue_max;
748 device->guid = GUID_NULL;
750 /* Set default wave format (may need it for waveOutOpen) */
751 device->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(WAVEFORMATEX));
752 if (device->pwfx == NULL) {
753 WARN("out of memory\n");
754 HeapFree(GetProcessHeap(),0,device);
755 return DSERR_OUTOFMEMORY;
758 device->pwfx->wFormatTag = WAVE_FORMAT_PCM;
759 device->pwfx->nSamplesPerSec = ds_default_sample_rate;
760 device->pwfx->wBitsPerSample = ds_default_bits_per_sample;
761 device->pwfx->nChannels = 2;
762 device->pwfx->nBlockAlign = device->pwfx->wBitsPerSample * device->pwfx->nChannels / 8;
763 device->pwfx->nAvgBytesPerSec = device->pwfx->nSamplesPerSec * device->pwfx->nBlockAlign;
764 device->pwfx->cbSize = 0;
766 InitializeCriticalSection(&(device->mixlock));
767 device->mixlock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DirectSoundDevice.mixlock");
769 RtlInitializeResource(&(device->buffer_list_lock));
771 *ppDevice = device;
773 return DS_OK;
776 static ULONG DirectSoundDevice_AddRef(DirectSoundDevice * device)
778 ULONG ref = InterlockedIncrement(&(device->ref));
779 TRACE("(%p) ref was %d\n", device, ref - 1);
780 return ref;
783 ULONG DirectSoundDevice_Release(DirectSoundDevice * device)
785 HRESULT hr;
786 ULONG ref = InterlockedDecrement(&(device->ref));
787 TRACE("(%p) ref was %u\n", device, ref + 1);
788 if (!ref) {
789 int i;
790 timeKillEvent(device->timerID);
791 timeEndPeriod(DS_TIME_RES);
793 /* The kill event should have allowed the timer process to expire
794 * but try to grab the lock just in case. Can't hold lock because
795 * secondarybuffer_destroy also grabs the lock */
796 RtlAcquireResourceShared(&(device->buffer_list_lock), TRUE);
797 RtlReleaseResource(&(device->buffer_list_lock));
799 EnterCriticalSection(&DSOUND_renderers_lock);
800 list_remove(&device->entry);
801 LeaveCriticalSection(&DSOUND_renderers_lock);
803 /* It is allowed to release this object even when buffers are playing */
804 if (device->buffers) {
805 WARN("%d secondary buffers not released\n", device->nrofbuffers);
806 for( i=0;i<device->nrofbuffers;i++)
807 secondarybuffer_destroy(device->buffers[i]);
810 hr = DSOUND_PrimaryDestroy(device);
811 if (hr != DS_OK)
812 WARN("DSOUND_PrimaryDestroy failed\n");
814 if(device->client)
815 IAudioClient_Release(device->client);
816 if(device->render)
817 IAudioRenderClient_Release(device->render);
818 if(device->clock)
819 IAudioClock_Release(device->clock);
820 if(device->volume)
821 IAudioStreamVolume_Release(device->volume);
823 HeapFree(GetProcessHeap(), 0, device->tmp_buffer);
824 HeapFree(GetProcessHeap(), 0, device->mix_buffer);
825 HeapFree(GetProcessHeap(), 0, device->buffer);
826 RtlDeleteResource(&device->buffer_list_lock);
827 device->mixlock.DebugInfo->Spare[0] = 0;
828 DeleteCriticalSection(&device->mixlock);
829 HeapFree(GetProcessHeap(),0,device);
830 TRACE("(%p) released\n", device);
832 return ref;
835 HRESULT DirectSoundDevice_GetCaps(
836 DirectSoundDevice * device,
837 LPDSCAPS lpDSCaps)
839 TRACE("(%p,%p)\n",device,lpDSCaps);
841 if (device == NULL) {
842 WARN("not initialized\n");
843 return DSERR_UNINITIALIZED;
846 if (lpDSCaps == NULL) {
847 WARN("invalid parameter: lpDSCaps = NULL\n");
848 return DSERR_INVALIDPARAM;
851 /* check if there is enough room */
852 if (lpDSCaps->dwSize < sizeof(*lpDSCaps)) {
853 WARN("invalid parameter: lpDSCaps->dwSize = %d\n", lpDSCaps->dwSize);
854 return DSERR_INVALIDPARAM;
857 lpDSCaps->dwFlags = device->drvcaps.dwFlags;
858 if (TRACE_ON(dsound)) {
859 TRACE("(flags=0x%08x:\n",lpDSCaps->dwFlags);
860 _dump_DSCAPS(lpDSCaps->dwFlags);
861 TRACE(")\n");
863 lpDSCaps->dwMinSecondarySampleRate = device->drvcaps.dwMinSecondarySampleRate;
864 lpDSCaps->dwMaxSecondarySampleRate = device->drvcaps.dwMaxSecondarySampleRate;
865 lpDSCaps->dwPrimaryBuffers = device->drvcaps.dwPrimaryBuffers;
866 lpDSCaps->dwMaxHwMixingAllBuffers = device->drvcaps.dwMaxHwMixingAllBuffers;
867 lpDSCaps->dwMaxHwMixingStaticBuffers = device->drvcaps.dwMaxHwMixingStaticBuffers;
868 lpDSCaps->dwMaxHwMixingStreamingBuffers = device->drvcaps.dwMaxHwMixingStreamingBuffers;
869 lpDSCaps->dwFreeHwMixingAllBuffers = device->drvcaps.dwFreeHwMixingAllBuffers;
870 lpDSCaps->dwFreeHwMixingStaticBuffers = device->drvcaps.dwFreeHwMixingStaticBuffers;
871 lpDSCaps->dwFreeHwMixingStreamingBuffers = device->drvcaps.dwFreeHwMixingStreamingBuffers;
872 lpDSCaps->dwMaxHw3DAllBuffers = device->drvcaps.dwMaxHw3DAllBuffers;
873 lpDSCaps->dwMaxHw3DStaticBuffers = device->drvcaps.dwMaxHw3DStaticBuffers;
874 lpDSCaps->dwMaxHw3DStreamingBuffers = device->drvcaps.dwMaxHw3DStreamingBuffers;
875 lpDSCaps->dwFreeHw3DAllBuffers = device->drvcaps.dwFreeHw3DAllBuffers;
876 lpDSCaps->dwFreeHw3DStaticBuffers = device->drvcaps.dwFreeHw3DStaticBuffers;
877 lpDSCaps->dwFreeHw3DStreamingBuffers = device->drvcaps.dwFreeHw3DStreamingBuffers;
878 lpDSCaps->dwTotalHwMemBytes = device->drvcaps.dwTotalHwMemBytes;
879 lpDSCaps->dwFreeHwMemBytes = device->drvcaps.dwFreeHwMemBytes;
880 lpDSCaps->dwMaxContigFreeHwMemBytes = device->drvcaps.dwMaxContigFreeHwMemBytes;
881 lpDSCaps->dwUnlockTransferRateHwBuffers = device->drvcaps.dwUnlockTransferRateHwBuffers;
882 lpDSCaps->dwPlayCpuOverheadSwBuffers = device->drvcaps.dwPlayCpuOverheadSwBuffers;
884 return DS_OK;
887 BOOL DSOUND_check_supported(IAudioClient *client, DWORD rate,
888 DWORD depth, WORD channels)
890 WAVEFORMATEX fmt, *junk;
891 HRESULT hr;
893 fmt.wFormatTag = WAVE_FORMAT_PCM;
894 fmt.nChannels = channels;
895 fmt.nSamplesPerSec = rate;
896 fmt.wBitsPerSample = depth;
897 fmt.nBlockAlign = (channels * depth) / 8;
898 fmt.nAvgBytesPerSec = rate * fmt.nBlockAlign;
899 fmt.cbSize = 0;
901 hr = IAudioClient_IsFormatSupported(client, AUDCLNT_SHAREMODE_SHARED, &fmt, &junk);
902 if(SUCCEEDED(hr))
903 CoTaskMemFree(junk);
905 return hr == S_OK;
908 UINT DSOUND_create_timer(LPTIMECALLBACK cb, DWORD_PTR user)
910 UINT triggertime = DS_TIME_DEL, res = DS_TIME_RES, id;
911 TIMECAPS time;
913 timeGetDevCaps(&time, sizeof(TIMECAPS));
914 TRACE("Minimum timer resolution: %u, max timer: %u\n", time.wPeriodMin, time.wPeriodMax);
915 if (triggertime < time.wPeriodMin)
916 triggertime = time.wPeriodMin;
917 if (res < time.wPeriodMin)
918 res = time.wPeriodMin;
919 if (timeBeginPeriod(res) == TIMERR_NOCANDO)
920 WARN("Could not set minimum resolution, don't expect sound\n");
921 id = timeSetEvent(triggertime, res, cb, user, TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
922 if (!id)
924 WARN("Timer not created! Retrying without TIME_KILL_SYNCHRONOUS\n");
925 id = timeSetEvent(triggertime, res, cb, user, TIME_PERIODIC);
926 if (!id)
927 ERR("Could not create timer, sound playback will not occur\n");
929 return id;
932 HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcGUID)
934 HRESULT hr = DS_OK;
935 GUID devGUID;
936 DirectSoundDevice *device;
937 IMMDevice *mmdevice;
939 TRACE("(%p,%s)\n",ppDevice,debugstr_guid(lpcGUID));
941 if (*ppDevice != NULL) {
942 WARN("already initialized\n");
943 return DSERR_ALREADYINITIALIZED;
946 /* Default device? */
947 if (!lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL))
948 lpcGUID = &DSDEVID_DefaultPlayback;
950 if(IsEqualGUID(lpcGUID, &DSDEVID_DefaultCapture) ||
951 IsEqualGUID(lpcGUID, &DSDEVID_DefaultVoiceCapture))
952 return DSERR_NODRIVER;
954 if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
955 WARN("invalid parameter: lpcGUID\n");
956 return DSERR_INVALIDPARAM;
959 hr = get_mmdevice(eRender, &devGUID, &mmdevice);
960 if(FAILED(hr))
961 return hr;
963 EnterCriticalSection(&DSOUND_renderers_lock);
965 LIST_FOR_EACH_ENTRY(device, &DSOUND_renderers, DirectSoundDevice, entry){
966 if(IsEqualGUID(&device->guid, &devGUID)){
967 IMMDevice_Release(mmdevice);
968 DirectSoundDevice_AddRef(device);
969 *ppDevice = device;
970 LeaveCriticalSection(&DSOUND_renderers_lock);
971 return DS_OK;
975 hr = DirectSoundDevice_Create(&device);
976 if(FAILED(hr)){
977 WARN("DirectSoundDevice_Create failed\n");
978 IMMDevice_Release(mmdevice);
979 LeaveCriticalSection(&DSOUND_renderers_lock);
980 return hr;
983 device->mmdevice = mmdevice;
984 device->guid = devGUID;
986 hr = DSOUND_ReopenDevice(device, FALSE);
987 if (FAILED(hr))
989 HeapFree(GetProcessHeap(), 0, device);
990 LeaveCriticalSection(&DSOUND_renderers_lock);
991 IMMDevice_Release(mmdevice);
992 WARN("DSOUND_ReopenDevice failed: %08x\n", hr);
993 return hr;
996 ZeroMemory(&device->drvcaps, sizeof(device->drvcaps));
998 if(DSOUND_check_supported(device->client, 11025, 8, 1) ||
999 DSOUND_check_supported(device->client, 22050, 8, 1) ||
1000 DSOUND_check_supported(device->client, 44100, 8, 1) ||
1001 DSOUND_check_supported(device->client, 48000, 8, 1) ||
1002 DSOUND_check_supported(device->client, 96000, 8, 1))
1003 device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT | DSCAPS_PRIMARYMONO;
1005 if(DSOUND_check_supported(device->client, 11025, 16, 1) ||
1006 DSOUND_check_supported(device->client, 22050, 16, 1) ||
1007 DSOUND_check_supported(device->client, 44100, 16, 1) ||
1008 DSOUND_check_supported(device->client, 48000, 16, 1) ||
1009 DSOUND_check_supported(device->client, 96000, 16, 1))
1010 device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT | DSCAPS_PRIMARYMONO;
1012 if(DSOUND_check_supported(device->client, 11025, 8, 2) ||
1013 DSOUND_check_supported(device->client, 22050, 8, 2) ||
1014 DSOUND_check_supported(device->client, 44100, 8, 2) ||
1015 DSOUND_check_supported(device->client, 48000, 8, 2) ||
1016 DSOUND_check_supported(device->client, 96000, 8, 2))
1017 device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT | DSCAPS_PRIMARYSTEREO;
1019 if(DSOUND_check_supported(device->client, 11025, 16, 2) ||
1020 DSOUND_check_supported(device->client, 22050, 16, 2) ||
1021 DSOUND_check_supported(device->client, 44100, 16, 2) ||
1022 DSOUND_check_supported(device->client, 48000, 16, 2) ||
1023 DSOUND_check_supported(device->client, 96000, 16, 2))
1024 device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT | DSCAPS_PRIMARYSTEREO;
1026 /* the dsound mixer supports all of the following */
1027 device->drvcaps.dwFlags |= DSCAPS_SECONDARY8BIT | DSCAPS_SECONDARY16BIT;
1028 device->drvcaps.dwFlags |= DSCAPS_SECONDARYMONO | DSCAPS_SECONDARYSTEREO;
1029 device->drvcaps.dwFlags |= DSCAPS_CONTINUOUSRATE;
1031 device->drvcaps.dwPrimaryBuffers = 1;
1032 device->drvcaps.dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
1033 device->drvcaps.dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
1034 device->drvcaps.dwMaxHwMixingAllBuffers = 1;
1035 device->drvcaps.dwMaxHwMixingStaticBuffers = 1;
1036 device->drvcaps.dwMaxHwMixingStreamingBuffers = 1;
1038 ZeroMemory(&device->volpan, sizeof(device->volpan));
1040 hr = DSOUND_PrimaryCreate(device);
1041 if (hr == DS_OK)
1042 device->timerID = DSOUND_create_timer(DSOUND_timer, (DWORD_PTR)device);
1043 else
1044 WARN("DSOUND_PrimaryCreate failed: %08x\n", hr);
1046 *ppDevice = device;
1047 list_add_tail(&DSOUND_renderers, &device->entry);
1049 LeaveCriticalSection(&DSOUND_renderers_lock);
1051 return hr;
1054 HRESULT DirectSoundDevice_CreateSoundBuffer(
1055 DirectSoundDevice * device,
1056 LPCDSBUFFERDESC dsbd,
1057 LPLPDIRECTSOUNDBUFFER ppdsb,
1058 LPUNKNOWN lpunk,
1059 BOOL from8)
1061 HRESULT hres = DS_OK;
1062 TRACE("(%p,%p,%p,%p)\n",device,dsbd,ppdsb,lpunk);
1064 if (device == NULL) {
1065 WARN("not initialized\n");
1066 return DSERR_UNINITIALIZED;
1069 if (dsbd == NULL) {
1070 WARN("invalid parameter: dsbd == NULL\n");
1071 return DSERR_INVALIDPARAM;
1074 if (dsbd->dwSize != sizeof(DSBUFFERDESC) &&
1075 dsbd->dwSize != sizeof(DSBUFFERDESC1)) {
1076 WARN("invalid parameter: dsbd\n");
1077 return DSERR_INVALIDPARAM;
1080 if (ppdsb == NULL) {
1081 WARN("invalid parameter: ppdsb == NULL\n");
1082 return DSERR_INVALIDPARAM;
1084 *ppdsb = NULL;
1086 if (TRACE_ON(dsound)) {
1087 TRACE("(structsize=%d)\n",dsbd->dwSize);
1088 TRACE("(flags=0x%08x:\n",dsbd->dwFlags);
1089 _dump_DSBCAPS(dsbd->dwFlags);
1090 TRACE(")\n");
1091 TRACE("(bufferbytes=%d)\n",dsbd->dwBufferBytes);
1092 TRACE("(lpwfxFormat=%p)\n",dsbd->lpwfxFormat);
1095 if (dsbd->dwFlags & DSBCAPS_LOCHARDWARE &&
1096 !(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
1097 TRACE("LOCHARDWARE is not supported, returning E_NOTIMPL\n");
1098 return E_NOTIMPL;
1101 if (dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) {
1102 if (dsbd->lpwfxFormat != NULL) {
1103 WARN("invalid parameter: dsbd->lpwfxFormat must be NULL for "
1104 "primary buffer\n");
1105 return DSERR_INVALIDPARAM;
1108 if (device->primary) {
1109 WARN("Primary Buffer already created\n");
1110 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(device->primary));
1111 *ppdsb = (LPDIRECTSOUNDBUFFER)(device->primary);
1112 } else {
1113 hres = primarybuffer_create(device, &device->primary, dsbd);
1114 if (device->primary) {
1115 *ppdsb = (IDirectSoundBuffer*)&device->primary->IDirectSoundBuffer8_iface;
1116 device->primary->dsbd.dwFlags &= ~(DSBCAPS_LOCHARDWARE | DSBCAPS_LOCSOFTWARE);
1117 device->primary->dsbd.dwFlags |= DSBCAPS_LOCSOFTWARE;
1118 } else
1119 WARN("primarybuffer_create() failed\n");
1121 } else {
1122 IDirectSoundBufferImpl * dsb;
1123 WAVEFORMATEXTENSIBLE *pwfxe;
1125 if (dsbd->lpwfxFormat == NULL) {
1126 WARN("invalid parameter: dsbd->lpwfxFormat can't be NULL for "
1127 "secondary buffer\n");
1128 return DSERR_INVALIDPARAM;
1130 pwfxe = (WAVEFORMATEXTENSIBLE*)dsbd->lpwfxFormat;
1132 if (pwfxe->Format.wBitsPerSample != 16 && pwfxe->Format.wBitsPerSample != 8 && pwfxe->Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE)
1134 WARN("wBitsPerSample=%d needs a WAVEFORMATEXTENSIBLE\n", dsbd->lpwfxFormat->wBitsPerSample);
1135 return DSERR_CONTROLUNAVAIL;
1137 if (pwfxe->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE)
1139 /* check if cbSize is at least 22 bytes */
1140 if (pwfxe->Format.cbSize < (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)))
1142 WARN("Too small a cbSize %u\n", pwfxe->Format.cbSize);
1143 return DSERR_INVALIDPARAM;
1146 /* cbSize should be 22 bytes, with one possible exception */
1147 if (pwfxe->Format.cbSize > (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)) &&
1148 !((IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) || IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) &&
1149 pwfxe->Format.cbSize == sizeof(WAVEFORMATEXTENSIBLE)))
1151 WARN("Too big a cbSize %u\n", pwfxe->Format.cbSize);
1152 return DSERR_CONTROLUNAVAIL;
1155 if ((!IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) && (!IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)))
1157 if (!IsEqualGUID(&pwfxe->SubFormat, &GUID_NULL))
1158 FIXME("SubFormat %s not supported right now.\n", debugstr_guid(&pwfxe->SubFormat));
1159 return DSERR_INVALIDPARAM;
1161 if (pwfxe->Samples.wValidBitsPerSample > dsbd->lpwfxFormat->wBitsPerSample)
1163 WARN("Samples.wValidBitsPerSample(%d) > Format.wBitsPerSample (%d)\n", pwfxe->Samples.wValidBitsPerSample, pwfxe->Format.wBitsPerSample);
1164 return DSERR_INVALIDPARAM;
1166 if (pwfxe->Samples.wValidBitsPerSample && pwfxe->Samples.wValidBitsPerSample < dsbd->lpwfxFormat->wBitsPerSample)
1168 FIXME("Non-packed formats not supported right now: %d/%d\n", pwfxe->Samples.wValidBitsPerSample, dsbd->lpwfxFormat->wBitsPerSample);
1169 return DSERR_CONTROLUNAVAIL;
1173 TRACE("(formattag=0x%04x,chans=%d,samplerate=%d,"
1174 "bytespersec=%d,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
1175 dsbd->lpwfxFormat->wFormatTag, dsbd->lpwfxFormat->nChannels,
1176 dsbd->lpwfxFormat->nSamplesPerSec,
1177 dsbd->lpwfxFormat->nAvgBytesPerSec,
1178 dsbd->lpwfxFormat->nBlockAlign,
1179 dsbd->lpwfxFormat->wBitsPerSample, dsbd->lpwfxFormat->cbSize);
1181 if (from8 && (dsbd->dwFlags & DSBCAPS_CTRL3D) && (dsbd->lpwfxFormat->nChannels != 1)) {
1182 WARN("invalid parameter: 3D buffer format must be mono\n");
1183 return DSERR_INVALIDPARAM;
1186 hres = IDirectSoundBufferImpl_Create(device, &dsb, dsbd);
1187 if (dsb)
1188 *ppdsb = (IDirectSoundBuffer*)&dsb->IDirectSoundBuffer8_iface;
1189 else
1190 WARN("IDirectSoundBufferImpl_Create failed\n");
1193 return hres;
1196 HRESULT DirectSoundDevice_DuplicateSoundBuffer(
1197 DirectSoundDevice * device,
1198 LPDIRECTSOUNDBUFFER psb,
1199 LPLPDIRECTSOUNDBUFFER ppdsb)
1201 HRESULT hres = DS_OK;
1202 IDirectSoundBufferImpl* dsb;
1203 TRACE("(%p,%p,%p)\n",device,psb,ppdsb);
1205 if (device == NULL) {
1206 WARN("not initialized\n");
1207 return DSERR_UNINITIALIZED;
1210 if (psb == NULL) {
1211 WARN("invalid parameter: psb == NULL\n");
1212 return DSERR_INVALIDPARAM;
1215 if (ppdsb == NULL) {
1216 WARN("invalid parameter: ppdsb == NULL\n");
1217 return DSERR_INVALIDPARAM;
1220 /* make sure we have a secondary buffer */
1221 if (psb == (IDirectSoundBuffer *)&device->primary->IDirectSoundBuffer8_iface) {
1222 WARN("trying to duplicate primary buffer\n");
1223 *ppdsb = NULL;
1224 return DSERR_INVALIDCALL;
1227 /* duplicate the actual buffer implementation */
1228 hres = IDirectSoundBufferImpl_Duplicate(device, &dsb, (IDirectSoundBufferImpl*)psb);
1229 if (hres == DS_OK)
1230 *ppdsb = (IDirectSoundBuffer*)&dsb->IDirectSoundBuffer8_iface;
1231 else
1232 WARN("IDirectSoundBufferImpl_Duplicate failed\n");
1234 return hres;
1237 HRESULT DirectSoundDevice_SetCooperativeLevel(
1238 DirectSoundDevice * device,
1239 HWND hwnd,
1240 DWORD level)
1242 TRACE("(%p,%p,%s)\n",device,hwnd,dumpCooperativeLevel(level));
1244 if (device == NULL) {
1245 WARN("not initialized\n");
1246 return DSERR_UNINITIALIZED;
1249 if (level==DSSCL_PRIORITY || level==DSSCL_EXCLUSIVE) {
1250 WARN("level=%s not fully supported\n",
1251 level==DSSCL_PRIORITY ? "DSSCL_PRIORITY" : "DSSCL_EXCLUSIVE");
1254 device->priolevel = level;
1255 return DS_OK;
1258 HRESULT DirectSoundDevice_Compact(
1259 DirectSoundDevice * device)
1261 TRACE("(%p)\n", device);
1263 if (device == NULL) {
1264 WARN("not initialized\n");
1265 return DSERR_UNINITIALIZED;
1268 if (device->priolevel < DSSCL_PRIORITY) {
1269 WARN("incorrect priority level\n");
1270 return DSERR_PRIOLEVELNEEDED;
1273 return DS_OK;
1276 HRESULT DirectSoundDevice_GetSpeakerConfig(
1277 DirectSoundDevice * device,
1278 LPDWORD lpdwSpeakerConfig)
1280 TRACE("(%p, %p)\n", device, lpdwSpeakerConfig);
1282 if (device == NULL) {
1283 WARN("not initialized\n");
1284 return DSERR_UNINITIALIZED;
1287 if (lpdwSpeakerConfig == NULL) {
1288 WARN("invalid parameter: lpdwSpeakerConfig == NULL\n");
1289 return DSERR_INVALIDPARAM;
1292 WARN("not fully functional\n");
1293 *lpdwSpeakerConfig = device->speaker_config;
1294 return DS_OK;
1297 HRESULT DirectSoundDevice_SetSpeakerConfig(
1298 DirectSoundDevice * device,
1299 DWORD config)
1301 TRACE("(%p,0x%08x)\n",device,config);
1303 if (device == NULL) {
1304 WARN("not initialized\n");
1305 return DSERR_UNINITIALIZED;
1308 device->speaker_config = config;
1309 WARN("not fully functional\n");
1310 return DS_OK;
1313 HRESULT DirectSoundDevice_VerifyCertification(
1314 DirectSoundDevice * device,
1315 LPDWORD pdwCertified)
1317 TRACE("(%p, %p)\n",device,pdwCertified);
1319 if (device == NULL) {
1320 WARN("not initialized\n");
1321 return DSERR_UNINITIALIZED;
1324 if (device->drvcaps.dwFlags & DSCAPS_CERTIFIED)
1325 *pdwCertified = DS_CERTIFIED;
1326 else
1327 *pdwCertified = DS_UNCERTIFIED;
1329 return DS_OK;
1333 * Add secondary buffer to buffer list.
1334 * Gets exclusive access to buffer for writing.
1336 HRESULT DirectSoundDevice_AddBuffer(
1337 DirectSoundDevice * device,
1338 IDirectSoundBufferImpl * pDSB)
1340 IDirectSoundBufferImpl **newbuffers;
1341 HRESULT hr = DS_OK;
1343 TRACE("(%p, %p)\n", device, pDSB);
1345 RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
1347 if (device->buffers)
1348 newbuffers = HeapReAlloc(GetProcessHeap(),0,device->buffers,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
1349 else
1350 newbuffers = HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
1352 if (newbuffers) {
1353 device->buffers = newbuffers;
1354 device->buffers[device->nrofbuffers] = pDSB;
1355 device->nrofbuffers++;
1356 TRACE("buffer count is now %d\n", device->nrofbuffers);
1357 } else {
1358 ERR("out of memory for buffer list! Current buffer count is %d\n", device->nrofbuffers);
1359 hr = DSERR_OUTOFMEMORY;
1362 RtlReleaseResource(&(device->buffer_list_lock));
1364 return hr;
1368 * Remove secondary buffer from buffer list.
1369 * Gets exclusive access to buffer for writing.
1371 HRESULT DirectSoundDevice_RemoveBuffer(
1372 DirectSoundDevice * device,
1373 IDirectSoundBufferImpl * pDSB)
1375 int i;
1376 HRESULT hr = DS_OK;
1378 TRACE("(%p, %p)\n", device, pDSB);
1380 RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
1382 for (i = 0; i < device->nrofbuffers; i++)
1383 if (device->buffers[i] == pDSB)
1384 break;
1386 if (i < device->nrofbuffers) {
1387 /* Put the last buffer of the list in the (now empty) position */
1388 device->buffers[i] = device->buffers[device->nrofbuffers - 1];
1389 device->nrofbuffers--;
1390 device->buffers = HeapReAlloc(GetProcessHeap(),0,device->buffers,sizeof(LPDIRECTSOUNDBUFFER8)*device->nrofbuffers);
1391 TRACE("buffer count is now %d\n", device->nrofbuffers);
1394 if (device->nrofbuffers == 0) {
1395 HeapFree(GetProcessHeap(),0,device->buffers);
1396 device->buffers = NULL;
1399 RtlReleaseResource(&(device->buffer_list_lock));
1401 return hr;