Fixup compile
[wine/multimedia.git] / dlls / dsound / dsound_main.c
blob04537ca905a9972bf862e6f9e8c449890d1474e3
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 * Most thread locking is complete. There may be a few race
22 * conditions still lurking.
24 * TODO:
25 * Implement SetCooperativeLevel properly (need to address focus issues)
26 * Implement DirectSound3DBuffers (stubs in place)
27 * Use hardware 3D support if available
28 * Add critical section locking inside Release and AddRef methods
29 * Handle static buffers - put those in hardware, non-static not in hardware
30 * Hardware DuplicateSoundBuffer
31 * Proper volume calculation for 3d buffers
32 * Remove DS_HEL_FRAGS and use mixer fragment length for it
35 #ifdef __WINESRC__
37 #include "config.h"
38 #include <stdarg.h>
39 #include "wine/port.h"
40 #include "wine/library.h"
42 #define COBJMACROS
43 #define NONAMELESSSTRUCT
44 #define NONAMELESSUNION
45 #include "config.h"
46 #include "wine/port.h"
47 #include <stdarg.h>
48 #include "wine/library.h"
50 #include "windef.h"
51 #include "winbase.h"
52 #include "winuser.h"
53 #include "winnls.h"
54 #include "winreg.h"
55 #include "mmsystem.h"
56 #include "winternl.h"
57 #include "mmddk.h"
58 #include "wine/debug.h"
59 #include "dsound.h"
60 #include "dsconf.h"
61 #include "ks.h"
62 #include "rpcproxy.h"
63 #include "rpc.h"
64 #include "rpcndr.h"
65 #include "unknwn.h"
66 #include "oleidl.h"
67 #include "shobjidl.h"
69 #include "initguid.h"
70 #include "ksmedia.h"
71 #include "propkey.h"
72 #include "devpkey.h"
74 #include "dsound_private.h"
76 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
78 #else
80 #include <stdarg.h>
82 #define WINVER 0x0600
83 #include <windows.h>
84 #include <dsound.h>
86 #include "dsound_private.h"
88 #ifndef CP_UNIXCP
89 #define CP_UNIXCP 65010
90 #endif
92 DEFINE_GUID(CLSID_DirectSoundPrivate,0x11ab3ec0,0x25ec,0x11d1,0xa4,0xd8,0x00,0xc0,0x4f,0xc2,0x8a,0xca);
94 int LogLevel = 1;
96 #endif
98 GUID DSOUND_renderer_guids[MAXWAVEDRIVERS];
99 GUID DSOUND_capture_guids[MAXWAVEDRIVERS];
101 WCHAR wine_vxd_drv[] = { 'w','i','n','e','m','m','.','v','x','d', 0 };
103 static HINSTANCE instance;
105 const IID DSPROPSETID_EAX20_ListenerProperties = {
106 0x0306a6a8, 0xb224, 0x11d2, { 0x99, 0xe5, 0x00, 0x00, 0xe8, 0xd8, 0xc7, 0x22 }
109 const IID DSPROPSETID_EAX20_BufferProperties = {
110 0x0306a6a7, 0xb224, 0x11d2, { 0x99, 0xe5, 0x00, 0x00, 0xe8, 0xd8, 0xc7, 0x22 }
113 const EAXLISTENERPROPERTIES EnvironmentDefaults[EAX_ENVIRONMENT_COUNT] =
115 REVERB_PRESET_GENERIC,
116 REVERB_PRESET_PADDEDCELL,
117 REVERB_PRESET_ROOM,
118 REVERB_PRESET_BATHROOM,
119 REVERB_PRESET_LIVINGROOM,
120 REVERB_PRESET_STONEROOM,
121 REVERB_PRESET_AUDITORIUM,
122 REVERB_PRESET_CONCERTHALL,
123 REVERB_PRESET_CAVE,
124 REVERB_PRESET_ARENA,
125 REVERB_PRESET_HANGAR,
126 REVERB_PRESET_CARPETEDHALLWAY,
127 REVERB_PRESET_HALLWAY,
128 REVERB_PRESET_STONECORRIDOR,
129 REVERB_PRESET_ALLEY,
130 REVERB_PRESET_FOREST,
131 REVERB_PRESET_CITY,
132 REVERB_PRESET_MOUNTAINS,
133 REVERB_PRESET_QUARRY,
134 REVERB_PRESET_PLAIN,
135 REVERB_PRESET_PARKINGLOT,
136 REVERB_PRESET_SEWERPIPE,
137 REVERB_PRESET_UNDERWATER,
138 REVERB_PRESET_DRUGGED,
139 REVERB_PRESET_DIZZY,
140 REVERB_PRESET_PSYCHOTIC
143 static CRITICAL_SECTION_DEBUG openal_crst_debug =
145 0, 0, &openal_crst,
146 { &openal_crst_debug.ProcessLocksList,
147 &openal_crst_debug.ProcessLocksList },
148 0, 0, { (DWORD_PTR)(__FILE__ ": openal_crst_debug") }
150 CRITICAL_SECTION openal_crst = { &openal_crst_debug, -1, 0, 0, 0, 0 };
152 int openal_loaded = 0;
153 #ifdef SONAME_LIBOPENAL
154 static void *openal_handle = NULL;
155 LPALCCREATECONTEXT palcCreateContext = NULL;
156 LPALCMAKECONTEXTCURRENT palcMakeContextCurrent = NULL;
157 LPALCPROCESSCONTEXT palcProcessContext = NULL;
158 LPALCSUSPENDCONTEXT palcSuspendContext = NULL;
159 LPALCDESTROYCONTEXT palcDestroyContext = NULL;
160 LPALCGETCURRENTCONTEXT palcGetCurrentContext = NULL;
161 LPALCGETCONTEXTSDEVICE palcGetContextsDevice = NULL;
162 LPALCOPENDEVICE palcOpenDevice = NULL;
163 LPALCCLOSEDEVICE palcCloseDevice = NULL;
164 LPALCGETERROR palcGetError = NULL;
165 LPALCISEXTENSIONPRESENT palcIsExtensionPresent = NULL;
166 LPALCGETPROCADDRESS palcGetProcAddress = NULL;
167 LPALCGETENUMVALUE palcGetEnumValue = NULL;
168 LPALCGETSTRING palcGetString = NULL;
169 LPALCGETINTEGERV palcGetIntegerv = NULL;
170 LPALCCAPTUREOPENDEVICE palcCaptureOpenDevice = NULL;
171 LPALCCAPTURECLOSEDEVICE palcCaptureCloseDevice = NULL;
172 LPALCCAPTURESTART palcCaptureStart = NULL;
173 LPALCCAPTURESTOP palcCaptureStop = NULL;
174 LPALCCAPTURESAMPLES palcCaptureSamples = NULL;
175 LPALENABLE palEnable = NULL;
176 LPALDISABLE palDisable = NULL;
177 LPALISENABLED palIsEnabled = NULL;
178 LPALGETSTRING palGetString = NULL;
179 LPALGETBOOLEANV palGetBooleanv = NULL;
180 LPALGETINTEGERV palGetIntegerv = NULL;
181 LPALGETFLOATV palGetFloatv = NULL;
182 LPALGETDOUBLEV palGetDoublev = NULL;
183 LPALGETBOOLEAN palGetBoolean = NULL;
184 LPALGETINTEGER palGetInteger = NULL;
185 LPALGETFLOAT palGetFloat = NULL;
186 LPALGETDOUBLE palGetDouble = NULL;
187 LPALGETERROR palGetError = NULL;
188 LPALISEXTENSIONPRESENT palIsExtensionPresent = NULL;
189 LPALGETPROCADDRESS palGetProcAddress = NULL;
190 LPALGETENUMVALUE palGetEnumValue = NULL;
191 LPALLISTENERF palListenerf = NULL;
192 LPALLISTENER3F palListener3f = NULL;
193 LPALLISTENERFV palListenerfv = NULL;
194 LPALLISTENERI palListeneri = NULL;
195 LPALLISTENER3I palListener3i = NULL;
196 LPALLISTENERIV palListeneriv = NULL;
197 LPALGETLISTENERF palGetListenerf = NULL;
198 LPALGETLISTENER3F palGetListener3f = NULL;
199 LPALGETLISTENERFV palGetListenerfv = NULL;
200 LPALGETLISTENERI palGetListeneri = NULL;
201 LPALGETLISTENER3I palGetListener3i = NULL;
202 LPALGETLISTENERIV palGetListeneriv = NULL;
203 LPALGENSOURCES palGenSources = NULL;
204 LPALDELETESOURCES palDeleteSources = NULL;
205 LPALISSOURCE palIsSource = NULL;
206 LPALSOURCEF palSourcef = NULL;
207 LPALSOURCE3F palSource3f = NULL;
208 LPALSOURCEFV palSourcefv = NULL;
209 LPALSOURCEI palSourcei = NULL;
210 LPALSOURCE3I palSource3i = NULL;
211 LPALSOURCEIV palSourceiv = NULL;
212 LPALGETSOURCEF palGetSourcef = NULL;
213 LPALGETSOURCE3F palGetSource3f = NULL;
214 LPALGETSOURCEFV palGetSourcefv = NULL;
215 LPALGETSOURCEI palGetSourcei = NULL;
216 LPALGETSOURCE3I palGetSource3i = NULL;
217 LPALGETSOURCEIV palGetSourceiv = NULL;
218 LPALSOURCEPLAYV palSourcePlayv = NULL;
219 LPALSOURCESTOPV palSourceStopv = NULL;
220 LPALSOURCEREWINDV palSourceRewindv = NULL;
221 LPALSOURCEPAUSEV palSourcePausev = NULL;
222 LPALSOURCEPLAY palSourcePlay = NULL;
223 LPALSOURCESTOP palSourceStop = NULL;
224 LPALSOURCEREWIND palSourceRewind = NULL;
225 LPALSOURCEPAUSE palSourcePause = NULL;
226 LPALSOURCEQUEUEBUFFERS palSourceQueueBuffers = NULL;
227 LPALSOURCEUNQUEUEBUFFERS palSourceUnqueueBuffers = NULL;
228 LPALGENBUFFERS palGenBuffers = NULL;
229 LPALDELETEBUFFERS palDeleteBuffers = NULL;
230 LPALISBUFFER palIsBuffer = NULL;
231 LPALBUFFERF palBufferf = NULL;
232 LPALBUFFER3F palBuffer3f = NULL;
233 LPALBUFFERFV palBufferfv = NULL;
234 LPALBUFFERI palBufferi = NULL;
235 LPALBUFFER3I palBuffer3i = NULL;
236 LPALBUFFERIV palBufferiv = NULL;
237 LPALGETBUFFERF palGetBufferf = NULL;
238 LPALGETBUFFER3F palGetBuffer3f = NULL;
239 LPALGETBUFFERFV palGetBufferfv = NULL;
240 LPALGETBUFFERI palGetBufferi = NULL;
241 LPALGETBUFFER3I palGetBuffer3i = NULL;
242 LPALGETBUFFERIV palGetBufferiv = NULL;
243 LPALBUFFERDATA palBufferData = NULL;
244 LPALDOPPLERFACTOR palDopplerFactor = NULL;
245 LPALDOPPLERVELOCITY palDopplerVelocity = NULL;
246 LPALDISTANCEMODEL palDistanceModel = NULL;
247 LPALSPEEDOFSOUND palSpeedOfSound = NULL;
248 #endif
250 LPALCMAKECONTEXTCURRENT set_context;
251 LPALCGETCURRENTCONTEXT get_context;
252 BOOL local_contexts;
254 static void load_libopenal(void)
256 #ifndef __WINESRC__
257 const char *str = getenv("DSOAL_LOGLEVEL");
258 if(str && *str)
259 LogLevel = atoi(str);
260 #elif defined(SONAME_LIBOPENAL)
261 BOOL failed = FALSE;
262 char error[128];
264 openal_handle = wine_dlopen(SONAME_LIBOPENAL, RTLD_NOW, error, sizeof(error));
265 if(!openal_handle)
266 ERR("Couldn't load " SONAME_LIBOPENAL ": %s\n", error);
267 #define LOAD_FUNCPTR(f) \
268 if((p##f = wine_dlsym(openal_handle, #f, NULL, 0)) == NULL) { \
269 ERR("Couldn't lookup %s in " SONAME_LIBOPENAL "\n", #f); \
270 failed = TRUE; \
273 LOAD_FUNCPTR(alcCreateContext);
274 LOAD_FUNCPTR(alcMakeContextCurrent);
275 LOAD_FUNCPTR(alcProcessContext);
276 LOAD_FUNCPTR(alcSuspendContext);
277 LOAD_FUNCPTR(alcDestroyContext);
278 LOAD_FUNCPTR(alcGetCurrentContext);
279 LOAD_FUNCPTR(alcGetContextsDevice);
280 LOAD_FUNCPTR(alcOpenDevice);
281 LOAD_FUNCPTR(alcCloseDevice);
282 LOAD_FUNCPTR(alcGetError);
283 LOAD_FUNCPTR(alcIsExtensionPresent);
284 LOAD_FUNCPTR(alcGetProcAddress);
285 LOAD_FUNCPTR(alcGetEnumValue);
286 LOAD_FUNCPTR(alcGetString);
287 LOAD_FUNCPTR(alcGetIntegerv);
288 LOAD_FUNCPTR(alcCaptureOpenDevice);
289 LOAD_FUNCPTR(alcCaptureCloseDevice);
290 LOAD_FUNCPTR(alcCaptureStart);
291 LOAD_FUNCPTR(alcCaptureStop);
292 LOAD_FUNCPTR(alcCaptureSamples);
293 LOAD_FUNCPTR(alEnable);
294 LOAD_FUNCPTR(alDisable);
295 LOAD_FUNCPTR(alIsEnabled);
296 LOAD_FUNCPTR(alGetString);
297 LOAD_FUNCPTR(alGetBooleanv);
298 LOAD_FUNCPTR(alGetIntegerv);
299 LOAD_FUNCPTR(alGetFloatv);
300 LOAD_FUNCPTR(alGetDoublev);
301 LOAD_FUNCPTR(alGetBoolean);
302 LOAD_FUNCPTR(alGetInteger);
303 LOAD_FUNCPTR(alGetFloat);
304 LOAD_FUNCPTR(alGetDouble);
305 LOAD_FUNCPTR(alGetError);
306 LOAD_FUNCPTR(alIsExtensionPresent);
307 LOAD_FUNCPTR(alGetProcAddress);
308 LOAD_FUNCPTR(alGetEnumValue);
309 LOAD_FUNCPTR(alListenerf);
310 LOAD_FUNCPTR(alListener3f);
311 LOAD_FUNCPTR(alListenerfv);
312 LOAD_FUNCPTR(alListeneri);
313 LOAD_FUNCPTR(alListener3i);
314 LOAD_FUNCPTR(alListeneriv);
315 LOAD_FUNCPTR(alGetListenerf);
316 LOAD_FUNCPTR(alGetListener3f);
317 LOAD_FUNCPTR(alGetListenerfv);
318 LOAD_FUNCPTR(alGetListeneri);
319 LOAD_FUNCPTR(alGetListener3i);
320 LOAD_FUNCPTR(alGetListeneriv);
321 LOAD_FUNCPTR(alGenSources);
322 LOAD_FUNCPTR(alDeleteSources);
323 LOAD_FUNCPTR(alIsSource);
324 LOAD_FUNCPTR(alSourcef);
325 LOAD_FUNCPTR(alSource3f);
326 LOAD_FUNCPTR(alSourcefv);
327 LOAD_FUNCPTR(alSourcei);
328 LOAD_FUNCPTR(alSource3i);
329 LOAD_FUNCPTR(alSourceiv);
330 LOAD_FUNCPTR(alGetSourcef);
331 LOAD_FUNCPTR(alGetSource3f);
332 LOAD_FUNCPTR(alGetSourcefv);
333 LOAD_FUNCPTR(alGetSourcei);
334 LOAD_FUNCPTR(alGetSource3i);
335 LOAD_FUNCPTR(alGetSourceiv);
336 LOAD_FUNCPTR(alSourcePlayv);
337 LOAD_FUNCPTR(alSourceStopv);
338 LOAD_FUNCPTR(alSourceRewindv);
339 LOAD_FUNCPTR(alSourcePausev);
340 LOAD_FUNCPTR(alSourcePlay);
341 LOAD_FUNCPTR(alSourceStop);
342 LOAD_FUNCPTR(alSourceRewind);
343 LOAD_FUNCPTR(alSourcePause);
344 LOAD_FUNCPTR(alSourceQueueBuffers);
345 LOAD_FUNCPTR(alSourceUnqueueBuffers);
346 LOAD_FUNCPTR(alGenBuffers);
347 LOAD_FUNCPTR(alDeleteBuffers);
348 LOAD_FUNCPTR(alIsBuffer);
349 LOAD_FUNCPTR(alBufferf);
350 LOAD_FUNCPTR(alBuffer3f);
351 LOAD_FUNCPTR(alBufferfv);
352 LOAD_FUNCPTR(alBufferi);
353 LOAD_FUNCPTR(alBuffer3i);
354 LOAD_FUNCPTR(alBufferiv);
355 LOAD_FUNCPTR(alGetBufferf);
356 LOAD_FUNCPTR(alGetBuffer3f);
357 LOAD_FUNCPTR(alGetBufferfv);
358 LOAD_FUNCPTR(alGetBufferi);
359 LOAD_FUNCPTR(alGetBuffer3i);
360 LOAD_FUNCPTR(alGetBufferiv);
361 LOAD_FUNCPTR(alBufferData);
362 LOAD_FUNCPTR(alDopplerFactor);
363 LOAD_FUNCPTR(alDopplerVelocity);
364 LOAD_FUNCPTR(alDistanceModel);
365 LOAD_FUNCPTR(alSpeedOfSound);
366 #undef LOAD_FUNCPTR
367 if (failed)
369 WARN("Unloading openal\n");
370 if (openal_handle != RTLD_DEFAULT)
371 wine_dlclose(openal_handle, NULL, 0);
372 openal_handle = NULL;
374 else
375 #endif
377 openal_loaded = 1;
379 local_contexts = alcIsExtensionPresent(NULL, "ALC_EXT_thread_local_context");
380 if(local_contexts)
382 set_context = alcGetProcAddress(NULL, "alcSetThreadContext");
383 get_context = alcGetProcAddress(NULL, "alcGetThreadContext");
384 if(!set_context || !get_context)
386 ERR("TLS advertised but functions not found, disabling thread local context\n");
387 local_contexts = 0;
390 if(!local_contexts)
392 set_context = alcMakeContextCurrent;
393 get_context = alcGetCurrentContext;
398 static HRESULT get_mmdevenum(IMMDeviceEnumerator **devenum)
400 HRESULT hr, init_hr;
402 init_hr = CoInitialize(NULL);
404 hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL,
405 CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, (void**)devenum);
406 if(FAILED(hr)){
407 CoUninitialize();
408 *devenum = NULL;
409 ERR("CoCreateInstance failed: %08x\n", hr);
410 return hr;
413 return init_hr;
416 static void release_mmdevenum(IMMDeviceEnumerator *devenum, HRESULT init_hr)
418 IMMDeviceEnumerator_Release(devenum);
419 if(SUCCEEDED(init_hr))
420 CoUninitialize();
423 static HRESULT get_mmdevice_guid(IMMDevice *device, IPropertyStore *ps,
424 GUID *guid)
426 PROPVARIANT pv;
427 HRESULT hr;
429 if(!ps){
430 hr = IMMDevice_OpenPropertyStore(device, STGM_READ, &ps);
431 if(FAILED(hr)){
432 WARN("OpenPropertyStore failed: %08x\n", hr);
433 return hr;
435 }else
436 IPropertyStore_AddRef(ps);
438 PropVariantInit(&pv);
440 hr = IPropertyStore_GetValue(ps, &PKEY_AudioEndpoint_GUID, &pv);
441 if(FAILED(hr)){
442 IPropertyStore_Release(ps);
443 WARN("GetValue(GUID) failed: %08x\n", hr);
444 return hr;
447 CLSIDFromString(pv.pwszVal, guid);
449 PropVariantClear(&pv);
450 IPropertyStore_Release(ps);
452 return S_OK;
455 /***************************************************************************
456 * GetDeviceID [DSOUND.9]
458 * Retrieves unique identifier of default device specified
460 * PARAMS
461 * pGuidSrc [I] Address of device GUID.
462 * pGuidDest [O] Address to receive unique device GUID.
464 * RETURNS
465 * Success: DS_OK
466 * Failure: DSERR_INVALIDPARAM
468 * NOTES
469 * pGuidSrc is a valid device GUID or DSDEVID_DefaultPlayback,
470 * DSDEVID_DefaultCapture, DSDEVID_DefaultVoicePlayback, or
471 * DSDEVID_DefaultVoiceCapture.
472 * Returns pGuidSrc if pGuidSrc is a valid device or the device
473 * GUID for the specified constants.
475 HRESULT WINAPI GetDeviceID(LPCGUID pGuidSrc, LPGUID pGuidDest)
477 IMMDeviceEnumerator *devenum;
478 EDataFlow flow = (EDataFlow)-1;
479 ERole role = (ERole)-1;
480 HRESULT hr, init_hr;
482 TRACE("(%s,%p)\n", debugstr_guid(pGuidSrc),pGuidDest);
484 if(!pGuidSrc || !pGuidDest)
485 return DSERR_INVALIDPARAM;
487 init_hr = get_mmdevenum(&devenum);
488 if(!devenum)
489 return init_hr;
491 if(IsEqualGUID(&DSDEVID_DefaultPlayback, pGuidSrc)){
492 role = eMultimedia;
493 flow = eRender;
494 }else if(IsEqualGUID(&DSDEVID_DefaultVoicePlayback, pGuidSrc)){
495 role = eCommunications;
496 flow = eRender;
497 }else if(IsEqualGUID(&DSDEVID_DefaultCapture, pGuidSrc)){
498 role = eMultimedia;
499 flow = eCapture;
500 }else if(IsEqualGUID(&DSDEVID_DefaultVoiceCapture, pGuidSrc)){
501 role = eCommunications;
502 flow = eCapture;
505 if(role != (ERole)-1 && flow != (EDataFlow)-1){
506 IMMDevice *device;
508 hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(devenum,
509 flow, role, &device);
510 if(FAILED(hr)){
511 WARN("GetDefaultAudioEndpoint failed: %08x\n", hr);
512 release_mmdevenum(devenum, init_hr);
513 return DSERR_NODRIVER;
516 hr = get_mmdevice_guid(device, NULL, pGuidDest);
517 IMMDevice_Release(device);
519 release_mmdevenum(devenum, init_hr);
521 return (hr == S_OK) ? DS_OK : hr;
524 release_mmdevenum(devenum, init_hr);
526 *pGuidDest = *pGuidSrc;
528 return DS_OK;
531 struct morecontext
533 LPDSENUMCALLBACKA callA;
534 LPVOID data;
537 static BOOL CALLBACK a_to_w_callback(LPGUID guid, LPCWSTR descW, LPCWSTR modW, LPVOID data)
539 struct morecontext *context = data;
540 char descA[MAXPNAMELEN], modA[MAXPNAMELEN];
542 WideCharToMultiByte(CP_ACP, 0, descW, -1, descA, sizeof(descA), NULL, NULL);
543 WideCharToMultiByte(CP_ACP, 0, modW, -1, modA, sizeof(modA), NULL, NULL);
545 return context->callA(guid, descA, modA, context->data);
548 /***************************************************************************
549 * DirectSoundEnumerateA [DSOUND.2]
551 * Enumerate all DirectSound drivers installed in the system
553 * PARAMS
554 * lpDSEnumCallback [I] Address of callback function.
555 * lpContext [I] Address of user defined context passed to callback function.
557 * RETURNS
558 * Success: DS_OK
559 * Failure: DSERR_INVALIDPARAM
561 HRESULT WINAPI DirectSoundEnumerateA(
562 LPDSENUMCALLBACKA lpDSEnumCallback,
563 LPVOID lpContext)
565 struct morecontext context;
567 if (lpDSEnumCallback == NULL) {
568 WARN("invalid parameter: lpDSEnumCallback == NULL\n");
569 return DSERR_INVALIDPARAM;
572 context.callA = lpDSEnumCallback;
573 context.data = lpContext;
575 return DirectSoundEnumerateW(a_to_w_callback, &context);
578 HRESULT get_mmdevice(EDataFlow flow, const GUID *tgt, IMMDevice **device)
580 IMMDeviceEnumerator *devenum;
581 IMMDeviceCollection *coll;
582 UINT count, i;
583 HRESULT hr, init_hr;
585 init_hr = get_mmdevenum(&devenum);
586 if(!devenum)
587 return init_hr;
589 hr = IMMDeviceEnumerator_EnumAudioEndpoints(devenum, flow,
590 DEVICE_STATE_ACTIVE, &coll);
591 if(FAILED(hr)){
592 WARN("EnumAudioEndpoints failed: %08x\n", hr);
593 release_mmdevenum(devenum, init_hr);
594 return hr;
597 hr = IMMDeviceCollection_GetCount(coll, &count);
598 if(FAILED(hr)){
599 IMMDeviceCollection_Release(coll);
600 release_mmdevenum(devenum, init_hr);
601 WARN("GetCount failed: %08x\n", hr);
602 return hr;
605 for(i = 0; i < count; ++i){
606 GUID guid;
608 hr = IMMDeviceCollection_Item(coll, i, device);
609 if(FAILED(hr))
610 continue;
612 hr = get_mmdevice_guid(*device, NULL, &guid);
613 if(FAILED(hr)){
614 IMMDevice_Release(*device);
615 continue;
618 if(IsEqualGUID(&guid, tgt)){
619 IMMDeviceCollection_Release(coll);
620 release_mmdevenum(devenum, init_hr);
621 return DS_OK;
624 IMMDevice_Release(*device);
627 WARN("No device with GUID %s found!\n", wine_dbgstr_guid(tgt));
629 IMMDeviceCollection_Release(coll);
630 release_mmdevenum(devenum, init_hr);
632 return DSERR_INVALIDPARAM;
635 static BOOL send_device(IMMDevice *device, GUID *guid,
636 LPDSENUMCALLBACKW cb, void *user)
638 IPropertyStore *ps;
639 PROPVARIANT pv;
640 BOOL keep_going;
641 HRESULT hr;
643 PropVariantInit(&pv);
645 hr = IMMDevice_OpenPropertyStore(device, STGM_READ, &ps);
646 if(FAILED(hr)){
647 WARN("OpenPropertyStore failed: %08x\n", hr);
648 return TRUE;
651 hr = get_mmdevice_guid(device, ps, guid);
652 if(FAILED(hr)){
653 IPropertyStore_Release(ps);
654 return TRUE;
657 hr = IPropertyStore_GetValue(ps,
658 (const PROPERTYKEY *)&DEVPKEY_Device_FriendlyName, &pv);
659 if(FAILED(hr)){
660 IPropertyStore_Release(ps);
661 WARN("GetValue(FriendlyName) failed: %08x\n", hr);
662 return TRUE;
665 TRACE("Calling back with %s (%s)\n", wine_dbgstr_guid(guid),
666 wine_dbgstr_w(pv.pwszVal));
668 keep_going = cb(guid, pv.pwszVal, wine_vxd_drv, user);
670 PropVariantClear(&pv);
671 IPropertyStore_Release(ps);
673 return keep_going;
676 /* S_FALSE means the callback returned FALSE at some point
677 * S_OK means the callback always returned TRUE */
678 HRESULT enumerate_mmdevices(EDataFlow flow, GUID *guids,
679 LPDSENUMCALLBACKW cb, void *user)
681 IMMDeviceEnumerator *devenum;
682 IMMDeviceCollection *coll;
683 IMMDevice *defdev = NULL;
684 UINT count, i, n;
685 BOOL keep_going;
686 HRESULT hr, init_hr;
688 static const WCHAR primary_desc[] = {'P','r','i','m','a','r','y',' ',
689 'S','o','u','n','d',' ','D','r','i','v','e','r',0};
690 static const WCHAR empty_drv[] = {0};
692 init_hr = get_mmdevenum(&devenum);
693 if(!devenum)
694 return init_hr;
696 hr = IMMDeviceEnumerator_EnumAudioEndpoints(devenum, flow,
697 DEVICE_STATE_ACTIVE, &coll);
698 if(FAILED(hr)){
699 release_mmdevenum(devenum, init_hr);
700 WARN("EnumAudioEndpoints failed: %08x\n", hr);
701 return DS_OK;
704 hr = IMMDeviceCollection_GetCount(coll, &count);
705 if(FAILED(hr)){
706 IMMDeviceCollection_Release(coll);
707 release_mmdevenum(devenum, init_hr);
708 WARN("GetCount failed: %08x\n", hr);
709 return DS_OK;
712 if(count == 0){
713 release_mmdevenum(devenum, init_hr);
714 return DS_OK;
717 TRACE("Calling back with NULL (%s)\n", wine_dbgstr_w(primary_desc));
718 keep_going = cb(NULL, primary_desc, empty_drv, user);
720 /* always send the default device first */
721 if(keep_going){
722 hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(devenum, flow,
723 eMultimedia, &defdev);
724 if(FAILED(hr)){
725 defdev = NULL;
726 n = 0;
727 }else{
728 keep_going = send_device(defdev, &guids[0], cb, user);
729 n = 1;
733 for(i = 0; keep_going && i < count; ++i){
734 IMMDevice *device;
736 hr = IMMDeviceCollection_Item(coll, i, &device);
737 if(FAILED(hr)){
738 WARN("Item failed: %08x\n", hr);
739 continue;
742 if(device != defdev){
743 send_device(device, &guids[n], cb, user);
744 ++n;
747 IMMDevice_Release(device);
750 if(defdev)
751 IMMDevice_Release(defdev);
752 IMMDeviceCollection_Release(coll);
754 release_mmdevenum(devenum, init_hr);
756 return (keep_going == TRUE) ? S_OK : S_FALSE;
759 /***************************************************************************
760 * DirectSoundEnumerateW [DSOUND.3]
762 * Enumerate all DirectSound drivers installed in the system
764 * PARAMS
765 * lpDSEnumCallback [I] Address of callback function.
766 * lpContext [I] Address of user defined context passed to callback function.
768 * RETURNS
769 * Success: DS_OK
770 * Failure: DSERR_INVALIDPARAM
772 HRESULT WINAPI DirectSoundEnumerateW(
773 LPDSENUMCALLBACKW lpDSEnumCallback,
774 LPVOID lpContext )
776 HRESULT hr;
778 TRACE("(%p,%p)\n", lpDSEnumCallback, lpContext);
780 if (lpDSEnumCallback == NULL) {
781 WARN("invalid parameter: lpDSEnumCallback == NULL\n");
782 return DSERR_INVALIDPARAM;
785 hr = enumerate_mmdevices(eRender, DSOUND_renderer_guids,
786 lpDSEnumCallback, lpContext);
787 return SUCCEEDED(hr) ? DS_OK : hr;
790 /***************************************************************************
791 * DirectSoundCaptureEnumerateA [DSOUND.7]
793 * Enumerate all DirectSound drivers installed in the system.
795 * PARAMS
796 * lpDSEnumCallback [I] Address of callback function.
797 * lpContext [I] Address of user defined context passed to callback function.
799 * RETURNS
800 * Success: DS_OK
801 * Failure: DSERR_INVALIDPARAM
803 HRESULT WINAPI DirectSoundCaptureEnumerateA(
804 LPDSENUMCALLBACKA lpDSEnumCallback,
805 LPVOID lpContext)
807 struct morecontext context;
809 if (lpDSEnumCallback == NULL) {
810 WARN("invalid parameter: lpDSEnumCallback == NULL\n");
811 return DSERR_INVALIDPARAM;
814 context.callA = lpDSEnumCallback;
815 context.data = lpContext;
817 return DirectSoundCaptureEnumerateW(a_to_w_callback, &context);
820 /***************************************************************************
821 * DirectSoundCaptureEnumerateW [DSOUND.8]
823 * Enumerate all DirectSound drivers installed in the system.
825 * PARAMS
826 * lpDSEnumCallback [I] Address of callback function.
827 * lpContext [I] Address of user defined context passed to callback function.
829 * RETURNS
830 * Success: DS_OK
831 * Failure: DSERR_INVALIDPARAM
833 HRESULT WINAPI
834 DirectSoundCaptureEnumerateW(
835 LPDSENUMCALLBACKW lpDSEnumCallback,
836 LPVOID lpContext)
838 HRESULT hr;
840 TRACE("(%p,%p)\n", lpDSEnumCallback, lpContext );
842 if (lpDSEnumCallback == NULL) {
843 WARN("invalid parameter: lpDSEnumCallback == NULL\n");
844 return DSERR_INVALIDPARAM;
847 hr = enumerate_mmdevices(eCapture, DSOUND_capture_guids,
848 lpDSEnumCallback, lpContext);
849 return SUCCEEDED(hr) ? DS_OK : hr;
852 /*******************************************************************************
853 * DirectSoundCreate (DSOUND.1)
855 * Creates and initializes a DirectSound interface.
857 * PARAMS
858 * lpcGUID [I] Address of the GUID that identifies the sound device.
859 * ppDS [O] Address of a variable to receive the interface pointer.
860 * pUnkOuter [I] Must be NULL.
862 * RETURNS
863 * Success: DS_OK
864 * Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
865 * DSERR_NODRIVER, DSERR_OUTOFMEMORY
867 HRESULT WINAPI
868 DirectSoundCreate(LPCGUID lpcGUID, IDirectSound **ppDS, IUnknown *pUnkOuter)
870 HRESULT hr;
871 IDirectSound *pDS;
873 TRACE("(%s, %p, %p)\n", debugstr_guid(lpcGUID), ppDS, pUnkOuter);
875 if (ppDS == NULL) {
876 WARN("invalid parameter: ppDS == NULL\n");
877 return DSERR_INVALIDPARAM;
879 *ppDS = NULL;
881 if (pUnkOuter != NULL) {
882 WARN("invalid parameter: pUnkOuter != NULL\n");
883 return DSERR_INVALIDPARAM;
886 hr = DSOUND_Create(&IID_IDirectSound, &pDS);
887 if(SUCCEEDED(hr))
889 *ppDS = pDS;
890 hr = IDirectSound_Initialize(*ppDS, lpcGUID);
891 if(FAILED(hr))
893 IDirectSound_Release(*ppDS);
894 *ppDS = NULL;
898 return hr;
901 /*******************************************************************************
902 * DirectSoundCreate8 (DSOUND.11)
904 * Creates and initializes a DirectSound8 interface.
906 * PARAMS
907 * lpcGUID [I] Address of the GUID that identifies the sound device.
908 * ppDS [O] Address of a variable to receive the interface pointer.
909 * pUnkOuter [I] Must be NULL.
911 * RETURNS
912 * Success: DS_OK
913 * Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
914 * DSERR_NODRIVER, DSERR_OUTOFMEMORY
916 HRESULT WINAPI
917 DirectSoundCreate8(LPCGUID lpcGUID, IDirectSound8 **ppDS, IUnknown *pUnkOuter)
919 HRESULT hr;
920 IDirectSound8 *pDS;
922 TRACE("(%s, %p, %p)\n", debugstr_guid(lpcGUID), ppDS, pUnkOuter);
924 if (ppDS == NULL) {
925 WARN("invalid parameter: ppDS == NULL\n");
926 return DSERR_INVALIDPARAM;
928 *ppDS = NULL;
930 if (pUnkOuter != NULL) {
931 WARN("invalid parameter: pUnkOuter != NULL\n");
932 return DSERR_INVALIDPARAM;
935 hr = DSOUND_Create8(&IID_IDirectSound8, &pDS);
936 if(SUCCEEDED(hr))
938 *ppDS = pDS;
939 hr = IDirectSound8_Initialize(*ppDS, lpcGUID);
940 if(FAILED(hr))
942 IDirectSound8_Release(*ppDS);
943 *ppDS = NULL;
947 return hr;
950 /*******************************************************************************
951 * DirectSound ClassFactory
954 typedef HRESULT (*FnCreateInstance)(REFIID riid, LPVOID *ppobj);
956 typedef struct {
957 IClassFactory IClassFactory_iface;
958 REFCLSID rclsid;
959 FnCreateInstance pfnCreateInstance;
960 } IClassFactoryImpl;
962 static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
964 return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface);
967 static HRESULT WINAPI
968 DSCF_QueryInterface(LPCLASSFACTORY iface, REFIID riid, LPVOID *ppobj)
970 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
971 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppobj);
972 if (ppobj == NULL)
973 return E_POINTER;
974 if (IsEqualIID(riid, &IID_IUnknown) ||
975 IsEqualIID(riid, &IID_IClassFactory))
977 *ppobj = iface;
978 IUnknown_AddRef(iface);
979 return S_OK;
981 *ppobj = NULL;
982 return E_NOINTERFACE;
985 static ULONG WINAPI DSCF_AddRef(LPCLASSFACTORY iface)
987 return 2;
990 static ULONG WINAPI DSCF_Release(LPCLASSFACTORY iface)
992 /* static class, won't be freed */
993 return 1;
996 static HRESULT WINAPI DSCF_CreateInstance(
997 LPCLASSFACTORY iface,
998 LPUNKNOWN pOuter,
999 REFIID riid,
1000 LPVOID *ppobj)
1002 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
1003 TRACE("(%p, %p, %s, %p)\n", This, pOuter, debugstr_guid(riid), ppobj);
1005 if (pOuter)
1006 return CLASS_E_NOAGGREGATION;
1008 if (ppobj == NULL) {
1009 WARN("invalid parameter\n");
1010 return DSERR_INVALIDPARAM;
1012 *ppobj = NULL;
1013 return This->pfnCreateInstance(riid, ppobj);
1016 static HRESULT WINAPI DSCF_LockServer(LPCLASSFACTORY iface, BOOL dolock)
1018 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
1019 FIXME("(%p, %d) stub!\n", This, dolock);
1020 return S_OK;
1023 static const IClassFactoryVtbl DSCF_Vtbl = {
1024 DSCF_QueryInterface,
1025 DSCF_AddRef,
1026 DSCF_Release,
1027 DSCF_CreateInstance,
1028 DSCF_LockServer
1031 static IClassFactoryImpl DSOUND_CF[] = {
1032 { { &DSCF_Vtbl }, &CLSID_DirectSound, (FnCreateInstance)DSOUND_Create },
1033 { { &DSCF_Vtbl }, &CLSID_DirectSound8, (FnCreateInstance)DSOUND_Create8 },
1034 { { &DSCF_Vtbl }, &CLSID_DirectSoundCapture, (FnCreateInstance)DSOUND_CaptureCreate },
1035 { { &DSCF_Vtbl }, &CLSID_DirectSoundCapture8, (FnCreateInstance)DSOUND_CaptureCreate8 },
1036 { { &DSCF_Vtbl }, &CLSID_DirectSoundFullDuplex, (FnCreateInstance)DSOUND_FullDuplexCreate },
1037 { { &DSCF_Vtbl }, &CLSID_DirectSoundPrivate, (FnCreateInstance)IKsPrivatePropertySetImpl_Create },
1038 { { NULL }, NULL, NULL }
1041 /*******************************************************************************
1042 * DllGetClassObject [DSOUND.@]
1043 * Retrieves class object from a DLL object
1045 * NOTES
1046 * Docs say returns STDAPI
1048 * PARAMS
1049 * rclsid [I] CLSID for the class object
1050 * riid [I] Reference to identifier of interface for class object
1051 * ppv [O] Address of variable to receive interface pointer for riid
1053 * RETURNS
1054 * Success: S_OK
1055 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
1056 * E_UNEXPECTED
1058 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
1060 int i = 0;
1061 TRACE("(%s, %s, %p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
1063 if (ppv == NULL) {
1064 WARN("invalid parameter\n");
1065 return E_INVALIDARG;
1068 *ppv = NULL;
1070 if (!IsEqualIID(riid, &IID_IClassFactory) &&
1071 !IsEqualIID(riid, &IID_IUnknown)) {
1072 WARN("no interface for %s\n", debugstr_guid(riid));
1073 return E_NOINTERFACE;
1076 while (NULL != DSOUND_CF[i].rclsid) {
1077 if (IsEqualGUID(rclsid, DSOUND_CF[i].rclsid)) {
1078 DSCF_AddRef(&DSOUND_CF[i].IClassFactory_iface);
1079 *ppv = &DSOUND_CF[i];
1080 return S_OK;
1082 i++;
1085 WARN("(%s, %s, %p): no class found.\n", debugstr_guid(rclsid),
1086 debugstr_guid(riid), ppv);
1087 return CLASS_E_CLASSNOTAVAILABLE;
1091 /*******************************************************************************
1092 * DllCanUnloadNow [DSOUND.4]
1093 * Determines whether the DLL is in use.
1095 * RETURNS
1096 * Can unload now: S_OK
1097 * Cannot unload now (the DLL is still active): S_FALSE
1099 HRESULT WINAPI DllCanUnloadNow(void)
1101 return S_FALSE;
1104 #define INIT_GUID(guid, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
1105 guid.Data1 = l; guid.Data2 = w1; guid.Data3 = w2; \
1106 guid.Data4[0] = b1; guid.Data4[1] = b2; guid.Data4[2] = b3; \
1107 guid.Data4[3] = b4; guid.Data4[4] = b5; guid.Data4[5] = b6; \
1108 guid.Data4[6] = b7; guid.Data4[7] = b8;
1110 /***********************************************************************
1111 * DllMain (DSOUND.init)
1113 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpvReserved)
1115 TRACE("(%p %d %p)\n", hInstDLL, fdwReason, lpvReserved);
1117 switch (fdwReason) {
1118 case DLL_PROCESS_ATTACH:
1119 TRACE("DLL_PROCESS_ATTACH\n");
1120 instance = hInstDLL;
1121 /* Increase refcount on dsound by 1 */
1122 GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCWSTR)hInstDLL, &hInstDLL);
1123 #ifdef HAVE_OPENAL
1124 load_libopenal();
1125 #endif /*HAVE_OPENAL*/
1126 break;
1127 case DLL_THREAD_DETACH:
1128 TRACE("DLL_THREAD_DETACH\n");
1129 #if !ALLOW_CONCURRENT_AL
1130 if(local_contexts)
1131 set_context(NULL);
1132 #endif
1133 break;
1134 case DLL_PROCESS_DETACH:
1135 TRACE("DLL_PROCESS_DETACH\n");
1136 #ifdef SONAME_LIBOPENAL
1137 if (openal_handle)
1138 wine_dlclose(openal_handle, NULL, 0);
1139 #endif /*SONAME_LIBOPENAL*/
1140 break;
1141 default:
1142 TRACE("UNKNOWN REASON\n");
1143 break;
1145 return TRUE;
1148 /***********************************************************************
1149 * DllRegisterServer (DSOUND.@)
1151 HRESULT WINAPI DllRegisterServer(void)
1153 return __wine_register_resources( instance );
1156 /***********************************************************************
1157 * DllUnregisterServer (DSOUND.@)
1159 HRESULT WINAPI DllUnregisterServer(void)
1161 return __wine_unregister_resources( instance );