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>
49 #include <math.h> /* Insomnia - pow() function */
61 #include "wine/windef16.h"
62 #include "wine/winbase16.h"
63 #include "wine/debug.h"
66 #include "dsound_private.h"
68 WINE_DEFAULT_DEBUG_CHANNEL(dsound
);
70 /* these are eligible for tuning... they must be high on slow machines... */
71 /* some stuff may get more responsive with lower values though... */
72 #define DS_EMULDRIVER 0 /* some games (Quake 2, UT) refuse to accept
73 emulated dsound devices. set to 0 ! */
74 #define DS_HEL_MARGIN 5 /* HEL only: number of waveOut fragments ahead to mix in new buffers
75 * (keep this close or equal to DS_HEL_QUEUE for best results) */
76 #define DS_HEL_QUEUE 5 /* HEL only: number of waveOut fragments ahead to queue to driver
77 * (this will affect HEL sound reliability and latency) */
79 #define DS_SND_QUEUE_MAX 28 /* max number of fragments to prebuffer */
80 #define DS_SND_QUEUE_MIN 12 /* min number of fragments to prebuffer */
82 IDirectSoundImpl
* dsound
= NULL
;
84 static HRESULT
mmErr(UINT err
)
87 case MMSYSERR_NOERROR
:
89 case MMSYSERR_ALLOCATED
:
90 return DSERR_ALLOCATED
;
91 case MMSYSERR_INVALHANDLE
:
92 return DSERR_GENERIC
; /* FIXME */
93 case MMSYSERR_NODRIVER
:
94 return DSERR_NODRIVER
;
96 return DSERR_OUTOFMEMORY
;
97 case MMSYSERR_INVALPARAM
:
98 return DSERR_INVALIDPARAM
;
100 FIXME("Unknown MMSYS error %d\n",err
);
101 return DSERR_GENERIC
;
105 int ds_emuldriver
= DS_EMULDRIVER
;
106 int ds_hel_margin
= DS_HEL_MARGIN
;
107 int ds_hel_queue
= DS_HEL_QUEUE
;
108 int ds_snd_queue_max
= DS_SND_QUEUE_MAX
;
109 int ds_snd_queue_min
= DS_SND_QUEUE_MIN
;
112 * Call the callback provided to DirectSoundEnumerateA.
115 inline static void enumerate_devices(LPDSENUMCALLBACKA lpDSEnumCallback
,
118 if (lpDSEnumCallback
!= NULL
)
119 if (lpDSEnumCallback(NULL
, "Primary DirectSound Driver",
121 lpDSEnumCallback((LPGUID
)&DSDEVID_WinePlayback
,
122 "WINE DirectSound", "sound",
128 * Get a config key from either the app-specific or the default config
131 inline static DWORD
get_config_key( HKEY defkey
, HKEY appkey
, const char *name
,
132 char *buffer
, DWORD size
)
134 if (appkey
&& !RegQueryValueExA( appkey
, name
, 0, NULL
, buffer
, &size
)) return 0;
135 return RegQueryValueExA( defkey
, name
, 0, NULL
, buffer
, &size
);
140 * Setup the dsound options.
143 inline static void setup_dsound_options(void)
145 char buffer
[MAX_PATH
+1];
146 HKEY hkey
, appkey
= 0;
148 buffer
[MAX_PATH
]='\0';
150 if (RegCreateKeyExA( HKEY_LOCAL_MACHINE
, "Software\\Wine\\Wine\\Config\\dsound", 0, NULL
,
151 REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
))
153 ERR("Cannot create config registry key\n" );
157 if (GetModuleFileNameA( 0, buffer
, MAX_PATH
))
161 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE
, "Software\\Wine\\Wine\\Config\\AppDefaults", &tmpkey
))
163 char appname
[MAX_PATH
+16];
164 char *p
= strrchr( buffer
, '\\' );
166 appname
[MAX_PATH
]='\0';
167 strncpy(appname
,p
+1,MAX_PATH
);
168 strcat(appname
,"\\dsound");
169 TRACE("appname = [%s] \n",appname
);
170 if (RegOpenKeyA( tmpkey
, appname
, &appkey
)) appkey
= 0;
171 RegCloseKey( tmpkey
);
178 if (!get_config_key( hkey
, appkey
, "EmulDriver", buffer
, MAX_PATH
))
179 ds_emuldriver
= strcmp(buffer
, "N");
181 if (!get_config_key( hkey
, appkey
, "HELmargin", buffer
, MAX_PATH
))
182 ds_hel_margin
= atoi(buffer
);
184 if (!get_config_key( hkey
, appkey
, "HELqueue", buffer
, MAX_PATH
))
185 ds_hel_queue
= atoi(buffer
);
187 if (!get_config_key( hkey
, appkey
, "SndQueueMax", buffer
, MAX_PATH
))
188 ds_snd_queue_max
= atoi(buffer
);
190 if (!get_config_key( hkey
, appkey
, "SndQueueMin", buffer
, MAX_PATH
))
191 ds_snd_queue_min
= atoi(buffer
);
193 if (appkey
) RegCloseKey( appkey
);
196 if (ds_emuldriver
!= DS_EMULDRIVER
)
197 WARN("ds_emuldriver = %d (default=%d)\n",ds_emuldriver
, DS_EMULDRIVER
);
198 if (ds_hel_margin
!= DS_HEL_MARGIN
)
199 WARN("ds_hel_margin = %d (default=%d)\n",ds_hel_margin
, DS_HEL_MARGIN
);
200 if (ds_hel_queue
!= DS_HEL_QUEUE
)
201 WARN("ds_hel_queue = %d (default=%d)\n",ds_hel_queue
, DS_HEL_QUEUE
);
202 if (ds_snd_queue_max
!= DS_SND_QUEUE_MAX
)
203 WARN("ds_snd_queue_max = %d (default=%d)\n",ds_snd_queue_max
,DS_SND_QUEUE_MAX
);
204 if (ds_snd_queue_min
!= DS_SND_QUEUE_MIN
)
205 WARN("ds_snd_queue_min = %d (default=%d)\n",ds_snd_queue_min
,DS_SND_QUEUE_MIN
);
211 /***************************************************************************
212 * DirectSoundEnumerateA [DSOUND.2]
214 * Enumerate all DirectSound drivers installed in the system
218 * Failure: DSERR_INVALIDPARAM
220 HRESULT WINAPI
DirectSoundEnumerateA(
221 LPDSENUMCALLBACKA lpDSEnumCallback
,
227 TRACE("lpDSEnumCallback = %p, lpContext = %p\n",
228 lpDSEnumCallback
, lpContext
);
230 devs
= waveOutGetNumDevs();
231 for (wod
= 0; wod
< devs
; ++wod
) {
232 waveOutGetDevCapsA(wod
, &wcaps
, sizeof(wcaps
));
233 if (wcaps
.dwSupport
& WAVECAPS_DIRECTSOUND
) {
234 TRACE("- Device %u supports DirectSound\n", wod
);
235 enumerate_devices(lpDSEnumCallback
, lpContext
);
242 /***************************************************************************
243 * DirectSoundEnumerateW [DSOUND.3]
245 * Enumerate all DirectSound drivers installed in the system
249 * Failure: DSERR_INVALIDPARAM
251 HRESULT WINAPI
DirectSoundEnumerateW(
252 LPDSENUMCALLBACKW lpDSEnumCallback
,
255 FIXME("lpDSEnumCallback = %p, lpContext = %p: stub\n",
256 lpDSEnumCallback
, lpContext
);
262 static void _dump_DSBCAPS(DWORD xmask
) {
267 #define FE(x) { x, #x },
268 FE(DSBCAPS_PRIMARYBUFFER
)
270 FE(DSBCAPS_LOCHARDWARE
)
271 FE(DSBCAPS_LOCSOFTWARE
)
273 FE(DSBCAPS_CTRLFREQUENCY
)
275 FE(DSBCAPS_CTRLVOLUME
)
276 FE(DSBCAPS_CTRLPOSITIONNOTIFY
)
277 FE(DSBCAPS_CTRLDEFAULT
)
279 FE(DSBCAPS_STICKYFOCUS
)
280 FE(DSBCAPS_GLOBALFOCUS
)
281 FE(DSBCAPS_GETCURRENTPOSITION2
)
282 FE(DSBCAPS_MUTE3DATMAXDISTANCE
)
287 for (i
=0;i
<sizeof(flags
)/sizeof(flags
[0]);i
++)
288 if ((flags
[i
].mask
& xmask
) == flags
[i
].mask
)
289 DPRINTF("%s ",flags
[i
].name
);
292 /*******************************************************************************
296 static HRESULT WINAPI
IDirectSoundImpl_SetCooperativeLevel(
297 LPDIRECTSOUND8 iface
,HWND hwnd
,DWORD level
299 ICOM_THIS(IDirectSoundImpl
,iface
);
301 FIXME("(%p,%08lx,%ld):stub\n",This
,(DWORD
)hwnd
,level
);
303 This
->priolevel
= level
;
308 static HRESULT WINAPI
IDirectSoundImpl_CreateSoundBuffer(
309 LPDIRECTSOUND8 iface
,LPDSBUFFERDESC dsbd
,LPLPDIRECTSOUNDBUFFER8 ppdsb
,LPUNKNOWN lpunk
311 ICOM_THIS(IDirectSoundImpl
,iface
);
314 TRACE("(%p,%p,%p,%p)\n",This
,dsbd
,ppdsb
,lpunk
);
316 if ((This
== NULL
) || (dsbd
== NULL
) || (ppdsb
== NULL
))
317 return DSERR_INVALIDPARAM
;
319 if (TRACE_ON(dsound
)) {
320 TRACE("(structsize=%ld)\n",dsbd
->dwSize
);
321 TRACE("(flags=0x%08lx:\n",dsbd
->dwFlags
);
322 _dump_DSBCAPS(dsbd
->dwFlags
);
324 TRACE("(bufferbytes=%ld)\n",dsbd
->dwBufferBytes
);
325 TRACE("(lpwfxFormat=%p)\n",dsbd
->lpwfxFormat
);
328 wfex
= dsbd
->lpwfxFormat
;
331 TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld,"
332 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
333 wfex
->wFormatTag
, wfex
->nChannels
, wfex
->nSamplesPerSec
,
334 wfex
->nAvgBytesPerSec
, wfex
->nBlockAlign
,
335 wfex
->wBitsPerSample
, wfex
->cbSize
);
337 if (dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
)
338 return PrimaryBuffer_Create(This
, (PrimaryBufferImpl
**)ppdsb
, dsbd
);
340 return SecondaryBuffer_Create(This
, (IDirectSoundBufferImpl
**)ppdsb
, dsbd
);
343 static HRESULT WINAPI
IDirectSoundImpl_DuplicateSoundBuffer(
344 LPDIRECTSOUND8 iface
,LPDIRECTSOUNDBUFFER8 pdsb
,LPLPDIRECTSOUNDBUFFER8 ppdsb
346 ICOM_THIS(IDirectSoundImpl
,iface
);
347 IDirectSoundBufferImpl
* ipdsb
=(IDirectSoundBufferImpl
*)pdsb
;
348 IDirectSoundBufferImpl
** ippdsb
=(IDirectSoundBufferImpl
**)ppdsb
;
349 TRACE("(%p,%p,%p)\n",This
,ipdsb
,ippdsb
);
351 if (ipdsb
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
352 ERR("trying to duplicate primary buffer\n");
353 return DSERR_INVALIDCALL
;
357 FIXME("need to duplicate hardware buffer\n");
360 if (ipdsb
->dsbd
.dwFlags
& DSBCAPS_CTRL3D
) {
361 FIXME("need to duplicate 3D buffer\n");
364 *ippdsb
= (IDirectSoundBufferImpl
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDirectSoundBufferImpl
));
366 IDirectSoundBuffer8_AddRef(pdsb
);
367 memcpy(*ippdsb
, ipdsb
, sizeof(IDirectSoundBufferImpl
));
369 (*ippdsb
)->state
= STATE_STOPPED
;
370 (*ippdsb
)->playpos
= 0;
371 (*ippdsb
)->buf_mixpos
= 0;
372 (*ippdsb
)->dsound
= This
;
373 (*ippdsb
)->parent
= ipdsb
;
374 (*ippdsb
)->hwbuf
= NULL
;
375 (*ippdsb
)->ds3db
= NULL
; /* FIXME? */
376 (*ippdsb
)->iks
= NULL
; /* FIXME? */
377 memcpy(&((*ippdsb
)->wfx
), &(ipdsb
->wfx
), sizeof((*ippdsb
)->wfx
));
378 InitializeCriticalSection(&(*ippdsb
)->lock
);
379 /* register buffer */
380 RtlAcquireResourceExclusive(&(This
->lock
), TRUE
);
382 IDirectSoundBufferImpl
**newbuffers
= (IDirectSoundBufferImpl
**)HeapReAlloc(GetProcessHeap(),0,This
->buffers
,sizeof(IDirectSoundBufferImpl
**)*(This
->nrofbuffers
+1));
384 This
->buffers
= newbuffers
;
385 This
->buffers
[This
->nrofbuffers
] = *ippdsb
;
387 TRACE("buffer count is now %d\n", This
->nrofbuffers
);
389 ERR("out of memory for buffer list! Current buffer count is %d\n", This
->nrofbuffers
);
390 /* FIXME: release buffer */
393 RtlReleaseResource(&(This
->lock
));
394 IDirectSound_AddRef(iface
);
399 static HRESULT WINAPI
IDirectSoundImpl_GetCaps(LPDIRECTSOUND8 iface
,LPDSCAPS caps
) {
400 ICOM_THIS(IDirectSoundImpl
,iface
);
401 TRACE("(%p,%p)\n",This
,caps
);
402 TRACE("(flags=0x%08lx)\n",caps
->dwFlags
);
405 return DSERR_INVALIDPARAM
;
407 /* We should check this value, not set it. See Inside DirectX, p215. */
408 caps
->dwSize
= sizeof(*caps
);
410 caps
->dwFlags
= This
->drvcaps
.dwFlags
;
412 /* FIXME: copy caps from This->drvcaps */
413 caps
->dwMinSecondarySampleRate
= DSBFREQUENCY_MIN
;
414 caps
->dwMaxSecondarySampleRate
= DSBFREQUENCY_MAX
;
416 caps
->dwPrimaryBuffers
= 1;
418 caps
->dwMaxHwMixingAllBuffers
= 0;
419 caps
->dwMaxHwMixingStaticBuffers
= 0;
420 caps
->dwMaxHwMixingStreamingBuffers
= 0;
422 caps
->dwFreeHwMixingAllBuffers
= 0;
423 caps
->dwFreeHwMixingStaticBuffers
= 0;
424 caps
->dwFreeHwMixingStreamingBuffers
= 0;
426 caps
->dwMaxHw3DAllBuffers
= 0;
427 caps
->dwMaxHw3DStaticBuffers
= 0;
428 caps
->dwMaxHw3DStreamingBuffers
= 0;
430 caps
->dwFreeHw3DAllBuffers
= 0;
431 caps
->dwFreeHw3DStaticBuffers
= 0;
432 caps
->dwFreeHw3DStreamingBuffers
= 0;
434 caps
->dwTotalHwMemBytes
= 0;
436 caps
->dwFreeHwMemBytes
= 0;
438 caps
->dwMaxContigFreeHwMemBytes
= 0;
440 caps
->dwUnlockTransferRateHwBuffers
= 4096; /* But we have none... */
442 caps
->dwPlayCpuOverheadSwBuffers
= 1; /* 1% */
447 static ULONG WINAPI
IDirectSoundImpl_AddRef(LPDIRECTSOUND8 iface
) {
448 ICOM_THIS(IDirectSoundImpl
,iface
);
449 return ++(This
->ref
);
452 static ULONG WINAPI
IDirectSoundImpl_Release(LPDIRECTSOUND8 iface
) {
453 ICOM_THIS(IDirectSoundImpl
,iface
);
454 TRACE("(%p), ref was %ld\n",This
,This
->ref
);
455 if (!--(This
->ref
)) {
458 timeKillEvent(This
->timerID
);
459 timeEndPeriod(DS_TIME_RES
);
462 for( i
=0;i
<This
->nrofbuffers
;i
++)
463 IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8
)This
->buffers
[i
]);
466 DSOUND_PrimaryDestroy(This
);
468 RtlDeleteResource(&This
->lock
);
469 DeleteCriticalSection(&This
->mixlock
);
471 IDsDriver_Close(This
->driver
);
474 for (c
=0; c
<DS_HEL_FRAGS
; c
++)
475 HeapFree(GetProcessHeap(),0,This
->pwave
[c
]);
477 if (This
->drvdesc
.dwFlags
& DSDDESC_DOMMSYSTEMOPEN
) {
478 waveOutClose(This
->hwo
);
481 IDsDriver_Release(This
->driver
);
483 HeapFree(GetProcessHeap(),0,This
);
490 static HRESULT WINAPI
IDirectSoundImpl_SetSpeakerConfig(
491 LPDIRECTSOUND8 iface
,DWORD config
493 ICOM_THIS(IDirectSoundImpl
,iface
);
494 FIXME("(%p,0x%08lx):stub\n",This
,config
);
498 static HRESULT WINAPI
IDirectSoundImpl_QueryInterface(
499 LPDIRECTSOUND8 iface
,REFIID riid
,LPVOID
*ppobj
501 ICOM_THIS(IDirectSoundImpl
,iface
);
503 if ( IsEqualGUID( &IID_IDirectSound3DListener
, riid
) ) {
504 ERR("app requested IDirectSound3DListener on dsound object\n");
509 FIXME("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
510 return E_NOINTERFACE
;
513 static HRESULT WINAPI
IDirectSoundImpl_Compact(
514 LPDIRECTSOUND8 iface
)
516 ICOM_THIS(IDirectSoundImpl
,iface
);
517 TRACE("(%p)\n", This
);
521 static HRESULT WINAPI
IDirectSoundImpl_GetSpeakerConfig(
522 LPDIRECTSOUND8 iface
,
523 LPDWORD lpdwSpeakerConfig
)
525 ICOM_THIS(IDirectSoundImpl
,iface
);
526 TRACE("(%p, %p)\n", This
, lpdwSpeakerConfig
);
527 *lpdwSpeakerConfig
= DSSPEAKER_STEREO
| (DSSPEAKER_GEOMETRY_NARROW
<< 16);
531 static HRESULT WINAPI
IDirectSoundImpl_Initialize(
532 LPDIRECTSOUND8 iface
,
535 ICOM_THIS(IDirectSoundImpl
,iface
);
536 TRACE("(%p, %p)\n", This
, lpcGuid
);
540 static HRESULT WINAPI
IDirectSoundImpl_VerifyCertification(
541 LPDIRECTSOUND8 iface
,
542 LPDWORD pdwCertified
)
544 ICOM_THIS(IDirectSoundImpl
,iface
);
545 TRACE("(%p, %p)\n", This
, pdwCertified
);
546 *pdwCertified
= DS_CERTIFIED
;
550 static ICOM_VTABLE(IDirectSound8
) dsvt
=
552 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
553 IDirectSoundImpl_QueryInterface
,
554 IDirectSoundImpl_AddRef
,
555 IDirectSoundImpl_Release
,
556 IDirectSoundImpl_CreateSoundBuffer
,
557 IDirectSoundImpl_GetCaps
,
558 IDirectSoundImpl_DuplicateSoundBuffer
,
559 IDirectSoundImpl_SetCooperativeLevel
,
560 IDirectSoundImpl_Compact
,
561 IDirectSoundImpl_GetSpeakerConfig
,
562 IDirectSoundImpl_SetSpeakerConfig
,
563 IDirectSoundImpl_Initialize
,
564 IDirectSoundImpl_VerifyCertification
568 /*******************************************************************************
569 * DirectSoundCreate (DSOUND.1)
571 HRESULT WINAPI
DirectSoundCreate8(REFGUID lpGUID
,LPDIRECTSOUND8
*ppDS
,IUnknown
*pUnkOuter
)
573 IDirectSoundImpl
** ippDS
=(IDirectSoundImpl
**)ppDS
;
574 PIDSDRIVER drv
= NULL
;
580 TRACE("(%p,%p,%p)\n",lpGUID
,ippDS
,pUnkOuter
);
582 TRACE("DirectSoundCreate (%p)\n", ippDS
);
585 return DSERR_INVALIDPARAM
;
588 IDirectSound_AddRef((LPDIRECTSOUND
)dsound
);
593 /* Get dsound configuration */
594 setup_dsound_options();
596 /* Enumerate WINMM audio devices and find the one we want */
597 wodn
= waveOutGetNumDevs();
598 if (!wodn
) return DSERR_NODRIVER
;
600 /* FIXME: How do we find the GUID of an audio device? */
601 wod
= 0; /* start at the first audio device */
603 /* Get output device caps */
604 waveOutGetDevCapsA(wod
, &wcaps
, sizeof(wcaps
));
605 /* DRV_QUERYDSOUNDIFACE is a "Wine extension" to get the DSound interface */
606 waveOutMessage((HWAVEOUT
)wod
, DRV_QUERYDSOUNDIFACE
, (DWORD
)&drv
, 0);
608 /* Allocate memory */
609 *ippDS
= (IDirectSoundImpl
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDirectSoundImpl
));
611 return DSERR_OUTOFMEMORY
;
613 ICOM_VTBL(*ippDS
) = &dsvt
;
616 (*ippDS
)->driver
= drv
;
617 (*ippDS
)->priolevel
= DSSCL_NORMAL
;
618 (*ippDS
)->fraglen
= 0;
619 (*ippDS
)->hwbuf
= NULL
;
620 (*ippDS
)->buffer
= NULL
;
621 (*ippDS
)->buflen
= 0;
622 (*ippDS
)->writelead
= 0;
623 (*ippDS
)->state
= STATE_STOPPED
;
624 (*ippDS
)->nrofbuffers
= 0;
625 (*ippDS
)->buffers
= NULL
;
626 /* (*ippDS)->primary = NULL; */
627 (*ippDS
)->listener
= NULL
;
629 (*ippDS
)->prebuf
= ds_snd_queue_max
;
631 /* Get driver description */
633 IDsDriver_GetDriverDesc(drv
,&((*ippDS
)->drvdesc
));
635 /* if no DirectSound interface available, use WINMM API instead */
636 (*ippDS
)->drvdesc
.dwFlags
= DSDDESC_DOMMSYSTEMOPEN
| DSDDESC_DOMMSYSTEMSETFORMAT
;
637 (*ippDS
)->drvdesc
.dnDevNode
= wod
; /* FIXME? */
640 /* Set default wave format (may need it for waveOutOpen) */
641 (*ippDS
)->wfx
.wFormatTag
= WAVE_FORMAT_PCM
;
642 (*ippDS
)->wfx
.nChannels
= 2;
643 (*ippDS
)->wfx
.nSamplesPerSec
= 22050;
644 (*ippDS
)->wfx
.nAvgBytesPerSec
= 44100;
645 (*ippDS
)->wfx
.nBlockAlign
= 2;
646 (*ippDS
)->wfx
.wBitsPerSample
= 8;
648 /* If the driver requests being opened through MMSYSTEM
649 * (which is recommended by the DDK), it is supposed to happen
650 * before the DirectSound interface is opened */
651 if ((*ippDS
)->drvdesc
.dwFlags
& DSDDESC_DOMMSYSTEMOPEN
)
653 /* FIXME: is this right? */
654 (*ippDS
)->drvdesc
.dnDevNode
= 0;
655 err
= DSERR_ALLOCATED
;
657 /* if this device is busy try the next one */
658 while((err
== DSERR_ALLOCATED
) &&
659 ((*ippDS
)->drvdesc
.dnDevNode
< wodn
))
661 err
= mmErr(waveOutOpen(&((*ippDS
)->hwo
),
662 (*ippDS
)->drvdesc
.dnDevNode
, &((*ippDS
)->wfx
),
663 (DWORD
)DSOUND_callback
, (DWORD
)(*ippDS
),
664 CALLBACK_FUNCTION
| WAVE_DIRECTSOUND
));
665 (*ippDS
)->drvdesc
.dnDevNode
++; /* next wave device */
668 (*ippDS
)->drvdesc
.dnDevNode
--; /* take away last increment */
671 if (drv
&& (err
== DS_OK
))
672 err
= IDsDriver_Open(drv
);
674 /* FIXME: do we want to handle a temporarily busy device? */
676 HeapFree(GetProcessHeap(),0,*ippDS
);
681 /* the driver is now open, so it's now allowed to call GetCaps */
683 IDsDriver_GetCaps(drv
,&((*ippDS
)->drvcaps
));
687 /* FIXME: look at wcaps */
688 (*ippDS
)->drvcaps
.dwFlags
=
689 DSCAPS_PRIMARY16BIT
| DSCAPS_PRIMARYSTEREO
;
691 (*ippDS
)->drvcaps
.dwFlags
|= DSCAPS_EMULDRIVER
;
693 /* Allocate memory for HEL buffer headers */
694 for (c
=0; c
<DS_HEL_FRAGS
; c
++) {
695 (*ippDS
)->pwave
[c
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(WAVEHDR
));
696 if (!(*ippDS
)->pwave
[c
]) {
697 /* Argh, out of memory */
699 HeapFree(GetProcessHeap(),0,(*ippDS
)->pwave
[c
]);
700 waveOutClose((*ippDS
)->hwo
);
701 HeapFree(GetProcessHeap(),0,*ippDS
);
703 return DSERR_OUTOFMEMORY
;
709 DSOUND_RecalcVolPan(&((*ippDS
)->volpan
));
711 InitializeCriticalSection(&((*ippDS
)->mixlock
));
712 RtlInitializeResource(&((*ippDS
)->lock
));
716 DSOUND_PrimaryCreate(dsound
);
717 timeBeginPeriod(DS_TIME_RES
);
718 dsound
->timerID
= timeSetEvent(DS_TIME_DEL
, DS_TIME_RES
, DSOUND_timer
,
719 (DWORD
)dsound
, TIME_PERIODIC
| TIME_CALLBACK_FUNCTION
);
725 /*******************************************************************************
726 * DirectSound ClassFactory
730 /* IUnknown fields */
731 ICOM_VFIELD(IClassFactory
);
735 static HRESULT WINAPI
736 DSCF_QueryInterface(LPCLASSFACTORY iface
,REFIID riid
,LPVOID
*ppobj
) {
737 ICOM_THIS(IClassFactoryImpl
,iface
);
739 FIXME("(%p)->(%s,%p),stub!\n",This
,debugstr_guid(riid
),ppobj
);
740 return E_NOINTERFACE
;
744 DSCF_AddRef(LPCLASSFACTORY iface
) {
745 ICOM_THIS(IClassFactoryImpl
,iface
);
746 return ++(This
->ref
);
749 static ULONG WINAPI
DSCF_Release(LPCLASSFACTORY iface
) {
750 ICOM_THIS(IClassFactoryImpl
,iface
);
751 /* static class, won't be freed */
752 return --(This
->ref
);
755 static HRESULT WINAPI
DSCF_CreateInstance(
756 LPCLASSFACTORY iface
,LPUNKNOWN pOuter
,REFIID riid
,LPVOID
*ppobj
758 ICOM_THIS(IClassFactoryImpl
,iface
);
760 TRACE("(%p)->(%p,%s,%p)\n",This
,pOuter
,debugstr_guid(riid
),ppobj
);
761 if ( IsEqualGUID( &IID_IDirectSound
, riid
) ||
762 IsEqualGUID( &IID_IDirectSound8
, riid
) ) {
763 /* FIXME: reuse already created dsound if present? */
764 return DirectSoundCreate8(riid
,(LPDIRECTSOUND8
*)ppobj
,pOuter
);
766 return E_NOINTERFACE
;
769 static HRESULT WINAPI
DSCF_LockServer(LPCLASSFACTORY iface
,BOOL dolock
) {
770 ICOM_THIS(IClassFactoryImpl
,iface
);
771 FIXME("(%p)->(%d),stub!\n",This
,dolock
);
775 static ICOM_VTABLE(IClassFactory
) DSCF_Vtbl
= {
776 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
783 static IClassFactoryImpl DSOUND_CF
= {&DSCF_Vtbl
, 1 };
785 /*******************************************************************************
786 * DllGetClassObject [DSOUND.5]
787 * Retrieves class object from a DLL object
790 * Docs say returns STDAPI
793 * rclsid [I] CLSID for the class object
794 * riid [I] Reference to identifier of interface for class object
795 * ppv [O] Address of variable to receive interface pointer for riid
799 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
802 DWORD WINAPI
DSOUND_DllGetClassObject(REFCLSID rclsid
,REFIID riid
,LPVOID
*ppv
)
804 TRACE("(%p,%p,%p)\n", debugstr_guid(rclsid
), debugstr_guid(riid
), ppv
);
805 if ( IsEqualCLSID( &IID_IClassFactory
, riid
) ) {
806 *ppv
= (LPVOID
)&DSOUND_CF
;
807 IClassFactory_AddRef((IClassFactory
*)*ppv
);
811 FIXME("(%p,%p,%p): no interface found.\n", debugstr_guid(rclsid
), debugstr_guid(riid
), ppv
);
812 return CLASS_E_CLASSNOTAVAILABLE
;
816 /*******************************************************************************
817 * DllCanUnloadNow [DSOUND.4] Determines whether the DLL is in use.
823 DWORD WINAPI
DSOUND_DllCanUnloadNow(void)
825 FIXME("(void): stub\n");