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
) {
532 *ppdsb
=(LPDIRECTSOUNDBUFFER8
)This
->primary
;
534 WARN("PrimaryBuffer_Create failed\n");
537 IDirectSoundBuffer_AddRef(*ppdsb
);
540 hres
= SecondaryBuffer_Create(This
, (IDirectSoundBufferImpl
**)ppdsb
, dsbd
);
542 WARN("SecondaryBuffer_Create failed\n");
544 IDirectSoundBuffer_AddRef(*ppdsb
);
550 static HRESULT WINAPI
IDirectSoundImpl_DuplicateSoundBuffer(
551 LPDIRECTSOUND8 iface
,LPDIRECTSOUNDBUFFER8 pdsb
,LPLPDIRECTSOUNDBUFFER8 ppdsb
553 ICOM_THIS(IDirectSoundImpl
,iface
);
554 IDirectSoundBufferImpl
* ipdsb
=(IDirectSoundBufferImpl
*)pdsb
;
555 IDirectSoundBufferImpl
* dsb
;
556 TRACE("(%p,%p,%p)\n",This
,pdsb
,ppdsb
);
559 WARN("invalid parameter: This == NULL\n");
560 return DSERR_INVALIDPARAM
;
564 WARN("invalid parameter: pdsb == NULL\n");
565 return DSERR_INVALIDPARAM
;
569 WARN("invalid parameter: ppdsb == NULL\n");
570 return DSERR_INVALIDPARAM
;
573 if (ipdsb
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
574 ERR("trying to duplicate primary buffer\n");
576 return DSERR_INVALIDCALL
;
580 FIXME("need to duplicate hardware buffer\n");
582 return DSERR_INVALIDCALL
;
585 dsb
= (IDirectSoundBufferImpl
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(*dsb
));
588 WARN("out of memory\n");
590 return DSERR_OUTOFMEMORY
;
593 memcpy(dsb
, ipdsb
, sizeof(IDirectSoundBufferImpl
));
595 dsb
->state
= STATE_STOPPED
;
602 dsb
->iks
= NULL
; /* FIXME? */
603 memcpy(&(dsb
->wfx
), &(ipdsb
->wfx
), sizeof(dsb
->wfx
));
604 InitializeCriticalSection(&(dsb
->lock
));
605 /* register buffer */
606 RtlAcquireResourceExclusive(&(This
->lock
), TRUE
);
608 IDirectSoundBufferImpl
**newbuffers
= (IDirectSoundBufferImpl
**)HeapReAlloc(GetProcessHeap(),0,This
->buffers
,sizeof(IDirectSoundBufferImpl
**)*(This
->nrofbuffers
+1));
610 This
->buffers
= newbuffers
;
611 This
->buffers
[This
->nrofbuffers
] = dsb
;
613 TRACE("buffer count is now %d\n", This
->nrofbuffers
);
615 ERR("out of memory for buffer list! Current buffer count is %d\n", This
->nrofbuffers
);
616 IDirectSoundBuffer8_Release(pdsb
);
617 DeleteCriticalSection(&(dsb
->lock
));
618 RtlReleaseResource(&(This
->lock
));
619 HeapFree(GetProcessHeap(),0,dsb
);
621 return DSERR_OUTOFMEMORY
;
624 RtlReleaseResource(&(This
->lock
));
625 IDirectSound_AddRef(iface
);
626 *ppdsb
= (LPDIRECTSOUNDBUFFER8
)dsb
;
631 static HRESULT WINAPI
IDirectSoundImpl_GetCaps(LPDIRECTSOUND8 iface
,LPDSCAPS lpDSCaps
) {
632 ICOM_THIS(IDirectSoundImpl
,iface
);
633 TRACE("(%p,%p)\n",This
,lpDSCaps
);
636 WARN("invalid parameter: This == NULL\n");
637 return DSERR_INVALIDPARAM
;
640 if (lpDSCaps
== NULL
) {
641 WARN("invalid parameter: lpDSCaps = NULL\n");
642 return DSERR_INVALIDPARAM
;
645 /* check is there is enough room */
646 if (lpDSCaps
->dwSize
< sizeof(*lpDSCaps
)) {
647 WARN("invalid parameter: lpDSCaps->dwSize = %ld < %d\n",
648 lpDSCaps
->dwSize
, sizeof(*lpDSCaps
));
649 return DSERR_INVALIDPARAM
;
652 lpDSCaps
->dwFlags
= This
->drvcaps
.dwFlags
;
653 TRACE("(flags=0x%08lx)\n",lpDSCaps
->dwFlags
);
655 /* FIXME: copy caps from This->drv */
656 lpDSCaps
->dwMinSecondarySampleRate
= DSBFREQUENCY_MIN
;
657 lpDSCaps
->dwMaxSecondarySampleRate
= DSBFREQUENCY_MAX
;
659 lpDSCaps
->dwPrimaryBuffers
= 1;
661 lpDSCaps
->dwMaxHwMixingAllBuffers
= 0;
662 lpDSCaps
->dwMaxHwMixingStaticBuffers
= 0;
663 lpDSCaps
->dwMaxHwMixingStreamingBuffers
= 0;
665 lpDSCaps
->dwFreeHwMixingAllBuffers
= 0;
666 lpDSCaps
->dwFreeHwMixingStaticBuffers
= 0;
667 lpDSCaps
->dwFreeHwMixingStreamingBuffers
= 0;
669 lpDSCaps
->dwMaxHw3DAllBuffers
= 0;
670 lpDSCaps
->dwMaxHw3DStaticBuffers
= 0;
671 lpDSCaps
->dwMaxHw3DStreamingBuffers
= 0;
673 lpDSCaps
->dwFreeHw3DAllBuffers
= 0;
674 lpDSCaps
->dwFreeHw3DStaticBuffers
= 0;
675 lpDSCaps
->dwFreeHw3DStreamingBuffers
= 0;
677 lpDSCaps
->dwTotalHwMemBytes
= 0;
679 lpDSCaps
->dwFreeHwMemBytes
= 0;
681 lpDSCaps
->dwMaxContigFreeHwMemBytes
= 0;
683 lpDSCaps
->dwUnlockTransferRateHwBuffers
= 4096; /* But we have none... */
685 lpDSCaps
->dwPlayCpuOverheadSwBuffers
= 1; /* 1% */
690 static ULONG WINAPI
IDirectSoundImpl_AddRef(LPDIRECTSOUND8 iface
) {
691 ICOM_THIS(IDirectSoundImpl
,iface
);
692 TRACE("(%p) ref was %ld, thread is %04lx\n", This
, This
->ref
, GetCurrentThreadId());
693 return InterlockedIncrement(&This
->ref
);
696 static ULONG WINAPI
IDirectSoundImpl_Release(LPDIRECTSOUND8 iface
) {
697 ICOM_THIS(IDirectSoundImpl
,iface
);
700 TRACE("(%p) ref was %ld, thread is %04lx\n", This
, This
->ref
, GetCurrentThreadId());
701 ulReturn
= InterlockedDecrement(&This
->ref
);
707 timeKillEvent(This
->timerID
);
708 timeEndPeriod(DS_TIME_RES
);
709 /* wait for timer to expire */
710 Sleep(DS_TIME_RES
+1);
712 RtlAcquireResourceShared(&(This
->lock
), TRUE
);
715 for( i
=0;i
<This
->nrofbuffers
;i
++)
716 IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8
)This
->buffers
[i
]);
719 RtlReleaseResource(&(This
->lock
));
722 IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8
)This
->primary
);
724 hres
= DSOUND_PrimaryDestroy(This
);
726 WARN("DSOUND_PrimaryDestroy failed\n");
729 IDsDriver_Close(This
->driver
);
731 if (This
->drvdesc
.dwFlags
& DSDDESC_DOMMSYSTEMOPEN
)
732 waveOutClose(This
->hwo
);
735 IDsDriver_Release(This
->driver
);
737 RtlDeleteResource(&This
->lock
);
738 DeleteCriticalSection(&This
->mixlock
);
739 DeleteCriticalSection(&This
->ds3dl_lock
);
740 HeapFree(GetProcessHeap(),0,This
);
747 static HRESULT WINAPI
IDirectSoundImpl_SetSpeakerConfig(
748 LPDIRECTSOUND8 iface
,DWORD config
750 ICOM_THIS(IDirectSoundImpl
,iface
);
751 FIXME("(%p,0x%08lx):stub\n",This
,config
);
755 static HRESULT WINAPI
IDirectSoundImpl_QueryInterface(
756 LPDIRECTSOUND8 iface
,REFIID riid
,LPVOID
*ppobj
758 ICOM_THIS(IDirectSoundImpl
,iface
);
759 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
762 WARN("invalid parameter\n");
766 *ppobj
= NULL
; /* assume failure */
768 if ( IsEqualGUID(riid
, &IID_IUnknown
) ||
769 IsEqualGUID(riid
, &IID_IDirectSound
) ||
770 IsEqualGUID(riid
, &IID_IDirectSound8
) ) {
771 IDirectSound8_AddRef((LPDIRECTSOUND8
)This
);
776 if ( IsEqualGUID( &IID_IDirectSound3DListener
, riid
) ) {
777 WARN("app requested IDirectSound3DListener on dsound object\n");
778 return E_NOINTERFACE
;
781 FIXME( "Unknown IID %s\n", debugstr_guid( riid
) );
782 return E_NOINTERFACE
;
785 static HRESULT WINAPI
IDirectSoundImpl_Compact(
786 LPDIRECTSOUND8 iface
)
788 ICOM_THIS(IDirectSoundImpl
,iface
);
789 TRACE("(%p)\n", This
);
793 static HRESULT WINAPI
IDirectSoundImpl_GetSpeakerConfig(
794 LPDIRECTSOUND8 iface
,
795 LPDWORD lpdwSpeakerConfig
)
797 ICOM_THIS(IDirectSoundImpl
,iface
);
798 TRACE("(%p, %p)\n", This
, lpdwSpeakerConfig
);
799 *lpdwSpeakerConfig
= DSSPEAKER_STEREO
| (DSSPEAKER_GEOMETRY_NARROW
<< 16);
803 static HRESULT WINAPI
IDirectSoundImpl_Initialize(
804 LPDIRECTSOUND8 iface
,
807 ICOM_THIS(IDirectSoundImpl
,iface
);
808 TRACE("(%p, %s)\n", This
, debugstr_guid(lpcGuid
));
812 static HRESULT WINAPI
IDirectSoundImpl_VerifyCertification(
813 LPDIRECTSOUND8 iface
,
814 LPDWORD pdwCertified
)
816 ICOM_THIS(IDirectSoundImpl
,iface
);
817 TRACE("(%p, %p)\n", This
, pdwCertified
);
818 *pdwCertified
= DS_CERTIFIED
;
822 static ICOM_VTABLE(IDirectSound8
) dsvt
=
824 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
825 IDirectSoundImpl_QueryInterface
,
826 IDirectSoundImpl_AddRef
,
827 IDirectSoundImpl_Release
,
828 IDirectSoundImpl_CreateSoundBuffer
,
829 IDirectSoundImpl_GetCaps
,
830 IDirectSoundImpl_DuplicateSoundBuffer
,
831 IDirectSoundImpl_SetCooperativeLevel
,
832 IDirectSoundImpl_Compact
,
833 IDirectSoundImpl_GetSpeakerConfig
,
834 IDirectSoundImpl_SetSpeakerConfig
,
835 IDirectSoundImpl_Initialize
,
836 IDirectSoundImpl_VerifyCertification
840 /*******************************************************************************
841 * DirectSoundCreate (DSOUND.1)
843 * Creates and initializes a DirectSound interface.
846 * lpcGUID [I] Address of the GUID that identifies the sound device.
847 * ppDS [O] Address of a variable to receive the interface pointer.
848 * pUnkOuter [I] Must be NULL.
852 * Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
853 * DSERR_NODRIVER, DSERR_OUTOFMEMORY
855 HRESULT WINAPI
DirectSoundCreate8(LPCGUID lpcGUID
,LPDIRECTSOUND8
*ppDS
,IUnknown
*pUnkOuter
)
857 IDirectSoundImpl
** ippDS
=(IDirectSoundImpl
**)ppDS
;
858 PIDSDRIVER drv
= NULL
;
860 HRESULT err
= DSERR_INVALIDPARAM
;
862 BOOLEAN found
= FALSE
;
864 TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID
),ippDS
,pUnkOuter
);
867 WARN("invalid parameter: ippDS == NULL\n");
868 return DSERR_INVALIDPARAM
;
871 /* Get dsound configuration */
872 setup_dsound_options();
874 /* Default device? */
875 if (!lpcGUID
|| IsEqualGUID(lpcGUID
, &GUID_NULL
))
876 lpcGUID
= &DSDEVID_DefaultPlayback
;
878 if (GetDeviceID(lpcGUID
, &devGuid
) != DS_OK
) {
879 WARN("invalid parameter: lpcGUID\n");
881 return DSERR_INVALIDPARAM
;
885 if (IsEqualGUID(&devGuid
, &dsound
->guid
) ) {
886 ERR("dsound already opened\n");
887 IDirectSound_AddRef((LPDIRECTSOUND
)dsound
);
891 ERR("different dsound already opened\n");
895 /* Enumerate WINMM audio devices and find the one we want */
896 wodn
= waveOutGetNumDevs();
900 return DSERR_NODRIVER
;
903 TRACE(" expecting GUID %s.\n", debugstr_guid(&devGuid
));
905 for (wod
=0; wod
<wodn
; wod
++) {
907 err
= mmErr(waveOutMessage((HWAVEOUT
)wod
,DRV_QUERYDSOUNDGUID
,(DWORD
)(&guid
),0));
909 WARN("waveOutMessage failed; err=%lx\n",err
);
913 TRACE("got GUID %s for wod %d.\n", debugstr_guid(&guid
), wod
);
914 if (IsEqualGUID( &devGuid
, &guid
) ) {
922 WARN("invalid parameter\n");
924 return DSERR_INVALIDPARAM
;
927 if (found
== FALSE
) {
928 WARN("No device found matching given ID - trying with default one !\n");
929 wod
= ds_default_playback
;
932 /* DRV_QUERYDSOUNDIFACE is a "Wine extension" to get the DSound interface */
933 waveOutMessage((HWAVEOUT
)wod
, DRV_QUERYDSOUNDIFACE
, (DWORD
)&drv
, 0);
935 /* Disable the direct sound driver to force emulation if requested. */
936 if (ds_hw_accel
== DS_HW_ACCEL_EMULATION
)
939 /* Allocate memory */
940 *ippDS
= (IDirectSoundImpl
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDirectSoundImpl
));
941 if (*ippDS
== NULL
) {
942 WARN("out of memory\n");
943 return DSERR_OUTOFMEMORY
;
946 (*ippDS
)->lpVtbl
= &dsvt
;
949 (*ippDS
)->driver
= drv
;
950 (*ippDS
)->priolevel
= DSSCL_NORMAL
;
951 (*ippDS
)->fraglen
= 0;
952 (*ippDS
)->hwbuf
= NULL
;
953 (*ippDS
)->buffer
= NULL
;
954 (*ippDS
)->buflen
= 0;
955 (*ippDS
)->writelead
= 0;
956 (*ippDS
)->state
= STATE_STOPPED
;
957 (*ippDS
)->nrofbuffers
= 0;
958 (*ippDS
)->buffers
= NULL
;
959 (*ippDS
)->primary
= NULL
;
961 /* 3D listener initial parameters */
962 (*ippDS
)->listener
= NULL
;
963 (*ippDS
)->ds3dl
.dwSize
= sizeof(DS3DLISTENER
);
964 (*ippDS
)->ds3dl
.vPosition
.u1
.x
= 0.0;
965 (*ippDS
)->ds3dl
.vPosition
.u2
.y
= 0.0;
966 (*ippDS
)->ds3dl
.vPosition
.u3
.z
= 0.0;
967 (*ippDS
)->ds3dl
.vVelocity
.u1
.x
= 0.0;
968 (*ippDS
)->ds3dl
.vVelocity
.u2
.y
= 0.0;
969 (*ippDS
)->ds3dl
.vVelocity
.u3
.z
= 0.0;
970 (*ippDS
)->ds3dl
.vOrientFront
.u1
.x
= 0.0;
971 (*ippDS
)->ds3dl
.vOrientFront
.u2
.y
= 0.0;
972 (*ippDS
)->ds3dl
.vOrientFront
.u3
.z
= 1.0;
973 (*ippDS
)->ds3dl
.vOrientTop
.u1
.x
= 0.0;
974 (*ippDS
)->ds3dl
.vOrientTop
.u2
.y
= 1.0;
975 (*ippDS
)->ds3dl
.vOrientTop
.u3
.z
= 0.0;
976 (*ippDS
)->ds3dl
.flDistanceFactor
= DS3D_DEFAULTDISTANCEFACTOR
;
977 (*ippDS
)->ds3dl
.flRolloffFactor
= DS3D_DEFAULTROLLOFFFACTOR
;
978 (*ippDS
)->ds3dl
.flDopplerFactor
= DS3D_DEFAULTDOPPLERFACTOR
;
980 InitializeCriticalSection(&(*ippDS
)->ds3dl_lock
);
982 (*ippDS
)->prebuf
= ds_snd_queue_max
;
983 (*ippDS
)->guid
= devGuid
;
985 /* Get driver description */
987 err
= IDsDriver_GetDriverDesc(drv
,&((*ippDS
)->drvdesc
));
989 WARN("IDsDriver_GetDriverDesc failed\n");
990 HeapFree(GetProcessHeap(),0,*ippDS
);
995 /* if no DirectSound interface available, use WINMM API instead */
996 (*ippDS
)->drvdesc
.dwFlags
= DSDDESC_DOMMSYSTEMOPEN
| DSDDESC_DOMMSYSTEMSETFORMAT
;
999 (*ippDS
)->drvdesc
.dnDevNode
= wod
;
1001 /* Set default wave format (may need it for waveOutOpen) */
1002 (*ippDS
)->wfx
.wFormatTag
= WAVE_FORMAT_PCM
;
1003 /* We rely on the sound driver to return the actual sound format of
1004 * the device if it does not support 22050x8x2 and is given the
1005 * WAVE_DIRECTSOUND flag.
1007 (*ippDS
)->wfx
.nSamplesPerSec
= 22050;
1008 (*ippDS
)->wfx
.wBitsPerSample
= 8;
1009 (*ippDS
)->wfx
.nChannels
= 2;
1010 (*ippDS
)->wfx
.nBlockAlign
= (*ippDS
)->wfx
.wBitsPerSample
* (*ippDS
)->wfx
.nChannels
/ 8;
1011 (*ippDS
)->wfx
.nAvgBytesPerSec
= (*ippDS
)->wfx
.nSamplesPerSec
* (*ippDS
)->wfx
.nBlockAlign
;
1012 (*ippDS
)->wfx
.cbSize
= 0;
1014 /* If the driver requests being opened through MMSYSTEM
1015 * (which is recommended by the DDK), it is supposed to happen
1016 * before the DirectSound interface is opened */
1017 if ((*ippDS
)->drvdesc
.dwFlags
& DSDDESC_DOMMSYSTEMOPEN
)
1019 DWORD flags
= CALLBACK_FUNCTION
;
1021 /* disable direct sound if requested */
1022 if (ds_hw_accel
!= DS_HW_ACCEL_EMULATION
)
1023 flags
|= WAVE_DIRECTSOUND
;
1025 err
= mmErr(waveOutOpen(&((*ippDS
)->hwo
),
1026 (*ippDS
)->drvdesc
.dnDevNode
, &((*ippDS
)->wfx
),
1027 (DWORD
)DSOUND_callback
, (DWORD
)(*ippDS
),
1030 WARN("waveOutOpen failed\n");
1031 HeapFree(GetProcessHeap(),0,*ippDS
);
1038 err
= IDsDriver_Open(drv
);
1040 WARN("IDsDriver_Open failed\n");
1041 HeapFree(GetProcessHeap(),0,*ippDS
);
1046 /* the driver is now open, so it's now allowed to call GetCaps */
1047 err
= IDsDriver_GetCaps(drv
,&((*ippDS
)->drvcaps
));
1049 WARN("IDsDriver_GetCaps failed\n");
1050 HeapFree(GetProcessHeap(),0,*ippDS
);
1056 err
= mmErr(waveOutGetDevCapsA((*ippDS
)->drvdesc
.dnDevNode
, &woc
, sizeof(woc
)));
1058 WARN("waveOutGetDevCaps failed\n");
1059 HeapFree(GetProcessHeap(),0,*ippDS
);
1063 (*ippDS
)->drvcaps
.dwFlags
= 0;
1064 if ((woc
.dwFormats
& WAVE_FORMAT_1M08
) ||
1065 (woc
.dwFormats
& WAVE_FORMAT_2M08
) ||
1066 (woc
.dwFormats
& WAVE_FORMAT_4M08
) ||
1067 (woc
.dwFormats
& WAVE_FORMAT_48M08
) ||
1068 (woc
.dwFormats
& WAVE_FORMAT_96M08
)) {
1069 (*ippDS
)->drvcaps
.dwFlags
|= DSCAPS_PRIMARY8BIT
;
1070 (*ippDS
)->drvcaps
.dwFlags
|= DSCAPS_PRIMARYMONO
;
1072 if ((woc
.dwFormats
& WAVE_FORMAT_1M16
) ||
1073 (woc
.dwFormats
& WAVE_FORMAT_2M16
) ||
1074 (woc
.dwFormats
& WAVE_FORMAT_4M16
) ||
1075 (woc
.dwFormats
& WAVE_FORMAT_48M16
) ||
1076 (woc
.dwFormats
& WAVE_FORMAT_96M16
)) {
1077 (*ippDS
)->drvcaps
.dwFlags
|= DSCAPS_PRIMARY16BIT
;
1078 (*ippDS
)->drvcaps
.dwFlags
|= DSCAPS_PRIMARYMONO
;
1080 if ((woc
.dwFormats
& WAVE_FORMAT_1S08
) ||
1081 (woc
.dwFormats
& WAVE_FORMAT_2S08
) ||
1082 (woc
.dwFormats
& WAVE_FORMAT_4S08
) ||
1083 (woc
.dwFormats
& WAVE_FORMAT_48S08
) ||
1084 (woc
.dwFormats
& WAVE_FORMAT_96S08
)) {
1085 (*ippDS
)->drvcaps
.dwFlags
|= DSCAPS_PRIMARY8BIT
;
1086 (*ippDS
)->drvcaps
.dwFlags
|= DSCAPS_PRIMARYSTEREO
;
1088 if ((woc
.dwFormats
& WAVE_FORMAT_1S16
) ||
1089 (woc
.dwFormats
& WAVE_FORMAT_2S16
) ||
1090 (woc
.dwFormats
& WAVE_FORMAT_4S16
) ||
1091 (woc
.dwFormats
& WAVE_FORMAT_48S16
) ||
1092 (woc
.dwFormats
& WAVE_FORMAT_96S16
)) {
1093 (*ippDS
)->drvcaps
.dwFlags
|= DSCAPS_PRIMARY16BIT
;
1094 (*ippDS
)->drvcaps
.dwFlags
|= DSCAPS_PRIMARYSTEREO
;
1097 (*ippDS
)->drvcaps
.dwFlags
|= DSCAPS_EMULDRIVER
;
1100 DSOUND_RecalcVolPan(&((*ippDS
)->volpan
));
1102 InitializeCriticalSection(&((*ippDS
)->mixlock
));
1103 RtlInitializeResource(&((*ippDS
)->lock
));
1108 hres
= DSOUND_PrimaryCreate(dsound
);
1109 if (hres
!= DS_OK
) {
1110 WARN("DSOUND_PrimaryCreate failed\n");
1113 timeBeginPeriod(DS_TIME_RES
);
1114 dsound
->timerID
= timeSetEvent(DS_TIME_DEL
, DS_TIME_RES
, DSOUND_timer
,
1115 (DWORD
)dsound
, TIME_PERIODIC
| TIME_CALLBACK_FUNCTION
);
1118 /* create a user accessable primary buffer */
1119 (*ippDS
)->dsbd
.dwSize
= sizeof((*ippDS
)->dsbd
);
1120 err
= PrimaryBuffer_Create((*ippDS
), (PrimaryBufferImpl
**)&((*ippDS
)->primary
), &((*ippDS
)->dsbd
));
1121 if ((*ippDS
)->primary
)
1122 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8
)(*ippDS
)->primary
);
1124 WARN("PrimaryBuffer_Create failed\n");
1130 /*******************************************************************************
1131 * DirectSound ClassFactory
1134 static HRESULT WINAPI
1135 DSCF_QueryInterface(LPCLASSFACTORY iface
,REFIID riid
,LPVOID
*ppobj
) {
1136 ICOM_THIS(IClassFactoryImpl
,iface
);
1138 FIXME("(%p)->(%s,%p),stub!\n",This
,debugstr_guid(riid
),ppobj
);
1139 return E_NOINTERFACE
;
1143 DSCF_AddRef(LPCLASSFACTORY iface
) {
1144 ICOM_THIS(IClassFactoryImpl
,iface
);
1145 TRACE("(%p) ref was %ld\n", This
, This
->ref
);
1146 return ++(This
->ref
);
1149 static ULONG WINAPI
DSCF_Release(LPCLASSFACTORY iface
) {
1150 ICOM_THIS(IClassFactoryImpl
,iface
);
1151 /* static class, won't be freed */
1152 TRACE("(%p) ref was %ld\n", This
, This
->ref
);
1153 return --(This
->ref
);
1156 static HRESULT WINAPI
DSCF_CreateInstance(
1157 LPCLASSFACTORY iface
,LPUNKNOWN pOuter
,REFIID riid
,LPVOID
*ppobj
1159 ICOM_THIS(IClassFactoryImpl
,iface
);
1160 TRACE("(%p)->(%p,%s,%p)\n",This
,pOuter
,debugstr_guid(riid
),ppobj
);
1162 if (ppobj
== NULL
) {
1163 WARN("invalid parameter\n");
1164 return DSERR_INVALIDPARAM
;
1169 if ( IsEqualGUID( &IID_IDirectSound
, riid
) ||
1170 IsEqualGUID( &IID_IDirectSound8
, riid
) ) {
1171 /* FIXME: reuse already created dsound if present? */
1172 return DirectSoundCreate8(0,(LPDIRECTSOUND8
*)ppobj
,pOuter
);
1175 WARN("(%p,%p,%s,%p) Interface not found!\n",This
,pOuter
,debugstr_guid(riid
),ppobj
);
1176 return E_NOINTERFACE
;
1179 static HRESULT WINAPI
DSCF_LockServer(LPCLASSFACTORY iface
,BOOL dolock
) {
1180 ICOM_THIS(IClassFactoryImpl
,iface
);
1181 FIXME("(%p)->(%d),stub!\n",This
,dolock
);
1185 static ICOM_VTABLE(IClassFactory
) DSCF_Vtbl
= {
1186 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1187 DSCF_QueryInterface
,
1190 DSCF_CreateInstance
,
1194 static IClassFactoryImpl DSOUND_CF
= { &DSCF_Vtbl
, 1 };
1196 /*******************************************************************************
1197 * DirectSoundPrivate ClassFactory
1200 static HRESULT WINAPI
1201 DSPCF_QueryInterface(LPCLASSFACTORY iface
,REFIID riid
,LPVOID
*ppobj
) {
1202 ICOM_THIS(IClassFactoryImpl
,iface
);
1204 FIXME("(%p)->(%s,%p),stub!\n",This
,debugstr_guid(riid
),ppobj
);
1205 return E_NOINTERFACE
;
1209 DSPCF_AddRef(LPCLASSFACTORY iface
) {
1210 ICOM_THIS(IClassFactoryImpl
,iface
);
1211 TRACE("(%p) ref was %ld\n", This
, This
->ref
);
1212 return ++(This
->ref
);
1216 DSPCF_Release(LPCLASSFACTORY iface
) {
1217 ICOM_THIS(IClassFactoryImpl
,iface
);
1218 /* static class, won't be freed */
1219 TRACE("(%p) ref was %ld\n", This
, This
->ref
);
1220 return --(This
->ref
);
1223 static HRESULT WINAPI
1224 DSPCF_CreateInstance(
1225 LPCLASSFACTORY iface
,LPUNKNOWN pOuter
,REFIID riid
,LPVOID
*ppobj
1227 ICOM_THIS(IClassFactoryImpl
,iface
);
1228 TRACE("(%p)->(%p,%s,%p)\n",This
,pOuter
,debugstr_guid(riid
),ppobj
);
1230 if (ppobj
== NULL
) {
1231 WARN("invalid parameter\n");
1232 return DSERR_INVALIDPARAM
;
1237 if ( IsEqualGUID( &IID_IKsPropertySet
, riid
) ) {
1238 return IKsPropertySetImpl_Create(0,(IKsPropertySetImpl
**)ppobj
);
1241 WARN("(%p,%p,%s,%p) Interface not found!\n",This
,pOuter
,debugstr_guid(riid
),ppobj
);
1242 return E_NOINTERFACE
;
1245 static HRESULT WINAPI
1246 DSPCF_LockServer(LPCLASSFACTORY iface
,BOOL dolock
) {
1247 ICOM_THIS(IClassFactoryImpl
,iface
);
1248 FIXME("(%p)->(%d),stub!\n",This
,dolock
);
1252 static ICOM_VTABLE(IClassFactory
) DSPCF_Vtbl
= {
1253 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1254 DSPCF_QueryInterface
,
1257 DSPCF_CreateInstance
,
1261 static IClassFactoryImpl DSOUND_PRIVATE_CF
= { &DSPCF_Vtbl
, 1 };
1263 /*******************************************************************************
1264 * DllGetClassObject [DSOUND.5]
1265 * Retrieves class object from a DLL object
1268 * Docs say returns STDAPI
1271 * rclsid [I] CLSID for the class object
1272 * riid [I] Reference to identifier of interface for class object
1273 * ppv [O] Address of variable to receive interface pointer for riid
1277 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
1280 DWORD WINAPI
DSOUND_DllGetClassObject(REFCLSID rclsid
,REFIID riid
,LPVOID
*ppv
)
1282 TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid
), debugstr_guid(riid
), ppv
);
1285 WARN("invalid parameter\n");
1286 return E_INVALIDARG
;
1291 if ( IsEqualCLSID( &CLSID_DirectSound
, rclsid
) ||
1292 IsEqualCLSID( &CLSID_DirectSound8
, rclsid
) ) {
1293 if ( IsEqualCLSID( &IID_IClassFactory
, riid
) ) {
1294 *ppv
= (LPVOID
)&DSOUND_CF
;
1295 IClassFactory_AddRef((IClassFactory
*)*ppv
);
1298 WARN("(%s,%s,%p): no interface found.\n",
1299 debugstr_guid(rclsid
), debugstr_guid(riid
), ppv
);
1303 if ( IsEqualCLSID( &CLSID_DirectSoundCapture
, rclsid
) ||
1304 IsEqualCLSID( &CLSID_DirectSoundCapture8
, rclsid
) ) {
1305 if ( IsEqualCLSID( &IID_IClassFactory
, riid
) ) {
1306 *ppv
= (LPVOID
)&DSOUND_CAPTURE_CF
;
1307 IClassFactory_AddRef((IClassFactory
*)*ppv
);
1310 WARN("(%s,%s,%p): no interface found.\n",
1311 debugstr_guid(rclsid
), debugstr_guid(riid
), ppv
);
1315 if ( IsEqualCLSID( &CLSID_DirectSoundFullDuplex
, rclsid
) ) {
1316 if ( IsEqualCLSID( &IID_IClassFactory
, riid
) ) {
1317 *ppv
= (LPVOID
)&DSOUND_FULLDUPLEX_CF
;
1318 IClassFactory_AddRef((IClassFactory
*)*ppv
);
1321 WARN("(%s,%s,%p): no interface found.\n",
1322 debugstr_guid(rclsid
), debugstr_guid(riid
), ppv
);
1326 if ( IsEqualCLSID( &CLSID_DirectSoundPrivate
, rclsid
) ) {
1327 if ( IsEqualCLSID( &IID_IClassFactory
, riid
) ) {
1328 *ppv
= (LPVOID
)&DSOUND_PRIVATE_CF
;
1329 IClassFactory_AddRef((IClassFactory
*)*ppv
);
1332 WARN("(%s,%s,%p): no interface found.\n",
1333 debugstr_guid(rclsid
), debugstr_guid(riid
), ppv
);
1337 WARN("(%s,%s,%p): no class found.\n", debugstr_guid(rclsid
), debugstr_guid(riid
), ppv
);
1338 return CLASS_E_CLASSNOTAVAILABLE
;
1342 /*******************************************************************************
1343 * DllCanUnloadNow [DSOUND.4]
1344 * Determines whether the DLL is in use.
1350 DWORD WINAPI
DSOUND_DllCanUnloadNow(void)
1352 FIXME("(void): stub\n");