mmdevapi: Add dependency on openal.
[wine] / dlls / mmdevapi / main.c
1 /*
2  * Copyright 2009 Maarten Lankhorst
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include "config.h"
20 #include "wine/port.h"
21
22 #include <stdarg.h>
23
24 #define CINTERFACE
25 #define COBJMACROS
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "wine/library.h"
30
31 #include "ole2.h"
32 #include "olectl.h"
33 #include "initguid.h"
34 #include "mmdeviceapi.h"
35 #include "dshow.h"
36 #include "dsound.h"
37 #include "audioclient.h"
38 #include "endpointvolume.h"
39 #include "audiopolicy.h"
40 #include "devpkey.h"
41
42 #include "mmdevapi.h"
43 #include "wine/debug.h"
44
45 WINE_DEFAULT_DEBUG_CHANNEL(mmdevapi);
46
47 #ifdef HAVE_OPENAL
48
49 int local_contexts;
50
51 static CRITICAL_SECTION_DEBUG openal_crst_debug =
52 {
53     0, 0, &openal_crst,
54     { &openal_crst_debug.ProcessLocksList,
55       &openal_crst_debug.ProcessLocksList },
56       0, 0, { (DWORD_PTR)(__FILE__ ": openal_crst_debug") }
57 };
58 CRITICAL_SECTION openal_crst = { &openal_crst_debug, -1, 0, 0, 0, 0 };
59
60 static void *openal_handle = RTLD_DEFAULT;
61 int openal_loaded;
62 #ifdef SONAME_LIBOPENAL
63 LPALCCREATECONTEXT palcCreateContext = NULL;
64 LPALCMAKECONTEXTCURRENT palcMakeContextCurrent = NULL;
65 LPALCPROCESSCONTEXT palcProcessContext = NULL;
66 LPALCSUSPENDCONTEXT palcSuspendContext = NULL;
67 LPALCDESTROYCONTEXT palcDestroyContext = NULL;
68 LPALCGETCURRENTCONTEXT palcGetCurrentContext = NULL;
69 LPALCGETCONTEXTSDEVICE palcGetContextsDevice = NULL;
70 LPALCOPENDEVICE palcOpenDevice = NULL;
71 LPALCCLOSEDEVICE palcCloseDevice = NULL;
72 LPALCGETERROR palcGetError = NULL;
73 LPALCISEXTENSIONPRESENT palcIsExtensionPresent = NULL;
74 LPALCGETPROCADDRESS palcGetProcAddress = NULL;
75 LPALCGETENUMVALUE palcGetEnumValue = NULL;
76 LPALCGETSTRING palcGetString = NULL;
77 LPALCGETINTEGERV palcGetIntegerv = NULL;
78 LPALCCAPTUREOPENDEVICE palcCaptureOpenDevice = NULL;
79 LPALCCAPTURECLOSEDEVICE palcCaptureCloseDevice = NULL;
80 LPALCCAPTURESTART palcCaptureStart = NULL;
81 LPALCCAPTURESTOP palcCaptureStop = NULL;
82 LPALCCAPTURESAMPLES palcCaptureSamples = NULL;
83 LPALENABLE palEnable = NULL;
84 LPALDISABLE palDisable = NULL;
85 LPALISENABLED palIsEnabled = NULL;
86 LPALGETSTRING palGetString = NULL;
87 LPALGETBOOLEANV palGetBooleanv = NULL;
88 LPALGETINTEGERV palGetIntegerv = NULL;
89 LPALGETFLOATV palGetFloatv = NULL;
90 LPALGETDOUBLEV palGetDoublev = NULL;
91 LPALGETBOOLEAN palGetBoolean = NULL;
92 LPALGETINTEGER palGetInteger = NULL;
93 LPALGETFLOAT palGetFloat = NULL;
94 LPALGETDOUBLE palGetDouble = NULL;
95 LPALGETERROR palGetError = NULL;
96 LPALISEXTENSIONPRESENT palIsExtensionPresent = NULL;
97 LPALGETPROCADDRESS palGetProcAddress = NULL;
98 LPALGETENUMVALUE palGetEnumValue = NULL;
99 LPALLISTENERF palListenerf = NULL;
100 LPALLISTENER3F palListener3f = NULL;
101 LPALLISTENERFV palListenerfv = NULL;
102 LPALLISTENERI palListeneri = NULL;
103 LPALLISTENER3I palListener3i = NULL;
104 LPALLISTENERIV palListeneriv = NULL;
105 LPALGETLISTENERF palGetListenerf = NULL;
106 LPALGETLISTENER3F palGetListener3f = NULL;
107 LPALGETLISTENERFV palGetListenerfv = NULL;
108 LPALGETLISTENERI palGetListeneri = NULL;
109 LPALGETLISTENER3I palGetListener3i = NULL;
110 LPALGETLISTENERIV palGetListeneriv = NULL;
111 LPALGENSOURCES palGenSources = NULL;
112 LPALDELETESOURCES palDeleteSources = NULL;
113 LPALISSOURCE palIsSource = NULL;
114 LPALSOURCEF palSourcef = NULL;
115 LPALSOURCE3F palSource3f = NULL;
116 LPALSOURCEFV palSourcefv = NULL;
117 LPALSOURCEI palSourcei = NULL;
118 LPALSOURCE3I palSource3i = NULL;
119 LPALSOURCEIV palSourceiv = NULL;
120 LPALGETSOURCEF palGetSourcef = NULL;
121 LPALGETSOURCE3F palGetSource3f = NULL;
122 LPALGETSOURCEFV palGetSourcefv = NULL;
123 LPALGETSOURCEI palGetSourcei = NULL;
124 LPALGETSOURCE3I palGetSource3i = NULL;
125 LPALGETSOURCEIV palGetSourceiv = NULL;
126 LPALSOURCEPLAYV palSourcePlayv = NULL;
127 LPALSOURCESTOPV palSourceStopv = NULL;
128 LPALSOURCEREWINDV palSourceRewindv = NULL;
129 LPALSOURCEPAUSEV palSourcePausev = NULL;
130 LPALSOURCEPLAY palSourcePlay = NULL;
131 LPALSOURCESTOP palSourceStop = NULL;
132 LPALSOURCEREWIND palSourceRewind = NULL;
133 LPALSOURCEPAUSE palSourcePause = NULL;
134 LPALSOURCEQUEUEBUFFERS palSourceQueueBuffers = NULL;
135 LPALSOURCEUNQUEUEBUFFERS palSourceUnqueueBuffers = NULL;
136 LPALGENBUFFERS palGenBuffers = NULL;
137 LPALDELETEBUFFERS palDeleteBuffers = NULL;
138 LPALISBUFFER palIsBuffer = NULL;
139 LPALBUFFERF palBufferf = NULL;
140 LPALBUFFER3F palBuffer3f = NULL;
141 LPALBUFFERFV palBufferfv = NULL;
142 LPALBUFFERI palBufferi = NULL;
143 LPALBUFFER3I palBuffer3i = NULL;
144 LPALBUFFERIV palBufferiv = NULL;
145 LPALGETBUFFERF palGetBufferf = NULL;
146 LPALGETBUFFER3F palGetBuffer3f = NULL;
147 LPALGETBUFFERFV palGetBufferfv = NULL;
148 LPALGETBUFFERI palGetBufferi = NULL;
149 LPALGETBUFFER3I palGetBuffer3i = NULL;
150 LPALGETBUFFERIV palGetBufferiv = NULL;
151 LPALBUFFERDATA palBufferData = NULL;
152 LPALDOPPLERFACTOR palDopplerFactor = NULL;
153 LPALDOPPLERVELOCITY palDopplerVelocity = NULL;
154 LPALDISTANCEMODEL palDistanceModel = NULL;
155 LPALSPEEDOFSOUND palSpeedOfSound = NULL;
156 #endif
157
158 typeof(alcGetCurrentContext) *get_context;
159 typeof(alcMakeContextCurrent) *set_context;
160
161 static void load_libopenal(void)
162 {
163     DWORD failed = 0;
164
165 #ifdef SONAME_LIBOPENAL
166     char error[128];
167     openal_handle = wine_dlopen(SONAME_LIBOPENAL, RTLD_NOW, error, sizeof(error));
168     if (!openal_handle)
169         ERR("Couldn't load " SONAME_LIBOPENAL ": %s\n", error);
170 #define LOAD_FUNCPTR(f) \
171     if((p##f = wine_dlsym(openal_handle, #f, NULL, 0)) == NULL) { \
172         ERR("Couldn't lookup %s in libopenal\n", #f); \
173         failed = 1; \
174     }
175
176     LOAD_FUNCPTR(alcCreateContext);
177     LOAD_FUNCPTR(alcMakeContextCurrent);
178     LOAD_FUNCPTR(alcProcessContext);
179     LOAD_FUNCPTR(alcSuspendContext);
180     LOAD_FUNCPTR(alcDestroyContext);
181     LOAD_FUNCPTR(alcGetCurrentContext);
182     LOAD_FUNCPTR(alcGetContextsDevice);
183     LOAD_FUNCPTR(alcOpenDevice);
184     LOAD_FUNCPTR(alcCloseDevice);
185     LOAD_FUNCPTR(alcGetError);
186     LOAD_FUNCPTR(alcIsExtensionPresent);
187     LOAD_FUNCPTR(alcGetProcAddress);
188     LOAD_FUNCPTR(alcGetEnumValue);
189     LOAD_FUNCPTR(alcGetString);
190     LOAD_FUNCPTR(alcGetIntegerv);
191     LOAD_FUNCPTR(alcCaptureOpenDevice);
192     LOAD_FUNCPTR(alcCaptureCloseDevice);
193     LOAD_FUNCPTR(alcCaptureStart);
194     LOAD_FUNCPTR(alcCaptureStop);
195     LOAD_FUNCPTR(alcCaptureSamples);
196     LOAD_FUNCPTR(alEnable);
197     LOAD_FUNCPTR(alDisable);
198     LOAD_FUNCPTR(alIsEnabled);
199     LOAD_FUNCPTR(alGetString);
200     LOAD_FUNCPTR(alGetBooleanv);
201     LOAD_FUNCPTR(alGetIntegerv);
202     LOAD_FUNCPTR(alGetFloatv);
203     LOAD_FUNCPTR(alGetDoublev);
204     LOAD_FUNCPTR(alGetBoolean);
205     LOAD_FUNCPTR(alGetInteger);
206     LOAD_FUNCPTR(alGetFloat);
207     LOAD_FUNCPTR(alGetDouble);
208     LOAD_FUNCPTR(alGetError);
209     LOAD_FUNCPTR(alIsExtensionPresent);
210     LOAD_FUNCPTR(alGetProcAddress);
211     LOAD_FUNCPTR(alGetEnumValue);
212     LOAD_FUNCPTR(alListenerf);
213     LOAD_FUNCPTR(alListener3f);
214     LOAD_FUNCPTR(alListenerfv);
215     LOAD_FUNCPTR(alListeneri);
216     LOAD_FUNCPTR(alListener3i);
217     LOAD_FUNCPTR(alListeneriv);
218     LOAD_FUNCPTR(alGetListenerf);
219     LOAD_FUNCPTR(alGetListener3f);
220     LOAD_FUNCPTR(alGetListenerfv);
221     LOAD_FUNCPTR(alGetListeneri);
222     LOAD_FUNCPTR(alGetListener3i);
223     LOAD_FUNCPTR(alGetListeneriv);
224     LOAD_FUNCPTR(alGenSources);
225     LOAD_FUNCPTR(alDeleteSources);
226     LOAD_FUNCPTR(alIsSource);
227     LOAD_FUNCPTR(alSourcef);
228     LOAD_FUNCPTR(alSource3f);
229     LOAD_FUNCPTR(alSourcefv);
230     LOAD_FUNCPTR(alSourcei);
231     LOAD_FUNCPTR(alSource3i);
232     LOAD_FUNCPTR(alSourceiv);
233     LOAD_FUNCPTR(alGetSourcef);
234     LOAD_FUNCPTR(alGetSource3f);
235     LOAD_FUNCPTR(alGetSourcefv);
236     LOAD_FUNCPTR(alGetSourcei);
237     LOAD_FUNCPTR(alGetSource3i);
238     LOAD_FUNCPTR(alGetSourceiv);
239     LOAD_FUNCPTR(alSourcePlayv);
240     LOAD_FUNCPTR(alSourceStopv);
241     LOAD_FUNCPTR(alSourceRewindv);
242     LOAD_FUNCPTR(alSourcePausev);
243     LOAD_FUNCPTR(alSourcePlay);
244     LOAD_FUNCPTR(alSourceStop);
245     LOAD_FUNCPTR(alSourceRewind);
246     LOAD_FUNCPTR(alSourcePause);
247     LOAD_FUNCPTR(alSourceQueueBuffers);
248     LOAD_FUNCPTR(alSourceUnqueueBuffers);
249     LOAD_FUNCPTR(alGenBuffers);
250     LOAD_FUNCPTR(alDeleteBuffers);
251     LOAD_FUNCPTR(alIsBuffer);
252     LOAD_FUNCPTR(alBufferf);
253     LOAD_FUNCPTR(alBuffer3f);
254     LOAD_FUNCPTR(alBufferfv);
255     LOAD_FUNCPTR(alBufferi);
256     LOAD_FUNCPTR(alBuffer3i);
257     LOAD_FUNCPTR(alBufferiv);
258     LOAD_FUNCPTR(alGetBufferf);
259     LOAD_FUNCPTR(alGetBuffer3f);
260     LOAD_FUNCPTR(alGetBufferfv);
261     LOAD_FUNCPTR(alGetBufferi);
262     LOAD_FUNCPTR(alGetBuffer3i);
263     LOAD_FUNCPTR(alGetBufferiv);
264     LOAD_FUNCPTR(alBufferData);
265     LOAD_FUNCPTR(alDopplerFactor);
266     LOAD_FUNCPTR(alDopplerVelocity);
267     LOAD_FUNCPTR(alDistanceModel);
268     LOAD_FUNCPTR(alSpeedOfSound);
269 #undef LOAD_FUNCPTR
270 #endif
271
272     if (failed)
273     {
274         WARN("Unloading openal\n");
275         if (openal_handle != RTLD_DEFAULT)
276             wine_dlclose(openal_handle, NULL, 0);
277         openal_handle = NULL;
278         openal_loaded = 0;
279     }
280     else
281     {
282         openal_loaded = 1;
283         local_contexts = palcIsExtensionPresent(NULL, "ALC_EXT_thread_local_context");
284         if (local_contexts)
285         {
286             set_context = palcGetProcAddress(NULL, "alcSetThreadContext");
287             get_context = palcGetProcAddress(NULL, "alcGetThreadContext");
288             if (!set_context || !get_context)
289             {
290                 ERR("TLS advertised but functions not found, disabling thread local context\n");
291                 local_contexts = 0;
292             }
293         }
294         if (!local_contexts)
295         {
296             set_context = palcMakeContextCurrent;
297             get_context = palcGetCurrentContext;
298         }
299     }
300 }
301
302 #endif /*HAVE_OPENAL*/
303
304 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
305 {
306     TRACE("(0x%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
307
308     switch (fdwReason)
309     {
310         case DLL_PROCESS_ATTACH:
311             DisableThreadLibraryCalls(hinstDLL);
312 #ifdef HAVE_OPENAL
313             load_libopenal();
314 #endif /*HAVE_OPENAL*/
315             break;
316         case DLL_PROCESS_DETACH:
317             MMDevEnum_Free();
318             break;
319     }
320
321     return TRUE;
322 }
323
324 HRESULT WINAPI DllCanUnloadNow(void)
325 {
326     return S_FALSE;
327 }
328
329 typedef HRESULT (*FnCreateInstance)(REFIID riid, LPVOID *ppobj);
330
331 typedef struct {
332     const IClassFactoryVtbl *lpVtbl;
333     REFCLSID rclsid;
334     FnCreateInstance pfnCreateInstance;
335 } IClassFactoryImpl;
336
337 static HRESULT WINAPI
338 MMCF_QueryInterface(LPCLASSFACTORY iface, REFIID riid, LPVOID *ppobj)
339 {
340     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
341     TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppobj);
342     if (ppobj == NULL)
343         return E_POINTER;
344     if (IsEqualIID(riid, &IID_IUnknown) ||
345         IsEqualIID(riid, &IID_IClassFactory))
346     {
347         *ppobj = iface;
348         IUnknown_AddRef(iface);
349         return S_OK;
350     }
351     *ppobj = NULL;
352     return E_NOINTERFACE;
353 }
354
355 static ULONG WINAPI MMCF_AddRef(LPCLASSFACTORY iface)
356 {
357     return 2;
358 }
359
360 static ULONG WINAPI MMCF_Release(LPCLASSFACTORY iface)
361 {
362     /* static class, won't be freed */
363     return 1;
364 }
365
366 static HRESULT WINAPI MMCF_CreateInstance(
367     LPCLASSFACTORY iface,
368     LPUNKNOWN pOuter,
369     REFIID riid,
370     LPVOID *ppobj)
371 {
372     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
373     TRACE("(%p, %p, %s, %p)\n", This, pOuter, debugstr_guid(riid), ppobj);
374
375     if (pOuter)
376         return CLASS_E_NOAGGREGATION;
377
378     if (ppobj == NULL) {
379         WARN("invalid parameter\n");
380         return E_POINTER;
381     }
382     *ppobj = NULL;
383     return This->pfnCreateInstance(riid, ppobj);
384 }
385
386 static HRESULT WINAPI MMCF_LockServer(LPCLASSFACTORY iface, BOOL dolock)
387 {
388     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
389     FIXME("(%p, %d) stub!\n", This, dolock);
390     return S_OK;
391 }
392
393 static const IClassFactoryVtbl MMCF_Vtbl = {
394     MMCF_QueryInterface,
395     MMCF_AddRef,
396     MMCF_Release,
397     MMCF_CreateInstance,
398     MMCF_LockServer
399 };
400
401 static IClassFactoryImpl MMDEVAPI_CF[] = {
402     { &MMCF_Vtbl, &CLSID_MMDeviceEnumerator, (FnCreateInstance)MMDevEnum_Create }
403 };
404
405 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
406 {
407     int i = 0;
408     TRACE("(%s, %s, %p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
409
410     if (ppv == NULL) {
411         WARN("invalid parameter\n");
412         return E_INVALIDARG;
413     }
414
415     *ppv = NULL;
416
417     if (!IsEqualIID(riid, &IID_IClassFactory) &&
418         !IsEqualIID(riid, &IID_IUnknown)) {
419         WARN("no interface for %s\n", debugstr_guid(riid));
420         return E_NOINTERFACE;
421     }
422
423     for (i = 0; i < sizeof(MMDEVAPI_CF)/sizeof(MMDEVAPI_CF[0]); ++i)
424     {
425         if (IsEqualGUID(rclsid, MMDEVAPI_CF[i].rclsid)) {
426             IUnknown_AddRef((IClassFactory*) &MMDEVAPI_CF[i]);
427             *ppv = &MMDEVAPI_CF[i];
428             return S_OK;
429         }
430         i++;
431     }
432
433     WARN("(%s, %s, %p): no class found.\n", debugstr_guid(rclsid),
434          debugstr_guid(riid), ppv);
435     return CLASS_E_CLASSNOTAVAILABLE;
436 }