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