How to Programmatically Set the System Volume

How to programmatically set the system volume?

I'm a bit late to the party but if you are looking now there's a nuget package available (AudioSwitcher.AudioApi.CoreAudio) that simplifies audio interactions. Install it then it’s as simple as:

CoreAudioDevice defaultPlaybackDevice = new CoreAudioController().DefaultPlaybackDevice;
Debug.WriteLine("Current Volume:" + defaultPlaybackDevice.Volume);
defaultPlaybackDevice.Volume = 80;

How to Get and Set System Volume in Windows

This requires a plugin. Since this question is for Windows, you can use IAudioEndpointVolume to build a C++ plugin then call it from C#. This post has a working C++ example of how to change volume with IAudioEndpointVolume and you can use it as the base source to create the C++ plugin.


I've gone ahead and cleaned that code up then converted into a dll plugin and placed the DLL at Assets/Plugins folder. You can see how to build the C++ plugin here.

The C++ code:

#include "stdafx.h"
#include <windows.h>
#include <mmdeviceapi.h>
#include <endpointvolume.h>

#define DLLExport __declspec(dllexport)

extern "C"
{
enum class VolumeUnit {
Decibel,
Scalar
};

//Gets volume
DLLExport float GetSystemVolume(VolumeUnit vUnit) {
HRESULT hr;

// -------------------------
CoInitialize(NULL);
IMMDeviceEnumerator *deviceEnumerator = NULL;
hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (LPVOID *)&deviceEnumerator);
IMMDevice *defaultDevice = NULL;

hr = deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &defaultDevice);
deviceEnumerator->Release();
deviceEnumerator = NULL;

IAudioEndpointVolume *endpointVolume = NULL;
hr = defaultDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (LPVOID *)&endpointVolume);
defaultDevice->Release();
defaultDevice = NULL;

float currentVolume = 0;
if (vUnit == VolumeUnit::Decibel) {
//Current volume in dB
hr = endpointVolume->GetMasterVolumeLevel(¤tVolume);
}

else if (vUnit == VolumeUnit::Scalar) {
//Current volume as a scalar
hr = endpointVolume->GetMasterVolumeLevelScalar(¤tVolume);
}
endpointVolume->Release();
CoUninitialize();

return currentVolume;
}

//Sets volume
DLLExport void SetSystemVolume(double newVolume, VolumeUnit vUnit) {
HRESULT hr;

// -------------------------
CoInitialize(NULL);
IMMDeviceEnumerator *deviceEnumerator = NULL;
hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (LPVOID *)&deviceEnumerator);
IMMDevice *defaultDevice = NULL;

hr = deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &defaultDevice);
deviceEnumerator->Release();
deviceEnumerator = NULL;

IAudioEndpointVolume *endpointVolume = NULL;
hr = defaultDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (LPVOID *)&endpointVolume);
defaultDevice->Release();
defaultDevice = NULL;

if (vUnit == VolumeUnit::Decibel)
hr = endpointVolume->SetMasterVolumeLevel((float)newVolume, NULL);

else if (vUnit == VolumeUnit::Scalar)
hr = endpointVolume->SetMasterVolumeLevelScalar((float)newVolume, NULL);

endpointVolume->Release();

CoUninitialize();
}
}

The C# code:

using System.Runtime.InteropServices;
using UnityEngine;

public class VolumeManager : MonoBehaviour
{
//The Unit to use when getting and setting the volume
public enum VolumeUnit
{
//Perform volume action in decibels</param>
Decibel,
//Perform volume action in scalar
Scalar
}

/// <summary>
/// Gets the current volume
/// </summary>
/// <param name="vUnit">The unit to report the current volume in</param>
[DllImport("ChangeVolumeWindows")]
public static extern float GetSystemVolume(VolumeUnit vUnit);
/// <summary>
/// sets the current volume
/// </summary>
/// <param name="newVolume">The new volume to set</param>
/// <param name="vUnit">The unit to set the current volume in</param>
[DllImport("ChangeVolumeWindows")]
public static extern void SetSystemVolume(double newVolume, VolumeUnit vUnit);

// Use this for initialization
void Start()
{
//Get volume in Decibel
float volumeDecibel = GetSystemVolume(VolumeUnit.Decibel);
Debug.Log("Volume in Decibel: " + volumeDecibel);

//Get volume in Scalar
float volumeScalar = GetSystemVolume(VolumeUnit.Scalar);
Debug.Log("Volume in Scalar: " + volumeScalar);

//Set volume in Decibel
SetSystemVolume(-16f, VolumeUnit.Decibel);

//Set volume in Scalar
SetSystemVolume(0.70f, VolumeUnit.Scalar);
}
}

The GetSystemVolume function is used to get the current volume and SetSystemVolume is used to set it. This question is for Windows but you can do a similar thing with the API for other platforms.

To set it to 70% when A key is pressed:

void Update()
{
if (Input.GetKeyDown(KeyCode.A))
{
//Set Windows Volume 70%
SetSystemVolume(0.70f, VolumeUnit.Scalar);
}
}

How to programmatically set the system volume?

I'm a bit late to the party but if you are looking now there's a nuget package available (AudioSwitcher.AudioApi.CoreAudio) that simplifies audio interactions. Install it then it’s as simple as:

CoreAudioDevice defaultPlaybackDevice = new CoreAudioController().DefaultPlaybackDevice;
Debug.WriteLine("Current Volume:" + defaultPlaybackDevice.Volume);
defaultPlaybackDevice.Volume = 80;

How to change the System Volume programmatically

You're getting an error because this.Handle isn't defined in a plain vanilla class like that VolumeChange class you have there.
It comes from a system.windows.forms form class.

It needs to, because the SendMessageW method requires a window handle

Since you didn't define it in your new class, you can't use it.

Try passing a valid window handle in the constructor for VolumeChange, and using that to call SendMessageW

public class VolumeChange
{
private const int APPCOMMAND_VOLUME_MUTE = 0x80000;
private const int APPCOMMAND_VOLUME_UP = 0xA0000;
private const int APPCOMMAND_VOLUME_DOWN = 0x90000;
private const int WM_APPCOMMAND = 0x319;

private IntPtr windowHandle;


public VolumeChange(IntPtr hwnd)
{
windowHandle = hwnd;
}

[DllImport("user32.dll")]
public static extern IntPtr SendMessageW(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
private void btnMute_Click(object sender, EventArgs e)
{
SendMessageW(windowHandle, WM_APPCOMMAND, windowHandle,(IntPtr)APPCOMMAND_VOLUME_MUTE);
}

private void btnDecVol_Click(object sender, EventArgs e)
{
SendMessageW(windowHandle, WM_APPCOMMAND, windowHandle,(IntPtr)APPCOMMAND_VOLUME_DOWN);
}

private void btnIncVol_Click(object sender, EventArgs e)
{
SendMessageW(windowHandle, WM_APPCOMMAND,windowHandle,(IntPtr)APPCOMMAND_VOLUME_UP);
}
}

If passing a window handle in the contructor isn't an option, (if you want to make VolumeChange static for instance)

Take a look at GetActiveWindow (MSDN)

Windows change system volume programmatically with Java or CMD

Take a look at a form post on oracles website https://forums.oracle.com/thread/2390172 you can see it is not possible from inside java using native libraries.

Quote from the oracle post: "Because Java is cross-platform, it cannot do platform-specific stuff like changing the volume or whatever you want to do to control the OS. You need to use the operating system's unique API layer to do it."

For command line I found this utility that seems to have what you are looking for http://www.nirsoft.net/utils/nircmd.html

If you don't want to rely on 3rd party executables you could either make your own exe or make a dll and look into using JNI.

Set System Volume Windows 10 in C#

class VolumeChanger
{
private const byte VK_VOLUME_MUTE = 0xAD;
private const byte VK_VOLUME_DOWN = 0xAE;
private const byte VK_VOLUME_UP = 0xAF;
private const UInt32 KEYEVENTF_EXTENDEDKEY = 0x0001;
private const UInt32 KEYEVENTF_KEYUP = 0x0002;

[DllImport("user32.dll")]
static extern void keybd_event(byte bVk, byte bScan, UInt32 dwFlags, UInt32 dwExtraInfo);

[DllImport("user32.dll")]
static extern Byte MapVirtualKey(UInt32 uCode, UInt32 uMapType);

public static void VolumeUp()
{
keybd_event(VK_VOLUME_UP, MapVirtualKey(VK_VOLUME_UP, 0), KEYEVENTF_EXTENDEDKEY, 0);
keybd_event(VK_VOLUME_UP, MapVirtualKey(VK_VOLUME_UP, 0), KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
}

public static void VolumeDown()
{
keybd_event(VK_VOLUME_DOWN, MapVirtualKey(VK_VOLUME_DOWN, 0), KEYEVENTF_EXTENDEDKEY, 0);
keybd_event(VK_VOLUME_DOWN, MapVirtualKey(VK_VOLUME_DOWN, 0), KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
}

public static void Mute()
{
keybd_event(VK_VOLUME_MUTE, MapVirtualKey(VK_VOLUME_MUTE, 0), KEYEVENTF_EXTENDEDKEY, 0);
keybd_event(VK_VOLUME_MUTE, MapVirtualKey(VK_VOLUME_MUTE, 0), KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
}
}

Using this, you can mute, and increase or decrease Systemvolume by 2 degree.

I still searching a way to get the current Systemvolume.



Related Topics



Leave a reply



Submit