Fixed typo.
[wine/multimedia.git] / dlls / dsound / dsound_main.c
blobbd926c9cf9fdd833b88ef7ababa0295d36d43450
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>
53 #define NONAMELESSSTRUCT
54 #define NONAMELESSUNION
55 #include "windef.h"
56 #include "winbase.h"
57 #include "winreg.h"
58 #include "winuser.h"
59 #include "wingdi.h"
60 #include "winuser.h"
61 #include "winerror.h"
62 #include "mmsystem.h"
63 #include "winternl.h"
64 #include "mmddk.h"
65 #include "wine/windef16.h"
66 #include "wine/winbase16.h"
67 #include "wine/debug.h"
68 #include "dsound.h"
69 #include "dsdriver.h"
70 #include "dsound_private.h"
71 #include "dsconf.h"
73 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
75 /* these are eligible for tuning... they must be high on slow machines... */
76 /* some stuff may get more responsive with lower values though... */
77 #define DS_EMULDRIVER 0 /* some games (Quake 2, UT) refuse to accept
78 emulated dsound devices. set to 0 ! */
79 #define DS_HEL_MARGIN 5 /* HEL only: number of waveOut fragments ahead to mix in new buffers
80 * (keep this close or equal to DS_HEL_QUEUE for best results) */
81 #define DS_HEL_QUEUE 5 /* HEL only: number of waveOut fragments ahead to queue to driver
82 * (this will affect HEL sound reliability and latency) */
84 #define DS_SND_QUEUE_MAX 28 /* max number of fragments to prebuffer */
85 #define DS_SND_QUEUE_MIN 12 /* min number of fragments to prebuffer */
87 IDirectSoundImpl* dsound = NULL;
89 HRESULT mmErr(UINT err)
91 switch(err) {
92 case MMSYSERR_NOERROR:
93 return DS_OK;
94 case MMSYSERR_ALLOCATED:
95 return DSERR_ALLOCATED;
96 case MMSYSERR_ERROR:
97 case MMSYSERR_INVALHANDLE:
98 case WAVERR_STILLPLAYING:
99 return DSERR_GENERIC; /* FIXME */
100 case MMSYSERR_NODRIVER:
101 return DSERR_NODRIVER;
102 case MMSYSERR_NOMEM:
103 return DSERR_OUTOFMEMORY;
104 case MMSYSERR_INVALPARAM:
105 case WAVERR_BADFORMAT:
106 case WAVERR_UNPREPARED:
107 return DSERR_INVALIDPARAM;
108 case MMSYSERR_NOTSUPPORTED:
109 return DSERR_UNSUPPORTED;
110 default:
111 FIXME("Unknown MMSYS error %d\n",err);
112 return DSERR_GENERIC;
116 int ds_emuldriver = DS_EMULDRIVER;
117 int ds_hel_margin = DS_HEL_MARGIN;
118 int ds_hel_queue = DS_HEL_QUEUE;
119 int ds_snd_queue_max = DS_SND_QUEUE_MAX;
120 int ds_snd_queue_min = DS_SND_QUEUE_MIN;
121 int ds_hw_accel = DS_HW_ACCEL_FULL;
122 int ds_default_playback = 0;
123 int ds_default_capture = 0;
126 * Get a config key from either the app-specific or the default config
129 inline static DWORD get_config_key( HKEY defkey, HKEY appkey, const char *name,
130 char *buffer, DWORD size )
132 if (appkey && !RegQueryValueExA( appkey, name, 0, NULL, buffer, &size )) return 0;
133 return RegQueryValueExA( defkey, name, 0, NULL, buffer, &size );
138 * Setup the dsound options.
141 void setup_dsound_options(void)
143 char buffer[MAX_PATH+1];
144 HKEY hkey, appkey = 0;
146 buffer[MAX_PATH]='\0';
148 if (RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\dsound", 0, NULL,
149 REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL ))
151 ERR("Cannot create config registry key\n" );
152 ExitProcess(1);
155 if (GetModuleFileNameA( 0, buffer, MAX_PATH ))
157 HKEY tmpkey;
159 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\AppDefaults", &tmpkey ))
161 char appname[MAX_PATH+16];
162 char *p = strrchr( buffer, '\\' );
163 if (p!=NULL) {
164 appname[MAX_PATH]='\0';
165 strncpy(appname,p+1,MAX_PATH);
166 strcat(appname,"\\dsound");
167 TRACE("appname = [%s] \n",appname);
168 if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0;
169 RegCloseKey( tmpkey );
174 /* get options */
176 if (!get_config_key( hkey, appkey, "EmulDriver", buffer, MAX_PATH ))
177 ds_emuldriver = strcmp(buffer, "N");
179 if (!get_config_key( hkey, appkey, "HELmargin", buffer, MAX_PATH ))
180 ds_hel_margin = atoi(buffer);
182 if (!get_config_key( hkey, appkey, "HELqueue", buffer, MAX_PATH ))
183 ds_hel_queue = atoi(buffer);
185 if (!get_config_key( hkey, appkey, "SndQueueMax", buffer, MAX_PATH ))
186 ds_snd_queue_max = atoi(buffer);
188 if (!get_config_key( hkey, appkey, "SndQueueMin", buffer, MAX_PATH ))
189 ds_snd_queue_min = atoi(buffer);
191 if (!get_config_key( hkey, appkey, "HardwareAcceleration", buffer, MAX_PATH )) {
192 if (strcmp(buffer, "Full") == 0)
193 ds_hw_accel = DS_HW_ACCEL_FULL;
194 else if (strcmp(buffer, "Standard") == 0)
195 ds_hw_accel = DS_HW_ACCEL_STANDARD;
196 else if (strcmp(buffer, "Basic") == 0)
197 ds_hw_accel = DS_HW_ACCEL_BASIC;
198 else if (strcmp(buffer, "Emulation") == 0)
199 ds_hw_accel = DS_HW_ACCEL_EMULATION;
202 if (!get_config_key( hkey, appkey, "DefaultPlayback", buffer, MAX_PATH ))
203 ds_default_playback = atoi(buffer);
205 if (!get_config_key( hkey, appkey, "DefaultCapture", buffer, MAX_PATH ))
206 ds_default_capture = atoi(buffer);
208 if (appkey) RegCloseKey( appkey );
209 RegCloseKey( hkey );
211 if (ds_emuldriver != DS_EMULDRIVER )
212 WARN("ds_emuldriver = %d (default=%d)\n",ds_emuldriver, DS_EMULDRIVER);
213 if (ds_hel_margin != DS_HEL_MARGIN )
214 WARN("ds_hel_margin = %d (default=%d)\n",ds_hel_margin, DS_HEL_MARGIN );
215 if (ds_hel_queue != DS_HEL_QUEUE )
216 WARN("ds_hel_queue = %d (default=%d)\n",ds_hel_queue, DS_HEL_QUEUE );
217 if (ds_snd_queue_max != DS_SND_QUEUE_MAX)
218 WARN("ds_snd_queue_max = %d (default=%d)\n",ds_snd_queue_max ,DS_SND_QUEUE_MAX);
219 if (ds_snd_queue_min != DS_SND_QUEUE_MIN)
220 WARN("ds_snd_queue_min = %d (default=%d)\n",ds_snd_queue_min ,DS_SND_QUEUE_MIN);
221 if (ds_hw_accel != DS_HW_ACCEL_FULL)
222 WARN("ds_hw_accel = %s (default=Full)\n",
223 ds_hw_accel==DS_HW_ACCEL_FULL ? "Full" :
224 ds_hw_accel==DS_HW_ACCEL_STANDARD ? "Standard" :
225 ds_hw_accel==DS_HW_ACCEL_BASIC ? "Basic" :
226 ds_hw_accel==DS_HW_ACCEL_EMULATION ? "Emulation" :
227 "Unknown");
228 if (ds_default_playback != 0)
229 WARN("ds_default_playback = %d (default=0)\n",ds_default_playback);
230 if (ds_default_capture != 0)
231 WARN("ds_default_capture = %d (default=0)\n",ds_default_playback);
236 /***************************************************************************
237 * GetDeviceID [DSOUND.9]
239 * Retrieves unique identifier of default device specified
241 * PARAMS
242 * pGuidSrc [I] Address of device GUID.
243 * pGuidDest [O] Address to receive unique device GUID.
245 * RETURNS
246 * Success: DS_OK
247 * Failure: DSERR_INVALIDPARAM
249 * NOTES
250 * pGuidSrc is a valid device GUID or DSDEVID_DefaultPlayback,
251 * DSDEVID_DefaultCapture, DSDEVID_DefaultVoicePlayback, or
252 * DSDEVID_DefaultVoiceCapture.
253 * Returns pGuidSrc if pGuidSrc is a valid device or the device
254 * GUID for the specified constants.
256 HRESULT WINAPI GetDeviceID(LPCGUID pGuidSrc, LPGUID pGuidDest)
258 TRACE("(%p,%p)\n",pGuidSrc,pGuidDest);
260 if ( pGuidSrc == NULL) {
261 WARN("invalid parameter: pGuidSrc == NULL\n");
262 return DSERR_INVALIDPARAM;
265 if ( pGuidDest == NULL ) {
266 WARN("invalid parameter: pGuidDest == NULL\n");
267 return DSERR_INVALIDPARAM;
270 if ( IsEqualGUID( &DSDEVID_DefaultPlayback, pGuidSrc ) ||
271 IsEqualGUID( &DSDEVID_DefaultVoicePlayback, pGuidSrc ) ) {
272 GUID guid;
273 int err = mmErr(waveOutMessage((HWAVEOUT)ds_default_playback,DRV_QUERYDSOUNDGUID,(DWORD)&guid,0));
274 if (err == DS_OK) {
275 memcpy(pGuidDest, &guid, sizeof(GUID));
276 return DS_OK;
280 if ( IsEqualGUID( &DSDEVID_DefaultCapture, pGuidSrc ) ||
281 IsEqualGUID( &DSDEVID_DefaultVoiceCapture, pGuidSrc ) ) {
282 GUID guid;
283 int err = mmErr(waveInMessage((HWAVEIN)ds_default_capture,DRV_QUERYDSOUNDGUID,(DWORD)&guid,0));
284 if (err == DS_OK) {
285 memcpy(pGuidDest, &guid, sizeof(GUID));
286 return DS_OK;
290 memcpy(pGuidDest, pGuidSrc, sizeof(GUID));
292 return DS_OK;
296 /***************************************************************************
297 * DirectSoundEnumerateA [DSOUND.2]
299 * Enumerate all DirectSound drivers installed in the system
301 * PARAMS
302 * lpDSEnumCallback [I] Address of callback function.
303 * lpContext [I] Address of user defined context passed to callback function.
305 * RETURNS
306 * Success: DS_OK
307 * Failure: DSERR_INVALIDPARAM
309 HRESULT WINAPI DirectSoundEnumerateA(
310 LPDSENUMCALLBACKA lpDSEnumCallback,
311 LPVOID lpContext)
313 unsigned devs, wod;
314 DSDRIVERDESC desc;
315 GUID guid;
316 int err;
318 TRACE("lpDSEnumCallback = %p, lpContext = %p\n",
319 lpDSEnumCallback, lpContext);
321 if (lpDSEnumCallback == NULL) {
322 WARN("invalid parameter: lpDSEnumCallback == NULL\n");
323 return DSERR_INVALIDPARAM;
326 devs = waveOutGetNumDevs();
327 if (devs > 0) {
328 if (GetDeviceID(&DSDEVID_DefaultPlayback, &guid) == DS_OK) {
329 GUID temp;
330 for (wod = 0; wod < devs; ++wod) {
331 err = mmErr(waveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDGUID,(DWORD)&temp,0));
332 if (err == DS_OK) {
333 if (IsEqualGUID( &guid, &temp ) ) {
334 err = mmErr(waveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDDESC,(DWORD)&desc,0));
335 if (err == DS_OK) {
336 TRACE("calling lpDSEnumCallback(%s,\"%s\",\"%s\",%p)\n",
337 debugstr_guid(&DSDEVID_DefaultPlayback),"Primary Sound Driver",desc.szDrvName,lpContext);
338 if (lpDSEnumCallback((LPGUID)&DSDEVID_DefaultPlayback, "Primary Sound Driver", desc.szDrvName, lpContext) == FALSE)
339 return DS_OK;
347 for (wod = 0; wod < devs; ++wod) {
348 err = mmErr(waveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDDESC,(DWORD)&desc,0));
349 if (err == DS_OK) {
350 err = mmErr(waveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDGUID,(DWORD)&guid,0));
351 if (err == DS_OK) {
352 TRACE("calling lpDSEnumCallback(%s,\"%s\",\"%s\",%p)\n",
353 debugstr_guid(&guid),desc.szDesc,desc.szDrvName,lpContext);
354 if (lpDSEnumCallback(&guid, desc.szDesc, desc.szDrvName, lpContext) == FALSE)
355 return DS_OK;
359 return DS_OK;
362 /***************************************************************************
363 * DirectSoundEnumerateW [DSOUND.3]
365 * Enumerate all DirectSound drivers installed in the system
367 * PARAMS
368 * lpDSEnumCallback [I] Address of callback function.
369 * lpContext [I] Address of user defined context passed to callback function.
371 * RETURNS
372 * Success: DS_OK
373 * Failure: DSERR_INVALIDPARAM
375 HRESULT WINAPI DirectSoundEnumerateW(
376 LPDSENUMCALLBACKW lpDSEnumCallback,
377 LPVOID lpContext )
379 unsigned devs, wod;
380 DSDRIVERDESC desc;
381 GUID guid;
382 int err;
383 WCHAR wDesc[MAXPNAMELEN];
384 WCHAR wName[MAXPNAMELEN];
386 TRACE("lpDSEnumCallback = %p, lpContext = %p\n",
387 lpDSEnumCallback, lpContext);
389 if (lpDSEnumCallback == NULL) {
390 WARN("invalid parameter: lpDSEnumCallback == NULL\n");
391 return DSERR_INVALIDPARAM;
394 devs = waveOutGetNumDevs();
395 if (devs > 0) {
396 if (GetDeviceID(&DSDEVID_DefaultPlayback, &guid) == DS_OK) {
397 GUID temp;
398 for (wod = 0; wod < devs; ++wod) {
399 err = mmErr(waveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDGUID,(DWORD)&temp,0));
400 if (err == DS_OK) {
401 if (IsEqualGUID( &guid, &temp ) ) {
402 err = mmErr(waveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDDESC,(DWORD)&desc,0));
403 if (err == DS_OK) {
404 TRACE("calling lpDSEnumCallback(%s,\"%s\",\"%s\",%p)\n",
405 debugstr_guid(&DSDEVID_DefaultPlayback),"Primary Sound Driver",desc.szDrvName,lpContext);
406 MultiByteToWideChar( CP_ACP, 0, "Primary Sound Driver", -1,
407 wDesc, sizeof(wDesc)/sizeof(WCHAR) );
408 MultiByteToWideChar( CP_ACP, 0, desc.szDrvName, -1,
409 wName, sizeof(wName)/sizeof(WCHAR) );
410 if (lpDSEnumCallback((LPGUID)&DSDEVID_DefaultPlayback, wDesc, wName, lpContext) == FALSE)
411 return DS_OK;
419 for (wod = 0; wod < devs; ++wod) {
420 err = mmErr(waveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDDESC,(DWORD)&desc,0));
421 if (err == DS_OK) {
422 err = mmErr(waveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDGUID,(DWORD)&guid,0));
423 if (err == DS_OK) {
424 TRACE("calling lpDSEnumCallback(%s,\"%s\",\"%s\",%p)\n",
425 debugstr_guid(&guid),desc.szDesc,desc.szDrvName,lpContext);
426 MultiByteToWideChar( CP_ACP, 0, desc.szDesc, -1,
427 wDesc, sizeof(wDesc)/sizeof(WCHAR) );
428 MultiByteToWideChar( CP_ACP, 0, desc.szDrvName, -1,
429 wName, sizeof(wName)/sizeof(WCHAR) );
430 if (lpDSEnumCallback(&guid, wDesc, wName, lpContext) == FALSE)
431 return DS_OK;
435 return DS_OK;
439 static void _dump_DSBCAPS(DWORD xmask) {
440 struct {
441 DWORD mask;
442 char *name;
443 } flags[] = {
444 #define FE(x) { x, #x },
445 FE(DSBCAPS_PRIMARYBUFFER)
446 FE(DSBCAPS_STATIC)
447 FE(DSBCAPS_LOCHARDWARE)
448 FE(DSBCAPS_LOCSOFTWARE)
449 FE(DSBCAPS_CTRL3D)
450 FE(DSBCAPS_CTRLFREQUENCY)
451 FE(DSBCAPS_CTRLPAN)
452 FE(DSBCAPS_CTRLVOLUME)
453 FE(DSBCAPS_CTRLPOSITIONNOTIFY)
454 FE(DSBCAPS_CTRLDEFAULT)
455 FE(DSBCAPS_CTRLALL)
456 FE(DSBCAPS_STICKYFOCUS)
457 FE(DSBCAPS_GLOBALFOCUS)
458 FE(DSBCAPS_GETCURRENTPOSITION2)
459 FE(DSBCAPS_MUTE3DATMAXDISTANCE)
460 #undef FE
462 int i;
464 for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
465 if ((flags[i].mask & xmask) == flags[i].mask)
466 DPRINTF("%s ",flags[i].name);
469 /*******************************************************************************
470 * IDirectSound
473 static HRESULT WINAPI IDirectSoundImpl_SetCooperativeLevel(
474 LPDIRECTSOUND8 iface,HWND hwnd,DWORD level
476 ICOM_THIS(IDirectSoundImpl,iface);
477 TRACE("(%p,%08lx,%ld)\n",This,(DWORD)hwnd,level);
479 if (level==DSSCL_PRIORITY || level==DSSCL_EXCLUSIVE) {
480 FIXME("level=%s not fully supported\n",
481 level==DSSCL_PRIORITY ? "DSSCL_PRIORITY" : "DSSCL_EXCLUSIVE");
484 This->priolevel = level;
486 return DS_OK;
489 static HRESULT WINAPI IDirectSoundImpl_CreateSoundBuffer(
490 LPDIRECTSOUND8 iface,LPDSBUFFERDESC dsbd,LPLPDIRECTSOUNDBUFFER8 ppdsb,LPUNKNOWN lpunk
492 ICOM_THIS(IDirectSoundImpl,iface);
493 LPWAVEFORMATEX wfex;
494 HRESULT hres = DS_OK;
496 TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
498 if (This == NULL) {
499 WARN("invalid parameter: This == NULL\n");
500 return DSERR_INVALIDPARAM;
503 if (dsbd == NULL) {
504 WARN("invalid parameter: dsbd == NULL\n");
505 return DSERR_INVALIDPARAM;
508 if (ppdsb == NULL) {
509 WARN("invalid parameter: ppdsb == NULL\n");
510 return DSERR_INVALIDPARAM;
513 if (TRACE_ON(dsound)) {
514 TRACE("(structsize=%ld)\n",dsbd->dwSize);
515 TRACE("(flags=0x%08lx:\n",dsbd->dwFlags);
516 _dump_DSBCAPS(dsbd->dwFlags);
517 DPRINTF(")\n");
518 TRACE("(bufferbytes=%ld)\n",dsbd->dwBufferBytes);
519 TRACE("(lpwfxFormat=%p)\n",dsbd->lpwfxFormat);
522 wfex = dsbd->lpwfxFormat;
524 if (wfex)
525 TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld,"
526 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
527 wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec,
528 wfex->nAvgBytesPerSec, wfex->nBlockAlign,
529 wfex->wBitsPerSample, wfex->cbSize);
531 if (dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) {
532 if (This->primary) {
533 WARN("Primary Buffer already created\n");
534 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(This->primary));
535 *ppdsb = (LPDIRECTSOUNDBUFFER8)(This->primary);
536 } else {
537 This->dsbd = *dsbd;
538 hres = PrimaryBufferImpl_Create(This, (PrimaryBufferImpl**)&(This->primary), &(This->dsbd));
539 if (This->primary) {
540 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(This->primary));
541 *ppdsb = (LPDIRECTSOUNDBUFFER8)(This->primary);
542 } else
543 WARN("PrimaryBufferImpl_Create failed\n");
545 } else {
546 IDirectSoundBufferImpl * dsb;
547 hres = IDirectSoundBufferImpl_Create(This, (IDirectSoundBufferImpl**)&dsb, dsbd);
548 if (dsb) {
549 hres = SecondaryBufferImpl_Create(dsb, (SecondaryBufferImpl**)ppdsb);
550 if (*ppdsb) {
551 dsb->dsb = (SecondaryBufferImpl*)*ppdsb;
552 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)*ppdsb);
553 } else
554 WARN("SecondaryBufferImpl_Create failed\n");
555 } else
556 WARN("IDirectSoundBufferImpl_Create failed\n");
559 return hres;
562 static HRESULT WINAPI IDirectSoundImpl_DuplicateSoundBuffer(
563 LPDIRECTSOUND8 iface,LPDIRECTSOUNDBUFFER8 psb,LPLPDIRECTSOUNDBUFFER8 ppdsb
565 ICOM_THIS(IDirectSoundImpl,iface);
566 IDirectSoundBufferImpl* pdsb;
567 IDirectSoundBufferImpl* dsb;
568 HRESULT hres = DS_OK;
569 TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
571 if (This == NULL) {
572 WARN("invalid parameter: This == NULL\n");
573 return DSERR_INVALIDPARAM;
576 if (psb == NULL) {
577 WARN("invalid parameter: psb == NULL\n");
578 return DSERR_INVALIDPARAM;
581 if (ppdsb == NULL) {
582 WARN("invalid parameter: ppdsb == NULL\n");
583 return DSERR_INVALIDPARAM;
586 /* FIXME: hack to make sure we have a secondary buffer */
587 if ((DWORD)((SecondaryBufferImpl *)psb)->dsb == (DWORD)This) {
588 ERR("trying to duplicate primary buffer\n");
589 *ppdsb = NULL;
590 return DSERR_INVALIDCALL;
593 pdsb = ((SecondaryBufferImpl *)psb)->dsb;
595 if (pdsb->hwbuf) {
596 FIXME("need to duplicate hardware buffer\n");
597 *ppdsb = NULL;
598 return DSERR_INVALIDCALL;
601 dsb = (IDirectSoundBufferImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb));
603 if (dsb == NULL) {
604 WARN("out of memory\n");
605 *ppdsb = NULL;
606 return DSERR_OUTOFMEMORY;
609 memcpy(dsb, pdsb, sizeof(IDirectSoundBufferImpl));
610 dsb->ref = 0;
611 dsb->state = STATE_STOPPED;
612 dsb->playpos = 0;
613 dsb->buf_mixpos = 0;
614 dsb->dsound = This;
615 dsb->buffer->ref++;
616 dsb->hwbuf = NULL;
617 dsb->ds3db = NULL;
618 dsb->iks = NULL; /* FIXME? */
619 dsb->dsb = NULL;
620 memcpy(&(dsb->wfx), &(pdsb->wfx), sizeof(dsb->wfx));
621 InitializeCriticalSection(&(dsb->lock));
622 /* register buffer */
623 RtlAcquireResourceExclusive(&(This->lock), TRUE);
625 IDirectSoundBufferImpl **newbuffers = (IDirectSoundBufferImpl**)HeapReAlloc(GetProcessHeap(),0,This->buffers,sizeof(IDirectSoundBufferImpl**)*(This->nrofbuffers+1));
626 if (newbuffers) {
627 This->buffers = newbuffers;
628 This->buffers[This->nrofbuffers] = dsb;
629 This->nrofbuffers++;
630 TRACE("buffer count is now %d\n", This->nrofbuffers);
631 } else {
632 ERR("out of memory for buffer list! Current buffer count is %d\n", This->nrofbuffers);
633 IDirectSoundBuffer8_Release(psb);
634 DeleteCriticalSection(&(dsb->lock));
635 RtlReleaseResource(&(This->lock));
636 HeapFree(GetProcessHeap(),0,dsb);
637 *ppdsb = 0;
638 return DSERR_OUTOFMEMORY;
641 RtlReleaseResource(&(This->lock));
642 IDirectSound_AddRef(iface);
643 hres = SecondaryBufferImpl_Create(dsb, (SecondaryBufferImpl**)ppdsb);
644 if (*ppdsb) {
645 dsb->dsb = (SecondaryBufferImpl*)*ppdsb;
646 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)*ppdsb);
647 } else
648 WARN("SecondaryBufferImpl_Create failed\n");
650 return hres;
653 static HRESULT WINAPI IDirectSoundImpl_GetCaps(LPDIRECTSOUND8 iface,LPDSCAPS lpDSCaps) {
654 ICOM_THIS(IDirectSoundImpl,iface);
655 TRACE("(%p,%p)\n",This,lpDSCaps);
657 if (This == NULL) {
658 WARN("invalid parameter: This == NULL\n");
659 return DSERR_INVALIDPARAM;
662 if (lpDSCaps == NULL) {
663 WARN("invalid parameter: lpDSCaps = NULL\n");
664 return DSERR_INVALIDPARAM;
667 /* check is there is enough room */
668 if (lpDSCaps->dwSize < sizeof(*lpDSCaps)) {
669 WARN("invalid parameter: lpDSCaps->dwSize = %ld < %d\n",
670 lpDSCaps->dwSize, sizeof(*lpDSCaps));
671 return DSERR_INVALIDPARAM;
674 lpDSCaps->dwFlags = This->drvcaps.dwFlags;
675 TRACE("(flags=0x%08lx)\n",lpDSCaps->dwFlags);
677 /* FIXME: copy caps from This->drv */
678 lpDSCaps->dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
679 lpDSCaps->dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
681 lpDSCaps->dwPrimaryBuffers = 1;
683 lpDSCaps->dwMaxHwMixingAllBuffers = 0;
684 lpDSCaps->dwMaxHwMixingStaticBuffers = 0;
685 lpDSCaps->dwMaxHwMixingStreamingBuffers = 0;
687 lpDSCaps->dwFreeHwMixingAllBuffers = 0;
688 lpDSCaps->dwFreeHwMixingStaticBuffers = 0;
689 lpDSCaps->dwFreeHwMixingStreamingBuffers = 0;
691 lpDSCaps->dwMaxHw3DAllBuffers = 0;
692 lpDSCaps->dwMaxHw3DStaticBuffers = 0;
693 lpDSCaps->dwMaxHw3DStreamingBuffers = 0;
695 lpDSCaps->dwFreeHw3DAllBuffers = 0;
696 lpDSCaps->dwFreeHw3DStaticBuffers = 0;
697 lpDSCaps->dwFreeHw3DStreamingBuffers = 0;
699 lpDSCaps->dwTotalHwMemBytes = 0;
701 lpDSCaps->dwFreeHwMemBytes = 0;
703 lpDSCaps->dwMaxContigFreeHwMemBytes = 0;
705 lpDSCaps->dwUnlockTransferRateHwBuffers = 4096; /* But we have none... */
707 lpDSCaps->dwPlayCpuOverheadSwBuffers = 1; /* 1% */
709 return DS_OK;
712 static ULONG WINAPI IDirectSoundImpl_AddRef(LPDIRECTSOUND8 iface) {
713 ICOM_THIS(IDirectSoundImpl,iface);
714 TRACE("(%p) ref was %ld, thread is %04lx\n", This, This->ref, GetCurrentThreadId());
715 return InterlockedIncrement(&This->ref);
718 static ULONG WINAPI IDirectSoundImpl_Release(LPDIRECTSOUND8 iface) {
719 ICOM_THIS(IDirectSoundImpl,iface);
720 ULONG ulReturn;
722 TRACE("(%p) ref was %ld, thread is %04lx\n", This, This->ref, GetCurrentThreadId());
723 ulReturn = InterlockedDecrement(&This->ref);
724 if (ulReturn == 0) {
725 HRESULT hres;
726 UINT i;
728 timeKillEvent(This->timerID);
729 timeEndPeriod(DS_TIME_RES);
730 /* wait for timer to expire */
731 Sleep(DS_TIME_RES+1);
733 RtlAcquireResourceShared(&(This->lock), TRUE);
735 if (This->buffers) {
736 for( i=0;i<This->nrofbuffers;i++)
737 IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)This->buffers[i]);
740 RtlReleaseResource(&(This->lock));
742 if (This->primary) {
743 WARN("primary buffer not released\n");
744 IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)This->primary);
747 hres = DSOUND_PrimaryDestroy(This);
748 if (hres != DS_OK)
749 WARN("DSOUND_PrimaryDestroy failed\n");
751 if (This->driver)
752 IDsDriver_Close(This->driver);
754 if (This->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN)
755 waveOutClose(This->hwo);
757 if (This->driver)
758 IDsDriver_Release(This->driver);
760 RtlDeleteResource(&This->lock);
761 DeleteCriticalSection(&This->mixlock);
762 DeleteCriticalSection(&This->ds3dl_lock);
763 HeapFree(GetProcessHeap(),0,This);
764 dsound = NULL;
765 TRACE("(%p) released\n",This);
768 return ulReturn;
771 static HRESULT WINAPI IDirectSoundImpl_SetSpeakerConfig(
772 LPDIRECTSOUND8 iface,DWORD config
774 ICOM_THIS(IDirectSoundImpl,iface);
775 TRACE("(%p,0x%08lx)\n",This,config);
777 This->speaker_config = config;
779 WARN("not fully functional\n");
780 return DS_OK;
783 static HRESULT WINAPI IDirectSoundImpl_QueryInterface(
784 LPDIRECTSOUND8 iface,REFIID riid,LPVOID *ppobj
786 ICOM_THIS(IDirectSoundImpl,iface);
787 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
789 if (ppobj == NULL) {
790 WARN("invalid parameter\n");
791 return E_INVALIDARG;
794 *ppobj = NULL; /* assume failure */
796 if ( IsEqualGUID(riid, &IID_IUnknown) ||
797 IsEqualGUID(riid, &IID_IDirectSound) ||
798 IsEqualGUID(riid, &IID_IDirectSound8) ) {
799 IDirectSound8_AddRef((LPDIRECTSOUND8)This);
800 *ppobj = This;
801 return S_OK;
804 if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
805 WARN("app requested IDirectSound3DListener on dsound object\n");
806 return E_NOINTERFACE;
809 FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
810 return E_NOINTERFACE;
813 static HRESULT WINAPI IDirectSoundImpl_Compact(
814 LPDIRECTSOUND8 iface)
816 ICOM_THIS(IDirectSoundImpl,iface);
817 TRACE("(%p)\n", This);
818 return DS_OK;
821 static HRESULT WINAPI IDirectSoundImpl_GetSpeakerConfig(
822 LPDIRECTSOUND8 iface,
823 LPDWORD lpdwSpeakerConfig)
825 ICOM_THIS(IDirectSoundImpl,iface);
826 TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
828 if (lpdwSpeakerConfig == NULL) {
829 WARN("invalid parameter\n");
830 return DSERR_INVALIDPARAM;
833 WARN("not fully functional\n");
835 *lpdwSpeakerConfig = This->speaker_config;
837 return DS_OK;
840 static HRESULT WINAPI IDirectSoundImpl_Initialize(
841 LPDIRECTSOUND8 iface,
842 LPCGUID lpcGuid)
844 ICOM_THIS(IDirectSoundImpl,iface);
845 TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
846 return DS_OK;
849 static HRESULT WINAPI IDirectSoundImpl_VerifyCertification(
850 LPDIRECTSOUND8 iface,
851 LPDWORD pdwCertified)
853 ICOM_THIS(IDirectSoundImpl,iface);
854 TRACE("(%p, %p)\n", This, pdwCertified);
855 *pdwCertified = DS_CERTIFIED;
856 return DS_OK;
859 static ICOM_VTABLE(IDirectSound8) dsvt =
861 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
862 IDirectSoundImpl_QueryInterface,
863 IDirectSoundImpl_AddRef,
864 IDirectSoundImpl_Release,
865 IDirectSoundImpl_CreateSoundBuffer,
866 IDirectSoundImpl_GetCaps,
867 IDirectSoundImpl_DuplicateSoundBuffer,
868 IDirectSoundImpl_SetCooperativeLevel,
869 IDirectSoundImpl_Compact,
870 IDirectSoundImpl_GetSpeakerConfig,
871 IDirectSoundImpl_SetSpeakerConfig,
872 IDirectSoundImpl_Initialize,
873 IDirectSoundImpl_VerifyCertification
877 /*******************************************************************************
878 * DirectSoundCreate (DSOUND.1)
880 * Creates and initializes a DirectSound interface.
882 * PARAMS
883 * lpcGUID [I] Address of the GUID that identifies the sound device.
884 * ppDS [O] Address of a variable to receive the interface pointer.
885 * pUnkOuter [I] Must be NULL.
887 * RETURNS
888 * Success: DS_OK
889 * Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
890 * DSERR_NODRIVER, DSERR_OUTOFMEMORY
892 HRESULT WINAPI DirectSoundCreate8(LPCGUID lpcGUID,LPDIRECTSOUND8 *ppDS,IUnknown *pUnkOuter )
894 IDirectSoundImpl** ippDS=(IDirectSoundImpl**)ppDS;
895 PIDSDRIVER drv = NULL;
896 unsigned wod, wodn;
897 HRESULT err = DSERR_INVALIDPARAM;
898 GUID devGuid;
899 BOOLEAN found = FALSE;
901 TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ippDS,pUnkOuter);
903 if (ippDS == NULL) {
904 WARN("invalid parameter: ippDS == NULL\n");
905 return DSERR_INVALIDPARAM;
908 /* Get dsound configuration */
909 setup_dsound_options();
911 /* Default device? */
912 if (!lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL))
913 lpcGUID = &DSDEVID_DefaultPlayback;
915 if (GetDeviceID(lpcGUID, &devGuid) != DS_OK) {
916 WARN("invalid parameter: lpcGUID\n");
917 *ippDS = NULL;
918 return DSERR_INVALIDPARAM;
921 if (dsound) {
922 if (IsEqualGUID(&devGuid, &dsound->guid) ) {
923 /* FIXME: this is wrong, need to create a new instance */
924 ERR("dsound already opened\n");
925 IDirectSound_AddRef((LPDIRECTSOUND)dsound);
926 *ippDS = dsound;
927 return DS_OK;
928 } else {
929 ERR("different dsound already opened\n");
933 /* Enumerate WINMM audio devices and find the one we want */
934 wodn = waveOutGetNumDevs();
935 if (!wodn) {
936 WARN("no driver\n");
937 *ippDS = NULL;
938 return DSERR_NODRIVER;
941 TRACE(" expecting GUID %s.\n", debugstr_guid(&devGuid));
943 for (wod=0; wod<wodn; wod++) {
944 GUID guid;
945 err = mmErr(waveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDGUID,(DWORD)(&guid),0));
946 if (err != DS_OK) {
947 WARN("waveOutMessage failed; err=%lx\n",err);
948 *ippDS = NULL;
949 return err;
951 TRACE("got GUID %s for wod %d.\n", debugstr_guid(&guid), wod);
952 if (IsEqualGUID( &devGuid, &guid) ) {
953 err = DS_OK;
954 found = TRUE;
955 break;
959 if (err != DS_OK) {
960 WARN("invalid parameter\n");
961 *ippDS = NULL;
962 return DSERR_INVALIDPARAM;
965 if (found == FALSE) {
966 WARN("No device found matching given ID - trying with default one !\n");
967 wod = ds_default_playback;
970 /* DRV_QUERYDSOUNDIFACE is a "Wine extension" to get the DSound interface */
971 waveOutMessage((HWAVEOUT)wod, DRV_QUERYDSOUNDIFACE, (DWORD)&drv, 0);
973 /* Disable the direct sound driver to force emulation if requested. */
974 if (ds_hw_accel == DS_HW_ACCEL_EMULATION)
975 drv = NULL;
977 /* Allocate memory */
978 *ippDS = (IDirectSoundImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundImpl));
979 if (*ippDS == NULL) {
980 WARN("out of memory\n");
981 return DSERR_OUTOFMEMORY;
984 (*ippDS)->lpVtbl = &dsvt;
985 (*ippDS)->ref = 1;
987 (*ippDS)->driver = drv;
988 (*ippDS)->priolevel = DSSCL_NORMAL;
989 (*ippDS)->fraglen = 0;
990 (*ippDS)->hwbuf = NULL;
991 (*ippDS)->buffer = NULL;
992 (*ippDS)->buflen = 0;
993 (*ippDS)->writelead = 0;
994 (*ippDS)->state = STATE_STOPPED;
995 (*ippDS)->nrofbuffers = 0;
996 (*ippDS)->buffers = NULL;
997 (*ippDS)->primary = NULL;
998 (*ippDS)->speaker_config = DSSPEAKER_STEREO | (DSSPEAKER_GEOMETRY_NARROW << 16);
1000 /* 3D listener initial parameters */
1001 (*ippDS)->listener = NULL;
1002 (*ippDS)->ds3dl.dwSize = sizeof(DS3DLISTENER);
1003 (*ippDS)->ds3dl.vPosition.u1.x = 0.0;
1004 (*ippDS)->ds3dl.vPosition.u2.y = 0.0;
1005 (*ippDS)->ds3dl.vPosition.u3.z = 0.0;
1006 (*ippDS)->ds3dl.vVelocity.u1.x = 0.0;
1007 (*ippDS)->ds3dl.vVelocity.u2.y = 0.0;
1008 (*ippDS)->ds3dl.vVelocity.u3.z = 0.0;
1009 (*ippDS)->ds3dl.vOrientFront.u1.x = 0.0;
1010 (*ippDS)->ds3dl.vOrientFront.u2.y = 0.0;
1011 (*ippDS)->ds3dl.vOrientFront.u3.z = 1.0;
1012 (*ippDS)->ds3dl.vOrientTop.u1.x = 0.0;
1013 (*ippDS)->ds3dl.vOrientTop.u2.y = 1.0;
1014 (*ippDS)->ds3dl.vOrientTop.u3.z = 0.0;
1015 (*ippDS)->ds3dl.flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
1016 (*ippDS)->ds3dl.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
1017 (*ippDS)->ds3dl.flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
1019 InitializeCriticalSection(&(*ippDS)->ds3dl_lock);
1021 (*ippDS)->prebuf = ds_snd_queue_max;
1022 (*ippDS)->guid = devGuid;
1024 /* Get driver description */
1025 if (drv) {
1026 err = IDsDriver_GetDriverDesc(drv,&((*ippDS)->drvdesc));
1027 if (err != DS_OK) {
1028 WARN("IDsDriver_GetDriverDesc failed\n");
1029 HeapFree(GetProcessHeap(),0,*ippDS);
1030 *ippDS = NULL;
1031 return err;
1033 } else {
1034 /* if no DirectSound interface available, use WINMM API instead */
1035 (*ippDS)->drvdesc.dwFlags = DSDDESC_DOMMSYSTEMOPEN | DSDDESC_DOMMSYSTEMSETFORMAT;
1038 (*ippDS)->drvdesc.dnDevNode = wod;
1040 /* Set default wave format (may need it for waveOutOpen) */
1041 (*ippDS)->wfx.wFormatTag = WAVE_FORMAT_PCM;
1042 /* We rely on the sound driver to return the actual sound format of
1043 * the device if it does not support 22050x8x2 and is given the
1044 * WAVE_DIRECTSOUND flag.
1046 (*ippDS)->wfx.nSamplesPerSec = 22050;
1047 (*ippDS)->wfx.wBitsPerSample = 8;
1048 (*ippDS)->wfx.nChannels = 2;
1049 (*ippDS)->wfx.nBlockAlign = (*ippDS)->wfx.wBitsPerSample * (*ippDS)->wfx.nChannels / 8;
1050 (*ippDS)->wfx.nAvgBytesPerSec = (*ippDS)->wfx.nSamplesPerSec * (*ippDS)->wfx.nBlockAlign;
1051 (*ippDS)->wfx.cbSize = 0;
1053 /* If the driver requests being opened through MMSYSTEM
1054 * (which is recommended by the DDK), it is supposed to happen
1055 * before the DirectSound interface is opened */
1056 if ((*ippDS)->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN)
1058 DWORD flags = CALLBACK_FUNCTION;
1060 /* disable direct sound if requested */
1061 if (ds_hw_accel != DS_HW_ACCEL_EMULATION)
1062 flags |= WAVE_DIRECTSOUND;
1064 err = mmErr(waveOutOpen(&((*ippDS)->hwo),
1065 (*ippDS)->drvdesc.dnDevNode, &((*ippDS)->wfx),
1066 (DWORD)DSOUND_callback, (DWORD)(*ippDS),
1067 flags));
1068 if (err != DS_OK) {
1069 WARN("waveOutOpen failed\n");
1070 HeapFree(GetProcessHeap(),0,*ippDS);
1071 *ippDS = NULL;
1072 return err;
1076 if (drv) {
1077 err = IDsDriver_Open(drv);
1078 if (err != DS_OK) {
1079 WARN("IDsDriver_Open failed\n");
1080 HeapFree(GetProcessHeap(),0,*ippDS);
1081 *ippDS = NULL;
1082 return err;
1085 /* the driver is now open, so it's now allowed to call GetCaps */
1086 err = IDsDriver_GetCaps(drv,&((*ippDS)->drvcaps));
1087 if (err != DS_OK) {
1088 WARN("IDsDriver_GetCaps failed\n");
1089 HeapFree(GetProcessHeap(),0,*ippDS);
1090 *ippDS = NULL;
1091 return err;
1093 } else {
1094 WAVEOUTCAPSA woc;
1095 err = mmErr(waveOutGetDevCapsA((*ippDS)->drvdesc.dnDevNode, &woc, sizeof(woc)));
1096 if (err != DS_OK) {
1097 WARN("waveOutGetDevCaps failed\n");
1098 HeapFree(GetProcessHeap(),0,*ippDS);
1099 *ippDS = NULL;
1100 return err;
1102 (*ippDS)->drvcaps.dwFlags = 0;
1103 if ((woc.dwFormats & WAVE_FORMAT_1M08) ||
1104 (woc.dwFormats & WAVE_FORMAT_2M08) ||
1105 (woc.dwFormats & WAVE_FORMAT_4M08) ||
1106 (woc.dwFormats & WAVE_FORMAT_48M08) ||
1107 (woc.dwFormats & WAVE_FORMAT_96M08)) {
1108 (*ippDS)->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT;
1109 (*ippDS)->drvcaps.dwFlags |= DSCAPS_PRIMARYMONO;
1111 if ((woc.dwFormats & WAVE_FORMAT_1M16) ||
1112 (woc.dwFormats & WAVE_FORMAT_2M16) ||
1113 (woc.dwFormats & WAVE_FORMAT_4M16) ||
1114 (woc.dwFormats & WAVE_FORMAT_48M16) ||
1115 (woc.dwFormats & WAVE_FORMAT_96M16)) {
1116 (*ippDS)->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT;
1117 (*ippDS)->drvcaps.dwFlags |= DSCAPS_PRIMARYMONO;
1119 if ((woc.dwFormats & WAVE_FORMAT_1S08) ||
1120 (woc.dwFormats & WAVE_FORMAT_2S08) ||
1121 (woc.dwFormats & WAVE_FORMAT_4S08) ||
1122 (woc.dwFormats & WAVE_FORMAT_48S08) ||
1123 (woc.dwFormats & WAVE_FORMAT_96S08)) {
1124 (*ippDS)->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT;
1125 (*ippDS)->drvcaps.dwFlags |= DSCAPS_PRIMARYSTEREO;
1127 if ((woc.dwFormats & WAVE_FORMAT_1S16) ||
1128 (woc.dwFormats & WAVE_FORMAT_2S16) ||
1129 (woc.dwFormats & WAVE_FORMAT_4S16) ||
1130 (woc.dwFormats & WAVE_FORMAT_48S16) ||
1131 (woc.dwFormats & WAVE_FORMAT_96S16)) {
1132 (*ippDS)->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT;
1133 (*ippDS)->drvcaps.dwFlags |= DSCAPS_PRIMARYSTEREO;
1135 if (ds_emuldriver)
1136 (*ippDS)->drvcaps.dwFlags |= DSCAPS_EMULDRIVER;
1139 DSOUND_RecalcVolPan(&((*ippDS)->volpan));
1141 InitializeCriticalSection(&((*ippDS)->mixlock));
1142 RtlInitializeResource(&((*ippDS)->lock));
1144 if (!dsound) {
1145 HRESULT hres;
1146 dsound = (*ippDS);
1147 hres = DSOUND_PrimaryCreate(dsound);
1148 if (hres != DS_OK) {
1149 WARN("DSOUND_PrimaryCreate failed\n");
1150 return hres;
1152 timeBeginPeriod(DS_TIME_RES);
1153 dsound->timerID = timeSetEvent(DS_TIME_DEL, DS_TIME_RES, DSOUND_timer,
1154 (DWORD)dsound, TIME_PERIODIC | TIME_CALLBACK_FUNCTION);
1157 return DS_OK;
1161 /*******************************************************************************
1162 * DirectSound ClassFactory
1165 static HRESULT WINAPI
1166 DSCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
1167 ICOM_THIS(IClassFactoryImpl,iface);
1169 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
1170 return E_NOINTERFACE;
1173 static ULONG WINAPI
1174 DSCF_AddRef(LPCLASSFACTORY iface) {
1175 ICOM_THIS(IClassFactoryImpl,iface);
1176 TRACE("(%p) ref was %ld\n", This, This->ref);
1177 return ++(This->ref);
1180 static ULONG WINAPI DSCF_Release(LPCLASSFACTORY iface) {
1181 ICOM_THIS(IClassFactoryImpl,iface);
1182 /* static class, won't be freed */
1183 TRACE("(%p) ref was %ld\n", This, This->ref);
1184 return --(This->ref);
1187 static HRESULT WINAPI DSCF_CreateInstance(
1188 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
1190 ICOM_THIS(IClassFactoryImpl,iface);
1191 TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
1193 if (ppobj == NULL) {
1194 WARN("invalid parameter\n");
1195 return DSERR_INVALIDPARAM;
1198 *ppobj = NULL;
1200 if ( IsEqualGUID( &IID_IDirectSound, riid ) ||
1201 IsEqualGUID( &IID_IDirectSound8, riid ) ) {
1202 /* FIXME: reuse already created dsound if present? */
1203 return DirectSoundCreate8(0,(LPDIRECTSOUND8*)ppobj,pOuter);
1206 WARN("(%p,%p,%s,%p) Interface not found!\n",This,pOuter,debugstr_guid(riid),ppobj);
1207 return E_NOINTERFACE;
1210 static HRESULT WINAPI DSCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
1211 ICOM_THIS(IClassFactoryImpl,iface);
1212 FIXME("(%p)->(%d),stub!\n",This,dolock);
1213 return S_OK;
1216 static ICOM_VTABLE(IClassFactory) DSCF_Vtbl = {
1217 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1218 DSCF_QueryInterface,
1219 DSCF_AddRef,
1220 DSCF_Release,
1221 DSCF_CreateInstance,
1222 DSCF_LockServer
1225 static IClassFactoryImpl DSOUND_CF = { &DSCF_Vtbl, 1 };
1227 /*******************************************************************************
1228 * DirectSoundPrivate ClassFactory
1231 static HRESULT WINAPI
1232 DSPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
1233 ICOM_THIS(IClassFactoryImpl,iface);
1235 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
1236 return E_NOINTERFACE;
1239 static ULONG WINAPI
1240 DSPCF_AddRef(LPCLASSFACTORY iface) {
1241 ICOM_THIS(IClassFactoryImpl,iface);
1242 TRACE("(%p) ref was %ld\n", This, This->ref);
1243 return ++(This->ref);
1246 static ULONG WINAPI
1247 DSPCF_Release(LPCLASSFACTORY iface) {
1248 ICOM_THIS(IClassFactoryImpl,iface);
1249 /* static class, won't be freed */
1250 TRACE("(%p) ref was %ld\n", This, This->ref);
1251 return --(This->ref);
1254 static HRESULT WINAPI
1255 DSPCF_CreateInstance(
1256 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
1258 ICOM_THIS(IClassFactoryImpl,iface);
1259 TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
1261 if (ppobj == NULL) {
1262 WARN("invalid parameter\n");
1263 return DSERR_INVALIDPARAM;
1266 *ppobj = NULL;
1268 if ( IsEqualGUID( &IID_IKsPropertySet, riid ) ) {
1269 return IKsPrivatePropertySetImpl_Create((IKsPrivatePropertySetImpl**)ppobj);
1272 WARN("(%p,%p,%s,%p) Interface not found!\n",This,pOuter,debugstr_guid(riid),ppobj);
1273 return E_NOINTERFACE;
1276 static HRESULT WINAPI
1277 DSPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
1278 ICOM_THIS(IClassFactoryImpl,iface);
1279 FIXME("(%p)->(%d),stub!\n",This,dolock);
1280 return S_OK;
1283 static ICOM_VTABLE(IClassFactory) DSPCF_Vtbl = {
1284 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1285 DSPCF_QueryInterface,
1286 DSPCF_AddRef,
1287 DSPCF_Release,
1288 DSPCF_CreateInstance,
1289 DSPCF_LockServer
1292 static IClassFactoryImpl DSOUND_PRIVATE_CF = { &DSPCF_Vtbl, 1 };
1294 /*******************************************************************************
1295 * DllGetClassObject [DSOUND.5]
1296 * Retrieves class object from a DLL object
1298 * NOTES
1299 * Docs say returns STDAPI
1301 * PARAMS
1302 * rclsid [I] CLSID for the class object
1303 * riid [I] Reference to identifier of interface for class object
1304 * ppv [O] Address of variable to receive interface pointer for riid
1306 * RETURNS
1307 * Success: S_OK
1308 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
1309 * E_UNEXPECTED
1311 DWORD WINAPI DSOUND_DllGetClassObject(REFCLSID rclsid,REFIID riid,LPVOID *ppv)
1313 TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
1315 if (ppv == NULL) {
1316 WARN("invalid parameter\n");
1317 return E_INVALIDARG;
1320 *ppv = NULL;
1322 if ( IsEqualCLSID( &CLSID_DirectSound, rclsid ) ||
1323 IsEqualCLSID( &CLSID_DirectSound8, rclsid ) ) {
1324 if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) {
1325 *ppv = (LPVOID)&DSOUND_CF;
1326 IClassFactory_AddRef((IClassFactory*)*ppv);
1327 return S_OK;
1329 WARN("(%s,%s,%p): no interface found.\n",
1330 debugstr_guid(rclsid), debugstr_guid(riid), ppv);
1331 return S_FALSE;
1334 if ( IsEqualCLSID( &CLSID_DirectSoundCapture, rclsid ) ||
1335 IsEqualCLSID( &CLSID_DirectSoundCapture8, rclsid ) ) {
1336 if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) {
1337 *ppv = (LPVOID)&DSOUND_CAPTURE_CF;
1338 IClassFactory_AddRef((IClassFactory*)*ppv);
1339 return S_OK;
1341 WARN("(%s,%s,%p): no interface found.\n",
1342 debugstr_guid(rclsid), debugstr_guid(riid), ppv);
1343 return S_FALSE;
1346 if ( IsEqualCLSID( &CLSID_DirectSoundFullDuplex, rclsid ) ) {
1347 if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) {
1348 *ppv = (LPVOID)&DSOUND_FULLDUPLEX_CF;
1349 IClassFactory_AddRef((IClassFactory*)*ppv);
1350 return S_OK;
1352 WARN("(%s,%s,%p): no interface found.\n",
1353 debugstr_guid(rclsid), debugstr_guid(riid), ppv);
1354 return S_FALSE;
1357 if ( IsEqualCLSID( &CLSID_DirectSoundPrivate, rclsid ) ) {
1358 if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) {
1359 *ppv = (LPVOID)&DSOUND_PRIVATE_CF;
1360 IClassFactory_AddRef((IClassFactory*)*ppv);
1361 return S_OK;
1363 WARN("(%s,%s,%p): no interface found.\n",
1364 debugstr_guid(rclsid), debugstr_guid(riid), ppv);
1365 return S_FALSE;
1368 WARN("(%s,%s,%p): no class found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
1369 return CLASS_E_CLASSNOTAVAILABLE;
1373 /*******************************************************************************
1374 * DllCanUnloadNow [DSOUND.4]
1375 * Determines whether the DLL is in use.
1377 * RETURNS
1378 * Success: S_OK
1379 * Failure: S_FALSE
1381 DWORD WINAPI DSOUND_DllCanUnloadNow(void)
1383 FIXME("(void): stub\n");
1384 return S_FALSE;