AndreMiras / pycaw

Python Core Audio Windows Library
MIT License
385 stars 67 forks source link

Control Microphone / Inputs, too? #50

Open McNugget6750 opened 3 years ago

McNugget6750 commented 3 years ago

Is there a way to control the input volumes for microphone (and line) as well as mute these? So far I have only found tools for setting the output volumes of things.

drp0 commented 2 years ago

Try this:

from __future__ import print_function
from ctypes import POINTER, cast
import comtypes
from comtypes import CLSCTX_ALL
from pycaw.pycaw import AudioUtilities, IAudioEndpointVolume, CLSID_MMDeviceEnumerator, IMMDeviceEnumerator, EDataFlow, ERole, DEVICE_STATE

# audioVol4
# D.R.Patterson, 28/11/2021
# Get and set the volume of any audio device
# Specify device type using "in" / "out"
# Specify device state using DEVICE_STATE enumeration
# Volume expressed in percentages.

# For the basis of this code: akaufman1, https://github.com/AndreMiras/pycaw/issues/8
# For pointing the way with SetMasterVolumeLevelScalar: Roy Joseph Argumido, https://github.com/AndreMiras/pycaw/issues/13

class MyAudioUtilities(AudioUtilities):
    @staticmethod
    def GetDevice(id=None, default=0):
        device_enumerator = comtypes.CoCreateInstance(
            CLSID_MMDeviceEnumerator,
            IMMDeviceEnumerator,
            comtypes.CLSCTX_INPROC_SERVER)
        if id is not None:
            thisDevice = device_enumerator.GetDevice(id)
        else:
            if default == 0:
                # output
                thisDevice = device_enumerator.GetDefaultAudioEndpoint(EDataFlow.eRender.value, ERole.eMultimedia.value)
            else:
                # input
                thisDevice = device_enumerator.GetDefaultAudioEndpoint(EDataFlow.eCapture.value, ERole.eMultimedia.value)
        return thisDevice

    @staticmethod
    def MyGetAudioDevices(direction="in", State = DEVICE_STATE.ACTIVE.value):
        devices = []
        # for all use EDataFlow.eAll.value
        if direction == "in":
            Flow = EDataFlow.eCapture.value     # 1
        else:
            Flow = EDataFlow.eRender.value      # 0

        deviceEnumerator = comtypes.CoCreateInstance(
            CLSID_MMDeviceEnumerator,
            IMMDeviceEnumerator,
            comtypes.CLSCTX_INPROC_SERVER)
        if deviceEnumerator is None:
            return devices

        collection = deviceEnumerator.EnumAudioEndpoints(Flow, State)
        if collection is None:
            return devices

        count = collection.GetCount()
        for i in range(count):
            dev = collection.Item(i)
            if dev is not None:
                if not ": None" in str(AudioUtilities.CreateDevice(dev)):
                    devices.append(AudioUtilities.CreateDevice(dev))
        return devices

def main():
    direction = input("Input or output devices (in / out) ")
    direction = direction.lower()
    if direction != "in" and direction != "out": direction = "in"
    # DEVICE_STATE pycaw library defines:
    #   ACTIVE = 0x00000001
    #   DISABLED = 0x00000002
    #   NOTPRESENT = 0x00000004
    #   UNPLUGGED = 0x00000008
    #   MASK_ALL = 0x0000000F
    states = []                                 # Copy states
    names = []                                  # copy state names
    state = 0
    I = 0
    for val in DEVICE_STATE:
        print("Ref " + str(I) + ": " + val.name)
        states.append(val.value)
        names.append(val.name)
        I += 1
    ref = -1
    while (ref < 0) or (ref >= I):
        ref = int(input("Enter Ref 0 to " + str(I-1) +" for required state "))
    state = states[ref]
    print("Selected " + names[ref] + ", mask value: " + str(state))
    print()

    mixer_output = None
    tmp = None
    #devicelist = MyAudioUtilities.GetAllDevices()
    devicelist = MyAudioUtilities.MyGetAudioDevices(direction, state)
    i = 0
    for device in devicelist:
        print(i, device)
        i += 1

    if direction == "in":
        print(i, "Default Input")
    else:
        print(i, "Default Output")
    i += 1

    deviceSel = i

    while (deviceSel >= i) or (deviceSel < 0):
        print()
        search = input("Which device 0 to " + str(i-1) + ": ")
        deviceSel = int(search)

    if deviceSel < i-1:                         # use specific audio device
        mixer_output = devicelist[int(search)]
        print(mixer_output)
        tmp = mixer_output.id
        devices = MyAudioUtilities.GetDevice(tmp)

    else:

        if direction == "in":                   # use default audio device
            print("Default Input")
            devices = MyAudioUtilities.GetDevice(tmp, 1)   # default input
        else:    
            print("Default Output")
            devices = MyAudioUtilities.GetDevice(tmp, 0)   # default output

    print()

    # NB if names[ref] = "DISABLED" or "NOTPRESENT" 0r "UNPLUGGED"
    # Setting the volume will not work!
    try:
        interface = devices.Activate(IAudioEndpointVolume._iid_, CLSCTX_ALL, None)
        volume = cast(interface, POINTER(IAudioEndpointVolume))

        print("GetMute(): ", volume.GetMute())      # set using volume.SetMute(1, None)
        print("GetMasterVolumeLevelScalar(): %s" % int(0.5 + 100.0 * volume.GetMasterVolumeLevelScalar()))
        print("GetVolumeRange(): (%s, %s, %s)" % volume.GetVolumeRange())

        newLevel = input("Enter new level (Ctrl C to quit): ")

        intnewLevel = int(newLevel.replace('%', ''))
        if intnewLevel < 0:  intnewLevel = 0.0
        if intnewLevel > 100: intnewLevel = 100.0
        print("SetMasterVolumeLevelScalar", intnewLevel / 100.0)
        volume.SetMasterVolumeLevelScalar(intnewLevel / 100.0, None)
        print("GetMasterVolumeLevelScalar(): %s" % int(0.5 + 100.0 * volume.GetMasterVolumeLevelScalar()))
    except:
        print("Error selecting interface volume.: device: " + names[ref])

if __name__ == "__main__":
    try:
        while True:
            main()
            print()
    except KeyboardInterrupt:
        print()

David

gitagogaming commented 2 years ago

Try this:

from __future__ import print_function
from ctypes import POINTER, cast
import comtypes
from comtypes import CLSCTX_ALL
from pycaw.pycaw import AudioUtilities, IAudioEndpointVolume, CLSID_MMDeviceEnumerator, IMMDeviceEnumerator, EDataFlow, ERole, DEVICE_STATE

# audioVol4
# D.R.Patterson, 28/11/2021
# Get and set the volume of any audio device
# Specify device type using "in" / "out"
# Specify device state using DEVICE_STATE enumeration
# Volume expressed in percentages.

# For the basis of this code: akaufman1, https://github.com/AndreMiras/pycaw/issues/8
# For pointing the way with SetMasterVolumeLevelScalar: Roy Joseph Argumido, https://github.com/AndreMiras/pycaw/issues/13

class MyAudioUtilities(AudioUtilities):
    @staticmethod
    def GetDevice(id=None, default=0):
        device_enumerator = comtypes.CoCreateInstance(
            CLSID_MMDeviceEnumerator,
            IMMDeviceEnumerator,
            comtypes.CLSCTX_INPROC_SERVER)
        if id is not None:
            thisDevice = device_enumerator.GetDevice(id)
        else:
            if default == 0:
                # output
                thisDevice = device_enumerator.GetDefaultAudioEndpoint(EDataFlow.eRender.value, ERole.eMultimedia.value)
            else:
                # input
                thisDevice = device_enumerator.GetDefaultAudioEndpoint(EDataFlow.eCapture.value, ERole.eMultimedia.value)
        return thisDevice

    @staticmethod
    def MyGetAudioDevices(direction="in", State = DEVICE_STATE.ACTIVE.value):
        devices = []
        # for all use EDataFlow.eAll.value
        if direction == "in":
            Flow = EDataFlow.eCapture.value     # 1
        else:
            Flow = EDataFlow.eRender.value      # 0

        deviceEnumerator = comtypes.CoCreateInstance(
            CLSID_MMDeviceEnumerator,
            IMMDeviceEnumerator,
            comtypes.CLSCTX_INPROC_SERVER)
        if deviceEnumerator is None:
            return devices

        collection = deviceEnumerator.EnumAudioEndpoints(Flow, State)
        if collection is None:
            return devices

        count = collection.GetCount()
        for i in range(count):
            dev = collection.Item(i)
            if dev is not None:
                if not ": None" in str(AudioUtilities.CreateDevice(dev)):
                    devices.append(AudioUtilities.CreateDevice(dev))
        return devices

def main():
    direction = input("Input or output devices (in / out) ")
    direction = direction.lower()
    if direction != "in" and direction != "out": direction = "in"
    # DEVICE_STATE pycaw library defines:
    #   ACTIVE = 0x00000001
    #   DISABLED = 0x00000002
    #   NOTPRESENT = 0x00000004
    #   UNPLUGGED = 0x00000008
    #   MASK_ALL = 0x0000000F
    states = []                                 # Copy states
    names = []                                  # copy state names
    state = 0
    I = 0
    for val in DEVICE_STATE:
        print("Ref " + str(I) + ": " + val.name)
        states.append(val.value)
        names.append(val.name)
        I += 1
    ref = -1
    while (ref < 0) or (ref >= I):
        ref = int(input("Enter Ref 0 to " + str(I-1) +" for required state "))
    state = states[ref]
    print("Selected " + names[ref] + ", mask value: " + str(state))
    print()

    mixer_output = None
    tmp = None
    #devicelist = MyAudioUtilities.GetAllDevices()
    devicelist = MyAudioUtilities.MyGetAudioDevices(direction, state)
    i = 0
    for device in devicelist:
        print(i, device)
        i += 1

    if direction == "in":
        print(i, "Default Input")
    else:
        print(i, "Default Output")
    i += 1

    deviceSel = i

    while (deviceSel >= i) or (deviceSel < 0):
        print()
        search = input("Which device 0 to " + str(i-1) + ": ")
        deviceSel = int(search)

    if deviceSel < i-1:                         # use specific audio device
        mixer_output = devicelist[int(search)]
        print(mixer_output)
        tmp = mixer_output.id
        devices = MyAudioUtilities.GetDevice(tmp)

    else:

        if direction == "in":                   # use default audio device
            print("Default Input")
            devices = MyAudioUtilities.GetDevice(tmp, 1)   # default input
        else:    
            print("Default Output")
            devices = MyAudioUtilities.GetDevice(tmp, 0)   # default output

    print()

    # NB if names[ref] = "DISABLED" or "NOTPRESENT" 0r "UNPLUGGED"
    # Setting the volume will not work!
    try:
        interface = devices.Activate(IAudioEndpointVolume._iid_, CLSCTX_ALL, None)
        volume = cast(interface, POINTER(IAudioEndpointVolume))

        print("GetMute(): ", volume.GetMute())      # set using volume.SetMute(1, None)
        print("GetMasterVolumeLevelScalar(): %s" % int(0.5 + 100.0 * volume.GetMasterVolumeLevelScalar()))
        print("GetVolumeRange(): (%s, %s, %s)" % volume.GetVolumeRange())

        newLevel = input("Enter new level (Ctrl C to quit): ")

        intnewLevel = int(newLevel.replace('%', ''))
        if intnewLevel < 0:  intnewLevel = 0.0
        if intnewLevel > 100: intnewLevel = 100.0
        print("SetMasterVolumeLevelScalar", intnewLevel / 100.0)
        volume.SetMasterVolumeLevelScalar(intnewLevel / 100.0, None)
        print("GetMasterVolumeLevelScalar(): %s" % int(0.5 + 100.0 * volume.GetMasterVolumeLevelScalar()))
    except:
        print("Error selecting interface volume.: device: " + names[ref])

if __name__ == "__main__":
    try:
        while True:
            main()
            print()
    except KeyboardInterrupt:
        print()

David

Was trying to get microphone mute state today and came across this but also had an error when trying

ImportError: cannot import name 'CLSID_MMDeviceEnumerator' from 'pycaw.pycaw' - was wondering how i might resolve this as I have the mostrecent version of the module

drp0 commented 2 years ago

Hi gitagogaming, I have just re-tested my code without issue. pip list gives my pycaw version as 20181226 David

drp0 commented 2 years ago

gitagogaming, I am using python 3.91 If you get past the import issue I suggest looking at the pycaw.py edit detailed at https://github.com/AndreMiras/pycaw/issues/53 You might want to try the amendment. David

cdwcgt commented 1 year ago
- from pycaw.pycaw import CLSID_MMDeviceEnumerator
+ from pycaw.constants import CLSID_MMDeviceEnumerator
Gloryness commented 1 year ago

This is so helpful because windows 11 keeps auto adjusting my microphone's input volume and I've already followed tutorials to stop it from happening but none work. So now I'm just gonna have a python script running 24/7 to keep setting my microphone to the volume I want it to be on.

hilmiguner commented 6 months ago

Try this:

from __future__ import print_function
from ctypes import POINTER, cast
import comtypes
from comtypes import CLSCTX_ALL
from pycaw.pycaw import AudioUtilities, IAudioEndpointVolume, CLSID_MMDeviceEnumerator, IMMDeviceEnumerator, EDataFlow, ERole, DEVICE_STATE

# audioVol4
# D.R.Patterson, 28/11/2021
# Get and set the volume of any audio device
# Specify device type using "in" / "out"
# Specify device state using DEVICE_STATE enumeration
# Volume expressed in percentages.

# For the basis of this code: akaufman1, https://github.com/AndreMiras/pycaw/issues/8
# For pointing the way with SetMasterVolumeLevelScalar: Roy Joseph Argumido, https://github.com/AndreMiras/pycaw/issues/13

class MyAudioUtilities(AudioUtilities):
    @staticmethod
    def GetDevice(id=None, default=0):
        device_enumerator = comtypes.CoCreateInstance(
            CLSID_MMDeviceEnumerator,
            IMMDeviceEnumerator,
            comtypes.CLSCTX_INPROC_SERVER)
        if id is not None:
            thisDevice = device_enumerator.GetDevice(id)
        else:
            if default == 0:
                # output
                thisDevice = device_enumerator.GetDefaultAudioEndpoint(EDataFlow.eRender.value, ERole.eMultimedia.value)
            else:
                # input
                thisDevice = device_enumerator.GetDefaultAudioEndpoint(EDataFlow.eCapture.value, ERole.eMultimedia.value)
        return thisDevice

    @staticmethod
    def MyGetAudioDevices(direction="in", State = DEVICE_STATE.ACTIVE.value):
        devices = []
        # for all use EDataFlow.eAll.value
        if direction == "in":
            Flow = EDataFlow.eCapture.value     # 1
        else:
            Flow = EDataFlow.eRender.value      # 0

        deviceEnumerator = comtypes.CoCreateInstance(
            CLSID_MMDeviceEnumerator,
            IMMDeviceEnumerator,
            comtypes.CLSCTX_INPROC_SERVER)
        if deviceEnumerator is None:
            return devices

        collection = deviceEnumerator.EnumAudioEndpoints(Flow, State)
        if collection is None:
            return devices

        count = collection.GetCount()
        for i in range(count):
            dev = collection.Item(i)
            if dev is not None:
                if not ": None" in str(AudioUtilities.CreateDevice(dev)):
                    devices.append(AudioUtilities.CreateDevice(dev))
        return devices

def main():
    direction = input("Input or output devices (in / out) ")
    direction = direction.lower()
    if direction != "in" and direction != "out": direction = "in"
    # DEVICE_STATE pycaw library defines:
    #   ACTIVE = 0x00000001
    #   DISABLED = 0x00000002
    #   NOTPRESENT = 0x00000004
    #   UNPLUGGED = 0x00000008
    #   MASK_ALL = 0x0000000F
    states = []                                 # Copy states
    names = []                                  # copy state names
    state = 0
    I = 0
    for val in DEVICE_STATE:
        print("Ref " + str(I) + ": " + val.name)
        states.append(val.value)
        names.append(val.name)
        I += 1
    ref = -1
    while (ref < 0) or (ref >= I):
        ref = int(input("Enter Ref 0 to " + str(I-1) +" for required state "))
    state = states[ref]
    print("Selected " + names[ref] + ", mask value: " + str(state))
    print()

    mixer_output = None
    tmp = None
    #devicelist = MyAudioUtilities.GetAllDevices()
    devicelist = MyAudioUtilities.MyGetAudioDevices(direction, state)
    i = 0
    for device in devicelist:
        print(i, device)
        i += 1

    if direction == "in":
        print(i, "Default Input")
    else:
        print(i, "Default Output")
    i += 1

    deviceSel = i

    while (deviceSel >= i) or (deviceSel < 0):
        print()
        search = input("Which device 0 to " + str(i-1) + ": ")
        deviceSel = int(search)

    if deviceSel < i-1:                         # use specific audio device
        mixer_output = devicelist[int(search)]
        print(mixer_output)
        tmp = mixer_output.id
        devices = MyAudioUtilities.GetDevice(tmp)

    else:

        if direction == "in":                   # use default audio device
            print("Default Input")
            devices = MyAudioUtilities.GetDevice(tmp, 1)   # default input
        else:    
            print("Default Output")
            devices = MyAudioUtilities.GetDevice(tmp, 0)   # default output

    print()

    # NB if names[ref] = "DISABLED" or "NOTPRESENT" 0r "UNPLUGGED"
    # Setting the volume will not work!
    try:
        interface = devices.Activate(IAudioEndpointVolume._iid_, CLSCTX_ALL, None)
        volume = cast(interface, POINTER(IAudioEndpointVolume))

        print("GetMute(): ", volume.GetMute())      # set using volume.SetMute(1, None)
        print("GetMasterVolumeLevelScalar(): %s" % int(0.5 + 100.0 * volume.GetMasterVolumeLevelScalar()))
        print("GetVolumeRange(): (%s, %s, %s)" % volume.GetVolumeRange())

        newLevel = input("Enter new level (Ctrl C to quit): ")

        intnewLevel = int(newLevel.replace('%', ''))
        if intnewLevel < 0:  intnewLevel = 0.0
        if intnewLevel > 100: intnewLevel = 100.0
        print("SetMasterVolumeLevelScalar", intnewLevel / 100.0)
        volume.SetMasterVolumeLevelScalar(intnewLevel / 100.0, None)
        print("GetMasterVolumeLevelScalar(): %s" % int(0.5 + 100.0 * volume.GetMasterVolumeLevelScalar()))
    except:
        print("Error selecting interface volume.: device: " + names[ref])

if __name__ == "__main__":
    try:
        while True:
            main()
            print()
    except KeyboardInterrupt:
        print()

David

You are the best man!!! I want to learn more about Windows Core Audio API for Python but in a more basic way than the original docs if its possible. Can you suggest me any source? If you can I will be very grateful!!