mmdevapi: Use wide-char string literals.
[wine.git] / dlls / mmdevapi / main.c
blob247ebc3b00184a578e36bae7e695bc2c90378974
1 /*
2 * Copyright 2009 Maarten Lankhorst
3 * Copyright 2011 Andrew Eikum for CodeWeavers
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include <stdarg.h>
22 #define COBJMACROS
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wingdi.h"
27 #include "ole2.h"
28 #include "olectl.h"
29 #include "rpcproxy.h"
30 #include "propsys.h"
31 #include "propkeydef.h"
32 #include "mmdeviceapi.h"
33 #include "mmsystem.h"
34 #include "dsound.h"
35 #include "audioclient.h"
36 #include "endpointvolume.h"
37 #include "audiopolicy.h"
38 #include "devpkey.h"
39 #include "winreg.h"
41 #include "mmdevapi.h"
42 #include "wine/debug.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(mmdevapi);
46 static HINSTANCE instance;
48 DriverFuncs drvs;
50 const WCHAR drv_keyW[] = L"Software\\Wine\\Drivers";
52 static const char *get_priority_string(int prio)
54 switch(prio){
55 case Priority_Unavailable:
56 return "Unavailable";
57 case Priority_Low:
58 return "Low";
59 case Priority_Neutral:
60 return "Neutral";
61 case Priority_Preferred:
62 return "Preferred";
64 return "Invalid";
67 static BOOL load_driver(const WCHAR *name, DriverFuncs *driver)
69 WCHAR driver_module[264];
71 lstrcpyW(driver_module, L"wine");
72 lstrcatW(driver_module, name);
73 lstrcatW(driver_module, L".drv");
75 TRACE("Attempting to load %s\n", wine_dbgstr_w(driver_module));
77 driver->module = LoadLibraryW(driver_module);
78 if(!driver->module){
79 TRACE("Unable to load %s: %u\n", wine_dbgstr_w(driver_module),
80 GetLastError());
81 return FALSE;
84 #define LDFC(n) do { driver->p##n = (void*)GetProcAddress(driver->module, #n);\
85 if(!driver->p##n) { FreeLibrary(driver->module); return FALSE; } } while(0)
86 LDFC(GetPriority);
87 LDFC(GetEndpointIDs);
88 LDFC(GetAudioEndpoint);
89 LDFC(GetAudioSessionManager);
90 #undef LDFC
92 /* optional - do not fail if not found */
93 driver->pGetPropValue = (void*)GetProcAddress(driver->module, "GetPropValue");
95 driver->priority = driver->pGetPriority();
96 lstrcpyW(driver->module_name, driver_module);
98 TRACE("Successfully loaded %s with priority %s\n",
99 wine_dbgstr_w(driver_module), get_priority_string(driver->priority));
101 return TRUE;
104 static BOOL WINAPI init_driver(INIT_ONCE *once, void *param, void **context)
106 static WCHAR default_list[] = L"pulse,alsa,oss,coreaudio,android";
107 DriverFuncs driver;
108 HKEY key;
109 WCHAR reg_list[256], *p, *next, *driver_list = default_list;
111 if(RegOpenKeyW(HKEY_CURRENT_USER, drv_keyW, &key) == ERROR_SUCCESS){
112 DWORD size = sizeof(reg_list);
114 if(RegQueryValueExW(key, L"Audio", 0, NULL, (BYTE*)reg_list, &size) == ERROR_SUCCESS){
115 if(reg_list[0] == '\0'){
116 TRACE("User explicitly chose no driver\n");
117 RegCloseKey(key);
118 return TRUE;
121 driver_list = reg_list;
124 RegCloseKey(key);
127 TRACE("Loading driver list %s\n", wine_dbgstr_w(driver_list));
128 for(next = p = driver_list; next; p = next + 1){
129 next = wcschr(p, ',');
130 if(next)
131 *next = '\0';
133 driver.priority = Priority_Unavailable;
134 if(load_driver(p, &driver)){
135 if(driver.priority == Priority_Unavailable)
136 FreeLibrary(driver.module);
137 else if(!drvs.module || driver.priority > drvs.priority){
138 TRACE("Selecting driver %s with priority %s\n",
139 wine_dbgstr_w(p), get_priority_string(driver.priority));
140 if(drvs.module)
141 FreeLibrary(drvs.module);
142 drvs = driver;
143 }else
144 FreeLibrary(driver.module);
145 }else
146 TRACE("Failed to load driver %s\n", wine_dbgstr_w(p));
148 if(next)
149 *next = ',';
152 return drvs.module != 0;
155 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
157 TRACE("(0x%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
159 switch (fdwReason)
161 case DLL_PROCESS_ATTACH:
162 instance = hinstDLL;
163 DisableThreadLibraryCalls(hinstDLL);
164 break;
165 case DLL_PROCESS_DETACH:
166 if(lpvReserved)
167 break;
168 MMDevEnum_Free();
169 break;
172 return TRUE;
175 HRESULT WINAPI DllCanUnloadNow(void)
177 return S_FALSE;
180 typedef HRESULT (*FnCreateInstance)(REFIID riid, LPVOID *ppobj);
182 typedef struct {
183 IClassFactory IClassFactory_iface;
184 REFCLSID rclsid;
185 FnCreateInstance pfnCreateInstance;
186 } IClassFactoryImpl;
188 static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
190 return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface);
193 static HRESULT WINAPI
194 MMCF_QueryInterface(IClassFactory *iface, REFIID riid, void **ppobj)
196 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
197 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppobj);
198 if (ppobj == NULL)
199 return E_POINTER;
200 if (IsEqualIID(riid, &IID_IUnknown) ||
201 IsEqualIID(riid, &IID_IClassFactory))
203 *ppobj = iface;
204 IClassFactory_AddRef(iface);
205 return S_OK;
207 *ppobj = NULL;
208 return E_NOINTERFACE;
211 static ULONG WINAPI MMCF_AddRef(LPCLASSFACTORY iface)
213 return 2;
216 static ULONG WINAPI MMCF_Release(LPCLASSFACTORY iface)
218 /* static class, won't be freed */
219 return 1;
222 static HRESULT WINAPI MMCF_CreateInstance(
223 LPCLASSFACTORY iface,
224 LPUNKNOWN pOuter,
225 REFIID riid,
226 LPVOID *ppobj)
228 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
229 TRACE("(%p, %p, %s, %p)\n", This, pOuter, debugstr_guid(riid), ppobj);
231 if (pOuter)
232 return CLASS_E_NOAGGREGATION;
234 if (ppobj == NULL) {
235 WARN("invalid parameter\n");
236 return E_POINTER;
238 *ppobj = NULL;
239 return This->pfnCreateInstance(riid, ppobj);
242 static HRESULT WINAPI MMCF_LockServer(LPCLASSFACTORY iface, BOOL dolock)
244 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
245 FIXME("(%p, %d) stub!\n", This, dolock);
246 return S_OK;
249 static const IClassFactoryVtbl MMCF_Vtbl = {
250 MMCF_QueryInterface,
251 MMCF_AddRef,
252 MMCF_Release,
253 MMCF_CreateInstance,
254 MMCF_LockServer
257 static IClassFactoryImpl MMDEVAPI_CF[] = {
258 { { &MMCF_Vtbl }, &CLSID_MMDeviceEnumerator, (FnCreateInstance)MMDevEnum_Create }
261 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
263 static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
264 unsigned int i = 0;
265 TRACE("(%s, %s, %p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
267 if(!InitOnceExecuteOnce(&init_once, init_driver, NULL, NULL)) {
268 ERR("Driver initialization failed\n");
269 return E_FAIL;
272 if (ppv == NULL) {
273 WARN("invalid parameter\n");
274 return E_INVALIDARG;
277 *ppv = NULL;
279 if (!IsEqualIID(riid, &IID_IClassFactory) &&
280 !IsEqualIID(riid, &IID_IUnknown)) {
281 WARN("no interface for %s\n", debugstr_guid(riid));
282 return E_NOINTERFACE;
285 for (i = 0; i < ARRAY_SIZE(MMDEVAPI_CF); ++i)
287 if (IsEqualGUID(rclsid, MMDEVAPI_CF[i].rclsid)) {
288 IClassFactory_AddRef(&MMDEVAPI_CF[i].IClassFactory_iface);
289 *ppv = &MMDEVAPI_CF[i];
290 return S_OK;
294 WARN("(%s, %s, %p): no class found.\n", debugstr_guid(rclsid),
295 debugstr_guid(riid), ppv);
296 return CLASS_E_CLASSNOTAVAILABLE;
299 /***********************************************************************
300 * DllRegisterServer (MMDEVAPI.@)
302 HRESULT WINAPI DllRegisterServer(void)
304 return __wine_register_resources( instance );
307 /***********************************************************************
308 * DllUnregisterServer (MMDEVAPI.@)
310 HRESULT WINAPI DllUnregisterServer(void)
312 return __wine_unregister_resources( instance );
315 struct activate_async_op {
316 IActivateAudioInterfaceAsyncOperation IActivateAudioInterfaceAsyncOperation_iface;
317 LONG ref;
319 IActivateAudioInterfaceCompletionHandler *callback;
320 HRESULT result_hr;
321 IUnknown *result_iface;
324 static struct activate_async_op *impl_from_IActivateAudioInterfaceAsyncOperation(IActivateAudioInterfaceAsyncOperation *iface)
326 return CONTAINING_RECORD(iface, struct activate_async_op, IActivateAudioInterfaceAsyncOperation_iface);
329 static HRESULT WINAPI activate_async_op_QueryInterface(IActivateAudioInterfaceAsyncOperation *iface,
330 REFIID riid, void **ppv)
332 struct activate_async_op *This = impl_from_IActivateAudioInterfaceAsyncOperation(iface);
334 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
336 if (!ppv)
337 return E_POINTER;
339 if (IsEqualIID(riid, &IID_IUnknown) ||
340 IsEqualIID(riid, &IID_IActivateAudioInterfaceAsyncOperation)) {
341 *ppv = &This->IActivateAudioInterfaceAsyncOperation_iface;
342 } else {
343 *ppv = NULL;
344 return E_NOINTERFACE;
347 IUnknown_AddRef((IUnknown*)*ppv);
348 return S_OK;
351 static ULONG WINAPI activate_async_op_AddRef(IActivateAudioInterfaceAsyncOperation *iface)
353 struct activate_async_op *This = impl_from_IActivateAudioInterfaceAsyncOperation(iface);
354 LONG ref = InterlockedIncrement(&This->ref);
355 TRACE("(%p) refcount now %i\n", This, ref);
356 return ref;
359 static ULONG WINAPI activate_async_op_Release(IActivateAudioInterfaceAsyncOperation *iface)
361 struct activate_async_op *This = impl_from_IActivateAudioInterfaceAsyncOperation(iface);
362 LONG ref = InterlockedDecrement(&This->ref);
363 TRACE("(%p) refcount now %i\n", This, ref);
364 if (!ref) {
365 if(This->result_iface)
366 IUnknown_Release(This->result_iface);
367 IActivateAudioInterfaceCompletionHandler_Release(This->callback);
368 HeapFree(GetProcessHeap(), 0, This);
370 return ref;
373 static HRESULT WINAPI activate_async_op_GetActivateResult(IActivateAudioInterfaceAsyncOperation *iface,
374 HRESULT *result_hr, IUnknown **result_iface)
376 struct activate_async_op *This = impl_from_IActivateAudioInterfaceAsyncOperation(iface);
378 TRACE("(%p)->(%p, %p)\n", This, result_hr, result_iface);
380 *result_hr = This->result_hr;
382 if(This->result_hr == S_OK){
383 *result_iface = This->result_iface;
384 IUnknown_AddRef(*result_iface);
387 return S_OK;
390 static IActivateAudioInterfaceAsyncOperationVtbl IActivateAudioInterfaceAsyncOperation_vtbl = {
391 activate_async_op_QueryInterface,
392 activate_async_op_AddRef,
393 activate_async_op_Release,
394 activate_async_op_GetActivateResult,
397 static DWORD WINAPI activate_async_threadproc(void *user)
399 struct activate_async_op *op = user;
401 IActivateAudioInterfaceCompletionHandler_ActivateCompleted(op->callback, &op->IActivateAudioInterfaceAsyncOperation_iface);
403 IActivateAudioInterfaceAsyncOperation_Release(&op->IActivateAudioInterfaceAsyncOperation_iface);
405 return 0;
408 static HRESULT get_mmdevice_by_activatepath(const WCHAR *path, IMMDevice **mmdev)
410 IMMDeviceEnumerator *devenum;
411 HRESULT hr;
413 static const WCHAR DEVINTERFACE_AUDIO_RENDER_WSTR[] = L"{E6327CAD-DCEC-4949-AE8A-991E976A79D2}";
414 static const WCHAR DEVINTERFACE_AUDIO_CAPTURE_WSTR[] = L"{2EEF81BE-33FA-4800-9670-1CD474972C3F}";
416 hr = MMDevEnum_Create(&IID_IMMDeviceEnumerator, (void**)&devenum);
417 if (FAILED(hr)) {
418 WARN("Failed to create MMDeviceEnumerator: %08x\n", hr);
419 return hr;
422 if (!lstrcmpiW(path, DEVINTERFACE_AUDIO_RENDER_WSTR)){
423 hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(devenum, eRender, eMultimedia, mmdev);
424 } else if (!lstrcmpiW(path, DEVINTERFACE_AUDIO_CAPTURE_WSTR)){
425 hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(devenum, eCapture, eMultimedia, mmdev);
426 } else {
427 FIXME("How to map path to device id? %s\n", debugstr_w(path));
428 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
431 if (FAILED(hr)) {
432 WARN("Failed to get requested device (%s): %08x\n", debugstr_w(path), hr);
433 *mmdev = NULL;
434 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
437 IMMDeviceEnumerator_Release(devenum);
439 return hr;
442 /***********************************************************************
443 * ActivateAudioInterfaceAsync (MMDEVAPI.17)
445 HRESULT WINAPI ActivateAudioInterfaceAsync(const WCHAR *path, REFIID riid,
446 PROPVARIANT *params, IActivateAudioInterfaceCompletionHandler *done_handler,
447 IActivateAudioInterfaceAsyncOperation **op_out)
449 struct activate_async_op *op;
450 HANDLE ht;
451 IMMDevice *mmdev;
453 TRACE("(%s, %s, %p, %p, %p)\n", debugstr_w(path), debugstr_guid(riid),
454 params, done_handler, op_out);
456 op = HeapAlloc(GetProcessHeap(), 0, sizeof(*op));
457 if (!op)
458 return E_OUTOFMEMORY;
460 op->ref = 2; /* returned ref and threadproc ref */
461 op->IActivateAudioInterfaceAsyncOperation_iface.lpVtbl = &IActivateAudioInterfaceAsyncOperation_vtbl;
462 op->callback = done_handler;
463 IActivateAudioInterfaceCompletionHandler_AddRef(done_handler);
465 op->result_hr = get_mmdevice_by_activatepath(path, &mmdev);
466 if (SUCCEEDED(op->result_hr)) {
467 op->result_hr = IMMDevice_Activate(mmdev, riid, CLSCTX_INPROC_SERVER, params, (void**)&op->result_iface);
468 IMMDevice_Release(mmdev);
469 }else
470 op->result_iface = NULL;
472 ht = CreateThread(NULL, 0, &activate_async_threadproc, op, 0, NULL);
473 CloseHandle(ht);
475 *op_out = &op->IActivateAudioInterfaceAsyncOperation_iface;
477 return S_OK;