在 Python 中读取和/或更改 Windows 8 主卷 [重复]

Posted

技术标签:

【中文标题】在 Python 中读取和/或更改 Windows 8 主卷 [重复]【英文标题】:Read and/or Change Windows 8 Master Volume in Python [duplicate] 【发布时间】:2015-08-21 21:54:44 【问题描述】:

如何使用 python 更改笔记本电脑的主音量?我知道一种方法,我使用 ctypes 模拟音量增大/音量减小按键,但是在不知道当前音量的情况下,每当我启动应用程序进行校准时,我必须让我的代码执行 50 次连续的音量减小按键归零。

有没有办法让我获得当前的系统音量,或者更好的是,将主音量设置为指定值?

我正在使用 Python 3.4 运行 Windows 8 64 位系统。

【问题讨论】:

请问您的申请是什么? Python 的内置音频能力很差。 从 Python 中调用类似于 mixerOpen 的 Windows API。 @DavidChing,在 Vista 和更高版本中,winmm.dll API 修改了每个应用程序的音频设置。设置主音量需要使用IAudioEndpointVolume COM 接口。 谢谢@eryksun,我不知道! 【参考方案1】:

Tim Roberts 在 python-win32 讨论列表中发布了一个 comtypes 示例,说明如何使用 Control Volume on Windows。在下面的示例中,我修改了 Tim 的代码并添加了返回默认音频端点及其 IAudioEndpointVolume 接口的类方法。

我测试的两个系统(Windows 7 和 Windows 10)上的 dB 音量范围将最大音量标准化为 0 dB,但最小音量和音量增量因系统而异。我建议改用标量和积分步长方法。标量范围是 0.0 到 1.0。

import ctypes
import comtypes
from ctypes import wintypes

MMDeviceApiLib = comtypes.GUID(
    '2FDAAFA3-7523-4F66-9957-9D5E7FE698F6')
IID_IMMDevice = comtypes.GUID(
    'D666063F-1587-4E43-81F1-B948E807363F')
IID_IMMDeviceCollection = comtypes.GUID(
    '0BD7A1BE-7A1A-44DB-8397-CC5392387B5E')
IID_IMMDeviceEnumerator = comtypes.GUID(
    'A95664D2-9614-4F35-A746-DE8DB63617E6')
IID_IAudioEndpointVolume = comtypes.GUID(
    '5CDF2C82-841E-4546-9722-0CF74078229A')
CLSID_MMDeviceEnumerator = comtypes.GUID(
    'BCDE0395-E52F-467C-8E3D-C4579291692E')

# EDataFlow
eRender = 0 # audio rendering stream
eCapture = 1 # audio capture stream
eAll = 2 # audio rendering or capture stream

# ERole
eConsole = 0 # games, system sounds, and voice commands
eMultimedia = 1 # music, movies, narration
eCommunications = 2 # voice communications

LPCGUID = REFIID = ctypes.POINTER(comtypes.GUID)
LPFLOAT = ctypes.POINTER(ctypes.c_float)
LPDWORD = ctypes.POINTER(wintypes.DWORD)
LPUINT = ctypes.POINTER(wintypes.UINT)
LPBOOL = ctypes.POINTER(wintypes.BOOL)
PIUnknown = ctypes.POINTER(comtypes.IUnknown)

class IMMDevice(comtypes.IUnknown):
    _iid_ = IID_IMMDevice
    _methods_ = (
        comtypes.COMMETHOD([], ctypes.HRESULT, 'Activate',
            (['in'], REFIID, 'iid'),
            (['in'], wintypes.DWORD, 'dwClsCtx'),
            (['in'], LPDWORD, 'pActivationParams', None),
            (['out','retval'], ctypes.POINTER(PIUnknown), 'ppInterface')),
        comtypes.STDMETHOD(ctypes.HRESULT, 'OpenPropertyStore', []),
        comtypes.STDMETHOD(ctypes.HRESULT, 'GetId', []),
        comtypes.STDMETHOD(ctypes.HRESULT, 'GetState', []))

PIMMDevice = ctypes.POINTER(IMMDevice)

class IMMDeviceCollection(comtypes.IUnknown):
    _iid_ = IID_IMMDeviceCollection

PIMMDeviceCollection = ctypes.POINTER(IMMDeviceCollection)

class IMMDeviceEnumerator(comtypes.IUnknown):
    _iid_ = IID_IMMDeviceEnumerator
    _methods_ = (
        comtypes.COMMETHOD([], ctypes.HRESULT, 'EnumAudioEndpoints',
            (['in'], wintypes.DWORD, 'dataFlow'),
            (['in'], wintypes.DWORD, 'dwStateMask'),
            (['out','retval'], ctypes.POINTER(PIMMDeviceCollection),
             'ppDevices')),
        comtypes.COMMETHOD([], ctypes.HRESULT, 'GetDefaultAudioEndpoint',
            (['in'], wintypes.DWORD, 'dataFlow'),
            (['in'], wintypes.DWORD, 'role'),
            (['out','retval'], ctypes.POINTER(PIMMDevice), 'ppDevices')))
    @classmethod
    def get_default(cls, dataFlow, role):
        enumerator = comtypes.CoCreateInstance(
            CLSID_MMDeviceEnumerator, cls, comtypes.CLSCTX_INPROC_SERVER)
        return enumerator.GetDefaultAudioEndpoint(dataFlow, role)

class IAudioEndpointVolume(comtypes.IUnknown):
    _iid_ = IID_IAudioEndpointVolume
    _methods_ = (
        comtypes.STDMETHOD(ctypes.HRESULT, 'RegisterControlChangeNotify', []),
        comtypes.STDMETHOD(ctypes.HRESULT, 'UnregisterControlChangeNotify', []),
        comtypes.COMMETHOD([], ctypes.HRESULT, 'GetChannelCount',
            (['out', 'retval'], LPUINT, 'pnChannelCount')),
        comtypes.COMMETHOD([], ctypes.HRESULT, 'SetMasterVolumeLevel',
            (['in'], ctypes.c_float, 'fLevelDB'),
            (['in'], LPCGUID, 'pguidEventContext', None)),
        comtypes.COMMETHOD([], ctypes.HRESULT, 'SetMasterVolumeLevelScalar',
            (['in'], ctypes.c_float, 'fLevel'),
            (['in'], LPCGUID, 'pguidEventContext', None)),
        comtypes.COMMETHOD([], ctypes.HRESULT, 'GetMasterVolumeLevel',
            (['out','retval'], LPFLOAT, 'pfLevelDB')),
        comtypes.COMMETHOD([], ctypes.HRESULT, 'GetMasterVolumeLevelScalar',
            (['out','retval'], LPFLOAT, 'pfLevel')),
        comtypes.COMMETHOD([], ctypes.HRESULT, 'SetChannelVolumeLevel',
            (['in'], wintypes.UINT, 'nChannel'),
            (['in'], ctypes.c_float, 'fLevelDB'),
            (['in'], LPCGUID, 'pguidEventContext', None)),
        comtypes.COMMETHOD([], ctypes.HRESULT, 'SetChannelVolumeLevelScalar',
            (['in'], wintypes.UINT, 'nChannel'),
            (['in'], ctypes.c_float, 'fLevel'),
            (['in'], LPCGUID, 'pguidEventContext', None)),
        comtypes.COMMETHOD([], ctypes.HRESULT, 'GetChannelVolumeLevel',
            (['in'], wintypes.UINT, 'nChannel'),
            (['out','retval'], LPFLOAT, 'pfLevelDB')),
        comtypes.COMMETHOD([], ctypes.HRESULT, 'GetChannelVolumeLevelScalar',
            (['in'], wintypes.UINT, 'nChannel'),
            (['out','retval'], LPFLOAT, 'pfLevel')),
        comtypes.COMMETHOD([], ctypes.HRESULT, 'SetMute',
            (['in'], wintypes.BOOL, 'bMute'),
            (['in'], LPCGUID, 'pguidEventContext', None)),
        comtypes.COMMETHOD([], ctypes.HRESULT, 'GetMute',
            (['out','retval'], LPBOOL, 'pbMute')),
        comtypes.COMMETHOD([], ctypes.HRESULT, 'GetVolumeStepInfo',
            (['out','retval'], LPUINT, 'pnStep'),
            (['out','retval'], LPUINT, 'pnStepCount')),
        comtypes.COMMETHOD([], ctypes.HRESULT, 'VolumeStepUp',
            (['in'], LPCGUID, 'pguidEventContext', None)),
        comtypes.COMMETHOD([], ctypes.HRESULT, 'VolumeStepDown',
            (['in'], LPCGUID, 'pguidEventContext', None)),
        comtypes.COMMETHOD([], ctypes.HRESULT, 'QueryHardwareSupport',
            (['out','retval'], LPDWORD, 'pdwHardwareSupportMask')),
        comtypes.COMMETHOD([], ctypes.HRESULT, 'GetVolumeRange',
            (['out','retval'], LPFLOAT, 'pfLevelMinDB'),
            (['out','retval'], LPFLOAT, 'pfLevelMaxDB'),
            (['out','retval'], LPFLOAT, 'pfVolumeIncrementDB')))
    @classmethod
    def get_default(cls):
        endpoint = IMMDeviceEnumerator.get_default(eRender, eMultimedia)
        interface = endpoint.Activate(cls._iid_, comtypes.CLSCTX_INPROC_SERVER)
        return ctypes.cast(interface, ctypes.POINTER(cls))

例如:

if __name__ == '__main__':

    def show_vol(ev):
        voldb = ev.GetMasterVolumeLevel()
        volsc = ev.GetMasterVolumeLevelScalar()
        volst, nstep = ev.GetVolumeStepInfo()
        print('Master Volume (dB): %0.4f' % voldb)
        print('Master Volume (scalar): %0.4f' % volsc)
        print('Master Volume (step): %d / %d' % (volst, nstep))

    def test():
        ev = IAudioEndpointVolume.get_default()
        vol = ev.GetMasterVolumeLevelScalar()
        vmin, vmax, vinc = ev.GetVolumeRange()
        print('Volume Range (min, max, step) (dB): '
              '%0.4f, %0.4f, %0.4f' % (vmin, vmax, vinc))
        show_vol(ev)
        try:
            print('\nIncrement the master volume')
            ev.VolumeStepUp()
            show_vol(ev)
            print('\nDecrement the master volume twice')
            ev.VolumeStepDown()
            ev.VolumeStepDown()
            show_vol(ev)
            print('\nSet the master volume to 0.75 scalar')
            ev.SetMasterVolumeLevelScalar(0.75)
            show_vol(ev)
            print('\nSet the master volume to 0.25 scalar')
            ev.SetMasterVolumeLevelScalar(0.25)
            show_vol(ev)
        finally:
            ev.SetMasterVolumeLevelScalar(vol)

    comtypes.CoInitialize()
    try:
        test()
    finally:
        comtypes.CoUninitialize()

【讨论】:

谢谢!效果很好!

以上是关于在 Python 中读取和/或更改 Windows 8 主卷 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

Spark [Python] - 在 Windows 中读取本地文件

如何从 C++/Qt 中的 .exe 和 .dlls 中读取图标(在 Windows 上)?

为什么python无法读取环境变量并且无法运行Windows命令行?

如何读取和更改使用 html 或 xhtml 中的图像标签包含的 svg 文件中的元素? [复制]

在 Windows 中更改 Python 路径

安装python3时出现了文件或目录损坏且无法读取怎么操作呀