/* * Copyright 2009 Maarten Lankhorst * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "config.h" #include "wine/port.h" #include #ifdef HAVE_AL_AL_H #include #include #elif defined(HAVE_OPENAL_AL_H) #include #include #endif #define COBJMACROS #include "windef.h" #include "winbase.h" #include "wingdi.h" #include "wine/library.h" #include "ole2.h" #include "olectl.h" #include "rpcproxy.h" #include "propsys.h" #include "initguid.h" #include "propkeydef.h" #include "mmdeviceapi.h" #include "dshow.h" #include "dsound.h" #include "audioclient.h" #include "endpointvolume.h" #include "audiopolicy.h" #include "devpkey.h" #include "mmdevapi.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(mmdevapi); #ifdef HAVE_OPENAL int local_contexts; static CRITICAL_SECTION_DEBUG openal_crst_debug = { 0, 0, &openal_crst, { &openal_crst_debug.ProcessLocksList, &openal_crst_debug.ProcessLocksList }, 0, 0, { (DWORD_PTR)(__FILE__ ": openal_crst_debug") } }; CRITICAL_SECTION openal_crst = { &openal_crst_debug, -1, 0, 0, 0, 0 }; static void *openal_handle = RTLD_DEFAULT; int openal_loaded; #ifdef SONAME_LIBOPENAL LPALCCREATECONTEXT palcCreateContext = NULL; LPALCMAKECONTEXTCURRENT palcMakeContextCurrent = NULL; LPALCPROCESSCONTEXT palcProcessContext = NULL; LPALCSUSPENDCONTEXT palcSuspendContext = NULL; LPALCDESTROYCONTEXT palcDestroyContext = NULL; LPALCGETCURRENTCONTEXT palcGetCurrentContext = NULL; LPALCGETCONTEXTSDEVICE palcGetContextsDevice = NULL; LPALCOPENDEVICE palcOpenDevice = NULL; LPALCCLOSEDEVICE palcCloseDevice = NULL; LPALCGETERROR palcGetError = NULL; LPALCISEXTENSIONPRESENT palcIsExtensionPresent = NULL; LPALCGETPROCADDRESS palcGetProcAddress = NULL; LPALCGETENUMVALUE palcGetEnumValue = NULL; LPALCGETSTRING palcGetString = NULL; LPALCGETINTEGERV palcGetIntegerv = NULL; LPALCCAPTUREOPENDEVICE palcCaptureOpenDevice = NULL; LPALCCAPTURECLOSEDEVICE palcCaptureCloseDevice = NULL; LPALCCAPTURESTART palcCaptureStart = NULL; LPALCCAPTURESTOP palcCaptureStop = NULL; LPALCCAPTURESAMPLES palcCaptureSamples = NULL; LPALENABLE palEnable = NULL; LPALDISABLE palDisable = NULL; LPALISENABLED palIsEnabled = NULL; LPALGETSTRING palGetString = NULL; LPALGETBOOLEANV palGetBooleanv = NULL; LPALGETINTEGERV palGetIntegerv = NULL; LPALGETFLOATV palGetFloatv = NULL; LPALGETDOUBLEV palGetDoublev = NULL; LPALGETBOOLEAN palGetBoolean = NULL; LPALGETINTEGER palGetInteger = NULL; LPALGETFLOAT palGetFloat = NULL; LPALGETDOUBLE palGetDouble = NULL; LPALGETERROR palGetError = NULL; LPALISEXTENSIONPRESENT palIsExtensionPresent = NULL; LPALGETPROCADDRESS palGetProcAddress = NULL; LPALGETENUMVALUE palGetEnumValue = NULL; LPALLISTENERF palListenerf = NULL; LPALLISTENER3F palListener3f = NULL; LPALLISTENERFV palListenerfv = NULL; LPALLISTENERI palListeneri = NULL; LPALLISTENER3I palListener3i = NULL; LPALLISTENERIV palListeneriv = NULL; LPALGETLISTENERF palGetListenerf = NULL; LPALGETLISTENER3F palGetListener3f = NULL; LPALGETLISTENERFV palGetListenerfv = NULL; LPALGETLISTENERI palGetListeneri = NULL; LPALGETLISTENER3I palGetListener3i = NULL; LPALGETLISTENERIV palGetListeneriv = NULL; LPALGENSOURCES palGenSources = NULL; LPALDELETESOURCES palDeleteSources = NULL; LPALISSOURCE palIsSource = NULL; LPALSOURCEF palSourcef = NULL; LPALSOURCE3F palSource3f = NULL; LPALSOURCEFV palSourcefv = NULL; LPALSOURCEI palSourcei = NULL; LPALSOURCE3I palSource3i = NULL; LPALSOURCEIV palSourceiv = NULL; LPALGETSOURCEF palGetSourcef = NULL; LPALGETSOURCE3F palGetSource3f = NULL; LPALGETSOURCEFV palGetSourcefv = NULL; LPALGETSOURCEI palGetSourcei = NULL; LPALGETSOURCE3I palGetSource3i = NULL; LPALGETSOURCEIV palGetSourceiv = NULL; LPALSOURCEPLAYV palSourcePlayv = NULL; LPALSOURCESTOPV palSourceStopv = NULL; LPALSOURCEREWINDV palSourceRewindv = NULL; LPALSOURCEPAUSEV palSourcePausev = NULL; LPALSOURCEPLAY palSourcePlay = NULL; LPALSOURCESTOP palSourceStop = NULL; LPALSOURCEREWIND palSourceRewind = NULL; LPALSOURCEPAUSE palSourcePause = NULL; LPALSOURCEQUEUEBUFFERS palSourceQueueBuffers = NULL; LPALSOURCEUNQUEUEBUFFERS palSourceUnqueueBuffers = NULL; LPALGENBUFFERS palGenBuffers = NULL; LPALDELETEBUFFERS palDeleteBuffers = NULL; LPALISBUFFER palIsBuffer = NULL; LPALBUFFERF palBufferf = NULL; LPALBUFFER3F palBuffer3f = NULL; LPALBUFFERFV palBufferfv = NULL; LPALBUFFERI palBufferi = NULL; LPALBUFFER3I palBuffer3i = NULL; LPALBUFFERIV palBufferiv = NULL; LPALGETBUFFERF palGetBufferf = NULL; LPALGETBUFFER3F palGetBuffer3f = NULL; LPALGETBUFFERFV palGetBufferfv = NULL; LPALGETBUFFERI palGetBufferi = NULL; LPALGETBUFFER3I palGetBuffer3i = NULL; LPALGETBUFFERIV palGetBufferiv = NULL; LPALBUFFERDATA palBufferData = NULL; LPALDOPPLERFACTOR palDopplerFactor = NULL; LPALDOPPLERVELOCITY palDopplerVelocity = NULL; LPALDISTANCEMODEL palDistanceModel = NULL; LPALSPEEDOFSOUND palSpeedOfSound = NULL; #endif typeof(alcGetCurrentContext) *get_context; typeof(alcMakeContextCurrent) *set_context; static void load_libopenal(void) { DWORD failed = 0; #ifdef SONAME_LIBOPENAL char error[128]; openal_handle = wine_dlopen(SONAME_LIBOPENAL, RTLD_NOW, error, sizeof(error)); if (!openal_handle) { ERR("Couldn't load " SONAME_LIBOPENAL ": %s\n", error); return; } #define LOAD_FUNCPTR(f) \ if((p##f = wine_dlsym(openal_handle, #f, NULL, 0)) == NULL) { \ ERR("Couldn't lookup %s in libopenal\n", #f); \ failed = 1; \ } LOAD_FUNCPTR(alcCreateContext); LOAD_FUNCPTR(alcMakeContextCurrent); LOAD_FUNCPTR(alcProcessContext); LOAD_FUNCPTR(alcSuspendContext); LOAD_FUNCPTR(alcDestroyContext); LOAD_FUNCPTR(alcGetCurrentContext); LOAD_FUNCPTR(alcGetContextsDevice); LOAD_FUNCPTR(alcOpenDevice); LOAD_FUNCPTR(alcCloseDevice); LOAD_FUNCPTR(alcGetError); LOAD_FUNCPTR(alcIsExtensionPresent); LOAD_FUNCPTR(alcGetProcAddress); LOAD_FUNCPTR(alcGetEnumValue); LOAD_FUNCPTR(alcGetString); LOAD_FUNCPTR(alcGetIntegerv); LOAD_FUNCPTR(alcCaptureOpenDevice); LOAD_FUNCPTR(alcCaptureCloseDevice); LOAD_FUNCPTR(alcCaptureStart); LOAD_FUNCPTR(alcCaptureStop); LOAD_FUNCPTR(alcCaptureSamples); LOAD_FUNCPTR(alEnable); LOAD_FUNCPTR(alDisable); LOAD_FUNCPTR(alIsEnabled); LOAD_FUNCPTR(alGetString); LOAD_FUNCPTR(alGetBooleanv); LOAD_FUNCPTR(alGetIntegerv); LOAD_FUNCPTR(alGetFloatv); LOAD_FUNCPTR(alGetDoublev); LOAD_FUNCPTR(alGetBoolean); LOAD_FUNCPTR(alGetInteger); LOAD_FUNCPTR(alGetFloat); LOAD_FUNCPTR(alGetDouble); LOAD_FUNCPTR(alGetError); LOAD_FUNCPTR(alIsExtensionPresent); LOAD_FUNCPTR(alGetProcAddress); LOAD_FUNCPTR(alGetEnumValue); LOAD_FUNCPTR(alListenerf); LOAD_FUNCPTR(alListener3f); LOAD_FUNCPTR(alListenerfv); LOAD_FUNCPTR(alListeneri); LOAD_FUNCPTR(alListener3i); LOAD_FUNCPTR(alListeneriv); LOAD_FUNCPTR(alGetListenerf); LOAD_FUNCPTR(alGetListener3f); LOAD_FUNCPTR(alGetListenerfv); LOAD_FUNCPTR(alGetListeneri); LOAD_FUNCPTR(alGetListener3i); LOAD_FUNCPTR(alGetListeneriv); LOAD_FUNCPTR(alGenSources); LOAD_FUNCPTR(alDeleteSources); LOAD_FUNCPTR(alIsSource); LOAD_FUNCPTR(alSourcef); LOAD_FUNCPTR(alSource3f); LOAD_FUNCPTR(alSourcefv); LOAD_FUNCPTR(alSourcei); LOAD_FUNCPTR(alSource3i); LOAD_FUNCPTR(alSourceiv); LOAD_FUNCPTR(alGetSourcef); LOAD_FUNCPTR(alGetSource3f); LOAD_FUNCPTR(alGetSourcefv); LOAD_FUNCPTR(alGetSourcei); LOAD_FUNCPTR(alGetSource3i); LOAD_FUNCPTR(alGetSourceiv); LOAD_FUNCPTR(alSourcePlayv); LOAD_FUNCPTR(alSourceStopv); LOAD_FUNCPTR(alSourceRewindv); LOAD_FUNCPTR(alSourcePausev); LOAD_FUNCPTR(alSourcePlay); LOAD_FUNCPTR(alSourceStop); LOAD_FUNCPTR(alSourceRewind); LOAD_FUNCPTR(alSourcePause); LOAD_FUNCPTR(alSourceQueueBuffers); LOAD_FUNCPTR(alSourceUnqueueBuffers); LOAD_FUNCPTR(alGenBuffers); LOAD_FUNCPTR(alDeleteBuffers); LOAD_FUNCPTR(alIsBuffer); LOAD_FUNCPTR(alBufferf); LOAD_FUNCPTR(alBuffer3f); LOAD_FUNCPTR(alBufferfv); LOAD_FUNCPTR(alBufferi); LOAD_FUNCPTR(alBuffer3i); LOAD_FUNCPTR(alBufferiv); LOAD_FUNCPTR(alGetBufferf); LOAD_FUNCPTR(alGetBuffer3f); LOAD_FUNCPTR(alGetBufferfv); LOAD_FUNCPTR(alGetBufferi); LOAD_FUNCPTR(alGetBuffer3i); LOAD_FUNCPTR(alGetBufferiv); LOAD_FUNCPTR(alBufferData); LOAD_FUNCPTR(alDopplerFactor); LOAD_FUNCPTR(alDopplerVelocity); LOAD_FUNCPTR(alDistanceModel); LOAD_FUNCPTR(alSpeedOfSound); #undef LOAD_FUNCPTR #endif if (failed) { WARN("Unloading openal\n"); if (openal_handle != RTLD_DEFAULT) wine_dlclose(openal_handle, NULL, 0); openal_handle = NULL; openal_loaded = 0; } else { openal_loaded = 1; local_contexts = palcIsExtensionPresent(NULL, "ALC_EXT_thread_local_context"); if (local_contexts) { set_context = palcGetProcAddress(NULL, "alcSetThreadContext"); get_context = palcGetProcAddress(NULL, "alcGetThreadContext"); if (!set_context || !get_context) { ERR("TLS advertised but functions not found, disabling thread local context\n"); local_contexts = 0; } } if (!local_contexts) { set_context = palcMakeContextCurrent; get_context = palcGetCurrentContext; } } } #endif /*HAVE_OPENAL*/ static HINSTANCE instance; BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { TRACE("(0x%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved); switch (fdwReason) { case DLL_PROCESS_ATTACH: instance = hinstDLL; DisableThreadLibraryCalls(hinstDLL); #ifdef HAVE_OPENAL load_libopenal(); #endif /*HAVE_OPENAL*/ break; case DLL_PROCESS_DETACH: MMDevEnum_Free(); break; } return TRUE; } HRESULT WINAPI DllCanUnloadNow(void) { return S_FALSE; } typedef HRESULT (*FnCreateInstance)(REFIID riid, LPVOID *ppobj); typedef struct { IClassFactory IClassFactory_iface; REFCLSID rclsid; FnCreateInstance pfnCreateInstance; } IClassFactoryImpl; static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface) { return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface); } static HRESULT WINAPI MMCF_QueryInterface(LPCLASSFACTORY iface, REFIID riid, LPVOID *ppobj) { IClassFactoryImpl *This = impl_from_IClassFactory(iface); TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppobj); if (ppobj == NULL) return E_POINTER; if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory)) { *ppobj = iface; IUnknown_AddRef(iface); return S_OK; } *ppobj = NULL; return E_NOINTERFACE; } static ULONG WINAPI MMCF_AddRef(LPCLASSFACTORY iface) { return 2; } static ULONG WINAPI MMCF_Release(LPCLASSFACTORY iface) { /* static class, won't be freed */ return 1; } static HRESULT WINAPI MMCF_CreateInstance( LPCLASSFACTORY iface, LPUNKNOWN pOuter, REFIID riid, LPVOID *ppobj) { IClassFactoryImpl *This = impl_from_IClassFactory(iface); TRACE("(%p, %p, %s, %p)\n", This, pOuter, debugstr_guid(riid), ppobj); if (pOuter) return CLASS_E_NOAGGREGATION; if (ppobj == NULL) { WARN("invalid parameter\n"); return E_POINTER; } *ppobj = NULL; return This->pfnCreateInstance(riid, ppobj); } static HRESULT WINAPI MMCF_LockServer(LPCLASSFACTORY iface, BOOL dolock) { IClassFactoryImpl *This = impl_from_IClassFactory(iface); FIXME("(%p, %d) stub!\n", This, dolock); return S_OK; } static const IClassFactoryVtbl MMCF_Vtbl = { MMCF_QueryInterface, MMCF_AddRef, MMCF_Release, MMCF_CreateInstance, MMCF_LockServer }; static IClassFactoryImpl MMDEVAPI_CF[] = { { { &MMCF_Vtbl }, &CLSID_MMDeviceEnumerator, (FnCreateInstance)MMDevEnum_Create } }; HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) { int i = 0; TRACE("(%s, %s, %p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); if (ppv == NULL) { WARN("invalid parameter\n"); return E_INVALIDARG; } *ppv = NULL; if (!IsEqualIID(riid, &IID_IClassFactory) && !IsEqualIID(riid, &IID_IUnknown)) { WARN("no interface for %s\n", debugstr_guid(riid)); return E_NOINTERFACE; } for (i = 0; i < sizeof(MMDEVAPI_CF)/sizeof(MMDEVAPI_CF[0]); ++i) { if (IsEqualGUID(rclsid, MMDEVAPI_CF[i].rclsid)) { IUnknown_AddRef(&MMDEVAPI_CF[i].IClassFactory_iface); *ppv = &MMDEVAPI_CF[i]; return S_OK; } i++; } WARN("(%s, %s, %p): no class found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); return CLASS_E_CLASSNOTAVAILABLE; } /*********************************************************************** * DllRegisterServer (MMDEVAPI.@) */ HRESULT WINAPI DllRegisterServer(void) { return __wine_register_resources( instance, NULL ); } /*********************************************************************** * DllUnregisterServer (MMDEVAPI.@) */ HRESULT WINAPI DllUnregisterServer(void) { return __wine_unregister_resources( instance, NULL ); }