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

Reply via email to