Set version to DirectX 7.
[wine/dcerpc.git] / dlls / dsound / dsound_main.c
blob0917bf890da15338c6198efd5f555ad065060659
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 *ppdsb=(LPDIRECTSOUNDBUFFER8)This->primary;
533 if (*ppdsb==NULL)
534 WARN("PrimaryBuffer_Create failed\n");
535 else {
536 This->dsbd = *dsbd;
537 IDirectSoundBuffer_AddRef(*ppdsb);
539 } else {
540 hres = SecondaryBuffer_Create(This, (IDirectSoundBufferImpl**)ppdsb, dsbd);
541 if (hres != DS_OK)
542 WARN("SecondaryBuffer_Create failed\n");
543 else
544 IDirectSoundBuffer_AddRef(*ppdsb);
547 return hres;
550 static HRESULT WINAPI IDirectSoundImpl_DuplicateSoundBuffer(
551 LPDIRECTSOUND8 iface,LPDIRECTSOUNDBUFFER8 pdsb,LPLPDIRECTSOUNDBUFFER8 ppdsb
553 ICOM_THIS(IDirectSoundImpl,iface);
554 IDirectSoundBufferImpl* ipdsb=(IDirectSoundBufferImpl*)pdsb;
555 IDirectSoundBufferImpl* dsb;
556 TRACE("(%p,%p,%p)\n",This,pdsb,ppdsb);
558 if (This == NULL) {
559 WARN("invalid parameter: This == NULL\n");
560 return DSERR_INVALIDPARAM;
563 if (pdsb == NULL) {
564 WARN("invalid parameter: pdsb == NULL\n");
565 return DSERR_INVALIDPARAM;
568 if (ppdsb == NULL) {
569 WARN("invalid parameter: ppdsb == NULL\n");
570 return DSERR_INVALIDPARAM;
573 if (ipdsb->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER) {
574 ERR("trying to duplicate primary buffer\n");
575 *ppdsb = NULL;
576 return DSERR_INVALIDCALL;
579 if (ipdsb->hwbuf) {
580 FIXME("need to duplicate hardware buffer\n");
581 *ppdsb = NULL;
582 return DSERR_INVALIDCALL;
585 dsb = (IDirectSoundBufferImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb));
587 if (dsb == NULL) {
588 WARN("out of memory\n");
589 *ppdsb = NULL;
590 return DSERR_OUTOFMEMORY;
593 memcpy(dsb, ipdsb, sizeof(IDirectSoundBufferImpl));
594 dsb->ref = 1;
595 dsb->state = STATE_STOPPED;
596 dsb->playpos = 0;
597 dsb->buf_mixpos = 0;
598 dsb->dsound = This;
599 dsb->buffer->ref++;
600 dsb->hwbuf = NULL;
601 dsb->ds3db = NULL;
602 dsb->iks = NULL; /* FIXME? */
603 memcpy(&(dsb->wfx), &(ipdsb->wfx), sizeof(dsb->wfx));
604 InitializeCriticalSection(&(dsb->lock));
605 /* register buffer */
606 RtlAcquireResourceExclusive(&(This->lock), TRUE);
608 IDirectSoundBufferImpl **newbuffers = (IDirectSoundBufferImpl**)HeapReAlloc(GetProcessHeap(),0,This->buffers,sizeof(IDirectSoundBufferImpl**)*(This->nrofbuffers+1));
609 if (newbuffers) {
610 This->buffers = newbuffers;
611 This->buffers[This->nrofbuffers] = dsb;
612 This->nrofbuffers++;
613 TRACE("buffer count is now %d\n", This->nrofbuffers);
614 } else {
615 ERR("out of memory for buffer list! Current buffer count is %d\n", This->nrofbuffers);
616 IDirectSoundBuffer8_Release(pdsb);
617 DeleteCriticalSection(&(dsb->lock));
618 RtlReleaseResource(&(This->lock));
619 HeapFree(GetProcessHeap(),0,dsb);
620 *ppdsb = 0;
621 return DSERR_OUTOFMEMORY;
624 RtlReleaseResource(&(This->lock));
625 IDirectSound_AddRef(iface);
626 *ppdsb = (LPDIRECTSOUNDBUFFER8)dsb;
627 return DS_OK;
631 static HRESULT WINAPI IDirectSoundImpl_GetCaps(LPDIRECTSOUND8 iface,LPDSCAPS lpDSCaps) {
632 ICOM_THIS(IDirectSoundImpl,iface);
633 TRACE("(%p,%p)\n",This,lpDSCaps);
635 if (This == NULL) {
636 WARN("invalid parameter: This == NULL\n");
637 return DSERR_INVALIDPARAM;
640 if (lpDSCaps == NULL) {
641 WARN("invalid parameter: lpDSCaps = NULL\n");
642 return DSERR_INVALIDPARAM;
645 /* check is there is enough room */
646 if (lpDSCaps->dwSize < sizeof(*lpDSCaps)) {
647 WARN("invalid parameter: lpDSCaps->dwSize = %ld < %d\n",
648 lpDSCaps->dwSize, sizeof(*lpDSCaps));
649 return DSERR_INVALIDPARAM;
652 lpDSCaps->dwFlags = This->drvcaps.dwFlags;
653 TRACE("(flags=0x%08lx)\n",lpDSCaps->dwFlags);
655 /* FIXME: copy caps from This->drv */
656 lpDSCaps->dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
657 lpDSCaps->dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
659 lpDSCaps->dwPrimaryBuffers = 1;
661 lpDSCaps->dwMaxHwMixingAllBuffers = 0;
662 lpDSCaps->dwMaxHwMixingStaticBuffers = 0;
663 lpDSCaps->dwMaxHwMixingStreamingBuffers = 0;
665 lpDSCaps->dwFreeHwMixingAllBuffers = 0;
666 lpDSCaps->dwFreeHwMixingStaticBuffers = 0;
667 lpDSCaps->dwFreeHwMixingStreamingBuffers = 0;
669 lpDSCaps->dwMaxHw3DAllBuffers = 0;
670 lpDSCaps->dwMaxHw3DStaticBuffers = 0;
671 lpDSCaps->dwMaxHw3DStreamingBuffers = 0;
673 lpDSCaps->dwFreeHw3DAllBuffers = 0;
674 lpDSCaps->dwFreeHw3DStaticBuffers = 0;
675 lpDSCaps->dwFreeHw3DStreamingBuffers = 0;
677 lpDSCaps->dwTotalHwMemBytes = 0;
679 lpDSCaps->dwFreeHwMemBytes = 0;
681 lpDSCaps->dwMaxContigFreeHwMemBytes = 0;
683 lpDSCaps->dwUnlockTransferRateHwBuffers = 4096; /* But we have none... */
685 lpDSCaps->dwPlayCpuOverheadSwBuffers = 1; /* 1% */
687 return DS_OK;
690 static ULONG WINAPI IDirectSoundImpl_AddRef(LPDIRECTSOUND8 iface) {
691 ICOM_THIS(IDirectSoundImpl,iface);
692 TRACE("(%p) ref was %ld, thread is %04lx\n", This, This->ref, GetCurrentThreadId());
693 return InterlockedIncrement(&This->ref);
696 static ULONG WINAPI IDirectSoundImpl_Release(LPDIRECTSOUND8 iface) {
697 ICOM_THIS(IDirectSoundImpl,iface);
698 ULONG ulReturn;
700 TRACE("(%p) ref was %ld, thread is %04lx\n", This, This->ref, GetCurrentThreadId());
701 ulReturn = InterlockedDecrement(&This->ref);
703 if (ulReturn == 0) {
704 HRESULT hres;
705 UINT i;
707 timeKillEvent(This->timerID);
708 timeEndPeriod(DS_TIME_RES);
709 /* wait for timer to expire */
710 Sleep(DS_TIME_RES+1);
712 RtlAcquireResourceShared(&(This->lock), TRUE);
714 if (This->buffers) {
715 for( i=0;i<This->nrofbuffers;i++)
716 IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)This->buffers[i]);
719 RtlReleaseResource(&(This->lock));
721 if (This->primary)
722 IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)This->primary);
724 hres = DSOUND_PrimaryDestroy(This);
725 if (hres != DS_OK)
726 WARN("DSOUND_PrimaryDestroy failed\n");
728 if (This->driver)
729 IDsDriver_Close(This->driver);
731 if (This->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN)
732 waveOutClose(This->hwo);
734 if (This->driver)
735 IDsDriver_Release(This->driver);
737 RtlDeleteResource(&This->lock);
738 DeleteCriticalSection(&This->mixlock);
739 DeleteCriticalSection(&This->ds3dl_lock);
740 HeapFree(GetProcessHeap(),0,This);
741 dsound = NULL;
742 return 0;
744 return ulReturn;
747 static HRESULT WINAPI IDirectSoundImpl_SetSpeakerConfig(
748 LPDIRECTSOUND8 iface,DWORD config
750 ICOM_THIS(IDirectSoundImpl,iface);
751 FIXME("(%p,0x%08lx):stub\n",This,config);
752 return DS_OK;
755 static HRESULT WINAPI IDirectSoundImpl_QueryInterface(
756 LPDIRECTSOUND8 iface,REFIID riid,LPVOID *ppobj
758 ICOM_THIS(IDirectSoundImpl,iface);
759 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
761 if (ppobj == NULL) {
762 WARN("invalid parameter\n");
763 return E_INVALIDARG;
766 *ppobj = NULL; /* assume failure */
768 if ( IsEqualGUID(riid, &IID_IUnknown) ||
769 IsEqualGUID(riid, &IID_IDirectSound) ||
770 IsEqualGUID(riid, &IID_IDirectSound8) ) {
771 IDirectSound8_AddRef((LPDIRECTSOUND8)This);
772 *ppobj = This;
773 return S_OK;
776 if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
777 WARN("app requested IDirectSound3DListener on dsound object\n");
778 return E_NOINTERFACE;
781 FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
782 return E_NOINTERFACE;
785 static HRESULT WINAPI IDirectSoundImpl_Compact(
786 LPDIRECTSOUND8 iface)
788 ICOM_THIS(IDirectSoundImpl,iface);
789 TRACE("(%p)\n", This);
790 return DS_OK;
793 static HRESULT WINAPI IDirectSoundImpl_GetSpeakerConfig(
794 LPDIRECTSOUND8 iface,
795 LPDWORD lpdwSpeakerConfig)
797 ICOM_THIS(IDirectSoundImpl,iface);
798 TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
799 *lpdwSpeakerConfig = DSSPEAKER_STEREO | (DSSPEAKER_GEOMETRY_NARROW << 16);
800 return DS_OK;
803 static HRESULT WINAPI IDirectSoundImpl_Initialize(
804 LPDIRECTSOUND8 iface,
805 LPCGUID lpcGuid)
807 ICOM_THIS(IDirectSoundImpl,iface);
808 TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
809 return DS_OK;
812 static HRESULT WINAPI IDirectSoundImpl_VerifyCertification(
813 LPDIRECTSOUND8 iface,
814 LPDWORD pdwCertified)
816 ICOM_THIS(IDirectSoundImpl,iface);
817 TRACE("(%p, %p)\n", This, pdwCertified);
818 *pdwCertified = DS_CERTIFIED;
819 return DS_OK;
822 static ICOM_VTABLE(IDirectSound8) dsvt =
824 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
825 IDirectSoundImpl_QueryInterface,
826 IDirectSoundImpl_AddRef,
827 IDirectSoundImpl_Release,
828 IDirectSoundImpl_CreateSoundBuffer,
829 IDirectSoundImpl_GetCaps,
830 IDirectSoundImpl_DuplicateSoundBuffer,
831 IDirectSoundImpl_SetCooperativeLevel,
832 IDirectSoundImpl_Compact,
833 IDirectSoundImpl_GetSpeakerConfig,
834 IDirectSoundImpl_SetSpeakerConfig,
835 IDirectSoundImpl_Initialize,
836 IDirectSoundImpl_VerifyCertification
840 /*******************************************************************************
841 * DirectSoundCreate (DSOUND.1)
843 * Creates and initializes a DirectSound interface.
845 * PARAMS
846 * lpcGUID [I] Address of the GUID that identifies the sound device.
847 * ppDS [O] Address of a variable to receive the interface pointer.
848 * pUnkOuter [I] Must be NULL.
850 * RETURNS
851 * Success: DS_OK
852 * Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
853 * DSERR_NODRIVER, DSERR_OUTOFMEMORY
855 HRESULT WINAPI DirectSoundCreate8(LPCGUID lpcGUID,LPDIRECTSOUND8 *ppDS,IUnknown *pUnkOuter )
857 IDirectSoundImpl** ippDS=(IDirectSoundImpl**)ppDS;
858 PIDSDRIVER drv = NULL;
859 unsigned wod, wodn;
860 HRESULT err = DSERR_INVALIDPARAM;
861 GUID devGuid;
862 BOOLEAN found = FALSE;
864 TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ippDS,pUnkOuter);
866 if (ippDS == NULL) {
867 WARN("invalid parameter: ippDS == NULL\n");
868 return DSERR_INVALIDPARAM;
871 /* Get dsound configuration */
872 setup_dsound_options();
874 /* Default device? */
875 if (!lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL))
876 lpcGUID = &DSDEVID_DefaultPlayback;
878 if (GetDeviceID(lpcGUID, &devGuid) != DS_OK) {
879 WARN("invalid parameter: lpcGUID\n");
880 *ippDS = NULL;
881 return DSERR_INVALIDPARAM;
884 if (dsound) {
885 if (IsEqualGUID(&devGuid, &dsound->guid) ) {
886 ERR("dsound already opened\n");
887 IDirectSound_AddRef((LPDIRECTSOUND)dsound);
888 *ippDS = dsound;
889 return DS_OK;
890 } else {
891 ERR("different dsound already opened\n");
895 /* Enumerate WINMM audio devices and find the one we want */
896 wodn = waveOutGetNumDevs();
897 if (!wodn) {
898 WARN("no driver\n");
899 *ippDS = NULL;
900 return DSERR_NODRIVER;
903 TRACE(" expecting GUID %s.\n", debugstr_guid(&devGuid));
905 for (wod=0; wod<wodn; wod++) {
906 GUID guid;
907 err = mmErr(waveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDGUID,(DWORD)(&guid),0));
908 if (err != DS_OK) {
909 WARN("waveOutMessage failed; err=%lx\n",err);
910 *ippDS = NULL;
911 return err;
913 TRACE("got GUID %s for wod %d.\n", debugstr_guid(&guid), wod);
914 if (IsEqualGUID( &devGuid, &guid) ) {
915 err = DS_OK;
916 found = TRUE;
917 break;
921 if (err != DS_OK) {
922 WARN("invalid parameter\n");
923 *ippDS = NULL;
924 return DSERR_INVALIDPARAM;
927 if (found == FALSE) {
928 WARN("No device found matching given ID - trying with default one !\n");
929 wod = ds_default_playback;
932 /* DRV_QUERYDSOUNDIFACE is a "Wine extension" to get the DSound interface */
933 waveOutMessage((HWAVEOUT)wod, DRV_QUERYDSOUNDIFACE, (DWORD)&drv, 0);
935 /* Disable the direct sound driver to force emulation if requested. */
936 if (ds_hw_accel == DS_HW_ACCEL_EMULATION)
937 drv = NULL;
939 /* Allocate memory */
940 *ippDS = (IDirectSoundImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundImpl));
941 if (*ippDS == NULL) {
942 WARN("out of memory\n");
943 return DSERR_OUTOFMEMORY;
946 (*ippDS)->lpVtbl = &dsvt;
947 (*ippDS)->ref = 1;
949 (*ippDS)->driver = drv;
950 (*ippDS)->priolevel = DSSCL_NORMAL;
951 (*ippDS)->fraglen = 0;
952 (*ippDS)->hwbuf = NULL;
953 (*ippDS)->buffer = NULL;
954 (*ippDS)->buflen = 0;
955 (*ippDS)->writelead = 0;
956 (*ippDS)->state = STATE_STOPPED;
957 (*ippDS)->nrofbuffers = 0;
958 (*ippDS)->buffers = NULL;
959 (*ippDS)->primary = NULL;
961 /* 3D listener initial parameters */
962 (*ippDS)->listener = NULL;
963 (*ippDS)->ds3dl.dwSize = sizeof(DS3DLISTENER);
964 (*ippDS)->ds3dl.vPosition.u1.x = 0.0;
965 (*ippDS)->ds3dl.vPosition.u2.y = 0.0;
966 (*ippDS)->ds3dl.vPosition.u3.z = 0.0;
967 (*ippDS)->ds3dl.vVelocity.u1.x = 0.0;
968 (*ippDS)->ds3dl.vVelocity.u2.y = 0.0;
969 (*ippDS)->ds3dl.vVelocity.u3.z = 0.0;
970 (*ippDS)->ds3dl.vOrientFront.u1.x = 0.0;
971 (*ippDS)->ds3dl.vOrientFront.u2.y = 0.0;
972 (*ippDS)->ds3dl.vOrientFront.u3.z = 1.0;
973 (*ippDS)->ds3dl.vOrientTop.u1.x = 0.0;
974 (*ippDS)->ds3dl.vOrientTop.u2.y = 1.0;
975 (*ippDS)->ds3dl.vOrientTop.u3.z = 0.0;
976 (*ippDS)->ds3dl.flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
977 (*ippDS)->ds3dl.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
978 (*ippDS)->ds3dl.flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
980 InitializeCriticalSection(&(*ippDS)->ds3dl_lock);
982 (*ippDS)->prebuf = ds_snd_queue_max;
983 (*ippDS)->guid = devGuid;
985 /* Get driver description */
986 if (drv) {
987 err = IDsDriver_GetDriverDesc(drv,&((*ippDS)->drvdesc));
988 if (err != DS_OK) {
989 WARN("IDsDriver_GetDriverDesc failed\n");
990 HeapFree(GetProcessHeap(),0,*ippDS);
991 *ippDS = NULL;
992 return err;
994 } else {
995 /* if no DirectSound interface available, use WINMM API instead */
996 (*ippDS)->drvdesc.dwFlags = DSDDESC_DOMMSYSTEMOPEN | DSDDESC_DOMMSYSTEMSETFORMAT;
999 (*ippDS)->drvdesc.dnDevNode = wod;
1001 /* Set default wave format (may need it for waveOutOpen) */
1002 (*ippDS)->wfx.wFormatTag = WAVE_FORMAT_PCM;
1003 /* We rely on the sound driver to return the actual sound format of
1004 * the device if it does not support 22050x8x2 and is given the
1005 * WAVE_DIRECTSOUND flag.
1007 (*ippDS)->wfx.nSamplesPerSec = 22050;
1008 (*ippDS)->wfx.wBitsPerSample = 8;
1009 (*ippDS)->wfx.nChannels = 2;
1010 (*ippDS)->wfx.nBlockAlign = (*ippDS)->wfx.wBitsPerSample * (*ippDS)->wfx.nChannels / 8;
1011 (*ippDS)->wfx.nAvgBytesPerSec = (*ippDS)->wfx.nSamplesPerSec * (*ippDS)->wfx.nBlockAlign;
1012 (*ippDS)->wfx.cbSize = 0;
1014 /* If the driver requests being opened through MMSYSTEM
1015 * (which is recommended by the DDK), it is supposed to happen
1016 * before the DirectSound interface is opened */
1017 if ((*ippDS)->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN)
1019 DWORD flags = CALLBACK_FUNCTION;
1021 /* disable direct sound if requested */
1022 if (ds_hw_accel != DS_HW_ACCEL_EMULATION)
1023 flags |= WAVE_DIRECTSOUND;
1025 err = mmErr(waveOutOpen(&((*ippDS)->hwo),
1026 (*ippDS)->drvdesc.dnDevNode, &((*ippDS)->wfx),
1027 (DWORD)DSOUND_callback, (DWORD)(*ippDS),
1028 flags));
1029 if (err != DS_OK) {
1030 WARN("waveOutOpen failed\n");
1031 HeapFree(GetProcessHeap(),0,*ippDS);
1032 *ippDS = NULL;
1033 return err;
1037 if (drv) {
1038 err = IDsDriver_Open(drv);
1039 if (err != DS_OK) {
1040 WARN("IDsDriver_Open failed\n");
1041 HeapFree(GetProcessHeap(),0,*ippDS);
1042 *ippDS = NULL;
1043 return err;
1046 /* the driver is now open, so it's now allowed to call GetCaps */
1047 err = IDsDriver_GetCaps(drv,&((*ippDS)->drvcaps));
1048 if (err != DS_OK) {
1049 WARN("IDsDriver_GetCaps failed\n");
1050 HeapFree(GetProcessHeap(),0,*ippDS);
1051 *ippDS = NULL;
1052 return err;
1054 } else {
1055 WAVEOUTCAPSA woc;
1056 err = mmErr(waveOutGetDevCapsA((*ippDS)->drvdesc.dnDevNode, &woc, sizeof(woc)));
1057 if (err != DS_OK) {
1058 WARN("waveOutGetDevCaps failed\n");
1059 HeapFree(GetProcessHeap(),0,*ippDS);
1060 *ippDS = NULL;
1061 return err;
1063 (*ippDS)->drvcaps.dwFlags = 0;
1064 if ((woc.dwFormats & WAVE_FORMAT_1M08) ||
1065 (woc.dwFormats & WAVE_FORMAT_2M08) ||
1066 (woc.dwFormats & WAVE_FORMAT_4M08) ||
1067 (woc.dwFormats & WAVE_FORMAT_48M08) ||
1068 (woc.dwFormats & WAVE_FORMAT_96M08)) {
1069 (*ippDS)->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT;
1070 (*ippDS)->drvcaps.dwFlags |= DSCAPS_PRIMARYMONO;
1072 if ((woc.dwFormats & WAVE_FORMAT_1M16) ||
1073 (woc.dwFormats & WAVE_FORMAT_2M16) ||
1074 (woc.dwFormats & WAVE_FORMAT_4M16) ||
1075 (woc.dwFormats & WAVE_FORMAT_48M16) ||
1076 (woc.dwFormats & WAVE_FORMAT_96M16)) {
1077 (*ippDS)->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT;
1078 (*ippDS)->drvcaps.dwFlags |= DSCAPS_PRIMARYMONO;
1080 if ((woc.dwFormats & WAVE_FORMAT_1S08) ||
1081 (woc.dwFormats & WAVE_FORMAT_2S08) ||
1082 (woc.dwFormats & WAVE_FORMAT_4S08) ||
1083 (woc.dwFormats & WAVE_FORMAT_48S08) ||
1084 (woc.dwFormats & WAVE_FORMAT_96S08)) {
1085 (*ippDS)->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT;
1086 (*ippDS)->drvcaps.dwFlags |= DSCAPS_PRIMARYSTEREO;
1088 if ((woc.dwFormats & WAVE_FORMAT_1S16) ||
1089 (woc.dwFormats & WAVE_FORMAT_2S16) ||
1090 (woc.dwFormats & WAVE_FORMAT_4S16) ||
1091 (woc.dwFormats & WAVE_FORMAT_48S16) ||
1092 (woc.dwFormats & WAVE_FORMAT_96S16)) {
1093 (*ippDS)->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT;
1094 (*ippDS)->drvcaps.dwFlags |= DSCAPS_PRIMARYSTEREO;
1096 if (ds_emuldriver)
1097 (*ippDS)->drvcaps.dwFlags |= DSCAPS_EMULDRIVER;
1100 DSOUND_RecalcVolPan(&((*ippDS)->volpan));
1102 InitializeCriticalSection(&((*ippDS)->mixlock));
1103 RtlInitializeResource(&((*ippDS)->lock));
1105 if (!dsound) {
1106 HRESULT hres;
1107 dsound = (*ippDS);
1108 hres = DSOUND_PrimaryCreate(dsound);
1109 if (hres != DS_OK) {
1110 WARN("DSOUND_PrimaryCreate failed\n");
1111 return hres;
1113 timeBeginPeriod(DS_TIME_RES);
1114 dsound->timerID = timeSetEvent(DS_TIME_DEL, DS_TIME_RES, DSOUND_timer,
1115 (DWORD)dsound, TIME_PERIODIC | TIME_CALLBACK_FUNCTION);
1118 /* create a user accessable primary buffer */
1119 (*ippDS)->dsbd.dwSize = sizeof((*ippDS)->dsbd);
1120 err = PrimaryBuffer_Create((*ippDS), (PrimaryBufferImpl**)&((*ippDS)->primary), &((*ippDS)->dsbd));
1121 if ((*ippDS)->primary)
1122 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(*ippDS)->primary);
1123 else
1124 WARN("PrimaryBuffer_Create failed\n");
1126 return err;
1130 /*******************************************************************************
1131 * DirectSound ClassFactory
1134 static HRESULT WINAPI
1135 DSCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
1136 ICOM_THIS(IClassFactoryImpl,iface);
1138 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
1139 return E_NOINTERFACE;
1142 static ULONG WINAPI
1143 DSCF_AddRef(LPCLASSFACTORY iface) {
1144 ICOM_THIS(IClassFactoryImpl,iface);
1145 TRACE("(%p) ref was %ld\n", This, This->ref);
1146 return ++(This->ref);
1149 static ULONG WINAPI DSCF_Release(LPCLASSFACTORY iface) {
1150 ICOM_THIS(IClassFactoryImpl,iface);
1151 /* static class, won't be freed */
1152 TRACE("(%p) ref was %ld\n", This, This->ref);
1153 return --(This->ref);
1156 static HRESULT WINAPI DSCF_CreateInstance(
1157 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
1159 ICOM_THIS(IClassFactoryImpl,iface);
1160 TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
1162 if (ppobj == NULL) {
1163 WARN("invalid parameter\n");
1164 return DSERR_INVALIDPARAM;
1167 *ppobj = NULL;
1169 if ( IsEqualGUID( &IID_IDirectSound, riid ) ||
1170 IsEqualGUID( &IID_IDirectSound8, riid ) ) {
1171 /* FIXME: reuse already created dsound if present? */
1172 return DirectSoundCreate8(0,(LPDIRECTSOUND8*)ppobj,pOuter);
1175 WARN("(%p,%p,%s,%p) Interface not found!\n",This,pOuter,debugstr_guid(riid),ppobj);
1176 return E_NOINTERFACE;
1179 static HRESULT WINAPI DSCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
1180 ICOM_THIS(IClassFactoryImpl,iface);
1181 FIXME("(%p)->(%d),stub!\n",This,dolock);
1182 return S_OK;
1185 static ICOM_VTABLE(IClassFactory) DSCF_Vtbl = {
1186 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1187 DSCF_QueryInterface,
1188 DSCF_AddRef,
1189 DSCF_Release,
1190 DSCF_CreateInstance,
1191 DSCF_LockServer
1194 static IClassFactoryImpl DSOUND_CF = { &DSCF_Vtbl, 1 };
1196 /*******************************************************************************
1197 * DirectSoundPrivate ClassFactory
1200 static HRESULT WINAPI
1201 DSPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
1202 ICOM_THIS(IClassFactoryImpl,iface);
1204 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
1205 return E_NOINTERFACE;
1208 static ULONG WINAPI
1209 DSPCF_AddRef(LPCLASSFACTORY iface) {
1210 ICOM_THIS(IClassFactoryImpl,iface);
1211 TRACE("(%p) ref was %ld\n", This, This->ref);
1212 return ++(This->ref);
1215 static ULONG WINAPI
1216 DSPCF_Release(LPCLASSFACTORY iface) {
1217 ICOM_THIS(IClassFactoryImpl,iface);
1218 /* static class, won't be freed */
1219 TRACE("(%p) ref was %ld\n", This, This->ref);
1220 return --(This->ref);
1223 static HRESULT WINAPI
1224 DSPCF_CreateInstance(
1225 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
1227 ICOM_THIS(IClassFactoryImpl,iface);
1228 TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
1230 if (ppobj == NULL) {
1231 WARN("invalid parameter\n");
1232 return DSERR_INVALIDPARAM;
1235 *ppobj = NULL;
1237 if ( IsEqualGUID( &IID_IKsPropertySet, riid ) ) {
1238 return IKsPropertySetImpl_Create(0,(IKsPropertySetImpl**)ppobj);
1241 WARN("(%p,%p,%s,%p) Interface not found!\n",This,pOuter,debugstr_guid(riid),ppobj);
1242 return E_NOINTERFACE;
1245 static HRESULT WINAPI
1246 DSPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
1247 ICOM_THIS(IClassFactoryImpl,iface);
1248 FIXME("(%p)->(%d),stub!\n",This,dolock);
1249 return S_OK;
1252 static ICOM_VTABLE(IClassFactory) DSPCF_Vtbl = {
1253 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1254 DSPCF_QueryInterface,
1255 DSPCF_AddRef,
1256 DSPCF_Release,
1257 DSPCF_CreateInstance,
1258 DSPCF_LockServer
1261 static IClassFactoryImpl DSOUND_PRIVATE_CF = { &DSPCF_Vtbl, 1 };
1263 /*******************************************************************************
1264 * DllGetClassObject [DSOUND.5]
1265 * Retrieves class object from a DLL object
1267 * NOTES
1268 * Docs say returns STDAPI
1270 * PARAMS
1271 * rclsid [I] CLSID for the class object
1272 * riid [I] Reference to identifier of interface for class object
1273 * ppv [O] Address of variable to receive interface pointer for riid
1275 * RETURNS
1276 * Success: S_OK
1277 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
1278 * E_UNEXPECTED
1280 DWORD WINAPI DSOUND_DllGetClassObject(REFCLSID rclsid,REFIID riid,LPVOID *ppv)
1282 TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
1284 if (ppv == NULL) {
1285 WARN("invalid parameter\n");
1286 return E_INVALIDARG;
1289 *ppv = NULL;
1291 if ( IsEqualCLSID( &CLSID_DirectSound, rclsid ) ||
1292 IsEqualCLSID( &CLSID_DirectSound8, rclsid ) ) {
1293 if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) {
1294 *ppv = (LPVOID)&DSOUND_CF;
1295 IClassFactory_AddRef((IClassFactory*)*ppv);
1296 return S_OK;
1298 WARN("(%s,%s,%p): no interface found.\n",
1299 debugstr_guid(rclsid), debugstr_guid(riid), ppv);
1300 return S_FALSE;
1303 if ( IsEqualCLSID( &CLSID_DirectSoundCapture, rclsid ) ||
1304 IsEqualCLSID( &CLSID_DirectSoundCapture8, rclsid ) ) {
1305 if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) {
1306 *ppv = (LPVOID)&DSOUND_CAPTURE_CF;
1307 IClassFactory_AddRef((IClassFactory*)*ppv);
1308 return S_OK;
1310 WARN("(%s,%s,%p): no interface found.\n",
1311 debugstr_guid(rclsid), debugstr_guid(riid), ppv);
1312 return S_FALSE;
1315 if ( IsEqualCLSID( &CLSID_DirectSoundFullDuplex, rclsid ) ) {
1316 if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) {
1317 *ppv = (LPVOID)&DSOUND_FULLDUPLEX_CF;
1318 IClassFactory_AddRef((IClassFactory*)*ppv);
1319 return S_OK;
1321 WARN("(%s,%s,%p): no interface found.\n",
1322 debugstr_guid(rclsid), debugstr_guid(riid), ppv);
1323 return S_FALSE;
1326 if ( IsEqualCLSID( &CLSID_DirectSoundPrivate, rclsid ) ) {
1327 if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) {
1328 *ppv = (LPVOID)&DSOUND_PRIVATE_CF;
1329 IClassFactory_AddRef((IClassFactory*)*ppv);
1330 return S_OK;
1332 WARN("(%s,%s,%p): no interface found.\n",
1333 debugstr_guid(rclsid), debugstr_guid(riid), ppv);
1334 return S_FALSE;
1337 WARN("(%s,%s,%p): no class found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
1338 return CLASS_E_CLASSNOTAVAILABLE;
1342 /*******************************************************************************
1343 * DllCanUnloadNow [DSOUND.4]
1344 * Determines whether the DLL is in use.
1346 * RETURNS
1347 * Success: S_OK
1348 * Failure: S_FALSE
1350 DWORD WINAPI DSOUND_DllCanUnloadNow(void)
1352 FIXME("(void): stub\n");
1353 return S_FALSE;