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"
44 #include <sys/types.h>
45 #include <sys/fcntl.h>
53 #define NONAMELESSSTRUCT
54 #define NONAMELESSUNION
65 #include "wine/windef16.h"
66 #include "wine/winbase16.h"
67 #include "wine/debug.h"
70 #include "dsound_private.h"
73 WINE_DEFAULT_DEBUG_CHANNEL(dsound
);
75 /* these are eligible for tuning... they must be high on slow machines... */
76 /* some stuff may get more responsive with lower values though... */
77 #define DS_EMULDRIVER 0 /* some games (Quake 2, UT) refuse to accept
78 emulated dsound devices. set to 0 ! */
79 #define DS_HEL_MARGIN 5 /* HEL only: number of waveOut fragments ahead to mix in new buffers
80 * (keep this close or equal to DS_HEL_QUEUE for best results) */
81 #define DS_HEL_QUEUE 5 /* HEL only: number of waveOut fragments ahead to queue to driver
82 * (this will affect HEL sound reliability and latency) */
84 #define DS_SND_QUEUE_MAX 28 /* max number of fragments to prebuffer */
85 #define DS_SND_QUEUE_MIN 12 /* min number of fragments to prebuffer */
87 IDirectSoundImpl
* dsound
= NULL
;
89 HRESULT
mmErr(UINT err
)
92 case MMSYSERR_NOERROR
:
94 case MMSYSERR_ALLOCATED
:
95 return DSERR_ALLOCATED
;
97 case MMSYSERR_INVALHANDLE
:
98 case WAVERR_STILLPLAYING
:
99 return DSERR_GENERIC
; /* FIXME */
100 case MMSYSERR_NODRIVER
:
101 return DSERR_NODRIVER
;
103 return DSERR_OUTOFMEMORY
;
104 case MMSYSERR_INVALPARAM
:
105 case WAVERR_BADFORMAT
:
106 case WAVERR_UNPREPARED
:
107 return DSERR_INVALIDPARAM
;
108 case MMSYSERR_NOTSUPPORTED
:
109 return DSERR_UNSUPPORTED
;
111 FIXME("Unknown MMSYS error %d\n",err
);
112 return DSERR_GENERIC
;
116 int ds_emuldriver
= DS_EMULDRIVER
;
117 int ds_hel_margin
= DS_HEL_MARGIN
;
118 int ds_hel_queue
= DS_HEL_QUEUE
;
119 int ds_snd_queue_max
= DS_SND_QUEUE_MAX
;
120 int ds_snd_queue_min
= DS_SND_QUEUE_MIN
;
121 int ds_hw_accel
= DS_HW_ACCEL_FULL
;
122 int ds_default_playback
= 0;
123 int ds_default_capture
= 0;
126 * Get a config key from either the app-specific or the default config
129 inline static DWORD
get_config_key( HKEY defkey
, HKEY appkey
, const char *name
,
130 char *buffer
, DWORD size
)
132 if (appkey
&& !RegQueryValueExA( appkey
, name
, 0, NULL
, buffer
, &size
)) return 0;
133 return RegQueryValueExA( defkey
, name
, 0, NULL
, buffer
, &size
);
138 * Setup the dsound options.
141 void setup_dsound_options(void)
143 char buffer
[MAX_PATH
+1];
144 HKEY hkey
, appkey
= 0;
146 buffer
[MAX_PATH
]='\0';
148 if (RegCreateKeyExA( HKEY_LOCAL_MACHINE
, "Software\\Wine\\Wine\\Config\\dsound", 0, NULL
,
149 REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
))
151 ERR("Cannot create config registry key\n" );
155 if (GetModuleFileNameA( 0, buffer
, MAX_PATH
))
159 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE
, "Software\\Wine\\Wine\\Config\\AppDefaults", &tmpkey
))
161 char appname
[MAX_PATH
+16];
162 char *p
= strrchr( buffer
, '\\' );
164 appname
[MAX_PATH
]='\0';
165 strncpy(appname
,p
+1,MAX_PATH
);
166 strcat(appname
,"\\dsound");
167 TRACE("appname = [%s] \n",appname
);
168 if (RegOpenKeyA( tmpkey
, appname
, &appkey
)) appkey
= 0;
169 RegCloseKey( tmpkey
);
176 if (!get_config_key( hkey
, appkey
, "EmulDriver", buffer
, MAX_PATH
))
177 ds_emuldriver
= strcmp(buffer
, "N");
179 if (!get_config_key( hkey
, appkey
, "HELmargin", buffer
, MAX_PATH
))
180 ds_hel_margin
= atoi(buffer
);
182 if (!get_config_key( hkey
, appkey
, "HELqueue", buffer
, MAX_PATH
))
183 ds_hel_queue
= atoi(buffer
);
185 if (!get_config_key( hkey
, appkey
, "SndQueueMax", buffer
, MAX_PATH
))
186 ds_snd_queue_max
= atoi(buffer
);
188 if (!get_config_key( hkey
, appkey
, "SndQueueMin", buffer
, MAX_PATH
))
189 ds_snd_queue_min
= atoi(buffer
);
191 if (!get_config_key( hkey
, appkey
, "HardwareAcceleration", buffer
, MAX_PATH
)) {
192 if (strcmp(buffer
, "Full") == 0)
193 ds_hw_accel
= DS_HW_ACCEL_FULL
;
194 else if (strcmp(buffer
, "Standard") == 0)
195 ds_hw_accel
= DS_HW_ACCEL_STANDARD
;
196 else if (strcmp(buffer
, "Basic") == 0)
197 ds_hw_accel
= DS_HW_ACCEL_BASIC
;
198 else if (strcmp(buffer
, "Emulation") == 0)
199 ds_hw_accel
= DS_HW_ACCEL_EMULATION
;
202 if (!get_config_key( hkey
, appkey
, "DefaultPlayback", buffer
, MAX_PATH
))
203 ds_default_playback
= atoi(buffer
);
205 if (!get_config_key( hkey
, appkey
, "DefaultCapture", buffer
, MAX_PATH
))
206 ds_default_capture
= atoi(buffer
);
208 if (appkey
) RegCloseKey( appkey
);
211 if (ds_emuldriver
!= DS_EMULDRIVER
)
212 WARN("ds_emuldriver = %d (default=%d)\n",ds_emuldriver
, DS_EMULDRIVER
);
213 if (ds_hel_margin
!= DS_HEL_MARGIN
)
214 WARN("ds_hel_margin = %d (default=%d)\n",ds_hel_margin
, DS_HEL_MARGIN
);
215 if (ds_hel_queue
!= DS_HEL_QUEUE
)
216 WARN("ds_hel_queue = %d (default=%d)\n",ds_hel_queue
, DS_HEL_QUEUE
);
217 if (ds_snd_queue_max
!= DS_SND_QUEUE_MAX
)
218 WARN("ds_snd_queue_max = %d (default=%d)\n",ds_snd_queue_max
,DS_SND_QUEUE_MAX
);
219 if (ds_snd_queue_min
!= DS_SND_QUEUE_MIN
)
220 WARN("ds_snd_queue_min = %d (default=%d)\n",ds_snd_queue_min
,DS_SND_QUEUE_MIN
);
221 if (ds_hw_accel
!= DS_HW_ACCEL_FULL
)
222 WARN("ds_hw_accel = %s (default=Full)\n",
223 ds_hw_accel
==DS_HW_ACCEL_FULL
? "Full" :
224 ds_hw_accel
==DS_HW_ACCEL_STANDARD
? "Standard" :
225 ds_hw_accel
==DS_HW_ACCEL_BASIC
? "Basic" :
226 ds_hw_accel
==DS_HW_ACCEL_EMULATION
? "Emulation" :
228 if (ds_default_playback
!= 0)
229 WARN("ds_default_playback = %d (default=0)\n",ds_default_playback
);
230 if (ds_default_capture
!= 0)
231 WARN("ds_default_capture = %d (default=0)\n",ds_default_playback
);
236 /***************************************************************************
237 * GetDeviceID [DSOUND.9]
239 * Retrieves unique identifier of default device specified
242 * pGuidSrc [I] Address of device GUID.
243 * pGuidDest [O] Address to receive unique device GUID.
247 * Failure: DSERR_INVALIDPARAM
250 * pGuidSrc is a valid device GUID or DSDEVID_DefaultPlayback,
251 * DSDEVID_DefaultCapture, DSDEVID_DefaultVoicePlayback, or
252 * DSDEVID_DefaultVoiceCapture.
253 * Returns pGuidSrc if pGuidSrc is a valid device or the device
254 * GUID for the specified constants.
256 HRESULT WINAPI
GetDeviceID(LPCGUID pGuidSrc
, LPGUID pGuidDest
)
258 TRACE("(%p,%p)\n",pGuidSrc
,pGuidDest
);
260 if ( pGuidSrc
== NULL
) {
261 WARN("invalid parameter: pGuidSrc == NULL\n");
262 return DSERR_INVALIDPARAM
;
265 if ( pGuidDest
== NULL
) {
266 WARN("invalid parameter: pGuidDest == NULL\n");
267 return DSERR_INVALIDPARAM
;
270 if ( IsEqualGUID( &DSDEVID_DefaultPlayback
, pGuidSrc
) ||
271 IsEqualGUID( &DSDEVID_DefaultVoicePlayback
, pGuidSrc
) ) {
273 int err
= mmErr(waveOutMessage((HWAVEOUT
)ds_default_playback
,DRV_QUERYDSOUNDGUID
,(DWORD
)&guid
,0));
275 memcpy(pGuidDest
, &guid
, sizeof(GUID
));
280 if ( IsEqualGUID( &DSDEVID_DefaultCapture
, pGuidSrc
) ||
281 IsEqualGUID( &DSDEVID_DefaultVoiceCapture
, pGuidSrc
) ) {
283 int err
= mmErr(waveInMessage((HWAVEIN
)ds_default_capture
,DRV_QUERYDSOUNDGUID
,(DWORD
)&guid
,0));
285 memcpy(pGuidDest
, &guid
, sizeof(GUID
));
290 memcpy(pGuidDest
, pGuidSrc
, sizeof(GUID
));
296 /***************************************************************************
297 * DirectSoundEnumerateA [DSOUND.2]
299 * Enumerate all DirectSound drivers installed in the system
302 * lpDSEnumCallback [I] Address of callback function.
303 * lpContext [I] Address of user defined context passed to callback function.
307 * Failure: DSERR_INVALIDPARAM
309 HRESULT WINAPI
DirectSoundEnumerateA(
310 LPDSENUMCALLBACKA lpDSEnumCallback
,
318 TRACE("lpDSEnumCallback = %p, lpContext = %p\n",
319 lpDSEnumCallback
, lpContext
);
321 if (lpDSEnumCallback
== NULL
) {
322 WARN("invalid parameter: lpDSEnumCallback == NULL\n");
323 return DSERR_INVALIDPARAM
;
326 devs
= waveOutGetNumDevs();
328 if (GetDeviceID(&DSDEVID_DefaultPlayback
, &guid
) == DS_OK
) {
330 for (wod
= 0; wod
< devs
; ++wod
) {
331 err
= mmErr(waveOutMessage((HWAVEOUT
)wod
,DRV_QUERYDSOUNDGUID
,(DWORD
)&temp
,0));
333 if (IsEqualGUID( &guid
, &temp
) ) {
334 err
= mmErr(waveOutMessage((HWAVEOUT
)wod
,DRV_QUERYDSOUNDDESC
,(DWORD
)&desc
,0));
336 TRACE("calling lpDSEnumCallback(%s,\"%s\",\"%s\",%p)\n",
337 debugstr_guid(&DSDEVID_DefaultPlayback
),"Primary Sound Driver",desc
.szDrvName
,lpContext
);
338 if (lpDSEnumCallback((LPGUID
)&DSDEVID_DefaultPlayback
, "Primary Sound Driver", desc
.szDrvName
, lpContext
) == FALSE
)
347 for (wod
= 0; wod
< devs
; ++wod
) {
348 err
= mmErr(waveOutMessage((HWAVEOUT
)wod
,DRV_QUERYDSOUNDDESC
,(DWORD
)&desc
,0));
350 err
= mmErr(waveOutMessage((HWAVEOUT
)wod
,DRV_QUERYDSOUNDGUID
,(DWORD
)&guid
,0));
352 TRACE("calling lpDSEnumCallback(%s,\"%s\",\"%s\",%p)\n",
353 debugstr_guid(&guid
),desc
.szDesc
,desc
.szDrvName
,lpContext
);
354 if (lpDSEnumCallback(&guid
, desc
.szDesc
, desc
.szDrvName
, lpContext
) == FALSE
)
362 /***************************************************************************
363 * DirectSoundEnumerateW [DSOUND.3]
365 * Enumerate all DirectSound drivers installed in the system
368 * lpDSEnumCallback [I] Address of callback function.
369 * lpContext [I] Address of user defined context passed to callback function.
373 * Failure: DSERR_INVALIDPARAM
375 HRESULT WINAPI
DirectSoundEnumerateW(
376 LPDSENUMCALLBACKW lpDSEnumCallback
,
383 WCHAR wDesc
[MAXPNAMELEN
];
384 WCHAR wName
[MAXPNAMELEN
];
386 TRACE("lpDSEnumCallback = %p, lpContext = %p\n",
387 lpDSEnumCallback
, lpContext
);
389 if (lpDSEnumCallback
== NULL
) {
390 WARN("invalid parameter: lpDSEnumCallback == NULL\n");
391 return DSERR_INVALIDPARAM
;
394 devs
= waveOutGetNumDevs();
396 if (GetDeviceID(&DSDEVID_DefaultPlayback
, &guid
) == DS_OK
) {
398 for (wod
= 0; wod
< devs
; ++wod
) {
399 err
= mmErr(waveOutMessage((HWAVEOUT
)wod
,DRV_QUERYDSOUNDGUID
,(DWORD
)&temp
,0));
401 if (IsEqualGUID( &guid
, &temp
) ) {
402 err
= mmErr(waveOutMessage((HWAVEOUT
)wod
,DRV_QUERYDSOUNDDESC
,(DWORD
)&desc
,0));
404 TRACE("calling lpDSEnumCallback(%s,\"%s\",\"%s\",%p)\n",
405 debugstr_guid(&DSDEVID_DefaultPlayback
),"Primary Sound Driver",desc
.szDrvName
,lpContext
);
406 MultiByteToWideChar( CP_ACP
, 0, "Primary Sound Driver", -1,
407 wDesc
, sizeof(wDesc
)/sizeof(WCHAR
) );
408 MultiByteToWideChar( CP_ACP
, 0, desc
.szDrvName
, -1,
409 wName
, sizeof(wName
)/sizeof(WCHAR
) );
410 if (lpDSEnumCallback((LPGUID
)&DSDEVID_DefaultPlayback
, wDesc
, wName
, lpContext
) == FALSE
)
419 for (wod
= 0; wod
< devs
; ++wod
) {
420 err
= mmErr(waveOutMessage((HWAVEOUT
)wod
,DRV_QUERYDSOUNDDESC
,(DWORD
)&desc
,0));
422 err
= mmErr(waveOutMessage((HWAVEOUT
)wod
,DRV_QUERYDSOUNDGUID
,(DWORD
)&guid
,0));
424 TRACE("calling lpDSEnumCallback(%s,\"%s\",\"%s\",%p)\n",
425 debugstr_guid(&guid
),desc
.szDesc
,desc
.szDrvName
,lpContext
);
426 MultiByteToWideChar( CP_ACP
, 0, desc
.szDesc
, -1,
427 wDesc
, sizeof(wDesc
)/sizeof(WCHAR
) );
428 MultiByteToWideChar( CP_ACP
, 0, desc
.szDrvName
, -1,
429 wName
, sizeof(wName
)/sizeof(WCHAR
) );
430 if (lpDSEnumCallback(&guid
, wDesc
, wName
, lpContext
) == FALSE
)
439 static void _dump_DSBCAPS(DWORD xmask
) {
444 #define FE(x) { x, #x },
445 FE(DSBCAPS_PRIMARYBUFFER
)
447 FE(DSBCAPS_LOCHARDWARE
)
448 FE(DSBCAPS_LOCSOFTWARE
)
450 FE(DSBCAPS_CTRLFREQUENCY
)
452 FE(DSBCAPS_CTRLVOLUME
)
453 FE(DSBCAPS_CTRLPOSITIONNOTIFY
)
454 FE(DSBCAPS_CTRLDEFAULT
)
456 FE(DSBCAPS_STICKYFOCUS
)
457 FE(DSBCAPS_GLOBALFOCUS
)
458 FE(DSBCAPS_GETCURRENTPOSITION2
)
459 FE(DSBCAPS_MUTE3DATMAXDISTANCE
)
464 for (i
=0;i
<sizeof(flags
)/sizeof(flags
[0]);i
++)
465 if ((flags
[i
].mask
& xmask
) == flags
[i
].mask
)
466 DPRINTF("%s ",flags
[i
].name
);
469 /*******************************************************************************
473 static HRESULT WINAPI
IDirectSoundImpl_SetCooperativeLevel(
474 LPDIRECTSOUND8 iface
,HWND hwnd
,DWORD level
476 ICOM_THIS(IDirectSoundImpl
,iface
);
477 TRACE("(%p,%08lx,%ld)\n",This
,(DWORD
)hwnd
,level
);
479 if (level
==DSSCL_PRIORITY
|| level
==DSSCL_EXCLUSIVE
) {
480 FIXME("level=%s not fully supported\n",
481 level
==DSSCL_PRIORITY
? "DSSCL_PRIORITY" : "DSSCL_EXCLUSIVE");
484 This
->priolevel
= level
;
489 static HRESULT WINAPI
IDirectSoundImpl_CreateSoundBuffer(
490 LPDIRECTSOUND8 iface
,LPDSBUFFERDESC dsbd
,LPLPDIRECTSOUNDBUFFER8 ppdsb
,LPUNKNOWN lpunk
492 ICOM_THIS(IDirectSoundImpl
,iface
);
494 HRESULT hres
= DS_OK
;
496 TRACE("(%p,%p,%p,%p)\n",This
,dsbd
,ppdsb
,lpunk
);
499 WARN("invalid parameter: This == NULL\n");
500 return DSERR_INVALIDPARAM
;
504 WARN("invalid parameter: dsbd == NULL\n");
505 return DSERR_INVALIDPARAM
;
509 WARN("invalid parameter: ppdsb == NULL\n");
510 return DSERR_INVALIDPARAM
;
513 if (TRACE_ON(dsound
)) {
514 TRACE("(structsize=%ld)\n",dsbd
->dwSize
);
515 TRACE("(flags=0x%08lx:\n",dsbd
->dwFlags
);
516 _dump_DSBCAPS(dsbd
->dwFlags
);
518 TRACE("(bufferbytes=%ld)\n",dsbd
->dwBufferBytes
);
519 TRACE("(lpwfxFormat=%p)\n",dsbd
->lpwfxFormat
);
522 wfex
= dsbd
->lpwfxFormat
;
525 TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld,"
526 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
527 wfex
->wFormatTag
, wfex
->nChannels
, wfex
->nSamplesPerSec
,
528 wfex
->nAvgBytesPerSec
, wfex
->nBlockAlign
,
529 wfex
->wBitsPerSample
, wfex
->cbSize
);
531 if (dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
533 WARN("Primary Buffer already created\n");
534 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8
)(This
->primary
));
535 *ppdsb
= (LPDIRECTSOUNDBUFFER8
)(This
->primary
);
538 hres
= PrimaryBufferImpl_Create(This
, (PrimaryBufferImpl
**)&(This
->primary
), &(This
->dsbd
));
540 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8
)(This
->primary
));
541 *ppdsb
= (LPDIRECTSOUNDBUFFER8
)(This
->primary
);
543 WARN("PrimaryBufferImpl_Create failed\n");
546 IDirectSoundBufferImpl
* dsb
;
547 hres
= IDirectSoundBufferImpl_Create(This
, (IDirectSoundBufferImpl
**)&dsb
, dsbd
);
549 hres
= SecondaryBufferImpl_Create(dsb
, (SecondaryBufferImpl
**)ppdsb
);
551 dsb
->dsb
= (SecondaryBufferImpl
*)*ppdsb
;
552 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8
)*ppdsb
);
554 WARN("SecondaryBufferImpl_Create failed\n");
556 WARN("IDirectSoundBufferImpl_Create failed\n");
562 static HRESULT WINAPI
IDirectSoundImpl_DuplicateSoundBuffer(
563 LPDIRECTSOUND8 iface
,LPDIRECTSOUNDBUFFER8 psb
,LPLPDIRECTSOUNDBUFFER8 ppdsb
565 ICOM_THIS(IDirectSoundImpl
,iface
);
566 IDirectSoundBufferImpl
* pdsb
;
567 IDirectSoundBufferImpl
* dsb
;
568 HRESULT hres
= DS_OK
;
569 TRACE("(%p,%p,%p)\n",This
,psb
,ppdsb
);
572 WARN("invalid parameter: This == NULL\n");
573 return DSERR_INVALIDPARAM
;
577 WARN("invalid parameter: psb == NULL\n");
578 return DSERR_INVALIDPARAM
;
582 WARN("invalid parameter: ppdsb == NULL\n");
583 return DSERR_INVALIDPARAM
;
586 /* FIXME: hack to make sure we have a secondary buffer */
587 if ((DWORD
)((SecondaryBufferImpl
*)psb
)->dsb
== (DWORD
)This
) {
588 ERR("trying to duplicate primary buffer\n");
590 return DSERR_INVALIDCALL
;
593 pdsb
= ((SecondaryBufferImpl
*)psb
)->dsb
;
596 FIXME("need to duplicate hardware buffer\n");
598 return DSERR_INVALIDCALL
;
601 dsb
= (IDirectSoundBufferImpl
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(*dsb
));
604 WARN("out of memory\n");
606 return DSERR_OUTOFMEMORY
;
609 memcpy(dsb
, pdsb
, sizeof(IDirectSoundBufferImpl
));
611 dsb
->state
= STATE_STOPPED
;
618 dsb
->iks
= NULL
; /* FIXME? */
620 memcpy(&(dsb
->wfx
), &(pdsb
->wfx
), sizeof(dsb
->wfx
));
621 InitializeCriticalSection(&(dsb
->lock
));
622 /* register buffer */
623 RtlAcquireResourceExclusive(&(This
->lock
), TRUE
);
625 IDirectSoundBufferImpl
**newbuffers
= (IDirectSoundBufferImpl
**)HeapReAlloc(GetProcessHeap(),0,This
->buffers
,sizeof(IDirectSoundBufferImpl
**)*(This
->nrofbuffers
+1));
627 This
->buffers
= newbuffers
;
628 This
->buffers
[This
->nrofbuffers
] = dsb
;
630 TRACE("buffer count is now %d\n", This
->nrofbuffers
);
632 ERR("out of memory for buffer list! Current buffer count is %d\n", This
->nrofbuffers
);
633 IDirectSoundBuffer8_Release(psb
);
634 DeleteCriticalSection(&(dsb
->lock
));
635 RtlReleaseResource(&(This
->lock
));
636 HeapFree(GetProcessHeap(),0,dsb
);
638 return DSERR_OUTOFMEMORY
;
641 RtlReleaseResource(&(This
->lock
));
642 IDirectSound_AddRef(iface
);
643 hres
= SecondaryBufferImpl_Create(dsb
, (SecondaryBufferImpl
**)ppdsb
);
645 dsb
->dsb
= (SecondaryBufferImpl
*)*ppdsb
;
646 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8
)*ppdsb
);
648 WARN("SecondaryBufferImpl_Create failed\n");
653 static HRESULT WINAPI
IDirectSoundImpl_GetCaps(LPDIRECTSOUND8 iface
,LPDSCAPS lpDSCaps
) {
654 ICOM_THIS(IDirectSoundImpl
,iface
);
655 TRACE("(%p,%p)\n",This
,lpDSCaps
);
658 WARN("invalid parameter: This == NULL\n");
659 return DSERR_INVALIDPARAM
;
662 if (lpDSCaps
== NULL
) {
663 WARN("invalid parameter: lpDSCaps = NULL\n");
664 return DSERR_INVALIDPARAM
;
667 /* check is there is enough room */
668 if (lpDSCaps
->dwSize
< sizeof(*lpDSCaps
)) {
669 WARN("invalid parameter: lpDSCaps->dwSize = %ld < %d\n",
670 lpDSCaps
->dwSize
, sizeof(*lpDSCaps
));
671 return DSERR_INVALIDPARAM
;
674 lpDSCaps
->dwFlags
= This
->drvcaps
.dwFlags
;
675 TRACE("(flags=0x%08lx)\n",lpDSCaps
->dwFlags
);
677 /* FIXME: copy caps from This->drv */
678 lpDSCaps
->dwMinSecondarySampleRate
= DSBFREQUENCY_MIN
;
679 lpDSCaps
->dwMaxSecondarySampleRate
= DSBFREQUENCY_MAX
;
681 lpDSCaps
->dwPrimaryBuffers
= 1;
683 lpDSCaps
->dwMaxHwMixingAllBuffers
= 0;
684 lpDSCaps
->dwMaxHwMixingStaticBuffers
= 0;
685 lpDSCaps
->dwMaxHwMixingStreamingBuffers
= 0;
687 lpDSCaps
->dwFreeHwMixingAllBuffers
= 0;
688 lpDSCaps
->dwFreeHwMixingStaticBuffers
= 0;
689 lpDSCaps
->dwFreeHwMixingStreamingBuffers
= 0;
691 lpDSCaps
->dwMaxHw3DAllBuffers
= 0;
692 lpDSCaps
->dwMaxHw3DStaticBuffers
= 0;
693 lpDSCaps
->dwMaxHw3DStreamingBuffers
= 0;
695 lpDSCaps
->dwFreeHw3DAllBuffers
= 0;
696 lpDSCaps
->dwFreeHw3DStaticBuffers
= 0;
697 lpDSCaps
->dwFreeHw3DStreamingBuffers
= 0;
699 lpDSCaps
->dwTotalHwMemBytes
= 0;
701 lpDSCaps
->dwFreeHwMemBytes
= 0;
703 lpDSCaps
->dwMaxContigFreeHwMemBytes
= 0;
705 lpDSCaps
->dwUnlockTransferRateHwBuffers
= 4096; /* But we have none... */
707 lpDSCaps
->dwPlayCpuOverheadSwBuffers
= 1; /* 1% */
712 static ULONG WINAPI
IDirectSoundImpl_AddRef(LPDIRECTSOUND8 iface
) {
713 ICOM_THIS(IDirectSoundImpl
,iface
);
714 TRACE("(%p) ref was %ld, thread is %04lx\n", This
, This
->ref
, GetCurrentThreadId());
715 return InterlockedIncrement(&This
->ref
);
718 static ULONG WINAPI
IDirectSoundImpl_Release(LPDIRECTSOUND8 iface
) {
719 ICOM_THIS(IDirectSoundImpl
,iface
);
722 TRACE("(%p) ref was %ld, thread is %04lx\n", This
, This
->ref
, GetCurrentThreadId());
723 ulReturn
= InterlockedDecrement(&This
->ref
);
728 timeKillEvent(This
->timerID
);
729 timeEndPeriod(DS_TIME_RES
);
730 /* wait for timer to expire */
731 Sleep(DS_TIME_RES
+1);
733 RtlAcquireResourceShared(&(This
->lock
), TRUE
);
736 for( i
=0;i
<This
->nrofbuffers
;i
++)
737 IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8
)This
->buffers
[i
]);
740 RtlReleaseResource(&(This
->lock
));
743 WARN("primary buffer not released\n");
744 IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8
)This
->primary
);
747 hres
= DSOUND_PrimaryDestroy(This
);
749 WARN("DSOUND_PrimaryDestroy failed\n");
752 IDsDriver_Close(This
->driver
);
754 if (This
->drvdesc
.dwFlags
& DSDDESC_DOMMSYSTEMOPEN
)
755 waveOutClose(This
->hwo
);
758 IDsDriver_Release(This
->driver
);
760 RtlDeleteResource(&This
->lock
);
761 DeleteCriticalSection(&This
->mixlock
);
762 DeleteCriticalSection(&This
->ds3dl_lock
);
763 HeapFree(GetProcessHeap(),0,This
);
765 TRACE("(%p) released\n",This
);
771 static HRESULT WINAPI
IDirectSoundImpl_SetSpeakerConfig(
772 LPDIRECTSOUND8 iface
,DWORD config
774 ICOM_THIS(IDirectSoundImpl
,iface
);
775 TRACE("(%p,0x%08lx)\n",This
,config
);
777 This
->speaker_config
= config
;
779 WARN("not fully functional\n");
783 static HRESULT WINAPI
IDirectSoundImpl_QueryInterface(
784 LPDIRECTSOUND8 iface
,REFIID riid
,LPVOID
*ppobj
786 ICOM_THIS(IDirectSoundImpl
,iface
);
787 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
790 WARN("invalid parameter\n");
794 *ppobj
= NULL
; /* assume failure */
796 if ( IsEqualGUID(riid
, &IID_IUnknown
) ||
797 IsEqualGUID(riid
, &IID_IDirectSound
) ||
798 IsEqualGUID(riid
, &IID_IDirectSound8
) ) {
799 IDirectSound8_AddRef((LPDIRECTSOUND8
)This
);
804 if ( IsEqualGUID( &IID_IDirectSound3DListener
, riid
) ) {
805 WARN("app requested IDirectSound3DListener on dsound object\n");
806 return E_NOINTERFACE
;
809 FIXME( "Unknown IID %s\n", debugstr_guid( riid
) );
810 return E_NOINTERFACE
;
813 static HRESULT WINAPI
IDirectSoundImpl_Compact(
814 LPDIRECTSOUND8 iface
)
816 ICOM_THIS(IDirectSoundImpl
,iface
);
817 TRACE("(%p)\n", This
);
821 static HRESULT WINAPI
IDirectSoundImpl_GetSpeakerConfig(
822 LPDIRECTSOUND8 iface
,
823 LPDWORD lpdwSpeakerConfig
)
825 ICOM_THIS(IDirectSoundImpl
,iface
);
826 TRACE("(%p, %p)\n", This
, lpdwSpeakerConfig
);
828 if (lpdwSpeakerConfig
== NULL
) {
829 WARN("invalid parameter\n");
830 return DSERR_INVALIDPARAM
;
833 WARN("not fully functional\n");
835 *lpdwSpeakerConfig
= This
->speaker_config
;
840 static HRESULT WINAPI
IDirectSoundImpl_Initialize(
841 LPDIRECTSOUND8 iface
,
844 ICOM_THIS(IDirectSoundImpl
,iface
);
845 TRACE("(%p, %s)\n", This
, debugstr_guid(lpcGuid
));
849 static HRESULT WINAPI
IDirectSoundImpl_VerifyCertification(
850 LPDIRECTSOUND8 iface
,
851 LPDWORD pdwCertified
)
853 ICOM_THIS(IDirectSoundImpl
,iface
);
854 TRACE("(%p, %p)\n", This
, pdwCertified
);
855 *pdwCertified
= DS_CERTIFIED
;
859 static ICOM_VTABLE(IDirectSound8
) dsvt
=
861 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
862 IDirectSoundImpl_QueryInterface
,
863 IDirectSoundImpl_AddRef
,
864 IDirectSoundImpl_Release
,
865 IDirectSoundImpl_CreateSoundBuffer
,
866 IDirectSoundImpl_GetCaps
,
867 IDirectSoundImpl_DuplicateSoundBuffer
,
868 IDirectSoundImpl_SetCooperativeLevel
,
869 IDirectSoundImpl_Compact
,
870 IDirectSoundImpl_GetSpeakerConfig
,
871 IDirectSoundImpl_SetSpeakerConfig
,
872 IDirectSoundImpl_Initialize
,
873 IDirectSoundImpl_VerifyCertification
877 /*******************************************************************************
878 * DirectSoundCreate (DSOUND.1)
880 * Creates and initializes a DirectSound interface.
883 * lpcGUID [I] Address of the GUID that identifies the sound device.
884 * ppDS [O] Address of a variable to receive the interface pointer.
885 * pUnkOuter [I] Must be NULL.
889 * Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
890 * DSERR_NODRIVER, DSERR_OUTOFMEMORY
892 HRESULT WINAPI
DirectSoundCreate8(LPCGUID lpcGUID
,LPDIRECTSOUND8
*ppDS
,IUnknown
*pUnkOuter
)
894 IDirectSoundImpl
** ippDS
=(IDirectSoundImpl
**)ppDS
;
895 PIDSDRIVER drv
= NULL
;
897 HRESULT err
= DSERR_INVALIDPARAM
;
899 BOOLEAN found
= FALSE
;
901 TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID
),ippDS
,pUnkOuter
);
904 WARN("invalid parameter: ippDS == NULL\n");
905 return DSERR_INVALIDPARAM
;
908 /* Get dsound configuration */
909 setup_dsound_options();
911 /* Default device? */
912 if (!lpcGUID
|| IsEqualGUID(lpcGUID
, &GUID_NULL
))
913 lpcGUID
= &DSDEVID_DefaultPlayback
;
915 if (GetDeviceID(lpcGUID
, &devGuid
) != DS_OK
) {
916 WARN("invalid parameter: lpcGUID\n");
918 return DSERR_INVALIDPARAM
;
922 if (IsEqualGUID(&devGuid
, &dsound
->guid
) ) {
923 /* FIXME: this is wrong, need to create a new instance */
924 ERR("dsound already opened\n");
925 IDirectSound_AddRef((LPDIRECTSOUND
)dsound
);
929 ERR("different dsound already opened\n");
933 /* Enumerate WINMM audio devices and find the one we want */
934 wodn
= waveOutGetNumDevs();
938 return DSERR_NODRIVER
;
941 TRACE(" expecting GUID %s.\n", debugstr_guid(&devGuid
));
943 for (wod
=0; wod
<wodn
; wod
++) {
945 err
= mmErr(waveOutMessage((HWAVEOUT
)wod
,DRV_QUERYDSOUNDGUID
,(DWORD
)(&guid
),0));
947 WARN("waveOutMessage failed; err=%lx\n",err
);
951 TRACE("got GUID %s for wod %d.\n", debugstr_guid(&guid
), wod
);
952 if (IsEqualGUID( &devGuid
, &guid
) ) {
960 WARN("invalid parameter\n");
962 return DSERR_INVALIDPARAM
;
965 if (found
== FALSE
) {
966 WARN("No device found matching given ID - trying with default one !\n");
967 wod
= ds_default_playback
;
970 /* DRV_QUERYDSOUNDIFACE is a "Wine extension" to get the DSound interface */
971 waveOutMessage((HWAVEOUT
)wod
, DRV_QUERYDSOUNDIFACE
, (DWORD
)&drv
, 0);
973 /* Disable the direct sound driver to force emulation if requested. */
974 if (ds_hw_accel
== DS_HW_ACCEL_EMULATION
)
977 /* Allocate memory */
978 *ippDS
= (IDirectSoundImpl
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDirectSoundImpl
));
979 if (*ippDS
== NULL
) {
980 WARN("out of memory\n");
981 return DSERR_OUTOFMEMORY
;
984 (*ippDS
)->lpVtbl
= &dsvt
;
987 (*ippDS
)->driver
= drv
;
988 (*ippDS
)->priolevel
= DSSCL_NORMAL
;
989 (*ippDS
)->fraglen
= 0;
990 (*ippDS
)->hwbuf
= NULL
;
991 (*ippDS
)->buffer
= NULL
;
992 (*ippDS
)->buflen
= 0;
993 (*ippDS
)->writelead
= 0;
994 (*ippDS
)->state
= STATE_STOPPED
;
995 (*ippDS
)->nrofbuffers
= 0;
996 (*ippDS
)->buffers
= NULL
;
997 (*ippDS
)->primary
= NULL
;
998 (*ippDS
)->speaker_config
= DSSPEAKER_STEREO
| (DSSPEAKER_GEOMETRY_NARROW
<< 16);
1000 /* 3D listener initial parameters */
1001 (*ippDS
)->listener
= NULL
;
1002 (*ippDS
)->ds3dl
.dwSize
= sizeof(DS3DLISTENER
);
1003 (*ippDS
)->ds3dl
.vPosition
.u1
.x
= 0.0;
1004 (*ippDS
)->ds3dl
.vPosition
.u2
.y
= 0.0;
1005 (*ippDS
)->ds3dl
.vPosition
.u3
.z
= 0.0;
1006 (*ippDS
)->ds3dl
.vVelocity
.u1
.x
= 0.0;
1007 (*ippDS
)->ds3dl
.vVelocity
.u2
.y
= 0.0;
1008 (*ippDS
)->ds3dl
.vVelocity
.u3
.z
= 0.0;
1009 (*ippDS
)->ds3dl
.vOrientFront
.u1
.x
= 0.0;
1010 (*ippDS
)->ds3dl
.vOrientFront
.u2
.y
= 0.0;
1011 (*ippDS
)->ds3dl
.vOrientFront
.u3
.z
= 1.0;
1012 (*ippDS
)->ds3dl
.vOrientTop
.u1
.x
= 0.0;
1013 (*ippDS
)->ds3dl
.vOrientTop
.u2
.y
= 1.0;
1014 (*ippDS
)->ds3dl
.vOrientTop
.u3
.z
= 0.0;
1015 (*ippDS
)->ds3dl
.flDistanceFactor
= DS3D_DEFAULTDISTANCEFACTOR
;
1016 (*ippDS
)->ds3dl
.flRolloffFactor
= DS3D_DEFAULTROLLOFFFACTOR
;
1017 (*ippDS
)->ds3dl
.flDopplerFactor
= DS3D_DEFAULTDOPPLERFACTOR
;
1019 InitializeCriticalSection(&(*ippDS
)->ds3dl_lock
);
1021 (*ippDS
)->prebuf
= ds_snd_queue_max
;
1022 (*ippDS
)->guid
= devGuid
;
1024 /* Get driver description */
1026 err
= IDsDriver_GetDriverDesc(drv
,&((*ippDS
)->drvdesc
));
1028 WARN("IDsDriver_GetDriverDesc failed\n");
1029 HeapFree(GetProcessHeap(),0,*ippDS
);
1034 /* if no DirectSound interface available, use WINMM API instead */
1035 (*ippDS
)->drvdesc
.dwFlags
= DSDDESC_DOMMSYSTEMOPEN
| DSDDESC_DOMMSYSTEMSETFORMAT
;
1038 (*ippDS
)->drvdesc
.dnDevNode
= wod
;
1040 /* Set default wave format (may need it for waveOutOpen) */
1041 (*ippDS
)->wfx
.wFormatTag
= WAVE_FORMAT_PCM
;
1042 /* We rely on the sound driver to return the actual sound format of
1043 * the device if it does not support 22050x8x2 and is given the
1044 * WAVE_DIRECTSOUND flag.
1046 (*ippDS
)->wfx
.nSamplesPerSec
= 22050;
1047 (*ippDS
)->wfx
.wBitsPerSample
= 8;
1048 (*ippDS
)->wfx
.nChannels
= 2;
1049 (*ippDS
)->wfx
.nBlockAlign
= (*ippDS
)->wfx
.wBitsPerSample
* (*ippDS
)->wfx
.nChannels
/ 8;
1050 (*ippDS
)->wfx
.nAvgBytesPerSec
= (*ippDS
)->wfx
.nSamplesPerSec
* (*ippDS
)->wfx
.nBlockAlign
;
1051 (*ippDS
)->wfx
.cbSize
= 0;
1053 /* If the driver requests being opened through MMSYSTEM
1054 * (which is recommended by the DDK), it is supposed to happen
1055 * before the DirectSound interface is opened */
1056 if ((*ippDS
)->drvdesc
.dwFlags
& DSDDESC_DOMMSYSTEMOPEN
)
1058 DWORD flags
= CALLBACK_FUNCTION
;
1060 /* disable direct sound if requested */
1061 if (ds_hw_accel
!= DS_HW_ACCEL_EMULATION
)
1062 flags
|= WAVE_DIRECTSOUND
;
1064 err
= mmErr(waveOutOpen(&((*ippDS
)->hwo
),
1065 (*ippDS
)->drvdesc
.dnDevNode
, &((*ippDS
)->wfx
),
1066 (DWORD
)DSOUND_callback
, (DWORD
)(*ippDS
),
1069 WARN("waveOutOpen failed\n");
1070 HeapFree(GetProcessHeap(),0,*ippDS
);
1077 err
= IDsDriver_Open(drv
);
1079 WARN("IDsDriver_Open failed\n");
1080 HeapFree(GetProcessHeap(),0,*ippDS
);
1085 /* the driver is now open, so it's now allowed to call GetCaps */
1086 err
= IDsDriver_GetCaps(drv
,&((*ippDS
)->drvcaps
));
1088 WARN("IDsDriver_GetCaps failed\n");
1089 HeapFree(GetProcessHeap(),0,*ippDS
);
1095 err
= mmErr(waveOutGetDevCapsA((*ippDS
)->drvdesc
.dnDevNode
, &woc
, sizeof(woc
)));
1097 WARN("waveOutGetDevCaps failed\n");
1098 HeapFree(GetProcessHeap(),0,*ippDS
);
1102 (*ippDS
)->drvcaps
.dwFlags
= 0;
1103 if ((woc
.dwFormats
& WAVE_FORMAT_1M08
) ||
1104 (woc
.dwFormats
& WAVE_FORMAT_2M08
) ||
1105 (woc
.dwFormats
& WAVE_FORMAT_4M08
) ||
1106 (woc
.dwFormats
& WAVE_FORMAT_48M08
) ||
1107 (woc
.dwFormats
& WAVE_FORMAT_96M08
)) {
1108 (*ippDS
)->drvcaps
.dwFlags
|= DSCAPS_PRIMARY8BIT
;
1109 (*ippDS
)->drvcaps
.dwFlags
|= DSCAPS_PRIMARYMONO
;
1111 if ((woc
.dwFormats
& WAVE_FORMAT_1M16
) ||
1112 (woc
.dwFormats
& WAVE_FORMAT_2M16
) ||
1113 (woc
.dwFormats
& WAVE_FORMAT_4M16
) ||
1114 (woc
.dwFormats
& WAVE_FORMAT_48M16
) ||
1115 (woc
.dwFormats
& WAVE_FORMAT_96M16
)) {
1116 (*ippDS
)->drvcaps
.dwFlags
|= DSCAPS_PRIMARY16BIT
;
1117 (*ippDS
)->drvcaps
.dwFlags
|= DSCAPS_PRIMARYMONO
;
1119 if ((woc
.dwFormats
& WAVE_FORMAT_1S08
) ||
1120 (woc
.dwFormats
& WAVE_FORMAT_2S08
) ||
1121 (woc
.dwFormats
& WAVE_FORMAT_4S08
) ||
1122 (woc
.dwFormats
& WAVE_FORMAT_48S08
) ||
1123 (woc
.dwFormats
& WAVE_FORMAT_96S08
)) {
1124 (*ippDS
)->drvcaps
.dwFlags
|= DSCAPS_PRIMARY8BIT
;
1125 (*ippDS
)->drvcaps
.dwFlags
|= DSCAPS_PRIMARYSTEREO
;
1127 if ((woc
.dwFormats
& WAVE_FORMAT_1S16
) ||
1128 (woc
.dwFormats
& WAVE_FORMAT_2S16
) ||
1129 (woc
.dwFormats
& WAVE_FORMAT_4S16
) ||
1130 (woc
.dwFormats
& WAVE_FORMAT_48S16
) ||
1131 (woc
.dwFormats
& WAVE_FORMAT_96S16
)) {
1132 (*ippDS
)->drvcaps
.dwFlags
|= DSCAPS_PRIMARY16BIT
;
1133 (*ippDS
)->drvcaps
.dwFlags
|= DSCAPS_PRIMARYSTEREO
;
1136 (*ippDS
)->drvcaps
.dwFlags
|= DSCAPS_EMULDRIVER
;
1139 DSOUND_RecalcVolPan(&((*ippDS
)->volpan
));
1141 InitializeCriticalSection(&((*ippDS
)->mixlock
));
1142 RtlInitializeResource(&((*ippDS
)->lock
));
1147 hres
= DSOUND_PrimaryCreate(dsound
);
1148 if (hres
!= DS_OK
) {
1149 WARN("DSOUND_PrimaryCreate failed\n");
1152 timeBeginPeriod(DS_TIME_RES
);
1153 dsound
->timerID
= timeSetEvent(DS_TIME_DEL
, DS_TIME_RES
, DSOUND_timer
,
1154 (DWORD
)dsound
, TIME_PERIODIC
| TIME_CALLBACK_FUNCTION
);
1161 /*******************************************************************************
1162 * DirectSound ClassFactory
1165 static HRESULT WINAPI
1166 DSCF_QueryInterface(LPCLASSFACTORY iface
,REFIID riid
,LPVOID
*ppobj
) {
1167 ICOM_THIS(IClassFactoryImpl
,iface
);
1169 FIXME("(%p)->(%s,%p),stub!\n",This
,debugstr_guid(riid
),ppobj
);
1170 return E_NOINTERFACE
;
1174 DSCF_AddRef(LPCLASSFACTORY iface
) {
1175 ICOM_THIS(IClassFactoryImpl
,iface
);
1176 TRACE("(%p) ref was %ld\n", This
, This
->ref
);
1177 return ++(This
->ref
);
1180 static ULONG WINAPI
DSCF_Release(LPCLASSFACTORY iface
) {
1181 ICOM_THIS(IClassFactoryImpl
,iface
);
1182 /* static class, won't be freed */
1183 TRACE("(%p) ref was %ld\n", This
, This
->ref
);
1184 return --(This
->ref
);
1187 static HRESULT WINAPI
DSCF_CreateInstance(
1188 LPCLASSFACTORY iface
,LPUNKNOWN pOuter
,REFIID riid
,LPVOID
*ppobj
1190 ICOM_THIS(IClassFactoryImpl
,iface
);
1191 TRACE("(%p)->(%p,%s,%p)\n",This
,pOuter
,debugstr_guid(riid
),ppobj
);
1193 if (ppobj
== NULL
) {
1194 WARN("invalid parameter\n");
1195 return DSERR_INVALIDPARAM
;
1200 if ( IsEqualGUID( &IID_IDirectSound
, riid
) ||
1201 IsEqualGUID( &IID_IDirectSound8
, riid
) ) {
1202 /* FIXME: reuse already created dsound if present? */
1203 return DirectSoundCreate8(0,(LPDIRECTSOUND8
*)ppobj
,pOuter
);
1206 WARN("(%p,%p,%s,%p) Interface not found!\n",This
,pOuter
,debugstr_guid(riid
),ppobj
);
1207 return E_NOINTERFACE
;
1210 static HRESULT WINAPI
DSCF_LockServer(LPCLASSFACTORY iface
,BOOL dolock
) {
1211 ICOM_THIS(IClassFactoryImpl
,iface
);
1212 FIXME("(%p)->(%d),stub!\n",This
,dolock
);
1216 static ICOM_VTABLE(IClassFactory
) DSCF_Vtbl
= {
1217 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1218 DSCF_QueryInterface
,
1221 DSCF_CreateInstance
,
1225 static IClassFactoryImpl DSOUND_CF
= { &DSCF_Vtbl
, 1 };
1227 /*******************************************************************************
1228 * DirectSoundPrivate ClassFactory
1231 static HRESULT WINAPI
1232 DSPCF_QueryInterface(LPCLASSFACTORY iface
,REFIID riid
,LPVOID
*ppobj
) {
1233 ICOM_THIS(IClassFactoryImpl
,iface
);
1235 FIXME("(%p)->(%s,%p),stub!\n",This
,debugstr_guid(riid
),ppobj
);
1236 return E_NOINTERFACE
;
1240 DSPCF_AddRef(LPCLASSFACTORY iface
) {
1241 ICOM_THIS(IClassFactoryImpl
,iface
);
1242 TRACE("(%p) ref was %ld\n", This
, This
->ref
);
1243 return ++(This
->ref
);
1247 DSPCF_Release(LPCLASSFACTORY iface
) {
1248 ICOM_THIS(IClassFactoryImpl
,iface
);
1249 /* static class, won't be freed */
1250 TRACE("(%p) ref was %ld\n", This
, This
->ref
);
1251 return --(This
->ref
);
1254 static HRESULT WINAPI
1255 DSPCF_CreateInstance(
1256 LPCLASSFACTORY iface
,LPUNKNOWN pOuter
,REFIID riid
,LPVOID
*ppobj
1258 ICOM_THIS(IClassFactoryImpl
,iface
);
1259 TRACE("(%p)->(%p,%s,%p)\n",This
,pOuter
,debugstr_guid(riid
),ppobj
);
1261 if (ppobj
== NULL
) {
1262 WARN("invalid parameter\n");
1263 return DSERR_INVALIDPARAM
;
1268 if ( IsEqualGUID( &IID_IKsPropertySet
, riid
) ) {
1269 return IKsPrivatePropertySetImpl_Create((IKsPrivatePropertySetImpl
**)ppobj
);
1272 WARN("(%p,%p,%s,%p) Interface not found!\n",This
,pOuter
,debugstr_guid(riid
),ppobj
);
1273 return E_NOINTERFACE
;
1276 static HRESULT WINAPI
1277 DSPCF_LockServer(LPCLASSFACTORY iface
,BOOL dolock
) {
1278 ICOM_THIS(IClassFactoryImpl
,iface
);
1279 FIXME("(%p)->(%d),stub!\n",This
,dolock
);
1283 static ICOM_VTABLE(IClassFactory
) DSPCF_Vtbl
= {
1284 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1285 DSPCF_QueryInterface
,
1288 DSPCF_CreateInstance
,
1292 static IClassFactoryImpl DSOUND_PRIVATE_CF
= { &DSPCF_Vtbl
, 1 };
1294 /*******************************************************************************
1295 * DllGetClassObject [DSOUND.5]
1296 * Retrieves class object from a DLL object
1299 * Docs say returns STDAPI
1302 * rclsid [I] CLSID for the class object
1303 * riid [I] Reference to identifier of interface for class object
1304 * ppv [O] Address of variable to receive interface pointer for riid
1308 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
1311 DWORD WINAPI
DSOUND_DllGetClassObject(REFCLSID rclsid
,REFIID riid
,LPVOID
*ppv
)
1313 TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid
), debugstr_guid(riid
), ppv
);
1316 WARN("invalid parameter\n");
1317 return E_INVALIDARG
;
1322 if ( IsEqualCLSID( &CLSID_DirectSound
, rclsid
) ||
1323 IsEqualCLSID( &CLSID_DirectSound8
, rclsid
) ) {
1324 if ( IsEqualCLSID( &IID_IClassFactory
, riid
) ) {
1325 *ppv
= (LPVOID
)&DSOUND_CF
;
1326 IClassFactory_AddRef((IClassFactory
*)*ppv
);
1329 WARN("(%s,%s,%p): no interface found.\n",
1330 debugstr_guid(rclsid
), debugstr_guid(riid
), ppv
);
1334 if ( IsEqualCLSID( &CLSID_DirectSoundCapture
, rclsid
) ||
1335 IsEqualCLSID( &CLSID_DirectSoundCapture8
, rclsid
) ) {
1336 if ( IsEqualCLSID( &IID_IClassFactory
, riid
) ) {
1337 *ppv
= (LPVOID
)&DSOUND_CAPTURE_CF
;
1338 IClassFactory_AddRef((IClassFactory
*)*ppv
);
1341 WARN("(%s,%s,%p): no interface found.\n",
1342 debugstr_guid(rclsid
), debugstr_guid(riid
), ppv
);
1346 if ( IsEqualCLSID( &CLSID_DirectSoundFullDuplex
, rclsid
) ) {
1347 if ( IsEqualCLSID( &IID_IClassFactory
, riid
) ) {
1348 *ppv
= (LPVOID
)&DSOUND_FULLDUPLEX_CF
;
1349 IClassFactory_AddRef((IClassFactory
*)*ppv
);
1352 WARN("(%s,%s,%p): no interface found.\n",
1353 debugstr_guid(rclsid
), debugstr_guid(riid
), ppv
);
1357 if ( IsEqualCLSID( &CLSID_DirectSoundPrivate
, rclsid
) ) {
1358 if ( IsEqualCLSID( &IID_IClassFactory
, riid
) ) {
1359 *ppv
= (LPVOID
)&DSOUND_PRIVATE_CF
;
1360 IClassFactory_AddRef((IClassFactory
*)*ppv
);
1363 WARN("(%s,%s,%p): no interface found.\n",
1364 debugstr_guid(rclsid
), debugstr_guid(riid
), ppv
);
1368 WARN("(%s,%s,%p): no class found.\n", debugstr_guid(rclsid
), debugstr_guid(riid
), ppv
);
1369 return CLASS_E_CLASSNOTAVAILABLE
;
1373 /*******************************************************************************
1374 * DllCanUnloadNow [DSOUND.4]
1375 * Determines whether the DLL is in use.
1381 DWORD WINAPI
DSOUND_DllCanUnloadNow(void)
1383 FIXME("(void): stub\n");