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
);
473 for (c
=0; c
<DS_HEL_FRAGS
; c
++)
474 HeapFree(GetProcessHeap(),0,This
->pwave
[c
]);
476 if (This
->drvdesc
.dwFlags
& DSDDESC_DOMMSYSTEMOPEN
) {
477 waveOutClose(This
->hwo
);
480 IDsDriver_Release(This
->driver
);
482 HeapFree(GetProcessHeap(),0,This
);
489 static HRESULT WINAPI
IDirectSoundImpl_SetSpeakerConfig(
490 LPDIRECTSOUND8 iface
,DWORD config
492 ICOM_THIS(IDirectSoundImpl
,iface
);
493 FIXME("(%p,0x%08lx):stub\n",This
,config
);
497 static HRESULT WINAPI
IDirectSoundImpl_QueryInterface(
498 LPDIRECTSOUND8 iface
,REFIID riid
,LPVOID
*ppobj
500 ICOM_THIS(IDirectSoundImpl
,iface
);
502 if ( IsEqualGUID( &IID_IDirectSound3DListener
, riid
) ) {
503 ERR("app requested IDirectSound3DListener on dsound object\n");
508 FIXME("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
509 return E_NOINTERFACE
;
512 static HRESULT WINAPI
IDirectSoundImpl_Compact(
513 LPDIRECTSOUND8 iface
)
515 ICOM_THIS(IDirectSoundImpl
,iface
);
516 TRACE("(%p)\n", This
);
520 static HRESULT WINAPI
IDirectSoundImpl_GetSpeakerConfig(
521 LPDIRECTSOUND8 iface
,
522 LPDWORD lpdwSpeakerConfig
)
524 ICOM_THIS(IDirectSoundImpl
,iface
);
525 TRACE("(%p, %p)\n", This
, lpdwSpeakerConfig
);
526 *lpdwSpeakerConfig
= DSSPEAKER_STEREO
| (DSSPEAKER_GEOMETRY_NARROW
<< 16);
530 static HRESULT WINAPI
IDirectSoundImpl_Initialize(
531 LPDIRECTSOUND8 iface
,
534 ICOM_THIS(IDirectSoundImpl
,iface
);
535 TRACE("(%p, %p)\n", This
, lpcGuid
);
539 static HRESULT WINAPI
IDirectSoundImpl_VerifyCertification(
540 LPDIRECTSOUND8 iface
,
541 LPDWORD pdwCertified
)
543 ICOM_THIS(IDirectSoundImpl
,iface
);
544 TRACE("(%p, %p)\n", This
, pdwCertified
);
545 *pdwCertified
= DS_CERTIFIED
;
549 static ICOM_VTABLE(IDirectSound8
) dsvt
=
551 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
552 IDirectSoundImpl_QueryInterface
,
553 IDirectSoundImpl_AddRef
,
554 IDirectSoundImpl_Release
,
555 IDirectSoundImpl_CreateSoundBuffer
,
556 IDirectSoundImpl_GetCaps
,
557 IDirectSoundImpl_DuplicateSoundBuffer
,
558 IDirectSoundImpl_SetCooperativeLevel
,
559 IDirectSoundImpl_Compact
,
560 IDirectSoundImpl_GetSpeakerConfig
,
561 IDirectSoundImpl_SetSpeakerConfig
,
562 IDirectSoundImpl_Initialize
,
563 IDirectSoundImpl_VerifyCertification
567 /*******************************************************************************
568 * DirectSoundCreate (DSOUND.1)
570 HRESULT WINAPI
DirectSoundCreate8(REFGUID lpGUID
,LPDIRECTSOUND8
*ppDS
,IUnknown
*pUnkOuter
)
572 IDirectSoundImpl
** ippDS
=(IDirectSoundImpl
**)ppDS
;
573 PIDSDRIVER drv
= NULL
;
579 TRACE("(%p,%p,%p)\n",lpGUID
,ippDS
,pUnkOuter
);
581 TRACE("DirectSoundCreate (%p)\n", ippDS
);
584 return DSERR_INVALIDPARAM
;
587 IDirectSound_AddRef((LPDIRECTSOUND
)dsound
);
592 /* Get dsound configuration */
593 setup_dsound_options();
595 /* Enumerate WINMM audio devices and find the one we want */
596 wodn
= waveOutGetNumDevs();
597 if (!wodn
) return DSERR_NODRIVER
;
599 /* FIXME: How do we find the GUID of an audio device? */
600 wod
= 0; /* start at the first audio device */
602 /* Get output device caps */
603 waveOutGetDevCapsA(wod
, &wcaps
, sizeof(wcaps
));
604 /* DRV_QUERYDSOUNDIFACE is a "Wine extension" to get the DSound interface */
605 waveOutMessage((HWAVEOUT
)wod
, DRV_QUERYDSOUNDIFACE
, (DWORD
)&drv
, 0);
607 /* Allocate memory */
608 *ippDS
= (IDirectSoundImpl
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDirectSoundImpl
));
610 return DSERR_OUTOFMEMORY
;
612 ICOM_VTBL(*ippDS
) = &dsvt
;
615 (*ippDS
)->driver
= drv
;
616 (*ippDS
)->priolevel
= DSSCL_NORMAL
;
617 (*ippDS
)->fraglen
= 0;
618 (*ippDS
)->hwbuf
= NULL
;
619 (*ippDS
)->buffer
= NULL
;
620 (*ippDS
)->buflen
= 0;
621 (*ippDS
)->writelead
= 0;
622 (*ippDS
)->state
= STATE_STOPPED
;
623 (*ippDS
)->nrofbuffers
= 0;
624 (*ippDS
)->buffers
= NULL
;
625 /* (*ippDS)->primary = NULL; */
626 (*ippDS
)->listener
= NULL
;
628 (*ippDS
)->prebuf
= ds_snd_queue_max
;
630 /* Get driver description */
632 IDsDriver_GetDriverDesc(drv
,&((*ippDS
)->drvdesc
));
634 /* if no DirectSound interface available, use WINMM API instead */
635 (*ippDS
)->drvdesc
.dwFlags
= DSDDESC_DOMMSYSTEMOPEN
| DSDDESC_DOMMSYSTEMSETFORMAT
;
636 (*ippDS
)->drvdesc
.dnDevNode
= wod
; /* FIXME? */
639 /* Set default wave format (may need it for waveOutOpen) */
640 (*ippDS
)->wfx
.wFormatTag
= WAVE_FORMAT_PCM
;
641 /* default to stereo, if the sound card can do it */
642 if (wcaps
.wChannels
> 1)
643 (*ippDS
)->wfx
.nChannels
= 2;
645 (*ippDS
)->wfx
.nChannels
= 1;
646 /* default to 8, if the sound card can do it */
647 if (wcaps
.dwFormats
& (WAVE_FORMAT_4M08
| WAVE_FORMAT_2M08
| WAVE_FORMAT_1M08
|
648 WAVE_FORMAT_4S08
| WAVE_FORMAT_2S08
| WAVE_FORMAT_1S08
)) {
649 (*ippDS
)->wfx
.wBitsPerSample
= 8;
650 (*ippDS
)->wfx
.nBlockAlign
= 1 * (*ippDS
)->wfx
.nChannels
;
652 /* it's probably a 16-bit-only card */
653 (*ippDS
)->wfx
.wBitsPerSample
= 16;
654 (*ippDS
)->wfx
.nBlockAlign
= 2 * (*ippDS
)->wfx
.nChannels
;
656 (*ippDS
)->wfx
.nSamplesPerSec
= 22050;
657 (*ippDS
)->wfx
.nAvgBytesPerSec
= 22050 * (*ippDS
)->wfx
.nBlockAlign
;
659 /* If the driver requests being opened through MMSYSTEM
660 * (which is recommended by the DDK), it is supposed to happen
661 * before the DirectSound interface is opened */
662 if ((*ippDS
)->drvdesc
.dwFlags
& DSDDESC_DOMMSYSTEMOPEN
)
664 /* FIXME: is this right? */
665 (*ippDS
)->drvdesc
.dnDevNode
= 0;
666 err
= DSERR_ALLOCATED
;
668 /* if this device is busy try the next one */
669 while((err
== DSERR_ALLOCATED
) &&
670 ((*ippDS
)->drvdesc
.dnDevNode
< wodn
))
672 err
= mmErr(waveOutOpen(&((*ippDS
)->hwo
),
673 (*ippDS
)->drvdesc
.dnDevNode
, &((*ippDS
)->wfx
),
674 (DWORD
)DSOUND_callback
, (DWORD
)(*ippDS
),
675 CALLBACK_FUNCTION
| WAVE_DIRECTSOUND
));
676 (*ippDS
)->drvdesc
.dnDevNode
++; /* next wave device */
679 (*ippDS
)->drvdesc
.dnDevNode
--; /* take away last increment */
682 if (drv
&& (err
== DS_OK
))
683 err
= IDsDriver_Open(drv
);
685 /* FIXME: do we want to handle a temporarily busy device? */
687 HeapFree(GetProcessHeap(),0,*ippDS
);
692 /* the driver is now open, so it's now allowed to call GetCaps */
694 IDsDriver_GetCaps(drv
,&((*ippDS
)->drvcaps
));
698 /* FIXME: look at wcaps */
699 (*ippDS
)->drvcaps
.dwFlags
=
700 DSCAPS_PRIMARY16BIT
| DSCAPS_PRIMARYSTEREO
;
702 (*ippDS
)->drvcaps
.dwFlags
|= DSCAPS_EMULDRIVER
;
704 /* Allocate memory for HEL buffer headers */
705 for (c
=0; c
<DS_HEL_FRAGS
; c
++) {
706 (*ippDS
)->pwave
[c
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(WAVEHDR
));
707 if (!(*ippDS
)->pwave
[c
]) {
708 /* Argh, out of memory */
710 HeapFree(GetProcessHeap(),0,(*ippDS
)->pwave
[c
]);
711 waveOutClose((*ippDS
)->hwo
);
712 HeapFree(GetProcessHeap(),0,*ippDS
);
714 return DSERR_OUTOFMEMORY
;
720 DSOUND_RecalcVolPan(&((*ippDS
)->volpan
));
722 InitializeCriticalSection(&((*ippDS
)->mixlock
));
723 RtlInitializeResource(&((*ippDS
)->lock
));
727 DSOUND_PrimaryCreate(dsound
);
728 timeBeginPeriod(DS_TIME_RES
);
729 dsound
->timerID
= timeSetEvent(DS_TIME_DEL
, DS_TIME_RES
, DSOUND_timer
,
730 (DWORD
)dsound
, TIME_PERIODIC
| TIME_CALLBACK_FUNCTION
);
736 /*******************************************************************************
737 * DirectSound ClassFactory
741 /* IUnknown fields */
742 ICOM_VFIELD(IClassFactory
);
746 static HRESULT WINAPI
747 DSCF_QueryInterface(LPCLASSFACTORY iface
,REFIID riid
,LPVOID
*ppobj
) {
748 ICOM_THIS(IClassFactoryImpl
,iface
);
750 FIXME("(%p)->(%s,%p),stub!\n",This
,debugstr_guid(riid
),ppobj
);
751 return E_NOINTERFACE
;
755 DSCF_AddRef(LPCLASSFACTORY iface
) {
756 ICOM_THIS(IClassFactoryImpl
,iface
);
757 return ++(This
->ref
);
760 static ULONG WINAPI
DSCF_Release(LPCLASSFACTORY iface
) {
761 ICOM_THIS(IClassFactoryImpl
,iface
);
762 /* static class, won't be freed */
763 return --(This
->ref
);
766 static HRESULT WINAPI
DSCF_CreateInstance(
767 LPCLASSFACTORY iface
,LPUNKNOWN pOuter
,REFIID riid
,LPVOID
*ppobj
769 ICOM_THIS(IClassFactoryImpl
,iface
);
771 TRACE("(%p)->(%p,%s,%p)\n",This
,pOuter
,debugstr_guid(riid
),ppobj
);
772 if ( IsEqualGUID( &IID_IDirectSound
, riid
) ||
773 IsEqualGUID( &IID_IDirectSound8
, riid
) ) {
774 /* FIXME: reuse already created dsound if present? */
775 return DirectSoundCreate8(riid
,(LPDIRECTSOUND8
*)ppobj
,pOuter
);
777 return E_NOINTERFACE
;
780 static HRESULT WINAPI
DSCF_LockServer(LPCLASSFACTORY iface
,BOOL dolock
) {
781 ICOM_THIS(IClassFactoryImpl
,iface
);
782 FIXME("(%p)->(%d),stub!\n",This
,dolock
);
786 static ICOM_VTABLE(IClassFactory
) DSCF_Vtbl
= {
787 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
794 static IClassFactoryImpl DSOUND_CF
= {&DSCF_Vtbl
, 1 };
796 /*******************************************************************************
797 * DllGetClassObject [DSOUND.5]
798 * Retrieves class object from a DLL object
801 * Docs say returns STDAPI
804 * rclsid [I] CLSID for the class object
805 * riid [I] Reference to identifier of interface for class object
806 * ppv [O] Address of variable to receive interface pointer for riid
810 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
813 DWORD WINAPI
DSOUND_DllGetClassObject(REFCLSID rclsid
,REFIID riid
,LPVOID
*ppv
)
815 TRACE("(%p,%p,%p)\n", debugstr_guid(rclsid
), debugstr_guid(riid
), ppv
);
816 if ( IsEqualCLSID( &IID_IClassFactory
, riid
) ) {
817 *ppv
= (LPVOID
)&DSOUND_CF
;
818 IClassFactory_AddRef((IClassFactory
*)*ppv
);
822 FIXME("(%p,%p,%p): no interface found.\n", debugstr_guid(rclsid
), debugstr_guid(riid
), ppv
);
823 return CLASS_E_CLASSNOTAVAILABLE
;
827 /*******************************************************************************
828 * DllCanUnloadNow [DSOUND.4] Determines whether the DLL is in use.
834 DWORD WINAPI
DSOUND_DllCanUnloadNow(void)
836 FIXME("(void): stub\n");