Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changing the volume of a non-default sound device #8

Open
ghost opened this issue Feb 7, 2018 · 4 comments
Open

Changing the volume of a non-default sound device #8

ghost opened this issue Feb 7, 2018 · 4 comments

Comments

@ghost
Copy link

ghost commented Feb 7, 2018

I always used SetMasterVolumeLevel to change the volume level on my pc, but now I have a problem because I need to change the volume of a different sound device. Is there a way to solve this?

@ahartquist
Copy link

I would like to control volume of an app, but I don't know how to do it if the app is on a non default device.
I have found that when I try to report all process names with AudioUtilities.GetAllSessions(), I only obtain a list of the applications that are associated with the default device.

This appears to be due to GetAllSessions() relies on
GetAudioSessionManager() which relies on
GetSpeakers() which relies on
GetDefaultAudioEndpoint. <---- That's the problem, it only takes into account the default audio endpoint (default device).

Anyone know a way around this?

from pycaw.pycaw import AudioUtilities, IAudioEndpointVolume

print("\nAll Auido Device Sessions: ")
AllSessions = AudioUtilities.GetAllSessions()
for d in AllSessions:
  print(d.Process.name())

@Morph763
Copy link

Anyone having an answer to the above?

What i can tell is that within the GetSpeakers() function the above is pointing to GetDefaultAudioEndpoint

speakers = deviceEnumerator.GetDefaultAudioEndpoint( EDataFlow.eRender.value, ERole.eMultimedia.value)

within the GetAllDevices funtion i am able to list sound output devices but the same data are not being collected.

collection = deviceEnumerator.EnumAudioEndpoints( EDataFlow.eAll.value, DEVICE_STATE.MASK_ALL.value)

Knowing this is looks like it could be possible to fetch the same values for output devices not considered "default" but not sure how that would be done.

@akaufman1
Copy link

akaufman1 commented Apr 30, 2020

I sub-classed the AudioUtilities class and overrode the Get Speaker function to allow input of device id gathered from the GetAllDevices method.

class MyAudioUtilities(AudioUtilities):

    @staticmethod
    def GetSpeaker(id=None):

        device_enumerator = comtypes.CoCreateInstance(
            CLSID_MMDeviceEnumerator,
            IMMDeviceEnumerator,
            comtypes.CLSCTX_INPROC_SERVER)
        if id is not None:
            speakers = device_enumerator.GetDevice(id)
        else:
            speakers = device_enumerator.GetDefaultAudioEndpoint(EDataFlow.eRender.value, ERole.eMultimedia.value)
        return speakers

I edited the endpoint example as such (including the new class):

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


class MyAudioUtilities(AudioUtilities):
    @staticmethod
    def GetSpeaker(id=None):
        device_enumerator = comtypes.CoCreateInstance(
            CLSID_MMDeviceEnumerator,
            IMMDeviceEnumerator,
            comtypes.CLSCTX_INPROC_SERVER)
        if id is not None:
            speakers = device_enumerator.GetDevice(id)
        else:
            speakers = device_enumerator.GetDefaultAudioEndpoint(EDataFlow.eRender.value, ERole.eMultimedia.value)
        return speakers


def main():
    mixer_output = None

    devicelist = MyAudioUtilities.GetAllDevices()

    for device in devicelist:
        if "UMC404HD" in str(device) and "Speaker" in str(device):
            mixer_output = device

    devices = MyAudioUtilities.GetSpeaker(mixer_output.id)
    print(devices)

    interface = devices.Activate(
        IAudioEndpointVolume._iid_, CLSCTX_ALL, None)
    volume = cast(interface, POINTER(IAudioEndpointVolume))
    print("volume.GetMute(): %s" % volume.GetMute())
    print("volume.GetMasterVolumeLevel(): %s" % volume.GetMasterVolumeLevel())
    print("volume.GetVolumeRange(): (%s, %s, %s)" % volume.GetVolumeRange())
    print("volume.SetMasterVolumeLevel()")
    volume.SetMasterVolumeLevel(-20.0, None)
    print("volume.GetMasterVolumeLevel(): %s" % volume.GetMasterVolumeLevel())


if __name__ == "__main__":
    main()

@Morph763
Copy link

Thanks @akaufman1 for helping us with this. I have not been able to try it yet but sure will!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants