Hi, I'm trying to enumerate audio devices and access their friendly names with python like in this example <https://learn.microsoft.com/en-us/windows/win32/coreaudio/device-properties>. I've expanded on volume control example <https://www.mail-archive.com/python-win32@python.org/msg10282.html> from the mail archive by Tim Roberts, I've added necessary methods to IMMDeviceEnumerator, redefined OpenPropertyStore() method in IMMDevice interface. Problem seems to be in IPropertyStore interface when defining its methods, specifically the GetValue method. I cannot find PropertyKey structure like PROPERTYKEY structure from windows SDK (propsys.h), so I tried defining my own, and I hope I'm using the correct type for PROPVARIANT argument. Also, I'm not sure where are constants like PKEY_Device_FriendlyName defined?
``` from comtypes import GUID, Structure, HRESULT, COMMETHOD, STDMETHOD, IUnknown, c_float, CoCreateInstance, CLSCTX_ALL from ctypes import POINTER from ctypes.wintypes import DWORD, BOOL, UINT, LPWSTR from win32comext.propsys import propsys # from: C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\um\functiondiscoverykeys_devpkey.h PKEY_Device_FriendlyName = 0xa45c254e CLSID_MMDeviceEnumerator = \ GUID('{BCDE0395-E52F-467C-8E3D-C4579291692E}') class PropertyKey(Structure): _fields_ = [("fmtid", GUID), ("pid", DWORD)] REFPROPERTYKEY = PropertyKey PROPVARIANT = propsys.PROPVARIANTType class IAudioEndpointVolume(IUnknown): _iid_ = GUID('{5CDF2C82-841E-4546-9722-0CF74078229A}') _methods_ = [ STDMETHOD(HRESULT, 'RegisterControlChangeNotify', []), STDMETHOD(HRESULT, 'UnregisterControlChangeNotify', []), STDMETHOD(HRESULT, 'GetChannelCount', []), COMMETHOD([], HRESULT, 'SetMasterVolumeLevel', (['in'], c_float, 'fLevelDB'), (['in'], POINTER(GUID), 'pguidEventContext') ), COMMETHOD([], HRESULT, 'SetMasterVolumeLevelScalar', (['in'], c_float, 'fLevelDB'), (['in'], POINTER(GUID), 'pguidEventContext') ), COMMETHOD([], HRESULT, 'GetMasterVolumeLevel', (['out', 'retval'], POINTER(c_float), 'pfLevelDB') ), COMMETHOD([], HRESULT, 'GetMasterVolumeLevelScalar', (['out', 'retval'], POINTER(c_float), 'pfLevelDB') ), COMMETHOD([], HRESULT, 'SetChannelVolumeLevel', (['in'], DWORD, 'nChannel'), (['in'], c_float, 'fLevelDB'), (['in'], POINTER(GUID), 'pguidEventContext') ), COMMETHOD([], HRESULT, 'SetChannelVolumeLevelScalar', (['in'], DWORD, 'nChannel'), (['in'], c_float, 'fLevelDB'), (['in'], POINTER(GUID), 'pguidEventContext') ), COMMETHOD([], HRESULT, 'GetChannelVolumeLevel', (['in'], DWORD, 'nChannel'), (['out', 'retval'], POINTER(c_float), 'pfLevelDB') ), COMMETHOD([], HRESULT, 'GetChannelVolumeLevelScalar', (['in'], DWORD, 'nChannel'), (['out', 'retval'], POINTER(c_float), 'pfLevelDB') ), COMMETHOD([], HRESULT, 'SetMute', (['in'], BOOL, 'bMute'), (['in'], POINTER(GUID), 'pguidEventContext') ), COMMETHOD([], HRESULT, 'GetMute', (['out', 'retval'], POINTER(BOOL), 'pbMute') ), COMMETHOD([], HRESULT, 'GetVolumeStepInfo', (['out', 'retval'], POINTER(c_float), 'pnStep'), (['out', 'retval'], POINTER(c_float), 'pnStepCount'), ), COMMETHOD([], HRESULT, 'VolumeStepUp', (['in'], POINTER(GUID), 'pguidEventContext') ), COMMETHOD([], HRESULT, 'VolumeStepDown', (['in'], POINTER(GUID), 'pguidEventContext') ), COMMETHOD([], HRESULT, 'QueryHardwareSupport', (['out', 'retval'], POINTER(DWORD), 'pdwHardwareSupportMask') ), COMMETHOD([], HRESULT, 'GetVolumeRange', (['out', 'retval'], POINTER(c_float), 'pfMin'), (['out', 'retval'], POINTER(c_float), 'pfMax'), (['out', 'retval'], POINTER(c_float), 'pfIncr') ), ] class IPropertyStore(IUnknown): _iid_ = GUID('{886d8eeb-8cf2-4446-8d02-cdba1dbdcf99}') _methods_ = [ COMMETHOD([], HRESULT, 'GetCount', (['out'], POINTER(DWORD), 'cProps') ), COMMETHOD([], HRESULT, 'GetAt', (['in'], DWORD, 'iProp'), (['out'], POINTER(PropertyKey), 'pkey') ), COMMETHOD([], HRESULT, 'GetValue', (['in'], REFPROPERTYKEY, 'key'), (['out', 'retval'], PROPVARIANT, 'pv') ), STDMETHOD('SetValue', HRESULT, []) ] pass class IMMDevice(IUnknown): _iid_ = GUID('{D666063F-1587-4E43-81F1-B948E807363F}') _methods_ = [ COMMETHOD([], HRESULT, 'Activate', (['in'], POINTER(GUID), 'iid'), (['in'], DWORD, 'dwClsCtx'), (['in'], POINTER(DWORD), 'pActivationParams'), (['out', 'retval'], POINTER(POINTER(IAudioEndpointVolume)), 'ppInterface') ), COMMETHOD([], HRESULT, 'OpenPropertyStore', (['in'], DWORD, 'stgmAccess'), (['out', 'retval'], POINTER(POINTER(IPropertyStore)), 'ppProperties') ), COMMETHOD([], HRESULT, 'GetId', (['out', 'retval'], POINTER(LPWSTR), 'ppstrId') ), STDMETHOD(HRESULT, 'GetState', []) ] pass class IMMDeviceCollection(IUnknown): _iid_ = GUID('{0BD7A1BE-7A1A-44DB-8397-CC5392387B5E}') _methods_ = [ COMMETHOD([], HRESULT, 'GetCount', (['out', 'retval'], POINTER(UINT), 'pcDevices') ), COMMETHOD([], HRESULT, 'Item', (['in'], UINT, 'nDevice'), (['out', 'retval'], POINTER(POINTER(IMMDevice)), 'ppDevice') ) ] pass class IMMDeviceEnumerator(IUnknown): _iid_ = GUID('{A95664D2-9614-4F35-A746-DE8DB63617E6}') _methods_ = [ COMMETHOD([], HRESULT, 'EnumAudioEndpoints', (['in'], DWORD, 'dataFlow'), (['in'], DWORD, 'dwStateMask'), (['out', 'retval'], POINTER(POINTER(IMMDeviceCollection)), 'ppDevices') ), COMMETHOD([], HRESULT, 'GetDefaultAudioEndpoint', (['in'], DWORD, 'dataFlow'), (['in'], DWORD, 'role'), (['out', 'retval'], POINTER(POINTER(IMMDevice)), 'ppDevices') ) ] enumerator = CoCreateInstance( CLSID_MMDeviceEnumerator, IMMDeviceEnumerator, CLSCTX_ALL ) def print_device_details(device): device_id = device.GetId() print(device_id) device.OpenPropertyStore(0) devices = enumerator.EnumAudioEndpoints(0, 1) device_count = devices.GetCount() print('device_count', device_count) for i in range(device_count): device = devices.Item(i) print_device_details(device) ``` Regards, Stefan Boskovic
_______________________________________________ python-win32 mailing list python-win32@python.org https://mail.python.org/mailman/listinfo/python-win32