3 * Copyright 1998 Marcus Meissner
4 * Copyright 1998 Rob Riggs
5 * Copyright 2000-2002 TransGaming Technologies, Inc.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * Most thread locking is complete. There may be a few race
23 * conditions still lurking.
25 * Tested with a Soundblaster clone, a Gravis UltraSound Classic,
26 * and a Turtle Beach Tropez+.
29 * Implement SetCooperativeLevel properly (need to address focus issues)
30 * Implement DirectSound3DBuffers (stubs in place)
31 * Use hardware 3D support if available
32 * Add critical section locking inside Release and AddRef methods
33 * Handle static buffers - put those in hardware, non-static not in hardware
34 * Hardware DuplicateSoundBuffer
35 * Proper volume calculation, and setting volume in HEL primary buffer
36 * Optimize WINMM and negotiate fragment size, decrease DS_HEL_MARGIN
40 #include "wine/port.h"
45 #include <sys/types.h>
46 #include <sys/fcntl.h>
54 #define NONAMELESSSTRUCT
55 #define NONAMELESSUNION
66 #include "wine/windef16.h"
67 #include "wine/winbase16.h"
68 #include "wine/debug.h"
71 #include "dsound_private.h"
74 WINE_DEFAULT_DEBUG_CHANNEL(dsound
);
76 /* these are eligible for tuning... they must be high on slow machines... */
77 /* some stuff may get more responsive with lower values though... */
78 #define DS_EMULDRIVER 0 /* some games (Quake 2, UT) refuse to accept
79 emulated dsound devices. set to 0 ! */
80 #define DS_HEL_MARGIN 5 /* HEL only: number of waveOut fragments ahead to mix in new buffers
81 * (keep this close or equal to DS_HEL_QUEUE for best results) */
82 #define DS_HEL_QUEUE 5 /* HEL only: number of waveOut fragments ahead to queue to driver
83 * (this will affect HEL sound reliability and latency) */
85 #define DS_SND_QUEUE_MAX 28 /* max number of fragments to prebuffer */
86 #define DS_SND_QUEUE_MIN 12 /* min number of fragments to prebuffer */
88 IDirectSoundImpl
* dsound
= NULL
;
90 HRESULT
mmErr(UINT err
)
93 case MMSYSERR_NOERROR
:
95 case MMSYSERR_ALLOCATED
:
96 return DSERR_ALLOCATED
;
98 case MMSYSERR_INVALHANDLE
:
99 case WAVERR_STILLPLAYING
:
100 return DSERR_GENERIC
; /* FIXME */
101 case MMSYSERR_NODRIVER
:
102 return DSERR_NODRIVER
;
104 return DSERR_OUTOFMEMORY
;
105 case MMSYSERR_INVALPARAM
:
106 case WAVERR_BADFORMAT
:
107 case WAVERR_UNPREPARED
:
108 return DSERR_INVALIDPARAM
;
109 case MMSYSERR_NOTSUPPORTED
:
110 return DSERR_UNSUPPORTED
;
112 FIXME("Unknown MMSYS error %d\n",err
);
113 return DSERR_GENERIC
;
117 int ds_emuldriver
= DS_EMULDRIVER
;
118 int ds_hel_margin
= DS_HEL_MARGIN
;
119 int ds_hel_queue
= DS_HEL_QUEUE
;
120 int ds_snd_queue_max
= DS_SND_QUEUE_MAX
;
121 int ds_snd_queue_min
= DS_SND_QUEUE_MIN
;
122 int ds_hw_accel
= DS_HW_ACCEL_FULL
;
123 int ds_default_playback
= 0;
124 int ds_default_capture
= 0;
127 * Get a config key from either the app-specific or the default config
130 inline static DWORD
get_config_key( HKEY defkey
, HKEY appkey
, const char *name
,
131 char *buffer
, DWORD size
)
133 if (appkey
&& !RegQueryValueExA( appkey
, name
, 0, NULL
, buffer
, &size
)) return 0;
134 return RegQueryValueExA( defkey
, name
, 0, NULL
, buffer
, &size
);
139 * Setup the dsound options.
142 void setup_dsound_options(void)
144 char buffer
[MAX_PATH
+1];
145 HKEY hkey
, appkey
= 0;
147 buffer
[MAX_PATH
]='\0';
149 if (RegCreateKeyExA( HKEY_LOCAL_MACHINE
, "Software\\Wine\\Wine\\Config\\dsound", 0, NULL
,
150 REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
))
152 ERR("Cannot create config registry key\n" );
156 if (GetModuleFileNameA( 0, buffer
, MAX_PATH
))
160 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE
, "Software\\Wine\\Wine\\Config\\AppDefaults", &tmpkey
))
162 char appname
[MAX_PATH
+16];
163 char *p
= strrchr( buffer
, '\\' );
165 appname
[MAX_PATH
]='\0';
166 strncpy(appname
,p
+1,MAX_PATH
);
167 strcat(appname
,"\\dsound");
168 TRACE("appname = [%s] \n",appname
);
169 if (RegOpenKeyA( tmpkey
, appname
, &appkey
)) appkey
= 0;
170 RegCloseKey( tmpkey
);
177 if (!get_config_key( hkey
, appkey
, "EmulDriver", buffer
, MAX_PATH
))
178 ds_emuldriver
= strcmp(buffer
, "N");
180 if (!get_config_key( hkey
, appkey
, "HELmargin", buffer
, MAX_PATH
))
181 ds_hel_margin
= atoi(buffer
);
183 if (!get_config_key( hkey
, appkey
, "HELqueue", buffer
, MAX_PATH
))
184 ds_hel_queue
= atoi(buffer
);
186 if (!get_config_key( hkey
, appkey
, "SndQueueMax", buffer
, MAX_PATH
))
187 ds_snd_queue_max
= atoi(buffer
);
189 if (!get_config_key( hkey
, appkey
, "SndQueueMin", buffer
, MAX_PATH
))
190 ds_snd_queue_min
= atoi(buffer
);
192 if (!get_config_key( hkey
, appkey
, "HardwareAcceleration", buffer
, MAX_PATH
)) {
193 if (strcmp(buffer
, "Full") == 0)
194 ds_hw_accel
= DS_HW_ACCEL_FULL
;
195 else if (strcmp(buffer
, "Standard") == 0)
196 ds_hw_accel
= DS_HW_ACCEL_STANDARD
;
197 else if (strcmp(buffer
, "Basic") == 0)
198 ds_hw_accel
= DS_HW_ACCEL_BASIC
;
199 else if (strcmp(buffer
, "Emulation") == 0)
200 ds_hw_accel
= DS_HW_ACCEL_EMULATION
;
203 if (!get_config_key( hkey
, appkey
, "DefaultPlayback", buffer
, MAX_PATH
))
204 ds_default_playback
= atoi(buffer
);
206 if (!get_config_key( hkey
, appkey
, "DefaultCapture", buffer
, MAX_PATH
))
207 ds_default_capture
= atoi(buffer
);
209 if (appkey
) RegCloseKey( appkey
);
212 if (ds_emuldriver
!= DS_EMULDRIVER
)
213 WARN("ds_emuldriver = %d (default=%d)\n",ds_emuldriver
, DS_EMULDRIVER
);
214 if (ds_hel_margin
!= DS_HEL_MARGIN
)
215 WARN("ds_hel_margin = %d (default=%d)\n",ds_hel_margin
, DS_HEL_MARGIN
);
216 if (ds_hel_queue
!= DS_HEL_QUEUE
)
217 WARN("ds_hel_queue = %d (default=%d)\n",ds_hel_queue
, DS_HEL_QUEUE
);
218 if (ds_snd_queue_max
!= DS_SND_QUEUE_MAX
)
219 WARN("ds_snd_queue_max = %d (default=%d)\n",ds_snd_queue_max
,DS_SND_QUEUE_MAX
);
220 if (ds_snd_queue_min
!= DS_SND_QUEUE_MIN
)
221 WARN("ds_snd_queue_min = %d (default=%d)\n",ds_snd_queue_min
,DS_SND_QUEUE_MIN
);
222 if (ds_hw_accel
!= DS_HW_ACCEL_FULL
)
223 WARN("ds_hw_accel = %s (default=Full)\n",
224 ds_hw_accel
==DS_HW_ACCEL_FULL
? "Full" :
225 ds_hw_accel
==DS_HW_ACCEL_STANDARD
? "Standard" :
226 ds_hw_accel
==DS_HW_ACCEL_BASIC
? "Basic" :
227 ds_hw_accel
==DS_HW_ACCEL_EMULATION
? "Emulation" :
229 if (ds_default_playback
!= 0)
230 WARN("ds_default_playback = %d (default=0)\n",ds_default_playback
);
231 if (ds_default_capture
!= 0)
232 WARN("ds_default_capture = %d (default=0)\n",ds_default_playback
);
237 /***************************************************************************
238 * GetDeviceID [DSOUND.9]
240 * Retrieves unique identifier of default device specified
243 * pGuidSrc [I] Address of device GUID.
244 * pGuidDest [O] Address to receive unique device GUID.
248 * Failure: DSERR_INVALIDPARAM
251 * pGuidSrc is a valid device GUID or DSDEVID_DefaultPlayback,
252 * DSDEVID_DefaultCapture, DSDEVID_DefaultVoicePlayback, or
253 * DSDEVID_DefaultVoiceCapture.
254 * Returns pGuidSrc if pGuidSrc is a valid device or the device
255 * GUID for the specified constants.
257 HRESULT WINAPI
GetDeviceID(LPCGUID pGuidSrc
, LPGUID pGuidDest
)
259 TRACE("(%p,%p)\n",pGuidSrc
,pGuidDest
);
261 if ( pGuidSrc
== NULL
) {
262 WARN("invalid parameter: pGuidSrc == NULL\n");
263 return DSERR_INVALIDPARAM
;
266 if ( pGuidDest
== NULL
) {
267 WARN("invalid parameter: pGuidDest == NULL\n");
268 return DSERR_INVALIDPARAM
;
271 if ( IsEqualGUID( &DSDEVID_DefaultPlayback
, pGuidSrc
) ||
272 IsEqualGUID( &DSDEVID_DefaultVoicePlayback
, pGuidSrc
) ) {
274 int err
= mmErr(waveOutMessage((HWAVEOUT
)ds_default_playback
,DRV_QUERYDSOUNDGUID
,(DWORD
)&guid
,0));
276 memcpy(pGuidDest
, &guid
, sizeof(GUID
));
281 if ( IsEqualGUID( &DSDEVID_DefaultCapture
, pGuidSrc
) ||
282 IsEqualGUID( &DSDEVID_DefaultVoiceCapture
, pGuidSrc
) ) {
284 int err
= mmErr(waveInMessage((HWAVEIN
)ds_default_capture
,DRV_QUERYDSOUNDGUID
,(DWORD
)&guid
,0));
286 memcpy(pGuidDest
, &guid
, sizeof(GUID
));
291 memcpy(pGuidDest
, pGuidSrc
, sizeof(GUID
));
297 /***************************************************************************
298 * DirectSoundEnumerateA [DSOUND.2]
300 * Enumerate all DirectSound drivers installed in the system
303 * lpDSEnumCallback [I] Address of callback function.
304 * lpContext [I] Address of user defined context passed to callback function.
308 * Failure: DSERR_INVALIDPARAM
310 HRESULT WINAPI
DirectSoundEnumerateA(
311 LPDSENUMCALLBACKA lpDSEnumCallback
,
319 TRACE("lpDSEnumCallback = %p, lpContext = %p\n",
320 lpDSEnumCallback
, lpContext
);
322 if (lpDSEnumCallback
== NULL
) {
323 WARN("invalid parameter: lpDSEnumCallback == NULL\n");
324 return DSERR_INVALIDPARAM
;
327 devs
= waveOutGetNumDevs();
329 if (GetDeviceID(&DSDEVID_DefaultPlayback
, &guid
) == DS_OK
) {
331 for (wod
= 0; wod
< devs
; ++wod
) {
332 err
= mmErr(waveOutMessage((HWAVEOUT
)wod
,DRV_QUERYDSOUNDGUID
,(DWORD
)&temp
,0));
334 if (IsEqualGUID( &guid
, &temp
) ) {
335 err
= mmErr(waveOutMessage((HWAVEOUT
)wod
,DRV_QUERYDSOUNDDESC
,(DWORD
)&desc
,0));
337 TRACE("calling lpDSEnumCallback(NULL,\"%s\",\"%s\",%p)\n",
338 "Primary Sound Driver",desc
.szDrvName
,lpContext
);
339 if (lpDSEnumCallback(NULL
, "Primary Sound Driver", desc
.szDrvName
, lpContext
) == FALSE
)
348 for (wod
= 0; wod
< devs
; ++wod
) {
349 err
= mmErr(waveOutMessage((HWAVEOUT
)wod
,DRV_QUERYDSOUNDDESC
,(DWORD
)&desc
,0));
351 err
= mmErr(waveOutMessage((HWAVEOUT
)wod
,DRV_QUERYDSOUNDGUID
,(DWORD
)&guid
,0));
353 TRACE("calling lpDSEnumCallback(%s,\"%s\",\"%s\",%p)\n",
354 debugstr_guid(&guid
),desc
.szDesc
,desc
.szDrvName
,lpContext
);
355 if (lpDSEnumCallback(&guid
, desc
.szDesc
, desc
.szDrvName
, lpContext
) == FALSE
)
363 /***************************************************************************
364 * DirectSoundEnumerateW [DSOUND.3]
366 * Enumerate all DirectSound drivers installed in the system
369 * lpDSEnumCallback [I] Address of callback function.
370 * lpContext [I] Address of user defined context passed to callback function.
374 * Failure: DSERR_INVALIDPARAM
376 HRESULT WINAPI
DirectSoundEnumerateW(
377 LPDSENUMCALLBACKW lpDSEnumCallback
,
384 WCHAR wDesc
[MAXPNAMELEN
];
385 WCHAR wName
[MAXPNAMELEN
];
387 TRACE("lpDSEnumCallback = %p, lpContext = %p\n",
388 lpDSEnumCallback
, lpContext
);
390 if (lpDSEnumCallback
== NULL
) {
391 WARN("invalid parameter: lpDSEnumCallback == NULL\n");
392 return DSERR_INVALIDPARAM
;
395 devs
= waveOutGetNumDevs();
397 if (GetDeviceID(&DSDEVID_DefaultPlayback
, &guid
) == DS_OK
) {
399 for (wod
= 0; wod
< devs
; ++wod
) {
400 err
= mmErr(waveOutMessage((HWAVEOUT
)wod
,DRV_QUERYDSOUNDGUID
,(DWORD
)&temp
,0));
402 if (IsEqualGUID( &guid
, &temp
) ) {
403 err
= mmErr(waveOutMessage((HWAVEOUT
)wod
,DRV_QUERYDSOUNDDESC
,(DWORD
)&desc
,0));
405 TRACE("calling lpDSEnumCallback(NULL,\"%s\",\"%s\",%p)\n",
406 "Primary Sound Driver",desc
.szDrvName
,lpContext
);
407 MultiByteToWideChar( CP_ACP
, 0, "Primary Sound Driver", -1,
408 wDesc
, sizeof(wDesc
)/sizeof(WCHAR
) );
409 MultiByteToWideChar( CP_ACP
, 0, desc
.szDrvName
, -1,
410 wName
, sizeof(wName
)/sizeof(WCHAR
) );
411 if (lpDSEnumCallback(NULL
, wDesc
, wName
, lpContext
) == FALSE
)
420 for (wod
= 0; wod
< devs
; ++wod
) {
421 err
= mmErr(waveOutMessage((HWAVEOUT
)wod
,DRV_QUERYDSOUNDDESC
,(DWORD
)&desc
,0));
423 err
= mmErr(waveOutMessage((HWAVEOUT
)wod
,DRV_QUERYDSOUNDGUID
,(DWORD
)&guid
,0));
425 TRACE("calling lpDSEnumCallback(%s,\"%s\",\"%s\",%p)\n",
426 debugstr_guid(&guid
),desc
.szDesc
,desc
.szDrvName
,lpContext
);
427 MultiByteToWideChar( CP_ACP
, 0, desc
.szDesc
, -1,
428 wDesc
, sizeof(wDesc
)/sizeof(WCHAR
) );
429 MultiByteToWideChar( CP_ACP
, 0, desc
.szDrvName
, -1,
430 wName
, sizeof(wName
)/sizeof(WCHAR
) );
431 if (lpDSEnumCallback(&guid
, wDesc
, wName
, lpContext
) == FALSE
)
440 static void _dump_DSBCAPS(DWORD xmask
) {
445 #define FE(x) { x, #x },
446 FE(DSBCAPS_PRIMARYBUFFER
)
448 FE(DSBCAPS_LOCHARDWARE
)
449 FE(DSBCAPS_LOCSOFTWARE
)
451 FE(DSBCAPS_CTRLFREQUENCY
)
453 FE(DSBCAPS_CTRLVOLUME
)
454 FE(DSBCAPS_CTRLPOSITIONNOTIFY
)
455 FE(DSBCAPS_CTRLDEFAULT
)
457 FE(DSBCAPS_STICKYFOCUS
)
458 FE(DSBCAPS_GLOBALFOCUS
)
459 FE(DSBCAPS_GETCURRENTPOSITION2
)
460 FE(DSBCAPS_MUTE3DATMAXDISTANCE
)
465 for (i
=0;i
<sizeof(flags
)/sizeof(flags
[0]);i
++)
466 if ((flags
[i
].mask
& xmask
) == flags
[i
].mask
)
467 DPRINTF("%s ",flags
[i
].name
);
470 /*******************************************************************************
474 static HRESULT WINAPI
IDirectSoundImpl_SetCooperativeLevel(
475 LPDIRECTSOUND8 iface
,HWND hwnd
,DWORD level
477 ICOM_THIS(IDirectSoundImpl
,iface
);
478 TRACE("(%p,%08lx,%ld(%s))\n",This
,(DWORD
)hwnd
,level
,
479 level
== DSSCL_NORMAL
? "DSSCL_NORMAL" :
480 level
== DSSCL_PRIORITY
? "DSSCL_PRIORITY" :
481 level
== DSSCL_EXCLUSIVE
? "DSSCL_EXCLUSIVE" :
482 level
== DSSCL_WRITEPRIMARY
? "DSSCL_WRITEPRIMARY" : "Unknown");
484 if (level
==DSSCL_PRIORITY
|| level
==DSSCL_EXCLUSIVE
) {
485 FIXME("level=%s not fully supported\n",
486 level
==DSSCL_PRIORITY
? "DSSCL_PRIORITY" : "DSSCL_EXCLUSIVE");
489 This
->priolevel
= level
;
494 static HRESULT WINAPI
IDirectSoundImpl_CreateSoundBuffer(
495 LPDIRECTSOUND8 iface
,LPCDSBUFFERDESC dsbd
,LPLPDIRECTSOUNDBUFFER8 ppdsb
,LPUNKNOWN lpunk
497 ICOM_THIS(IDirectSoundImpl
,iface
);
499 HRESULT hres
= DS_OK
;
501 TRACE("(%p,%p,%p,%p)\n",This
,dsbd
,ppdsb
,lpunk
);
504 WARN("invalid parameter: This == NULL\n");
505 return DSERR_INVALIDPARAM
;
509 WARN("invalid parameter: dsbd == NULL\n");
510 return DSERR_INVALIDPARAM
;
513 if (dsbd
->dwSize
!= sizeof(DSBUFFERDESC
) && dsbd
->dwSize
!= sizeof(DSBUFFERDESC1
)) {
514 WARN("invalid parameter: dsbd\n");
515 return DSERR_INVALIDPARAM
;
519 WARN("invalid parameter: ppdsb == NULL\n");
520 return DSERR_INVALIDPARAM
;
523 if (TRACE_ON(dsound
)) {
524 TRACE("(structsize=%ld)\n",dsbd
->dwSize
);
525 TRACE("(flags=0x%08lx:\n",dsbd
->dwFlags
);
526 _dump_DSBCAPS(dsbd
->dwFlags
);
528 TRACE("(bufferbytes=%ld)\n",dsbd
->dwBufferBytes
);
529 TRACE("(lpwfxFormat=%p)\n",dsbd
->lpwfxFormat
);
532 wfex
= dsbd
->lpwfxFormat
;
535 TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld,"
536 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
537 wfex
->wFormatTag
, wfex
->nChannels
, wfex
->nSamplesPerSec
,
538 wfex
->nAvgBytesPerSec
, wfex
->nBlockAlign
,
539 wfex
->wBitsPerSample
, wfex
->cbSize
);
541 if (dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
543 WARN("Primary Buffer already created\n");
544 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8
)(This
->primary
));
545 *ppdsb
= (LPDIRECTSOUNDBUFFER8
)(This
->primary
);
548 hres
= PrimaryBufferImpl_Create(This
, (PrimaryBufferImpl
**)&(This
->primary
), &(This
->dsbd
));
550 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8
)(This
->primary
));
551 *ppdsb
= (LPDIRECTSOUNDBUFFER8
)(This
->primary
);
553 WARN("PrimaryBufferImpl_Create failed\n");
556 IDirectSoundBufferImpl
* dsb
;
557 hres
= IDirectSoundBufferImpl_Create(This
, (IDirectSoundBufferImpl
**)&dsb
, dsbd
);
559 hres
= SecondaryBufferImpl_Create(dsb
, (SecondaryBufferImpl
**)ppdsb
);
561 dsb
->dsb
= (SecondaryBufferImpl
*)*ppdsb
;
562 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8
)*ppdsb
);
564 WARN("SecondaryBufferImpl_Create failed\n");
566 WARN("IDirectSoundBufferImpl_Create failed\n");
572 static HRESULT WINAPI
IDirectSoundImpl_DuplicateSoundBuffer(
573 LPDIRECTSOUND8 iface
,LPDIRECTSOUNDBUFFER8 psb
,LPLPDIRECTSOUNDBUFFER8 ppdsb
575 ICOM_THIS(IDirectSoundImpl
,iface
);
576 IDirectSoundBufferImpl
* pdsb
;
577 IDirectSoundBufferImpl
* dsb
;
578 HRESULT hres
= DS_OK
;
579 TRACE("(%p,%p,%p)\n",This
,psb
,ppdsb
);
582 WARN("invalid parameter: This == NULL\n");
583 return DSERR_INVALIDPARAM
;
587 WARN("invalid parameter: psb == NULL\n");
588 return DSERR_INVALIDPARAM
;
592 WARN("invalid parameter: ppdsb == NULL\n");
593 return DSERR_INVALIDPARAM
;
596 /* FIXME: hack to make sure we have a secondary buffer */
597 if ((DWORD
)((SecondaryBufferImpl
*)psb
)->dsb
== (DWORD
)This
) {
598 ERR("trying to duplicate primary buffer\n");
600 return DSERR_INVALIDCALL
;
603 pdsb
= ((SecondaryBufferImpl
*)psb
)->dsb
;
605 dsb
= (IDirectSoundBufferImpl
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(*dsb
));
608 WARN("out of memory\n");
610 return DSERR_OUTOFMEMORY
;
613 memcpy(dsb
, pdsb
, sizeof(IDirectSoundBufferImpl
));
616 TRACE("duplicating hardware buffer\n");
618 hres
= IDsDriver_DuplicateSoundBuffer(This
->driver
, pdsb
->hwbuf
, (LPVOID
*)&dsb
->hwbuf
);
620 TRACE("IDsDriver_DuplicateSoundBuffer failed, falling back to software buffer\n");
622 /* allocate buffer */
623 if (This
->drvdesc
.dwFlags
& DSDDESC_USESYSTEMMEMORY
) {
624 dsb
->buffer
= HeapAlloc(GetProcessHeap(),0,sizeof(*(dsb
->buffer
)));
625 if (dsb
->buffer
== NULL
) {
626 WARN("out of memory\n");
627 HeapFree(GetProcessHeap(),0,dsb
);
629 return DSERR_OUTOFMEMORY
;
632 dsb
->buffer
->memory
= (LPBYTE
)HeapAlloc(GetProcessHeap(),0,dsb
->buflen
);
633 if (dsb
->buffer
->memory
== NULL
) {
634 WARN("out of memory\n");
635 HeapFree(GetProcessHeap(),0,dsb
->buffer
);
636 HeapFree(GetProcessHeap(),0,dsb
);
638 return DSERR_OUTOFMEMORY
;
640 dsb
->buffer
->ref
= 1;
642 /* FIXME: copy buffer ? */
651 dsb
->state
= STATE_STOPPED
;
656 dsb
->iks
= NULL
; /* FIXME? */
658 memcpy(&(dsb
->wfx
), &(pdsb
->wfx
), sizeof(dsb
->wfx
));
659 InitializeCriticalSection(&(dsb
->lock
));
660 /* register buffer */
661 RtlAcquireResourceExclusive(&(This
->lock
), TRUE
);
663 IDirectSoundBufferImpl
**newbuffers
;
665 newbuffers
= (IDirectSoundBufferImpl
**)HeapReAlloc(GetProcessHeap(),0,This
->buffers
,sizeof(IDirectSoundBufferImpl
**)*(This
->nrofbuffers
+1));
667 newbuffers
= (IDirectSoundBufferImpl
**)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundBufferImpl
**)*(This
->nrofbuffers
+1));
670 This
->buffers
= newbuffers
;
671 This
->buffers
[This
->nrofbuffers
] = dsb
;
673 TRACE("buffer count is now %d\n", This
->nrofbuffers
);
675 ERR("out of memory for buffer list! Current buffer count is %d\n", This
->nrofbuffers
);
676 IDirectSoundBuffer8_Release(psb
);
677 DeleteCriticalSection(&(dsb
->lock
));
678 RtlReleaseResource(&(This
->lock
));
679 HeapFree(GetProcessHeap(),0,dsb
);
681 return DSERR_OUTOFMEMORY
;
684 RtlReleaseResource(&(This
->lock
));
685 IDirectSound_AddRef(iface
);
686 hres
= SecondaryBufferImpl_Create(dsb
, (SecondaryBufferImpl
**)ppdsb
);
688 dsb
->dsb
= (SecondaryBufferImpl
*)*ppdsb
;
689 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8
)*ppdsb
);
691 WARN("SecondaryBufferImpl_Create failed\n");
696 static HRESULT WINAPI
IDirectSoundImpl_GetCaps(LPDIRECTSOUND8 iface
,LPDSCAPS lpDSCaps
) {
697 ICOM_THIS(IDirectSoundImpl
,iface
);
698 TRACE("(%p,%p)\n",This
,lpDSCaps
);
701 WARN("invalid parameter: This == NULL\n");
702 return DSERR_INVALIDPARAM
;
705 if (lpDSCaps
== NULL
) {
706 WARN("invalid parameter: lpDSCaps = NULL\n");
707 return DSERR_INVALIDPARAM
;
710 /* check is there is enough room */
711 if (lpDSCaps
->dwSize
< sizeof(*lpDSCaps
)) {
712 WARN("invalid parameter: lpDSCaps->dwSize = %ld < %d\n",
713 lpDSCaps
->dwSize
, sizeof(*lpDSCaps
));
714 return DSERR_INVALIDPARAM
;
717 lpDSCaps
->dwFlags
= This
->drvcaps
.dwFlags
;
718 TRACE("(flags=0x%08lx)\n",lpDSCaps
->dwFlags
);
720 lpDSCaps
->dwMinSecondarySampleRate
= This
->drvcaps
.dwMinSecondarySampleRate
;
721 lpDSCaps
->dwMaxSecondarySampleRate
= This
->drvcaps
.dwMaxSecondarySampleRate
;
723 lpDSCaps
->dwPrimaryBuffers
= This
->drvcaps
.dwPrimaryBuffers
;
725 lpDSCaps
->dwMaxHwMixingAllBuffers
= This
->drvcaps
.dwMaxHwMixingAllBuffers
;
726 lpDSCaps
->dwMaxHwMixingStaticBuffers
= This
->drvcaps
.dwMaxHwMixingStaticBuffers
;
727 lpDSCaps
->dwMaxHwMixingStreamingBuffers
= This
->drvcaps
.dwMaxHwMixingStreamingBuffers
;
729 lpDSCaps
->dwFreeHwMixingAllBuffers
= This
->drvcaps
.dwFreeHwMixingAllBuffers
;
730 lpDSCaps
->dwFreeHwMixingStaticBuffers
= This
->drvcaps
.dwFreeHwMixingStaticBuffers
;
731 lpDSCaps
->dwFreeHwMixingStreamingBuffers
= This
->drvcaps
.dwFreeHwMixingStreamingBuffers
;
733 lpDSCaps
->dwMaxHw3DAllBuffers
= This
->drvcaps
.dwMaxHw3DAllBuffers
;
734 lpDSCaps
->dwMaxHw3DStaticBuffers
= This
->drvcaps
.dwMaxHw3DStaticBuffers
;
735 lpDSCaps
->dwMaxHw3DStreamingBuffers
= This
->drvcaps
.dwMaxHw3DStreamingBuffers
;
737 lpDSCaps
->dwFreeHw3DAllBuffers
= This
->drvcaps
.dwFreeHw3DAllBuffers
;
738 lpDSCaps
->dwFreeHw3DStaticBuffers
= This
->drvcaps
.dwFreeHw3DStaticBuffers
;
739 lpDSCaps
->dwFreeHw3DStreamingBuffers
= This
->drvcaps
.dwFreeHw3DStreamingBuffers
;
741 lpDSCaps
->dwTotalHwMemBytes
= This
->drvcaps
.dwTotalHwMemBytes
;
743 lpDSCaps
->dwFreeHwMemBytes
= This
->drvcaps
.dwFreeHwMemBytes
;
745 lpDSCaps
->dwMaxContigFreeHwMemBytes
= This
->drvcaps
.dwMaxContigFreeHwMemBytes
;
747 /* driver doesn't have these */
748 lpDSCaps
->dwUnlockTransferRateHwBuffers
= 4096; /* But we have none... */
750 lpDSCaps
->dwPlayCpuOverheadSwBuffers
= 1; /* 1% */
755 static ULONG WINAPI
IDirectSoundImpl_AddRef(LPDIRECTSOUND8 iface
) {
756 ICOM_THIS(IDirectSoundImpl
,iface
);
757 TRACE("(%p) ref was %ld, thread is %04lx\n", This
, This
->ref
, GetCurrentThreadId());
758 return InterlockedIncrement(&This
->ref
);
761 static ULONG WINAPI
IDirectSoundImpl_Release(LPDIRECTSOUND8 iface
) {
762 ICOM_THIS(IDirectSoundImpl
,iface
);
765 TRACE("(%p) ref was %ld, thread is %04lx\n", This
, This
->ref
, GetCurrentThreadId());
766 ulReturn
= InterlockedDecrement(&This
->ref
);
771 timeKillEvent(This
->timerID
);
772 timeEndPeriod(DS_TIME_RES
);
773 /* wait for timer to expire */
774 Sleep(DS_TIME_RES
+1);
776 RtlAcquireResourceShared(&(This
->lock
), TRUE
);
779 for( i
=0;i
<This
->nrofbuffers
;i
++)
780 IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8
)This
->buffers
[i
]);
783 RtlReleaseResource(&(This
->lock
));
786 WARN("primary buffer not released\n");
787 IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8
)This
->primary
);
790 hres
= DSOUND_PrimaryDestroy(This
);
792 WARN("DSOUND_PrimaryDestroy failed\n");
795 IDsDriver_Close(This
->driver
);
797 if (This
->drvdesc
.dwFlags
& DSDDESC_DOMMSYSTEMOPEN
)
798 waveOutClose(This
->hwo
);
801 IDsDriver_Release(This
->driver
);
803 RtlDeleteResource(&This
->lock
);
804 DeleteCriticalSection(&This
->mixlock
);
805 HeapFree(GetProcessHeap(),0,This
);
807 TRACE("(%p) released\n",This
);
813 static HRESULT WINAPI
IDirectSoundImpl_SetSpeakerConfig(
814 LPDIRECTSOUND8 iface
,DWORD config
816 ICOM_THIS(IDirectSoundImpl
,iface
);
817 TRACE("(%p,0x%08lx)\n",This
,config
);
819 This
->speaker_config
= config
;
821 WARN("not fully functional\n");
825 static HRESULT WINAPI
IDirectSoundImpl_QueryInterface(
826 LPDIRECTSOUND8 iface
,REFIID riid
,LPVOID
*ppobj
828 ICOM_THIS(IDirectSoundImpl
,iface
);
829 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
832 WARN("invalid parameter\n");
836 *ppobj
= NULL
; /* assume failure */
838 if ( IsEqualGUID(riid
, &IID_IUnknown
) ||
839 IsEqualGUID(riid
, &IID_IDirectSound
) ||
840 IsEqualGUID(riid
, &IID_IDirectSound8
) ) {
841 IDirectSound8_AddRef((LPDIRECTSOUND8
)This
);
846 if ( IsEqualGUID( &IID_IDirectSound3DListener
, riid
) ) {
847 WARN("app requested IDirectSound3DListener on dsound object\n");
848 return E_NOINTERFACE
;
851 FIXME( "Unknown IID %s\n", debugstr_guid( riid
) );
852 return E_NOINTERFACE
;
855 static HRESULT WINAPI
IDirectSoundImpl_Compact(
856 LPDIRECTSOUND8 iface
)
858 ICOM_THIS(IDirectSoundImpl
,iface
);
859 TRACE("(%p)\n", This
);
863 static HRESULT WINAPI
IDirectSoundImpl_GetSpeakerConfig(
864 LPDIRECTSOUND8 iface
,
865 LPDWORD lpdwSpeakerConfig
)
867 ICOM_THIS(IDirectSoundImpl
,iface
);
868 TRACE("(%p, %p)\n", This
, lpdwSpeakerConfig
);
870 if (lpdwSpeakerConfig
== NULL
) {
871 WARN("invalid parameter\n");
872 return DSERR_INVALIDPARAM
;
875 WARN("not fully functional\n");
877 *lpdwSpeakerConfig
= This
->speaker_config
;
882 static HRESULT WINAPI
IDirectSoundImpl_Initialize(
883 LPDIRECTSOUND8 iface
,
886 ICOM_THIS(IDirectSoundImpl
,iface
);
887 TRACE("(%p, %s)\n", This
, debugstr_guid(lpcGuid
));
891 static HRESULT WINAPI
IDirectSoundImpl_VerifyCertification(
892 LPDIRECTSOUND8 iface
,
893 LPDWORD pdwCertified
)
895 ICOM_THIS(IDirectSoundImpl
,iface
);
896 TRACE("(%p, %p)\n", This
, pdwCertified
);
897 *pdwCertified
= DS_CERTIFIED
;
901 static ICOM_VTABLE(IDirectSound8
) dsvt
=
903 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
904 IDirectSoundImpl_QueryInterface
,
905 IDirectSoundImpl_AddRef
,
906 IDirectSoundImpl_Release
,
907 IDirectSoundImpl_CreateSoundBuffer
,
908 IDirectSoundImpl_GetCaps
,
909 IDirectSoundImpl_DuplicateSoundBuffer
,
910 IDirectSoundImpl_SetCooperativeLevel
,
911 IDirectSoundImpl_Compact
,
912 IDirectSoundImpl_GetSpeakerConfig
,
913 IDirectSoundImpl_SetSpeakerConfig
,
914 IDirectSoundImpl_Initialize
,
915 IDirectSoundImpl_VerifyCertification
919 /*******************************************************************************
920 * DirectSoundCreate (DSOUND.1)
922 * Creates and initializes a DirectSound interface.
925 * lpcGUID [I] Address of the GUID that identifies the sound device.
926 * ppDS [O] Address of a variable to receive the interface pointer.
927 * pUnkOuter [I] Must be NULL.
931 * Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
932 * DSERR_NODRIVER, DSERR_OUTOFMEMORY
934 HRESULT WINAPI
DirectSoundCreate8(LPCGUID lpcGUID
,LPDIRECTSOUND8
*ppDS
,IUnknown
*pUnkOuter
)
936 IDirectSoundImpl
** ippDS
=(IDirectSoundImpl
**)ppDS
;
937 PIDSDRIVER drv
= NULL
;
939 HRESULT err
= DSERR_INVALIDPARAM
;
941 BOOLEAN found
= FALSE
;
943 TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID
),ippDS
,pUnkOuter
);
946 WARN("invalid parameter: ippDS == NULL\n");
947 return DSERR_INVALIDPARAM
;
950 /* Get dsound configuration */
951 setup_dsound_options();
953 /* Default device? */
954 if (!lpcGUID
|| IsEqualGUID(lpcGUID
, &GUID_NULL
))
955 lpcGUID
= &DSDEVID_DefaultPlayback
;
957 if (GetDeviceID(lpcGUID
, &devGuid
) != DS_OK
) {
958 WARN("invalid parameter: lpcGUID\n");
960 return DSERR_INVALIDPARAM
;
964 if (IsEqualGUID(&devGuid
, &dsound
->guid
) ) {
965 /* FIXME: this is wrong, need to create a new instance */
966 ERR("dsound already opened\n");
967 IDirectSound_AddRef((LPDIRECTSOUND
)dsound
);
971 ERR("different dsound already opened\n");
975 /* Enumerate WINMM audio devices and find the one we want */
976 wodn
= waveOutGetNumDevs();
980 return DSERR_NODRIVER
;
983 TRACE(" expecting GUID %s.\n", debugstr_guid(&devGuid
));
985 for (wod
=0; wod
<wodn
; wod
++) {
987 err
= mmErr(waveOutMessage((HWAVEOUT
)wod
,DRV_QUERYDSOUNDGUID
,(DWORD
)(&guid
),0));
989 WARN("waveOutMessage failed; err=%lx\n",err
);
993 TRACE("got GUID %s for wod %d.\n", debugstr_guid(&guid
), wod
);
994 if (IsEqualGUID( &devGuid
, &guid
) ) {
1002 WARN("invalid parameter\n");
1004 return DSERR_INVALIDPARAM
;
1007 if (found
== FALSE
) {
1008 WARN("No device found matching given ID - trying with default one !\n");
1009 wod
= ds_default_playback
;
1012 /* DRV_QUERYDSOUNDIFACE is a "Wine extension" to get the DSound interface */
1013 waveOutMessage((HWAVEOUT
)wod
, DRV_QUERYDSOUNDIFACE
, (DWORD
)&drv
, 0);
1015 /* Disable the direct sound driver to force emulation if requested. */
1016 if (ds_hw_accel
== DS_HW_ACCEL_EMULATION
)
1019 /* Allocate memory */
1020 *ippDS
= (IDirectSoundImpl
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDirectSoundImpl
));
1021 if (*ippDS
== NULL
) {
1022 WARN("out of memory\n");
1023 return DSERR_OUTOFMEMORY
;
1026 (*ippDS
)->lpVtbl
= &dsvt
;
1029 (*ippDS
)->driver
= drv
;
1030 (*ippDS
)->priolevel
= DSSCL_NORMAL
;
1031 (*ippDS
)->fraglen
= 0;
1032 (*ippDS
)->hwbuf
= NULL
;
1033 (*ippDS
)->buffer
= NULL
;
1034 (*ippDS
)->buflen
= 0;
1035 (*ippDS
)->writelead
= 0;
1036 (*ippDS
)->state
= STATE_STOPPED
;
1037 (*ippDS
)->nrofbuffers
= 0;
1038 (*ippDS
)->buffers
= NULL
;
1039 (*ippDS
)->primary
= NULL
;
1040 (*ippDS
)->speaker_config
= DSSPEAKER_STEREO
| (DSSPEAKER_GEOMETRY_NARROW
<< 16);
1042 /* 3D listener initial parameters */
1043 (*ippDS
)->listener
= NULL
;
1044 (*ippDS
)->ds3dl
.dwSize
= sizeof(DS3DLISTENER
);
1045 (*ippDS
)->ds3dl
.vPosition
.x
= 0.0;
1046 (*ippDS
)->ds3dl
.vPosition
.y
= 0.0;
1047 (*ippDS
)->ds3dl
.vPosition
.z
= 0.0;
1048 (*ippDS
)->ds3dl
.vVelocity
.x
= 0.0;
1049 (*ippDS
)->ds3dl
.vVelocity
.y
= 0.0;
1050 (*ippDS
)->ds3dl
.vVelocity
.z
= 0.0;
1051 (*ippDS
)->ds3dl
.vOrientFront
.x
= 0.0;
1052 (*ippDS
)->ds3dl
.vOrientFront
.y
= 0.0;
1053 (*ippDS
)->ds3dl
.vOrientFront
.z
= 1.0;
1054 (*ippDS
)->ds3dl
.vOrientTop
.x
= 0.0;
1055 (*ippDS
)->ds3dl
.vOrientTop
.y
= 1.0;
1056 (*ippDS
)->ds3dl
.vOrientTop
.z
= 0.0;
1057 (*ippDS
)->ds3dl
.flDistanceFactor
= DS3D_DEFAULTDISTANCEFACTOR
;
1058 (*ippDS
)->ds3dl
.flRolloffFactor
= DS3D_DEFAULTROLLOFFFACTOR
;
1059 (*ippDS
)->ds3dl
.flDopplerFactor
= DS3D_DEFAULTDOPPLERFACTOR
;
1061 (*ippDS
)->prebuf
= ds_snd_queue_max
;
1062 (*ippDS
)->guid
= devGuid
;
1064 /* Get driver description */
1066 err
= IDsDriver_GetDriverDesc(drv
,&((*ippDS
)->drvdesc
));
1068 WARN("IDsDriver_GetDriverDesc failed\n");
1069 HeapFree(GetProcessHeap(),0,*ippDS
);
1074 /* if no DirectSound interface available, use WINMM API instead */
1075 (*ippDS
)->drvdesc
.dwFlags
= DSDDESC_DOMMSYSTEMOPEN
| DSDDESC_DOMMSYSTEMSETFORMAT
;
1078 (*ippDS
)->drvdesc
.dnDevNode
= wod
;
1080 /* Set default wave format (may need it for waveOutOpen) */
1081 (*ippDS
)->wfx
.wFormatTag
= WAVE_FORMAT_PCM
;
1082 /* We rely on the sound driver to return the actual sound format of
1083 * the device if it does not support 22050x8x2 and is given the
1084 * WAVE_DIRECTSOUND flag.
1086 (*ippDS
)->wfx
.nSamplesPerSec
= 22050;
1087 (*ippDS
)->wfx
.wBitsPerSample
= 8;
1088 (*ippDS
)->wfx
.nChannels
= 2;
1089 (*ippDS
)->wfx
.nBlockAlign
= (*ippDS
)->wfx
.wBitsPerSample
* (*ippDS
)->wfx
.nChannels
/ 8;
1090 (*ippDS
)->wfx
.nAvgBytesPerSec
= (*ippDS
)->wfx
.nSamplesPerSec
* (*ippDS
)->wfx
.nBlockAlign
;
1091 (*ippDS
)->wfx
.cbSize
= 0;
1093 /* If the driver requests being opened through MMSYSTEM
1094 * (which is recommended by the DDK), it is supposed to happen
1095 * before the DirectSound interface is opened */
1096 if ((*ippDS
)->drvdesc
.dwFlags
& DSDDESC_DOMMSYSTEMOPEN
)
1098 DWORD flags
= CALLBACK_FUNCTION
;
1100 /* disable direct sound if requested */
1101 if (ds_hw_accel
!= DS_HW_ACCEL_EMULATION
)
1102 flags
|= WAVE_DIRECTSOUND
;
1104 err
= mmErr(waveOutOpen(&((*ippDS
)->hwo
),
1105 (*ippDS
)->drvdesc
.dnDevNode
, &((*ippDS
)->wfx
),
1106 (DWORD
)DSOUND_callback
, (DWORD
)(*ippDS
),
1109 WARN("waveOutOpen failed\n");
1110 HeapFree(GetProcessHeap(),0,*ippDS
);
1117 err
= IDsDriver_Open(drv
);
1119 WARN("IDsDriver_Open failed\n");
1120 HeapFree(GetProcessHeap(),0,*ippDS
);
1125 /* the driver is now open, so it's now allowed to call GetCaps */
1126 err
= IDsDriver_GetCaps(drv
,&((*ippDS
)->drvcaps
));
1128 WARN("IDsDriver_GetCaps failed\n");
1129 HeapFree(GetProcessHeap(),0,*ippDS
);
1135 err
= mmErr(waveOutGetDevCapsA((*ippDS
)->drvdesc
.dnDevNode
, &woc
, sizeof(woc
)));
1137 WARN("waveOutGetDevCaps failed\n");
1138 HeapFree(GetProcessHeap(),0,*ippDS
);
1142 ZeroMemory(&(*ippDS
)->drvcaps
, sizeof((*ippDS
)->drvcaps
));
1143 if ((woc
.dwFormats
& WAVE_FORMAT_1M08
) ||
1144 (woc
.dwFormats
& WAVE_FORMAT_2M08
) ||
1145 (woc
.dwFormats
& WAVE_FORMAT_4M08
) ||
1146 (woc
.dwFormats
& WAVE_FORMAT_48M08
) ||
1147 (woc
.dwFormats
& WAVE_FORMAT_96M08
)) {
1148 (*ippDS
)->drvcaps
.dwFlags
|= DSCAPS_PRIMARY8BIT
;
1149 (*ippDS
)->drvcaps
.dwFlags
|= DSCAPS_PRIMARYMONO
;
1151 if ((woc
.dwFormats
& WAVE_FORMAT_1M16
) ||
1152 (woc
.dwFormats
& WAVE_FORMAT_2M16
) ||
1153 (woc
.dwFormats
& WAVE_FORMAT_4M16
) ||
1154 (woc
.dwFormats
& WAVE_FORMAT_48M16
) ||
1155 (woc
.dwFormats
& WAVE_FORMAT_96M16
)) {
1156 (*ippDS
)->drvcaps
.dwFlags
|= DSCAPS_PRIMARY16BIT
;
1157 (*ippDS
)->drvcaps
.dwFlags
|= DSCAPS_PRIMARYMONO
;
1159 if ((woc
.dwFormats
& WAVE_FORMAT_1S08
) ||
1160 (woc
.dwFormats
& WAVE_FORMAT_2S08
) ||
1161 (woc
.dwFormats
& WAVE_FORMAT_4S08
) ||
1162 (woc
.dwFormats
& WAVE_FORMAT_48S08
) ||
1163 (woc
.dwFormats
& WAVE_FORMAT_96S08
)) {
1164 (*ippDS
)->drvcaps
.dwFlags
|= DSCAPS_PRIMARY8BIT
;
1165 (*ippDS
)->drvcaps
.dwFlags
|= DSCAPS_PRIMARYSTEREO
;
1167 if ((woc
.dwFormats
& WAVE_FORMAT_1S16
) ||
1168 (woc
.dwFormats
& WAVE_FORMAT_2S16
) ||
1169 (woc
.dwFormats
& WAVE_FORMAT_4S16
) ||
1170 (woc
.dwFormats
& WAVE_FORMAT_48S16
) ||
1171 (woc
.dwFormats
& WAVE_FORMAT_96S16
)) {
1172 (*ippDS
)->drvcaps
.dwFlags
|= DSCAPS_PRIMARY16BIT
;
1173 (*ippDS
)->drvcaps
.dwFlags
|= DSCAPS_PRIMARYSTEREO
;
1176 (*ippDS
)->drvcaps
.dwFlags
|= DSCAPS_EMULDRIVER
;
1177 (*ippDS
)->drvcaps
.dwMinSecondarySampleRate
= DSBFREQUENCY_MIN
;
1178 (*ippDS
)->drvcaps
.dwMaxSecondarySampleRate
= DSBFREQUENCY_MAX
;
1179 (*ippDS
)->drvcaps
.dwPrimaryBuffers
= 1;
1182 (*ippDS
)->volpan
.lVolume
= 0;
1183 (*ippDS
)->volpan
.lPan
= 0;
1184 DSOUND_RecalcVolPan(&((*ippDS
)->volpan
));
1186 InitializeCriticalSection(&((*ippDS
)->mixlock
));
1187 RtlInitializeResource(&((*ippDS
)->lock
));
1192 hres
= DSOUND_PrimaryCreate(dsound
);
1193 if (hres
!= DS_OK
) {
1194 WARN("DSOUND_PrimaryCreate failed\n");
1197 timeBeginPeriod(DS_TIME_RES
);
1198 dsound
->timerID
= timeSetEvent(DS_TIME_DEL
, DS_TIME_RES
, DSOUND_timer
,
1199 (DWORD
)dsound
, TIME_PERIODIC
| TIME_CALLBACK_FUNCTION
);
1206 /*******************************************************************************
1207 * DirectSound ClassFactory
1210 static HRESULT WINAPI
1211 DSCF_QueryInterface(LPCLASSFACTORY iface
,REFIID riid
,LPVOID
*ppobj
) {
1212 ICOM_THIS(IClassFactoryImpl
,iface
);
1214 FIXME("(%p)->(%s,%p),stub!\n",This
,debugstr_guid(riid
),ppobj
);
1215 return E_NOINTERFACE
;
1219 DSCF_AddRef(LPCLASSFACTORY iface
) {
1220 ICOM_THIS(IClassFactoryImpl
,iface
);
1221 TRACE("(%p) ref was %ld\n", This
, This
->ref
);
1222 return ++(This
->ref
);
1225 static ULONG WINAPI
DSCF_Release(LPCLASSFACTORY iface
) {
1226 ICOM_THIS(IClassFactoryImpl
,iface
);
1227 /* static class, won't be freed */
1228 TRACE("(%p) ref was %ld\n", This
, This
->ref
);
1229 return --(This
->ref
);
1232 static HRESULT WINAPI
DSCF_CreateInstance(
1233 LPCLASSFACTORY iface
,LPUNKNOWN pOuter
,REFIID riid
,LPVOID
*ppobj
1235 ICOM_THIS(IClassFactoryImpl
,iface
);
1236 TRACE("(%p)->(%p,%s,%p)\n",This
,pOuter
,debugstr_guid(riid
),ppobj
);
1238 if (ppobj
== NULL
) {
1239 WARN("invalid parameter\n");
1240 return DSERR_INVALIDPARAM
;
1245 if ( IsEqualGUID( &IID_IDirectSound
, riid
) ||
1246 IsEqualGUID( &IID_IDirectSound8
, riid
) ) {
1247 /* FIXME: reuse already created dsound if present? */
1248 return DirectSoundCreate8(0,(LPDIRECTSOUND8
*)ppobj
,pOuter
);
1251 WARN("(%p,%p,%s,%p) Interface not found!\n",This
,pOuter
,debugstr_guid(riid
),ppobj
);
1252 return E_NOINTERFACE
;
1255 static HRESULT WINAPI
DSCF_LockServer(LPCLASSFACTORY iface
,BOOL dolock
) {
1256 ICOM_THIS(IClassFactoryImpl
,iface
);
1257 FIXME("(%p)->(%d),stub!\n",This
,dolock
);
1261 static ICOM_VTABLE(IClassFactory
) DSCF_Vtbl
= {
1262 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1263 DSCF_QueryInterface
,
1266 DSCF_CreateInstance
,
1270 static IClassFactoryImpl DSOUND_CF
= { &DSCF_Vtbl
, 1 };
1272 /*******************************************************************************
1273 * DirectSoundPrivate ClassFactory
1276 static HRESULT WINAPI
1277 DSPCF_QueryInterface(LPCLASSFACTORY iface
,REFIID riid
,LPVOID
*ppobj
) {
1278 ICOM_THIS(IClassFactoryImpl
,iface
);
1280 FIXME("(%p)->(%s,%p),stub!\n",This
,debugstr_guid(riid
),ppobj
);
1281 return E_NOINTERFACE
;
1285 DSPCF_AddRef(LPCLASSFACTORY iface
) {
1286 ICOM_THIS(IClassFactoryImpl
,iface
);
1287 TRACE("(%p) ref was %ld\n", This
, This
->ref
);
1288 return ++(This
->ref
);
1292 DSPCF_Release(LPCLASSFACTORY iface
) {
1293 ICOM_THIS(IClassFactoryImpl
,iface
);
1294 /* static class, won't be freed */
1295 TRACE("(%p) ref was %ld\n", This
, This
->ref
);
1296 return --(This
->ref
);
1299 static HRESULT WINAPI
1300 DSPCF_CreateInstance(
1301 LPCLASSFACTORY iface
,LPUNKNOWN pOuter
,REFIID riid
,LPVOID
*ppobj
1303 ICOM_THIS(IClassFactoryImpl
,iface
);
1304 TRACE("(%p)->(%p,%s,%p)\n",This
,pOuter
,debugstr_guid(riid
),ppobj
);
1306 if (ppobj
== NULL
) {
1307 WARN("invalid parameter\n");
1308 return DSERR_INVALIDPARAM
;
1313 if ( IsEqualGUID( &IID_IKsPropertySet
, riid
) ) {
1314 return IKsPrivatePropertySetImpl_Create((IKsPrivatePropertySetImpl
**)ppobj
);
1317 WARN("(%p,%p,%s,%p) Interface not found!\n",This
,pOuter
,debugstr_guid(riid
),ppobj
);
1318 return E_NOINTERFACE
;
1321 static HRESULT WINAPI
1322 DSPCF_LockServer(LPCLASSFACTORY iface
,BOOL dolock
) {
1323 ICOM_THIS(IClassFactoryImpl
,iface
);
1324 FIXME("(%p)->(%d),stub!\n",This
,dolock
);
1328 static ICOM_VTABLE(IClassFactory
) DSPCF_Vtbl
= {
1329 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1330 DSPCF_QueryInterface
,
1333 DSPCF_CreateInstance
,
1337 static IClassFactoryImpl DSOUND_PRIVATE_CF
= { &DSPCF_Vtbl
, 1 };
1339 /*******************************************************************************
1340 * DllGetClassObject [DSOUND.5]
1341 * Retrieves class object from a DLL object
1344 * Docs say returns STDAPI
1347 * rclsid [I] CLSID for the class object
1348 * riid [I] Reference to identifier of interface for class object
1349 * ppv [O] Address of variable to receive interface pointer for riid
1353 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
1356 DWORD WINAPI
DSOUND_DllGetClassObject(REFCLSID rclsid
,REFIID riid
,LPVOID
*ppv
)
1358 TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid
), debugstr_guid(riid
), ppv
);
1361 WARN("invalid parameter\n");
1362 return E_INVALIDARG
;
1367 if ( IsEqualCLSID( &CLSID_DirectSound
, rclsid
) ||
1368 IsEqualCLSID( &CLSID_DirectSound8
, rclsid
) ) {
1369 if ( IsEqualCLSID( &IID_IClassFactory
, riid
) ) {
1370 *ppv
= (LPVOID
)&DSOUND_CF
;
1371 IClassFactory_AddRef((IClassFactory
*)*ppv
);
1374 WARN("(%s,%s,%p): no interface found.\n",
1375 debugstr_guid(rclsid
), debugstr_guid(riid
), ppv
);
1379 if ( IsEqualCLSID( &CLSID_DirectSoundCapture
, rclsid
) ||
1380 IsEqualCLSID( &CLSID_DirectSoundCapture8
, rclsid
) ) {
1381 if ( IsEqualCLSID( &IID_IClassFactory
, riid
) ) {
1382 *ppv
= (LPVOID
)&DSOUND_CAPTURE_CF
;
1383 IClassFactory_AddRef((IClassFactory
*)*ppv
);
1386 WARN("(%s,%s,%p): no interface found.\n",
1387 debugstr_guid(rclsid
), debugstr_guid(riid
), ppv
);
1391 if ( IsEqualCLSID( &CLSID_DirectSoundFullDuplex
, rclsid
) ) {
1392 if ( IsEqualCLSID( &IID_IClassFactory
, riid
) ) {
1393 *ppv
= (LPVOID
)&DSOUND_FULLDUPLEX_CF
;
1394 IClassFactory_AddRef((IClassFactory
*)*ppv
);
1397 WARN("(%s,%s,%p): no interface found.\n",
1398 debugstr_guid(rclsid
), debugstr_guid(riid
), ppv
);
1402 if ( IsEqualCLSID( &CLSID_DirectSoundPrivate
, rclsid
) ) {
1403 if ( IsEqualCLSID( &IID_IClassFactory
, riid
) ) {
1404 *ppv
= (LPVOID
)&DSOUND_PRIVATE_CF
;
1405 IClassFactory_AddRef((IClassFactory
*)*ppv
);
1408 WARN("(%s,%s,%p): no interface found.\n",
1409 debugstr_guid(rclsid
), debugstr_guid(riid
), ppv
);
1413 WARN("(%s,%s,%p): no class found.\n", debugstr_guid(rclsid
), debugstr_guid(riid
), ppv
);
1414 return CLASS_E_CLASSNOTAVAILABLE
;
1418 /*******************************************************************************
1419 * DllCanUnloadNow [DSOUND.4]
1420 * Determines whether the DLL is in use.
1426 DWORD WINAPI
DSOUND_DllCanUnloadNow(void)
1428 FIXME("(void): stub\n");