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
19 #define NONAMELESSUNION
30 #include "wine/debug.h"
31 #include "wine/unicode.h"
34 #include "mmdeviceapi.h"
37 #include "audioclient.h"
38 #include "endpointvolume.h"
39 #include "audiopolicy.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(mmdevapi
);
46 static const WCHAR software_mmdevapi
[] =
47 { 'S','o','f','t','w','a','r','e','\\',
48 'M','i','c','r','o','s','o','f','t','\\',
49 'W','i','n','d','o','w','s','\\',
50 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
51 'M','M','D','e','v','i','c','e','s','\\',
52 'A','u','d','i','o',0};
53 static const WCHAR reg_render
[] =
54 { 'R','e','n','d','e','r',0 };
55 static const WCHAR reg_capture
[] =
56 { 'C','a','p','t','u','r','e',0 };
57 static const WCHAR reg_devicestate
[] =
58 { 'D','e','v','i','c','e','S','t','a','t','e',0 };
59 static const WCHAR reg_properties
[] =
60 { 'P','r','o','p','e','r','t','i','e','s',0 };
62 static HKEY key_render
;
63 static HKEY key_capture
;
65 typedef struct MMDevPropStoreImpl
67 const IPropertyStoreVtbl
*lpVtbl
;
73 typedef struct MMDevEnumImpl
75 const IMMDeviceEnumeratorVtbl
*lpVtbl
;
79 static MMDevEnumImpl
*MMDevEnumerator
;
80 static MMDevice
**MMDevice_head
;
81 static MMDevice
*MMDevice_def_rec
, *MMDevice_def_play
;
82 static DWORD MMDevice_count
;
83 static const IMMDeviceEnumeratorVtbl MMDevEnumVtbl
;
84 static const IMMDeviceCollectionVtbl MMDevColVtbl
;
85 static const IMMDeviceVtbl MMDeviceVtbl
;
86 static const IPropertyStoreVtbl MMDevPropVtbl
;
87 static const IMMEndpointVtbl MMEndpointVtbl
;
89 typedef struct MMDevColImpl
91 const IMMDeviceCollectionVtbl
*lpVtbl
;
97 typedef struct IPropertyBagImpl
{
98 const IPropertyBagVtbl
*lpVtbl
;
101 static const IPropertyBagVtbl PB_Vtbl
;
103 static HRESULT
MMDevPropStore_Create(MMDevice
*This
, DWORD access
, IPropertyStore
**ppv
);
105 /* Creates or updates the state of a device
106 * If GUID is null, a random guid will be assigned
107 * and the device will be created
109 static void MMDevice_Create(WCHAR
*name
, GUID
*id
, EDataFlow flow
, DWORD state
, BOOL setdefault
)
116 for (i
= 0; i
< MMDevice_count
; ++i
)
118 cur
= MMDevice_head
[i
];
119 if (cur
->flow
== flow
&& !lstrcmpW(cur
->alname
, name
))
122 /* Same device, update state */
124 StringFromGUID2(&cur
->devguid
, guidstr
, sizeof(guidstr
)/sizeof(*guidstr
));
125 ret
= RegOpenKeyExW(flow
== eRender
? key_render
: key_capture
, guidstr
, 0, KEY_WRITE
, &key
);
126 if (ret
== ERROR_SUCCESS
)
128 RegSetValueExW(key
, reg_devicestate
, 0, REG_DWORD
, (const BYTE
*)&state
, sizeof(DWORD
));
135 /* No device found, allocate new one */
136 cur
= HeapAlloc(GetProcessHeap(), 0, sizeof(*cur
));
139 cur
->alname
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(name
)+1)*sizeof(WCHAR
));
142 HeapFree(GetProcessHeap(), 0, cur
);
145 lstrcpyW(cur
->alname
, name
);
146 cur
->lpVtbl
= &MMDeviceVtbl
;
147 cur
->lpEndpointVtbl
= &MMEndpointVtbl
;
149 InitializeCriticalSection(&cur
->crst
);
150 cur
->crst
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": MMDevice.crst");
159 StringFromGUID2(id
, guidstr
, sizeof(guidstr
)/sizeof(*guidstr
));
164 if (!RegCreateKeyExW(root
, guidstr
, 0, NULL
, 0, KEY_WRITE
|KEY_READ
, NULL
, &key
, NULL
))
167 RegSetValueExW(key
, reg_devicestate
, 0, REG_DWORD
, (const BYTE
*)&state
, sizeof(DWORD
));
168 if (!RegCreateKeyExW(key
, reg_properties
, 0, NULL
, 0, KEY_WRITE
|KEY_READ
, NULL
, &keyprop
, NULL
))
173 MMDevice_SetPropValue(id
, flow
, (const PROPERTYKEY
*)&DEVPKEY_Device_FriendlyName
, &pv
);
174 MMDevice_SetPropValue(id
, flow
, (const PROPERTYKEY
*)&DEVPKEY_Device_DeviceDesc
, &pv
);
175 RegCloseKey(keyprop
);
180 MMDevice_head
= HeapAlloc(GetProcessHeap(), 0, sizeof(*MMDevice_head
));
182 MMDevice_head
= HeapReAlloc(GetProcessHeap(), 0, MMDevice_head
, sizeof(*MMDevice_head
)*(1+MMDevice_count
));
183 MMDevice_head
[MMDevice_count
++] = cur
;
189 MMDevice_def_play
= cur
;
191 MMDevice_def_rec
= cur
;
195 static void MMDevice_Destroy(MMDevice
*This
)
198 TRACE("Freeing %s\n", debugstr_w(This
->alname
));
199 /* Since this function is called at destruction time, reordering of the list is unimportant */
200 for (i
= 0; i
< MMDevice_count
; ++i
)
202 if (MMDevice_head
[i
] == This
)
204 MMDevice_head
[i
] = MMDevice_head
[--MMDevice_count
];
208 This
->crst
.DebugInfo
->Spare
[0] = 0;
209 DeleteCriticalSection(&This
->crst
);
210 HeapFree(GetProcessHeap(), 0, This
->alname
);
211 HeapFree(GetProcessHeap(), 0, This
);
214 static HRESULT WINAPI
MMDevice_QueryInterface(IMMDevice
*iface
, REFIID riid
, void **ppv
)
216 MMDevice
*This
= (MMDevice
*)iface
;
217 TRACE("(%p)->(%s,%p)\n", iface
, debugstr_guid(riid
), ppv
);
222 if (IsEqualIID(riid
, &IID_IUnknown
)
223 || IsEqualIID(riid
, &IID_IMMDevice
))
225 else if (IsEqualIID(riid
, &IID_IMMEndpoint
))
226 *ppv
= &This
->lpEndpointVtbl
;
229 IUnknown_AddRef((IUnknown
*)*ppv
);
232 WARN("Unknown interface %s\n", debugstr_guid(riid
));
233 return E_NOINTERFACE
;
236 static ULONG WINAPI
MMDevice_AddRef(IMMDevice
*iface
)
238 MMDevice
*This
= (MMDevice
*)iface
;
241 ref
= InterlockedIncrement(&This
->ref
);
242 TRACE("Refcount now %i\n", ref
);
246 static ULONG WINAPI
MMDevice_Release(IMMDevice
*iface
)
248 MMDevice
*This
= (MMDevice
*)iface
;
251 ref
= InterlockedDecrement(&This
->ref
);
252 TRACE("Refcount now %i\n", ref
);
256 static HRESULT WINAPI
MMDevice_Activate(IMMDevice
*iface
, REFIID riid
, DWORD clsctx
, PROPVARIANT
*params
, void **ppv
)
258 MMDevice
*This
= (MMDevice
*)iface
;
259 HRESULT hr
= E_NOINTERFACE
;
260 TRACE("(%p)->(%p,%x,%p,%p)\n", This
, riid
, clsctx
, params
, ppv
);
265 if (IsEqualIID(riid
, &IID_IAudioClient
))
267 FIXME("IID_IAudioClient unsupported\n");
269 else if (IsEqualIID(riid
, &IID_IAudioEndpointVolume
))
271 FIXME("IID_IAudioEndpointVolume unsupported\n");
273 else if (IsEqualIID(riid
, &IID_IAudioSessionManager
)
274 || IsEqualIID(riid
, &IID_IAudioSessionManager2
))
276 FIXME("IID_IAudioSessionManager unsupported\n");
278 else if (IsEqualIID(riid
, &IID_IBaseFilter
))
280 if (This
->flow
== eRender
)
281 hr
= CoCreateInstance(&CLSID_DSoundRender
, NULL
, clsctx
, riid
, ppv
);
283 ERR("Not supported for recording?\n");
286 IPersistPropertyBag
*ppb
;
287 hr
= IUnknown_QueryInterface((IUnknown
*)*ppv
, &IID_IPersistPropertyBag
, (void*)&ppb
);
290 /* ::Load cannot assume the interface stays alive after the function returns,
291 * so just create the interface on the stack, saves a lot of complicated code */
292 IPropertyBagImpl bag
= { &PB_Vtbl
, This
->devguid
};
293 hr
= IPersistPropertyBag_Load(ppb
, (IPropertyBag
*)&bag
, NULL
);
294 IPersistPropertyBag_Release(ppb
);
296 IBaseFilter_Release((IBaseFilter
*)*ppv
);
300 FIXME("Wine doesn't support IPersistPropertyBag on DSoundRender yet, ignoring..\n");
305 else if (IsEqualIID(riid
, &IID_IDeviceTopology
))
307 FIXME("IID_IDeviceTopology unsupported\n");
309 else if (IsEqualIID(riid
, &IID_IDirectSound
)
310 || IsEqualIID(riid
, &IID_IDirectSound8
))
312 if (This
->flow
== eRender
)
313 hr
= CoCreateInstance(&CLSID_DirectSound8
, NULL
, clsctx
, riid
, ppv
);
316 hr
= IDirectSound_Initialize((IDirectSound
*)*ppv
, &This
->devguid
);
318 IDirectSound_Release((IDirectSound
*)*ppv
);
321 else if (IsEqualIID(riid
, &IID_IDirectSoundCapture
)
322 || IsEqualIID(riid
, &IID_IDirectSoundCapture8
))
324 if (This
->flow
== eCapture
)
325 hr
= CoCreateInstance(&CLSID_DirectSoundCapture8
, NULL
, clsctx
, riid
, ppv
);
328 hr
= IDirectSoundCapture_Initialize((IDirectSoundCapture
*)*ppv
, &This
->devguid
);
330 IDirectSoundCapture_Release((IDirectSoundCapture
*)*ppv
);
334 ERR("Invalid/unknown iid %s\n", debugstr_guid(riid
));
339 TRACE("Returning %08x\n", hr
);
343 static HRESULT WINAPI
MMDevice_OpenPropertyStore(IMMDevice
*iface
, DWORD access
, IPropertyStore
**ppv
)
345 MMDevice
*This
= (MMDevice
*)iface
;
346 TRACE("(%p)->(%x,%p)\n", This
, access
, ppv
);
350 return MMDevPropStore_Create(This
, access
, ppv
);
353 static HRESULT WINAPI
MMDevice_GetId(IMMDevice
*iface
, WCHAR
**itemid
)
355 MMDevice
*This
= (MMDevice
*)iface
;
357 GUID
*id
= &This
->devguid
;
358 static const WCHAR formatW
[] = { '{','0','.','0','.','0','.','0','0','0','0','0','0','0','0','}','.',
359 '{','%','0','8','X','-','%','0','4','X','-',
360 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
361 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
362 '%','0','2','X','%','0','2','X','}',0 };
364 TRACE("(%p)->(%p)\n", This
, itemid
);
367 *itemid
= str
= CoTaskMemAlloc(56 * sizeof(WCHAR
));
369 return E_OUTOFMEMORY
;
370 wsprintfW( str
, formatW
, id
->Data1
, id
->Data2
, id
->Data3
,
371 id
->Data4
[0], id
->Data4
[1], id
->Data4
[2], id
->Data4
[3],
372 id
->Data4
[4], id
->Data4
[5], id
->Data4
[6], id
->Data4
[7] );
376 static HRESULT WINAPI
MMDevice_GetState(IMMDevice
*iface
, DWORD
*state
)
378 MMDevice
*This
= (MMDevice
*)iface
;
379 TRACE("(%p)->(%p)\n", iface
, state
);
383 *state
= This
->state
;
387 static const IMMDeviceVtbl MMDeviceVtbl
=
389 MMDevice_QueryInterface
,
393 MMDevice_OpenPropertyStore
,
398 static MMDevice
*get_this_from_endpoint(IMMEndpoint
*iface
)
400 return (MMDevice
*)((char*)iface
- offsetof(MMDevice
,lpEndpointVtbl
));
403 static HRESULT WINAPI
MMEndpoint_QueryInterface(IMMEndpoint
*iface
, REFIID riid
, void **ppv
)
405 MMDevice
*This
= get_this_from_endpoint(iface
);
406 return IMMDevice_QueryInterface((IMMDevice
*)This
, riid
, ppv
);
409 static ULONG WINAPI
MMEndpoint_AddRef(IMMEndpoint
*iface
)
411 MMDevice
*This
= get_this_from_endpoint(iface
);
412 return IMMDevice_AddRef((IMMDevice
*)This
);
415 static ULONG WINAPI
MMEndpoint_Release(IMMEndpoint
*iface
)
417 MMDevice
*This
= get_this_from_endpoint(iface
);
418 return IMMDevice_Release((IMMDevice
*)This
);
421 static HRESULT WINAPI
MMEndpoint_GetDataFlow(IMMEndpoint
*iface
, EDataFlow
*flow
)
423 MMDevice
*This
= get_this_from_endpoint(iface
);
430 static const IMMEndpointVtbl MMEndpointVtbl
=
432 MMEndpoint_QueryInterface
,
435 MMEndpoint_GetDataFlow
438 static HRESULT
MMDevCol_Create(IMMDeviceCollection
**ppv
, EDataFlow flow
, DWORD state
)
442 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
));
445 return E_OUTOFMEMORY
;
446 This
->lpVtbl
= &MMDevColVtbl
;
450 *ppv
= (IMMDeviceCollection
*)This
;
454 static void MMDevCol_Destroy(MMDevColImpl
*This
)
456 HeapFree(GetProcessHeap(), 0, This
);
459 static HRESULT WINAPI
MMDevCol_QueryInterface(IMMDeviceCollection
*iface
, REFIID riid
, void **ppv
)
461 MMDevColImpl
*This
= (MMDevColImpl
*)iface
;
465 if (IsEqualIID(riid
, &IID_IUnknown
)
466 || IsEqualIID(riid
, &IID_IMMDeviceCollection
))
471 return E_NOINTERFACE
;
472 IUnknown_AddRef((IUnknown
*)*ppv
);
476 static ULONG WINAPI
MMDevCol_AddRef(IMMDeviceCollection
*iface
)
478 MMDevColImpl
*This
= (MMDevColImpl
*)iface
;
479 LONG ref
= InterlockedIncrement(&This
->ref
);
480 TRACE("Refcount now %i\n", ref
);
484 static ULONG WINAPI
MMDevCol_Release(IMMDeviceCollection
*iface
)
486 MMDevColImpl
*This
= (MMDevColImpl
*)iface
;
487 LONG ref
= InterlockedDecrement(&This
->ref
);
488 TRACE("Refcount now %i\n", ref
);
490 MMDevCol_Destroy(This
);
494 static HRESULT WINAPI
MMDevCol_GetCount(IMMDeviceCollection
*iface
, UINT
*numdevs
)
496 MMDevColImpl
*This
= (MMDevColImpl
*)iface
;
499 TRACE("(%p)->(%p)\n", This
, numdevs
);
504 for (i
= 0; i
< MMDevice_count
; ++i
)
506 MMDevice
*cur
= MMDevice_head
[i
];
507 if ((cur
->flow
== This
->flow
|| This
->flow
== eAll
)
508 && (cur
->state
& This
->state
))
514 static HRESULT WINAPI
MMDevCol_Item(IMMDeviceCollection
*iface
, UINT n
, IMMDevice
**dev
)
516 MMDevColImpl
*This
= (MMDevColImpl
*)iface
;
519 TRACE("(%p)->(%u, %p)\n", This
, n
, dev
);
523 for (j
= 0; j
< MMDevice_count
; ++j
)
525 MMDevice
*cur
= MMDevice_head
[j
];
526 if ((cur
->flow
== This
->flow
|| This
->flow
== eAll
)
527 && (cur
->state
& This
->state
)
530 *dev
= (IMMDevice
*)cur
;
531 IMMDevice_AddRef(*dev
);
535 WARN("Could not obtain item %u\n", n
);
540 static const IMMDeviceCollectionVtbl MMDevColVtbl
=
542 MMDevCol_QueryInterface
,
549 static const WCHAR propkey_formatW
[] = {
550 '{','%','0','8','X','-','%','0','4','X','-',
551 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
552 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
553 '%','0','2','X','%','0','2','X','}',',','%','d',0 };
555 static HRESULT
MMDevPropStore_OpenPropKey(const GUID
*guid
, DWORD flow
, HKEY
*propkey
)
560 StringFromGUID2(guid
, buffer
, 39);
561 if ((ret
= RegOpenKeyExW(flow
== eRender
? key_render
: key_capture
, buffer
, 0, KEY_READ
|KEY_WRITE
, &key
)) != ERROR_SUCCESS
)
563 WARN("Opening key %s failed with %u\n", debugstr_w(buffer
), ret
);
566 ret
= RegOpenKeyExW(key
, reg_properties
, 0, KEY_READ
|KEY_WRITE
, propkey
);
568 if (ret
!= ERROR_SUCCESS
)
570 WARN("Opening key %s failed with %u\n", debugstr_w(reg_properties
), ret
);
576 HRESULT
MMDevice_GetPropValue(const GUID
*devguid
, DWORD flow
, REFPROPERTYKEY key
, PROPVARIANT
*pv
)
579 const GUID
*id
= &key
->fmtid
;
585 hr
= MMDevPropStore_OpenPropKey(devguid
, flow
, ®key
);
588 wsprintfW( buffer
, propkey_formatW
, id
->Data1
, id
->Data2
, id
->Data3
,
589 id
->Data4
[0], id
->Data4
[1], id
->Data4
[2], id
->Data4
[3],
590 id
->Data4
[4], id
->Data4
[5], id
->Data4
[6], id
->Data4
[7], key
->pid
);
591 ret
= RegGetValueW(regkey
, NULL
, buffer
, RRF_RT_ANY
, &type
, NULL
, &size
);
592 if (ret
!= ERROR_SUCCESS
)
594 WARN("Reading %s returned %d\n", debugstr_w(buffer
), ret
);
596 PropVariantClear(pv
);
605 pv
->u
.pwszVal
= CoTaskMemAlloc(size
);
609 RegGetValueW(regkey
, NULL
, buffer
, RRF_RT_REG_SZ
, NULL
, (BYTE
*)pv
->u
.pwszVal
, &size
);
615 RegGetValueW(regkey
, NULL
, buffer
, RRF_RT_REG_DWORD
, NULL
, (BYTE
*)&pv
->u
.ulVal
, &size
);
621 pv
->u
.blob
.cbSize
= size
;
622 pv
->u
.blob
.pBlobData
= CoTaskMemAlloc(size
);
623 if (!pv
->u
.blob
.pBlobData
)
626 RegGetValueW(regkey
, NULL
, buffer
, RRF_RT_REG_BINARY
, NULL
, (BYTE
*)pv
->u
.blob
.pBlobData
, &size
);
630 ERR("Unknown/unhandled type: %u\n", type
);
631 PropVariantClear(pv
);
638 HRESULT
MMDevice_SetPropValue(const GUID
*devguid
, DWORD flow
, REFPROPERTYKEY key
, REFPROPVARIANT pv
)
641 const GUID
*id
= &key
->fmtid
;
646 hr
= MMDevPropStore_OpenPropKey(devguid
, flow
, ®key
);
649 wsprintfW( buffer
, propkey_formatW
, id
->Data1
, id
->Data2
, id
->Data3
,
650 id
->Data4
[0], id
->Data4
[1], id
->Data4
[2], id
->Data4
[3],
651 id
->Data4
[4], id
->Data4
[5], id
->Data4
[6], id
->Data4
[7], key
->pid
);
656 ret
= RegSetValueExW(regkey
, buffer
, 0, REG_DWORD
, (const BYTE
*)&pv
->u
.ulVal
, sizeof(DWORD
));
661 ret
= RegSetValueExW(regkey
, buffer
, 0, REG_BINARY
, pv
->u
.blob
.pBlobData
, pv
->u
.blob
.cbSize
);
662 TRACE("Blob %p %u\n", pv
->u
.blob
.pBlobData
, pv
->u
.blob
.cbSize
);
668 ret
= RegSetValueExW(regkey
, buffer
, 0, REG_SZ
, (const BYTE
*)pv
->u
.pwszVal
, sizeof(WCHAR
)*(1+lstrlenW(pv
->u
.pwszVal
)));
673 FIXME("Unhandled type %u\n", pv
->vt
);
678 TRACE("Writing %s returned %u\n", debugstr_w(buffer
), ret
);
682 HRESULT
MMDevEnum_Create(REFIID riid
, void **ppv
)
684 MMDevEnumImpl
*This
= MMDevEnumerator
;
693 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
));
696 return E_OUTOFMEMORY
;
698 This
->lpVtbl
= &MMDevEnumVtbl
;
699 MMDevEnumerator
= This
;
701 ret
= RegCreateKeyExW(HKEY_LOCAL_MACHINE
, software_mmdevapi
, 0, NULL
, 0, KEY_WRITE
|KEY_READ
, NULL
, &root
, NULL
);
702 if (ret
== ERROR_SUCCESS
)
703 ret
= RegCreateKeyExW(root
, reg_capture
, 0, NULL
, 0, KEY_READ
|KEY_WRITE
, NULL
, &key_capture
, NULL
);
704 if (ret
== ERROR_SUCCESS
)
705 ret
= RegCreateKeyExW(root
, reg_render
, 0, NULL
, 0, KEY_READ
|KEY_WRITE
, NULL
, &key_render
, NULL
);
709 if (ret
!= ERROR_SUCCESS
)
711 RegCloseKey(key_capture
);
712 key_render
= key_capture
= NULL
;
713 WARN("Couldn't create key: %u\n", ret
);
720 PROPVARIANT pv
= { VT_EMPTY
};
722 len
= sizeof(guidvalue
);
723 ret
= RegEnumKeyExW(cur
, i
++, guidvalue
, &len
, NULL
, NULL
, NULL
, NULL
);
724 if (ret
== ERROR_NO_MORE_ITEMS
)
726 if (cur
== key_capture
)
735 if (ret
!= ERROR_SUCCESS
)
737 if (SUCCEEDED(CLSIDFromString(guidvalue
, &guid
))
738 && SUCCEEDED(MMDevice_GetPropValue(&guid
, curflow
, (const PROPERTYKEY
*)&DEVPKEY_Device_FriendlyName
, &pv
))
739 && pv
.vt
== VT_LPWSTR
)
741 MMDevice_Create(pv
.u
.pwszVal
, &guid
, curflow
,
742 DEVICE_STATE_NOTPRESENT
, FALSE
);
743 CoTaskMemFree(pv
.u
.pwszVal
);
747 return IUnknown_QueryInterface((IUnknown
*)This
, riid
, ppv
);
750 void MMDevEnum_Free(void)
752 while (MMDevice_count
)
753 MMDevice_Destroy(MMDevice_head
[0]);
754 RegCloseKey(key_render
);
755 RegCloseKey(key_capture
);
756 key_render
= key_capture
= NULL
;
757 HeapFree(GetProcessHeap(), 0, MMDevEnumerator
);
758 MMDevEnumerator
= NULL
;
761 static HRESULT WINAPI
MMDevEnum_QueryInterface(IMMDeviceEnumerator
*iface
, REFIID riid
, void **ppv
)
763 MMDevEnumImpl
*This
= (MMDevEnumImpl
*)iface
;
767 if (IsEqualIID(riid
, &IID_IUnknown
)
768 || IsEqualIID(riid
, &IID_IMMDeviceEnumerator
))
773 return E_NOINTERFACE
;
774 IUnknown_AddRef((IUnknown
*)*ppv
);
778 static ULONG WINAPI
MMDevEnum_AddRef(IMMDeviceEnumerator
*iface
)
780 MMDevEnumImpl
*This
= (MMDevEnumImpl
*)iface
;
781 LONG ref
= InterlockedIncrement(&This
->ref
);
782 TRACE("Refcount now %i\n", ref
);
786 static ULONG WINAPI
MMDevEnum_Release(IMMDeviceEnumerator
*iface
)
788 MMDevEnumImpl
*This
= (MMDevEnumImpl
*)iface
;
789 LONG ref
= InterlockedDecrement(&This
->ref
);
792 TRACE("Refcount now %i\n", ref
);
796 static HRESULT WINAPI
MMDevEnum_EnumAudioEndpoints(IMMDeviceEnumerator
*iface
, EDataFlow flow
, DWORD mask
, IMMDeviceCollection
**devices
)
798 MMDevEnumImpl
*This
= (MMDevEnumImpl
*)iface
;
799 TRACE("(%p)->(%u,%u,%p)\n", This
, flow
, mask
, devices
);
803 if (flow
>= EDataFlow_enum_count
)
805 if (mask
& ~DEVICE_STATEMASK_ALL
)
807 return MMDevCol_Create(devices
, flow
, mask
);
810 static HRESULT WINAPI
MMDevEnum_GetDefaultAudioEndpoint(IMMDeviceEnumerator
*iface
, EDataFlow flow
, ERole role
, IMMDevice
**device
)
812 MMDevEnumImpl
*This
= (MMDevEnumImpl
*)iface
;
813 TRACE("(%p)->(%u,%u,%p)\n", This
, flow
, role
, device
);
820 *device
= (IMMDevice
*)MMDevice_def_play
;
821 else if (flow
== eCapture
)
822 *device
= (IMMDevice
*)MMDevice_def_rec
;
825 WARN("Unknown flow %u\n", flow
);
831 IMMDevice_AddRef(*device
);
835 static HRESULT WINAPI
MMDevEnum_GetDevice(IMMDeviceEnumerator
*iface
, const WCHAR
*name
, IMMDevice
**device
)
837 MMDevEnumImpl
*This
= (MMDevEnumImpl
*)iface
;
839 IMMDevice
*dev
= NULL
;
841 TRACE("(%p)->(%s,%p)\n", This
, debugstr_w(name
), device
);
842 for (i
= 0; i
< MMDevice_count
; ++i
)
845 dev
= (IMMDevice
*)MMDevice_head
[i
];
846 IMMDevice_GetId(dev
, &str
);
848 if (str
&& !lstrcmpW(str
, name
))
857 IUnknown_AddRef(dev
);
861 WARN("Could not find device %s\n", debugstr_w(name
));
865 static HRESULT WINAPI
MMDevEnum_RegisterEndpointNotificationCallback(IMMDeviceEnumerator
*iface
, IMMNotificationClient
*client
)
867 MMDevEnumImpl
*This
= (MMDevEnumImpl
*)iface
;
868 TRACE("(%p)->(%p)\n", This
, client
);
873 static HRESULT WINAPI
MMDevEnum_UnregisterEndpointNotificationCallback(IMMDeviceEnumerator
*iface
, IMMNotificationClient
*client
)
875 MMDevEnumImpl
*This
= (MMDevEnumImpl
*)iface
;
876 TRACE("(%p)->(%p)\n", This
, client
);
881 static const IMMDeviceEnumeratorVtbl MMDevEnumVtbl
=
883 MMDevEnum_QueryInterface
,
886 MMDevEnum_EnumAudioEndpoints
,
887 MMDevEnum_GetDefaultAudioEndpoint
,
889 MMDevEnum_RegisterEndpointNotificationCallback
,
890 MMDevEnum_UnregisterEndpointNotificationCallback
893 static HRESULT
MMDevPropStore_Create(MMDevice
*parent
, DWORD access
, IPropertyStore
**ppv
)
895 MMDevPropStore
*This
;
896 if (access
!= STGM_READ
897 && access
!= STGM_WRITE
898 && access
!= STGM_READWRITE
)
900 WARN("Invalid access %08x\n", access
);
903 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
));
904 *ppv
= (IPropertyStore
*)This
;
906 return E_OUTOFMEMORY
;
907 This
->lpVtbl
= &MMDevPropVtbl
;
909 This
->parent
= parent
;
910 This
->access
= access
;
914 static void MMDevPropStore_Destroy(MMDevPropStore
*This
)
916 HeapFree(GetProcessHeap(), 0, This
);
919 static HRESULT WINAPI
MMDevPropStore_QueryInterface(IPropertyStore
*iface
, REFIID riid
, void **ppv
)
921 MMDevPropStore
*This
= (MMDevPropStore
*)iface
;
925 if (IsEqualIID(riid
, &IID_IUnknown
)
926 || IsEqualIID(riid
, &IID_IPropertyStore
))
931 return E_NOINTERFACE
;
932 IUnknown_AddRef((IUnknown
*)*ppv
);
936 static ULONG WINAPI
MMDevPropStore_AddRef(IPropertyStore
*iface
)
938 MMDevPropStore
*This
= (MMDevPropStore
*)iface
;
939 LONG ref
= InterlockedIncrement(&This
->ref
);
940 TRACE("Refcount now %i\n", ref
);
944 static ULONG WINAPI
MMDevPropStore_Release(IPropertyStore
*iface
)
946 MMDevPropStore
*This
= (MMDevPropStore
*)iface
;
947 LONG ref
= InterlockedDecrement(&This
->ref
);
948 TRACE("Refcount now %i\n", ref
);
950 MMDevPropStore_Destroy(This
);
954 static HRESULT WINAPI
MMDevPropStore_GetCount(IPropertyStore
*iface
, DWORD
*nprops
)
956 MMDevPropStore
*This
= (MMDevPropStore
*)iface
;
962 TRACE("(%p)->(%p)\n", iface
, nprops
);
965 hr
= MMDevPropStore_OpenPropKey(&This
->parent
->devguid
, This
->parent
->flow
, &propkey
);
970 DWORD len
= sizeof(buffer
)/sizeof(*buffer
);
971 if (RegEnumKeyExW(propkey
, i
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
)
975 RegCloseKey(propkey
);
976 TRACE("Returning %i\n", i
);
981 static HRESULT WINAPI
MMDevPropStore_GetAt(IPropertyStore
*iface
, DWORD prop
, PROPERTYKEY
*key
)
983 MMDevPropStore
*This
= (MMDevPropStore
*)iface
;
985 DWORD len
= sizeof(buffer
)/sizeof(*buffer
);
989 TRACE("(%p)->(%u,%p)\n", iface
, prop
, key
);
993 hr
= MMDevPropStore_OpenPropKey(&This
->parent
->devguid
, This
->parent
->flow
, &propkey
);
997 if (RegEnumKeyExW(propkey
, prop
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
1000 WARN("GetAt %u failed\n", prop
);
1001 return E_INVALIDARG
;
1003 RegCloseKey(propkey
);
1005 CLSIDFromString(buffer
, &key
->fmtid
);
1006 key
->pid
= atoiW(&buffer
[40]);
1010 static HRESULT WINAPI
MMDevPropStore_GetValue(IPropertyStore
*iface
, REFPROPERTYKEY key
, PROPVARIANT
*pv
)
1012 MMDevPropStore
*This
= (MMDevPropStore
*)iface
;
1013 TRACE("(%p)->(\"%s,%u\", %p\n", This
, debugstr_guid(&key
->fmtid
), key
? key
->pid
: 0, pv
);
1017 if (This
->access
!= STGM_READ
1018 && This
->access
!= STGM_READWRITE
)
1019 return STG_E_ACCESSDENIED
;
1022 if (IsEqualPropertyKey(*key
, PKEY_AudioEndpoint_GUID
))
1024 pv
->u
.pwszVal
= CoTaskMemAlloc(39 * sizeof(WCHAR
));
1026 return E_OUTOFMEMORY
;
1027 StringFromGUID2(&This
->parent
->devguid
, pv
->u
.pwszVal
, 39);
1031 return MMDevice_GetPropValue(&This
->parent
->devguid
, This
->parent
->flow
, key
, pv
);
1034 static HRESULT WINAPI
MMDevPropStore_SetValue(IPropertyStore
*iface
, REFPROPERTYKEY key
, REFPROPVARIANT pv
)
1036 MMDevPropStore
*This
= (MMDevPropStore
*)iface
;
1041 if (This
->access
!= STGM_WRITE
1042 && This
->access
!= STGM_READWRITE
)
1043 return STG_E_ACCESSDENIED
;
1044 return MMDevice_SetPropValue(&This
->parent
->devguid
, This
->parent
->flow
, key
, pv
);
1047 static HRESULT WINAPI
MMDevPropStore_Commit(IPropertyStore
*iface
)
1053 static const IPropertyStoreVtbl MMDevPropVtbl
=
1055 MMDevPropStore_QueryInterface
,
1056 MMDevPropStore_AddRef
,
1057 MMDevPropStore_Release
,
1058 MMDevPropStore_GetCount
,
1059 MMDevPropStore_GetAt
,
1060 MMDevPropStore_GetValue
,
1061 MMDevPropStore_SetValue
,
1062 MMDevPropStore_Commit
1066 /* Property bag for IBaseFilter activation */
1067 static HRESULT WINAPI
PB_QueryInterface(IPropertyBag
*iface
, REFIID riid
, void **ppv
)
1069 ERR("Should not be called\n");
1071 return E_NOINTERFACE
;
1074 static ULONG WINAPI
PB_AddRef(IPropertyBag
*iface
)
1076 ERR("Should not be called\n");
1080 static ULONG WINAPI
PB_Release(IPropertyBag
*iface
)
1082 ERR("Should not be called\n");
1086 static HRESULT WINAPI
PB_Read(IPropertyBag
*iface
, LPCOLESTR name
, VARIANT
*var
, IErrorLog
*log
)
1088 static const WCHAR dsguid
[] = { 'D','S','G','u','i','d', 0 };
1089 IPropertyBagImpl
*This
= (IPropertyBagImpl
*)iface
;
1090 TRACE("Trying to read %s, type %u\n", debugstr_w(name
), var
->n1
.n2
.vt
);
1091 if (!lstrcmpW(name
, dsguid
))
1094 StringFromGUID2(&This
->devguid
, guidstr
,sizeof(guidstr
)/sizeof(*guidstr
));
1095 var
->n1
.n2
.vt
= VT_BSTR
;
1096 var
->n1
.n2
.n3
.bstrVal
= SysAllocString(guidstr
);
1099 ERR("Unknown property '%s' queried\n", debugstr_w(name
));
1103 static HRESULT WINAPI
PB_Write(IPropertyBag
*iface
, LPCOLESTR name
, VARIANT
*var
)
1105 ERR("Should not be called\n");
1109 static const IPropertyBagVtbl PB_Vtbl
=