Get Master Sound Volume in c#
You can get at these values using IAudioMeterInformation in the CoreAudio APIs in Vista and Win 7.
Managed wrappers are available in NAudio (get at the AudioMeterInformation from the MMDevice).
C# get master volume level/precent
I could not do it for all Windows versions (xp, vista & 7).
Though, I achieved it by used external programs, such as NirCmd, and sent the command I needed.
not so good solution but it did solve my problem.
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);
}
}
Change master audio volume from XP to Windows 8 in C#
So my solutions is to combine 2 projects:
Mute/unmute, Change master volume in Windows 7 x64 with C#
http://www.geekpedia.com/tutorial176_Get-and-set-the-wave-sound-volume.html
The final code should be like (It uses NAudio framework)
static class NativeMethods
{
[DllImport("winmm.dll", EntryPoint = "waveOutSetVolume")]
public static extern int WaveOutSetVolume(IntPtr hwo, uint dwVolume);
[DllImport("winmm.dll", SetLastError = true)]
public static extern bool PlaySound(string pszSound, IntPtr hmod, uint fdwSound);
}
public static class MSWindowsFriendlyNames
{
public static string WindowsXP { get { return "Windows XP"; } }
public static string WindowsVista { get { return "Windows Vista"; } }
public static string Windows7 { get { return "Windows 7"; } }
public static string Windows8 { get { return "Windows 8"; } }
}
public static class SistemVolumChanger
{
public static void SetVolume(int value)
{
if (value < 0)
value = 0;
if (value > 100)
value = 100;
var osFriendlyName = GetOSFriendlyName();
if (osFriendlyName.Contains(MSWindowsFriendlyNames.WindowsXP))
{
SetVolumeForWIndowsXP(value);
}
else if (osFriendlyName.Contains(MSWindowsFriendlyNames.WindowsVista) || osFriendlyName.Contains(MSWindowsFriendlyNames.Windows7) || osFriendlyName.Contains(MSWindowsFriendlyNames.Windows8))
{
SetVolumeForWIndowsVista78(value);
}
else
{
SetVolumeForWIndowsVista78(value);
}
}
public static int GetVolume()
{
int result = 100;
try
{
MMDeviceEnumerator DevEnum = new MMDeviceEnumerator();
MMDevice device = DevEnum.GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eMultimedia);
result = (int)(device.AudioEndpointVolume.MasterVolumeLevelScalar * 100);
}
catch (Exception)
{
}
return result;
}
private static void SetVolumeForWIndowsVista78(int value)
{
try
{
MMDeviceEnumerator DevEnum = new MMDeviceEnumerator();
MMDevice device = DevEnum.GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eMultimedia);
device.AudioEndpointVolume.MasterVolumeLevelScalar = (float)value / 100.0f;
}
catch (Exception)
{
}
}
private static void SetVolumeForWIndowsXP(int value)
{
try
{
// Calculate the volume that's being set
double newVolume = ushort.MaxValue * value / 10.0;
uint v = ((uint)newVolume) & 0xffff;
uint vAll = v | (v << 16);
// Set the volume
int retVal = NativeMethods.WaveOutSetVolume(IntPtr.Zero, vAll);
}
catch (Exception)
{
}
}
private static string GetOSFriendlyName()
{
string result = string.Empty;
ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT Caption FROM Win32_OperatingSystem");
foreach (ManagementObject os in searcher.Get())
{
result = os["Caption"].ToString();
break;
}
return result;
}
}
Update #1. Year 2015
Basically it uses NAudio framework. So nowdays some methods and properties of NAudio have other names.
For instance
eDataFlow.eRender is now DataFlow.Render
and
eRole.eMultimedia is Role.Multimedia
getting Master audio volume
No, current API does not allow you to do it.
Related Topics
Questions About Entity Framework Context Lifetime
Server.Mappath - Physical Path Given, Virtual Path Expected
Regex to Match All Us Phone Number Formats
Equivalent of Tuple (.Net 4) for .Net Framework 3.5
Linq to Objects - Return Pairs of Numbers from List of Numbers
Is Using an an 'Async' Lambda with 'Task.Run()' Redundant
How to Hide Public Methods from Intellisense
Return All Enumerables with Yield Return at Once; Without Looping Through
Multicast Delegate of Type Func (With Return Value)
C# MACro Definitions in Preprocessor
Piping in a File on the Command-Line Using System.Diagnostics.Process
"Nested Foreach" VS "Lambda/Linq Query" Performance(Linq-To-Objects)
Directoryinfo.Enumeratefiles(...) Causes Unauthorizedaccessexception (And Other Exceptions)
How to Disable the Horizontal Scrollbar in a Panel
Is There an Entity Framework 7 Database-First Poco Generator
How to Implement One "Catch'Em All" Exception Handler with Resume
Formatting Literal Parameters of a C# Code Snippet
Excluding Some Properties During Serialization Without Changing the Original Class