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
23 #define NONAMELESSUNION
29 #include "wine/debug.h"
30 #include "wine/unicode.h"
33 #include "mmdeviceapi.h"
36 #include "audioclient.h"
37 #include "endpointvolume.h"
38 #include "audiopolicy.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(mmdevapi
);
45 static const WCHAR software_mmdevapi
[] =
46 { 'S','o','f','t','w','a','r','e','\\',
47 'M','i','c','r','o','s','o','f','t','\\',
48 'W','i','n','d','o','w','s','\\',
49 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
50 'M','M','D','e','v','i','c','e','s','\\',
51 'A','u','d','i','o',0};
52 static const WCHAR reg_render
[] =
53 { 'R','e','n','d','e','r',0 };
54 static const WCHAR reg_capture
[] =
55 { 'C','a','p','t','u','r','e',0 };
56 static const WCHAR reg_devicestate
[] =
57 { 'D','e','v','i','c','e','S','t','a','t','e',0 };
58 static const WCHAR reg_properties
[] =
59 { 'P','r','o','p','e','r','t','i','e','s',0 };
61 static HKEY key_render
;
62 static HKEY key_capture
;
64 typedef struct MMDevPropStoreImpl
66 IPropertyStore IPropertyStore_iface
;
72 typedef struct MMDevEnumImpl
74 IMMDeviceEnumerator IMMDeviceEnumerator_iface
;
78 static MMDevEnumImpl
*MMDevEnumerator
;
79 static MMDevice
**MMDevice_head
;
80 static MMDevice
*MMDevice_def_rec
, *MMDevice_def_play
;
81 static DWORD MMDevice_count
;
82 static const IMMDeviceEnumeratorVtbl MMDevEnumVtbl
;
83 static const IMMDeviceCollectionVtbl MMDevColVtbl
;
84 static const IMMDeviceVtbl MMDeviceVtbl
;
85 static const IPropertyStoreVtbl MMDevPropVtbl
;
86 static const IMMEndpointVtbl MMEndpointVtbl
;
88 static IMMDevice info_device
;
90 typedef struct MMDevColImpl
92 IMMDeviceCollection IMMDeviceCollection_iface
;
98 typedef struct IPropertyBagImpl
{
99 IPropertyBag IPropertyBag_iface
;
103 static const IPropertyBagVtbl PB_Vtbl
;
105 static HRESULT
MMDevPropStore_Create(MMDevice
*This
, DWORD access
, IPropertyStore
**ppv
);
107 static inline MMDevPropStore
*impl_from_IPropertyStore(IPropertyStore
*iface
)
109 return CONTAINING_RECORD(iface
, MMDevPropStore
, IPropertyStore_iface
);
112 static inline MMDevEnumImpl
*impl_from_IMMDeviceEnumerator(IMMDeviceEnumerator
*iface
)
114 return CONTAINING_RECORD(iface
, MMDevEnumImpl
, IMMDeviceEnumerator_iface
);
117 static inline MMDevColImpl
*impl_from_IMMDeviceCollection(IMMDeviceCollection
*iface
)
119 return CONTAINING_RECORD(iface
, MMDevColImpl
, IMMDeviceCollection_iface
);
122 static inline IPropertyBagImpl
*impl_from_IPropertyBag(IPropertyBag
*iface
)
124 return CONTAINING_RECORD(iface
, IPropertyBagImpl
, IPropertyBag_iface
);
127 static const WCHAR propkey_formatW
[] = {
128 '{','%','0','8','X','-','%','0','4','X','-',
129 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
130 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
131 '%','0','2','X','%','0','2','X','}',',','%','d',0 };
133 static HRESULT
MMDevPropStore_OpenPropKey(const GUID
*guid
, DWORD flow
, HKEY
*propkey
)
138 StringFromGUID2(guid
, buffer
, 39);
139 if ((ret
= RegOpenKeyExW(flow
== eRender
? key_render
: key_capture
, buffer
, 0, KEY_READ
|KEY_WRITE
, &key
)) != ERROR_SUCCESS
)
141 WARN("Opening key %s failed with %u\n", debugstr_w(buffer
), ret
);
144 ret
= RegOpenKeyExW(key
, reg_properties
, 0, KEY_READ
|KEY_WRITE
, propkey
);
146 if (ret
!= ERROR_SUCCESS
)
148 WARN("Opening key %s failed with %u\n", debugstr_w(reg_properties
), ret
);
154 HRESULT
MMDevice_GetPropValue(const GUID
*devguid
, DWORD flow
, REFPROPERTYKEY key
, PROPVARIANT
*pv
)
157 const GUID
*id
= &key
->fmtid
;
163 hr
= MMDevPropStore_OpenPropKey(devguid
, flow
, ®key
);
166 wsprintfW( buffer
, propkey_formatW
, id
->Data1
, id
->Data2
, id
->Data3
,
167 id
->Data4
[0], id
->Data4
[1], id
->Data4
[2], id
->Data4
[3],
168 id
->Data4
[4], id
->Data4
[5], id
->Data4
[6], id
->Data4
[7], key
->pid
);
169 ret
= RegGetValueW(regkey
, NULL
, buffer
, RRF_RT_ANY
, &type
, NULL
, &size
);
170 if (ret
!= ERROR_SUCCESS
)
172 WARN("Reading %s returned %d\n", debugstr_w(buffer
), ret
);
174 PropVariantClear(pv
);
183 pv
->u
.pwszVal
= CoTaskMemAlloc(size
);
187 RegGetValueW(regkey
, NULL
, buffer
, RRF_RT_REG_SZ
, NULL
, (BYTE
*)pv
->u
.pwszVal
, &size
);
193 RegGetValueW(regkey
, NULL
, buffer
, RRF_RT_REG_DWORD
, NULL
, (BYTE
*)&pv
->u
.ulVal
, &size
);
199 pv
->u
.blob
.cbSize
= size
;
200 pv
->u
.blob
.pBlobData
= CoTaskMemAlloc(size
);
201 if (!pv
->u
.blob
.pBlobData
)
204 RegGetValueW(regkey
, NULL
, buffer
, RRF_RT_REG_BINARY
, NULL
, (BYTE
*)pv
->u
.blob
.pBlobData
, &size
);
208 ERR("Unknown/unhandled type: %u\n", type
);
209 PropVariantClear(pv
);
216 static HRESULT
MMDevice_SetPropValue(const GUID
*devguid
, DWORD flow
, REFPROPERTYKEY key
, REFPROPVARIANT pv
)
219 const GUID
*id
= &key
->fmtid
;
224 hr
= MMDevPropStore_OpenPropKey(devguid
, flow
, ®key
);
227 wsprintfW( buffer
, propkey_formatW
, id
->Data1
, id
->Data2
, id
->Data3
,
228 id
->Data4
[0], id
->Data4
[1], id
->Data4
[2], id
->Data4
[3],
229 id
->Data4
[4], id
->Data4
[5], id
->Data4
[6], id
->Data4
[7], key
->pid
);
234 ret
= RegSetValueExW(regkey
, buffer
, 0, REG_DWORD
, (const BYTE
*)&pv
->u
.ulVal
, sizeof(DWORD
));
239 ret
= RegSetValueExW(regkey
, buffer
, 0, REG_BINARY
, pv
->u
.blob
.pBlobData
, pv
->u
.blob
.cbSize
);
240 TRACE("Blob %p %u\n", pv
->u
.blob
.pBlobData
, pv
->u
.blob
.cbSize
);
246 ret
= RegSetValueExW(regkey
, buffer
, 0, REG_SZ
, (const BYTE
*)pv
->u
.pwszVal
, sizeof(WCHAR
)*(1+lstrlenW(pv
->u
.pwszVal
)));
251 FIXME("Unhandled type %u\n", pv
->vt
);
256 TRACE("Writing %s returned %u\n", debugstr_w(buffer
), ret
);
260 /* Creates or updates the state of a device
261 * If GUID is null, a random guid will be assigned
262 * and the device will be created
264 static MMDevice
*MMDevice_Create(WCHAR
*name
, void *devkey
, GUID
*id
, EDataFlow flow
, DWORD state
, BOOL setdefault
)
271 for (i
= 0; i
< MMDevice_count
; ++i
)
273 cur
= MMDevice_head
[i
];
274 if (cur
->flow
== flow
&& !lstrcmpW(cur
->drv_id
, name
))
277 /* Same device, update state */
280 StringFromGUID2(&cur
->devguid
, guidstr
, sizeof(guidstr
)/sizeof(*guidstr
));
281 ret
= RegOpenKeyExW(flow
== eRender
? key_render
: key_capture
, guidstr
, 0, KEY_WRITE
, &key
);
282 if (ret
== ERROR_SUCCESS
)
284 RegSetValueExW(key
, reg_devicestate
, 0, REG_DWORD
, (const BYTE
*)&state
, sizeof(DWORD
));
291 /* No device found, allocate new one */
292 cur
= HeapAlloc(GetProcessHeap(), 0, sizeof(*cur
));
294 HeapFree(GetProcessHeap(), 0, devkey
);
297 cur
->drv_id
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(name
)+1)*sizeof(WCHAR
));
300 HeapFree(GetProcessHeap(), 0, cur
);
301 HeapFree(GetProcessHeap(), 0, devkey
);
304 lstrcpyW(cur
->drv_id
, name
);
306 cur
->IMMDevice_iface
.lpVtbl
= &MMDeviceVtbl
;
307 cur
->IMMEndpoint_iface
.lpVtbl
= &MMEndpointVtbl
;
309 InitializeCriticalSection(&cur
->crst
);
310 cur
->crst
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": MMDevice.crst");
319 StringFromGUID2(id
, guidstr
, sizeof(guidstr
)/sizeof(*guidstr
));
324 if (!RegCreateKeyExW(root
, guidstr
, 0, NULL
, 0, KEY_WRITE
|KEY_READ
, NULL
, &key
, NULL
))
327 RegSetValueExW(key
, reg_devicestate
, 0, REG_DWORD
, (const BYTE
*)&state
, sizeof(DWORD
));
328 if (!RegCreateKeyExW(key
, reg_properties
, 0, NULL
, 0, KEY_WRITE
|KEY_READ
, NULL
, &keyprop
, NULL
))
333 MMDevice_SetPropValue(id
, flow
, (const PROPERTYKEY
*)&DEVPKEY_Device_FriendlyName
, &pv
);
334 MMDevice_SetPropValue(id
, flow
, (const PROPERTYKEY
*)&DEVPKEY_Device_DeviceDesc
, &pv
);
335 RegCloseKey(keyprop
);
340 MMDevice_head
= HeapAlloc(GetProcessHeap(), 0, sizeof(*MMDevice_head
));
342 MMDevice_head
= HeapReAlloc(GetProcessHeap(), 0, MMDevice_head
, sizeof(*MMDevice_head
)*(1+MMDevice_count
));
343 MMDevice_head
[MMDevice_count
++] = cur
;
349 MMDevice_def_play
= cur
;
351 MMDevice_def_rec
= cur
;
356 static HRESULT
load_devices_from_reg(void)
363 ret
= RegCreateKeyExW(HKEY_LOCAL_MACHINE
, software_mmdevapi
, 0, NULL
, 0, KEY_WRITE
|KEY_READ
, NULL
, &root
, NULL
);
364 if (ret
== ERROR_SUCCESS
)
365 ret
= RegCreateKeyExW(root
, reg_capture
, 0, NULL
, 0, KEY_READ
|KEY_WRITE
, NULL
, &key_capture
, NULL
);
366 if (ret
== ERROR_SUCCESS
)
367 ret
= RegCreateKeyExW(root
, reg_render
, 0, NULL
, 0, KEY_READ
|KEY_WRITE
, NULL
, &key_render
, NULL
);
371 if (ret
!= ERROR_SUCCESS
)
373 RegCloseKey(key_capture
);
374 key_render
= key_capture
= NULL
;
375 WARN("Couldn't create key: %u\n", ret
);
383 PROPVARIANT pv
= { VT_EMPTY
};
385 len
= sizeof(guidvalue
)/sizeof(guidvalue
[0]);
386 ret
= RegEnumKeyExW(cur
, i
++, guidvalue
, &len
, NULL
, NULL
, NULL
, NULL
);
387 if (ret
== ERROR_NO_MORE_ITEMS
)
389 if (cur
== key_capture
)
398 if (ret
!= ERROR_SUCCESS
)
400 if (SUCCEEDED(CLSIDFromString(guidvalue
, &guid
))
401 && SUCCEEDED(MMDevice_GetPropValue(&guid
, curflow
, (const PROPERTYKEY
*)&DEVPKEY_Device_FriendlyName
, &pv
))
402 && pv
.vt
== VT_LPWSTR
)
404 MMDevice_Create(pv
.u
.pwszVal
, NULL
, &guid
, curflow
,
405 DEVICE_STATE_NOTPRESENT
, FALSE
);
406 CoTaskMemFree(pv
.u
.pwszVal
);
413 static HRESULT
set_format(MMDevice
*dev
)
416 IAudioClient
*client
;
418 PROPVARIANT pv
= { VT_EMPTY
};
420 hr
= drvs
.pGetAudioEndpoint(dev
->key
, &dev
->IMMDevice_iface
, dev
->flow
, &client
);
424 hr
= IAudioClient_GetMixFormat(client
, &fmt
);
426 IAudioClient_Release(client
);
430 IAudioClient_Release(client
);
433 pv
.u
.blob
.cbSize
= sizeof(WAVEFORMATEX
) + fmt
->cbSize
;
434 pv
.u
.blob
.pBlobData
= (BYTE
*)fmt
;
435 MMDevice_SetPropValue(&dev
->devguid
, dev
->flow
,
436 &PKEY_AudioEngine_DeviceFormat
, &pv
);
437 MMDevice_SetPropValue(&dev
->devguid
, dev
->flow
,
438 &PKEY_AudioEngine_OEMFormat
, &pv
);
443 static HRESULT
load_driver_devices(EDataFlow flow
)
450 if(!drvs
.pGetEndpointIDs
)
453 hr
= drvs
.pGetEndpointIDs(flow
, &ids
, &keys
, &num
, &def
);
457 for(i
= 0; i
< num
; ++i
){
459 dev
= MMDevice_Create(ids
[i
], keys
[i
], NULL
, flow
, DEVICE_STATE_ACTIVE
,
462 HeapFree(GetProcessHeap(), 0, ids
[i
]);
465 HeapFree(GetProcessHeap(), 0, keys
);
466 HeapFree(GetProcessHeap(), 0, ids
);
471 static void MMDevice_Destroy(MMDevice
*This
)
474 TRACE("Freeing %s\n", debugstr_w(This
->drv_id
));
475 /* Since this function is called at destruction time, reordering of the list is unimportant */
476 for (i
= 0; i
< MMDevice_count
; ++i
)
478 if (MMDevice_head
[i
] == This
)
480 MMDevice_head
[i
] = MMDevice_head
[--MMDevice_count
];
484 This
->crst
.DebugInfo
->Spare
[0] = 0;
485 DeleteCriticalSection(&This
->crst
);
486 HeapFree(GetProcessHeap(), 0, This
->drv_id
);
487 HeapFree(GetProcessHeap(), 0, This
->key
);
488 HeapFree(GetProcessHeap(), 0, This
);
491 static inline MMDevice
*impl_from_IMMDevice(IMMDevice
*iface
)
493 return CONTAINING_RECORD(iface
, MMDevice
, IMMDevice_iface
);
496 static HRESULT WINAPI
MMDevice_QueryInterface(IMMDevice
*iface
, REFIID riid
, void **ppv
)
498 MMDevice
*This
= impl_from_IMMDevice(iface
);
499 TRACE("(%p)->(%s,%p)\n", iface
, debugstr_guid(riid
), ppv
);
504 if (IsEqualIID(riid
, &IID_IUnknown
)
505 || IsEqualIID(riid
, &IID_IMMDevice
))
507 else if (IsEqualIID(riid
, &IID_IMMEndpoint
))
508 *ppv
= &This
->IMMEndpoint_iface
;
511 IUnknown_AddRef((IUnknown
*)*ppv
);
514 WARN("Unknown interface %s\n", debugstr_guid(riid
));
515 return E_NOINTERFACE
;
518 static ULONG WINAPI
MMDevice_AddRef(IMMDevice
*iface
)
520 MMDevice
*This
= impl_from_IMMDevice(iface
);
523 ref
= InterlockedIncrement(&This
->ref
);
524 TRACE("Refcount now %i\n", ref
);
528 static ULONG WINAPI
MMDevice_Release(IMMDevice
*iface
)
530 MMDevice
*This
= impl_from_IMMDevice(iface
);
533 ref
= InterlockedDecrement(&This
->ref
);
534 TRACE("Refcount now %i\n", ref
);
538 static HRESULT WINAPI
MMDevice_Activate(IMMDevice
*iface
, REFIID riid
, DWORD clsctx
, PROPVARIANT
*params
, void **ppv
)
540 HRESULT hr
= E_NOINTERFACE
;
541 MMDevice
*This
= impl_from_IMMDevice(iface
);
543 TRACE("(%p)->(%p,%x,%p,%p)\n", iface
, riid
, clsctx
, params
, ppv
);
548 if (IsEqualIID(riid
, &IID_IAudioClient
)){
549 hr
= drvs
.pGetAudioEndpoint(This
->key
, iface
, This
->flow
, (IAudioClient
**)ppv
);
550 }else if (IsEqualIID(riid
, &IID_IAudioEndpointVolume
))
551 hr
= AudioEndpointVolume_Create(This
, (IAudioEndpointVolume
**)ppv
);
552 else if (IsEqualIID(riid
, &IID_IAudioSessionManager
)
553 || IsEqualIID(riid
, &IID_IAudioSessionManager2
))
555 hr
= drvs
.pGetAudioSessionManager(iface
, (IAudioSessionManager2
**)ppv
);
557 else if (IsEqualIID(riid
, &IID_IBaseFilter
))
559 if (This
->flow
== eRender
)
560 hr
= CoCreateInstance(&CLSID_DSoundRender
, NULL
, clsctx
, riid
, ppv
);
562 ERR("Not supported for recording?\n");
565 IPersistPropertyBag
*ppb
;
566 hr
= IUnknown_QueryInterface((IUnknown
*)*ppv
, &IID_IPersistPropertyBag
, (void*)&ppb
);
569 /* ::Load cannot assume the interface stays alive after the function returns,
570 * so just create the interface on the stack, saves a lot of complicated code */
571 IPropertyBagImpl bag
= { { &PB_Vtbl
}, This
->devguid
};
572 hr
= IPersistPropertyBag_Load(ppb
, &bag
.IPropertyBag_iface
, NULL
);
573 IPersistPropertyBag_Release(ppb
);
575 IBaseFilter_Release((IBaseFilter
*)*ppv
);
579 FIXME("Wine doesn't support IPersistPropertyBag on DSoundRender yet, ignoring..\n");
584 else if (IsEqualIID(riid
, &IID_IDeviceTopology
))
586 FIXME("IID_IDeviceTopology unsupported\n");
588 else if (IsEqualIID(riid
, &IID_IDirectSound
)
589 || IsEqualIID(riid
, &IID_IDirectSound8
))
591 if (This
->flow
== eRender
)
592 hr
= CoCreateInstance(&CLSID_DirectSound8
, NULL
, clsctx
, riid
, ppv
);
595 hr
= IDirectSound_Initialize((IDirectSound
*)*ppv
, &This
->devguid
);
597 IDirectSound_Release((IDirectSound
*)*ppv
);
600 else if (IsEqualIID(riid
, &IID_IDirectSoundCapture
)
601 || IsEqualIID(riid
, &IID_IDirectSoundCapture8
))
603 if (This
->flow
== eCapture
)
604 hr
= CoCreateInstance(&CLSID_DirectSoundCapture8
, NULL
, clsctx
, riid
, ppv
);
607 hr
= IDirectSoundCapture_Initialize((IDirectSoundCapture
*)*ppv
, &This
->devguid
);
609 IDirectSoundCapture_Release((IDirectSoundCapture
*)*ppv
);
613 ERR("Invalid/unknown iid %s\n", debugstr_guid(riid
));
618 TRACE("Returning %08x\n", hr
);
622 static HRESULT WINAPI
MMDevice_OpenPropertyStore(IMMDevice
*iface
, DWORD access
, IPropertyStore
**ppv
)
624 MMDevice
*This
= impl_from_IMMDevice(iface
);
625 TRACE("(%p)->(%x,%p)\n", This
, access
, ppv
);
629 return MMDevPropStore_Create(This
, access
, ppv
);
632 static HRESULT WINAPI
MMDevice_GetId(IMMDevice
*iface
, WCHAR
**itemid
)
634 MMDevice
*This
= impl_from_IMMDevice(iface
);
636 GUID
*id
= &This
->devguid
;
637 static const WCHAR formatW
[] = { '{','0','.','0','.','0','.','0','0','0','0','0','0','0','0','}','.',
638 '{','%','0','8','X','-','%','0','4','X','-',
639 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
640 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
641 '%','0','2','X','%','0','2','X','}',0 };
643 TRACE("(%p)->(%p)\n", This
, itemid
);
646 *itemid
= str
= CoTaskMemAlloc(56 * sizeof(WCHAR
));
648 return E_OUTOFMEMORY
;
649 wsprintfW( str
, 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] );
655 static HRESULT WINAPI
MMDevice_GetState(IMMDevice
*iface
, DWORD
*state
)
657 MMDevice
*This
= impl_from_IMMDevice(iface
);
658 TRACE("(%p)->(%p)\n", iface
, state
);
662 *state
= This
->state
;
666 static const IMMDeviceVtbl MMDeviceVtbl
=
668 MMDevice_QueryInterface
,
672 MMDevice_OpenPropertyStore
,
677 static inline MMDevice
*impl_from_IMMEndpoint(IMMEndpoint
*iface
)
679 return CONTAINING_RECORD(iface
, MMDevice
, IMMEndpoint_iface
);
682 static HRESULT WINAPI
MMEndpoint_QueryInterface(IMMEndpoint
*iface
, REFIID riid
, void **ppv
)
684 MMDevice
*This
= impl_from_IMMEndpoint(iface
);
685 return IMMDevice_QueryInterface(&This
->IMMDevice_iface
, riid
, ppv
);
688 static ULONG WINAPI
MMEndpoint_AddRef(IMMEndpoint
*iface
)
690 MMDevice
*This
= impl_from_IMMEndpoint(iface
);
691 return IMMDevice_AddRef(&This
->IMMDevice_iface
);
694 static ULONG WINAPI
MMEndpoint_Release(IMMEndpoint
*iface
)
696 MMDevice
*This
= impl_from_IMMEndpoint(iface
);
697 return IMMDevice_Release(&This
->IMMDevice_iface
);
700 static HRESULT WINAPI
MMEndpoint_GetDataFlow(IMMEndpoint
*iface
, EDataFlow
*flow
)
702 MMDevice
*This
= impl_from_IMMEndpoint(iface
);
709 static const IMMEndpointVtbl MMEndpointVtbl
=
711 MMEndpoint_QueryInterface
,
714 MMEndpoint_GetDataFlow
717 static HRESULT
MMDevCol_Create(IMMDeviceCollection
**ppv
, EDataFlow flow
, DWORD state
)
721 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
));
724 return E_OUTOFMEMORY
;
725 This
->IMMDeviceCollection_iface
.lpVtbl
= &MMDevColVtbl
;
729 *ppv
= &This
->IMMDeviceCollection_iface
;
733 static void MMDevCol_Destroy(MMDevColImpl
*This
)
735 HeapFree(GetProcessHeap(), 0, This
);
738 static HRESULT WINAPI
MMDevCol_QueryInterface(IMMDeviceCollection
*iface
, REFIID riid
, void **ppv
)
740 MMDevColImpl
*This
= impl_from_IMMDeviceCollection(iface
);
744 if (IsEqualIID(riid
, &IID_IUnknown
)
745 || IsEqualIID(riid
, &IID_IMMDeviceCollection
))
750 return E_NOINTERFACE
;
751 IUnknown_AddRef((IUnknown
*)*ppv
);
755 static ULONG WINAPI
MMDevCol_AddRef(IMMDeviceCollection
*iface
)
757 MMDevColImpl
*This
= impl_from_IMMDeviceCollection(iface
);
758 LONG ref
= InterlockedIncrement(&This
->ref
);
759 TRACE("Refcount now %i\n", ref
);
763 static ULONG WINAPI
MMDevCol_Release(IMMDeviceCollection
*iface
)
765 MMDevColImpl
*This
= impl_from_IMMDeviceCollection(iface
);
766 LONG ref
= InterlockedDecrement(&This
->ref
);
767 TRACE("Refcount now %i\n", ref
);
769 MMDevCol_Destroy(This
);
773 static HRESULT WINAPI
MMDevCol_GetCount(IMMDeviceCollection
*iface
, UINT
*numdevs
)
775 MMDevColImpl
*This
= impl_from_IMMDeviceCollection(iface
);
778 TRACE("(%p)->(%p)\n", This
, numdevs
);
783 for (i
= 0; i
< MMDevice_count
; ++i
)
785 MMDevice
*cur
= MMDevice_head
[i
];
786 if ((cur
->flow
== This
->flow
|| This
->flow
== eAll
)
787 && (cur
->state
& This
->state
))
793 static HRESULT WINAPI
MMDevCol_Item(IMMDeviceCollection
*iface
, UINT n
, IMMDevice
**dev
)
795 MMDevColImpl
*This
= impl_from_IMMDeviceCollection(iface
);
798 TRACE("(%p)->(%u, %p)\n", This
, n
, dev
);
802 for (j
= 0; j
< MMDevice_count
; ++j
)
804 MMDevice
*cur
= MMDevice_head
[j
];
805 if ((cur
->flow
== This
->flow
|| This
->flow
== eAll
)
806 && (cur
->state
& This
->state
)
809 *dev
= &cur
->IMMDevice_iface
;
810 IMMDevice_AddRef(*dev
);
814 WARN("Could not obtain item %u\n", n
);
819 static const IMMDeviceCollectionVtbl MMDevColVtbl
=
821 MMDevCol_QueryInterface
,
828 HRESULT
MMDevEnum_Create(REFIID riid
, void **ppv
)
830 MMDevEnumImpl
*This
= MMDevEnumerator
;
834 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
));
837 return E_OUTOFMEMORY
;
839 This
->IMMDeviceEnumerator_iface
.lpVtbl
= &MMDevEnumVtbl
;
840 MMDevEnumerator
= This
;
842 load_devices_from_reg();
843 load_driver_devices(eRender
);
844 load_driver_devices(eCapture
);
846 return IUnknown_QueryInterface((IUnknown
*)This
, riid
, ppv
);
849 void MMDevEnum_Free(void)
851 while (MMDevice_count
)
852 MMDevice_Destroy(MMDevice_head
[0]);
853 RegCloseKey(key_render
);
854 RegCloseKey(key_capture
);
855 key_render
= key_capture
= NULL
;
856 HeapFree(GetProcessHeap(), 0, MMDevEnumerator
);
857 MMDevEnumerator
= NULL
;
860 static HRESULT WINAPI
MMDevEnum_QueryInterface(IMMDeviceEnumerator
*iface
, REFIID riid
, void **ppv
)
862 MMDevEnumImpl
*This
= impl_from_IMMDeviceEnumerator(iface
);
866 if (IsEqualIID(riid
, &IID_IUnknown
)
867 || IsEqualIID(riid
, &IID_IMMDeviceEnumerator
))
872 return E_NOINTERFACE
;
873 IUnknown_AddRef((IUnknown
*)*ppv
);
877 static ULONG WINAPI
MMDevEnum_AddRef(IMMDeviceEnumerator
*iface
)
879 MMDevEnumImpl
*This
= impl_from_IMMDeviceEnumerator(iface
);
880 LONG ref
= InterlockedIncrement(&This
->ref
);
881 TRACE("Refcount now %i\n", ref
);
885 static ULONG WINAPI
MMDevEnum_Release(IMMDeviceEnumerator
*iface
)
887 MMDevEnumImpl
*This
= impl_from_IMMDeviceEnumerator(iface
);
888 LONG ref
= InterlockedDecrement(&This
->ref
);
891 TRACE("Refcount now %i\n", ref
);
895 static HRESULT WINAPI
MMDevEnum_EnumAudioEndpoints(IMMDeviceEnumerator
*iface
, EDataFlow flow
, DWORD mask
, IMMDeviceCollection
**devices
)
897 MMDevEnumImpl
*This
= impl_from_IMMDeviceEnumerator(iface
);
898 TRACE("(%p)->(%u,%u,%p)\n", This
, flow
, mask
, devices
);
902 if (flow
>= EDataFlow_enum_count
)
904 if (mask
& ~DEVICE_STATEMASK_ALL
)
906 return MMDevCol_Create(devices
, flow
, mask
);
909 static HRESULT WINAPI
MMDevEnum_GetDefaultAudioEndpoint(IMMDeviceEnumerator
*iface
, EDataFlow flow
, ERole role
, IMMDevice
**device
)
911 MMDevEnumImpl
*This
= impl_from_IMMDeviceEnumerator(iface
);
916 static const WCHAR slashW
[] = {'\\',0};
917 static const WCHAR reg_out_nameW
[] = {'D','e','f','a','u','l','t','O','u','t','p','u','t',0};
918 static const WCHAR reg_vout_nameW
[] = {'D','e','f','a','u','l','t','V','o','i','c','e','O','u','t','p','u','t',0};
919 static const WCHAR reg_in_nameW
[] = {'D','e','f','a','u','l','t','I','n','p','u','t',0};
920 static const WCHAR reg_vin_nameW
[] = {'D','e','f','a','u','l','t','V','o','i','c','e','I','n','p','u','t',0};
922 TRACE("(%p)->(%u,%u,%p)\n", This
, flow
, role
, device
);
927 if((flow
!= eRender
&& flow
!= eCapture
) ||
928 (role
!= eConsole
&& role
!= eMultimedia
&& role
!= eCommunications
)){
929 WARN("Unknown flow (%u) or role (%u)\n", flow
, role
);
935 if(!drvs
.module_name
[0])
938 lstrcpyW(reg_key
, drv_keyW
);
939 lstrcatW(reg_key
, slashW
);
940 lstrcatW(reg_key
, drvs
.module_name
);
942 if(RegOpenKeyW(HKEY_CURRENT_USER
, reg_key
, &key
) == ERROR_SUCCESS
){
943 const WCHAR
*reg_x_name
, *reg_vx_name
;
945 DWORD size
= sizeof(def_id
);
948 reg_x_name
= reg_out_nameW
;
949 reg_vx_name
= reg_vout_nameW
;
951 reg_x_name
= reg_in_nameW
;
952 reg_vx_name
= reg_vin_nameW
;
955 if(role
== eCommunications
&&
956 RegQueryValueExW(key
, reg_vx_name
, 0, NULL
,
957 (BYTE
*)def_id
, &size
) == ERROR_SUCCESS
){
958 hr
= IMMDeviceEnumerator_GetDevice(iface
, def_id
, device
);
964 TRACE("Unable to find voice device %s\n", wine_dbgstr_w(def_id
));
967 if(RegQueryValueExW(key
, reg_x_name
, 0, NULL
,
968 (BYTE
*)def_id
, &size
) == ERROR_SUCCESS
){
969 hr
= IMMDeviceEnumerator_GetDevice(iface
, def_id
, device
);
975 TRACE("Unable to find device %s\n", wine_dbgstr_w(def_id
));
982 *device
= &MMDevice_def_play
->IMMDevice_iface
;
984 *device
= &MMDevice_def_rec
->IMMDevice_iface
;
988 IMMDevice_AddRef(*device
);
992 static HRESULT WINAPI
MMDevEnum_GetDevice(IMMDeviceEnumerator
*iface
, const WCHAR
*name
, IMMDevice
**device
)
994 MMDevEnumImpl
*This
= impl_from_IMMDeviceEnumerator(iface
);
996 IMMDevice
*dev
= NULL
;
998 static const WCHAR wine_info_deviceW
[] = {'W','i','n','e',' ',
999 'i','n','f','o',' ','d','e','v','i','c','e',0};
1001 TRACE("(%p)->(%s,%p)\n", This
, debugstr_w(name
), device
);
1003 if(!name
|| !device
)
1006 if(!lstrcmpW(name
, wine_info_deviceW
)){
1007 *device
= &info_device
;
1011 for (i
= 0; i
< MMDevice_count
; ++i
)
1014 dev
= &MMDevice_head
[i
]->IMMDevice_iface
;
1015 IMMDevice_GetId(dev
, &str
);
1017 if (str
&& !lstrcmpW(str
, name
))
1020 IUnknown_AddRef(dev
);
1026 TRACE("Could not find device %s\n", debugstr_w(name
));
1027 return E_INVALIDARG
;
1030 static HRESULT WINAPI
MMDevEnum_RegisterEndpointNotificationCallback(IMMDeviceEnumerator
*iface
, IMMNotificationClient
*client
)
1032 MMDevEnumImpl
*This
= impl_from_IMMDeviceEnumerator(iface
);
1033 TRACE("(%p)->(%p)\n", This
, client
);
1038 static HRESULT WINAPI
MMDevEnum_UnregisterEndpointNotificationCallback(IMMDeviceEnumerator
*iface
, IMMNotificationClient
*client
)
1040 MMDevEnumImpl
*This
= impl_from_IMMDeviceEnumerator(iface
);
1041 TRACE("(%p)->(%p)\n", This
, client
);
1046 static const IMMDeviceEnumeratorVtbl MMDevEnumVtbl
=
1048 MMDevEnum_QueryInterface
,
1051 MMDevEnum_EnumAudioEndpoints
,
1052 MMDevEnum_GetDefaultAudioEndpoint
,
1053 MMDevEnum_GetDevice
,
1054 MMDevEnum_RegisterEndpointNotificationCallback
,
1055 MMDevEnum_UnregisterEndpointNotificationCallback
1058 static HRESULT
MMDevPropStore_Create(MMDevice
*parent
, DWORD access
, IPropertyStore
**ppv
)
1060 MMDevPropStore
*This
;
1061 if (access
!= STGM_READ
1062 && access
!= STGM_WRITE
1063 && access
!= STGM_READWRITE
)
1065 WARN("Invalid access %08x\n", access
);
1066 return E_INVALIDARG
;
1068 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
));
1069 *ppv
= &This
->IPropertyStore_iface
;
1071 return E_OUTOFMEMORY
;
1072 This
->IPropertyStore_iface
.lpVtbl
= &MMDevPropVtbl
;
1074 This
->parent
= parent
;
1075 This
->access
= access
;
1079 static void MMDevPropStore_Destroy(MMDevPropStore
*This
)
1081 HeapFree(GetProcessHeap(), 0, This
);
1084 static HRESULT WINAPI
MMDevPropStore_QueryInterface(IPropertyStore
*iface
, REFIID riid
, void **ppv
)
1086 MMDevPropStore
*This
= impl_from_IPropertyStore(iface
);
1090 if (IsEqualIID(riid
, &IID_IUnknown
)
1091 || IsEqualIID(riid
, &IID_IPropertyStore
))
1096 return E_NOINTERFACE
;
1097 IUnknown_AddRef((IUnknown
*)*ppv
);
1101 static ULONG WINAPI
MMDevPropStore_AddRef(IPropertyStore
*iface
)
1103 MMDevPropStore
*This
= impl_from_IPropertyStore(iface
);
1104 LONG ref
= InterlockedIncrement(&This
->ref
);
1105 TRACE("Refcount now %i\n", ref
);
1109 static ULONG WINAPI
MMDevPropStore_Release(IPropertyStore
*iface
)
1111 MMDevPropStore
*This
= impl_from_IPropertyStore(iface
);
1112 LONG ref
= InterlockedDecrement(&This
->ref
);
1113 TRACE("Refcount now %i\n", ref
);
1115 MMDevPropStore_Destroy(This
);
1119 static HRESULT WINAPI
MMDevPropStore_GetCount(IPropertyStore
*iface
, DWORD
*nprops
)
1121 MMDevPropStore
*This
= impl_from_IPropertyStore(iface
);
1127 TRACE("(%p)->(%p)\n", iface
, nprops
);
1130 hr
= MMDevPropStore_OpenPropKey(&This
->parent
->devguid
, This
->parent
->flow
, &propkey
);
1135 DWORD len
= sizeof(buffer
)/sizeof(*buffer
);
1136 if (RegEnumKeyExW(propkey
, i
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
)
1140 RegCloseKey(propkey
);
1141 TRACE("Returning %i\n", i
);
1146 static HRESULT WINAPI
MMDevPropStore_GetAt(IPropertyStore
*iface
, DWORD prop
, PROPERTYKEY
*key
)
1148 MMDevPropStore
*This
= impl_from_IPropertyStore(iface
);
1150 DWORD len
= sizeof(buffer
)/sizeof(*buffer
);
1154 TRACE("(%p)->(%u,%p)\n", iface
, prop
, key
);
1158 hr
= MMDevPropStore_OpenPropKey(&This
->parent
->devguid
, This
->parent
->flow
, &propkey
);
1162 if (RegEnumKeyExW(propkey
, prop
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
1165 WARN("GetAt %u failed\n", prop
);
1166 return E_INVALIDARG
;
1168 RegCloseKey(propkey
);
1170 CLSIDFromString(buffer
, &key
->fmtid
);
1171 key
->pid
= atoiW(&buffer
[40]);
1175 static HRESULT WINAPI
MMDevPropStore_GetValue(IPropertyStore
*iface
, REFPROPERTYKEY key
, PROPVARIANT
*pv
)
1177 MMDevPropStore
*This
= impl_from_IPropertyStore(iface
);
1178 TRACE("(%p)->(\"%s,%u\", %p\n", This
, debugstr_guid(&key
->fmtid
), key
? key
->pid
: 0, pv
);
1182 if (This
->access
!= STGM_READ
1183 && This
->access
!= STGM_READWRITE
)
1184 return STG_E_ACCESSDENIED
;
1187 if (IsEqualPropertyKey(*key
, PKEY_AudioEndpoint_GUID
))
1190 pv
->u
.pwszVal
= CoTaskMemAlloc(39 * sizeof(WCHAR
));
1192 return E_OUTOFMEMORY
;
1193 StringFromGUID2(&This
->parent
->devguid
, pv
->u
.pwszVal
, 39);
1197 return MMDevice_GetPropValue(&This
->parent
->devguid
, This
->parent
->flow
, key
, pv
);
1200 static HRESULT WINAPI
MMDevPropStore_SetValue(IPropertyStore
*iface
, REFPROPERTYKEY key
, REFPROPVARIANT pv
)
1202 MMDevPropStore
*This
= impl_from_IPropertyStore(iface
);
1207 if (This
->access
!= STGM_WRITE
1208 && This
->access
!= STGM_READWRITE
)
1209 return STG_E_ACCESSDENIED
;
1210 return MMDevice_SetPropValue(&This
->parent
->devguid
, This
->parent
->flow
, key
, pv
);
1213 static HRESULT WINAPI
MMDevPropStore_Commit(IPropertyStore
*iface
)
1219 static const IPropertyStoreVtbl MMDevPropVtbl
=
1221 MMDevPropStore_QueryInterface
,
1222 MMDevPropStore_AddRef
,
1223 MMDevPropStore_Release
,
1224 MMDevPropStore_GetCount
,
1225 MMDevPropStore_GetAt
,
1226 MMDevPropStore_GetValue
,
1227 MMDevPropStore_SetValue
,
1228 MMDevPropStore_Commit
1232 /* Property bag for IBaseFilter activation */
1233 static HRESULT WINAPI
PB_QueryInterface(IPropertyBag
*iface
, REFIID riid
, void **ppv
)
1235 ERR("Should not be called\n");
1237 return E_NOINTERFACE
;
1240 static ULONG WINAPI
PB_AddRef(IPropertyBag
*iface
)
1242 ERR("Should not be called\n");
1246 static ULONG WINAPI
PB_Release(IPropertyBag
*iface
)
1248 ERR("Should not be called\n");
1252 static HRESULT WINAPI
PB_Read(IPropertyBag
*iface
, LPCOLESTR name
, VARIANT
*var
, IErrorLog
*log
)
1254 static const WCHAR dsguid
[] = { 'D','S','G','u','i','d', 0 };
1255 IPropertyBagImpl
*This
= impl_from_IPropertyBag(iface
);
1256 TRACE("Trying to read %s, type %u\n", debugstr_w(name
), var
->n1
.n2
.vt
);
1257 if (!lstrcmpW(name
, dsguid
))
1260 StringFromGUID2(&This
->devguid
, guidstr
,sizeof(guidstr
)/sizeof(*guidstr
));
1261 var
->n1
.n2
.vt
= VT_BSTR
;
1262 var
->n1
.n2
.n3
.bstrVal
= SysAllocString(guidstr
);
1265 ERR("Unknown property '%s' queried\n", debugstr_w(name
));
1269 static HRESULT WINAPI
PB_Write(IPropertyBag
*iface
, LPCOLESTR name
, VARIANT
*var
)
1271 ERR("Should not be called\n");
1275 static const IPropertyBagVtbl PB_Vtbl
=
1284 static ULONG WINAPI
info_device_ps_AddRef(IPropertyStore
*iface
)
1289 static ULONG WINAPI
info_device_ps_Release(IPropertyStore
*iface
)
1294 static HRESULT WINAPI
info_device_ps_GetValue(IPropertyStore
*iface
,
1295 REFPROPERTYKEY key
, PROPVARIANT
*pv
)
1297 TRACE("(static)->(\"%s,%u\", %p)\n", debugstr_guid(&key
->fmtid
), key
? key
->pid
: 0, pv
);
1302 if (IsEqualPropertyKey(*key
, DEVPKEY_Device_Driver
))
1304 INT size
= (lstrlenW(drvs
.module_name
) + 1) * sizeof(WCHAR
);
1306 pv
->u
.pwszVal
= CoTaskMemAlloc(size
);
1308 return E_OUTOFMEMORY
;
1309 memcpy(pv
->u
.pwszVal
, drvs
.module_name
, size
);
1313 return E_INVALIDARG
;
1316 static const IPropertyStoreVtbl info_device_ps_Vtbl
=
1319 info_device_ps_AddRef
,
1320 info_device_ps_Release
,
1323 info_device_ps_GetValue
,
1328 static IPropertyStore info_device_ps
= {
1329 &info_device_ps_Vtbl
1332 static ULONG WINAPI
info_device_AddRef(IMMDevice
*iface
)
1337 static ULONG WINAPI
info_device_Release(IMMDevice
*iface
)
1342 static HRESULT WINAPI
info_device_OpenPropertyStore(IMMDevice
*iface
,
1343 DWORD access
, IPropertyStore
**ppv
)
1345 *ppv
= &info_device_ps
;
1349 static const IMMDeviceVtbl info_device_Vtbl
=
1353 info_device_Release
,
1355 info_device_OpenPropertyStore
,
1360 static IMMDevice info_device
= {