dsound: Merge IDirectSound8 into the main DirectSound object.
[wine/multimedia.git] / dlls / dsound / dsound.c
blob9ef4bcae166ff08f452f4b5401c2f5d7c0f5a899
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 typedef struct IDirectSoundImpl {
56 IUnknown IUnknown_iface; /* Separate refcount, not for COM aggregation */
57 IDirectSound8 IDirectSound8_iface;
58 LONG ref, refds, numIfaces;
59 DirectSoundDevice *device;
60 BOOL has_ds8;
61 LPDIRECTSOUND pDS;
62 } IDirectSoundImpl;
64 static ULONG WINAPI IDirectSound_IDirectSound_AddRef(LPDIRECTSOUND iface);
66 const char * dumpCooperativeLevel(DWORD level)
68 #define LE(x) case x: return #x
69 switch (level) {
70 LE(DSSCL_NORMAL);
71 LE(DSSCL_PRIORITY);
72 LE(DSSCL_EXCLUSIVE);
73 LE(DSSCL_WRITEPRIMARY);
75 #undef LE
76 return wine_dbg_sprintf("Unknown(%08x)", level);
79 static void _dump_DSCAPS(DWORD xmask) {
80 struct {
81 DWORD mask;
82 const char *name;
83 } flags[] = {
84 #define FE(x) { x, #x },
85 FE(DSCAPS_PRIMARYMONO)
86 FE(DSCAPS_PRIMARYSTEREO)
87 FE(DSCAPS_PRIMARY8BIT)
88 FE(DSCAPS_PRIMARY16BIT)
89 FE(DSCAPS_CONTINUOUSRATE)
90 FE(DSCAPS_EMULDRIVER)
91 FE(DSCAPS_CERTIFIED)
92 FE(DSCAPS_SECONDARYMONO)
93 FE(DSCAPS_SECONDARYSTEREO)
94 FE(DSCAPS_SECONDARY8BIT)
95 FE(DSCAPS_SECONDARY16BIT)
96 #undef FE
98 unsigned int i;
100 for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
101 if ((flags[i].mask & xmask) == flags[i].mask)
102 TRACE("%s ",flags[i].name);
105 static void _dump_DSBCAPS(DWORD xmask) {
106 struct {
107 DWORD mask;
108 const char *name;
109 } flags[] = {
110 #define FE(x) { x, #x },
111 FE(DSBCAPS_PRIMARYBUFFER)
112 FE(DSBCAPS_STATIC)
113 FE(DSBCAPS_LOCHARDWARE)
114 FE(DSBCAPS_LOCSOFTWARE)
115 FE(DSBCAPS_CTRL3D)
116 FE(DSBCAPS_CTRLFREQUENCY)
117 FE(DSBCAPS_CTRLPAN)
118 FE(DSBCAPS_CTRLVOLUME)
119 FE(DSBCAPS_CTRLPOSITIONNOTIFY)
120 FE(DSBCAPS_STICKYFOCUS)
121 FE(DSBCAPS_GLOBALFOCUS)
122 FE(DSBCAPS_GETCURRENTPOSITION2)
123 FE(DSBCAPS_MUTE3DATMAXDISTANCE)
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 /*******************************************************************************
134 * IDirectSoundImpl_DirectSound
136 static HRESULT DSOUND_QueryInterface(
137 LPDIRECTSOUND8 iface,
138 REFIID riid,
139 LPVOID * ppobj)
141 IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
142 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
144 if (ppobj == NULL) {
145 WARN("invalid parameter\n");
146 return E_INVALIDARG;
149 if (IsEqualIID(riid, &IID_IUnknown)) {
150 IUnknown_AddRef(&This->IUnknown_iface);
151 *ppobj = &This->IUnknown_iface;
152 return S_OK;
153 } else if (IsEqualIID(riid, &IID_IDirectSound)) {
154 if (!This->pDS) {
155 IDirectSound_IDirectSound_Create(iface, &This->pDS);
156 if (!This->pDS) {
157 WARN("IDirectSound_IDirectSound_Create() failed\n");
158 *ppobj = NULL;
159 return E_NOINTERFACE;
162 IDirectSound_IDirectSound_AddRef(This->pDS);
163 *ppobj = This->pDS;
164 return S_OK;
165 } else if (This->has_ds8 && IsEqualIID(riid, &IID_IDirectSound8)) {
166 IDirectSound8_AddRef(&This->IDirectSound8_iface);
167 *ppobj = &This->IDirectSound8_iface;
168 return S_OK;
171 *ppobj = NULL;
172 WARN("Unknown IID %s\n",debugstr_guid(riid));
173 return E_NOINTERFACE;
176 static void directsound_destroy(IDirectSoundImpl *This)
178 if (This->device)
179 DirectSoundDevice_Release(This->device);
180 HeapFree(GetProcessHeap(),0,This);
181 TRACE("(%p) released\n", This);
184 /*******************************************************************************
185 * IUnknown Implementation for DirectSound
187 static inline IDirectSoundImpl *impl_from_IUnknown(IUnknown *iface)
189 return CONTAINING_RECORD(iface, IDirectSoundImpl, IUnknown_iface);
192 static HRESULT WINAPI IUnknownImpl_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
194 IDirectSoundImpl *This = impl_from_IUnknown(iface);
195 TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
196 return DSOUND_QueryInterface((IDirectSound8 *)This, riid, ppv);
199 static ULONG WINAPI IUnknownImpl_AddRef(IUnknown *iface)
201 IDirectSoundImpl *This = impl_from_IUnknown(iface);
202 ULONG ref = InterlockedIncrement(&This->ref);
204 TRACE("(%p) ref=%d\n", This, ref);
206 if(ref == 1)
207 InterlockedIncrement(&This->numIfaces);
209 return ref;
212 static ULONG WINAPI IUnknownImpl_Release(IUnknown *iface)
214 IDirectSoundImpl *This = impl_from_IUnknown(iface);
215 ULONG ref = InterlockedDecrement(&This->ref);
217 TRACE("(%p) ref=%d\n", This, ref);
219 if (!ref && !InterlockedDecrement(&This->numIfaces))
220 directsound_destroy(This);
222 return ref;
225 static const IUnknownVtbl unk_vtbl =
227 IUnknownImpl_QueryInterface,
228 IUnknownImpl_AddRef,
229 IUnknownImpl_Release
232 /*******************************************************************************
233 * IDirectSound_IDirectSound
235 static HRESULT WINAPI IDirectSound_IDirectSound_QueryInterface(
236 LPDIRECTSOUND iface,
237 REFIID riid,
238 LPVOID * ppobj)
240 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
241 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
242 return DSOUND_QueryInterface(This->pds, riid, ppobj);
245 static ULONG WINAPI IDirectSound_IDirectSound_AddRef(
246 LPDIRECTSOUND iface)
248 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
249 ULONG ref = InterlockedIncrement(&(This->ref));
250 TRACE("(%p) ref was %d\n", This, ref - 1);
251 return ref;
254 static ULONG WINAPI IDirectSound_IDirectSound_Release(
255 LPDIRECTSOUND iface)
257 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
258 ULONG ref = InterlockedDecrement(&(This->ref));
259 TRACE("(%p) ref was %d\n", This, ref + 1);
260 if (!ref && !InterlockedDecrement(&((IDirectSoundImpl *)This->pds)->numIfaces)) {
261 ((IDirectSoundImpl*)This->pds)->pDS = NULL;
262 directsound_destroy((IDirectSoundImpl*)This->pds);
263 HeapFree(GetProcessHeap(), 0, This);
264 TRACE("(%p) released\n", This);
266 return ref;
269 static HRESULT WINAPI IDirectSound_IDirectSound_CreateSoundBuffer(
270 LPDIRECTSOUND iface,
271 LPCDSBUFFERDESC dsbd,
272 LPLPDIRECTSOUNDBUFFER ppdsb,
273 LPUNKNOWN lpunk)
275 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
276 TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
277 return DirectSoundDevice_CreateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,dsbd,ppdsb,lpunk,((IDirectSoundImpl *)This->pds)->has_ds8);
280 static HRESULT WINAPI IDirectSound_IDirectSound_GetCaps(
281 LPDIRECTSOUND iface,
282 LPDSCAPS lpDSCaps)
284 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
285 TRACE("(%p,%p)\n",This,lpDSCaps);
286 return DirectSoundDevice_GetCaps(((IDirectSoundImpl *)This->pds)->device, lpDSCaps);
289 static HRESULT WINAPI IDirectSound_IDirectSound_DuplicateSoundBuffer(
290 LPDIRECTSOUND iface,
291 LPDIRECTSOUNDBUFFER psb,
292 LPLPDIRECTSOUNDBUFFER ppdsb)
294 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
295 TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
296 return DirectSoundDevice_DuplicateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,psb,ppdsb);
299 static HRESULT WINAPI IDirectSound_IDirectSound_SetCooperativeLevel(
300 LPDIRECTSOUND iface,
301 HWND hwnd,
302 DWORD level)
304 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
305 TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level));
306 return DirectSoundDevice_SetCooperativeLevel(((IDirectSoundImpl *)This->pds)->device, hwnd, level);
309 static HRESULT WINAPI IDirectSound_IDirectSound_Compact(
310 LPDIRECTSOUND iface)
312 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
313 TRACE("(%p)\n", This);
314 return DirectSoundDevice_Compact(((IDirectSoundImpl *)This->pds)->device);
317 static HRESULT WINAPI IDirectSound_IDirectSound_GetSpeakerConfig(
318 LPDIRECTSOUND iface,
319 LPDWORD lpdwSpeakerConfig)
321 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
322 TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
323 return DirectSoundDevice_GetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,lpdwSpeakerConfig);
326 static HRESULT WINAPI IDirectSound_IDirectSound_SetSpeakerConfig(
327 LPDIRECTSOUND iface,
328 DWORD config)
330 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
331 TRACE("(%p,0x%08x)\n",This,config);
332 return DirectSoundDevice_SetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,config);
335 static HRESULT WINAPI IDirectSound_IDirectSound_Initialize(
336 LPDIRECTSOUND iface,
337 LPCGUID lpcGuid)
339 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
340 TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
341 return DirectSoundDevice_Initialize(&((IDirectSoundImpl *)This->pds)->device,lpcGuid);
344 static const IDirectSoundVtbl DirectSound_DirectSound_Vtbl =
346 IDirectSound_IDirectSound_QueryInterface,
347 IDirectSound_IDirectSound_AddRef,
348 IDirectSound_IDirectSound_Release,
349 IDirectSound_IDirectSound_CreateSoundBuffer,
350 IDirectSound_IDirectSound_GetCaps,
351 IDirectSound_IDirectSound_DuplicateSoundBuffer,
352 IDirectSound_IDirectSound_SetCooperativeLevel,
353 IDirectSound_IDirectSound_Compact,
354 IDirectSound_IDirectSound_GetSpeakerConfig,
355 IDirectSound_IDirectSound_SetSpeakerConfig,
356 IDirectSound_IDirectSound_Initialize
359 static HRESULT IDirectSound_IDirectSound_Create(
360 LPDIRECTSOUND8 pds,
361 LPDIRECTSOUND * ppds)
363 IDirectSound_IDirectSound * pdsds;
364 TRACE("(%p,%p)\n",pds,ppds);
366 if (ppds == NULL) {
367 ERR("invalid parameter: ppds == NULL\n");
368 return DSERR_INVALIDPARAM;
371 if (pds == NULL) {
372 ERR("invalid parameter: pds == NULL\n");
373 *ppds = NULL;
374 return DSERR_INVALIDPARAM;
377 pdsds = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsds));
378 if (pdsds == NULL) {
379 WARN("out of memory\n");
380 *ppds = NULL;
381 return DSERR_OUTOFMEMORY;
384 pdsds->lpVtbl = &DirectSound_DirectSound_Vtbl;
385 pdsds->ref = 0;
386 pdsds->pds = pds;
388 InterlockedIncrement(&((IDirectSoundImpl *)pds)->numIfaces);
389 *ppds = (LPDIRECTSOUND)pdsds;
391 return DS_OK;
394 /*******************************************************************************
395 * IDirectSound8 Implementation
397 static inline IDirectSoundImpl *impl_from_IDirectSound8(IDirectSound8 *iface)
399 return CONTAINING_RECORD(iface, IDirectSoundImpl, IDirectSound8_iface);
402 static HRESULT WINAPI IDirectSound8Impl_QueryInterface(IDirectSound8 *iface, REFIID riid,
403 void **ppv)
405 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
406 TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
407 return IUnknown_QueryInterface(&This->IUnknown_iface, riid, ppv);
410 static ULONG WINAPI IDirectSound8Impl_AddRef(IDirectSound8 *iface)
412 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
413 ULONG ref = InterlockedIncrement(&This->refds);
415 TRACE("(%p) refds=%d\n", This, ref);
417 if(ref == 1)
418 InterlockedIncrement(&This->numIfaces);
420 return ref;
423 static ULONG WINAPI IDirectSound8Impl_Release(IDirectSound8 *iface)
425 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
426 ULONG ref = InterlockedDecrement(&(This->refds));
428 TRACE("(%p) refds=%d\n", This, ref);
430 if (!ref && !InterlockedDecrement(&This->numIfaces))
431 directsound_destroy(This);
433 return ref;
436 static HRESULT WINAPI IDirectSound8Impl_CreateSoundBuffer(IDirectSound8 *iface,
437 const DSBUFFERDESC *dsbd, IDirectSoundBuffer **ppdsb, IUnknown *lpunk)
439 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
440 TRACE("(%p,%p,%p,%p)\n", This, dsbd, ppdsb, lpunk);
441 return DirectSoundDevice_CreateSoundBuffer(This->device, dsbd, ppdsb, lpunk, TRUE);
444 static HRESULT WINAPI IDirectSound8Impl_GetCaps(IDirectSound8 *iface, DSCAPS *lpDSCaps)
446 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
447 TRACE("(%p,%p)\n", This, lpDSCaps);
448 return DirectSoundDevice_GetCaps(This->device, lpDSCaps);
451 static HRESULT WINAPI IDirectSound8Impl_DuplicateSoundBuffer(IDirectSound8 *iface,
452 IDirectSoundBuffer *psb, IDirectSoundBuffer **ppdsb)
454 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
455 TRACE("(%p,%p,%p)\n", This, psb, ppdsb);
456 return DirectSoundDevice_DuplicateSoundBuffer(This->device, psb, ppdsb);
459 static HRESULT WINAPI IDirectSound8Impl_SetCooperativeLevel(IDirectSound8 *iface, HWND hwnd,
460 DWORD level)
462 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
463 TRACE("(%p,%p,%s)\n", This, hwnd, dumpCooperativeLevel(level));
464 return DirectSoundDevice_SetCooperativeLevel(This->device, hwnd, level);
467 static HRESULT WINAPI IDirectSound8Impl_Compact(IDirectSound8 *iface)
469 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
470 TRACE("(%p)\n", This);
471 return DirectSoundDevice_Compact(This->device);
474 static HRESULT WINAPI IDirectSound8Impl_GetSpeakerConfig(IDirectSound8 *iface,
475 DWORD *lpdwSpeakerConfig)
477 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
478 TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
479 return DirectSoundDevice_GetSpeakerConfig(This->device, lpdwSpeakerConfig);
482 static HRESULT WINAPI IDirectSound8Impl_SetSpeakerConfig(IDirectSound8 *iface, DWORD config)
484 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
485 TRACE("(%p,0x%08x)\n", This, config);
486 return DirectSoundDevice_SetSpeakerConfig(This->device, config);
489 static HRESULT WINAPI IDirectSound8Impl_Initialize(IDirectSound8 *iface, const GUID *lpcGuid)
491 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
492 TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
493 return DirectSoundDevice_Initialize(&This->device, lpcGuid);
496 static HRESULT WINAPI IDirectSound8Impl_VerifyCertification(IDirectSound8 *iface,
497 DWORD *pdwCertified)
499 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
500 TRACE("(%p, %p)\n", This, pdwCertified);
501 return DirectSoundDevice_VerifyCertification(This->device, pdwCertified);
504 static const IDirectSound8Vtbl ds8_vtbl =
506 IDirectSound8Impl_QueryInterface,
507 IDirectSound8Impl_AddRef,
508 IDirectSound8Impl_Release,
509 IDirectSound8Impl_CreateSoundBuffer,
510 IDirectSound8Impl_GetCaps,
511 IDirectSound8Impl_DuplicateSoundBuffer,
512 IDirectSound8Impl_SetCooperativeLevel,
513 IDirectSound8Impl_Compact,
514 IDirectSound8Impl_GetSpeakerConfig,
515 IDirectSound8Impl_SetSpeakerConfig,
516 IDirectSound8Impl_Initialize,
517 IDirectSound8Impl_VerifyCertification
520 static HRESULT IDirectSoundImpl_Create(REFIID riid, void **ppv, BOOL has_ds8)
522 IDirectSoundImpl *obj;
523 HRESULT hr;
525 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
527 *ppv = NULL;
528 obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*obj));
529 if (!obj) {
530 WARN("out of memory\n");
531 return DSERR_OUTOFMEMORY;
534 setup_dsound_options();
536 obj->IUnknown_iface.lpVtbl = &unk_vtbl;
537 obj->IDirectSound8_iface.lpVtbl = &ds8_vtbl;
538 obj->ref = 1;
539 obj->refds = 0;
540 obj->numIfaces = 1;
541 obj->device = NULL;
542 obj->has_ds8 = has_ds8;
544 hr = IUnknown_QueryInterface(&obj->IUnknown_iface, riid, ppv);
545 IUnknown_Release(&obj->IUnknown_iface);
547 return hr;
550 HRESULT DSOUND_Create(REFIID riid, void **ppv)
552 return IDirectSoundImpl_Create(riid, ppv, FALSE);
555 HRESULT DSOUND_Create8(REFIID riid, void **ppv)
557 return IDirectSoundImpl_Create(riid, ppv, TRUE);
560 /*******************************************************************************
561 * DirectSoundCreate (DSOUND.1)
563 * Creates and initializes a DirectSound interface.
565 * PARAMS
566 * lpcGUID [I] Address of the GUID that identifies the sound device.
567 * ppDS [O] Address of a variable to receive the interface pointer.
568 * pUnkOuter [I] Must be NULL.
570 * RETURNS
571 * Success: DS_OK
572 * Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
573 * DSERR_NODRIVER, DSERR_OUTOFMEMORY
575 HRESULT WINAPI DirectSoundCreate(
576 LPCGUID lpcGUID,
577 LPDIRECTSOUND *ppDS,
578 IUnknown *pUnkOuter)
580 HRESULT hr;
581 LPDIRECTSOUND pDS;
583 TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
585 if (ppDS == NULL) {
586 WARN("invalid parameter: ppDS == NULL\n");
587 return DSERR_INVALIDPARAM;
590 if (pUnkOuter != NULL) {
591 WARN("invalid parameter: pUnkOuter != NULL\n");
592 *ppDS = 0;
593 return DSERR_INVALIDPARAM;
596 hr = DSOUND_Create(&IID_IDirectSound, (void **)&pDS);
597 if (hr == DS_OK) {
598 hr = IDirectSound_Initialize(pDS, lpcGUID);
599 if (hr != DS_OK) {
600 if (hr != DSERR_ALREADYINITIALIZED) {
601 IDirectSound_Release(pDS);
602 pDS = 0;
603 } else
604 hr = DS_OK;
608 *ppDS = pDS;
610 return hr;
613 /*******************************************************************************
614 * DirectSoundCreate8 (DSOUND.11)
616 * Creates and initializes a DirectSound8 interface.
618 * PARAMS
619 * lpcGUID [I] Address of the GUID that identifies the sound device.
620 * ppDS [O] Address of a variable to receive the interface pointer.
621 * pUnkOuter [I] Must be NULL.
623 * RETURNS
624 * Success: DS_OK
625 * Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
626 * DSERR_NODRIVER, DSERR_OUTOFMEMORY
628 HRESULT WINAPI DirectSoundCreate8(
629 LPCGUID lpcGUID,
630 LPDIRECTSOUND8 *ppDS,
631 IUnknown *pUnkOuter)
633 HRESULT hr;
634 LPDIRECTSOUND8 pDS;
636 TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
638 if (ppDS == NULL) {
639 WARN("invalid parameter: ppDS == NULL\n");
640 return DSERR_INVALIDPARAM;
643 if (pUnkOuter != NULL) {
644 WARN("invalid parameter: pUnkOuter != NULL\n");
645 *ppDS = 0;
646 return DSERR_INVALIDPARAM;
649 hr = DSOUND_Create8(&IID_IDirectSound8, (void **)&pDS);
650 if (hr == DS_OK) {
651 hr = IDirectSound8_Initialize(pDS, lpcGUID);
652 if (hr != DS_OK) {
653 if (hr != DSERR_ALREADYINITIALIZED) {
654 IDirectSound8_Release(pDS);
655 pDS = 0;
656 } else
657 hr = DS_OK;
661 *ppDS = pDS;
663 return hr;
666 /*******************************************************************************
667 * DirectSoundDevice
669 static HRESULT DirectSoundDevice_Create(DirectSoundDevice ** ppDevice)
671 DirectSoundDevice * device;
672 TRACE("(%p)\n", ppDevice);
674 /* Allocate memory */
675 device = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DirectSoundDevice));
676 if (device == NULL) {
677 WARN("out of memory\n");
678 return DSERR_OUTOFMEMORY;
681 device->ref = 1;
682 device->priolevel = DSSCL_NORMAL;
683 device->state = STATE_STOPPED;
684 device->speaker_config = DSSPEAKER_COMBINED(DSSPEAKER_STEREO, DSSPEAKER_GEOMETRY_WIDE);
686 /* 3D listener initial parameters */
687 device->ds3dl.dwSize = sizeof(DS3DLISTENER);
688 device->ds3dl.vPosition.x = 0.0;
689 device->ds3dl.vPosition.y = 0.0;
690 device->ds3dl.vPosition.z = 0.0;
691 device->ds3dl.vVelocity.x = 0.0;
692 device->ds3dl.vVelocity.y = 0.0;
693 device->ds3dl.vVelocity.z = 0.0;
694 device->ds3dl.vOrientFront.x = 0.0;
695 device->ds3dl.vOrientFront.y = 0.0;
696 device->ds3dl.vOrientFront.z = 1.0;
697 device->ds3dl.vOrientTop.x = 0.0;
698 device->ds3dl.vOrientTop.y = 1.0;
699 device->ds3dl.vOrientTop.z = 0.0;
700 device->ds3dl.flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
701 device->ds3dl.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
702 device->ds3dl.flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
704 device->prebuf = ds_snd_queue_max;
705 device->guid = GUID_NULL;
707 /* Set default wave format (may need it for waveOutOpen) */
708 device->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(WAVEFORMATEX));
709 if (device->pwfx == NULL) {
710 WARN("out of memory\n");
711 HeapFree(GetProcessHeap(),0,device);
712 return DSERR_OUTOFMEMORY;
715 device->pwfx->wFormatTag = WAVE_FORMAT_PCM;
716 device->pwfx->nSamplesPerSec = ds_default_sample_rate;
717 device->pwfx->wBitsPerSample = ds_default_bits_per_sample;
718 device->pwfx->nChannels = 2;
719 device->pwfx->nBlockAlign = device->pwfx->wBitsPerSample * device->pwfx->nChannels / 8;
720 device->pwfx->nAvgBytesPerSec = device->pwfx->nSamplesPerSec * device->pwfx->nBlockAlign;
721 device->pwfx->cbSize = 0;
723 InitializeCriticalSection(&(device->mixlock));
724 device->mixlock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DirectSoundDevice.mixlock");
726 RtlInitializeResource(&(device->buffer_list_lock));
728 *ppDevice = device;
730 return DS_OK;
733 static ULONG DirectSoundDevice_AddRef(DirectSoundDevice * device)
735 ULONG ref = InterlockedIncrement(&(device->ref));
736 TRACE("(%p) ref was %d\n", device, ref - 1);
737 return ref;
740 ULONG DirectSoundDevice_Release(DirectSoundDevice * device)
742 HRESULT hr;
743 ULONG ref = InterlockedDecrement(&(device->ref));
744 TRACE("(%p) ref was %u\n", device, ref + 1);
745 if (!ref) {
746 int i;
747 timeKillEvent(device->timerID);
748 timeEndPeriod(DS_TIME_RES);
750 /* The kill event should have allowed the timer process to expire
751 * but try to grab the lock just in case. Can't hold lock because
752 * secondarybuffer_destroy also grabs the lock */
753 RtlAcquireResourceShared(&(device->buffer_list_lock), TRUE);
754 RtlReleaseResource(&(device->buffer_list_lock));
756 EnterCriticalSection(&DSOUND_renderers_lock);
757 list_remove(&device->entry);
758 LeaveCriticalSection(&DSOUND_renderers_lock);
760 /* It is allowed to release this object even when buffers are playing */
761 if (device->buffers) {
762 WARN("%d secondary buffers not released\n", device->nrofbuffers);
763 for( i=0;i<device->nrofbuffers;i++)
764 secondarybuffer_destroy(device->buffers[i]);
767 hr = DSOUND_PrimaryDestroy(device);
768 if (hr != DS_OK)
769 WARN("DSOUND_PrimaryDestroy failed\n");
771 if(device->client)
772 IAudioClient_Release(device->client);
773 if(device->render)
774 IAudioRenderClient_Release(device->render);
775 if(device->clock)
776 IAudioClock_Release(device->clock);
777 if(device->volume)
778 IAudioStreamVolume_Release(device->volume);
780 HeapFree(GetProcessHeap(), 0, device->tmp_buffer);
781 HeapFree(GetProcessHeap(), 0, device->mix_buffer);
782 HeapFree(GetProcessHeap(), 0, device->buffer);
783 RtlDeleteResource(&device->buffer_list_lock);
784 device->mixlock.DebugInfo->Spare[0] = 0;
785 DeleteCriticalSection(&device->mixlock);
786 HeapFree(GetProcessHeap(),0,device);
787 TRACE("(%p) released\n", device);
789 return ref;
792 HRESULT DirectSoundDevice_GetCaps(
793 DirectSoundDevice * device,
794 LPDSCAPS lpDSCaps)
796 TRACE("(%p,%p)\n",device,lpDSCaps);
798 if (device == NULL) {
799 WARN("not initialized\n");
800 return DSERR_UNINITIALIZED;
803 if (lpDSCaps == NULL) {
804 WARN("invalid parameter: lpDSCaps = NULL\n");
805 return DSERR_INVALIDPARAM;
808 /* check if there is enough room */
809 if (lpDSCaps->dwSize < sizeof(*lpDSCaps)) {
810 WARN("invalid parameter: lpDSCaps->dwSize = %d\n", lpDSCaps->dwSize);
811 return DSERR_INVALIDPARAM;
814 lpDSCaps->dwFlags = device->drvcaps.dwFlags;
815 if (TRACE_ON(dsound)) {
816 TRACE("(flags=0x%08x:\n",lpDSCaps->dwFlags);
817 _dump_DSCAPS(lpDSCaps->dwFlags);
818 TRACE(")\n");
820 lpDSCaps->dwMinSecondarySampleRate = device->drvcaps.dwMinSecondarySampleRate;
821 lpDSCaps->dwMaxSecondarySampleRate = device->drvcaps.dwMaxSecondarySampleRate;
822 lpDSCaps->dwPrimaryBuffers = device->drvcaps.dwPrimaryBuffers;
823 lpDSCaps->dwMaxHwMixingAllBuffers = device->drvcaps.dwMaxHwMixingAllBuffers;
824 lpDSCaps->dwMaxHwMixingStaticBuffers = device->drvcaps.dwMaxHwMixingStaticBuffers;
825 lpDSCaps->dwMaxHwMixingStreamingBuffers = device->drvcaps.dwMaxHwMixingStreamingBuffers;
826 lpDSCaps->dwFreeHwMixingAllBuffers = device->drvcaps.dwFreeHwMixingAllBuffers;
827 lpDSCaps->dwFreeHwMixingStaticBuffers = device->drvcaps.dwFreeHwMixingStaticBuffers;
828 lpDSCaps->dwFreeHwMixingStreamingBuffers = device->drvcaps.dwFreeHwMixingStreamingBuffers;
829 lpDSCaps->dwMaxHw3DAllBuffers = device->drvcaps.dwMaxHw3DAllBuffers;
830 lpDSCaps->dwMaxHw3DStaticBuffers = device->drvcaps.dwMaxHw3DStaticBuffers;
831 lpDSCaps->dwMaxHw3DStreamingBuffers = device->drvcaps.dwMaxHw3DStreamingBuffers;
832 lpDSCaps->dwFreeHw3DAllBuffers = device->drvcaps.dwFreeHw3DAllBuffers;
833 lpDSCaps->dwFreeHw3DStaticBuffers = device->drvcaps.dwFreeHw3DStaticBuffers;
834 lpDSCaps->dwFreeHw3DStreamingBuffers = device->drvcaps.dwFreeHw3DStreamingBuffers;
835 lpDSCaps->dwTotalHwMemBytes = device->drvcaps.dwTotalHwMemBytes;
836 lpDSCaps->dwFreeHwMemBytes = device->drvcaps.dwFreeHwMemBytes;
837 lpDSCaps->dwMaxContigFreeHwMemBytes = device->drvcaps.dwMaxContigFreeHwMemBytes;
838 lpDSCaps->dwUnlockTransferRateHwBuffers = device->drvcaps.dwUnlockTransferRateHwBuffers;
839 lpDSCaps->dwPlayCpuOverheadSwBuffers = device->drvcaps.dwPlayCpuOverheadSwBuffers;
841 return DS_OK;
844 BOOL DSOUND_check_supported(IAudioClient *client, DWORD rate,
845 DWORD depth, WORD channels)
847 WAVEFORMATEX fmt, *junk;
848 HRESULT hr;
850 fmt.wFormatTag = WAVE_FORMAT_PCM;
851 fmt.nChannels = channels;
852 fmt.nSamplesPerSec = rate;
853 fmt.wBitsPerSample = depth;
854 fmt.nBlockAlign = (channels * depth) / 8;
855 fmt.nAvgBytesPerSec = rate * fmt.nBlockAlign;
856 fmt.cbSize = 0;
858 hr = IAudioClient_IsFormatSupported(client, AUDCLNT_SHAREMODE_SHARED, &fmt, &junk);
859 if(SUCCEEDED(hr))
860 CoTaskMemFree(junk);
862 return hr == S_OK;
865 UINT DSOUND_create_timer(LPTIMECALLBACK cb, DWORD_PTR user)
867 UINT triggertime = DS_TIME_DEL, res = DS_TIME_RES, id;
868 TIMECAPS time;
870 timeGetDevCaps(&time, sizeof(TIMECAPS));
871 TRACE("Minimum timer resolution: %u, max timer: %u\n", time.wPeriodMin, time.wPeriodMax);
872 if (triggertime < time.wPeriodMin)
873 triggertime = time.wPeriodMin;
874 if (res < time.wPeriodMin)
875 res = time.wPeriodMin;
876 if (timeBeginPeriod(res) == TIMERR_NOCANDO)
877 WARN("Could not set minimum resolution, don't expect sound\n");
878 id = timeSetEvent(triggertime, res, cb, user, TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
879 if (!id)
881 WARN("Timer not created! Retrying without TIME_KILL_SYNCHRONOUS\n");
882 id = timeSetEvent(triggertime, res, cb, user, TIME_PERIODIC);
883 if (!id)
884 ERR("Could not create timer, sound playback will not occur\n");
886 return id;
889 HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcGUID)
891 HRESULT hr = DS_OK;
892 GUID devGUID;
893 DirectSoundDevice *device;
894 IMMDevice *mmdevice;
896 TRACE("(%p,%s)\n",ppDevice,debugstr_guid(lpcGUID));
898 if (*ppDevice != NULL) {
899 WARN("already initialized\n");
900 return DSERR_ALREADYINITIALIZED;
903 /* Default device? */
904 if (!lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL))
905 lpcGUID = &DSDEVID_DefaultPlayback;
907 if(IsEqualGUID(lpcGUID, &DSDEVID_DefaultCapture) ||
908 IsEqualGUID(lpcGUID, &DSDEVID_DefaultVoiceCapture))
909 return DSERR_NODRIVER;
911 if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
912 WARN("invalid parameter: lpcGUID\n");
913 return DSERR_INVALIDPARAM;
916 hr = get_mmdevice(eRender, &devGUID, &mmdevice);
917 if(FAILED(hr))
918 return hr;
920 EnterCriticalSection(&DSOUND_renderers_lock);
922 LIST_FOR_EACH_ENTRY(device, &DSOUND_renderers, DirectSoundDevice, entry){
923 if(IsEqualGUID(&device->guid, &devGUID)){
924 IMMDevice_Release(mmdevice);
925 DirectSoundDevice_AddRef(device);
926 *ppDevice = device;
927 LeaveCriticalSection(&DSOUND_renderers_lock);
928 return DS_OK;
932 hr = DirectSoundDevice_Create(&device);
933 if(FAILED(hr)){
934 WARN("DirectSoundDevice_Create failed\n");
935 IMMDevice_Release(mmdevice);
936 LeaveCriticalSection(&DSOUND_renderers_lock);
937 return hr;
940 device->mmdevice = mmdevice;
941 device->guid = devGUID;
943 hr = DSOUND_ReopenDevice(device, FALSE);
944 if (FAILED(hr))
946 HeapFree(GetProcessHeap(), 0, device);
947 LeaveCriticalSection(&DSOUND_renderers_lock);
948 IMMDevice_Release(mmdevice);
949 WARN("DSOUND_ReopenDevice failed: %08x\n", hr);
950 return hr;
953 ZeroMemory(&device->drvcaps, sizeof(device->drvcaps));
955 if(DSOUND_check_supported(device->client, 11025, 8, 1) ||
956 DSOUND_check_supported(device->client, 22050, 8, 1) ||
957 DSOUND_check_supported(device->client, 44100, 8, 1) ||
958 DSOUND_check_supported(device->client, 48000, 8, 1) ||
959 DSOUND_check_supported(device->client, 96000, 8, 1))
960 device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT | DSCAPS_PRIMARYMONO;
962 if(DSOUND_check_supported(device->client, 11025, 16, 1) ||
963 DSOUND_check_supported(device->client, 22050, 16, 1) ||
964 DSOUND_check_supported(device->client, 44100, 16, 1) ||
965 DSOUND_check_supported(device->client, 48000, 16, 1) ||
966 DSOUND_check_supported(device->client, 96000, 16, 1))
967 device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT | DSCAPS_PRIMARYMONO;
969 if(DSOUND_check_supported(device->client, 11025, 8, 2) ||
970 DSOUND_check_supported(device->client, 22050, 8, 2) ||
971 DSOUND_check_supported(device->client, 44100, 8, 2) ||
972 DSOUND_check_supported(device->client, 48000, 8, 2) ||
973 DSOUND_check_supported(device->client, 96000, 8, 2))
974 device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT | DSCAPS_PRIMARYSTEREO;
976 if(DSOUND_check_supported(device->client, 11025, 16, 2) ||
977 DSOUND_check_supported(device->client, 22050, 16, 2) ||
978 DSOUND_check_supported(device->client, 44100, 16, 2) ||
979 DSOUND_check_supported(device->client, 48000, 16, 2) ||
980 DSOUND_check_supported(device->client, 96000, 16, 2))
981 device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT | DSCAPS_PRIMARYSTEREO;
983 /* the dsound mixer supports all of the following */
984 device->drvcaps.dwFlags |= DSCAPS_SECONDARY8BIT | DSCAPS_SECONDARY16BIT;
985 device->drvcaps.dwFlags |= DSCAPS_SECONDARYMONO | DSCAPS_SECONDARYSTEREO;
986 device->drvcaps.dwFlags |= DSCAPS_CONTINUOUSRATE;
988 device->drvcaps.dwPrimaryBuffers = 1;
989 device->drvcaps.dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
990 device->drvcaps.dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
991 device->drvcaps.dwMaxHwMixingAllBuffers = 1;
992 device->drvcaps.dwMaxHwMixingStaticBuffers = 1;
993 device->drvcaps.dwMaxHwMixingStreamingBuffers = 1;
995 ZeroMemory(&device->volpan, sizeof(device->volpan));
997 hr = DSOUND_PrimaryCreate(device);
998 if (hr == DS_OK)
999 device->timerID = DSOUND_create_timer(DSOUND_timer, (DWORD_PTR)device);
1000 else
1001 WARN("DSOUND_PrimaryCreate failed: %08x\n", hr);
1003 *ppDevice = device;
1004 list_add_tail(&DSOUND_renderers, &device->entry);
1006 LeaveCriticalSection(&DSOUND_renderers_lock);
1008 return hr;
1011 HRESULT DirectSoundDevice_CreateSoundBuffer(
1012 DirectSoundDevice * device,
1013 LPCDSBUFFERDESC dsbd,
1014 LPLPDIRECTSOUNDBUFFER ppdsb,
1015 LPUNKNOWN lpunk,
1016 BOOL from8)
1018 HRESULT hres = DS_OK;
1019 TRACE("(%p,%p,%p,%p)\n",device,dsbd,ppdsb,lpunk);
1021 if (device == NULL) {
1022 WARN("not initialized\n");
1023 return DSERR_UNINITIALIZED;
1026 if (dsbd == NULL) {
1027 WARN("invalid parameter: dsbd == NULL\n");
1028 return DSERR_INVALIDPARAM;
1031 if (dsbd->dwSize != sizeof(DSBUFFERDESC) &&
1032 dsbd->dwSize != sizeof(DSBUFFERDESC1)) {
1033 WARN("invalid parameter: dsbd\n");
1034 return DSERR_INVALIDPARAM;
1037 if (ppdsb == NULL) {
1038 WARN("invalid parameter: ppdsb == NULL\n");
1039 return DSERR_INVALIDPARAM;
1041 *ppdsb = NULL;
1043 if (TRACE_ON(dsound)) {
1044 TRACE("(structsize=%d)\n",dsbd->dwSize);
1045 TRACE("(flags=0x%08x:\n",dsbd->dwFlags);
1046 _dump_DSBCAPS(dsbd->dwFlags);
1047 TRACE(")\n");
1048 TRACE("(bufferbytes=%d)\n",dsbd->dwBufferBytes);
1049 TRACE("(lpwfxFormat=%p)\n",dsbd->lpwfxFormat);
1052 if (dsbd->dwFlags & DSBCAPS_LOCHARDWARE &&
1053 !(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
1054 TRACE("LOCHARDWARE is not supported, returning E_NOTIMPL\n");
1055 return E_NOTIMPL;
1058 if (dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) {
1059 if (dsbd->lpwfxFormat != NULL) {
1060 WARN("invalid parameter: dsbd->lpwfxFormat must be NULL for "
1061 "primary buffer\n");
1062 return DSERR_INVALIDPARAM;
1065 if (device->primary) {
1066 WARN("Primary Buffer already created\n");
1067 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(device->primary));
1068 *ppdsb = (LPDIRECTSOUNDBUFFER)(device->primary);
1069 } else {
1070 hres = primarybuffer_create(device, &device->primary, dsbd);
1071 if (device->primary) {
1072 *ppdsb = (IDirectSoundBuffer*)&device->primary->IDirectSoundBuffer8_iface;
1073 device->primary->dsbd.dwFlags &= ~(DSBCAPS_LOCHARDWARE | DSBCAPS_LOCSOFTWARE);
1074 device->primary->dsbd.dwFlags |= DSBCAPS_LOCSOFTWARE;
1075 } else
1076 WARN("primarybuffer_create() failed\n");
1078 } else {
1079 IDirectSoundBufferImpl * dsb;
1080 WAVEFORMATEXTENSIBLE *pwfxe;
1082 if (dsbd->lpwfxFormat == NULL) {
1083 WARN("invalid parameter: dsbd->lpwfxFormat can't be NULL for "
1084 "secondary buffer\n");
1085 return DSERR_INVALIDPARAM;
1087 pwfxe = (WAVEFORMATEXTENSIBLE*)dsbd->lpwfxFormat;
1089 if (pwfxe->Format.wBitsPerSample != 16 && pwfxe->Format.wBitsPerSample != 8 && pwfxe->Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE)
1091 WARN("wBitsPerSample=%d needs a WAVEFORMATEXTENSIBLE\n", dsbd->lpwfxFormat->wBitsPerSample);
1092 return DSERR_CONTROLUNAVAIL;
1094 if (pwfxe->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE)
1096 /* check if cbSize is at least 22 bytes */
1097 if (pwfxe->Format.cbSize < (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)))
1099 WARN("Too small a cbSize %u\n", pwfxe->Format.cbSize);
1100 return DSERR_INVALIDPARAM;
1103 /* cbSize should be 22 bytes, with one possible exception */
1104 if (pwfxe->Format.cbSize > (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)) &&
1105 !((IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) || IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) &&
1106 pwfxe->Format.cbSize == sizeof(WAVEFORMATEXTENSIBLE)))
1108 WARN("Too big a cbSize %u\n", pwfxe->Format.cbSize);
1109 return DSERR_CONTROLUNAVAIL;
1112 if ((!IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) && (!IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)))
1114 if (!IsEqualGUID(&pwfxe->SubFormat, &GUID_NULL))
1115 FIXME("SubFormat %s not supported right now.\n", debugstr_guid(&pwfxe->SubFormat));
1116 return DSERR_INVALIDPARAM;
1118 if (pwfxe->Samples.wValidBitsPerSample > dsbd->lpwfxFormat->wBitsPerSample)
1120 WARN("Samples.wValidBitsPerSample(%d) > Format.wBitsPerSample (%d)\n", pwfxe->Samples.wValidBitsPerSample, pwfxe->Format.wBitsPerSample);
1121 return DSERR_INVALIDPARAM;
1123 if (pwfxe->Samples.wValidBitsPerSample && pwfxe->Samples.wValidBitsPerSample < dsbd->lpwfxFormat->wBitsPerSample)
1125 FIXME("Non-packed formats not supported right now: %d/%d\n", pwfxe->Samples.wValidBitsPerSample, dsbd->lpwfxFormat->wBitsPerSample);
1126 return DSERR_CONTROLUNAVAIL;
1130 TRACE("(formattag=0x%04x,chans=%d,samplerate=%d,"
1131 "bytespersec=%d,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
1132 dsbd->lpwfxFormat->wFormatTag, dsbd->lpwfxFormat->nChannels,
1133 dsbd->lpwfxFormat->nSamplesPerSec,
1134 dsbd->lpwfxFormat->nAvgBytesPerSec,
1135 dsbd->lpwfxFormat->nBlockAlign,
1136 dsbd->lpwfxFormat->wBitsPerSample, dsbd->lpwfxFormat->cbSize);
1138 if (from8 && (dsbd->dwFlags & DSBCAPS_CTRL3D) && (dsbd->lpwfxFormat->nChannels != 1)) {
1139 WARN("invalid parameter: 3D buffer format must be mono\n");
1140 return DSERR_INVALIDPARAM;
1143 hres = IDirectSoundBufferImpl_Create(device, &dsb, dsbd);
1144 if (dsb)
1145 *ppdsb = (IDirectSoundBuffer*)&dsb->IDirectSoundBuffer8_iface;
1146 else
1147 WARN("IDirectSoundBufferImpl_Create failed\n");
1150 return hres;
1153 HRESULT DirectSoundDevice_DuplicateSoundBuffer(
1154 DirectSoundDevice * device,
1155 LPDIRECTSOUNDBUFFER psb,
1156 LPLPDIRECTSOUNDBUFFER ppdsb)
1158 HRESULT hres = DS_OK;
1159 IDirectSoundBufferImpl* dsb;
1160 TRACE("(%p,%p,%p)\n",device,psb,ppdsb);
1162 if (device == NULL) {
1163 WARN("not initialized\n");
1164 return DSERR_UNINITIALIZED;
1167 if (psb == NULL) {
1168 WARN("invalid parameter: psb == NULL\n");
1169 return DSERR_INVALIDPARAM;
1172 if (ppdsb == NULL) {
1173 WARN("invalid parameter: ppdsb == NULL\n");
1174 return DSERR_INVALIDPARAM;
1177 /* make sure we have a secondary buffer */
1178 if (psb == (IDirectSoundBuffer *)&device->primary->IDirectSoundBuffer8_iface) {
1179 WARN("trying to duplicate primary buffer\n");
1180 *ppdsb = NULL;
1181 return DSERR_INVALIDCALL;
1184 /* duplicate the actual buffer implementation */
1185 hres = IDirectSoundBufferImpl_Duplicate(device, &dsb, (IDirectSoundBufferImpl*)psb);
1186 if (hres == DS_OK)
1187 *ppdsb = (IDirectSoundBuffer*)&dsb->IDirectSoundBuffer8_iface;
1188 else
1189 WARN("IDirectSoundBufferImpl_Duplicate failed\n");
1191 return hres;
1194 HRESULT DirectSoundDevice_SetCooperativeLevel(
1195 DirectSoundDevice * device,
1196 HWND hwnd,
1197 DWORD level)
1199 TRACE("(%p,%p,%s)\n",device,hwnd,dumpCooperativeLevel(level));
1201 if (device == NULL) {
1202 WARN("not initialized\n");
1203 return DSERR_UNINITIALIZED;
1206 if (level==DSSCL_PRIORITY || level==DSSCL_EXCLUSIVE) {
1207 WARN("level=%s not fully supported\n",
1208 level==DSSCL_PRIORITY ? "DSSCL_PRIORITY" : "DSSCL_EXCLUSIVE");
1211 device->priolevel = level;
1212 return DS_OK;
1215 HRESULT DirectSoundDevice_Compact(
1216 DirectSoundDevice * device)
1218 TRACE("(%p)\n", device);
1220 if (device == NULL) {
1221 WARN("not initialized\n");
1222 return DSERR_UNINITIALIZED;
1225 if (device->priolevel < DSSCL_PRIORITY) {
1226 WARN("incorrect priority level\n");
1227 return DSERR_PRIOLEVELNEEDED;
1230 return DS_OK;
1233 HRESULT DirectSoundDevice_GetSpeakerConfig(
1234 DirectSoundDevice * device,
1235 LPDWORD lpdwSpeakerConfig)
1237 TRACE("(%p, %p)\n", device, lpdwSpeakerConfig);
1239 if (device == NULL) {
1240 WARN("not initialized\n");
1241 return DSERR_UNINITIALIZED;
1244 if (lpdwSpeakerConfig == NULL) {
1245 WARN("invalid parameter: lpdwSpeakerConfig == NULL\n");
1246 return DSERR_INVALIDPARAM;
1249 WARN("not fully functional\n");
1250 *lpdwSpeakerConfig = device->speaker_config;
1251 return DS_OK;
1254 HRESULT DirectSoundDevice_SetSpeakerConfig(
1255 DirectSoundDevice * device,
1256 DWORD config)
1258 TRACE("(%p,0x%08x)\n",device,config);
1260 if (device == NULL) {
1261 WARN("not initialized\n");
1262 return DSERR_UNINITIALIZED;
1265 device->speaker_config = config;
1266 WARN("not fully functional\n");
1267 return DS_OK;
1270 HRESULT DirectSoundDevice_VerifyCertification(
1271 DirectSoundDevice * device,
1272 LPDWORD pdwCertified)
1274 TRACE("(%p, %p)\n",device,pdwCertified);
1276 if (device == NULL) {
1277 WARN("not initialized\n");
1278 return DSERR_UNINITIALIZED;
1281 if (device->drvcaps.dwFlags & DSCAPS_CERTIFIED)
1282 *pdwCertified = DS_CERTIFIED;
1283 else
1284 *pdwCertified = DS_UNCERTIFIED;
1286 return DS_OK;
1290 * Add secondary buffer to buffer list.
1291 * Gets exclusive access to buffer for writing.
1293 HRESULT DirectSoundDevice_AddBuffer(
1294 DirectSoundDevice * device,
1295 IDirectSoundBufferImpl * pDSB)
1297 IDirectSoundBufferImpl **newbuffers;
1298 HRESULT hr = DS_OK;
1300 TRACE("(%p, %p)\n", device, pDSB);
1302 RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
1304 if (device->buffers)
1305 newbuffers = HeapReAlloc(GetProcessHeap(),0,device->buffers,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
1306 else
1307 newbuffers = HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
1309 if (newbuffers) {
1310 device->buffers = newbuffers;
1311 device->buffers[device->nrofbuffers] = pDSB;
1312 device->nrofbuffers++;
1313 TRACE("buffer count is now %d\n", device->nrofbuffers);
1314 } else {
1315 ERR("out of memory for buffer list! Current buffer count is %d\n", device->nrofbuffers);
1316 hr = DSERR_OUTOFMEMORY;
1319 RtlReleaseResource(&(device->buffer_list_lock));
1321 return hr;
1325 * Remove secondary buffer from buffer list.
1326 * Gets exclusive access to buffer for writing.
1328 HRESULT DirectSoundDevice_RemoveBuffer(
1329 DirectSoundDevice * device,
1330 IDirectSoundBufferImpl * pDSB)
1332 int i;
1333 HRESULT hr = DS_OK;
1335 TRACE("(%p, %p)\n", device, pDSB);
1337 RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
1339 for (i = 0; i < device->nrofbuffers; i++)
1340 if (device->buffers[i] == pDSB)
1341 break;
1343 if (i < device->nrofbuffers) {
1344 /* Put the last buffer of the list in the (now empty) position */
1345 device->buffers[i] = device->buffers[device->nrofbuffers - 1];
1346 device->nrofbuffers--;
1347 device->buffers = HeapReAlloc(GetProcessHeap(),0,device->buffers,sizeof(LPDIRECTSOUNDBUFFER8)*device->nrofbuffers);
1348 TRACE("buffer count is now %d\n", device->nrofbuffers);
1351 if (device->nrofbuffers == 0) {
1352 HeapFree(GetProcessHeap(),0,device->buffers);
1353 device->buffers = NULL;
1356 RtlReleaseResource(&(device->buffer_list_lock));
1358 return hr;