dsound: Convert IDirectSoundImpl from a COM class to a regular class
[wine/hacks.git] / dlls / dsound / dsound.c
blob99400c2c29c98ef0621f1091bb7a7300ca01a47a
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include <stdarg.h>
24 #include <stdio.h>
26 #define NONAMELESSSTRUCT
27 #define NONAMELESSUNION
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winuser.h"
31 #include "winreg.h"
32 #include "mmsystem.h"
33 #include "winternl.h"
34 #include "mmddk.h"
35 #include "wine/debug.h"
36 #include "dsound.h"
37 #include "dsdriver.h"
38 #include "dsound_private.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
42 static ULONG WINAPI IDirectSound_IUnknown_AddRef(LPUNKNOWN iface);
43 static ULONG WINAPI IDirectSound_IDirectSound_AddRef(LPDIRECTSOUND iface);
44 static ULONG WINAPI IDirectSound8_IUnknown_AddRef(LPUNKNOWN iface);
45 static ULONG WINAPI IDirectSound8_IDirectSound_AddRef(LPDIRECTSOUND iface);
46 static ULONG WINAPI IDirectSound8_IDirectSound8_AddRef(LPDIRECTSOUND8 iface);
48 const char * dumpCooperativeLevel(DWORD level)
50 static char unknown[32];
51 #define LE(x) case x: return #x
52 switch (level) {
53 LE(DSSCL_NORMAL);
54 LE(DSSCL_PRIORITY);
55 LE(DSSCL_EXCLUSIVE);
56 LE(DSSCL_WRITEPRIMARY);
58 #undef LE
59 sprintf(unknown, "Unknown(%08lx)", level);
60 return unknown;
63 static void _dump_DSCAPS(DWORD xmask) {
64 struct {
65 DWORD mask;
66 const char *name;
67 } flags[] = {
68 #define FE(x) { x, #x },
69 FE(DSCAPS_PRIMARYMONO)
70 FE(DSCAPS_PRIMARYSTEREO)
71 FE(DSCAPS_PRIMARY8BIT)
72 FE(DSCAPS_PRIMARY16BIT)
73 FE(DSCAPS_CONTINUOUSRATE)
74 FE(DSCAPS_EMULDRIVER)
75 FE(DSCAPS_CERTIFIED)
76 FE(DSCAPS_SECONDARYMONO)
77 FE(DSCAPS_SECONDARYSTEREO)
78 FE(DSCAPS_SECONDARY8BIT)
79 FE(DSCAPS_SECONDARY16BIT)
80 #undef FE
82 unsigned int i;
84 for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
85 if ((flags[i].mask & xmask) == flags[i].mask)
86 DPRINTF("%s ",flags[i].name);
89 static void _dump_DSBCAPS(DWORD xmask) {
90 struct {
91 DWORD mask;
92 const char *name;
93 } flags[] = {
94 #define FE(x) { x, #x },
95 FE(DSBCAPS_PRIMARYBUFFER)
96 FE(DSBCAPS_STATIC)
97 FE(DSBCAPS_LOCHARDWARE)
98 FE(DSBCAPS_LOCSOFTWARE)
99 FE(DSBCAPS_CTRL3D)
100 FE(DSBCAPS_CTRLFREQUENCY)
101 FE(DSBCAPS_CTRLPAN)
102 FE(DSBCAPS_CTRLVOLUME)
103 FE(DSBCAPS_CTRLPOSITIONNOTIFY)
104 FE(DSBCAPS_STICKYFOCUS)
105 FE(DSBCAPS_GLOBALFOCUS)
106 FE(DSBCAPS_GETCURRENTPOSITION2)
107 FE(DSBCAPS_MUTE3DATMAXDISTANCE)
108 #undef FE
110 unsigned int i;
112 for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
113 if ((flags[i].mask & xmask) == flags[i].mask)
114 DPRINTF("%s ",flags[i].name);
117 /*******************************************************************************
118 * IDirectSoundImpl_DirectSound
120 static HRESULT DSOUND_QueryInterface(
121 LPDIRECTSOUND8 iface,
122 REFIID riid,
123 LPVOID * ppobj)
125 IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
126 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
128 if (ppobj == NULL) {
129 WARN("invalid parameter\n");
130 return E_INVALIDARG;
133 if (IsEqualIID(riid, &IID_IUnknown)) {
134 if (!This->pUnknown) {
135 IDirectSound_IUnknown_Create(iface, &This->pUnknown);
136 if (!This->pUnknown) {
137 WARN("IDirectSound_IUnknown_Create() failed\n");
138 *ppobj = NULL;
139 return E_NOINTERFACE;
142 IDirectSound_IUnknown_AddRef(This->pUnknown);
143 *ppobj = This->pUnknown;
144 return S_OK;
145 } else if (IsEqualIID(riid, &IID_IDirectSound)) {
146 if (!This->pDS) {
147 IDirectSound_IDirectSound_Create(iface, &This->pDS);
148 if (!This->pDS) {
149 WARN("IDirectSound_IDirectSound_Create() failed\n");
150 *ppobj = NULL;
151 return E_NOINTERFACE;
154 IDirectSound_IDirectSound_AddRef(This->pDS);
155 *ppobj = This->pDS;
156 return S_OK;
159 *ppobj = NULL;
160 WARN("Unknown IID %s\n",debugstr_guid(riid));
161 return E_NOINTERFACE;
164 static HRESULT DSOUND_QueryInterface8(
165 LPDIRECTSOUND8 iface,
166 REFIID riid,
167 LPVOID * ppobj)
169 IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
170 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
172 if (ppobj == NULL) {
173 WARN("invalid parameter\n");
174 return E_INVALIDARG;
177 if (IsEqualIID(riid, &IID_IUnknown)) {
178 if (!This->pUnknown) {
179 IDirectSound8_IUnknown_Create(iface, &This->pUnknown);
180 if (!This->pUnknown) {
181 WARN("IDirectSound8_IUnknown_Create() failed\n");
182 *ppobj = NULL;
183 return E_NOINTERFACE;
186 IDirectSound8_IUnknown_AddRef(This->pUnknown);
187 *ppobj = This->pUnknown;
188 return S_OK;
189 } else if (IsEqualIID(riid, &IID_IDirectSound)) {
190 if (!This->pDS) {
191 IDirectSound8_IDirectSound_Create(iface, &This->pDS);
192 if (!This->pDS) {
193 WARN("IDirectSound8_IDirectSound_Create() failed\n");
194 *ppobj = NULL;
195 return E_NOINTERFACE;
198 IDirectSound8_IDirectSound_AddRef(This->pDS);
199 *ppobj = This->pDS;
200 return S_OK;
201 } else if (IsEqualIID(riid, &IID_IDirectSound8)) {
202 if (!This->pDS8) {
203 IDirectSound8_IDirectSound8_Create(iface, &This->pDS8);
204 if (!This->pDS8) {
205 WARN("IDirectSound8_IDirectSound8_Create() failed\n");
206 *ppobj = NULL;
207 return E_NOINTERFACE;
210 IDirectSound8_IDirectSound8_AddRef(This->pDS8);
211 *ppobj = This->pDS8;
212 return S_OK;
215 *ppobj = NULL;
216 WARN("Unknown IID %s\n",debugstr_guid(riid));
217 return E_NOINTERFACE;
220 static ULONG IDirectSoundImpl_AddRef(
221 LPDIRECTSOUND8 iface)
223 IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
224 ULONG ref = InterlockedIncrement(&(This->ref));
225 TRACE("(%p) ref was %ld\n", This, ref - 1);
226 return ref;
229 static ULONG IDirectSoundImpl_Release(
230 LPDIRECTSOUND8 iface)
232 IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
233 ULONG ref = InterlockedDecrement(&(This->ref));
234 TRACE("(%p) ref was %ld\n", This, ref + 1);
236 if (!ref) {
237 if (This->device)
238 DirectSoundDevice_Release(This->device);
239 HeapFree(GetProcessHeap(),0,This);
240 TRACE("(%p) released\n", This);
242 return ref;
245 HRESULT IDirectSoundImpl_Create(
246 LPDIRECTSOUND8 * ppDS)
248 IDirectSoundImpl* pDS;
249 TRACE("(%p)\n",ppDS);
251 /* Allocate memory */
252 pDS = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundImpl));
253 if (pDS == NULL) {
254 WARN("out of memory\n");
255 *ppDS = NULL;
256 return DSERR_OUTOFMEMORY;
259 pDS->ref = 0;
260 pDS->device = NULL;
262 *ppDS = (LPDIRECTSOUND8)pDS;
264 return DS_OK;
267 /*******************************************************************************
268 * IDirectSound_IUnknown
270 static HRESULT WINAPI IDirectSound_IUnknown_QueryInterface(
271 LPUNKNOWN iface,
272 REFIID riid,
273 LPVOID * ppobj)
275 IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
276 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
277 return DSOUND_QueryInterface(This->pds, riid, ppobj);
280 static ULONG WINAPI IDirectSound_IUnknown_AddRef(
281 LPUNKNOWN iface)
283 IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
284 ULONG ref = InterlockedIncrement(&(This->ref));
285 TRACE("(%p) ref was %ld\n", This, ref - 1);
286 return ref;
289 static ULONG WINAPI IDirectSound_IUnknown_Release(
290 LPUNKNOWN iface)
292 IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
293 ULONG ref = InterlockedDecrement(&(This->ref));
294 TRACE("(%p) ref was %ld\n", This, ref + 1);
295 if (!ref) {
296 IDirectSoundImpl_Release(This->pds);
297 HeapFree(GetProcessHeap(), 0, This);
298 TRACE("(%p) released\n", This);
300 return ref;
303 static const IUnknownVtbl DirectSound_Unknown_Vtbl =
305 IDirectSound_IUnknown_QueryInterface,
306 IDirectSound_IUnknown_AddRef,
307 IDirectSound_IUnknown_Release
310 HRESULT IDirectSound_IUnknown_Create(
311 LPDIRECTSOUND8 pds,
312 LPUNKNOWN * ppunk)
314 IDirectSound_IUnknown * pdsunk;
315 TRACE("(%p,%p)\n",pds,ppunk);
317 if (ppunk == NULL) {
318 ERR("invalid parameter: ppunk == NULL\n");
319 return DSERR_INVALIDPARAM;
322 if (pds == NULL) {
323 ERR("invalid parameter: pds == NULL\n");
324 *ppunk = NULL;
325 return DSERR_INVALIDPARAM;
328 pdsunk = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsunk));
329 if (pdsunk == NULL) {
330 WARN("out of memory\n");
331 *ppunk = NULL;
332 return DSERR_OUTOFMEMORY;
335 pdsunk->lpVtbl = &DirectSound_Unknown_Vtbl;
336 pdsunk->ref = 0;
337 pdsunk->pds = pds;
339 IDirectSoundImpl_AddRef(pds);
340 *ppunk = (LPUNKNOWN)pdsunk;
342 return DS_OK;
345 /*******************************************************************************
346 * IDirectSound_IDirectSound
348 static HRESULT WINAPI IDirectSound_IDirectSound_QueryInterface(
349 LPDIRECTSOUND iface,
350 REFIID riid,
351 LPVOID * ppobj)
353 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
354 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
355 return DSOUND_QueryInterface(This->pds, riid, ppobj);
358 static ULONG WINAPI IDirectSound_IDirectSound_AddRef(
359 LPDIRECTSOUND iface)
361 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
362 ULONG ref = InterlockedIncrement(&(This->ref));
363 TRACE("(%p) ref was %ld\n", This, ref - 1);
364 return ref;
367 static ULONG WINAPI IDirectSound_IDirectSound_Release(
368 LPDIRECTSOUND iface)
370 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
371 ULONG ref = InterlockedDecrement(&(This->ref));
372 TRACE("(%p) ref was %ld\n", This, ref + 1);
373 if (!ref) {
374 IDirectSoundImpl_Release(This->pds);
375 HeapFree(GetProcessHeap(), 0, This);
376 TRACE("(%p) released\n", This);
378 return ref;
381 static HRESULT WINAPI IDirectSound_IDirectSound_CreateSoundBuffer(
382 LPDIRECTSOUND iface,
383 LPCDSBUFFERDESC dsbd,
384 LPLPDIRECTSOUNDBUFFER ppdsb,
385 LPUNKNOWN lpunk)
387 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
388 TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
389 return DirectSoundDevice_CreateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,dsbd,ppdsb,lpunk,FALSE);
392 static HRESULT WINAPI IDirectSound_IDirectSound_GetCaps(
393 LPDIRECTSOUND iface,
394 LPDSCAPS lpDSCaps)
396 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
397 TRACE("(%p,%p)\n",This,lpDSCaps);
398 return DirectSoundDevice_GetCaps(((IDirectSoundImpl *)This->pds)->device, lpDSCaps);
401 static HRESULT WINAPI IDirectSound_IDirectSound_DuplicateSoundBuffer(
402 LPDIRECTSOUND iface,
403 LPDIRECTSOUNDBUFFER psb,
404 LPLPDIRECTSOUNDBUFFER ppdsb)
406 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
407 TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
408 return DirectSoundDevice_DuplicateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,psb,ppdsb);
411 static HRESULT WINAPI IDirectSound_IDirectSound_SetCooperativeLevel(
412 LPDIRECTSOUND iface,
413 HWND hwnd,
414 DWORD level)
416 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
417 TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level));
418 return DirectSoundDevice_SetCooperativeLevel(((IDirectSoundImpl *)This->pds)->device, hwnd, level);
421 static HRESULT WINAPI IDirectSound_IDirectSound_Compact(
422 LPDIRECTSOUND iface)
424 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
425 TRACE("(%p)\n", This);
426 return DirectSoundDevice_Compact(((IDirectSoundImpl *)This->pds)->device);
429 static HRESULT WINAPI IDirectSound_IDirectSound_GetSpeakerConfig(
430 LPDIRECTSOUND iface,
431 LPDWORD lpdwSpeakerConfig)
433 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
434 TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
435 return DirectSoundDevice_GetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,lpdwSpeakerConfig);
438 static HRESULT WINAPI IDirectSound_IDirectSound_SetSpeakerConfig(
439 LPDIRECTSOUND iface,
440 DWORD config)
442 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
443 TRACE("(%p,0x%08lx)\n",This,config);
444 return DirectSoundDevice_SetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,config);
447 static HRESULT WINAPI IDirectSound_IDirectSound_Initialize(
448 LPDIRECTSOUND iface,
449 LPCGUID lpcGuid)
451 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
452 TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
453 return DirectSoundDevice_Initialize(&((IDirectSoundImpl *)This->pds)->device,lpcGuid);
456 static const IDirectSoundVtbl DirectSound_DirectSound_Vtbl =
458 IDirectSound_IDirectSound_QueryInterface,
459 IDirectSound_IDirectSound_AddRef,
460 IDirectSound_IDirectSound_Release,
461 IDirectSound_IDirectSound_CreateSoundBuffer,
462 IDirectSound_IDirectSound_GetCaps,
463 IDirectSound_IDirectSound_DuplicateSoundBuffer,
464 IDirectSound_IDirectSound_SetCooperativeLevel,
465 IDirectSound_IDirectSound_Compact,
466 IDirectSound_IDirectSound_GetSpeakerConfig,
467 IDirectSound_IDirectSound_SetSpeakerConfig,
468 IDirectSound_IDirectSound_Initialize
471 HRESULT IDirectSound_IDirectSound_Create(
472 LPDIRECTSOUND8 pds,
473 LPDIRECTSOUND * ppds)
475 IDirectSound_IDirectSound * pdsds;
476 TRACE("(%p,%p)\n",pds,ppds);
478 if (ppds == NULL) {
479 ERR("invalid parameter: ppds == NULL\n");
480 return DSERR_INVALIDPARAM;
483 if (pds == NULL) {
484 ERR("invalid parameter: pds == NULL\n");
485 *ppds = NULL;
486 return DSERR_INVALIDPARAM;
489 pdsds = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsds));
490 if (pdsds == NULL) {
491 WARN("out of memory\n");
492 *ppds = NULL;
493 return DSERR_OUTOFMEMORY;
496 pdsds->lpVtbl = &DirectSound_DirectSound_Vtbl;
497 pdsds->ref = 0;
498 pdsds->pds = pds;
500 IDirectSoundImpl_AddRef(pds);
501 *ppds = (LPDIRECTSOUND)pdsds;
503 return DS_OK;
506 /*******************************************************************************
507 * IDirectSound8_IUnknown
509 static HRESULT WINAPI IDirectSound8_IUnknown_QueryInterface(
510 LPUNKNOWN iface,
511 REFIID riid,
512 LPVOID * ppobj)
514 IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
515 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
516 return DSOUND_QueryInterface8(This->pds, riid, ppobj);
519 static ULONG WINAPI IDirectSound8_IUnknown_AddRef(
520 LPUNKNOWN iface)
522 IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
523 ULONG ref = InterlockedIncrement(&(This->ref));
524 TRACE("(%p) ref was %ld\n", This, ref - 1);
525 return ref;
528 static ULONG WINAPI IDirectSound8_IUnknown_Release(
529 LPUNKNOWN iface)
531 IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
532 ULONG ref = InterlockedDecrement(&(This->ref));
533 TRACE("(%p) ref was %ld\n", This, ref + 1);
534 if (!ref) {
535 IDirectSoundImpl_Release(This->pds);
536 HeapFree(GetProcessHeap(), 0, This);
537 TRACE("(%p) released\n", This);
539 return ref;
542 static const IUnknownVtbl DirectSound8_Unknown_Vtbl =
544 IDirectSound8_IUnknown_QueryInterface,
545 IDirectSound8_IUnknown_AddRef,
546 IDirectSound8_IUnknown_Release
549 HRESULT IDirectSound8_IUnknown_Create(
550 LPDIRECTSOUND8 pds,
551 LPUNKNOWN * ppunk)
553 IDirectSound8_IUnknown * pdsunk;
554 TRACE("(%p,%p)\n",pds,ppunk);
556 if (ppunk == NULL) {
557 ERR("invalid parameter: ppunk == NULL\n");
558 return DSERR_INVALIDPARAM;
561 if (pds == NULL) {
562 ERR("invalid parameter: pds == NULL\n");
563 *ppunk = NULL;
564 return DSERR_INVALIDPARAM;
567 pdsunk = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsunk));
568 if (pdsunk == NULL) {
569 WARN("out of memory\n");
570 *ppunk = NULL;
571 return DSERR_OUTOFMEMORY;
574 pdsunk->lpVtbl = &DirectSound8_Unknown_Vtbl;
575 pdsunk->ref = 0;
576 pdsunk->pds = pds;
578 IDirectSoundImpl_AddRef(pds);
579 *ppunk = (LPUNKNOWN)pdsunk;
581 return DS_OK;
584 /*******************************************************************************
585 * IDirectSound8_IDirectSound
587 static HRESULT WINAPI IDirectSound8_IDirectSound_QueryInterface(
588 LPDIRECTSOUND iface,
589 REFIID riid,
590 LPVOID * ppobj)
592 IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
593 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
594 return DSOUND_QueryInterface8(This->pds, riid, ppobj);
597 static ULONG WINAPI IDirectSound8_IDirectSound_AddRef(
598 LPDIRECTSOUND iface)
600 IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
601 ULONG ref = InterlockedIncrement(&(This->ref));
602 TRACE("(%p) ref was %ld\n", This, ref - 1);
603 return ref;
606 static ULONG WINAPI IDirectSound8_IDirectSound_Release(
607 LPDIRECTSOUND iface)
609 IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
610 ULONG ref = InterlockedDecrement(&(This->ref));
611 TRACE("(%p) ref was %ld\n", This, ref + 1);
612 if (!ref) {
613 IDirectSoundImpl_Release(This->pds);
614 HeapFree(GetProcessHeap(), 0, This);
615 TRACE("(%p) released\n", This);
617 return ref;
620 static HRESULT WINAPI IDirectSound8_IDirectSound_CreateSoundBuffer(
621 LPDIRECTSOUND iface,
622 LPCDSBUFFERDESC dsbd,
623 LPLPDIRECTSOUNDBUFFER ppdsb,
624 LPUNKNOWN lpunk)
626 IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
627 TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
628 return DirectSoundDevice_CreateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,dsbd,ppdsb,lpunk,TRUE);
631 static HRESULT WINAPI IDirectSound8_IDirectSound_GetCaps(
632 LPDIRECTSOUND iface,
633 LPDSCAPS lpDSCaps)
635 IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
636 TRACE("(%p,%p)\n",This,lpDSCaps);
637 return DirectSoundDevice_GetCaps(((IDirectSoundImpl *)This->pds)->device, lpDSCaps);
640 static HRESULT WINAPI IDirectSound8_IDirectSound_DuplicateSoundBuffer(
641 LPDIRECTSOUND iface,
642 LPDIRECTSOUNDBUFFER psb,
643 LPLPDIRECTSOUNDBUFFER ppdsb)
645 IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
646 TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
647 return DirectSoundDevice_DuplicateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,psb,ppdsb);
650 static HRESULT WINAPI IDirectSound8_IDirectSound_SetCooperativeLevel(
651 LPDIRECTSOUND iface,
652 HWND hwnd,
653 DWORD level)
655 IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
656 TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level));
657 return DirectSoundDevice_SetCooperativeLevel(((IDirectSoundImpl *)This->pds)->device, hwnd, level);
660 static HRESULT WINAPI IDirectSound8_IDirectSound_Compact(
661 LPDIRECTSOUND iface)
663 IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
664 TRACE("(%p)\n", This);
665 return DirectSoundDevice_Compact(((IDirectSoundImpl *)This->pds)->device);
668 static HRESULT WINAPI IDirectSound8_IDirectSound_GetSpeakerConfig(
669 LPDIRECTSOUND iface,
670 LPDWORD lpdwSpeakerConfig)
672 IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
673 TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
674 return DirectSoundDevice_GetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,lpdwSpeakerConfig);
677 static HRESULT WINAPI IDirectSound8_IDirectSound_SetSpeakerConfig(
678 LPDIRECTSOUND iface,
679 DWORD config)
681 IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
682 TRACE("(%p,0x%08lx)\n",This,config);
683 return DirectSoundDevice_SetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,config);
686 static HRESULT WINAPI IDirectSound8_IDirectSound_Initialize(
687 LPDIRECTSOUND iface,
688 LPCGUID lpcGuid)
690 IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
691 TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
692 return DirectSoundDevice_Initialize(&((IDirectSoundImpl *)This->pds)->device,lpcGuid);
695 static const IDirectSoundVtbl DirectSound8_DirectSound_Vtbl =
697 IDirectSound8_IDirectSound_QueryInterface,
698 IDirectSound8_IDirectSound_AddRef,
699 IDirectSound8_IDirectSound_Release,
700 IDirectSound8_IDirectSound_CreateSoundBuffer,
701 IDirectSound8_IDirectSound_GetCaps,
702 IDirectSound8_IDirectSound_DuplicateSoundBuffer,
703 IDirectSound8_IDirectSound_SetCooperativeLevel,
704 IDirectSound8_IDirectSound_Compact,
705 IDirectSound8_IDirectSound_GetSpeakerConfig,
706 IDirectSound8_IDirectSound_SetSpeakerConfig,
707 IDirectSound8_IDirectSound_Initialize
710 HRESULT IDirectSound8_IDirectSound_Create(
711 LPDIRECTSOUND8 pds,
712 LPDIRECTSOUND * ppds)
714 IDirectSound8_IDirectSound * pdsds;
715 TRACE("(%p,%p)\n",pds,ppds);
717 if (ppds == NULL) {
718 ERR("invalid parameter: ppds == NULL\n");
719 return DSERR_INVALIDPARAM;
722 if (pds == NULL) {
723 ERR("invalid parameter: pds == NULL\n");
724 *ppds = NULL;
725 return DSERR_INVALIDPARAM;
728 pdsds = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsds));
729 if (pdsds == NULL) {
730 WARN("out of memory\n");
731 *ppds = NULL;
732 return DSERR_OUTOFMEMORY;
735 pdsds->lpVtbl = &DirectSound8_DirectSound_Vtbl;
736 pdsds->ref = 0;
737 pdsds->pds = pds;
739 IDirectSoundImpl_AddRef(pds);
740 *ppds = (LPDIRECTSOUND)pdsds;
742 return DS_OK;
745 /*******************************************************************************
746 * IDirectSound8_IDirectSound8
748 static HRESULT WINAPI IDirectSound8_IDirectSound8_QueryInterface(
749 LPDIRECTSOUND8 iface,
750 REFIID riid,
751 LPVOID * ppobj)
753 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
754 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
755 return DSOUND_QueryInterface8(This->pds, riid, ppobj);
758 static ULONG WINAPI IDirectSound8_IDirectSound8_AddRef(
759 LPDIRECTSOUND8 iface)
761 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
762 ULONG ref = InterlockedIncrement(&(This->ref));
763 TRACE("(%p) ref was %ld\n", This, ref - 1);
764 return ref;
767 static ULONG WINAPI IDirectSound8_IDirectSound8_Release(
768 LPDIRECTSOUND8 iface)
770 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
771 ULONG ref = InterlockedDecrement(&(This->ref));
772 TRACE("(%p) ref was %ld\n", This, ref + 1);
773 if (!ref) {
774 IDirectSoundImpl_Release(This->pds);
775 HeapFree(GetProcessHeap(), 0, This);
776 TRACE("(%p) released\n", This);
778 return ref;
781 static HRESULT WINAPI IDirectSound8_IDirectSound8_CreateSoundBuffer(
782 LPDIRECTSOUND8 iface,
783 LPCDSBUFFERDESC dsbd,
784 LPLPDIRECTSOUNDBUFFER ppdsb,
785 LPUNKNOWN lpunk)
787 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
788 TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
789 return DirectSoundDevice_CreateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,dsbd,ppdsb,lpunk,TRUE);
792 static HRESULT WINAPI IDirectSound8_IDirectSound8_GetCaps(
793 LPDIRECTSOUND8 iface,
794 LPDSCAPS lpDSCaps)
796 IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
797 TRACE("(%p,%p)\n",This,lpDSCaps);
798 return DirectSoundDevice_GetCaps(((IDirectSoundImpl *)This->pds)->device, lpDSCaps);
801 static HRESULT WINAPI IDirectSound8_IDirectSound8_DuplicateSoundBuffer(
802 LPDIRECTSOUND8 iface,
803 LPDIRECTSOUNDBUFFER psb,
804 LPLPDIRECTSOUNDBUFFER ppdsb)
806 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
807 TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
808 return DirectSoundDevice_DuplicateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,psb,ppdsb);
811 static HRESULT WINAPI IDirectSound8_IDirectSound8_SetCooperativeLevel(
812 LPDIRECTSOUND8 iface,
813 HWND hwnd,
814 DWORD level)
816 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
817 TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level));
818 return DirectSoundDevice_SetCooperativeLevel(((IDirectSoundImpl *)This->pds)->device, hwnd, level);
821 static HRESULT WINAPI IDirectSound8_IDirectSound8_Compact(
822 LPDIRECTSOUND8 iface)
824 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
825 TRACE("(%p)\n", This);
826 return DirectSoundDevice_Compact(((IDirectSoundImpl *)This->pds)->device);
829 static HRESULT WINAPI IDirectSound8_IDirectSound8_GetSpeakerConfig(
830 LPDIRECTSOUND8 iface,
831 LPDWORD lpdwSpeakerConfig)
833 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
834 TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
835 return DirectSoundDevice_GetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,lpdwSpeakerConfig);
838 static HRESULT WINAPI IDirectSound8_IDirectSound8_SetSpeakerConfig(
839 LPDIRECTSOUND8 iface,
840 DWORD config)
842 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
843 TRACE("(%p,0x%08lx)\n",This,config);
844 return DirectSoundDevice_SetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,config);
847 static HRESULT WINAPI IDirectSound8_IDirectSound8_Initialize(
848 LPDIRECTSOUND8 iface,
849 LPCGUID lpcGuid)
851 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
852 TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
853 return DirectSoundDevice_Initialize(&((IDirectSoundImpl *)This->pds)->device,lpcGuid);
856 static HRESULT WINAPI IDirectSound8_IDirectSound8_VerifyCertification(
857 LPDIRECTSOUND8 iface,
858 LPDWORD pdwCertified)
860 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
861 TRACE("(%p, %p)\n", This, pdwCertified);
862 return DirectSoundDevice_VerifyCertification(((IDirectSoundImpl *)This->pds)->device,pdwCertified);
865 static const IDirectSound8Vtbl DirectSound8_DirectSound8_Vtbl =
867 IDirectSound8_IDirectSound8_QueryInterface,
868 IDirectSound8_IDirectSound8_AddRef,
869 IDirectSound8_IDirectSound8_Release,
870 IDirectSound8_IDirectSound8_CreateSoundBuffer,
871 IDirectSound8_IDirectSound8_GetCaps,
872 IDirectSound8_IDirectSound8_DuplicateSoundBuffer,
873 IDirectSound8_IDirectSound8_SetCooperativeLevel,
874 IDirectSound8_IDirectSound8_Compact,
875 IDirectSound8_IDirectSound8_GetSpeakerConfig,
876 IDirectSound8_IDirectSound8_SetSpeakerConfig,
877 IDirectSound8_IDirectSound8_Initialize,
878 IDirectSound8_IDirectSound8_VerifyCertification
881 HRESULT IDirectSound8_IDirectSound8_Create(
882 LPDIRECTSOUND8 pds,
883 LPDIRECTSOUND8 * ppds)
885 IDirectSound8_IDirectSound8 * pdsds;
886 TRACE("(%p,%p)\n",pds,ppds);
888 if (ppds == NULL) {
889 ERR("invalid parameter: ppds == NULL\n");
890 return DSERR_INVALIDPARAM;
893 if (pds == NULL) {
894 ERR("invalid parameter: pds == NULL\n");
895 *ppds = NULL;
896 return DSERR_INVALIDPARAM;
899 pdsds = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsds));
900 if (pdsds == NULL) {
901 WARN("out of memory\n");
902 *ppds = NULL;
903 return DSERR_OUTOFMEMORY;
906 pdsds->lpVtbl = &DirectSound8_DirectSound8_Vtbl;
907 pdsds->ref = 0;
908 pdsds->pds = pds;
910 IDirectSoundImpl_AddRef(pds);
911 *ppds = (LPDIRECTSOUND8)pdsds;
913 return DS_OK;
916 HRESULT DSOUND_Create(
917 LPDIRECTSOUND *ppDS,
918 IUnknown *pUnkOuter)
920 LPDIRECTSOUND8 pDS;
921 HRESULT hr;
922 TRACE("(%p,%p)\n",ppDS,pUnkOuter);
924 /* Get dsound configuration */
925 setup_dsound_options();
927 hr = IDirectSoundImpl_Create(&pDS);
928 if (hr == DS_OK) {
929 hr = IDirectSound_IDirectSound_Create(pDS, ppDS);
930 if (*ppDS)
931 IDirectSound_IDirectSound_AddRef(*ppDS);
932 else {
933 WARN("IDirectSound_IDirectSound_Create failed\n");
934 IDirectSound8_Release(pDS);
936 } else {
937 WARN("IDirectSoundImpl_Create failed\n");
938 *ppDS = 0;
941 return hr;
944 /*******************************************************************************
945 * DirectSoundCreate (DSOUND.1)
947 * Creates and initializes a DirectSound interface.
949 * PARAMS
950 * lpcGUID [I] Address of the GUID that identifies the sound device.
951 * ppDS [O] Address of a variable to receive the interface pointer.
952 * pUnkOuter [I] Must be NULL.
954 * RETURNS
955 * Success: DS_OK
956 * Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
957 * DSERR_NODRIVER, DSERR_OUTOFMEMORY
959 HRESULT WINAPI DirectSoundCreate(
960 LPCGUID lpcGUID,
961 LPDIRECTSOUND *ppDS,
962 IUnknown *pUnkOuter)
964 HRESULT hr;
965 LPDIRECTSOUND pDS;
967 TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
969 if (ppDS == NULL) {
970 WARN("invalid parameter: ppDS == NULL\n");
971 return DSERR_INVALIDPARAM;
974 if (pUnkOuter != NULL) {
975 WARN("invalid parameter: pUnkOuter != NULL\n");
976 *ppDS = 0;
977 return DSERR_INVALIDPARAM;
980 hr = DSOUND_Create(&pDS, pUnkOuter);
981 if (hr == DS_OK) {
982 hr = IDirectSound_Initialize(pDS, lpcGUID);
983 if (hr != DS_OK) {
984 if (hr != DSERR_ALREADYINITIALIZED) {
985 IDirectSound_Release(pDS);
986 pDS = 0;
987 } else
988 hr = DS_OK;
992 *ppDS = pDS;
994 return hr;
997 HRESULT DSOUND_Create8(
998 LPDIRECTSOUND8 *ppDS,
999 IUnknown *pUnkOuter)
1001 LPDIRECTSOUND8 pDS;
1002 HRESULT hr;
1003 TRACE("(%p,%p)\n",ppDS,pUnkOuter);
1005 /* Get dsound configuration */
1006 setup_dsound_options();
1008 hr = IDirectSoundImpl_Create(&pDS);
1009 if (hr == DS_OK) {
1010 hr = IDirectSound8_IDirectSound8_Create(pDS, ppDS);
1011 if (*ppDS)
1012 IDirectSound8_IDirectSound8_AddRef(*ppDS);
1013 else {
1014 WARN("IDirectSound8_IDirectSound8_Create failed\n");
1015 IDirectSound8_Release(pDS);
1017 } else {
1018 WARN("IDirectSoundImpl_Create failed\n");
1019 *ppDS = 0;
1022 return hr;
1025 /*******************************************************************************
1026 * DirectSoundCreate8 (DSOUND.11)
1028 * Creates and initializes a DirectSound8 interface.
1030 * PARAMS
1031 * lpcGUID [I] Address of the GUID that identifies the sound device.
1032 * ppDS [O] Address of a variable to receive the interface pointer.
1033 * pUnkOuter [I] Must be NULL.
1035 * RETURNS
1036 * Success: DS_OK
1037 * Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
1038 * DSERR_NODRIVER, DSERR_OUTOFMEMORY
1040 HRESULT WINAPI DirectSoundCreate8(
1041 LPCGUID lpcGUID,
1042 LPDIRECTSOUND8 *ppDS,
1043 IUnknown *pUnkOuter)
1045 HRESULT hr;
1046 LPDIRECTSOUND8 pDS;
1048 TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
1050 if (ppDS == NULL) {
1051 WARN("invalid parameter: ppDS == NULL\n");
1052 return DSERR_INVALIDPARAM;
1055 if (pUnkOuter != NULL) {
1056 WARN("invalid parameter: pUnkOuter != NULL\n");
1057 *ppDS = 0;
1058 return DSERR_INVALIDPARAM;
1061 hr = DSOUND_Create8(&pDS, pUnkOuter);
1062 if (hr == DS_OK) {
1063 hr = IDirectSound8_Initialize(pDS, lpcGUID);
1064 if (hr != DS_OK) {
1065 if (hr != DSERR_ALREADYINITIALIZED) {
1066 IDirectSound8_Release(pDS);
1067 pDS = 0;
1068 } else
1069 hr = DS_OK;
1073 *ppDS = pDS;
1075 return hr;
1078 /*******************************************************************************
1079 * DirectSoundDevice
1081 HRESULT DirectSoundDevice_Create(DirectSoundDevice ** ppDevice)
1083 DirectSoundDevice * device;
1084 TRACE("(%p)\n", ppDevice);
1086 /* Allocate memory */
1087 device = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DirectSoundDevice));
1088 if (device == NULL) {
1089 WARN("out of memory\n");
1090 return DSERR_OUTOFMEMORY;
1093 device->ref = 1;
1094 device->driver = NULL;
1095 device->priolevel = DSSCL_NORMAL;
1096 device->fraglen = 0;
1097 device->hwbuf = NULL;
1098 device->buffer = NULL;
1099 device->buflen = 0;
1100 device->writelead = 0;
1101 device->state = STATE_STOPPED;
1102 device->nrofbuffers = 0;
1103 device->buffers = NULL;
1104 device->primary = NULL;
1105 device->speaker_config = DSSPEAKER_STEREO | (DSSPEAKER_GEOMETRY_NARROW << 16);
1106 device->tmp_buffer = NULL;
1107 device->tmp_buffer_len = 0;
1109 /* 3D listener initial parameters */
1110 device->listener = NULL;
1111 device->ds3dl.dwSize = sizeof(DS3DLISTENER);
1112 device->ds3dl.vPosition.x = 0.0;
1113 device->ds3dl.vPosition.y = 0.0;
1114 device->ds3dl.vPosition.z = 0.0;
1115 device->ds3dl.vVelocity.x = 0.0;
1116 device->ds3dl.vVelocity.y = 0.0;
1117 device->ds3dl.vVelocity.z = 0.0;
1118 device->ds3dl.vOrientFront.x = 0.0;
1119 device->ds3dl.vOrientFront.y = 0.0;
1120 device->ds3dl.vOrientFront.z = 1.0;
1121 device->ds3dl.vOrientTop.x = 0.0;
1122 device->ds3dl.vOrientTop.y = 1.0;
1123 device->ds3dl.vOrientTop.z = 0.0;
1124 device->ds3dl.flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
1125 device->ds3dl.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
1126 device->ds3dl.flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
1128 device->prebuf = ds_snd_queue_max;
1129 device->guid = GUID_NULL;
1131 /* Set default wave format (may need it for waveOutOpen) */
1132 device->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(WAVEFORMATEX));
1133 if (device->pwfx == NULL) {
1134 WARN("out of memory\n");
1135 HeapFree(GetProcessHeap(),0,device);
1136 return DSERR_OUTOFMEMORY;
1139 /* We rely on the sound driver to return the actual sound format of
1140 * the device if it does not support 22050x8x2 and is given the
1141 * WAVE_DIRECTSOUND flag.
1143 device->pwfx->wFormatTag = WAVE_FORMAT_PCM;
1144 device->pwfx->nSamplesPerSec = 22050;
1145 device->pwfx->wBitsPerSample = 8;
1146 device->pwfx->nChannels = 2;
1147 device->pwfx->nBlockAlign = device->pwfx->wBitsPerSample * device->pwfx->nChannels / 8;
1148 device->pwfx->nAvgBytesPerSec = device->pwfx->nSamplesPerSec * device->pwfx->nBlockAlign;
1149 device->pwfx->cbSize = 0;
1151 InitializeCriticalSection(&(device->mixlock));
1152 device->mixlock.DebugInfo->Spare[0] = (DWORD_PTR)"DSOUND_mixlock";
1154 RtlInitializeResource(&(device->buffer_list_lock));
1156 *ppDevice = device;
1158 return DS_OK;
1161 ULONG DirectSoundDevice_AddRef(DirectSoundDevice * device)
1163 ULONG ref = InterlockedIncrement(&(device->ref));
1164 TRACE("(%p) ref was %ld\n", device, ref - 1);
1165 return ref;
1168 ULONG DirectSoundDevice_Release(DirectSoundDevice * device)
1170 HRESULT hr;
1171 ULONG ref = InterlockedDecrement(&(device->ref));
1172 TRACE("(%p) ref was %lu\n", device, ref + 1);
1173 if (!ref) {
1174 int i;
1175 timeKillEvent(device->timerID);
1176 timeEndPeriod(DS_TIME_RES);
1177 /* wait for timer to expire */
1178 Sleep(DS_TIME_RES+1);
1180 /* The sleep above should have allowed the timer process to expire
1181 * but try to grab the lock just in case. Can't hold lock because
1182 * IDirectSoundBufferImpl_Destroy also grabs the lock */
1183 RtlAcquireResourceShared(&(device->buffer_list_lock), TRUE);
1184 RtlReleaseResource(&(device->buffer_list_lock));
1186 /* It is allowed to release this object even when buffers are playing */
1187 if (device->buffers) {
1188 WARN("%d secondary buffers not released\n", device->nrofbuffers);
1189 for( i=0;i<device->nrofbuffers;i++)
1190 IDirectSoundBufferImpl_Destroy(device->buffers[i]);
1193 if (device->primary) {
1194 WARN("primary buffer not released\n");
1195 IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)device->primary);
1198 hr = DSOUND_PrimaryDestroy(device);
1199 if (hr != DS_OK)
1200 WARN("DSOUND_PrimaryDestroy failed\n");
1202 if (device->driver)
1203 IDsDriver_Close(device->driver);
1205 if (device->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN)
1206 waveOutClose(device->hwo);
1208 if (device->driver)
1209 IDsDriver_Release(device->driver);
1211 DSOUND_renderer[device->drvdesc.dnDevNode] = NULL;
1213 HeapFree(GetProcessHeap(),0,device->tmp_buffer);
1214 HeapFree(GetProcessHeap(),0,device->buffer);
1215 RtlDeleteResource(&device->buffer_list_lock);
1216 device->mixlock.DebugInfo->Spare[0] = 0;
1217 DeleteCriticalSection(&device->mixlock);
1218 HeapFree(GetProcessHeap(),0,device);
1219 TRACE("(%p) released\n", device);
1221 return ref;
1224 HRESULT DirectSoundDevice_GetCaps(
1225 DirectSoundDevice * device,
1226 LPDSCAPS lpDSCaps)
1228 TRACE("(%p,%p)\n",device,lpDSCaps);
1230 if (device == NULL) {
1231 WARN("not initialized\n");
1232 return DSERR_UNINITIALIZED;
1235 if (lpDSCaps == NULL) {
1236 WARN("invalid parameter: lpDSCaps = NULL\n");
1237 return DSERR_INVALIDPARAM;
1240 /* check if there is enough room */
1241 if (lpDSCaps->dwSize < sizeof(*lpDSCaps)) {
1242 WARN("invalid parameter: lpDSCaps->dwSize = %ld < %d\n",
1243 lpDSCaps->dwSize, sizeof(*lpDSCaps));
1244 return DSERR_INVALIDPARAM;
1247 lpDSCaps->dwFlags = device->drvcaps.dwFlags;
1248 if (TRACE_ON(dsound)) {
1249 TRACE("(flags=0x%08lx:\n",lpDSCaps->dwFlags);
1250 _dump_DSCAPS(lpDSCaps->dwFlags);
1251 DPRINTF(")\n");
1253 lpDSCaps->dwMinSecondarySampleRate = device->drvcaps.dwMinSecondarySampleRate;
1254 lpDSCaps->dwMaxSecondarySampleRate = device->drvcaps.dwMaxSecondarySampleRate;
1255 lpDSCaps->dwPrimaryBuffers = device->drvcaps.dwPrimaryBuffers;
1256 lpDSCaps->dwMaxHwMixingAllBuffers = device->drvcaps.dwMaxHwMixingAllBuffers;
1257 lpDSCaps->dwMaxHwMixingStaticBuffers = device->drvcaps.dwMaxHwMixingStaticBuffers;
1258 lpDSCaps->dwMaxHwMixingStreamingBuffers = device->drvcaps.dwMaxHwMixingStreamingBuffers;
1259 lpDSCaps->dwFreeHwMixingAllBuffers = device->drvcaps.dwFreeHwMixingAllBuffers;
1260 lpDSCaps->dwFreeHwMixingStaticBuffers = device->drvcaps.dwFreeHwMixingStaticBuffers;
1261 lpDSCaps->dwFreeHwMixingStreamingBuffers = device->drvcaps.dwFreeHwMixingStreamingBuffers;
1262 lpDSCaps->dwMaxHw3DAllBuffers = device->drvcaps.dwMaxHw3DAllBuffers;
1263 lpDSCaps->dwMaxHw3DStaticBuffers = device->drvcaps.dwMaxHw3DStaticBuffers;
1264 lpDSCaps->dwMaxHw3DStreamingBuffers = device->drvcaps.dwMaxHw3DStreamingBuffers;
1265 lpDSCaps->dwFreeHw3DAllBuffers = device->drvcaps.dwFreeHw3DAllBuffers;
1266 lpDSCaps->dwFreeHw3DStaticBuffers = device->drvcaps.dwFreeHw3DStaticBuffers;
1267 lpDSCaps->dwFreeHw3DStreamingBuffers = device->drvcaps.dwFreeHw3DStreamingBuffers;
1268 lpDSCaps->dwTotalHwMemBytes = device->drvcaps.dwTotalHwMemBytes;
1269 lpDSCaps->dwFreeHwMemBytes = device->drvcaps.dwFreeHwMemBytes;
1270 lpDSCaps->dwMaxContigFreeHwMemBytes = device->drvcaps.dwMaxContigFreeHwMemBytes;
1272 /* driver doesn't have these */
1273 lpDSCaps->dwUnlockTransferRateHwBuffers = 4096; /* But we have none... */
1274 lpDSCaps->dwPlayCpuOverheadSwBuffers = 1; /* 1% */
1276 return DS_OK;
1279 HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcGUID)
1281 HRESULT hr = DS_OK;
1282 unsigned wod, wodn;
1283 BOOLEAN found = FALSE;
1284 GUID devGUID;
1285 DirectSoundDevice * device = *ppDevice;
1286 TRACE("(%p,%s)\n",ppDevice,debugstr_guid(lpcGUID));
1288 if (*ppDevice != NULL) {
1289 WARN("already initialized\n");
1290 return DSERR_ALREADYINITIALIZED;
1293 /* Default device? */
1294 if (!lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL))
1295 lpcGUID = &DSDEVID_DefaultPlayback;
1297 if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
1298 WARN("invalid parameter: lpcGUID\n");
1299 return DSERR_INVALIDPARAM;
1302 /* Enumerate WINMM audio devices and find the one we want */
1303 wodn = waveOutGetNumDevs();
1304 if (!wodn) {
1305 WARN("no driver\n");
1306 return DSERR_NODRIVER;
1309 for (wod=0; wod<wodn; wod++) {
1310 if (IsEqualGUID( &devGUID, &DSOUND_renderer_guids[wod])) {
1311 found = TRUE;
1312 break;
1316 if (found == FALSE) {
1317 WARN("No device found matching given ID!\n");
1318 return DSERR_NODRIVER;
1321 if (DSOUND_renderer[wod]) {
1322 if (IsEqualGUID(&devGUID, &DSOUND_renderer[wod]->guid)) {
1323 device = DSOUND_renderer[wod];
1324 DirectSoundDevice_AddRef(device);
1325 *ppDevice = device;
1326 return DS_OK;
1327 } else {
1328 ERR("device GUID doesn't match\n");
1329 hr = DSERR_GENERIC;
1330 return hr;
1332 } else {
1333 hr = DirectSoundDevice_Create(&device);
1334 if (hr != DS_OK) {
1335 WARN("DirectSoundDevice_Create failed\n");
1336 return hr;
1340 *ppDevice = device;
1341 device->guid = devGUID;
1343 /* DRV_QUERYDSOUNDIFACE is a "Wine extension" to get the DSound interface */
1344 waveOutMessage((HWAVEOUT)wod, DRV_QUERYDSOUNDIFACE, (DWORD_PTR)&device->driver, 0);
1346 /* Disable the direct sound driver to force emulation if requested. */
1347 if (ds_hw_accel == DS_HW_ACCEL_EMULATION)
1348 device->driver = NULL;
1350 /* Get driver description */
1351 if (device->driver) {
1352 hr = IDsDriver_GetDriverDesc(device->driver,&(device->drvdesc));
1353 if (hr != DS_OK) {
1354 WARN("IDsDriver_GetDriverDesc failed\n");
1355 return hr;
1357 } else {
1358 /* if no DirectSound interface available, use WINMM API instead */
1359 device->drvdesc.dwFlags = DSDDESC_DOMMSYSTEMOPEN | DSDDESC_DOMMSYSTEMSETFORMAT;
1362 device->drvdesc.dnDevNode = wod;
1364 /* If the driver requests being opened through MMSYSTEM
1365 * (which is recommended by the DDK), it is supposed to happen
1366 * before the DirectSound interface is opened */
1367 if (device->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN)
1369 DWORD flags = CALLBACK_FUNCTION;
1371 /* disable direct sound if requested */
1372 if (ds_hw_accel != DS_HW_ACCEL_EMULATION)
1373 flags |= WAVE_DIRECTSOUND;
1375 hr = mmErr(waveOutOpen(&(device->hwo),
1376 device->drvdesc.dnDevNode, device->pwfx,
1377 (DWORD_PTR)DSOUND_callback, (DWORD)device,
1378 flags));
1379 if (hr != DS_OK) {
1380 WARN("waveOutOpen failed\n");
1381 return hr;
1385 if (device->driver) {
1386 hr = IDsDriver_Open(device->driver);
1387 if (hr != DS_OK) {
1388 WARN("IDsDriver_Open failed\n");
1389 return hr;
1392 /* the driver is now open, so it's now allowed to call GetCaps */
1393 hr = IDsDriver_GetCaps(device->driver,&(device->drvcaps));
1394 if (hr != DS_OK) {
1395 WARN("IDsDriver_GetCaps failed\n");
1396 return hr;
1398 } else {
1399 WAVEOUTCAPSA woc;
1400 hr = mmErr(waveOutGetDevCapsA(device->drvdesc.dnDevNode, &woc, sizeof(woc)));
1401 if (hr != DS_OK) {
1402 WARN("waveOutGetDevCaps failed\n");
1403 return hr;
1405 ZeroMemory(&device->drvcaps, sizeof(device->drvcaps));
1406 if ((woc.dwFormats & WAVE_FORMAT_1M08) ||
1407 (woc.dwFormats & WAVE_FORMAT_2M08) ||
1408 (woc.dwFormats & WAVE_FORMAT_4M08) ||
1409 (woc.dwFormats & WAVE_FORMAT_48M08) ||
1410 (woc.dwFormats & WAVE_FORMAT_96M08)) {
1411 device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT;
1412 device->drvcaps.dwFlags |= DSCAPS_PRIMARYMONO;
1414 if ((woc.dwFormats & WAVE_FORMAT_1M16) ||
1415 (woc.dwFormats & WAVE_FORMAT_2M16) ||
1416 (woc.dwFormats & WAVE_FORMAT_4M16) ||
1417 (woc.dwFormats & WAVE_FORMAT_48M16) ||
1418 (woc.dwFormats & WAVE_FORMAT_96M16)) {
1419 device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT;
1420 device->drvcaps.dwFlags |= DSCAPS_PRIMARYMONO;
1422 if ((woc.dwFormats & WAVE_FORMAT_1S08) ||
1423 (woc.dwFormats & WAVE_FORMAT_2S08) ||
1424 (woc.dwFormats & WAVE_FORMAT_4S08) ||
1425 (woc.dwFormats & WAVE_FORMAT_48S08) ||
1426 (woc.dwFormats & WAVE_FORMAT_96S08)) {
1427 device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT;
1428 device->drvcaps.dwFlags |= DSCAPS_PRIMARYSTEREO;
1430 if ((woc.dwFormats & WAVE_FORMAT_1S16) ||
1431 (woc.dwFormats & WAVE_FORMAT_2S16) ||
1432 (woc.dwFormats & WAVE_FORMAT_4S16) ||
1433 (woc.dwFormats & WAVE_FORMAT_48S16) ||
1434 (woc.dwFormats & WAVE_FORMAT_96S16)) {
1435 device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT;
1436 device->drvcaps.dwFlags |= DSCAPS_PRIMARYSTEREO;
1438 if (ds_emuldriver)
1439 device->drvcaps.dwFlags |= DSCAPS_EMULDRIVER;
1440 device->drvcaps.dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
1441 device->drvcaps.dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
1442 device->drvcaps.dwPrimaryBuffers = 1;
1445 hr = DSOUND_PrimaryCreate(device);
1446 if (hr == DS_OK) {
1447 DSOUND_renderer[device->drvdesc.dnDevNode] = device;
1448 timeBeginPeriod(DS_TIME_RES);
1449 DSOUND_renderer[device->drvdesc.dnDevNode]->timerID = timeSetEvent(DS_TIME_DEL, DS_TIME_RES, DSOUND_timer,
1450 (DWORD_PTR)DSOUND_renderer[device->drvdesc.dnDevNode], TIME_PERIODIC | TIME_CALLBACK_FUNCTION);
1451 } else {
1452 WARN("DSOUND_PrimaryCreate failed\n");
1455 return hr;
1458 HRESULT DirectSoundDevice_CreateSoundBuffer(
1459 DirectSoundDevice * device,
1460 LPCDSBUFFERDESC dsbd,
1461 LPLPDIRECTSOUNDBUFFER ppdsb,
1462 LPUNKNOWN lpunk,
1463 BOOL from8)
1465 HRESULT hres = DS_OK;
1466 TRACE("(%p,%p,%p,%p)\n",device,dsbd,ppdsb,lpunk);
1468 if (device == NULL) {
1469 WARN("not initialized\n");
1470 return DSERR_UNINITIALIZED;
1473 if (dsbd == NULL) {
1474 WARN("invalid parameter: dsbd == NULL\n");
1475 return DSERR_INVALIDPARAM;
1478 if (dsbd->dwSize != sizeof(DSBUFFERDESC) &&
1479 dsbd->dwSize != sizeof(DSBUFFERDESC1)) {
1480 WARN("invalid parameter: dsbd\n");
1481 return DSERR_INVALIDPARAM;
1484 if (ppdsb == NULL) {
1485 WARN("invalid parameter: ppdsb == NULL\n");
1486 return DSERR_INVALIDPARAM;
1489 if (TRACE_ON(dsound)) {
1490 TRACE("(structsize=%ld)\n",dsbd->dwSize);
1491 TRACE("(flags=0x%08lx:\n",dsbd->dwFlags);
1492 _dump_DSBCAPS(dsbd->dwFlags);
1493 DPRINTF(")\n");
1494 TRACE("(bufferbytes=%ld)\n",dsbd->dwBufferBytes);
1495 TRACE("(lpwfxFormat=%p)\n",dsbd->lpwfxFormat);
1498 if (dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) {
1499 if (dsbd->lpwfxFormat != NULL) {
1500 WARN("invalid parameter: dsbd->lpwfxFormat must be NULL for "
1501 "primary buffer\n");
1502 return DSERR_INVALIDPARAM;
1505 if (device->primary) {
1506 WARN("Primary Buffer already created\n");
1507 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(device->primary));
1508 *ppdsb = (LPDIRECTSOUNDBUFFER)(device->primary);
1509 } else {
1510 device->dsbd = *dsbd;
1511 hres = PrimaryBufferImpl_Create(device, (PrimaryBufferImpl**)&(device->primary), &(device->dsbd));
1512 if (device->primary) {
1513 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(device->primary));
1514 *ppdsb = (LPDIRECTSOUNDBUFFER)(device->primary);
1515 } else
1516 WARN("PrimaryBufferImpl_Create failed\n");
1518 } else {
1519 IDirectSoundBufferImpl * dsb;
1521 if (dsbd->lpwfxFormat == NULL) {
1522 WARN("invalid parameter: dsbd->lpwfxFormat can't be NULL for "
1523 "secondary buffer\n");
1524 return DSERR_INVALIDPARAM;
1527 TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld,"
1528 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
1529 dsbd->lpwfxFormat->wFormatTag, dsbd->lpwfxFormat->nChannels,
1530 dsbd->lpwfxFormat->nSamplesPerSec,
1531 dsbd->lpwfxFormat->nAvgBytesPerSec,
1532 dsbd->lpwfxFormat->nBlockAlign,
1533 dsbd->lpwfxFormat->wBitsPerSample, dsbd->lpwfxFormat->cbSize);
1535 if (from8 && (dsbd->dwFlags & DSBCAPS_CTRL3D) && (dsbd->lpwfxFormat->nChannels != 1)) {
1536 WARN("invalid parameter: 3D buffer format must be mono\n");
1537 return DSERR_INVALIDPARAM;
1540 hres = IDirectSoundBufferImpl_Create(device, (IDirectSoundBufferImpl**)&dsb, dsbd);
1541 if (dsb) {
1542 hres = SecondaryBufferImpl_Create(dsb, (SecondaryBufferImpl**)ppdsb);
1543 if (*ppdsb) {
1544 dsb->secondary = (SecondaryBufferImpl*)*ppdsb;
1545 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)*ppdsb);
1546 } else
1547 WARN("SecondaryBufferImpl_Create failed\n");
1548 } else
1549 WARN("IDirectSoundBufferImpl_Create failed\n");
1552 return hres;
1555 HRESULT DirectSoundDevice_DuplicateSoundBuffer(
1556 DirectSoundDevice * device,
1557 LPDIRECTSOUNDBUFFER psb,
1558 LPLPDIRECTSOUNDBUFFER ppdsb)
1560 HRESULT hres = DS_OK;
1561 IDirectSoundBufferImpl* dsb;
1562 TRACE("(%p,%p,%p)\n",device,psb,ppdsb);
1564 if (device == NULL) {
1565 WARN("not initialized\n");
1566 return DSERR_UNINITIALIZED;
1569 if (psb == NULL) {
1570 WARN("invalid parameter: psb == NULL\n");
1571 return DSERR_INVALIDPARAM;
1574 if (ppdsb == NULL) {
1575 WARN("invalid parameter: ppdsb == NULL\n");
1576 return DSERR_INVALIDPARAM;
1579 /* make sure we have a secondary buffer */
1580 if ((PrimaryBufferImpl *)psb == device->primary) {
1581 WARN("trying to duplicate primary buffer\n");
1582 *ppdsb = NULL;
1583 return DSERR_INVALIDCALL;
1586 /* duplicate the actual buffer implementation */
1587 hres = IDirectSoundBufferImpl_Duplicate(device, &dsb,
1588 ((SecondaryBufferImpl *)psb)->dsb);
1590 if (hres == DS_OK) {
1591 /* create a new secondary buffer using the new implementation */
1592 hres = SecondaryBufferImpl_Create(dsb, (SecondaryBufferImpl**)ppdsb);
1593 if (*ppdsb) {
1594 dsb->secondary = (SecondaryBufferImpl*)*ppdsb;
1595 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)*ppdsb);
1596 } else {
1597 WARN("SecondaryBufferImpl_Create failed\n");
1598 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)dsb);
1599 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER8)dsb);
1603 return hres;
1606 HRESULT DirectSoundDevice_SetCooperativeLevel(
1607 DirectSoundDevice * device,
1608 HWND hwnd,
1609 DWORD level)
1611 TRACE("(%p,%p,%s)\n",device,hwnd,dumpCooperativeLevel(level));
1613 if (device == NULL) {
1614 WARN("not initialized\n");
1615 return DSERR_UNINITIALIZED;
1618 if (level==DSSCL_PRIORITY || level==DSSCL_EXCLUSIVE) {
1619 WARN("level=%s not fully supported\n",
1620 level==DSSCL_PRIORITY ? "DSSCL_PRIORITY" : "DSSCL_EXCLUSIVE");
1623 device->priolevel = level;
1624 return DS_OK;
1627 HRESULT DirectSoundDevice_Compact(
1628 DirectSoundDevice * device)
1630 TRACE("(%p)\n", device);
1632 if (device == NULL) {
1633 WARN("not initialized\n");
1634 return DSERR_UNINITIALIZED;
1637 if (device->priolevel != DSSCL_PRIORITY) {
1638 WARN("incorrect priority level\n");
1639 return DSERR_PRIOLEVELNEEDED;
1642 return DS_OK;
1645 HRESULT DirectSoundDevice_GetSpeakerConfig(
1646 DirectSoundDevice * device,
1647 LPDWORD lpdwSpeakerConfig)
1649 TRACE("(%p, %p)\n", device, lpdwSpeakerConfig);
1651 if (device == NULL) {
1652 WARN("not initialized\n");
1653 return DSERR_UNINITIALIZED;
1656 if (lpdwSpeakerConfig == NULL) {
1657 WARN("invalid parameter: lpdwSpeakerConfig == NULL\n");
1658 return DSERR_INVALIDPARAM;
1661 WARN("not fully functional\n");
1662 *lpdwSpeakerConfig = device->speaker_config;
1663 return DS_OK;
1666 HRESULT DirectSoundDevice_SetSpeakerConfig(
1667 DirectSoundDevice * device,
1668 DWORD config)
1670 TRACE("(%p,0x%08lx)\n",device,config);
1672 if (device == NULL) {
1673 WARN("not initialized\n");
1674 return DSERR_UNINITIALIZED;
1677 device->speaker_config = config;
1678 WARN("not fully functional\n");
1679 return DS_OK;
1682 HRESULT DirectSoundDevice_VerifyCertification(
1683 DirectSoundDevice * device,
1684 LPDWORD pdwCertified)
1686 TRACE("(%p, %p)\n",device,pdwCertified);
1688 if (device == NULL) {
1689 WARN("not initialized\n");
1690 return DSERR_UNINITIALIZED;
1693 if (device->drvcaps.dwFlags & DSCAPS_CERTIFIED)
1694 *pdwCertified = DS_CERTIFIED;
1695 else
1696 *pdwCertified = DS_UNCERTIFIED;
1698 return DS_OK;
1702 * Add secondary buffer to buffer list.
1703 * Gets exclusive access to buffer for writing.
1705 HRESULT DirectSoundDevice_AddBuffer(
1706 DirectSoundDevice * device,
1707 IDirectSoundBufferImpl * pDSB)
1709 IDirectSoundBufferImpl **newbuffers;
1710 HRESULT hr = DS_OK;
1712 TRACE("(%p, %p)\n", device, pDSB);
1714 RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
1716 if (device->buffers)
1717 newbuffers = HeapReAlloc(GetProcessHeap(),0,device->buffers,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
1718 else
1719 newbuffers = HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
1721 if (newbuffers) {
1722 device->buffers = newbuffers;
1723 device->buffers[device->nrofbuffers] = pDSB;
1724 device->nrofbuffers++;
1725 TRACE("buffer count is now %d\n", device->nrofbuffers);
1726 } else {
1727 ERR("out of memory for buffer list! Current buffer count is %d\n", device->nrofbuffers);
1728 hr = DSERR_OUTOFMEMORY;
1731 RtlReleaseResource(&(device->buffer_list_lock));
1733 return hr;
1737 * Remove secondary buffer from buffer list.
1738 * Gets exclusive access to buffer for writing.
1740 HRESULT DirectSoundDevice_RemoveBuffer(
1741 DirectSoundDevice * device,
1742 IDirectSoundBufferImpl * pDSB)
1744 int i;
1745 HRESULT hr = DS_OK;
1747 TRACE("(%p, %p)\n", device, pDSB);
1749 RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
1751 for (i = 0; i < device->nrofbuffers; i++)
1752 if (device->buffers[i] == pDSB)
1753 break;
1755 if (i < device->nrofbuffers) {
1756 /* Put the last buffer of the list in the (now empty) position */
1757 device->buffers[i] = device->buffers[device->nrofbuffers - 1];
1758 device->nrofbuffers--;
1759 device->buffers = HeapReAlloc(GetProcessHeap(),0,device->buffers,sizeof(LPDIRECTSOUNDBUFFER8)*device->nrofbuffers);
1760 TRACE("buffer count is now %d\n", device->nrofbuffers);
1763 if (device->nrofbuffers == 0) {
1764 HeapFree(GetProcessHeap(),0,device->buffers);
1765 device->buffers = NULL;
1768 RtlReleaseResource(&(device->buffer_list_lock));
1770 return hr;