Fixes support for older versions of direct sound.
[wine.git] / dlls / dsound / dsound_main.c
blobbdf9dda38c1c455619a69ea4d94e5a7af7f4f540
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 <stdarg.h>
44 #include <stdio.h>
45 #include <sys/types.h>
46 #include <sys/fcntl.h>
47 #ifdef HAVE_UNISTD_H
48 # include <unistd.h>
49 #endif
50 #include <stdlib.h>
51 #include <string.h>
52 #include <math.h>
54 #define NONAMELESSSTRUCT
55 #define NONAMELESSUNION
56 #include "windef.h"
57 #include "winbase.h"
58 #include "winreg.h"
59 #include "winuser.h"
60 #include "wingdi.h"
61 #include "winuser.h"
62 #include "winerror.h"
63 #include "mmsystem.h"
64 #include "winternl.h"
65 #include "mmddk.h"
66 #include "wine/windef16.h"
67 #include "wine/winbase16.h"
68 #include "wine/debug.h"
69 #include "dsound.h"
70 #include "dsdriver.h"
71 #include "dsound_private.h"
72 #include "dsconf.h"
74 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
76 /* these are eligible for tuning... they must be high on slow machines... */
77 /* some stuff may get more responsive with lower values though... */
78 #define DS_EMULDRIVER 0 /* some games (Quake 2, UT) refuse to accept
79 emulated dsound devices. set to 0 ! */
80 #define DS_HEL_MARGIN 5 /* HEL only: number of waveOut fragments ahead to mix in new buffers
81 * (keep this close or equal to DS_HEL_QUEUE for best results) */
82 #define DS_HEL_QUEUE 5 /* HEL only: number of waveOut fragments ahead to queue to driver
83 * (this will affect HEL sound reliability and latency) */
85 #define DS_SND_QUEUE_MAX 28 /* max number of fragments to prebuffer */
86 #define DS_SND_QUEUE_MIN 12 /* min number of fragments to prebuffer */
88 IDirectSoundImpl* dsound = NULL;
90 HRESULT mmErr(UINT err)
92 switch(err) {
93 case MMSYSERR_NOERROR:
94 return DS_OK;
95 case MMSYSERR_ALLOCATED:
96 return DSERR_ALLOCATED;
97 case MMSYSERR_ERROR:
98 case MMSYSERR_INVALHANDLE:
99 case WAVERR_STILLPLAYING:
100 return DSERR_GENERIC; /* FIXME */
101 case MMSYSERR_NODRIVER:
102 return DSERR_NODRIVER;
103 case MMSYSERR_NOMEM:
104 return DSERR_OUTOFMEMORY;
105 case MMSYSERR_INVALPARAM:
106 case WAVERR_BADFORMAT:
107 case WAVERR_UNPREPARED:
108 return DSERR_INVALIDPARAM;
109 case MMSYSERR_NOTSUPPORTED:
110 return DSERR_UNSUPPORTED;
111 default:
112 FIXME("Unknown MMSYS error %d\n",err);
113 return DSERR_GENERIC;
117 int ds_emuldriver = DS_EMULDRIVER;
118 int ds_hel_margin = DS_HEL_MARGIN;
119 int ds_hel_queue = DS_HEL_QUEUE;
120 int ds_snd_queue_max = DS_SND_QUEUE_MAX;
121 int ds_snd_queue_min = DS_SND_QUEUE_MIN;
122 int ds_hw_accel = DS_HW_ACCEL_FULL;
123 int ds_default_playback = 0;
124 int ds_default_capture = 0;
127 * Get a config key from either the app-specific or the default config
130 inline static DWORD get_config_key( HKEY defkey, HKEY appkey, const char *name,
131 char *buffer, DWORD size )
133 if (appkey && !RegQueryValueExA( appkey, name, 0, NULL, buffer, &size )) return 0;
134 return RegQueryValueExA( defkey, name, 0, NULL, buffer, &size );
139 * Setup the dsound options.
142 void setup_dsound_options(void)
144 char buffer[MAX_PATH+1];
145 HKEY hkey, appkey = 0;
147 buffer[MAX_PATH]='\0';
149 if (RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\dsound", 0, NULL,
150 REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL ))
152 ERR("Cannot create config registry key\n" );
153 ExitProcess(1);
156 if (GetModuleFileNameA( 0, buffer, MAX_PATH ))
158 HKEY tmpkey;
160 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\AppDefaults", &tmpkey ))
162 char appname[MAX_PATH+16];
163 char *p = strrchr( buffer, '\\' );
164 if (p!=NULL) {
165 appname[MAX_PATH]='\0';
166 strncpy(appname,p+1,MAX_PATH);
167 strcat(appname,"\\dsound");
168 TRACE("appname = [%s] \n",appname);
169 if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0;
170 RegCloseKey( tmpkey );
175 /* get options */
177 if (!get_config_key( hkey, appkey, "EmulDriver", buffer, MAX_PATH ))
178 ds_emuldriver = strcmp(buffer, "N");
180 if (!get_config_key( hkey, appkey, "HELmargin", buffer, MAX_PATH ))
181 ds_hel_margin = atoi(buffer);
183 if (!get_config_key( hkey, appkey, "HELqueue", buffer, MAX_PATH ))
184 ds_hel_queue = atoi(buffer);
186 if (!get_config_key( hkey, appkey, "SndQueueMax", buffer, MAX_PATH ))
187 ds_snd_queue_max = atoi(buffer);
189 if (!get_config_key( hkey, appkey, "SndQueueMin", buffer, MAX_PATH ))
190 ds_snd_queue_min = atoi(buffer);
192 if (!get_config_key( hkey, appkey, "HardwareAcceleration", buffer, MAX_PATH )) {
193 if (strcmp(buffer, "Full") == 0)
194 ds_hw_accel = DS_HW_ACCEL_FULL;
195 else if (strcmp(buffer, "Standard") == 0)
196 ds_hw_accel = DS_HW_ACCEL_STANDARD;
197 else if (strcmp(buffer, "Basic") == 0)
198 ds_hw_accel = DS_HW_ACCEL_BASIC;
199 else if (strcmp(buffer, "Emulation") == 0)
200 ds_hw_accel = DS_HW_ACCEL_EMULATION;
203 if (!get_config_key( hkey, appkey, "DefaultPlayback", buffer, MAX_PATH ))
204 ds_default_playback = atoi(buffer);
206 if (!get_config_key( hkey, appkey, "DefaultCapture", buffer, MAX_PATH ))
207 ds_default_capture = atoi(buffer);
209 if (appkey) RegCloseKey( appkey );
210 RegCloseKey( hkey );
212 if (ds_emuldriver != DS_EMULDRIVER )
213 WARN("ds_emuldriver = %d (default=%d)\n",ds_emuldriver, DS_EMULDRIVER);
214 if (ds_hel_margin != DS_HEL_MARGIN )
215 WARN("ds_hel_margin = %d (default=%d)\n",ds_hel_margin, DS_HEL_MARGIN );
216 if (ds_hel_queue != DS_HEL_QUEUE )
217 WARN("ds_hel_queue = %d (default=%d)\n",ds_hel_queue, DS_HEL_QUEUE );
218 if (ds_snd_queue_max != DS_SND_QUEUE_MAX)
219 WARN("ds_snd_queue_max = %d (default=%d)\n",ds_snd_queue_max ,DS_SND_QUEUE_MAX);
220 if (ds_snd_queue_min != DS_SND_QUEUE_MIN)
221 WARN("ds_snd_queue_min = %d (default=%d)\n",ds_snd_queue_min ,DS_SND_QUEUE_MIN);
222 if (ds_hw_accel != DS_HW_ACCEL_FULL)
223 WARN("ds_hw_accel = %s (default=Full)\n",
224 ds_hw_accel==DS_HW_ACCEL_FULL ? "Full" :
225 ds_hw_accel==DS_HW_ACCEL_STANDARD ? "Standard" :
226 ds_hw_accel==DS_HW_ACCEL_BASIC ? "Basic" :
227 ds_hw_accel==DS_HW_ACCEL_EMULATION ? "Emulation" :
228 "Unknown");
229 if (ds_default_playback != 0)
230 WARN("ds_default_playback = %d (default=0)\n",ds_default_playback);
231 if (ds_default_capture != 0)
232 WARN("ds_default_capture = %d (default=0)\n",ds_default_playback);
237 /***************************************************************************
238 * GetDeviceID [DSOUND.9]
240 * Retrieves unique identifier of default device specified
242 * PARAMS
243 * pGuidSrc [I] Address of device GUID.
244 * pGuidDest [O] Address to receive unique device GUID.
246 * RETURNS
247 * Success: DS_OK
248 * Failure: DSERR_INVALIDPARAM
250 * NOTES
251 * pGuidSrc is a valid device GUID or DSDEVID_DefaultPlayback,
252 * DSDEVID_DefaultCapture, DSDEVID_DefaultVoicePlayback, or
253 * DSDEVID_DefaultVoiceCapture.
254 * Returns pGuidSrc if pGuidSrc is a valid device or the device
255 * GUID for the specified constants.
257 HRESULT WINAPI GetDeviceID(LPCGUID pGuidSrc, LPGUID pGuidDest)
259 TRACE("(%p,%p)\n",pGuidSrc,pGuidDest);
261 if ( pGuidSrc == NULL) {
262 WARN("invalid parameter: pGuidSrc == NULL\n");
263 return DSERR_INVALIDPARAM;
266 if ( pGuidDest == NULL ) {
267 WARN("invalid parameter: pGuidDest == NULL\n");
268 return DSERR_INVALIDPARAM;
271 if ( IsEqualGUID( &DSDEVID_DefaultPlayback, pGuidSrc ) ||
272 IsEqualGUID( &DSDEVID_DefaultVoicePlayback, pGuidSrc ) ) {
273 GUID guid;
274 int err = mmErr(waveOutMessage((HWAVEOUT)ds_default_playback,DRV_QUERYDSOUNDGUID,(DWORD)&guid,0));
275 if (err == DS_OK) {
276 memcpy(pGuidDest, &guid, sizeof(GUID));
277 return DS_OK;
281 if ( IsEqualGUID( &DSDEVID_DefaultCapture, pGuidSrc ) ||
282 IsEqualGUID( &DSDEVID_DefaultVoiceCapture, pGuidSrc ) ) {
283 GUID guid;
284 int err = mmErr(waveInMessage((HWAVEIN)ds_default_capture,DRV_QUERYDSOUNDGUID,(DWORD)&guid,0));
285 if (err == DS_OK) {
286 memcpy(pGuidDest, &guid, sizeof(GUID));
287 return DS_OK;
291 memcpy(pGuidDest, pGuidSrc, sizeof(GUID));
293 return DS_OK;
297 /***************************************************************************
298 * DirectSoundEnumerateA [DSOUND.2]
300 * Enumerate all DirectSound drivers installed in the system
302 * PARAMS
303 * lpDSEnumCallback [I] Address of callback function.
304 * lpContext [I] Address of user defined context passed to callback function.
306 * RETURNS
307 * Success: DS_OK
308 * Failure: DSERR_INVALIDPARAM
310 HRESULT WINAPI DirectSoundEnumerateA(
311 LPDSENUMCALLBACKA lpDSEnumCallback,
312 LPVOID lpContext)
314 unsigned devs, wod;
315 DSDRIVERDESC desc;
316 GUID guid;
317 int err;
319 TRACE("lpDSEnumCallback = %p, lpContext = %p\n",
320 lpDSEnumCallback, lpContext);
322 if (lpDSEnumCallback == NULL) {
323 WARN("invalid parameter: lpDSEnumCallback == NULL\n");
324 return DSERR_INVALIDPARAM;
327 devs = waveOutGetNumDevs();
328 if (devs > 0) {
329 if (GetDeviceID(&DSDEVID_DefaultPlayback, &guid) == DS_OK) {
330 GUID temp;
331 for (wod = 0; wod < devs; ++wod) {
332 err = mmErr(waveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDGUID,(DWORD)&temp,0));
333 if (err == DS_OK) {
334 if (IsEqualGUID( &guid, &temp ) ) {
335 err = mmErr(waveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDDESC,(DWORD)&desc,0));
336 if (err == DS_OK) {
337 TRACE("calling lpDSEnumCallback(NULL,\"%s\",\"%s\",%p)\n",
338 "Primary Sound Driver",desc.szDrvName,lpContext);
339 if (lpDSEnumCallback(NULL, "Primary Sound Driver", desc.szDrvName, lpContext) == FALSE)
340 return DS_OK;
348 for (wod = 0; wod < devs; ++wod) {
349 err = mmErr(waveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDDESC,(DWORD)&desc,0));
350 if (err == DS_OK) {
351 err = mmErr(waveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDGUID,(DWORD)&guid,0));
352 if (err == DS_OK) {
353 TRACE("calling lpDSEnumCallback(%s,\"%s\",\"%s\",%p)\n",
354 debugstr_guid(&guid),desc.szDesc,desc.szDrvName,lpContext);
355 if (lpDSEnumCallback(&guid, desc.szDesc, desc.szDrvName, lpContext) == FALSE)
356 return DS_OK;
360 return DS_OK;
363 /***************************************************************************
364 * DirectSoundEnumerateW [DSOUND.3]
366 * Enumerate all DirectSound drivers installed in the system
368 * PARAMS
369 * lpDSEnumCallback [I] Address of callback function.
370 * lpContext [I] Address of user defined context passed to callback function.
372 * RETURNS
373 * Success: DS_OK
374 * Failure: DSERR_INVALIDPARAM
376 HRESULT WINAPI DirectSoundEnumerateW(
377 LPDSENUMCALLBACKW lpDSEnumCallback,
378 LPVOID lpContext )
380 unsigned devs, wod;
381 DSDRIVERDESC desc;
382 GUID guid;
383 int err;
384 WCHAR wDesc[MAXPNAMELEN];
385 WCHAR wName[MAXPNAMELEN];
387 TRACE("lpDSEnumCallback = %p, lpContext = %p\n",
388 lpDSEnumCallback, lpContext);
390 if (lpDSEnumCallback == NULL) {
391 WARN("invalid parameter: lpDSEnumCallback == NULL\n");
392 return DSERR_INVALIDPARAM;
395 devs = waveOutGetNumDevs();
396 if (devs > 0) {
397 if (GetDeviceID(&DSDEVID_DefaultPlayback, &guid) == DS_OK) {
398 GUID temp;
399 for (wod = 0; wod < devs; ++wod) {
400 err = mmErr(waveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDGUID,(DWORD)&temp,0));
401 if (err == DS_OK) {
402 if (IsEqualGUID( &guid, &temp ) ) {
403 err = mmErr(waveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDDESC,(DWORD)&desc,0));
404 if (err == DS_OK) {
405 TRACE("calling lpDSEnumCallback(NULL,\"%s\",\"%s\",%p)\n",
406 "Primary Sound Driver",desc.szDrvName,lpContext);
407 MultiByteToWideChar( CP_ACP, 0, "Primary Sound Driver", -1,
408 wDesc, sizeof(wDesc)/sizeof(WCHAR) );
409 MultiByteToWideChar( CP_ACP, 0, desc.szDrvName, -1,
410 wName, sizeof(wName)/sizeof(WCHAR) );
411 if (lpDSEnumCallback(NULL, wDesc, wName, lpContext) == FALSE)
412 return DS_OK;
420 for (wod = 0; wod < devs; ++wod) {
421 err = mmErr(waveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDDESC,(DWORD)&desc,0));
422 if (err == DS_OK) {
423 err = mmErr(waveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDGUID,(DWORD)&guid,0));
424 if (err == DS_OK) {
425 TRACE("calling lpDSEnumCallback(%s,\"%s\",\"%s\",%p)\n",
426 debugstr_guid(&guid),desc.szDesc,desc.szDrvName,lpContext);
427 MultiByteToWideChar( CP_ACP, 0, desc.szDesc, -1,
428 wDesc, sizeof(wDesc)/sizeof(WCHAR) );
429 MultiByteToWideChar( CP_ACP, 0, desc.szDrvName, -1,
430 wName, sizeof(wName)/sizeof(WCHAR) );
431 if (lpDSEnumCallback(&guid, wDesc, wName, lpContext) == FALSE)
432 return DS_OK;
436 return DS_OK;
440 static void _dump_DSBCAPS(DWORD xmask) {
441 struct {
442 DWORD mask;
443 char *name;
444 } flags[] = {
445 #define FE(x) { x, #x },
446 FE(DSBCAPS_PRIMARYBUFFER)
447 FE(DSBCAPS_STATIC)
448 FE(DSBCAPS_LOCHARDWARE)
449 FE(DSBCAPS_LOCSOFTWARE)
450 FE(DSBCAPS_CTRL3D)
451 FE(DSBCAPS_CTRLFREQUENCY)
452 FE(DSBCAPS_CTRLPAN)
453 FE(DSBCAPS_CTRLVOLUME)
454 FE(DSBCAPS_CTRLPOSITIONNOTIFY)
455 FE(DSBCAPS_CTRLDEFAULT)
456 FE(DSBCAPS_CTRLALL)
457 FE(DSBCAPS_STICKYFOCUS)
458 FE(DSBCAPS_GLOBALFOCUS)
459 FE(DSBCAPS_GETCURRENTPOSITION2)
460 FE(DSBCAPS_MUTE3DATMAXDISTANCE)
461 #undef FE
463 int i;
465 for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
466 if ((flags[i].mask & xmask) == flags[i].mask)
467 DPRINTF("%s ",flags[i].name);
470 /*******************************************************************************
471 * IDirectSound
474 static HRESULT WINAPI IDirectSoundImpl_SetCooperativeLevel(
475 LPDIRECTSOUND8 iface,HWND hwnd,DWORD level
477 ICOM_THIS(IDirectSoundImpl,iface);
478 TRACE("(%p,%08lx,%ld(%s))\n",This,(DWORD)hwnd,level,
479 level == DSSCL_NORMAL ? "DSSCL_NORMAL" :
480 level == DSSCL_PRIORITY ? "DSSCL_PRIORITY" :
481 level == DSSCL_EXCLUSIVE ? "DSSCL_EXCLUSIVE" :
482 level == DSSCL_WRITEPRIMARY ? "DSSCL_WRITEPRIMARY" : "Unknown");
484 if (level==DSSCL_PRIORITY || level==DSSCL_EXCLUSIVE) {
485 FIXME("level=%s not fully supported\n",
486 level==DSSCL_PRIORITY ? "DSSCL_PRIORITY" : "DSSCL_EXCLUSIVE");
489 This->priolevel = level;
491 return DS_OK;
494 static HRESULT WINAPI IDirectSoundImpl_CreateSoundBuffer(
495 LPDIRECTSOUND8 iface,LPCDSBUFFERDESC dsbd,LPLPDIRECTSOUNDBUFFER8 ppdsb,LPUNKNOWN lpunk
497 ICOM_THIS(IDirectSoundImpl,iface);
498 LPWAVEFORMATEX wfex;
499 HRESULT hres = DS_OK;
501 TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
503 if (This == NULL) {
504 WARN("invalid parameter: This == NULL\n");
505 return DSERR_INVALIDPARAM;
508 if (dsbd == NULL) {
509 WARN("invalid parameter: dsbd == NULL\n");
510 return DSERR_INVALIDPARAM;
513 if (dsbd->dwSize != sizeof(DSBUFFERDESC) && dsbd->dwSize != sizeof(DSBUFFERDESC1)) {
514 WARN("invalid parameter: dsbd\n");
515 return DSERR_INVALIDPARAM;
518 if (ppdsb == NULL) {
519 WARN("invalid parameter: ppdsb == NULL\n");
520 return DSERR_INVALIDPARAM;
523 if (TRACE_ON(dsound)) {
524 TRACE("(structsize=%ld)\n",dsbd->dwSize);
525 TRACE("(flags=0x%08lx:\n",dsbd->dwFlags);
526 _dump_DSBCAPS(dsbd->dwFlags);
527 DPRINTF(")\n");
528 TRACE("(bufferbytes=%ld)\n",dsbd->dwBufferBytes);
529 TRACE("(lpwfxFormat=%p)\n",dsbd->lpwfxFormat);
532 wfex = dsbd->lpwfxFormat;
534 if (wfex)
535 TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld,"
536 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
537 wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec,
538 wfex->nAvgBytesPerSec, wfex->nBlockAlign,
539 wfex->wBitsPerSample, wfex->cbSize);
541 if (dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) {
542 if (This->primary) {
543 WARN("Primary Buffer already created\n");
544 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(This->primary));
545 *ppdsb = (LPDIRECTSOUNDBUFFER8)(This->primary);
546 } else {
547 This->dsbd = *dsbd;
548 hres = PrimaryBufferImpl_Create(This, (PrimaryBufferImpl**)&(This->primary), &(This->dsbd));
549 if (This->primary) {
550 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(This->primary));
551 *ppdsb = (LPDIRECTSOUNDBUFFER8)(This->primary);
552 } else
553 WARN("PrimaryBufferImpl_Create failed\n");
555 } else {
556 IDirectSoundBufferImpl * dsb;
557 hres = IDirectSoundBufferImpl_Create(This, (IDirectSoundBufferImpl**)&dsb, dsbd);
558 if (dsb) {
559 hres = SecondaryBufferImpl_Create(dsb, (SecondaryBufferImpl**)ppdsb);
560 if (*ppdsb) {
561 dsb->dsb = (SecondaryBufferImpl*)*ppdsb;
562 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)*ppdsb);
563 } else
564 WARN("SecondaryBufferImpl_Create failed\n");
565 } else
566 WARN("IDirectSoundBufferImpl_Create failed\n");
569 return hres;
572 static HRESULT WINAPI IDirectSoundImpl_DuplicateSoundBuffer(
573 LPDIRECTSOUND8 iface,LPDIRECTSOUNDBUFFER8 psb,LPLPDIRECTSOUNDBUFFER8 ppdsb
575 ICOM_THIS(IDirectSoundImpl,iface);
576 IDirectSoundBufferImpl* pdsb;
577 IDirectSoundBufferImpl* dsb;
578 HRESULT hres = DS_OK;
579 TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
581 if (This == NULL) {
582 WARN("invalid parameter: This == NULL\n");
583 return DSERR_INVALIDPARAM;
586 if (psb == NULL) {
587 WARN("invalid parameter: psb == NULL\n");
588 return DSERR_INVALIDPARAM;
591 if (ppdsb == NULL) {
592 WARN("invalid parameter: ppdsb == NULL\n");
593 return DSERR_INVALIDPARAM;
596 /* FIXME: hack to make sure we have a secondary buffer */
597 if ((DWORD)((SecondaryBufferImpl *)psb)->dsb == (DWORD)This) {
598 ERR("trying to duplicate primary buffer\n");
599 *ppdsb = NULL;
600 return DSERR_INVALIDCALL;
603 pdsb = ((SecondaryBufferImpl *)psb)->dsb;
605 dsb = (IDirectSoundBufferImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb));
607 if (dsb == NULL) {
608 WARN("out of memory\n");
609 *ppdsb = NULL;
610 return DSERR_OUTOFMEMORY;
613 memcpy(dsb, pdsb, sizeof(IDirectSoundBufferImpl));
615 if (pdsb->hwbuf) {
616 TRACE("duplicating hardware buffer\n");
618 hres = IDsDriver_DuplicateSoundBuffer(This->driver, pdsb->hwbuf, (LPVOID *)&dsb->hwbuf);
619 if (hres != DS_OK) {
620 TRACE("IDsDriver_DuplicateSoundBuffer failed, falling back to software buffer\n");
621 dsb->hwbuf = NULL;
622 /* allocate buffer */
623 if (This->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) {
624 dsb->buffer = HeapAlloc(GetProcessHeap(),0,sizeof(*(dsb->buffer)));
625 if (dsb->buffer == NULL) {
626 WARN("out of memory\n");
627 HeapFree(GetProcessHeap(),0,dsb);
628 *ppdsb = NULL;
629 return DSERR_OUTOFMEMORY;
632 dsb->buffer->memory = (LPBYTE)HeapAlloc(GetProcessHeap(),0,dsb->buflen);
633 if (dsb->buffer->memory == NULL) {
634 WARN("out of memory\n");
635 HeapFree(GetProcessHeap(),0,dsb->buffer);
636 HeapFree(GetProcessHeap(),0,dsb);
637 *ppdsb = NULL;
638 return DSERR_OUTOFMEMORY;
640 dsb->buffer->ref = 1;
642 /* FIXME: copy buffer ? */
645 } else {
646 dsb->hwbuf = NULL;
647 dsb->buffer->ref++;
650 dsb->ref = 0;
651 dsb->state = STATE_STOPPED;
652 dsb->playpos = 0;
653 dsb->buf_mixpos = 0;
654 dsb->dsound = This;
655 dsb->ds3db = NULL;
656 dsb->iks = NULL; /* FIXME? */
657 dsb->dsb = NULL;
658 memcpy(&(dsb->wfx), &(pdsb->wfx), sizeof(dsb->wfx));
659 InitializeCriticalSection(&(dsb->lock));
660 /* register buffer */
661 RtlAcquireResourceExclusive(&(This->lock), TRUE);
663 IDirectSoundBufferImpl **newbuffers;
664 if (This->buffers)
665 newbuffers = (IDirectSoundBufferImpl**)HeapReAlloc(GetProcessHeap(),0,This->buffers,sizeof(IDirectSoundBufferImpl**)*(This->nrofbuffers+1));
666 else
667 newbuffers = (IDirectSoundBufferImpl**)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundBufferImpl**)*(This->nrofbuffers+1));
669 if (newbuffers) {
670 This->buffers = newbuffers;
671 This->buffers[This->nrofbuffers] = dsb;
672 This->nrofbuffers++;
673 TRACE("buffer count is now %d\n", This->nrofbuffers);
674 } else {
675 ERR("out of memory for buffer list! Current buffer count is %d\n", This->nrofbuffers);
676 IDirectSoundBuffer8_Release(psb);
677 DeleteCriticalSection(&(dsb->lock));
678 RtlReleaseResource(&(This->lock));
679 HeapFree(GetProcessHeap(),0,dsb);
680 *ppdsb = 0;
681 return DSERR_OUTOFMEMORY;
684 RtlReleaseResource(&(This->lock));
685 IDirectSound_AddRef(iface);
686 hres = SecondaryBufferImpl_Create(dsb, (SecondaryBufferImpl**)ppdsb);
687 if (*ppdsb) {
688 dsb->dsb = (SecondaryBufferImpl*)*ppdsb;
689 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)*ppdsb);
690 } else
691 WARN("SecondaryBufferImpl_Create failed\n");
693 return hres;
696 static HRESULT WINAPI IDirectSoundImpl_GetCaps(LPDIRECTSOUND8 iface,LPDSCAPS lpDSCaps) {
697 ICOM_THIS(IDirectSoundImpl,iface);
698 TRACE("(%p,%p)\n",This,lpDSCaps);
700 if (This == NULL) {
701 WARN("invalid parameter: This == NULL\n");
702 return DSERR_INVALIDPARAM;
705 if (lpDSCaps == NULL) {
706 WARN("invalid parameter: lpDSCaps = NULL\n");
707 return DSERR_INVALIDPARAM;
710 /* check is there is enough room */
711 if (lpDSCaps->dwSize < sizeof(*lpDSCaps)) {
712 WARN("invalid parameter: lpDSCaps->dwSize = %ld < %d\n",
713 lpDSCaps->dwSize, sizeof(*lpDSCaps));
714 return DSERR_INVALIDPARAM;
717 lpDSCaps->dwFlags = This->drvcaps.dwFlags;
718 TRACE("(flags=0x%08lx)\n",lpDSCaps->dwFlags);
720 lpDSCaps->dwMinSecondarySampleRate = This->drvcaps.dwMinSecondarySampleRate;
721 lpDSCaps->dwMaxSecondarySampleRate = This->drvcaps.dwMaxSecondarySampleRate;
723 lpDSCaps->dwPrimaryBuffers = This->drvcaps.dwPrimaryBuffers;
725 lpDSCaps->dwMaxHwMixingAllBuffers = This->drvcaps.dwMaxHwMixingAllBuffers;
726 lpDSCaps->dwMaxHwMixingStaticBuffers = This->drvcaps.dwMaxHwMixingStaticBuffers;
727 lpDSCaps->dwMaxHwMixingStreamingBuffers = This->drvcaps.dwMaxHwMixingStreamingBuffers;
729 lpDSCaps->dwFreeHwMixingAllBuffers = This->drvcaps.dwFreeHwMixingAllBuffers;
730 lpDSCaps->dwFreeHwMixingStaticBuffers = This->drvcaps.dwFreeHwMixingStaticBuffers;
731 lpDSCaps->dwFreeHwMixingStreamingBuffers = This->drvcaps.dwFreeHwMixingStreamingBuffers;
733 lpDSCaps->dwMaxHw3DAllBuffers = This->drvcaps.dwMaxHw3DAllBuffers;
734 lpDSCaps->dwMaxHw3DStaticBuffers = This->drvcaps.dwMaxHw3DStaticBuffers;
735 lpDSCaps->dwMaxHw3DStreamingBuffers = This->drvcaps.dwMaxHw3DStreamingBuffers;
737 lpDSCaps->dwFreeHw3DAllBuffers = This->drvcaps.dwFreeHw3DAllBuffers;
738 lpDSCaps->dwFreeHw3DStaticBuffers = This->drvcaps.dwFreeHw3DStaticBuffers;
739 lpDSCaps->dwFreeHw3DStreamingBuffers = This->drvcaps.dwFreeHw3DStreamingBuffers;
741 lpDSCaps->dwTotalHwMemBytes = This->drvcaps.dwTotalHwMemBytes;
743 lpDSCaps->dwFreeHwMemBytes = This->drvcaps.dwFreeHwMemBytes;
745 lpDSCaps->dwMaxContigFreeHwMemBytes = This->drvcaps.dwMaxContigFreeHwMemBytes;
747 /* driver doesn't have these */
748 lpDSCaps->dwUnlockTransferRateHwBuffers = 4096; /* But we have none... */
750 lpDSCaps->dwPlayCpuOverheadSwBuffers = 1; /* 1% */
752 return DS_OK;
755 static ULONG WINAPI IDirectSoundImpl_AddRef(LPDIRECTSOUND8 iface) {
756 ICOM_THIS(IDirectSoundImpl,iface);
757 TRACE("(%p) ref was %ld, thread is %04lx\n", This, This->ref, GetCurrentThreadId());
758 return InterlockedIncrement(&This->ref);
761 static ULONG WINAPI IDirectSoundImpl_Release(LPDIRECTSOUND8 iface) {
762 ICOM_THIS(IDirectSoundImpl,iface);
763 ULONG ulReturn;
765 TRACE("(%p) ref was %ld, thread is %04lx\n", This, This->ref, GetCurrentThreadId());
766 ulReturn = InterlockedDecrement(&This->ref);
767 if (ulReturn == 0) {
768 HRESULT hres;
769 UINT i;
771 timeKillEvent(This->timerID);
772 timeEndPeriod(DS_TIME_RES);
773 /* wait for timer to expire */
774 Sleep(DS_TIME_RES+1);
776 RtlAcquireResourceShared(&(This->lock), TRUE);
778 if (This->buffers) {
779 for( i=0;i<This->nrofbuffers;i++)
780 IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)This->buffers[i]);
783 RtlReleaseResource(&(This->lock));
785 if (This->primary) {
786 WARN("primary buffer not released\n");
787 IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)This->primary);
790 hres = DSOUND_PrimaryDestroy(This);
791 if (hres != DS_OK)
792 WARN("DSOUND_PrimaryDestroy failed\n");
794 if (This->driver)
795 IDsDriver_Close(This->driver);
797 if (This->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN)
798 waveOutClose(This->hwo);
800 if (This->driver)
801 IDsDriver_Release(This->driver);
803 RtlDeleteResource(&This->lock);
804 DeleteCriticalSection(&This->mixlock);
805 HeapFree(GetProcessHeap(),0,This);
806 dsound = NULL;
807 TRACE("(%p) released\n",This);
810 return ulReturn;
813 static HRESULT WINAPI IDirectSoundImpl_SetSpeakerConfig(
814 LPDIRECTSOUND8 iface,DWORD config
816 ICOM_THIS(IDirectSoundImpl,iface);
817 TRACE("(%p,0x%08lx)\n",This,config);
819 This->speaker_config = config;
821 WARN("not fully functional\n");
822 return DS_OK;
825 static HRESULT WINAPI IDirectSoundImpl_QueryInterface(
826 LPDIRECTSOUND8 iface,REFIID riid,LPVOID *ppobj
828 ICOM_THIS(IDirectSoundImpl,iface);
829 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
831 if (ppobj == NULL) {
832 WARN("invalid parameter\n");
833 return E_INVALIDARG;
836 *ppobj = NULL; /* assume failure */
838 if ( IsEqualGUID(riid, &IID_IUnknown) ||
839 IsEqualGUID(riid, &IID_IDirectSound) ||
840 IsEqualGUID(riid, &IID_IDirectSound8) ) {
841 IDirectSound8_AddRef((LPDIRECTSOUND8)This);
842 *ppobj = This;
843 return S_OK;
846 if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
847 WARN("app requested IDirectSound3DListener on dsound object\n");
848 return E_NOINTERFACE;
851 FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
852 return E_NOINTERFACE;
855 static HRESULT WINAPI IDirectSoundImpl_Compact(
856 LPDIRECTSOUND8 iface)
858 ICOM_THIS(IDirectSoundImpl,iface);
859 TRACE("(%p)\n", This);
860 return DS_OK;
863 static HRESULT WINAPI IDirectSoundImpl_GetSpeakerConfig(
864 LPDIRECTSOUND8 iface,
865 LPDWORD lpdwSpeakerConfig)
867 ICOM_THIS(IDirectSoundImpl,iface);
868 TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
870 if (lpdwSpeakerConfig == NULL) {
871 WARN("invalid parameter\n");
872 return DSERR_INVALIDPARAM;
875 WARN("not fully functional\n");
877 *lpdwSpeakerConfig = This->speaker_config;
879 return DS_OK;
882 static HRESULT WINAPI IDirectSoundImpl_Initialize(
883 LPDIRECTSOUND8 iface,
884 LPCGUID lpcGuid)
886 ICOM_THIS(IDirectSoundImpl,iface);
887 TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
888 return DS_OK;
891 static HRESULT WINAPI IDirectSoundImpl_VerifyCertification(
892 LPDIRECTSOUND8 iface,
893 LPDWORD pdwCertified)
895 ICOM_THIS(IDirectSoundImpl,iface);
896 TRACE("(%p, %p)\n", This, pdwCertified);
897 *pdwCertified = DS_CERTIFIED;
898 return DS_OK;
901 static ICOM_VTABLE(IDirectSound8) dsvt =
903 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
904 IDirectSoundImpl_QueryInterface,
905 IDirectSoundImpl_AddRef,
906 IDirectSoundImpl_Release,
907 IDirectSoundImpl_CreateSoundBuffer,
908 IDirectSoundImpl_GetCaps,
909 IDirectSoundImpl_DuplicateSoundBuffer,
910 IDirectSoundImpl_SetCooperativeLevel,
911 IDirectSoundImpl_Compact,
912 IDirectSoundImpl_GetSpeakerConfig,
913 IDirectSoundImpl_SetSpeakerConfig,
914 IDirectSoundImpl_Initialize,
915 IDirectSoundImpl_VerifyCertification
919 /*******************************************************************************
920 * DirectSoundCreate (DSOUND.1)
922 * Creates and initializes a DirectSound interface.
924 * PARAMS
925 * lpcGUID [I] Address of the GUID that identifies the sound device.
926 * ppDS [O] Address of a variable to receive the interface pointer.
927 * pUnkOuter [I] Must be NULL.
929 * RETURNS
930 * Success: DS_OK
931 * Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
932 * DSERR_NODRIVER, DSERR_OUTOFMEMORY
934 HRESULT WINAPI DirectSoundCreate8(LPCGUID lpcGUID,LPDIRECTSOUND8 *ppDS,IUnknown *pUnkOuter )
936 IDirectSoundImpl** ippDS=(IDirectSoundImpl**)ppDS;
937 PIDSDRIVER drv = NULL;
938 unsigned wod, wodn;
939 HRESULT err = DSERR_INVALIDPARAM;
940 GUID devGuid;
941 BOOLEAN found = FALSE;
943 TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ippDS,pUnkOuter);
945 if (ippDS == NULL) {
946 WARN("invalid parameter: ippDS == NULL\n");
947 return DSERR_INVALIDPARAM;
950 /* Get dsound configuration */
951 setup_dsound_options();
953 /* Default device? */
954 if (!lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL))
955 lpcGUID = &DSDEVID_DefaultPlayback;
957 if (GetDeviceID(lpcGUID, &devGuid) != DS_OK) {
958 WARN("invalid parameter: lpcGUID\n");
959 *ippDS = NULL;
960 return DSERR_INVALIDPARAM;
963 if (dsound) {
964 if (IsEqualGUID(&devGuid, &dsound->guid) ) {
965 /* FIXME: this is wrong, need to create a new instance */
966 ERR("dsound already opened\n");
967 IDirectSound_AddRef((LPDIRECTSOUND)dsound);
968 *ippDS = dsound;
969 return DS_OK;
970 } else {
971 ERR("different dsound already opened\n");
975 /* Enumerate WINMM audio devices and find the one we want */
976 wodn = waveOutGetNumDevs();
977 if (!wodn) {
978 WARN("no driver\n");
979 *ippDS = NULL;
980 return DSERR_NODRIVER;
983 TRACE(" expecting GUID %s.\n", debugstr_guid(&devGuid));
985 for (wod=0; wod<wodn; wod++) {
986 GUID guid;
987 err = mmErr(waveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDGUID,(DWORD)(&guid),0));
988 if (err != DS_OK) {
989 WARN("waveOutMessage failed; err=%lx\n",err);
990 *ippDS = NULL;
991 return err;
993 TRACE("got GUID %s for wod %d.\n", debugstr_guid(&guid), wod);
994 if (IsEqualGUID( &devGuid, &guid) ) {
995 err = DS_OK;
996 found = TRUE;
997 break;
1001 if (err != DS_OK) {
1002 WARN("invalid parameter\n");
1003 *ippDS = NULL;
1004 return DSERR_INVALIDPARAM;
1007 if (found == FALSE) {
1008 WARN("No device found matching given ID - trying with default one !\n");
1009 wod = ds_default_playback;
1012 /* DRV_QUERYDSOUNDIFACE is a "Wine extension" to get the DSound interface */
1013 waveOutMessage((HWAVEOUT)wod, DRV_QUERYDSOUNDIFACE, (DWORD)&drv, 0);
1015 /* Disable the direct sound driver to force emulation if requested. */
1016 if (ds_hw_accel == DS_HW_ACCEL_EMULATION)
1017 drv = NULL;
1019 /* Allocate memory */
1020 *ippDS = (IDirectSoundImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundImpl));
1021 if (*ippDS == NULL) {
1022 WARN("out of memory\n");
1023 return DSERR_OUTOFMEMORY;
1026 (*ippDS)->lpVtbl = &dsvt;
1027 (*ippDS)->ref = 1;
1029 (*ippDS)->driver = drv;
1030 (*ippDS)->priolevel = DSSCL_NORMAL;
1031 (*ippDS)->fraglen = 0;
1032 (*ippDS)->hwbuf = NULL;
1033 (*ippDS)->buffer = NULL;
1034 (*ippDS)->buflen = 0;
1035 (*ippDS)->writelead = 0;
1036 (*ippDS)->state = STATE_STOPPED;
1037 (*ippDS)->nrofbuffers = 0;
1038 (*ippDS)->buffers = NULL;
1039 (*ippDS)->primary = NULL;
1040 (*ippDS)->speaker_config = DSSPEAKER_STEREO | (DSSPEAKER_GEOMETRY_NARROW << 16);
1042 /* 3D listener initial parameters */
1043 (*ippDS)->listener = NULL;
1044 (*ippDS)->ds3dl.dwSize = sizeof(DS3DLISTENER);
1045 (*ippDS)->ds3dl.vPosition.x = 0.0;
1046 (*ippDS)->ds3dl.vPosition.y = 0.0;
1047 (*ippDS)->ds3dl.vPosition.z = 0.0;
1048 (*ippDS)->ds3dl.vVelocity.x = 0.0;
1049 (*ippDS)->ds3dl.vVelocity.y = 0.0;
1050 (*ippDS)->ds3dl.vVelocity.z = 0.0;
1051 (*ippDS)->ds3dl.vOrientFront.x = 0.0;
1052 (*ippDS)->ds3dl.vOrientFront.y = 0.0;
1053 (*ippDS)->ds3dl.vOrientFront.z = 1.0;
1054 (*ippDS)->ds3dl.vOrientTop.x = 0.0;
1055 (*ippDS)->ds3dl.vOrientTop.y = 1.0;
1056 (*ippDS)->ds3dl.vOrientTop.z = 0.0;
1057 (*ippDS)->ds3dl.flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
1058 (*ippDS)->ds3dl.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
1059 (*ippDS)->ds3dl.flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
1061 (*ippDS)->prebuf = ds_snd_queue_max;
1062 (*ippDS)->guid = devGuid;
1064 /* Get driver description */
1065 if (drv) {
1066 err = IDsDriver_GetDriverDesc(drv,&((*ippDS)->drvdesc));
1067 if (err != DS_OK) {
1068 WARN("IDsDriver_GetDriverDesc failed\n");
1069 HeapFree(GetProcessHeap(),0,*ippDS);
1070 *ippDS = NULL;
1071 return err;
1073 } else {
1074 /* if no DirectSound interface available, use WINMM API instead */
1075 (*ippDS)->drvdesc.dwFlags = DSDDESC_DOMMSYSTEMOPEN | DSDDESC_DOMMSYSTEMSETFORMAT;
1078 (*ippDS)->drvdesc.dnDevNode = wod;
1080 /* Set default wave format (may need it for waveOutOpen) */
1081 (*ippDS)->wfx.wFormatTag = WAVE_FORMAT_PCM;
1082 /* We rely on the sound driver to return the actual sound format of
1083 * the device if it does not support 22050x8x2 and is given the
1084 * WAVE_DIRECTSOUND flag.
1086 (*ippDS)->wfx.nSamplesPerSec = 22050;
1087 (*ippDS)->wfx.wBitsPerSample = 8;
1088 (*ippDS)->wfx.nChannels = 2;
1089 (*ippDS)->wfx.nBlockAlign = (*ippDS)->wfx.wBitsPerSample * (*ippDS)->wfx.nChannels / 8;
1090 (*ippDS)->wfx.nAvgBytesPerSec = (*ippDS)->wfx.nSamplesPerSec * (*ippDS)->wfx.nBlockAlign;
1091 (*ippDS)->wfx.cbSize = 0;
1093 /* If the driver requests being opened through MMSYSTEM
1094 * (which is recommended by the DDK), it is supposed to happen
1095 * before the DirectSound interface is opened */
1096 if ((*ippDS)->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN)
1098 DWORD flags = CALLBACK_FUNCTION;
1100 /* disable direct sound if requested */
1101 if (ds_hw_accel != DS_HW_ACCEL_EMULATION)
1102 flags |= WAVE_DIRECTSOUND;
1104 err = mmErr(waveOutOpen(&((*ippDS)->hwo),
1105 (*ippDS)->drvdesc.dnDevNode, &((*ippDS)->wfx),
1106 (DWORD)DSOUND_callback, (DWORD)(*ippDS),
1107 flags));
1108 if (err != DS_OK) {
1109 WARN("waveOutOpen failed\n");
1110 HeapFree(GetProcessHeap(),0,*ippDS);
1111 *ippDS = NULL;
1112 return err;
1116 if (drv) {
1117 err = IDsDriver_Open(drv);
1118 if (err != DS_OK) {
1119 WARN("IDsDriver_Open failed\n");
1120 HeapFree(GetProcessHeap(),0,*ippDS);
1121 *ippDS = NULL;
1122 return err;
1125 /* the driver is now open, so it's now allowed to call GetCaps */
1126 err = IDsDriver_GetCaps(drv,&((*ippDS)->drvcaps));
1127 if (err != DS_OK) {
1128 WARN("IDsDriver_GetCaps failed\n");
1129 HeapFree(GetProcessHeap(),0,*ippDS);
1130 *ippDS = NULL;
1131 return err;
1133 } else {
1134 WAVEOUTCAPSA woc;
1135 err = mmErr(waveOutGetDevCapsA((*ippDS)->drvdesc.dnDevNode, &woc, sizeof(woc)));
1136 if (err != DS_OK) {
1137 WARN("waveOutGetDevCaps failed\n");
1138 HeapFree(GetProcessHeap(),0,*ippDS);
1139 *ippDS = NULL;
1140 return err;
1142 ZeroMemory(&(*ippDS)->drvcaps, sizeof((*ippDS)->drvcaps));
1143 if ((woc.dwFormats & WAVE_FORMAT_1M08) ||
1144 (woc.dwFormats & WAVE_FORMAT_2M08) ||
1145 (woc.dwFormats & WAVE_FORMAT_4M08) ||
1146 (woc.dwFormats & WAVE_FORMAT_48M08) ||
1147 (woc.dwFormats & WAVE_FORMAT_96M08)) {
1148 (*ippDS)->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT;
1149 (*ippDS)->drvcaps.dwFlags |= DSCAPS_PRIMARYMONO;
1151 if ((woc.dwFormats & WAVE_FORMAT_1M16) ||
1152 (woc.dwFormats & WAVE_FORMAT_2M16) ||
1153 (woc.dwFormats & WAVE_FORMAT_4M16) ||
1154 (woc.dwFormats & WAVE_FORMAT_48M16) ||
1155 (woc.dwFormats & WAVE_FORMAT_96M16)) {
1156 (*ippDS)->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT;
1157 (*ippDS)->drvcaps.dwFlags |= DSCAPS_PRIMARYMONO;
1159 if ((woc.dwFormats & WAVE_FORMAT_1S08) ||
1160 (woc.dwFormats & WAVE_FORMAT_2S08) ||
1161 (woc.dwFormats & WAVE_FORMAT_4S08) ||
1162 (woc.dwFormats & WAVE_FORMAT_48S08) ||
1163 (woc.dwFormats & WAVE_FORMAT_96S08)) {
1164 (*ippDS)->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT;
1165 (*ippDS)->drvcaps.dwFlags |= DSCAPS_PRIMARYSTEREO;
1167 if ((woc.dwFormats & WAVE_FORMAT_1S16) ||
1168 (woc.dwFormats & WAVE_FORMAT_2S16) ||
1169 (woc.dwFormats & WAVE_FORMAT_4S16) ||
1170 (woc.dwFormats & WAVE_FORMAT_48S16) ||
1171 (woc.dwFormats & WAVE_FORMAT_96S16)) {
1172 (*ippDS)->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT;
1173 (*ippDS)->drvcaps.dwFlags |= DSCAPS_PRIMARYSTEREO;
1175 if (ds_emuldriver)
1176 (*ippDS)->drvcaps.dwFlags |= DSCAPS_EMULDRIVER;
1177 (*ippDS)->drvcaps.dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
1178 (*ippDS)->drvcaps.dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
1179 (*ippDS)->drvcaps.dwPrimaryBuffers = 1;
1182 (*ippDS)->volpan.lVolume = 0;
1183 (*ippDS)->volpan.lPan = 0;
1184 DSOUND_RecalcVolPan(&((*ippDS)->volpan));
1186 InitializeCriticalSection(&((*ippDS)->mixlock));
1187 RtlInitializeResource(&((*ippDS)->lock));
1189 if (!dsound) {
1190 HRESULT hres;
1191 dsound = (*ippDS);
1192 hres = DSOUND_PrimaryCreate(dsound);
1193 if (hres != DS_OK) {
1194 WARN("DSOUND_PrimaryCreate failed\n");
1195 return hres;
1197 timeBeginPeriod(DS_TIME_RES);
1198 dsound->timerID = timeSetEvent(DS_TIME_DEL, DS_TIME_RES, DSOUND_timer,
1199 (DWORD)dsound, TIME_PERIODIC | TIME_CALLBACK_FUNCTION);
1202 return DS_OK;
1206 /*******************************************************************************
1207 * DirectSound ClassFactory
1210 static HRESULT WINAPI
1211 DSCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
1212 ICOM_THIS(IClassFactoryImpl,iface);
1214 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
1215 return E_NOINTERFACE;
1218 static ULONG WINAPI
1219 DSCF_AddRef(LPCLASSFACTORY iface) {
1220 ICOM_THIS(IClassFactoryImpl,iface);
1221 TRACE("(%p) ref was %ld\n", This, This->ref);
1222 return ++(This->ref);
1225 static ULONG WINAPI DSCF_Release(LPCLASSFACTORY iface) {
1226 ICOM_THIS(IClassFactoryImpl,iface);
1227 /* static class, won't be freed */
1228 TRACE("(%p) ref was %ld\n", This, This->ref);
1229 return --(This->ref);
1232 static HRESULT WINAPI DSCF_CreateInstance(
1233 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
1235 ICOM_THIS(IClassFactoryImpl,iface);
1236 TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
1238 if (ppobj == NULL) {
1239 WARN("invalid parameter\n");
1240 return DSERR_INVALIDPARAM;
1243 *ppobj = NULL;
1245 if ( IsEqualGUID( &IID_IDirectSound, riid ) ||
1246 IsEqualGUID( &IID_IDirectSound8, riid ) ) {
1247 /* FIXME: reuse already created dsound if present? */
1248 return DirectSoundCreate8(0,(LPDIRECTSOUND8*)ppobj,pOuter);
1251 WARN("(%p,%p,%s,%p) Interface not found!\n",This,pOuter,debugstr_guid(riid),ppobj);
1252 return E_NOINTERFACE;
1255 static HRESULT WINAPI DSCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
1256 ICOM_THIS(IClassFactoryImpl,iface);
1257 FIXME("(%p)->(%d),stub!\n",This,dolock);
1258 return S_OK;
1261 static ICOM_VTABLE(IClassFactory) DSCF_Vtbl = {
1262 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1263 DSCF_QueryInterface,
1264 DSCF_AddRef,
1265 DSCF_Release,
1266 DSCF_CreateInstance,
1267 DSCF_LockServer
1270 static IClassFactoryImpl DSOUND_CF = { &DSCF_Vtbl, 1 };
1272 /*******************************************************************************
1273 * DirectSoundPrivate ClassFactory
1276 static HRESULT WINAPI
1277 DSPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
1278 ICOM_THIS(IClassFactoryImpl,iface);
1280 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
1281 return E_NOINTERFACE;
1284 static ULONG WINAPI
1285 DSPCF_AddRef(LPCLASSFACTORY iface) {
1286 ICOM_THIS(IClassFactoryImpl,iface);
1287 TRACE("(%p) ref was %ld\n", This, This->ref);
1288 return ++(This->ref);
1291 static ULONG WINAPI
1292 DSPCF_Release(LPCLASSFACTORY iface) {
1293 ICOM_THIS(IClassFactoryImpl,iface);
1294 /* static class, won't be freed */
1295 TRACE("(%p) ref was %ld\n", This, This->ref);
1296 return --(This->ref);
1299 static HRESULT WINAPI
1300 DSPCF_CreateInstance(
1301 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
1303 ICOM_THIS(IClassFactoryImpl,iface);
1304 TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
1306 if (ppobj == NULL) {
1307 WARN("invalid parameter\n");
1308 return DSERR_INVALIDPARAM;
1311 *ppobj = NULL;
1313 if ( IsEqualGUID( &IID_IKsPropertySet, riid ) ) {
1314 return IKsPrivatePropertySetImpl_Create((IKsPrivatePropertySetImpl**)ppobj);
1317 WARN("(%p,%p,%s,%p) Interface not found!\n",This,pOuter,debugstr_guid(riid),ppobj);
1318 return E_NOINTERFACE;
1321 static HRESULT WINAPI
1322 DSPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
1323 ICOM_THIS(IClassFactoryImpl,iface);
1324 FIXME("(%p)->(%d),stub!\n",This,dolock);
1325 return S_OK;
1328 static ICOM_VTABLE(IClassFactory) DSPCF_Vtbl = {
1329 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1330 DSPCF_QueryInterface,
1331 DSPCF_AddRef,
1332 DSPCF_Release,
1333 DSPCF_CreateInstance,
1334 DSPCF_LockServer
1337 static IClassFactoryImpl DSOUND_PRIVATE_CF = { &DSPCF_Vtbl, 1 };
1339 /*******************************************************************************
1340 * DllGetClassObject [DSOUND.5]
1341 * Retrieves class object from a DLL object
1343 * NOTES
1344 * Docs say returns STDAPI
1346 * PARAMS
1347 * rclsid [I] CLSID for the class object
1348 * riid [I] Reference to identifier of interface for class object
1349 * ppv [O] Address of variable to receive interface pointer for riid
1351 * RETURNS
1352 * Success: S_OK
1353 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
1354 * E_UNEXPECTED
1356 DWORD WINAPI DSOUND_DllGetClassObject(REFCLSID rclsid,REFIID riid,LPVOID *ppv)
1358 TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
1360 if (ppv == NULL) {
1361 WARN("invalid parameter\n");
1362 return E_INVALIDARG;
1365 *ppv = NULL;
1367 if ( IsEqualCLSID( &CLSID_DirectSound, rclsid ) ||
1368 IsEqualCLSID( &CLSID_DirectSound8, rclsid ) ) {
1369 if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) {
1370 *ppv = (LPVOID)&DSOUND_CF;
1371 IClassFactory_AddRef((IClassFactory*)*ppv);
1372 return S_OK;
1374 WARN("(%s,%s,%p): no interface found.\n",
1375 debugstr_guid(rclsid), debugstr_guid(riid), ppv);
1376 return S_FALSE;
1379 if ( IsEqualCLSID( &CLSID_DirectSoundCapture, rclsid ) ||
1380 IsEqualCLSID( &CLSID_DirectSoundCapture8, rclsid ) ) {
1381 if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) {
1382 *ppv = (LPVOID)&DSOUND_CAPTURE_CF;
1383 IClassFactory_AddRef((IClassFactory*)*ppv);
1384 return S_OK;
1386 WARN("(%s,%s,%p): no interface found.\n",
1387 debugstr_guid(rclsid), debugstr_guid(riid), ppv);
1388 return S_FALSE;
1391 if ( IsEqualCLSID( &CLSID_DirectSoundFullDuplex, rclsid ) ) {
1392 if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) {
1393 *ppv = (LPVOID)&DSOUND_FULLDUPLEX_CF;
1394 IClassFactory_AddRef((IClassFactory*)*ppv);
1395 return S_OK;
1397 WARN("(%s,%s,%p): no interface found.\n",
1398 debugstr_guid(rclsid), debugstr_guid(riid), ppv);
1399 return S_FALSE;
1402 if ( IsEqualCLSID( &CLSID_DirectSoundPrivate, rclsid ) ) {
1403 if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) {
1404 *ppv = (LPVOID)&DSOUND_PRIVATE_CF;
1405 IClassFactory_AddRef((IClassFactory*)*ppv);
1406 return S_OK;
1408 WARN("(%s,%s,%p): no interface found.\n",
1409 debugstr_guid(rclsid), debugstr_guid(riid), ppv);
1410 return S_FALSE;
1413 WARN("(%s,%s,%p): no class found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
1414 return CLASS_E_CLASSNOTAVAILABLE;
1418 /*******************************************************************************
1419 * DllCanUnloadNow [DSOUND.4]
1420 * Determines whether the DLL is in use.
1422 * RETURNS
1423 * Success: S_OK
1424 * Failure: S_FALSE
1426 DWORD WINAPI DSOUND_DllCanUnloadNow(void)
1428 FIXME("(void): stub\n");
1429 return S_FALSE;