Converted implementation of _stat and _fstat to _stati64 and
[wine/multimedia.git] / dlls / dsound / dsound_main.c
blobaa07b8cc71289a086e471d05e2cd2650bf8cb85c
1 /* DirectSound
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+.
28 * TODO:
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
39 #include "config.h"
40 #include "wine/port.h"
42 #include <assert.h>
43 #include <stdio.h>
44 #include <sys/types.h>
45 #include <sys/fcntl.h>
46 #ifdef HAVE_UNISTD_H
47 # include <unistd.h>
48 #endif
49 #include <stdlib.h>
50 #include <string.h>
51 #include <math.h> /* Insomnia - pow() function */
53 #include "windef.h"
54 #include "winbase.h"
55 #include "winreg.h"
56 #include "winuser.h"
57 #include "wingdi.h"
58 #include "winuser.h"
59 #include "winerror.h"
60 #include "mmsystem.h"
61 #include "winternl.h"
62 #include "mmddk.h"
63 #include "wine/windef16.h"
64 #include "wine/winbase16.h"
65 #include "wine/debug.h"
66 #include "dsound.h"
67 #include "dsdriver.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)
88 switch(err) {
89 case MMSYSERR_NOERROR:
90 return DS_OK;
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;
97 case MMSYSERR_NOMEM:
98 return DSERR_OUTOFMEMORY;
99 case MMSYSERR_INVALPARAM:
100 return DSERR_INVALIDPARAM;
101 default:
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,
118 LPVOID lpContext)
120 if (lpDSEnumCallback != NULL)
121 if (lpDSEnumCallback(NULL, "Primary DirectSound Driver",
122 "sound", lpContext))
123 lpDSEnumCallback((LPGUID)&DSDEVID_WinePlayback,
124 "WINE DirectSound", "sound",
125 lpContext);
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" );
156 ExitProcess(1);
159 if (GetModuleFileNameA( 0, buffer, MAX_PATH ))
161 HKEY tmpkey;
163 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\AppDefaults", &tmpkey ))
165 char appname[MAX_PATH+16];
166 char *p = strrchr( buffer, '\\' );
167 if (p!=NULL) {
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 );
178 /* get options */
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 );
196 RegCloseKey( hkey );
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
218 * RETURNS
219 * Success: DS_OK
220 * Failure: DSERR_INVALIDPARAM
222 HRESULT WINAPI DirectSoundEnumerateA(
223 LPDSENUMCALLBACKA lpDSEnumCallback,
224 LPVOID lpContext)
226 WAVEOUTCAPSA wcaps;
227 unsigned devs, wod;
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);
238 return DS_OK;
241 return DS_OK;
244 /***************************************************************************
245 * DirectSoundEnumerateW [DSOUND.3]
247 * Enumerate all DirectSound drivers installed in the system
249 * RETURNS
250 * Success: DS_OK
251 * Failure: DSERR_INVALIDPARAM
253 HRESULT WINAPI DirectSoundEnumerateW(
254 LPDSENUMCALLBACKW lpDSEnumCallback,
255 LPVOID lpContext )
257 FIXME("lpDSEnumCallback = %p, lpContext = %p: stub\n",
258 lpDSEnumCallback, lpContext);
260 return DS_OK;
264 static void _dump_DSBCAPS(DWORD xmask) {
265 struct {
266 DWORD mask;
267 char *name;
268 } flags[] = {
269 #define FE(x) { x, #x },
270 FE(DSBCAPS_PRIMARYBUFFER)
271 FE(DSBCAPS_STATIC)
272 FE(DSBCAPS_LOCHARDWARE)
273 FE(DSBCAPS_LOCSOFTWARE)
274 FE(DSBCAPS_CTRL3D)
275 FE(DSBCAPS_CTRLFREQUENCY)
276 FE(DSBCAPS_CTRLPAN)
277 FE(DSBCAPS_CTRLVOLUME)
278 FE(DSBCAPS_CTRLPOSITIONNOTIFY)
279 FE(DSBCAPS_CTRLDEFAULT)
280 FE(DSBCAPS_CTRLALL)
281 FE(DSBCAPS_STICKYFOCUS)
282 FE(DSBCAPS_GLOBALFOCUS)
283 FE(DSBCAPS_GETCURRENTPOSITION2)
284 FE(DSBCAPS_MUTE3DATMAXDISTANCE)
285 #undef FE
287 int i;
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 /*******************************************************************************
295 * IDirectSound
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;
307 return DS_OK;
310 static HRESULT WINAPI IDirectSoundImpl_CreateSoundBuffer(
311 LPDIRECTSOUND8 iface,LPDSBUFFERDESC dsbd,LPLPDIRECTSOUNDBUFFER8 ppdsb,LPUNKNOWN lpunk
313 ICOM_THIS(IDirectSoundImpl,iface);
314 LPWAVEFORMATEX wfex;
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);
325 DPRINTF(")\n");
326 TRACE("(bufferbytes=%ld)\n",dsbd->dwBufferBytes);
327 TRACE("(lpwfxFormat=%p)\n",dsbd->lpwfxFormat);
330 wfex = dsbd->lpwfxFormat;
332 if (wfex)
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);
341 else
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;
358 if (ipdsb->hwbuf) {
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));
370 (*ippdsb)->ref = 1;
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));
385 if (newbuffers) {
386 This->buffers = newbuffers;
387 This->buffers[This->nrofbuffers] = *ippdsb;
388 This->nrofbuffers++;
389 TRACE("buffer count is now %d\n", This->nrofbuffers);
390 } else {
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);
397 return DS_OK;
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);
406 if (caps == NULL)
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% */
446 return DS_OK;
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)) {
458 UINT i;
460 timeKillEvent(This->timerID);
461 timeEndPeriod(DS_TIME_RES);
463 if (This->buffers) {
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);
472 if (This->driver) {
473 IDsDriver_Close(This->driver);
474 } else {
475 unsigned c;
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);
482 if (This->driver)
483 IDsDriver_Release(This->driver);
485 HeapFree(GetProcessHeap(),0,This);
486 dsound = NULL;
487 return 0;
489 return This->ref;
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);
497 return DS_OK;
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");
507 *ppobj = NULL;
508 return E_FAIL;
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);
520 return DS_OK;
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);
530 return DS_OK;
533 static HRESULT WINAPI IDirectSoundImpl_Initialize(
534 LPDIRECTSOUND8 iface,
535 LPCGUID lpcGuid)
537 ICOM_THIS(IDirectSoundImpl,iface);
538 TRACE("(%p, %p)\n", This, lpcGuid);
539 return DS_OK;
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;
549 return DS_OK;
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;
577 WAVEOUTCAPSA wcaps;
578 unsigned wod, wodn;
579 HRESULT err = DS_OK;
581 if (lpGUID)
582 TRACE("(%p,%p,%p)\n",lpGUID,ippDS,pUnkOuter);
583 else
584 TRACE("DirectSoundCreate (%p)\n", ippDS);
586 if (ippDS == NULL)
587 return DSERR_INVALIDPARAM;
589 if (dsound) {
590 IDirectSound_AddRef((LPDIRECTSOUND)dsound);
591 *ippDS = dsound;
592 return DS_OK;
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));
612 if (*ippDS == NULL)
613 return DSERR_OUTOFMEMORY;
615 ICOM_VTBL(*ippDS) = &dsvt;
616 (*ippDS)->ref = 1;
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 */
634 if (drv) {
635 IDsDriver_GetDriverDesc(drv,&((*ippDS)->drvdesc));
636 } else {
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;
647 else
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;
654 } else {
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? */
692 if (err != DS_OK) {
693 HeapFree(GetProcessHeap(),0,*ippDS);
694 *ippDS = NULL;
695 return err;
698 /* the driver is now open, so it's now allowed to call GetCaps */
699 if (drv) {
700 IDsDriver_GetCaps(drv,&((*ippDS)->drvcaps));
701 } else {
702 unsigned c;
704 /* FIXME: look at wcaps */
705 (*ippDS)->drvcaps.dwFlags =
706 DSCAPS_PRIMARY16BIT | DSCAPS_PRIMARYSTEREO;
707 if (ds_emuldriver)
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 */
715 while (c--) {
716 HeapFree(GetProcessHeap(),0,(*ippDS)->pwave[c]);
717 waveOutClose((*ippDS)->hwo);
718 HeapFree(GetProcessHeap(),0,*ippDS);
719 *ippDS = NULL;
720 return DSERR_OUTOFMEMORY;
726 DSOUND_RecalcVolPan(&((*ippDS)->volpan));
728 InitializeCriticalSection(&((*ippDS)->mixlock));
729 RtlInitializeResource(&((*ippDS)->lock));
731 if (!dsound) {
732 dsound = (*ippDS);
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);
738 return DS_OK;
742 /*******************************************************************************
743 * DirectSound ClassFactory
745 typedef struct
747 /* IUnknown fields */
748 ICOM_VFIELD(IClassFactory);
749 DWORD ref;
750 } IClassFactoryImpl;
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;
760 static ULONG WINAPI
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);
789 return S_OK;
792 static ICOM_VTABLE(IClassFactory) DSCF_Vtbl = {
793 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
794 DSCF_QueryInterface,
795 DSCF_AddRef,
796 DSCF_Release,
797 DSCF_CreateInstance,
798 DSCF_LockServer
800 static IClassFactoryImpl DSOUND_CF = {&DSCF_Vtbl, 1 };
802 /*******************************************************************************
803 * DllGetClassObject [DSOUND.5]
804 * Retrieves class object from a DLL object
806 * NOTES
807 * Docs say returns STDAPI
809 * PARAMS
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
814 * RETURNS
815 * Success: S_OK
816 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
817 * E_UNEXPECTED
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);
825 return S_OK;
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.
836 * RETURNS
837 * Success: S_OK
838 * Failure: S_FALSE
840 DWORD WINAPI DSOUND_DllCanUnloadNow(void)
842 FIXME("(void): stub\n");
843 return S_FALSE;