gdi32: Re-create the brush bits only when the ROP has really changed.
[wine/multimedia.git] / dlls / dsound / dsound.c
blobfbfb4f853fd4c727f6f9be9190770db0b292d11a
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_IUnknown {
67 const IUnknownVtbl *lpVtbl;
68 LONG ref;
69 LPDIRECTSOUND8 pds;
72 static HRESULT IDirectSound8_IUnknown_Create(LPDIRECTSOUND8 pds, LPUNKNOWN * ppunk);
73 static ULONG WINAPI IDirectSound8_IUnknown_AddRef(LPUNKNOWN iface);
75 struct IDirectSound8_IDirectSound {
76 const IDirectSoundVtbl *lpVtbl;
77 LONG ref;
78 LPDIRECTSOUND8 pds;
81 static HRESULT IDirectSound8_IDirectSound_Create(LPDIRECTSOUND8 pds, LPDIRECTSOUND * ppds);
82 static ULONG WINAPI IDirectSound8_IDirectSound_AddRef(LPDIRECTSOUND iface);
84 struct IDirectSound8_IDirectSound8 {
85 const IDirectSound8Vtbl *lpVtbl;
86 LONG ref;
87 LPDIRECTSOUND8 pds;
90 static HRESULT IDirectSound8_IDirectSound8_Create(LPDIRECTSOUND8 pds, LPDIRECTSOUND8 * ppds);
91 static ULONG WINAPI IDirectSound8_IDirectSound8_AddRef(LPDIRECTSOUND8 iface);
93 /*****************************************************************************
94 * IDirectSound implementation structure
96 struct IDirectSoundImpl
98 LONG ref;
100 DirectSoundDevice *device;
101 LPUNKNOWN pUnknown;
102 LPDIRECTSOUND pDS;
103 LPDIRECTSOUND8 pDS8;
106 static HRESULT IDirectSoundImpl_Create(LPDIRECTSOUND8 * ppds);
108 static ULONG WINAPI IDirectSound_IUnknown_AddRef(LPUNKNOWN iface);
109 static ULONG WINAPI IDirectSound_IDirectSound_AddRef(LPDIRECTSOUND iface);
111 const char * dumpCooperativeLevel(DWORD level)
113 #define LE(x) case x: return #x
114 switch (level) {
115 LE(DSSCL_NORMAL);
116 LE(DSSCL_PRIORITY);
117 LE(DSSCL_EXCLUSIVE);
118 LE(DSSCL_WRITEPRIMARY);
120 #undef LE
121 return wine_dbg_sprintf("Unknown(%08x)", level);
124 static void _dump_DSCAPS(DWORD xmask) {
125 struct {
126 DWORD mask;
127 const char *name;
128 } flags[] = {
129 #define FE(x) { x, #x },
130 FE(DSCAPS_PRIMARYMONO)
131 FE(DSCAPS_PRIMARYSTEREO)
132 FE(DSCAPS_PRIMARY8BIT)
133 FE(DSCAPS_PRIMARY16BIT)
134 FE(DSCAPS_CONTINUOUSRATE)
135 FE(DSCAPS_EMULDRIVER)
136 FE(DSCAPS_CERTIFIED)
137 FE(DSCAPS_SECONDARYMONO)
138 FE(DSCAPS_SECONDARYSTEREO)
139 FE(DSCAPS_SECONDARY8BIT)
140 FE(DSCAPS_SECONDARY16BIT)
141 #undef FE
143 unsigned int i;
145 for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
146 if ((flags[i].mask & xmask) == flags[i].mask)
147 TRACE("%s ",flags[i].name);
150 static void _dump_DSBCAPS(DWORD xmask) {
151 struct {
152 DWORD mask;
153 const char *name;
154 } flags[] = {
155 #define FE(x) { x, #x },
156 FE(DSBCAPS_PRIMARYBUFFER)
157 FE(DSBCAPS_STATIC)
158 FE(DSBCAPS_LOCHARDWARE)
159 FE(DSBCAPS_LOCSOFTWARE)
160 FE(DSBCAPS_CTRL3D)
161 FE(DSBCAPS_CTRLFREQUENCY)
162 FE(DSBCAPS_CTRLPAN)
163 FE(DSBCAPS_CTRLVOLUME)
164 FE(DSBCAPS_CTRLPOSITIONNOTIFY)
165 FE(DSBCAPS_STICKYFOCUS)
166 FE(DSBCAPS_GLOBALFOCUS)
167 FE(DSBCAPS_GETCURRENTPOSITION2)
168 FE(DSBCAPS_MUTE3DATMAXDISTANCE)
169 #undef FE
171 unsigned int i;
173 for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
174 if ((flags[i].mask & xmask) == flags[i].mask)
175 TRACE("%s ",flags[i].name);
178 /*******************************************************************************
179 * IDirectSoundImpl_DirectSound
181 static HRESULT DSOUND_QueryInterface(
182 LPDIRECTSOUND8 iface,
183 REFIID riid,
184 LPVOID * ppobj)
186 IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
187 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
189 if (ppobj == NULL) {
190 WARN("invalid parameter\n");
191 return E_INVALIDARG;
194 if (IsEqualIID(riid, &IID_IUnknown)) {
195 if (!This->pUnknown) {
196 IDirectSound_IUnknown_Create(iface, &This->pUnknown);
197 if (!This->pUnknown) {
198 WARN("IDirectSound_IUnknown_Create() failed\n");
199 *ppobj = NULL;
200 return E_NOINTERFACE;
203 IDirectSound_IUnknown_AddRef(This->pUnknown);
204 *ppobj = This->pUnknown;
205 return S_OK;
206 } else if (IsEqualIID(riid, &IID_IDirectSound)) {
207 if (!This->pDS) {
208 IDirectSound_IDirectSound_Create(iface, &This->pDS);
209 if (!This->pDS) {
210 WARN("IDirectSound_IDirectSound_Create() failed\n");
211 *ppobj = NULL;
212 return E_NOINTERFACE;
215 IDirectSound_IDirectSound_AddRef(This->pDS);
216 *ppobj = This->pDS;
217 return S_OK;
220 *ppobj = NULL;
221 WARN("Unknown IID %s\n",debugstr_guid(riid));
222 return E_NOINTERFACE;
225 static HRESULT DSOUND_QueryInterface8(
226 LPDIRECTSOUND8 iface,
227 REFIID riid,
228 LPVOID * ppobj)
230 IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
231 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
233 if (ppobj == NULL) {
234 WARN("invalid parameter\n");
235 return E_INVALIDARG;
238 if (IsEqualIID(riid, &IID_IUnknown)) {
239 if (!This->pUnknown) {
240 IDirectSound8_IUnknown_Create(iface, &This->pUnknown);
241 if (!This->pUnknown) {
242 WARN("IDirectSound8_IUnknown_Create() failed\n");
243 *ppobj = NULL;
244 return E_NOINTERFACE;
247 IDirectSound8_IUnknown_AddRef(This->pUnknown);
248 *ppobj = This->pUnknown;
249 return S_OK;
250 } else if (IsEqualIID(riid, &IID_IDirectSound)) {
251 if (!This->pDS) {
252 IDirectSound8_IDirectSound_Create(iface, &This->pDS);
253 if (!This->pDS) {
254 WARN("IDirectSound8_IDirectSound_Create() failed\n");
255 *ppobj = NULL;
256 return E_NOINTERFACE;
259 IDirectSound8_IDirectSound_AddRef(This->pDS);
260 *ppobj = This->pDS;
261 return S_OK;
262 } else if (IsEqualIID(riid, &IID_IDirectSound8)) {
263 if (!This->pDS8) {
264 IDirectSound8_IDirectSound8_Create(iface, &This->pDS8);
265 if (!This->pDS8) {
266 WARN("IDirectSound8_IDirectSound8_Create() failed\n");
267 *ppobj = NULL;
268 return E_NOINTERFACE;
271 IDirectSound8_IDirectSound8_AddRef(This->pDS8);
272 *ppobj = This->pDS8;
273 return S_OK;
276 *ppobj = NULL;
277 WARN("Unknown IID %s\n",debugstr_guid(riid));
278 return E_NOINTERFACE;
281 static ULONG IDirectSoundImpl_AddRef(
282 LPDIRECTSOUND8 iface)
284 IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
285 ULONG ref = InterlockedIncrement(&(This->ref));
286 TRACE("(%p) ref was %d\n", This, ref - 1);
287 return ref;
290 static ULONG IDirectSoundImpl_Release(
291 LPDIRECTSOUND8 iface)
293 IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
294 ULONG ref = InterlockedDecrement(&(This->ref));
295 TRACE("(%p) ref was %d\n", This, ref + 1);
297 if (!ref) {
298 if (This->device)
299 DirectSoundDevice_Release(This->device);
300 HeapFree(GetProcessHeap(),0,This);
301 TRACE("(%p) released\n", This);
303 return ref;
306 static HRESULT IDirectSoundImpl_Create(
307 LPDIRECTSOUND8 * ppDS)
309 IDirectSoundImpl* pDS;
310 TRACE("(%p)\n",ppDS);
312 /* Allocate memory */
313 pDS = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundImpl));
314 if (pDS == NULL) {
315 WARN("out of memory\n");
316 *ppDS = NULL;
317 return DSERR_OUTOFMEMORY;
320 pDS->ref = 0;
321 pDS->device = NULL;
323 *ppDS = (LPDIRECTSOUND8)pDS;
325 return DS_OK;
328 /*******************************************************************************
329 * IDirectSound_IUnknown
331 static HRESULT WINAPI IDirectSound_IUnknown_QueryInterface(
332 LPUNKNOWN iface,
333 REFIID riid,
334 LPVOID * ppobj)
336 IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
337 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
338 return DSOUND_QueryInterface(This->pds, riid, ppobj);
341 static ULONG WINAPI IDirectSound_IUnknown_AddRef(
342 LPUNKNOWN iface)
344 IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
345 ULONG ref = InterlockedIncrement(&(This->ref));
346 TRACE("(%p) ref was %d\n", This, ref - 1);
347 return ref;
350 static ULONG WINAPI IDirectSound_IUnknown_Release(
351 LPUNKNOWN iface)
353 IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
354 ULONG ref = InterlockedDecrement(&(This->ref));
355 TRACE("(%p) ref was %d\n", This, ref + 1);
356 if (!ref) {
357 ((IDirectSoundImpl*)This->pds)->pUnknown = NULL;
358 IDirectSoundImpl_Release(This->pds);
359 HeapFree(GetProcessHeap(), 0, This);
360 TRACE("(%p) released\n", This);
362 return ref;
365 static const IUnknownVtbl DirectSound_Unknown_Vtbl =
367 IDirectSound_IUnknown_QueryInterface,
368 IDirectSound_IUnknown_AddRef,
369 IDirectSound_IUnknown_Release
372 static HRESULT IDirectSound_IUnknown_Create(
373 LPDIRECTSOUND8 pds,
374 LPUNKNOWN * ppunk)
376 IDirectSound_IUnknown * pdsunk;
377 TRACE("(%p,%p)\n",pds,ppunk);
379 if (ppunk == NULL) {
380 ERR("invalid parameter: ppunk == NULL\n");
381 return DSERR_INVALIDPARAM;
384 if (pds == NULL) {
385 ERR("invalid parameter: pds == NULL\n");
386 *ppunk = NULL;
387 return DSERR_INVALIDPARAM;
390 pdsunk = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsunk));
391 if (pdsunk == NULL) {
392 WARN("out of memory\n");
393 *ppunk = NULL;
394 return DSERR_OUTOFMEMORY;
397 pdsunk->lpVtbl = &DirectSound_Unknown_Vtbl;
398 pdsunk->ref = 0;
399 pdsunk->pds = pds;
401 IDirectSoundImpl_AddRef(pds);
402 *ppunk = (LPUNKNOWN)pdsunk;
404 return DS_OK;
407 /*******************************************************************************
408 * IDirectSound_IDirectSound
410 static HRESULT WINAPI IDirectSound_IDirectSound_QueryInterface(
411 LPDIRECTSOUND iface,
412 REFIID riid,
413 LPVOID * ppobj)
415 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
416 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
417 return DSOUND_QueryInterface(This->pds, riid, ppobj);
420 static ULONG WINAPI IDirectSound_IDirectSound_AddRef(
421 LPDIRECTSOUND iface)
423 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
424 ULONG ref = InterlockedIncrement(&(This->ref));
425 TRACE("(%p) ref was %d\n", This, ref - 1);
426 return ref;
429 static ULONG WINAPI IDirectSound_IDirectSound_Release(
430 LPDIRECTSOUND iface)
432 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
433 ULONG ref = InterlockedDecrement(&(This->ref));
434 TRACE("(%p) ref was %d\n", This, ref + 1);
435 if (!ref) {
436 ((IDirectSoundImpl*)This->pds)->pDS = NULL;
437 IDirectSoundImpl_Release(This->pds);
438 HeapFree(GetProcessHeap(), 0, This);
439 TRACE("(%p) released\n", This);
441 return ref;
444 static HRESULT WINAPI IDirectSound_IDirectSound_CreateSoundBuffer(
445 LPDIRECTSOUND iface,
446 LPCDSBUFFERDESC dsbd,
447 LPLPDIRECTSOUNDBUFFER ppdsb,
448 LPUNKNOWN lpunk)
450 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
451 TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
452 return DirectSoundDevice_CreateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,dsbd,ppdsb,lpunk,FALSE);
455 static HRESULT WINAPI IDirectSound_IDirectSound_GetCaps(
456 LPDIRECTSOUND iface,
457 LPDSCAPS lpDSCaps)
459 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
460 TRACE("(%p,%p)\n",This,lpDSCaps);
461 return DirectSoundDevice_GetCaps(((IDirectSoundImpl *)This->pds)->device, lpDSCaps);
464 static HRESULT WINAPI IDirectSound_IDirectSound_DuplicateSoundBuffer(
465 LPDIRECTSOUND iface,
466 LPDIRECTSOUNDBUFFER psb,
467 LPLPDIRECTSOUNDBUFFER ppdsb)
469 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
470 TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
471 return DirectSoundDevice_DuplicateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,psb,ppdsb);
474 static HRESULT WINAPI IDirectSound_IDirectSound_SetCooperativeLevel(
475 LPDIRECTSOUND iface,
476 HWND hwnd,
477 DWORD level)
479 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
480 TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level));
481 return DirectSoundDevice_SetCooperativeLevel(((IDirectSoundImpl *)This->pds)->device, hwnd, level);
484 static HRESULT WINAPI IDirectSound_IDirectSound_Compact(
485 LPDIRECTSOUND iface)
487 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
488 TRACE("(%p)\n", This);
489 return DirectSoundDevice_Compact(((IDirectSoundImpl *)This->pds)->device);
492 static HRESULT WINAPI IDirectSound_IDirectSound_GetSpeakerConfig(
493 LPDIRECTSOUND iface,
494 LPDWORD lpdwSpeakerConfig)
496 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
497 TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
498 return DirectSoundDevice_GetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,lpdwSpeakerConfig);
501 static HRESULT WINAPI IDirectSound_IDirectSound_SetSpeakerConfig(
502 LPDIRECTSOUND iface,
503 DWORD config)
505 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
506 TRACE("(%p,0x%08x)\n",This,config);
507 return DirectSoundDevice_SetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,config);
510 static HRESULT WINAPI IDirectSound_IDirectSound_Initialize(
511 LPDIRECTSOUND iface,
512 LPCGUID lpcGuid)
514 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
515 TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
516 return DirectSoundDevice_Initialize(&((IDirectSoundImpl *)This->pds)->device,lpcGuid);
519 static const IDirectSoundVtbl DirectSound_DirectSound_Vtbl =
521 IDirectSound_IDirectSound_QueryInterface,
522 IDirectSound_IDirectSound_AddRef,
523 IDirectSound_IDirectSound_Release,
524 IDirectSound_IDirectSound_CreateSoundBuffer,
525 IDirectSound_IDirectSound_GetCaps,
526 IDirectSound_IDirectSound_DuplicateSoundBuffer,
527 IDirectSound_IDirectSound_SetCooperativeLevel,
528 IDirectSound_IDirectSound_Compact,
529 IDirectSound_IDirectSound_GetSpeakerConfig,
530 IDirectSound_IDirectSound_SetSpeakerConfig,
531 IDirectSound_IDirectSound_Initialize
534 static HRESULT IDirectSound_IDirectSound_Create(
535 LPDIRECTSOUND8 pds,
536 LPDIRECTSOUND * ppds)
538 IDirectSound_IDirectSound * pdsds;
539 TRACE("(%p,%p)\n",pds,ppds);
541 if (ppds == NULL) {
542 ERR("invalid parameter: ppds == NULL\n");
543 return DSERR_INVALIDPARAM;
546 if (pds == NULL) {
547 ERR("invalid parameter: pds == NULL\n");
548 *ppds = NULL;
549 return DSERR_INVALIDPARAM;
552 pdsds = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsds));
553 if (pdsds == NULL) {
554 WARN("out of memory\n");
555 *ppds = NULL;
556 return DSERR_OUTOFMEMORY;
559 pdsds->lpVtbl = &DirectSound_DirectSound_Vtbl;
560 pdsds->ref = 0;
561 pdsds->pds = pds;
563 IDirectSoundImpl_AddRef(pds);
564 *ppds = (LPDIRECTSOUND)pdsds;
566 return DS_OK;
569 /*******************************************************************************
570 * IDirectSound8_IUnknown
572 static HRESULT WINAPI IDirectSound8_IUnknown_QueryInterface(
573 LPUNKNOWN iface,
574 REFIID riid,
575 LPVOID * ppobj)
577 IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
578 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
579 return DSOUND_QueryInterface8(This->pds, riid, ppobj);
582 static ULONG WINAPI IDirectSound8_IUnknown_AddRef(
583 LPUNKNOWN iface)
585 IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
586 ULONG ref = InterlockedIncrement(&(This->ref));
587 TRACE("(%p) ref was %d\n", This, ref - 1);
588 return ref;
591 static ULONG WINAPI IDirectSound8_IUnknown_Release(
592 LPUNKNOWN iface)
594 IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
595 ULONG ref = InterlockedDecrement(&(This->ref));
596 TRACE("(%p) ref was %d\n", This, ref + 1);
597 if (!ref) {
598 ((IDirectSoundImpl*)This->pds)->pUnknown = NULL;
599 IDirectSoundImpl_Release(This->pds);
600 HeapFree(GetProcessHeap(), 0, This);
601 TRACE("(%p) released\n", This);
603 return ref;
606 static const IUnknownVtbl DirectSound8_Unknown_Vtbl =
608 IDirectSound8_IUnknown_QueryInterface,
609 IDirectSound8_IUnknown_AddRef,
610 IDirectSound8_IUnknown_Release
613 static HRESULT IDirectSound8_IUnknown_Create(
614 LPDIRECTSOUND8 pds,
615 LPUNKNOWN * ppunk)
617 IDirectSound8_IUnknown * pdsunk;
618 TRACE("(%p,%p)\n",pds,ppunk);
620 if (ppunk == NULL) {
621 ERR("invalid parameter: ppunk == NULL\n");
622 return DSERR_INVALIDPARAM;
625 if (pds == NULL) {
626 ERR("invalid parameter: pds == NULL\n");
627 *ppunk = NULL;
628 return DSERR_INVALIDPARAM;
631 pdsunk = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsunk));
632 if (pdsunk == NULL) {
633 WARN("out of memory\n");
634 *ppunk = NULL;
635 return DSERR_OUTOFMEMORY;
638 pdsunk->lpVtbl = &DirectSound8_Unknown_Vtbl;
639 pdsunk->ref = 0;
640 pdsunk->pds = pds;
642 IDirectSoundImpl_AddRef(pds);
643 *ppunk = (LPUNKNOWN)pdsunk;
645 return DS_OK;
648 /*******************************************************************************
649 * IDirectSound8_IDirectSound
651 static HRESULT WINAPI IDirectSound8_IDirectSound_QueryInterface(
652 LPDIRECTSOUND iface,
653 REFIID riid,
654 LPVOID * ppobj)
656 IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
657 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
658 return DSOUND_QueryInterface8(This->pds, riid, ppobj);
661 static ULONG WINAPI IDirectSound8_IDirectSound_AddRef(
662 LPDIRECTSOUND iface)
664 IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
665 ULONG ref = InterlockedIncrement(&(This->ref));
666 TRACE("(%p) ref was %d\n", This, ref - 1);
667 return ref;
670 static ULONG WINAPI IDirectSound8_IDirectSound_Release(
671 LPDIRECTSOUND iface)
673 IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
674 ULONG ref = InterlockedDecrement(&(This->ref));
675 TRACE("(%p) ref was %d\n", This, ref + 1);
676 if (!ref) {
677 ((IDirectSoundImpl*)This->pds)->pDS = NULL;
678 IDirectSoundImpl_Release(This->pds);
679 HeapFree(GetProcessHeap(), 0, This);
680 TRACE("(%p) released\n", This);
682 return ref;
685 static HRESULT WINAPI IDirectSound8_IDirectSound_CreateSoundBuffer(
686 LPDIRECTSOUND iface,
687 LPCDSBUFFERDESC dsbd,
688 LPLPDIRECTSOUNDBUFFER ppdsb,
689 LPUNKNOWN lpunk)
691 IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
692 TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
693 return DirectSoundDevice_CreateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,dsbd,ppdsb,lpunk,TRUE);
696 static HRESULT WINAPI IDirectSound8_IDirectSound_GetCaps(
697 LPDIRECTSOUND iface,
698 LPDSCAPS lpDSCaps)
700 IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
701 TRACE("(%p,%p)\n",This,lpDSCaps);
702 return DirectSoundDevice_GetCaps(((IDirectSoundImpl *)This->pds)->device, lpDSCaps);
705 static HRESULT WINAPI IDirectSound8_IDirectSound_DuplicateSoundBuffer(
706 LPDIRECTSOUND iface,
707 LPDIRECTSOUNDBUFFER psb,
708 LPLPDIRECTSOUNDBUFFER ppdsb)
710 IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
711 TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
712 return DirectSoundDevice_DuplicateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,psb,ppdsb);
715 static HRESULT WINAPI IDirectSound8_IDirectSound_SetCooperativeLevel(
716 LPDIRECTSOUND iface,
717 HWND hwnd,
718 DWORD level)
720 IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
721 TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level));
722 return DirectSoundDevice_SetCooperativeLevel(((IDirectSoundImpl *)This->pds)->device, hwnd, level);
725 static HRESULT WINAPI IDirectSound8_IDirectSound_Compact(
726 LPDIRECTSOUND iface)
728 IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
729 TRACE("(%p)\n", This);
730 return DirectSoundDevice_Compact(((IDirectSoundImpl *)This->pds)->device);
733 static HRESULT WINAPI IDirectSound8_IDirectSound_GetSpeakerConfig(
734 LPDIRECTSOUND iface,
735 LPDWORD lpdwSpeakerConfig)
737 IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
738 TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
739 return DirectSoundDevice_GetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,lpdwSpeakerConfig);
742 static HRESULT WINAPI IDirectSound8_IDirectSound_SetSpeakerConfig(
743 LPDIRECTSOUND iface,
744 DWORD config)
746 IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
747 TRACE("(%p,0x%08x)\n",This,config);
748 return DirectSoundDevice_SetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,config);
751 static HRESULT WINAPI IDirectSound8_IDirectSound_Initialize(
752 LPDIRECTSOUND iface,
753 LPCGUID lpcGuid)
755 IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
756 TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
757 return DirectSoundDevice_Initialize(&((IDirectSoundImpl *)This->pds)->device,lpcGuid);
760 static const IDirectSoundVtbl DirectSound8_DirectSound_Vtbl =
762 IDirectSound8_IDirectSound_QueryInterface,
763 IDirectSound8_IDirectSound_AddRef,
764 IDirectSound8_IDirectSound_Release,
765 IDirectSound8_IDirectSound_CreateSoundBuffer,
766 IDirectSound8_IDirectSound_GetCaps,
767 IDirectSound8_IDirectSound_DuplicateSoundBuffer,
768 IDirectSound8_IDirectSound_SetCooperativeLevel,
769 IDirectSound8_IDirectSound_Compact,
770 IDirectSound8_IDirectSound_GetSpeakerConfig,
771 IDirectSound8_IDirectSound_SetSpeakerConfig,
772 IDirectSound8_IDirectSound_Initialize
775 static HRESULT IDirectSound8_IDirectSound_Create(
776 LPDIRECTSOUND8 pds,
777 LPDIRECTSOUND * ppds)
779 IDirectSound8_IDirectSound * pdsds;
780 TRACE("(%p,%p)\n",pds,ppds);
782 if (ppds == NULL) {
783 ERR("invalid parameter: ppds == NULL\n");
784 return DSERR_INVALIDPARAM;
787 if (pds == NULL) {
788 ERR("invalid parameter: pds == NULL\n");
789 *ppds = NULL;
790 return DSERR_INVALIDPARAM;
793 pdsds = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsds));
794 if (pdsds == NULL) {
795 WARN("out of memory\n");
796 *ppds = NULL;
797 return DSERR_OUTOFMEMORY;
800 pdsds->lpVtbl = &DirectSound8_DirectSound_Vtbl;
801 pdsds->ref = 0;
802 pdsds->pds = pds;
804 IDirectSoundImpl_AddRef(pds);
805 *ppds = (LPDIRECTSOUND)pdsds;
807 return DS_OK;
810 /*******************************************************************************
811 * IDirectSound8_IDirectSound8
813 static HRESULT WINAPI IDirectSound8_IDirectSound8_QueryInterface(
814 LPDIRECTSOUND8 iface,
815 REFIID riid,
816 LPVOID * ppobj)
818 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
819 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
820 return DSOUND_QueryInterface8(This->pds, riid, ppobj);
823 static ULONG WINAPI IDirectSound8_IDirectSound8_AddRef(
824 LPDIRECTSOUND8 iface)
826 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
827 ULONG ref = InterlockedIncrement(&(This->ref));
828 TRACE("(%p) ref was %d\n", This, ref - 1);
829 return ref;
832 static ULONG WINAPI IDirectSound8_IDirectSound8_Release(
833 LPDIRECTSOUND8 iface)
835 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
836 ULONG ref = InterlockedDecrement(&(This->ref));
837 TRACE("(%p) ref was %d\n", This, ref + 1);
838 if (!ref) {
839 ((IDirectSoundImpl*)This->pds)->pDS8 = NULL;
840 IDirectSoundImpl_Release(This->pds);
841 HeapFree(GetProcessHeap(), 0, This);
842 TRACE("(%p) released\n", This);
844 return ref;
847 static HRESULT WINAPI IDirectSound8_IDirectSound8_CreateSoundBuffer(
848 LPDIRECTSOUND8 iface,
849 LPCDSBUFFERDESC dsbd,
850 LPLPDIRECTSOUNDBUFFER ppdsb,
851 LPUNKNOWN lpunk)
853 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
854 TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
855 return DirectSoundDevice_CreateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,dsbd,ppdsb,lpunk,TRUE);
858 static HRESULT WINAPI IDirectSound8_IDirectSound8_GetCaps(
859 LPDIRECTSOUND8 iface,
860 LPDSCAPS lpDSCaps)
862 IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
863 TRACE("(%p,%p)\n",This,lpDSCaps);
864 return DirectSoundDevice_GetCaps(((IDirectSoundImpl *)This->pds)->device, lpDSCaps);
867 static HRESULT WINAPI IDirectSound8_IDirectSound8_DuplicateSoundBuffer(
868 LPDIRECTSOUND8 iface,
869 LPDIRECTSOUNDBUFFER psb,
870 LPLPDIRECTSOUNDBUFFER ppdsb)
872 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
873 TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
874 return DirectSoundDevice_DuplicateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,psb,ppdsb);
877 static HRESULT WINAPI IDirectSound8_IDirectSound8_SetCooperativeLevel(
878 LPDIRECTSOUND8 iface,
879 HWND hwnd,
880 DWORD level)
882 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
883 TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level));
884 return DirectSoundDevice_SetCooperativeLevel(((IDirectSoundImpl *)This->pds)->device, hwnd, level);
887 static HRESULT WINAPI IDirectSound8_IDirectSound8_Compact(
888 LPDIRECTSOUND8 iface)
890 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
891 TRACE("(%p)\n", This);
892 return DirectSoundDevice_Compact(((IDirectSoundImpl *)This->pds)->device);
895 static HRESULT WINAPI IDirectSound8_IDirectSound8_GetSpeakerConfig(
896 LPDIRECTSOUND8 iface,
897 LPDWORD lpdwSpeakerConfig)
899 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
900 TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
901 return DirectSoundDevice_GetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,lpdwSpeakerConfig);
904 static HRESULT WINAPI IDirectSound8_IDirectSound8_SetSpeakerConfig(
905 LPDIRECTSOUND8 iface,
906 DWORD config)
908 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
909 TRACE("(%p,0x%08x)\n",This,config);
910 return DirectSoundDevice_SetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,config);
913 static HRESULT WINAPI IDirectSound8_IDirectSound8_Initialize(
914 LPDIRECTSOUND8 iface,
915 LPCGUID lpcGuid)
917 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
918 TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
919 return DirectSoundDevice_Initialize(&((IDirectSoundImpl *)This->pds)->device,lpcGuid);
922 static HRESULT WINAPI IDirectSound8_IDirectSound8_VerifyCertification(
923 LPDIRECTSOUND8 iface,
924 LPDWORD pdwCertified)
926 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
927 TRACE("(%p, %p)\n", This, pdwCertified);
928 return DirectSoundDevice_VerifyCertification(((IDirectSoundImpl *)This->pds)->device,pdwCertified);
931 static const IDirectSound8Vtbl DirectSound8_DirectSound8_Vtbl =
933 IDirectSound8_IDirectSound8_QueryInterface,
934 IDirectSound8_IDirectSound8_AddRef,
935 IDirectSound8_IDirectSound8_Release,
936 IDirectSound8_IDirectSound8_CreateSoundBuffer,
937 IDirectSound8_IDirectSound8_GetCaps,
938 IDirectSound8_IDirectSound8_DuplicateSoundBuffer,
939 IDirectSound8_IDirectSound8_SetCooperativeLevel,
940 IDirectSound8_IDirectSound8_Compact,
941 IDirectSound8_IDirectSound8_GetSpeakerConfig,
942 IDirectSound8_IDirectSound8_SetSpeakerConfig,
943 IDirectSound8_IDirectSound8_Initialize,
944 IDirectSound8_IDirectSound8_VerifyCertification
947 static HRESULT IDirectSound8_IDirectSound8_Create(
948 LPDIRECTSOUND8 pds,
949 LPDIRECTSOUND8 * ppds)
951 IDirectSound8_IDirectSound8 * pdsds;
952 TRACE("(%p,%p)\n",pds,ppds);
954 if (ppds == NULL) {
955 ERR("invalid parameter: ppds == NULL\n");
956 return DSERR_INVALIDPARAM;
959 if (pds == NULL) {
960 ERR("invalid parameter: pds == NULL\n");
961 *ppds = NULL;
962 return DSERR_INVALIDPARAM;
965 pdsds = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsds));
966 if (pdsds == NULL) {
967 WARN("out of memory\n");
968 *ppds = NULL;
969 return DSERR_OUTOFMEMORY;
972 pdsds->lpVtbl = &DirectSound8_DirectSound8_Vtbl;
973 pdsds->ref = 0;
974 pdsds->pds = pds;
976 IDirectSoundImpl_AddRef(pds);
977 *ppds = (LPDIRECTSOUND8)pdsds;
979 return DS_OK;
982 HRESULT DSOUND_Create(
983 REFIID riid,
984 LPDIRECTSOUND *ppDS)
986 LPDIRECTSOUND8 pDS;
987 HRESULT hr;
988 TRACE("(%s, %p)\n", debugstr_guid(riid), ppDS);
990 if (!IsEqualIID(riid, &IID_IUnknown) &&
991 !IsEqualIID(riid, &IID_IDirectSound)) {
992 *ppDS = 0;
993 return E_NOINTERFACE;
996 /* Get dsound configuration */
997 setup_dsound_options();
999 hr = IDirectSoundImpl_Create(&pDS);
1000 if (hr == DS_OK) {
1001 hr = IDirectSound_IDirectSound_Create(pDS, ppDS);
1002 if (*ppDS)
1003 IDirectSound_IDirectSound_AddRef(*ppDS);
1004 else {
1005 WARN("IDirectSound_IDirectSound_Create failed\n");
1006 IDirectSound8_Release(pDS);
1008 } else {
1009 WARN("IDirectSoundImpl_Create failed\n");
1010 *ppDS = 0;
1013 return hr;
1016 /*******************************************************************************
1017 * DirectSoundCreate (DSOUND.1)
1019 * Creates and initializes a DirectSound interface.
1021 * PARAMS
1022 * lpcGUID [I] Address of the GUID that identifies the sound device.
1023 * ppDS [O] Address of a variable to receive the interface pointer.
1024 * pUnkOuter [I] Must be NULL.
1026 * RETURNS
1027 * Success: DS_OK
1028 * Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
1029 * DSERR_NODRIVER, DSERR_OUTOFMEMORY
1031 HRESULT WINAPI DirectSoundCreate(
1032 LPCGUID lpcGUID,
1033 LPDIRECTSOUND *ppDS,
1034 IUnknown *pUnkOuter)
1036 HRESULT hr;
1037 LPDIRECTSOUND pDS;
1039 TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
1041 if (ppDS == NULL) {
1042 WARN("invalid parameter: ppDS == NULL\n");
1043 return DSERR_INVALIDPARAM;
1046 if (pUnkOuter != NULL) {
1047 WARN("invalid parameter: pUnkOuter != NULL\n");
1048 *ppDS = 0;
1049 return DSERR_INVALIDPARAM;
1052 hr = DSOUND_Create(&IID_IDirectSound, &pDS);
1053 if (hr == DS_OK) {
1054 hr = IDirectSound_Initialize(pDS, lpcGUID);
1055 if (hr != DS_OK) {
1056 if (hr != DSERR_ALREADYINITIALIZED) {
1057 IDirectSound_Release(pDS);
1058 pDS = 0;
1059 } else
1060 hr = DS_OK;
1064 *ppDS = pDS;
1066 return hr;
1069 HRESULT DSOUND_Create8(
1070 REFIID riid,
1071 LPDIRECTSOUND8 *ppDS)
1073 LPDIRECTSOUND8 pDS;
1074 HRESULT hr;
1075 TRACE("(%s, %p)\n", debugstr_guid(riid), ppDS);
1077 if (!IsEqualIID(riid, &IID_IUnknown) &&
1078 !IsEqualIID(riid, &IID_IDirectSound) &&
1079 !IsEqualIID(riid, &IID_IDirectSound8)) {
1080 *ppDS = 0;
1081 return E_NOINTERFACE;
1084 /* Get dsound configuration */
1085 setup_dsound_options();
1087 hr = IDirectSoundImpl_Create(&pDS);
1088 if (hr == DS_OK) {
1089 hr = IDirectSound8_IDirectSound8_Create(pDS, ppDS);
1090 if (*ppDS)
1091 IDirectSound8_IDirectSound8_AddRef(*ppDS);
1092 else {
1093 WARN("IDirectSound8_IDirectSound8_Create failed\n");
1094 IDirectSound8_Release(pDS);
1096 } else {
1097 WARN("IDirectSoundImpl_Create failed\n");
1098 *ppDS = 0;
1101 return hr;
1104 /*******************************************************************************
1105 * DirectSoundCreate8 (DSOUND.11)
1107 * Creates and initializes a DirectSound8 interface.
1109 * PARAMS
1110 * lpcGUID [I] Address of the GUID that identifies the sound device.
1111 * ppDS [O] Address of a variable to receive the interface pointer.
1112 * pUnkOuter [I] Must be NULL.
1114 * RETURNS
1115 * Success: DS_OK
1116 * Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
1117 * DSERR_NODRIVER, DSERR_OUTOFMEMORY
1119 HRESULT WINAPI DirectSoundCreate8(
1120 LPCGUID lpcGUID,
1121 LPDIRECTSOUND8 *ppDS,
1122 IUnknown *pUnkOuter)
1124 HRESULT hr;
1125 LPDIRECTSOUND8 pDS;
1127 TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
1129 if (ppDS == NULL) {
1130 WARN("invalid parameter: ppDS == NULL\n");
1131 return DSERR_INVALIDPARAM;
1134 if (pUnkOuter != NULL) {
1135 WARN("invalid parameter: pUnkOuter != NULL\n");
1136 *ppDS = 0;
1137 return DSERR_INVALIDPARAM;
1140 hr = DSOUND_Create8(&IID_IDirectSound8, &pDS);
1141 if (hr == DS_OK) {
1142 hr = IDirectSound8_Initialize(pDS, lpcGUID);
1143 if (hr != DS_OK) {
1144 if (hr != DSERR_ALREADYINITIALIZED) {
1145 IDirectSound8_Release(pDS);
1146 pDS = 0;
1147 } else
1148 hr = DS_OK;
1152 *ppDS = pDS;
1154 return hr;
1157 /*******************************************************************************
1158 * DirectSoundDevice
1160 static HRESULT DirectSoundDevice_Create(DirectSoundDevice ** ppDevice)
1162 DirectSoundDevice * device;
1163 TRACE("(%p)\n", ppDevice);
1165 /* Allocate memory */
1166 device = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DirectSoundDevice));
1167 if (device == NULL) {
1168 WARN("out of memory\n");
1169 return DSERR_OUTOFMEMORY;
1172 device->ref = 1;
1173 device->priolevel = DSSCL_NORMAL;
1174 device->state = STATE_STOPPED;
1175 device->speaker_config = DSSPEAKER_STEREO | (DSSPEAKER_GEOMETRY_NARROW << 16);
1177 /* 3D listener initial parameters */
1178 device->ds3dl.dwSize = sizeof(DS3DLISTENER);
1179 device->ds3dl.vPosition.x = 0.0;
1180 device->ds3dl.vPosition.y = 0.0;
1181 device->ds3dl.vPosition.z = 0.0;
1182 device->ds3dl.vVelocity.x = 0.0;
1183 device->ds3dl.vVelocity.y = 0.0;
1184 device->ds3dl.vVelocity.z = 0.0;
1185 device->ds3dl.vOrientFront.x = 0.0;
1186 device->ds3dl.vOrientFront.y = 0.0;
1187 device->ds3dl.vOrientFront.z = 1.0;
1188 device->ds3dl.vOrientTop.x = 0.0;
1189 device->ds3dl.vOrientTop.y = 1.0;
1190 device->ds3dl.vOrientTop.z = 0.0;
1191 device->ds3dl.flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
1192 device->ds3dl.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
1193 device->ds3dl.flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
1195 device->prebuf = ds_snd_queue_max;
1196 device->guid = GUID_NULL;
1198 /* Set default wave format (may need it for waveOutOpen) */
1199 device->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(WAVEFORMATEX));
1200 if (device->pwfx == NULL) {
1201 WARN("out of memory\n");
1202 HeapFree(GetProcessHeap(),0,device);
1203 return DSERR_OUTOFMEMORY;
1206 /* We rely on the sound driver to return the actual sound format of
1207 * the device if it does not support 22050x8x2 and is given the
1208 * WAVE_DIRECTSOUND flag.
1210 device->pwfx->wFormatTag = WAVE_FORMAT_PCM;
1211 device->pwfx->nSamplesPerSec = ds_default_sample_rate;
1212 device->pwfx->wBitsPerSample = ds_default_bits_per_sample;
1213 device->pwfx->nChannels = 2;
1214 device->pwfx->nBlockAlign = device->pwfx->wBitsPerSample * device->pwfx->nChannels / 8;
1215 device->pwfx->nAvgBytesPerSec = device->pwfx->nSamplesPerSec * device->pwfx->nBlockAlign;
1216 device->pwfx->cbSize = 0;
1218 InitializeCriticalSection(&(device->mixlock));
1219 device->mixlock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DirectSoundDevice.mixlock");
1221 RtlInitializeResource(&(device->buffer_list_lock));
1223 *ppDevice = device;
1225 return DS_OK;
1228 static ULONG DirectSoundDevice_AddRef(DirectSoundDevice * device)
1230 ULONG ref = InterlockedIncrement(&(device->ref));
1231 TRACE("(%p) ref was %d\n", device, ref - 1);
1232 return ref;
1235 ULONG DirectSoundDevice_Release(DirectSoundDevice * device)
1237 HRESULT hr;
1238 ULONG ref = InterlockedDecrement(&(device->ref));
1239 TRACE("(%p) ref was %u\n", device, ref + 1);
1240 if (!ref) {
1241 int i;
1242 timeKillEvent(device->timerID);
1243 timeEndPeriod(DS_TIME_RES);
1245 /* The kill event should have allowed the timer process to expire
1246 * but try to grab the lock just in case. Can't hold lock because
1247 * IDirectSoundBufferImpl_Destroy also grabs the lock */
1248 RtlAcquireResourceShared(&(device->buffer_list_lock), TRUE);
1249 RtlReleaseResource(&(device->buffer_list_lock));
1251 EnterCriticalSection(&DSOUND_renderers_lock);
1252 list_remove(&device->entry);
1253 LeaveCriticalSection(&DSOUND_renderers_lock);
1255 /* It is allowed to release this object even when buffers are playing */
1256 if (device->buffers) {
1257 WARN("%d secondary buffers not released\n", device->nrofbuffers);
1258 for( i=0;i<device->nrofbuffers;i++)
1259 IDirectSoundBufferImpl_Destroy(device->buffers[i]);
1262 if (device->primary) {
1263 WARN("primary buffer not released\n");
1264 IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)device->primary);
1267 hr = DSOUND_PrimaryDestroy(device);
1268 if (hr != DS_OK)
1269 WARN("DSOUND_PrimaryDestroy failed\n");
1271 if(device->client)
1272 IAudioClient_Release(device->client);
1273 if(device->render)
1274 IAudioRenderClient_Release(device->render);
1275 if(device->clock)
1276 IAudioClock_Release(device->clock);
1277 if(device->volume)
1278 IAudioStreamVolume_Release(device->volume);
1280 HeapFree(GetProcessHeap(), 0, device->tmp_buffer);
1281 HeapFree(GetProcessHeap(), 0, device->mix_buffer);
1282 HeapFree(GetProcessHeap(), 0, device->buffer);
1283 RtlDeleteResource(&device->buffer_list_lock);
1284 device->mixlock.DebugInfo->Spare[0] = 0;
1285 DeleteCriticalSection(&device->mixlock);
1286 HeapFree(GetProcessHeap(),0,device);
1287 TRACE("(%p) released\n", device);
1289 return ref;
1292 HRESULT DirectSoundDevice_GetCaps(
1293 DirectSoundDevice * device,
1294 LPDSCAPS lpDSCaps)
1296 TRACE("(%p,%p)\n",device,lpDSCaps);
1298 if (device == NULL) {
1299 WARN("not initialized\n");
1300 return DSERR_UNINITIALIZED;
1303 if (lpDSCaps == NULL) {
1304 WARN("invalid parameter: lpDSCaps = NULL\n");
1305 return DSERR_INVALIDPARAM;
1308 /* check if there is enough room */
1309 if (lpDSCaps->dwSize < sizeof(*lpDSCaps)) {
1310 WARN("invalid parameter: lpDSCaps->dwSize = %d\n", lpDSCaps->dwSize);
1311 return DSERR_INVALIDPARAM;
1314 lpDSCaps->dwFlags = device->drvcaps.dwFlags;
1315 if (TRACE_ON(dsound)) {
1316 TRACE("(flags=0x%08x:\n",lpDSCaps->dwFlags);
1317 _dump_DSCAPS(lpDSCaps->dwFlags);
1318 TRACE(")\n");
1320 lpDSCaps->dwMinSecondarySampleRate = device->drvcaps.dwMinSecondarySampleRate;
1321 lpDSCaps->dwMaxSecondarySampleRate = device->drvcaps.dwMaxSecondarySampleRate;
1322 lpDSCaps->dwPrimaryBuffers = device->drvcaps.dwPrimaryBuffers;
1323 lpDSCaps->dwMaxHwMixingAllBuffers = device->drvcaps.dwMaxHwMixingAllBuffers;
1324 lpDSCaps->dwMaxHwMixingStaticBuffers = device->drvcaps.dwMaxHwMixingStaticBuffers;
1325 lpDSCaps->dwMaxHwMixingStreamingBuffers = device->drvcaps.dwMaxHwMixingStreamingBuffers;
1326 lpDSCaps->dwFreeHwMixingAllBuffers = device->drvcaps.dwFreeHwMixingAllBuffers;
1327 lpDSCaps->dwFreeHwMixingStaticBuffers = device->drvcaps.dwFreeHwMixingStaticBuffers;
1328 lpDSCaps->dwFreeHwMixingStreamingBuffers = device->drvcaps.dwFreeHwMixingStreamingBuffers;
1329 lpDSCaps->dwMaxHw3DAllBuffers = device->drvcaps.dwMaxHw3DAllBuffers;
1330 lpDSCaps->dwMaxHw3DStaticBuffers = device->drvcaps.dwMaxHw3DStaticBuffers;
1331 lpDSCaps->dwMaxHw3DStreamingBuffers = device->drvcaps.dwMaxHw3DStreamingBuffers;
1332 lpDSCaps->dwFreeHw3DAllBuffers = device->drvcaps.dwFreeHw3DAllBuffers;
1333 lpDSCaps->dwFreeHw3DStaticBuffers = device->drvcaps.dwFreeHw3DStaticBuffers;
1334 lpDSCaps->dwFreeHw3DStreamingBuffers = device->drvcaps.dwFreeHw3DStreamingBuffers;
1335 lpDSCaps->dwTotalHwMemBytes = device->drvcaps.dwTotalHwMemBytes;
1336 lpDSCaps->dwFreeHwMemBytes = device->drvcaps.dwFreeHwMemBytes;
1337 lpDSCaps->dwMaxContigFreeHwMemBytes = device->drvcaps.dwMaxContigFreeHwMemBytes;
1338 lpDSCaps->dwUnlockTransferRateHwBuffers = device->drvcaps.dwUnlockTransferRateHwBuffers;
1339 lpDSCaps->dwPlayCpuOverheadSwBuffers = device->drvcaps.dwPlayCpuOverheadSwBuffers;
1341 return DS_OK;
1344 BOOL DSOUND_check_supported(IAudioClient *client, DWORD rate,
1345 DWORD depth, WORD channels)
1347 WAVEFORMATEX fmt, *junk;
1348 HRESULT hr;
1350 fmt.wFormatTag = WAVE_FORMAT_PCM;
1351 fmt.nChannels = channels;
1352 fmt.nSamplesPerSec = rate;
1353 fmt.wBitsPerSample = depth;
1354 fmt.nBlockAlign = (channels * depth) / 8;
1355 fmt.nAvgBytesPerSec = rate * fmt.nBlockAlign;
1356 fmt.cbSize = 0;
1358 hr = IAudioClient_IsFormatSupported(client, AUDCLNT_SHAREMODE_SHARED, &fmt, &junk);
1359 if(SUCCEEDED(hr))
1360 CoTaskMemFree(junk);
1362 return hr == S_OK;
1365 UINT DSOUND_create_timer(LPTIMECALLBACK cb, DWORD_PTR user)
1367 UINT triggertime = DS_TIME_DEL, res = DS_TIME_RES, id;
1368 TIMECAPS time;
1370 timeGetDevCaps(&time, sizeof(TIMECAPS));
1371 TRACE("Minimum timer resolution: %u, max timer: %u\n", time.wPeriodMin, time.wPeriodMax);
1372 if (triggertime < time.wPeriodMin)
1373 triggertime = time.wPeriodMin;
1374 if (res < time.wPeriodMin)
1375 res = time.wPeriodMin;
1376 if (timeBeginPeriod(res) == TIMERR_NOCANDO)
1377 WARN("Could not set minimum resolution, don't expect sound\n");
1378 id = timeSetEvent(triggertime, res, cb, user, TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
1379 if (!id)
1381 WARN("Timer not created! Retrying without TIME_KILL_SYNCHRONOUS\n");
1382 id = timeSetEvent(triggertime, res, cb, user, TIME_PERIODIC);
1383 if (!id)
1384 ERR("Could not create timer, sound playback will not occur\n");
1386 return id;
1389 HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcGUID)
1391 HRESULT hr = DS_OK;
1392 GUID devGUID;
1393 DirectSoundDevice *device;
1394 IMMDevice *mmdevice;
1396 TRACE("(%p,%s)\n",ppDevice,debugstr_guid(lpcGUID));
1398 if (*ppDevice != NULL) {
1399 WARN("already initialized\n");
1400 return DSERR_ALREADYINITIALIZED;
1403 /* Default device? */
1404 if (!lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL))
1405 lpcGUID = &DSDEVID_DefaultPlayback;
1407 if(IsEqualGUID(lpcGUID, &DSDEVID_DefaultCapture) ||
1408 IsEqualGUID(lpcGUID, &DSDEVID_DefaultVoiceCapture))
1409 return DSERR_NODRIVER;
1411 if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
1412 WARN("invalid parameter: lpcGUID\n");
1413 return DSERR_INVALIDPARAM;
1416 hr = get_mmdevice(eRender, &devGUID, &mmdevice);
1417 if(FAILED(hr))
1418 return hr;
1420 EnterCriticalSection(&DSOUND_renderers_lock);
1422 LIST_FOR_EACH_ENTRY(device, &DSOUND_renderers, DirectSoundDevice, entry){
1423 if(IsEqualGUID(&device->guid, &devGUID)){
1424 IMMDevice_Release(mmdevice);
1425 DirectSoundDevice_AddRef(device);
1426 *ppDevice = device;
1427 LeaveCriticalSection(&DSOUND_renderers_lock);
1428 return DS_OK;
1432 hr = DirectSoundDevice_Create(&device);
1433 if(FAILED(hr)){
1434 WARN("DirectSoundDevice_Create failed\n");
1435 IMMDevice_Release(mmdevice);
1436 LeaveCriticalSection(&DSOUND_renderers_lock);
1437 return hr;
1440 device->mmdevice = mmdevice;
1441 device->guid = devGUID;
1443 hr = DSOUND_ReopenDevice(device, FALSE);
1444 if (FAILED(hr))
1446 HeapFree(GetProcessHeap(), 0, device);
1447 LeaveCriticalSection(&DSOUND_renderers_lock);
1448 IMMDevice_Release(mmdevice);
1449 WARN("DSOUND_ReopenDevice failed: %08x\n", hr);
1450 return hr;
1453 ZeroMemory(&device->drvcaps, sizeof(device->drvcaps));
1455 if(DSOUND_check_supported(device->client, 11025, 8, 1) ||
1456 DSOUND_check_supported(device->client, 22050, 8, 1) ||
1457 DSOUND_check_supported(device->client, 44100, 8, 1) ||
1458 DSOUND_check_supported(device->client, 48000, 8, 1) ||
1459 DSOUND_check_supported(device->client, 96000, 8, 1))
1460 device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT | DSCAPS_PRIMARYMONO;
1462 if(DSOUND_check_supported(device->client, 11025, 16, 1) ||
1463 DSOUND_check_supported(device->client, 22050, 16, 1) ||
1464 DSOUND_check_supported(device->client, 44100, 16, 1) ||
1465 DSOUND_check_supported(device->client, 48000, 16, 1) ||
1466 DSOUND_check_supported(device->client, 96000, 16, 1))
1467 device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT | DSCAPS_PRIMARYMONO;
1469 if(DSOUND_check_supported(device->client, 11025, 8, 2) ||
1470 DSOUND_check_supported(device->client, 22050, 8, 2) ||
1471 DSOUND_check_supported(device->client, 44100, 8, 2) ||
1472 DSOUND_check_supported(device->client, 48000, 8, 2) ||
1473 DSOUND_check_supported(device->client, 96000, 8, 2))
1474 device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT | DSCAPS_PRIMARYSTEREO;
1476 if(DSOUND_check_supported(device->client, 11025, 16, 2) ||
1477 DSOUND_check_supported(device->client, 22050, 16, 2) ||
1478 DSOUND_check_supported(device->client, 44100, 16, 2) ||
1479 DSOUND_check_supported(device->client, 48000, 16, 2) ||
1480 DSOUND_check_supported(device->client, 96000, 16, 2))
1481 device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT | DSCAPS_PRIMARYSTEREO;
1483 device->drvcaps.dwPrimaryBuffers = 1;
1484 device->drvcaps.dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
1485 device->drvcaps.dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
1486 device->drvcaps.dwMaxHwMixingAllBuffers = 1;
1487 device->drvcaps.dwMaxHwMixingStaticBuffers = 1;
1488 device->drvcaps.dwMaxHwMixingStreamingBuffers = 1;
1490 ZeroMemory(&device->volpan, sizeof(device->volpan));
1492 hr = DSOUND_PrimaryCreate(device);
1493 if (hr == DS_OK)
1494 device->timerID = DSOUND_create_timer(DSOUND_timer, (DWORD_PTR)device);
1495 else
1496 WARN("DSOUND_PrimaryCreate failed: %08x\n", hr);
1498 *ppDevice = device;
1499 list_add_tail(&DSOUND_renderers, &device->entry);
1501 LeaveCriticalSection(&DSOUND_renderers_lock);
1503 return hr;
1506 HRESULT DirectSoundDevice_CreateSoundBuffer(
1507 DirectSoundDevice * device,
1508 LPCDSBUFFERDESC dsbd,
1509 LPLPDIRECTSOUNDBUFFER ppdsb,
1510 LPUNKNOWN lpunk,
1511 BOOL from8)
1513 HRESULT hres = DS_OK;
1514 TRACE("(%p,%p,%p,%p)\n",device,dsbd,ppdsb,lpunk);
1516 if (device == NULL) {
1517 WARN("not initialized\n");
1518 return DSERR_UNINITIALIZED;
1521 if (dsbd == NULL) {
1522 WARN("invalid parameter: dsbd == NULL\n");
1523 return DSERR_INVALIDPARAM;
1526 if (dsbd->dwSize != sizeof(DSBUFFERDESC) &&
1527 dsbd->dwSize != sizeof(DSBUFFERDESC1)) {
1528 WARN("invalid parameter: dsbd\n");
1529 return DSERR_INVALIDPARAM;
1532 if (ppdsb == NULL) {
1533 WARN("invalid parameter: ppdsb == NULL\n");
1534 return DSERR_INVALIDPARAM;
1536 *ppdsb = NULL;
1538 if (TRACE_ON(dsound)) {
1539 TRACE("(structsize=%d)\n",dsbd->dwSize);
1540 TRACE("(flags=0x%08x:\n",dsbd->dwFlags);
1541 _dump_DSBCAPS(dsbd->dwFlags);
1542 TRACE(")\n");
1543 TRACE("(bufferbytes=%d)\n",dsbd->dwBufferBytes);
1544 TRACE("(lpwfxFormat=%p)\n",dsbd->lpwfxFormat);
1547 if (dsbd->dwFlags & DSBCAPS_LOCHARDWARE &&
1548 !(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
1549 TRACE("LOCHARDWARE is not supported, returning E_NOTIMPL\n");
1550 return E_NOTIMPL;
1553 if (dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) {
1554 if (dsbd->lpwfxFormat != NULL) {
1555 WARN("invalid parameter: dsbd->lpwfxFormat must be NULL for "
1556 "primary buffer\n");
1557 return DSERR_INVALIDPARAM;
1560 if (device->primary) {
1561 WARN("Primary Buffer already created\n");
1562 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(device->primary));
1563 *ppdsb = (LPDIRECTSOUNDBUFFER)(device->primary);
1564 } else {
1565 hres = primarybuffer_create(device, &device->primary, dsbd);
1566 if (device->primary) {
1567 *ppdsb = (IDirectSoundBuffer*)&device->primary->IDirectSoundBuffer8_iface;
1568 device->primary->dsbd.dwFlags &= ~(DSBCAPS_LOCHARDWARE | DSBCAPS_LOCSOFTWARE);
1569 device->primary->dsbd.dwFlags |= DSBCAPS_LOCSOFTWARE;
1570 } else
1571 WARN("primarybuffer_create() failed\n");
1573 } else {
1574 IDirectSoundBufferImpl * dsb;
1575 WAVEFORMATEXTENSIBLE *pwfxe;
1577 if (dsbd->lpwfxFormat == NULL) {
1578 WARN("invalid parameter: dsbd->lpwfxFormat can't be NULL for "
1579 "secondary buffer\n");
1580 return DSERR_INVALIDPARAM;
1582 pwfxe = (WAVEFORMATEXTENSIBLE*)dsbd->lpwfxFormat;
1584 if (pwfxe->Format.wBitsPerSample != 16 && pwfxe->Format.wBitsPerSample != 8 && pwfxe->Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE)
1586 WARN("wBitsPerSample=%d needs a WAVEFORMATEXTENSIBLE\n", dsbd->lpwfxFormat->wBitsPerSample);
1587 return DSERR_CONTROLUNAVAIL;
1589 if (pwfxe->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE)
1591 /* check if cbSize is at least 22 bytes */
1592 if (pwfxe->Format.cbSize < (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)))
1594 WARN("Too small a cbSize %u\n", pwfxe->Format.cbSize);
1595 return DSERR_INVALIDPARAM;
1598 /* cbSize should be 22 bytes, with one possible exception */
1599 if (pwfxe->Format.cbSize > (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)) &&
1600 !((IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) || IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) &&
1601 pwfxe->Format.cbSize == sizeof(WAVEFORMATEXTENSIBLE)))
1603 WARN("Too big a cbSize %u\n", pwfxe->Format.cbSize);
1604 return DSERR_CONTROLUNAVAIL;
1607 if ((!IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) && (!IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)))
1609 if (!IsEqualGUID(&pwfxe->SubFormat, &GUID_NULL))
1610 FIXME("SubFormat %s not supported right now.\n", debugstr_guid(&pwfxe->SubFormat));
1611 return DSERR_INVALIDPARAM;
1613 if (pwfxe->Samples.wValidBitsPerSample > dsbd->lpwfxFormat->wBitsPerSample)
1615 WARN("Samples.wValidBitsPerSample(%d) > Format.wBitsPerSample (%d)\n", pwfxe->Samples.wValidBitsPerSample, pwfxe->Format.wBitsPerSample);
1616 return DSERR_INVALIDPARAM;
1618 if (pwfxe->Samples.wValidBitsPerSample && pwfxe->Samples.wValidBitsPerSample < dsbd->lpwfxFormat->wBitsPerSample)
1620 FIXME("Non-packed formats not supported right now: %d/%d\n", pwfxe->Samples.wValidBitsPerSample, dsbd->lpwfxFormat->wBitsPerSample);
1621 return DSERR_CONTROLUNAVAIL;
1625 TRACE("(formattag=0x%04x,chans=%d,samplerate=%d,"
1626 "bytespersec=%d,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
1627 dsbd->lpwfxFormat->wFormatTag, dsbd->lpwfxFormat->nChannels,
1628 dsbd->lpwfxFormat->nSamplesPerSec,
1629 dsbd->lpwfxFormat->nAvgBytesPerSec,
1630 dsbd->lpwfxFormat->nBlockAlign,
1631 dsbd->lpwfxFormat->wBitsPerSample, dsbd->lpwfxFormat->cbSize);
1633 if (from8 && (dsbd->dwFlags & DSBCAPS_CTRL3D) && (dsbd->lpwfxFormat->nChannels != 1)) {
1634 WARN("invalid parameter: 3D buffer format must be mono\n");
1635 return DSERR_INVALIDPARAM;
1638 hres = IDirectSoundBufferImpl_Create(device, &dsb, dsbd);
1639 if (dsb)
1640 *ppdsb = (IDirectSoundBuffer*)&dsb->IDirectSoundBuffer8_iface;
1641 else
1642 WARN("IDirectSoundBufferImpl_Create failed\n");
1645 return hres;
1648 HRESULT DirectSoundDevice_DuplicateSoundBuffer(
1649 DirectSoundDevice * device,
1650 LPDIRECTSOUNDBUFFER psb,
1651 LPLPDIRECTSOUNDBUFFER ppdsb)
1653 HRESULT hres = DS_OK;
1654 IDirectSoundBufferImpl* dsb;
1655 TRACE("(%p,%p,%p)\n",device,psb,ppdsb);
1657 if (device == NULL) {
1658 WARN("not initialized\n");
1659 return DSERR_UNINITIALIZED;
1662 if (psb == NULL) {
1663 WARN("invalid parameter: psb == NULL\n");
1664 return DSERR_INVALIDPARAM;
1667 if (ppdsb == NULL) {
1668 WARN("invalid parameter: ppdsb == NULL\n");
1669 return DSERR_INVALIDPARAM;
1672 /* make sure we have a secondary buffer */
1673 if (psb == (IDirectSoundBuffer *)&device->primary->IDirectSoundBuffer8_iface) {
1674 WARN("trying to duplicate primary buffer\n");
1675 *ppdsb = NULL;
1676 return DSERR_INVALIDCALL;
1679 /* duplicate the actual buffer implementation */
1680 hres = IDirectSoundBufferImpl_Duplicate(device, &dsb, (IDirectSoundBufferImpl*)psb);
1681 if (hres == DS_OK)
1682 *ppdsb = (IDirectSoundBuffer*)&dsb->IDirectSoundBuffer8_iface;
1683 else
1684 WARN("IDirectSoundBufferImpl_Duplicate failed\n");
1686 return hres;
1689 HRESULT DirectSoundDevice_SetCooperativeLevel(
1690 DirectSoundDevice * device,
1691 HWND hwnd,
1692 DWORD level)
1694 TRACE("(%p,%p,%s)\n",device,hwnd,dumpCooperativeLevel(level));
1696 if (device == NULL) {
1697 WARN("not initialized\n");
1698 return DSERR_UNINITIALIZED;
1701 if (level==DSSCL_PRIORITY || level==DSSCL_EXCLUSIVE) {
1702 WARN("level=%s not fully supported\n",
1703 level==DSSCL_PRIORITY ? "DSSCL_PRIORITY" : "DSSCL_EXCLUSIVE");
1706 device->priolevel = level;
1707 return DS_OK;
1710 HRESULT DirectSoundDevice_Compact(
1711 DirectSoundDevice * device)
1713 TRACE("(%p)\n", device);
1715 if (device == NULL) {
1716 WARN("not initialized\n");
1717 return DSERR_UNINITIALIZED;
1720 if (device->priolevel < DSSCL_PRIORITY) {
1721 WARN("incorrect priority level\n");
1722 return DSERR_PRIOLEVELNEEDED;
1725 return DS_OK;
1728 HRESULT DirectSoundDevice_GetSpeakerConfig(
1729 DirectSoundDevice * device,
1730 LPDWORD lpdwSpeakerConfig)
1732 TRACE("(%p, %p)\n", device, lpdwSpeakerConfig);
1734 if (device == NULL) {
1735 WARN("not initialized\n");
1736 return DSERR_UNINITIALIZED;
1739 if (lpdwSpeakerConfig == NULL) {
1740 WARN("invalid parameter: lpdwSpeakerConfig == NULL\n");
1741 return DSERR_INVALIDPARAM;
1744 WARN("not fully functional\n");
1745 *lpdwSpeakerConfig = device->speaker_config;
1746 return DS_OK;
1749 HRESULT DirectSoundDevice_SetSpeakerConfig(
1750 DirectSoundDevice * device,
1751 DWORD config)
1753 TRACE("(%p,0x%08x)\n",device,config);
1755 if (device == NULL) {
1756 WARN("not initialized\n");
1757 return DSERR_UNINITIALIZED;
1760 device->speaker_config = config;
1761 WARN("not fully functional\n");
1762 return DS_OK;
1765 HRESULT DirectSoundDevice_VerifyCertification(
1766 DirectSoundDevice * device,
1767 LPDWORD pdwCertified)
1769 TRACE("(%p, %p)\n",device,pdwCertified);
1771 if (device == NULL) {
1772 WARN("not initialized\n");
1773 return DSERR_UNINITIALIZED;
1776 if (device->drvcaps.dwFlags & DSCAPS_CERTIFIED)
1777 *pdwCertified = DS_CERTIFIED;
1778 else
1779 *pdwCertified = DS_UNCERTIFIED;
1781 return DS_OK;
1785 * Add secondary buffer to buffer list.
1786 * Gets exclusive access to buffer for writing.
1788 HRESULT DirectSoundDevice_AddBuffer(
1789 DirectSoundDevice * device,
1790 IDirectSoundBufferImpl * pDSB)
1792 IDirectSoundBufferImpl **newbuffers;
1793 HRESULT hr = DS_OK;
1795 TRACE("(%p, %p)\n", device, pDSB);
1797 RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
1799 if (device->buffers)
1800 newbuffers = HeapReAlloc(GetProcessHeap(),0,device->buffers,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
1801 else
1802 newbuffers = HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
1804 if (newbuffers) {
1805 device->buffers = newbuffers;
1806 device->buffers[device->nrofbuffers] = pDSB;
1807 device->nrofbuffers++;
1808 TRACE("buffer count is now %d\n", device->nrofbuffers);
1809 } else {
1810 ERR("out of memory for buffer list! Current buffer count is %d\n", device->nrofbuffers);
1811 hr = DSERR_OUTOFMEMORY;
1814 RtlReleaseResource(&(device->buffer_list_lock));
1816 return hr;
1820 * Remove secondary buffer from buffer list.
1821 * Gets exclusive access to buffer for writing.
1823 HRESULT DirectSoundDevice_RemoveBuffer(
1824 DirectSoundDevice * device,
1825 IDirectSoundBufferImpl * pDSB)
1827 int i;
1828 HRESULT hr = DS_OK;
1830 TRACE("(%p, %p)\n", device, pDSB);
1832 RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
1834 for (i = 0; i < device->nrofbuffers; i++)
1835 if (device->buffers[i] == pDSB)
1836 break;
1838 if (i < device->nrofbuffers) {
1839 /* Put the last buffer of the list in the (now empty) position */
1840 device->buffers[i] = device->buffers[device->nrofbuffers - 1];
1841 device->nrofbuffers--;
1842 device->buffers = HeapReAlloc(GetProcessHeap(),0,device->buffers,sizeof(LPDIRECTSOUNDBUFFER8)*device->nrofbuffers);
1843 TRACE("buffer count is now %d\n", device->nrofbuffers);
1846 if (device->nrofbuffers == 0) {
1847 HeapFree(GetProcessHeap(),0,device->buffers);
1848 device->buffers = NULL;
1851 RtlReleaseResource(&(device->buffer_list_lock));
1853 return hr;