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
);
404 TRACE("(flags=0x%08lx)\n",caps
->dwFlags
);
407 return DSERR_INVALIDPARAM
;
409 /* We should check this value, not set it. See Inside DirectX, p215. */
410 caps
->dwSize
= sizeof(*caps
);
412 caps
->dwFlags
= This
->drvcaps
.dwFlags
;
414 /* FIXME: copy caps from This->drvcaps */
415 caps
->dwMinSecondarySampleRate
= DSBFREQUENCY_MIN
;
416 caps
->dwMaxSecondarySampleRate
= DSBFREQUENCY_MAX
;
418 caps
->dwPrimaryBuffers
= 1;
420 caps
->dwMaxHwMixingAllBuffers
= 0;
421 caps
->dwMaxHwMixingStaticBuffers
= 0;
422 caps
->dwMaxHwMixingStreamingBuffers
= 0;
424 caps
->dwFreeHwMixingAllBuffers
= 0;
425 caps
->dwFreeHwMixingStaticBuffers
= 0;
426 caps
->dwFreeHwMixingStreamingBuffers
= 0;
428 caps
->dwMaxHw3DAllBuffers
= 0;
429 caps
->dwMaxHw3DStaticBuffers
= 0;
430 caps
->dwMaxHw3DStreamingBuffers
= 0;
432 caps
->dwFreeHw3DAllBuffers
= 0;
433 caps
->dwFreeHw3DStaticBuffers
= 0;
434 caps
->dwFreeHw3DStreamingBuffers
= 0;
436 caps
->dwTotalHwMemBytes
= 0;
438 caps
->dwFreeHwMemBytes
= 0;
440 caps
->dwMaxContigFreeHwMemBytes
= 0;
442 caps
->dwUnlockTransferRateHwBuffers
= 4096; /* But we have none... */
444 caps
->dwPlayCpuOverheadSwBuffers
= 1; /* 1% */
449 static ULONG WINAPI
IDirectSoundImpl_AddRef(LPDIRECTSOUND8 iface
) {
450 ICOM_THIS(IDirectSoundImpl
,iface
);
451 return ++(This
->ref
);
454 static ULONG WINAPI
IDirectSoundImpl_Release(LPDIRECTSOUND8 iface
) {
455 ICOM_THIS(IDirectSoundImpl
,iface
);
456 TRACE("(%p), ref was %ld\n",This
,This
->ref
);
457 if (!--(This
->ref
)) {
460 timeKillEvent(This
->timerID
);
461 timeEndPeriod(DS_TIME_RES
);
464 for( i
=0;i
<This
->nrofbuffers
;i
++)
465 IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8
)This
->buffers
[i
]);
468 DSOUND_PrimaryDestroy(This
);
470 RtlDeleteResource(&This
->lock
);
471 DeleteCriticalSection(&This
->mixlock
);
473 IDsDriver_Close(This
->driver
);
476 for (c
=0; c
<DS_HEL_FRAGS
; c
++)
477 HeapFree(GetProcessHeap(),0,This
->pwave
[c
]);
479 if (This
->drvdesc
.dwFlags
& DSDDESC_DOMMSYSTEMOPEN
) {
480 waveOutClose(This
->hwo
);
483 IDsDriver_Release(This
->driver
);
485 HeapFree(GetProcessHeap(),0,This
);
492 static HRESULT WINAPI
IDirectSoundImpl_SetSpeakerConfig(
493 LPDIRECTSOUND8 iface
,DWORD config
495 ICOM_THIS(IDirectSoundImpl
,iface
);
496 FIXME("(%p,0x%08lx):stub\n",This
,config
);
500 static HRESULT WINAPI
IDirectSoundImpl_QueryInterface(
501 LPDIRECTSOUND8 iface
,REFIID riid
,LPVOID
*ppobj
503 ICOM_THIS(IDirectSoundImpl
,iface
);
505 if ( IsEqualGUID( &IID_IDirectSound3DListener
, riid
) ) {
506 ERR("app requested IDirectSound3DListener on dsound object\n");
511 FIXME("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
512 return E_NOINTERFACE
;
515 static HRESULT WINAPI
IDirectSoundImpl_Compact(
516 LPDIRECTSOUND8 iface
)
518 ICOM_THIS(IDirectSoundImpl
,iface
);
519 TRACE("(%p)\n", This
);
523 static HRESULT WINAPI
IDirectSoundImpl_GetSpeakerConfig(
524 LPDIRECTSOUND8 iface
,
525 LPDWORD lpdwSpeakerConfig
)
527 ICOM_THIS(IDirectSoundImpl
,iface
);
528 TRACE("(%p, %p)\n", This
, lpdwSpeakerConfig
);
529 *lpdwSpeakerConfig
= DSSPEAKER_STEREO
| (DSSPEAKER_GEOMETRY_NARROW
<< 16);
533 static HRESULT WINAPI
IDirectSoundImpl_Initialize(
534 LPDIRECTSOUND8 iface
,
537 ICOM_THIS(IDirectSoundImpl
,iface
);
538 TRACE("(%p, %p)\n", This
, lpcGuid
);
542 static HRESULT WINAPI
IDirectSoundImpl_VerifyCertification(
543 LPDIRECTSOUND8 iface
,
544 LPDWORD pdwCertified
)
546 ICOM_THIS(IDirectSoundImpl
,iface
);
547 TRACE("(%p, %p)\n", This
, pdwCertified
);
548 *pdwCertified
= DS_CERTIFIED
;
552 static ICOM_VTABLE(IDirectSound8
) dsvt
=
554 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
555 IDirectSoundImpl_QueryInterface
,
556 IDirectSoundImpl_AddRef
,
557 IDirectSoundImpl_Release
,
558 IDirectSoundImpl_CreateSoundBuffer
,
559 IDirectSoundImpl_GetCaps
,
560 IDirectSoundImpl_DuplicateSoundBuffer
,
561 IDirectSoundImpl_SetCooperativeLevel
,
562 IDirectSoundImpl_Compact
,
563 IDirectSoundImpl_GetSpeakerConfig
,
564 IDirectSoundImpl_SetSpeakerConfig
,
565 IDirectSoundImpl_Initialize
,
566 IDirectSoundImpl_VerifyCertification
570 /*******************************************************************************
571 * DirectSoundCreate (DSOUND.1)
573 HRESULT WINAPI
DirectSoundCreate8(REFGUID lpGUID
,LPDIRECTSOUND8
*ppDS
,IUnknown
*pUnkOuter
)
575 IDirectSoundImpl
** ippDS
=(IDirectSoundImpl
**)ppDS
;
576 PIDSDRIVER drv
= NULL
;
582 TRACE("(%p,%p,%p)\n",lpGUID
,ippDS
,pUnkOuter
);
584 TRACE("DirectSoundCreate (%p)\n", ippDS
);
587 return DSERR_INVALIDPARAM
;
590 IDirectSound_AddRef((LPDIRECTSOUND
)dsound
);
595 /* Get dsound configuration */
596 setup_dsound_options();
598 /* Enumerate WINMM audio devices and find the one we want */
599 wodn
= waveOutGetNumDevs();
600 if (!wodn
) return DSERR_NODRIVER
;
602 /* FIXME: How do we find the GUID of an audio device? */
603 wod
= 0; /* start at the first audio device */
605 /* Get output device caps */
606 waveOutGetDevCapsA(wod
, &wcaps
, sizeof(wcaps
));
607 /* DRV_QUERYDSOUNDIFACE is a "Wine extension" to get the DSound interface */
608 waveOutMessage((HWAVEOUT
)wod
, DRV_QUERYDSOUNDIFACE
, (DWORD
)&drv
, 0);
610 /* Allocate memory */
611 *ippDS
= (IDirectSoundImpl
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDirectSoundImpl
));
613 return DSERR_OUTOFMEMORY
;
615 ICOM_VTBL(*ippDS
) = &dsvt
;
618 (*ippDS
)->driver
= drv
;
619 (*ippDS
)->priolevel
= DSSCL_NORMAL
;
620 (*ippDS
)->fraglen
= 0;
621 (*ippDS
)->hwbuf
= NULL
;
622 (*ippDS
)->buffer
= NULL
;
623 (*ippDS
)->buflen
= 0;
624 (*ippDS
)->writelead
= 0;
625 (*ippDS
)->state
= STATE_STOPPED
;
626 (*ippDS
)->nrofbuffers
= 0;
627 (*ippDS
)->buffers
= NULL
;
628 /* (*ippDS)->primary = NULL; */
629 (*ippDS
)->listener
= NULL
;
631 (*ippDS
)->prebuf
= ds_snd_queue_max
;
633 /* Get driver description */
635 IDsDriver_GetDriverDesc(drv
,&((*ippDS
)->drvdesc
));
637 /* if no DirectSound interface available, use WINMM API instead */
638 (*ippDS
)->drvdesc
.dwFlags
= DSDDESC_DOMMSYSTEMOPEN
| DSDDESC_DOMMSYSTEMSETFORMAT
;
639 (*ippDS
)->drvdesc
.dnDevNode
= wod
; /* FIXME? */
642 /* Set default wave format (may need it for waveOutOpen) */
643 (*ippDS
)->wfx
.wFormatTag
= WAVE_FORMAT_PCM
;
644 /* default to stereo, if the sound card can do it */
645 if (wcaps
.wChannels
> 1)
646 (*ippDS
)->wfx
.nChannels
= 2;
648 (*ippDS
)->wfx
.nChannels
= 1;
649 /* default to 8, if the sound card can do it */
650 if (wcaps
.dwFormats
& (WAVE_FORMAT_4M08
| WAVE_FORMAT_2M08
| WAVE_FORMAT_1M08
|
651 WAVE_FORMAT_4S08
| WAVE_FORMAT_2S08
| WAVE_FORMAT_1S08
)) {
652 (*ippDS
)->wfx
.wBitsPerSample
= 8;
653 (*ippDS
)->wfx
.nBlockAlign
= 1 * (*ippDS
)->wfx
.nChannels
;
655 /* it's probably a 16-bit-only card */
656 (*ippDS
)->wfx
.wBitsPerSample
= 16;
657 (*ippDS
)->wfx
.nBlockAlign
= 2 * (*ippDS
)->wfx
.nChannels
;
659 (*ippDS
)->wfx
.nSamplesPerSec
= 22050;
660 (*ippDS
)->wfx
.nAvgBytesPerSec
= 22050 * (*ippDS
)->wfx
.nBlockAlign
;
662 /* If the driver requests being opened through MMSYSTEM
663 * (which is recommended by the DDK), it is supposed to happen
664 * before the DirectSound interface is opened */
665 if ((*ippDS
)->drvdesc
.dwFlags
& DSDDESC_DOMMSYSTEMOPEN
)
667 /* FIXME: is this right? */
668 (*ippDS
)->drvdesc
.dnDevNode
= 0;
669 err
= DSERR_ALLOCATED
;
671 /* if this device is busy try the next one */
672 while((err
== DSERR_ALLOCATED
) &&
673 ((*ippDS
)->drvdesc
.dnDevNode
< wodn
))
675 err
= mmErr(waveOutOpen(&((*ippDS
)->hwo
),
676 (*ippDS
)->drvdesc
.dnDevNode
, &((*ippDS
)->wfx
),
677 (DWORD
)DSOUND_callback
, (DWORD
)(*ippDS
),
678 CALLBACK_FUNCTION
| WAVE_DIRECTSOUND
));
679 (*ippDS
)->drvdesc
.dnDevNode
++; /* next wave device */
682 (*ippDS
)->drvdesc
.dnDevNode
--; /* take away last increment */
684 /* for aRts sound server */
685 if (err
== DS_OK
) waveOutSetVolume( (*ippDS
)->drvdesc
.dnDevNode
, 0xFFFFFFFFL
);
688 if (drv
&& (err
== DS_OK
))
689 err
= IDsDriver_Open(drv
);
691 /* FIXME: do we want to handle a temporarily busy device? */
693 HeapFree(GetProcessHeap(),0,*ippDS
);
698 /* the driver is now open, so it's now allowed to call GetCaps */
700 IDsDriver_GetCaps(drv
,&((*ippDS
)->drvcaps
));
704 /* FIXME: look at wcaps */
705 (*ippDS
)->drvcaps
.dwFlags
=
706 DSCAPS_PRIMARY16BIT
| DSCAPS_PRIMARYSTEREO
;
708 (*ippDS
)->drvcaps
.dwFlags
|= DSCAPS_EMULDRIVER
;
710 /* Allocate memory for HEL buffer headers */
711 for (c
=0; c
<DS_HEL_FRAGS
; c
++) {
712 (*ippDS
)->pwave
[c
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(WAVEHDR
));
713 if (!(*ippDS
)->pwave
[c
]) {
714 /* Argh, out of memory */
716 HeapFree(GetProcessHeap(),0,(*ippDS
)->pwave
[c
]);
717 waveOutClose((*ippDS
)->hwo
);
718 HeapFree(GetProcessHeap(),0,*ippDS
);
720 return DSERR_OUTOFMEMORY
;
726 DSOUND_RecalcVolPan(&((*ippDS
)->volpan
));
728 InitializeCriticalSection(&((*ippDS
)->mixlock
));
729 RtlInitializeResource(&((*ippDS
)->lock
));
733 DSOUND_PrimaryCreate(dsound
);
734 timeBeginPeriod(DS_TIME_RES
);
735 dsound
->timerID
= timeSetEvent(DS_TIME_DEL
, DS_TIME_RES
, DSOUND_timer
,
736 (DWORD
)dsound
, TIME_PERIODIC
| TIME_CALLBACK_FUNCTION
);
742 /*******************************************************************************
743 * DirectSound ClassFactory
747 /* IUnknown fields */
748 ICOM_VFIELD(IClassFactory
);
752 static HRESULT WINAPI
753 DSCF_QueryInterface(LPCLASSFACTORY iface
,REFIID riid
,LPVOID
*ppobj
) {
754 ICOM_THIS(IClassFactoryImpl
,iface
);
756 FIXME("(%p)->(%s,%p),stub!\n",This
,debugstr_guid(riid
),ppobj
);
757 return E_NOINTERFACE
;
761 DSCF_AddRef(LPCLASSFACTORY iface
) {
762 ICOM_THIS(IClassFactoryImpl
,iface
);
763 return ++(This
->ref
);
766 static ULONG WINAPI
DSCF_Release(LPCLASSFACTORY iface
) {
767 ICOM_THIS(IClassFactoryImpl
,iface
);
768 /* static class, won't be freed */
769 return --(This
->ref
);
772 static HRESULT WINAPI
DSCF_CreateInstance(
773 LPCLASSFACTORY iface
,LPUNKNOWN pOuter
,REFIID riid
,LPVOID
*ppobj
775 ICOM_THIS(IClassFactoryImpl
,iface
);
777 TRACE("(%p)->(%p,%s,%p)\n",This
,pOuter
,debugstr_guid(riid
),ppobj
);
778 if ( IsEqualGUID( &IID_IDirectSound
, riid
) ||
779 IsEqualGUID( &IID_IDirectSound8
, riid
) ) {
780 /* FIXME: reuse already created dsound if present? */
781 return DirectSoundCreate8(riid
,(LPDIRECTSOUND8
*)ppobj
,pOuter
);
783 return E_NOINTERFACE
;
786 static HRESULT WINAPI
DSCF_LockServer(LPCLASSFACTORY iface
,BOOL dolock
) {
787 ICOM_THIS(IClassFactoryImpl
,iface
);
788 FIXME("(%p)->(%d),stub!\n",This
,dolock
);
792 static ICOM_VTABLE(IClassFactory
) DSCF_Vtbl
= {
793 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
800 static IClassFactoryImpl DSOUND_CF
= {&DSCF_Vtbl
, 1 };
802 /*******************************************************************************
803 * DllGetClassObject [DSOUND.5]
804 * Retrieves class object from a DLL object
807 * Docs say returns STDAPI
810 * rclsid [I] CLSID for the class object
811 * riid [I] Reference to identifier of interface for class object
812 * ppv [O] Address of variable to receive interface pointer for riid
816 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
819 DWORD WINAPI
DSOUND_DllGetClassObject(REFCLSID rclsid
,REFIID riid
,LPVOID
*ppv
)
821 TRACE("(%p,%p,%p)\n", debugstr_guid(rclsid
), debugstr_guid(riid
), ppv
);
822 if ( IsEqualCLSID( &IID_IClassFactory
, riid
) ) {
823 *ppv
= (LPVOID
)&DSOUND_CF
;
824 IClassFactory_AddRef((IClassFactory
*)*ppv
);
828 FIXME("(%p,%p,%p): no interface found.\n", debugstr_guid(rclsid
), debugstr_guid(riid
), ppv
);
829 return CLASS_E_CLASSNOTAVAILABLE
;
833 /*******************************************************************************
834 * DllCanUnloadNow [DSOUND.4] Determines whether the DLL is in use.
840 DWORD WINAPI
DSOUND_DllCanUnloadNow(void)
842 FIXME("(void): stub\n");