pythonaudiocomtypespycaw

python set and get windows 11 volume


I have this script:

from pycaw.pycaw import AudioUtilities, IAudioEndpointVolume
from ctypes import cast, POINTER
from comtypes import CLSCTX_ALL, CoInitialize, CoUninitialize
CLSCTX_ALL = 7

import time

def set_windows_volume(value_max_100):
    devices = AudioUtilities.GetSpeakers()
    interface = devices.Activate(IAudioEndpointVolume._iid_, CLSCTX_ALL, None)
    volume = cast(interface, POINTER(IAudioEndpointVolume))
    scalarVolume = int(value_max_100) / 100
    volume.SetMasterVolumeLevelScalar(scalarVolume, None)
    
def get_windows_volume():
    devices = AudioUtilities.GetSpeakers()
    interface = devices.Activate(IAudioEndpointVolume._iid_, CLSCTX_ALL, None)
    windows_volume = cast(interface, POINTER(IAudioEndpointVolume))
    volume_percentage = int(round(windows_volume.GetMasterVolumeLevelScalar() * 100))
    return volume_percentage

for i in range(0,100):
    set_windows_volume(i)
    time.sleep(2)
    print(get_windows_volume())

but sometimes it raises errors:

Exception ignored in: <function _compointer_base.__del__ at 0x000002B538E96B90>
Traceback (most recent call last):
  File "C:\Python\lib\site-packages\comtypes\_post_coinit\unknwn.py", line 426, in __del__
    self.Release()
  File "C:\Python\lib\site-packages\comtypes\_post_coinit\unknwn.py", line 559, in Release
    return self.__com_Release()  # type: ignore
ValueError: COM method call without VTable
Exception ignored in: <function _compointer_base.__del__ at 0x000002B538E96B90>
Traceback (most recent call last):
  File "C:\Python\lib\site-packages\comtypes\_post_coinit\unknwn.py", line 426, in __del__
    self.Release()
  File "C:\Python\lib\site-packages\comtypes\_post_coinit\unknwn.py", line 559, in Release
    return self.__com_Release()  # type: ignore
ValueError: COM method call without VTable
Exception ignored in: <function _compointer_base.__del__ at 0x000002B538E96B90>
Traceback (most recent call last):
  File "C:\Python\lib\site-packages\comtypes\_post_coinit\unknwn.py", line 426, in __del__
    self.Release()
  File "C:\Python\lib\site-packages\comtypes\_post_coinit\unknwn.py", line 559, in Release
    return self.__com_Release()  # type: ignore
ValueError: COM method call without VTable
Exception ignored in: <function _compointer_base.__del__ at 0x000002B538E96B90>
Traceback (most recent call last):
  File "C:\Python\lib\site-packages\comtypes\_post_coinit\unknwn.py", line 426, in __del__
    self.Release()
  File "C:\Python\lib\site-packages\comtypes\_post_coinit\unknwn.py", line 559, in Release
    return self.__com_Release()  # type: ignore
ValueError: COM method call without VTable
Exception ignored in: <function _compointer_base.__del__ at 0x000002B538E96B90>
Traceback (most recent call last):
  File "C:\Python\lib\site-packages\comtypes\_post_coinit\unknwn.py", line 426, in __del__
    self.Release()
  File "C:\Python\lib\site-packages\comtypes\_post_coinit\unknwn.py", line 559, in Release
    return self.__com_Release()  # type: ignore
ValueError: COM method call without VTable
Exception ignored in: <function _compointer_base.__del__ at 0x000002B538E96B90>
Traceback (most recent call last):
  File "C:\Python\lib\site-packages\comtypes\_post_coinit\unknwn.py", line 426, in __del__
    self.Release()
  File "C:\Python\lib\site-packages\comtypes\_post_coinit\unknwn.py", line 559, in Release
    return self.__com_Release()  # type: ignore
ValueError: COM method call without VTable
Exception ignored in: <function _compointer_base.__del__ at 0x000002B538E96B90>
Traceback (most recent call last):
  File "C:\Python\lib\site-packages\comtypes\_post_coinit\unknwn.py", line 426, in __del__
    self.Release()
  File "C:\Python\lib\site-packages\comtypes\_post_coinit\unknwn.py", line 559, in Release
    return self.__com_Release()  # type: ignore
ValueError: COM method call without VTable
Exception ignored in: <function _compointer_base.__del__ at 0x000002B538E96B90>
Traceback (most recent call last):
  File "C:\Python\lib\site-packages\comtypes\_post_coinit\unknwn.py", line 426, in __del__
    self.Release()
  File "C:\Python\lib\site-packages\comtypes\_post_coinit\unknwn.py", line 559, in Release
    return self.__com_Release()  # type: ignore
ValueError: COM method call without VTable
Exception ignored in: <function _compointer_base.__del__ at 0x000002B538E96B90>
Traceback (most recent call last):
  File "C:\Python\lib\site-packages\comtypes\_post_coinit\unknwn.py", line 426, in __del__
    self.Release()
  File "C:\Python\lib\site-packages\comtypes\_post_coinit\unknwn.py", line 559, in Release
    return self.__com_Release()  # type: ignore
ValueError: COM method call without VTable
Exception ignored in: <function _compointer_base.__del__ at 0x000002B538E96B90>
Traceback (most recent call last):
  File "C:\Python\lib\site-packages\comtypes\_post_coinit\unknwn.py", line 426, in __del__
    self.Release()
  File "C:\Python\lib\site-packages\comtypes\_post_coinit\unknwn.py", line 559, in Release
    return self.__com_Release()  # type: ignore
ValueError: COM method call without VTable
======== Running on http://192.168.1.188:8080 ========
Exception ignored in: <function _compointer_base.__del__ at 0x000002B538E96B90>
Traceback (most recent call last):
  File "C:\Python\lib\site-packages\comtypes\_post_coinit\unknwn.py", line 426, in __del__
    self.Release()
  File "C:\Python\lib\site-packages\comtypes\_post_coinit\unknwn.py", line 559, in Release
    return self.__com_Release()  # type: ignore
ValueError: COM method call without VTable

Basically i use this script in a multiprocessing.Process with CoInitialize and CoUninitialize and safe release, but the error is still there.

Any help or alternatives?


Solution

  • I have downloaded some tools from https://www.nirsoft.net/

    1. SoundVolumeView.exe
    2. svcl.exe
    3. nircmd.exe

    python script:

    import csv
    import subprocess
    import os
    
    def find_active_audio_device():
        try:
            subprocess.run("SoundVolumeView.exe /scomma devices_list.csv", shell=True, check=True)
            if not os.path.exists("devices_list.csv"):
                raise FileNotFoundError("devices_list.csv not found. Ensure SoundVolumeView.exe is working correctly.")
            with open("devices_list.csv", "r", encoding="utf-8") as csvfile:
                reader = csv.DictReader(csvfile)
                for row in reader:
                    if row["Device State"] == "Active" and row["Type"] == "Device" and row["Direction"] == "Render":
                        return row["Command-Line Friendly ID"]
        except subprocess.CalledProcessError as e:
            return f"Error running SoundVolumeView: {e}"
        except FileNotFoundError:
            return "CSV file not generated."
        except KeyError:
            return "CSV format is invalid or missing required fields."
        return None
    
    def get_audio_volume():
        device_id = find_active_audio_device()
        if not device_id:
            return "No active audio device found."
        try:
            command = f'svcl.exe /Stdout /GetPercent "{device_id}"'
            result = subprocess.run(command, capture_output=True, text=True, shell=True, check=True)
            return result.stdout.strip()
        except subprocess.CalledProcessError as e:
            return f"Error getting volume: {e}"
    
    def set_audio_volume(percent=50):
        if not 0 <= percent <= 100:
            raise ValueError("Volume percentage must be between 0 and 100.")
        try:
            max_volume = 65535
            volume = int(max_volume * percent / 100)
            subprocess.run(["nircmd.exe", "setsysvolume", str(volume)], check=True)
        except subprocess.CalledProcessError as e:
            return f"Error setting volume: {e}"
        except FileNotFoundError:
            return "nircmd.exe not found. Ensure it is in the same directory or added to PATH."
    
    # Example usage
    set_audio_volume(34)
    volume = get_audio_volume()
    print(f"Current Volume: {volume}")
    

    I am not the maker of this exe tools, so use at your own risk.