2 * Copyright 2009 Maarten Lankhorst
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.
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.
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
29 #include "wine/debug.h"
32 #include "mmdeviceapi.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(mmdevapi);
38 static const WCHAR software_mmdevapi[] =
39 { 'S','o','f','t','w','a','r','e','\\',
40 'M','i','c','r','o','s','o','f','t','\\',
41 'W','i','n','d','o','w','s','\\',
42 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
43 'M','M','D','e','v','i','c','e','s','\\',
44 'A','u','d','i','o',0};
45 static const WCHAR reg_render[] =
46 { 'R','e','n','d','e','r',0 };
47 static const WCHAR reg_capture[] =
48 { 'C','a','p','t','u','r','e',0 };
49 static const WCHAR reg_devicestate[] =
50 { 'D','e','v','i','c','e','S','t','a','t','e',0 };
51 static const WCHAR reg_alname[] =
52 { 'A','L','N','a','m','e',0 };
53 static const WCHAR reg_properties[] =
54 { 'P','r','o','p','e','r','t','i','e','s',0 };
56 typedef struct MMDevEnumImpl
58 const IMMDeviceEnumeratorVtbl *lpVtbl;
62 static MMDevEnumImpl *MMDevEnumerator;
63 static const IMMDeviceEnumeratorVtbl MMDevEnumVtbl;
64 static const IMMDeviceCollectionVtbl MMDevColVtbl;
66 typedef struct MMDevColImpl
68 const IMMDeviceCollectionVtbl *lpVtbl;
74 /* Creates or updates the state of a device
75 * If GUID is null, a random guid will be assigned
76 * and the device will be created
78 static void MMDevice_Create(WCHAR *name, GUID *id, EDataFlow flow, DWORD state)
83 static HRESULT MMDevCol_Create(IMMDeviceCollection **ppv, EDataFlow flow, DWORD state)
87 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
91 This->lpVtbl = &MMDevColVtbl;
95 *ppv = (IMMDeviceCollection*)This;
99 static void MMDevCol_Destroy(MMDevColImpl *This)
101 HeapFree(GetProcessHeap(), 0, This);
104 static HRESULT WINAPI MMDevCol_QueryInterface(IMMDeviceCollection *iface, REFIID riid, void **ppv)
106 MMDevColImpl *This = (MMDevColImpl*)iface;
110 if (IsEqualIID(riid, &IID_IUnknown)
111 || IsEqualIID(riid, &IID_IMMDeviceCollection))
116 return E_NOINTERFACE;
117 IUnknown_AddRef((IUnknown*)*ppv);
121 static ULONG WINAPI MMDevCol_AddRef(IMMDeviceCollection *iface)
123 MMDevColImpl *This = (MMDevColImpl*)iface;
124 LONG ref = InterlockedIncrement(&This->ref);
125 TRACE("Refcount now %i\n", ref);
129 static ULONG WINAPI MMDevCol_Release(IMMDeviceCollection *iface)
131 MMDevColImpl *This = (MMDevColImpl*)iface;
132 LONG ref = InterlockedDecrement(&This->ref);
133 TRACE("Refcount now %i\n", ref);
135 MMDevCol_Destroy(This);
139 static HRESULT WINAPI MMDevCol_GetCount(IMMDeviceCollection *iface, UINT *numdevs)
141 MMDevColImpl *This = (MMDevColImpl*)iface;
142 TRACE("(%p)->(%p)\n", This, numdevs);
149 static HRESULT WINAPI MMDevCol_Item(IMMDeviceCollection *iface, UINT i, IMMDevice **dev)
151 MMDevColImpl *This = (MMDevColImpl*)iface;
152 TRACE("(%p)->(%u, %p)\n", This, i, dev);
159 static const IMMDeviceCollectionVtbl MMDevColVtbl =
161 MMDevCol_QueryInterface,
168 HRESULT MMDevEnum_Create(REFIID riid, void **ppv)
170 MMDevEnumImpl *This = MMDevEnumerator;
175 HKEY root, cur, key_capture = NULL, key_render = NULL;
178 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
181 return E_OUTOFMEMORY;
183 This->lpVtbl = &MMDevEnumVtbl;
184 MMDevEnumerator = This;
186 ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, software_mmdevapi, 0, KEY_READ, &root);
187 if (ret == ERROR_SUCCESS)
188 ret = RegOpenKeyExW(root, reg_capture, 0, KEY_READ, &key_capture);
189 if (ret == ERROR_SUCCESS)
190 ret = RegOpenKeyExW(root, reg_render, 0, KEY_READ, &key_render);
192 if (ret != ERROR_SUCCESS)
194 RegCloseKey(key_capture);
195 RegCloseKey(key_render);
196 TRACE("Couldn't open key: %u\n", ret);
204 len = sizeof(guidvalue);
205 ret = RegEnumKeyExW(cur, i++, guidvalue, &len, NULL, NULL, NULL, NULL);
206 if (ret == ERROR_NO_MORE_ITEMS)
208 if (cur == key_capture)
216 if (ret != ERROR_SUCCESS)
218 len = sizeof(alname);
219 RegGetValueW(cur, guidvalue, reg_alname, RRF_RT_REG_SZ, NULL, alname, &len);
220 if (SUCCEEDED(CLSIDFromString(guidvalue, &guid)))
221 MMDevice_Create(alname, &guid,
222 cur == key_capture ? eCapture : eRender,
223 DEVICE_STATE_NOTPRESENT);
227 return IUnknown_QueryInterface((IUnknown*)This, riid, ppv);
230 void MMDevEnum_Free(void)
232 HeapFree(GetProcessHeap(), 0, MMDevEnumerator);
233 MMDevEnumerator = NULL;
236 static HRESULT WINAPI MMDevEnum_QueryInterface(IMMDeviceEnumerator *iface, REFIID riid, void **ppv)
238 MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
242 if (IsEqualIID(riid, &IID_IUnknown)
243 || IsEqualIID(riid, &IID_IMMDeviceEnumerator))
248 return E_NOINTERFACE;
249 IUnknown_AddRef((IUnknown*)*ppv);
253 static ULONG WINAPI MMDevEnum_AddRef(IMMDeviceEnumerator *iface)
255 MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
256 LONG ref = InterlockedIncrement(&This->ref);
257 TRACE("Refcount now %i\n", ref);
261 static ULONG WINAPI MMDevEnum_Release(IMMDeviceEnumerator *iface)
263 MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
264 LONG ref = InterlockedDecrement(&This->ref);
267 TRACE("Refcount now %i\n", ref);
271 static HRESULT WINAPI MMDevEnum_EnumAudioEndpoints(IMMDeviceEnumerator *iface, EDataFlow flow, DWORD mask, IMMDeviceCollection **devices)
273 MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
274 TRACE("(%p)->(%u,%u,%p)\n", This, flow, mask, devices);
278 if (flow >= EDataFlow_enum_count)
280 if (mask & ~DEVICE_STATEMASK_ALL)
282 return MMDevCol_Create(devices, flow, mask);
285 static HRESULT WINAPI MMDevEnum_GetDefaultAudioEndpoint(IMMDeviceEnumerator *iface, EDataFlow flow, ERole role, IMMDevice **device)
287 MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
288 TRACE("(%p)->(%u,%u,%p)\n", This, flow, role, device);
293 static HRESULT WINAPI MMDevEnum_GetDevice(IMMDeviceEnumerator *iface, const WCHAR *name, IMMDevice **device)
295 MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
296 TRACE("(%p)->(%s,%p)\n", This, debugstr_w(name), device);
301 static HRESULT WINAPI MMDevEnum_RegisterEndpointNotificationCallback(IMMDeviceEnumerator *iface, IMMNotificationClient *client)
303 MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
304 TRACE("(%p)->(%p)\n", This, client);
309 static HRESULT WINAPI MMDevEnum_UnregisterEndpointNotificationCallback(IMMDeviceEnumerator *iface, IMMNotificationClient *client)
311 MMDevEnumImpl *This = (MMDevEnumImpl*)iface;
312 TRACE("(%p)->(%p)\n", This, client);
317 static const IMMDeviceEnumeratorVtbl MMDevEnumVtbl =
319 MMDevEnum_QueryInterface,
322 MMDevEnum_EnumAudioEndpoints,
323 MMDevEnum_GetDefaultAudioEndpoint,
325 MMDevEnum_RegisterEndpointNotificationCallback,
326 MMDevEnum_UnregisterEndpointNotificationCallback