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>
51 #include <math.h> /* Insomnia - pow() function */
63 #include "wine/windef16.h"
64 #include "wine/winbase16.h"
65 #include "wine/debug.h"
68 #include "dsound_private.h"
70 WINE_DEFAULT_DEBUG_CHANNEL(dsound
);
72 /* these are eligible for tuning... they must be high on slow machines... */
73 /* some stuff may get more responsive with lower values though... */
74 #define DS_EMULDRIVER 0 /* some games (Quake 2, UT) refuse to accept
75 emulated dsound devices. set to 0 ! */
76 #define DS_HEL_MARGIN 5 /* HEL only: number of waveOut fragments ahead to mix in new buffers
77 * (keep this close or equal to DS_HEL_QUEUE for best results) */
78 #define DS_HEL_QUEUE 5 /* HEL only: number of waveOut fragments ahead to queue to driver
79 * (this will affect HEL sound reliability and latency) */
81 #define DS_SND_QUEUE_MAX 28 /* max number of fragments to prebuffer */
82 #define DS_SND_QUEUE_MIN 12 /* min number of fragments to prebuffer */
84 IDirectSoundImpl
* dsound
= NULL
;
86 static HRESULT
mmErr(UINT err
)
89 case MMSYSERR_NOERROR
:
91 case MMSYSERR_ALLOCATED
:
92 return DSERR_ALLOCATED
;
93 case MMSYSERR_INVALHANDLE
:
94 return DSERR_GENERIC
; /* FIXME */
95 case MMSYSERR_NODRIVER
:
96 return DSERR_NODRIVER
;
98 return DSERR_OUTOFMEMORY
;
99 case MMSYSERR_INVALPARAM
:
100 return DSERR_INVALIDPARAM
;
102 FIXME("Unknown MMSYS error %d\n",err
);
103 return DSERR_GENERIC
;
107 int ds_emuldriver
= DS_EMULDRIVER
;
108 int ds_hel_margin
= DS_HEL_MARGIN
;
109 int ds_hel_queue
= DS_HEL_QUEUE
;
110 int ds_snd_queue_max
= DS_SND_QUEUE_MAX
;
111 int ds_snd_queue_min
= DS_SND_QUEUE_MIN
;
114 * Call the callback provided to DirectSoundEnumerateA.
117 inline static void enumerate_devices(LPDSENUMCALLBACKA lpDSEnumCallback
,
120 if (lpDSEnumCallback
!= NULL
)
121 if (lpDSEnumCallback(NULL
, "Primary DirectSound Driver",
123 lpDSEnumCallback((LPGUID
)&DSDEVID_WinePlayback
,
124 "WINE DirectSound", "sound",
130 * Get a config key from either the app-specific or the default config
133 inline static DWORD
get_config_key( HKEY defkey
, HKEY appkey
, const char *name
,
134 char *buffer
, DWORD size
)
136 if (appkey
&& !RegQueryValueExA( appkey
, name
, 0, NULL
, buffer
, &size
)) return 0;
137 return RegQueryValueExA( defkey
, name
, 0, NULL
, buffer
, &size
);
142 * Setup the dsound options.
145 inline static void setup_dsound_options(void)
147 char buffer
[MAX_PATH
+1];
148 HKEY hkey
, appkey
= 0;
150 buffer
[MAX_PATH
]='\0';
152 if (RegCreateKeyExA( HKEY_LOCAL_MACHINE
, "Software\\Wine\\Wine\\Config\\dsound", 0, NULL
,
153 REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
))
155 ERR("Cannot create config registry key\n" );
159 if (GetModuleFileNameA( 0, buffer
, MAX_PATH
))
163 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE
, "Software\\Wine\\Wine\\Config\\AppDefaults", &tmpkey
))
165 char appname
[MAX_PATH
+16];
166 char *p
= strrchr( buffer
, '\\' );
168 appname
[MAX_PATH
]='\0';
169 strncpy(appname
,p
+1,MAX_PATH
);
170 strcat(appname
,"\\dsound");
171 TRACE("appname = [%s] \n",appname
);
172 if (RegOpenKeyA( tmpkey
, appname
, &appkey
)) appkey
= 0;
173 RegCloseKey( tmpkey
);
180 if (!get_config_key( hkey
, appkey
, "EmulDriver", buffer
, MAX_PATH
))
181 ds_emuldriver
= strcmp(buffer
, "N");
183 if (!get_config_key( hkey
, appkey
, "HELmargin", buffer
, MAX_PATH
))
184 ds_hel_margin
= atoi(buffer
);
186 if (!get_config_key( hkey
, appkey
, "HELqueue", buffer
, MAX_PATH
))
187 ds_hel_queue
= atoi(buffer
);
189 if (!get_config_key( hkey
, appkey
, "SndQueueMax", buffer
, MAX_PATH
))
190 ds_snd_queue_max
= atoi(buffer
);
192 if (!get_config_key( hkey
, appkey
, "SndQueueMin", buffer
, MAX_PATH
))
193 ds_snd_queue_min
= atoi(buffer
);
195 if (appkey
) RegCloseKey( appkey
);
198 if (ds_emuldriver
!= DS_EMULDRIVER
)
199 WARN("ds_emuldriver = %d (default=%d)\n",ds_emuldriver
, DS_EMULDRIVER
);
200 if (ds_hel_margin
!= DS_HEL_MARGIN
)
201 WARN("ds_hel_margin = %d (default=%d)\n",ds_hel_margin
, DS_HEL_MARGIN
);
202 if (ds_hel_queue
!= DS_HEL_QUEUE
)
203 WARN("ds_hel_queue = %d (default=%d)\n",ds_hel_queue
, DS_HEL_QUEUE
);
204 if (ds_snd_queue_max
!= DS_SND_QUEUE_MAX
)
205 WARN("ds_snd_queue_max = %d (default=%d)\n",ds_snd_queue_max
,DS_SND_QUEUE_MAX
);
206 if (ds_snd_queue_min
!= DS_SND_QUEUE_MIN
)
207 WARN("ds_snd_queue_min = %d (default=%d)\n",ds_snd_queue_min
,DS_SND_QUEUE_MIN
);
213 /***************************************************************************
214 * DirectSoundEnumerateA [DSOUND.2]
216 * Enumerate all DirectSound drivers installed in the system
220 * Failure: DSERR_INVALIDPARAM
222 HRESULT WINAPI
DirectSoundEnumerateA(
223 LPDSENUMCALLBACKA lpDSEnumCallback
,
229 TRACE("lpDSEnumCallback = %p, lpContext = %p\n",
230 lpDSEnumCallback
, lpContext
);
232 devs
= waveOutGetNumDevs();
233 for (wod
= 0; wod
< devs
; ++wod
) {
234 waveOutGetDevCapsA(wod
, &wcaps
, sizeof(wcaps
));
235 if (wcaps
.dwSupport
& WAVECAPS_DIRECTSOUND
) {
236 TRACE("- Device %u supports DirectSound\n", wod
);
237 enumerate_devices(lpDSEnumCallback
, lpContext
);
244 /***************************************************************************
245 * DirectSoundEnumerateW [DSOUND.3]
247 * Enumerate all DirectSound drivers installed in the system
251 * Failure: DSERR_INVALIDPARAM
253 HRESULT WINAPI
DirectSoundEnumerateW(
254 LPDSENUMCALLBACKW lpDSEnumCallback
,
257 FIXME("lpDSEnumCallback = %p, lpContext = %p: stub\n",
258 lpDSEnumCallback
, lpContext
);
264 static void _dump_DSBCAPS(DWORD xmask
) {
269 #define FE(x) { x, #x },
270 FE(DSBCAPS_PRIMARYBUFFER
)
272 FE(DSBCAPS_LOCHARDWARE
)
273 FE(DSBCAPS_LOCSOFTWARE
)
275 FE(DSBCAPS_CTRLFREQUENCY
)
277 FE(DSBCAPS_CTRLVOLUME
)
278 FE(DSBCAPS_CTRLPOSITIONNOTIFY
)
279 FE(DSBCAPS_CTRLDEFAULT
)
281 FE(DSBCAPS_STICKYFOCUS
)
282 FE(DSBCAPS_GLOBALFOCUS
)
283 FE(DSBCAPS_GETCURRENTPOSITION2
)
284 FE(DSBCAPS_MUTE3DATMAXDISTANCE
)
289 for (i
=0;i
<sizeof(flags
)/sizeof(flags
[0]);i
++)
290 if ((flags
[i
].mask
& xmask
) == flags
[i
].mask
)
291 DPRINTF("%s ",flags
[i
].name
);
294 /*******************************************************************************
298 static HRESULT WINAPI
IDirectSoundImpl_SetCooperativeLevel(
299 LPDIRECTSOUND8 iface
,HWND hwnd
,DWORD level
301 ICOM_THIS(IDirectSoundImpl
,iface
);
303 FIXME("(%p,%08lx,%ld):stub\n",This
,(DWORD
)hwnd
,level
);
305 This
->priolevel
= level
;
310 static HRESULT WINAPI
IDirectSoundImpl_CreateSoundBuffer(
311 LPDIRECTSOUND8 iface
,LPDSBUFFERDESC dsbd
,LPLPDIRECTSOUNDBUFFER8 ppdsb
,LPUNKNOWN lpunk
313 ICOM_THIS(IDirectSoundImpl
,iface
);
316 TRACE("(%p,%p,%p,%p)\n",This
,dsbd
,ppdsb
,lpunk
);
318 if ((This
== NULL
) || (dsbd
== NULL
) || (ppdsb
== NULL
))
319 return DSERR_INVALIDPARAM
;
321 if (TRACE_ON(dsound
)) {
322 TRACE("(structsize=%ld)\n",dsbd
->dwSize
);
323 TRACE("(flags=0x%08lx:\n",dsbd
->dwFlags
);
324 _dump_DSBCAPS(dsbd
->dwFlags
);
326 TRACE("(bufferbytes=%ld)\n",dsbd
->dwBufferBytes
);
327 TRACE("(lpwfxFormat=%p)\n",dsbd
->lpwfxFormat
);
330 wfex
= dsbd
->lpwfxFormat
;
333 TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld,"
334 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
335 wfex
->wFormatTag
, wfex
->nChannels
, wfex
->nSamplesPerSec
,
336 wfex
->nAvgBytesPerSec
, wfex
->nBlockAlign
,
337 wfex
->wBitsPerSample
, wfex
->cbSize
);
339 if (dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
)
340 return PrimaryBuffer_Create(This
, (PrimaryBufferImpl
**)ppdsb
, dsbd
);
342 return SecondaryBuffer_Create(This
, (IDirectSoundBufferImpl
**)ppdsb
, dsbd
);
345 static HRESULT WINAPI
IDirectSoundImpl_DuplicateSoundBuffer(
346 LPDIRECTSOUND8 iface
,LPDIRECTSOUNDBUFFER8 pdsb
,LPLPDIRECTSOUNDBUFFER8 ppdsb
348 ICOM_THIS(IDirectSoundImpl
,iface
);
349 IDirectSoundBufferImpl
* ipdsb
=(IDirectSoundBufferImpl
*)pdsb
;
350 IDirectSoundBufferImpl
** ippdsb
=(IDirectSoundBufferImpl
**)ppdsb
;
351 TRACE("(%p,%p,%p)\n",This
,ipdsb
,ippdsb
);
353 if (ipdsb
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
354 ERR("trying to duplicate primary buffer\n");
355 return DSERR_INVALIDCALL
;
359 FIXME("need to duplicate hardware buffer\n");
362 if (ipdsb
->dsbd
.dwFlags
& DSBCAPS_CTRL3D
) {
363 FIXME("need to duplicate 3D buffer\n");
366 *ippdsb
= (IDirectSoundBufferImpl
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDirectSoundBufferImpl
));
368 IDirectSoundBuffer8_AddRef(pdsb
);
369 memcpy(*ippdsb
, ipdsb
, sizeof(IDirectSoundBufferImpl
));
371 (*ippdsb
)->state
= STATE_STOPPED
;
372 (*ippdsb
)->playpos
= 0;
373 (*ippdsb
)->buf_mixpos
= 0;
374 (*ippdsb
)->dsound
= This
;
375 (*ippdsb
)->parent
= ipdsb
;
376 (*ippdsb
)->hwbuf
= NULL
;
377 (*ippdsb
)->ds3db
= NULL
; /* FIXME? */
378 (*ippdsb
)->iks
= NULL
; /* FIXME? */
379 memcpy(&((*ippdsb
)->wfx
), &(ipdsb
->wfx
), sizeof((*ippdsb
)->wfx
));
380 InitializeCriticalSection(&(*ippdsb
)->lock
);
381 /* register buffer */
382 RtlAcquireResourceExclusive(&(This
->lock
), TRUE
);
384 IDirectSoundBufferImpl
**newbuffers
= (IDirectSoundBufferImpl
**)HeapReAlloc(GetProcessHeap(),0,This
->buffers
,sizeof(IDirectSoundBufferImpl
**)*(This
->nrofbuffers
+1));
386 This
->buffers
= newbuffers
;
387 This
->buffers
[This
->nrofbuffers
] = *ippdsb
;
389 TRACE("buffer count is now %d\n", This
->nrofbuffers
);
391 ERR("out of memory for buffer list! Current buffer count is %d\n", This
->nrofbuffers
);
392 /* FIXME: release buffer */
395 RtlReleaseResource(&(This
->lock
));
396 IDirectSound_AddRef(iface
);
401 static HRESULT WINAPI
IDirectSoundImpl_GetCaps(LPDIRECTSOUND8 iface
,LPDSCAPS caps
) {
402 ICOM_THIS(IDirectSoundImpl
,iface
);
403 TRACE("(%p,%p)\n",This
,caps
);
405 if (caps
== NULL
|| caps
->dwSize
!=sizeof(*caps
))
406 return DSERR_INVALIDPARAM
;
408 caps
->dwFlags
= This
->drvcaps
.dwFlags
;
409 TRACE("(flags=0x%08lx)\n",caps
->dwFlags
);
411 /* FIXME: copy caps from This->drvcaps */
412 caps
->dwMinSecondarySampleRate
= DSBFREQUENCY_MIN
;
413 caps
->dwMaxSecondarySampleRate
= DSBFREQUENCY_MAX
;
415 caps
->dwPrimaryBuffers
= 1;
417 caps
->dwMaxHwMixingAllBuffers
= 0;
418 caps
->dwMaxHwMixingStaticBuffers
= 0;
419 caps
->dwMaxHwMixingStreamingBuffers
= 0;
421 caps
->dwFreeHwMixingAllBuffers
= 0;
422 caps
->dwFreeHwMixingStaticBuffers
= 0;
423 caps
->dwFreeHwMixingStreamingBuffers
= 0;
425 caps
->dwMaxHw3DAllBuffers
= 0;
426 caps
->dwMaxHw3DStaticBuffers
= 0;
427 caps
->dwMaxHw3DStreamingBuffers
= 0;
429 caps
->dwFreeHw3DAllBuffers
= 0;
430 caps
->dwFreeHw3DStaticBuffers
= 0;
431 caps
->dwFreeHw3DStreamingBuffers
= 0;
433 caps
->dwTotalHwMemBytes
= 0;
435 caps
->dwFreeHwMemBytes
= 0;
437 caps
->dwMaxContigFreeHwMemBytes
= 0;
439 caps
->dwUnlockTransferRateHwBuffers
= 4096; /* But we have none... */
441 caps
->dwPlayCpuOverheadSwBuffers
= 1; /* 1% */
446 static ULONG WINAPI
IDirectSoundImpl_AddRef(LPDIRECTSOUND8 iface
) {
447 ICOM_THIS(IDirectSoundImpl
,iface
);
448 return ++(This
->ref
);
451 static ULONG WINAPI
IDirectSoundImpl_Release(LPDIRECTSOUND8 iface
) {
452 ICOM_THIS(IDirectSoundImpl
,iface
);
453 TRACE("(%p), ref was %ld\n",This
,This
->ref
);
454 if (!--(This
->ref
)) {
457 timeKillEvent(This
->timerID
);
458 timeEndPeriod(DS_TIME_RES
);
461 for( i
=0;i
<This
->nrofbuffers
;i
++)
462 IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8
)This
->buffers
[i
]);
465 DSOUND_PrimaryDestroy(This
);
467 RtlDeleteResource(&This
->lock
);
468 DeleteCriticalSection(&This
->mixlock
);
470 IDsDriver_Close(This
->driver
);
472 if (This
->drvdesc
.dwFlags
& DSDDESC_DOMMSYSTEMOPEN
) {
473 waveOutClose(This
->hwo
);
476 IDsDriver_Release(This
->driver
);
478 HeapFree(GetProcessHeap(),0,This
);
485 static HRESULT WINAPI
IDirectSoundImpl_SetSpeakerConfig(
486 LPDIRECTSOUND8 iface
,DWORD config
488 ICOM_THIS(IDirectSoundImpl
,iface
);
489 FIXME("(%p,0x%08lx):stub\n",This
,config
);
493 static HRESULT WINAPI
IDirectSoundImpl_QueryInterface(
494 LPDIRECTSOUND8 iface
,REFIID riid
,LPVOID
*ppobj
496 ICOM_THIS(IDirectSoundImpl
,iface
);
498 if ( IsEqualGUID( &IID_IDirectSound3DListener
, riid
) ) {
499 ERR("app requested IDirectSound3DListener on dsound object\n");
504 FIXME("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
505 return E_NOINTERFACE
;
508 static HRESULT WINAPI
IDirectSoundImpl_Compact(
509 LPDIRECTSOUND8 iface
)
511 ICOM_THIS(IDirectSoundImpl
,iface
);
512 TRACE("(%p)\n", This
);
516 static HRESULT WINAPI
IDirectSoundImpl_GetSpeakerConfig(
517 LPDIRECTSOUND8 iface
,
518 LPDWORD lpdwSpeakerConfig
)
520 ICOM_THIS(IDirectSoundImpl
,iface
);
521 TRACE("(%p, %p)\n", This
, lpdwSpeakerConfig
);
522 *lpdwSpeakerConfig
= DSSPEAKER_STEREO
| (DSSPEAKER_GEOMETRY_NARROW
<< 16);
526 static HRESULT WINAPI
IDirectSoundImpl_Initialize(
527 LPDIRECTSOUND8 iface
,
530 ICOM_THIS(IDirectSoundImpl
,iface
);
531 TRACE("(%p, %p)\n", This
, lpcGuid
);
535 static HRESULT WINAPI
IDirectSoundImpl_VerifyCertification(
536 LPDIRECTSOUND8 iface
,
537 LPDWORD pdwCertified
)
539 ICOM_THIS(IDirectSoundImpl
,iface
);
540 TRACE("(%p, %p)\n", This
, pdwCertified
);
541 *pdwCertified
= DS_CERTIFIED
;
545 static ICOM_VTABLE(IDirectSound8
) dsvt
=
547 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
548 IDirectSoundImpl_QueryInterface
,
549 IDirectSoundImpl_AddRef
,
550 IDirectSoundImpl_Release
,
551 IDirectSoundImpl_CreateSoundBuffer
,
552 IDirectSoundImpl_GetCaps
,
553 IDirectSoundImpl_DuplicateSoundBuffer
,
554 IDirectSoundImpl_SetCooperativeLevel
,
555 IDirectSoundImpl_Compact
,
556 IDirectSoundImpl_GetSpeakerConfig
,
557 IDirectSoundImpl_SetSpeakerConfig
,
558 IDirectSoundImpl_Initialize
,
559 IDirectSoundImpl_VerifyCertification
563 /*******************************************************************************
564 * DirectSoundCreate (DSOUND.1)
566 HRESULT WINAPI
DirectSoundCreate8(REFGUID lpGUID
,LPDIRECTSOUND8
*ppDS
,IUnknown
*pUnkOuter
)
568 IDirectSoundImpl
** ippDS
=(IDirectSoundImpl
**)ppDS
;
569 PIDSDRIVER drv
= NULL
;
574 TRACE("(%p,%p,%p)\n",lpGUID
,ippDS
,pUnkOuter
);
576 TRACE("DirectSoundCreate (%p)\n", ippDS
);
579 return DSERR_INVALIDPARAM
;
582 IDirectSound_AddRef((LPDIRECTSOUND
)dsound
);
587 /* Get dsound configuration */
588 setup_dsound_options();
590 /* Enumerate WINMM audio devices and find the one we want */
591 wodn
= waveOutGetNumDevs();
592 if (!wodn
) return DSERR_NODRIVER
;
594 /* FIXME: How do we find the GUID of an audio device? */
595 wod
= 0; /* start at the first audio device */
597 /* DRV_QUERYDSOUNDIFACE is a "Wine extension" to get the DSound interface */
598 waveOutMessage((HWAVEOUT
)wod
, DRV_QUERYDSOUNDIFACE
, (DWORD
)&drv
, 0);
600 /* Allocate memory */
601 *ippDS
= (IDirectSoundImpl
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDirectSoundImpl
));
603 return DSERR_OUTOFMEMORY
;
605 ICOM_VTBL(*ippDS
) = &dsvt
;
608 (*ippDS
)->driver
= drv
;
609 (*ippDS
)->priolevel
= DSSCL_NORMAL
;
610 (*ippDS
)->fraglen
= 0;
611 (*ippDS
)->hwbuf
= NULL
;
612 (*ippDS
)->buffer
= NULL
;
613 (*ippDS
)->buflen
= 0;
614 (*ippDS
)->writelead
= 0;
615 (*ippDS
)->state
= STATE_STOPPED
;
616 (*ippDS
)->nrofbuffers
= 0;
617 (*ippDS
)->buffers
= NULL
;
618 /* (*ippDS)->primary = NULL; */
619 (*ippDS
)->listener
= NULL
;
621 (*ippDS
)->prebuf
= ds_snd_queue_max
;
623 /* Get driver description */
625 IDsDriver_GetDriverDesc(drv
,&((*ippDS
)->drvdesc
));
627 /* if no DirectSound interface available, use WINMM API instead */
628 (*ippDS
)->drvdesc
.dwFlags
= DSDDESC_DOMMSYSTEMOPEN
| DSDDESC_DOMMSYSTEMSETFORMAT
;
629 (*ippDS
)->drvdesc
.dnDevNode
= wod
; /* FIXME? */
632 /* Set default wave format (may need it for waveOutOpen) */
633 (*ippDS
)->wfx
.wFormatTag
= WAVE_FORMAT_PCM
;
634 /* We rely on the sound driver to return the actual sound format of
635 * the device if it does not support 22050x8x2 and is given the
636 * WAVE_DIRECTSOUND flag.
638 (*ippDS
)->wfx
.nSamplesPerSec
= 22050;
639 (*ippDS
)->wfx
.wBitsPerSample
= 8;
640 (*ippDS
)->wfx
.nChannels
= 2;
641 (*ippDS
)->wfx
.nBlockAlign
= (*ippDS
)->wfx
.wBitsPerSample
* (*ippDS
)->wfx
.nChannels
/ 8;
642 (*ippDS
)->wfx
.nAvgBytesPerSec
= (*ippDS
)->wfx
.nSamplesPerSec
* (*ippDS
)->wfx
.nBlockAlign
;
643 (*ippDS
)->wfx
.cbSize
= 0;
645 /* If the driver requests being opened through MMSYSTEM
646 * (which is recommended by the DDK), it is supposed to happen
647 * before the DirectSound interface is opened */
648 if ((*ippDS
)->drvdesc
.dwFlags
& DSDDESC_DOMMSYSTEMOPEN
)
650 /* FIXME: is this right? */
651 (*ippDS
)->drvdesc
.dnDevNode
= 0;
652 err
= DSERR_ALLOCATED
;
654 /* if this device is busy try the next one */
655 while((err
== DSERR_ALLOCATED
) &&
656 ((*ippDS
)->drvdesc
.dnDevNode
< wodn
))
658 err
= mmErr(waveOutOpen(&((*ippDS
)->hwo
),
659 (*ippDS
)->drvdesc
.dnDevNode
, &((*ippDS
)->wfx
),
660 (DWORD
)DSOUND_callback
, (DWORD
)(*ippDS
),
661 CALLBACK_FUNCTION
| WAVE_DIRECTSOUND
));
662 (*ippDS
)->drvdesc
.dnDevNode
++; /* next wave device */
665 (*ippDS
)->drvdesc
.dnDevNode
--; /* take away last increment */
668 if (drv
&& (err
== DS_OK
))
669 err
= IDsDriver_Open(drv
);
671 /* FIXME: do we want to handle a temporarily busy device? */
673 HeapFree(GetProcessHeap(),0,*ippDS
);
678 /* the driver is now open, so it's now allowed to call GetCaps */
680 IDsDriver_GetCaps(drv
,&((*ippDS
)->drvcaps
));
682 /* FIXME: We should check the device capabilities */
683 (*ippDS
)->drvcaps
.dwFlags
=
684 DSCAPS_PRIMARY16BIT
| DSCAPS_PRIMARYSTEREO
;
686 (*ippDS
)->drvcaps
.dwFlags
|= DSCAPS_EMULDRIVER
;
689 DSOUND_RecalcVolPan(&((*ippDS
)->volpan
));
691 InitializeCriticalSection(&((*ippDS
)->mixlock
));
692 RtlInitializeResource(&((*ippDS
)->lock
));
696 DSOUND_PrimaryCreate(dsound
);
697 timeBeginPeriod(DS_TIME_RES
);
698 dsound
->timerID
= timeSetEvent(DS_TIME_DEL
, DS_TIME_RES
, DSOUND_timer
,
699 (DWORD
)dsound
, TIME_PERIODIC
| TIME_CALLBACK_FUNCTION
);
705 /*******************************************************************************
706 * DirectSound ClassFactory
710 /* IUnknown fields */
711 ICOM_VFIELD(IClassFactory
);
715 static HRESULT WINAPI
716 DSCF_QueryInterface(LPCLASSFACTORY iface
,REFIID riid
,LPVOID
*ppobj
) {
717 ICOM_THIS(IClassFactoryImpl
,iface
);
719 FIXME("(%p)->(%s,%p),stub!\n",This
,debugstr_guid(riid
),ppobj
);
720 return E_NOINTERFACE
;
724 DSCF_AddRef(LPCLASSFACTORY iface
) {
725 ICOM_THIS(IClassFactoryImpl
,iface
);
726 return ++(This
->ref
);
729 static ULONG WINAPI
DSCF_Release(LPCLASSFACTORY iface
) {
730 ICOM_THIS(IClassFactoryImpl
,iface
);
731 /* static class, won't be freed */
732 return --(This
->ref
);
735 static HRESULT WINAPI
DSCF_CreateInstance(
736 LPCLASSFACTORY iface
,LPUNKNOWN pOuter
,REFIID riid
,LPVOID
*ppobj
738 ICOM_THIS(IClassFactoryImpl
,iface
);
740 TRACE("(%p)->(%p,%s,%p)\n",This
,pOuter
,debugstr_guid(riid
),ppobj
);
741 if ( IsEqualGUID( &IID_IDirectSound
, riid
) ||
742 IsEqualGUID( &IID_IDirectSound8
, riid
) ) {
743 /* FIXME: reuse already created dsound if present? */
744 return DirectSoundCreate8(riid
,(LPDIRECTSOUND8
*)ppobj
,pOuter
);
746 return E_NOINTERFACE
;
749 static HRESULT WINAPI
DSCF_LockServer(LPCLASSFACTORY iface
,BOOL dolock
) {
750 ICOM_THIS(IClassFactoryImpl
,iface
);
751 FIXME("(%p)->(%d),stub!\n",This
,dolock
);
755 static ICOM_VTABLE(IClassFactory
) DSCF_Vtbl
= {
756 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
763 static IClassFactoryImpl DSOUND_CF
= {&DSCF_Vtbl
, 1 };
765 /*******************************************************************************
766 * DllGetClassObject [DSOUND.5]
767 * Retrieves class object from a DLL object
770 * Docs say returns STDAPI
773 * rclsid [I] CLSID for the class object
774 * riid [I] Reference to identifier of interface for class object
775 * ppv [O] Address of variable to receive interface pointer for riid
779 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
782 DWORD WINAPI
DSOUND_DllGetClassObject(REFCLSID rclsid
,REFIID riid
,LPVOID
*ppv
)
784 TRACE("(%p,%p,%p)\n", debugstr_guid(rclsid
), debugstr_guid(riid
), ppv
);
785 if ( IsEqualCLSID( &IID_IClassFactory
, riid
) ) {
786 *ppv
= (LPVOID
)&DSOUND_CF
;
787 IClassFactory_AddRef((IClassFactory
*)*ppv
);
791 FIXME("(%p,%p,%p): no interface found.\n", debugstr_guid(rclsid
), debugstr_guid(riid
), ppv
);
792 return CLASS_E_CLASSNOTAVAILABLE
;
796 /*******************************************************************************
797 * DllCanUnloadNow [DSOUND.4] Determines whether the DLL is in use.
803 DWORD WINAPI
DSOUND_DllCanUnloadNow(void)
805 FIXME("(void): stub\n");