Detect Audio on Windows 10

Micah Holmes 126 Reputation points
2021-01-28T19:37:11.867+00:00

I'm using Unity but I want to perform a sound check of the users windows audio to ensure they have enabled their windows audio. How do I detect if they muted their speakers or if a speaker is even present?

I found this code but it appears to give errors and not work:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Runtime.InteropServices;
using System;

public class WBGAudioTest : MonoBehaviour
{
    #region Windows
    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;

    [DllImport("user32.dll")]
    public static extern IntPtr SendMessageW(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
    //public static extern IntPtr SendMessageW(IntPtr hWnd, int Msg,IntPtr wParam, IntPtr lParam);
    #endregion

    public Text txtAudioTestMessage;
    public Button btnYes;
    public Button btnNo;   

    void Start()
    {

    }

    private void Mute(object sender, EventArgs e)
    {
        SendMessageW(this, WM_APPCOMMAND, this(IntPtr)APPCOMMAND_VOLUME_MUTE);
    }

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

    private void Volume_Up(object sender, EventArgs e)
    {
        SendMessageW(this, WM_APPCOMMAND, this, (IntPtr)APPCOMMAND_VOLUME_UP);
    }
}
Developer technologies | C#
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. Castorix31 90,686 Reputation points
    2021-01-28T20:10:38.73+00:00

    With Core Audio APIs

    Test =>

    HRESULT hr = HRESULT.E_FAIL;
    Guid CLSID_MMDeviceEnumerator = new Guid("{BCDE0395-E52F-467C-8E3D-C4579291692E}");
    Type MMDeviceEnumeratorType = Type.GetTypeFromCLSID(CLSID_MMDeviceEnumerator, true);
    object MMDeviceEnumerator = Activator.CreateInstance(MMDeviceEnumeratorType);
    IMMDeviceEnumerator pMMDeviceEnumerator = (IMMDeviceEnumerator)MMDeviceEnumerator;
    if (pMMDeviceEnumerator != null)
    {
        IMMDevice pDevice = null;
        hr = pMMDeviceEnumerator.GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eConsole, out pDevice);
        if (hr == HRESULT.S_OK)
        {
            IntPtr pAudioEndpointVolumePtr = IntPtr.Zero;
            PROPVARIANT pvActivate = new PROPVARIANT();
            hr = pDevice.Activate(typeof(IAudioEndpointVolume).GUID, 0, ref pvActivate, out pAudioEndpointVolumePtr);
            if (hr == HRESULT.S_OK)
            {
                string sFriendlyName = null;
                string sDesc = null;
                IPropertyStore pPropertyStore = null;
                hr = pDevice.OpenPropertyStore(STGM_READ, out pPropertyStore);
                if (hr == HRESULT.S_OK)
                { 
                    PROPVARIANT pv = new PROPVARIANT();
                    hr = pPropertyStore.GetValue(ref PKEY_Device_FriendlyName, out pv);
                    if (hr == HRESULT.S_OK)
                    {
                        sFriendlyName = Marshal.PtrToStringUni(pv.pwszVal);
                    }
                    hr = pPropertyStore.GetValue(ref PKEY_Device_DeviceDesc, out pv);
                    if (hr == HRESULT.S_OK)
                    {
                        sDesc = Marshal.PtrToStringUni(pv.pwszVal);
                    }
                }                            
    
                IAudioEndpointVolume pAudioEndpointVolume = Marshal.GetObjectForIUnknown(pAudioEndpointVolumePtr) as IAudioEndpointVolume;
                float nVolume = 0;
                hr = pAudioEndpointVolume.GetMasterVolumeLevelScalar(out nVolume);
                bool bMute = false;
                hr = pAudioEndpointVolume.GetMute(out bMute);
                Marshal.ReleaseComObject(pAudioEndpointVolume);
    
                int nState = 0;
                string sState = "";
                hr = pDevice.GetState(out nState);
                if ((nState == DEVICE_STATE_ACTIVE))
                    sState = "Active";
                else if ((nState == DEVICE_STATE_DISABLED))
                    sState = "Disabled";
                else if ((nState == DEVICE_STATE_NOTPRESENT))
                    sState = "Not present";
                else if ((nState == DEVICE_STATE_UNPLUGGED))
                    sState = "Unplugged";
    
                Console.WriteLine("Device: {0} - {1} - Volume : {2} {3}", sFriendlyName, sState, nVolume.ToString(), bMute?"(Mute)":"");
            }
            Marshal.ReleaseComObject(pDevice);
        }
        Marshal.ReleaseComObject(pMMDeviceEnumerator);
    }
    

    Declarations :

    public static PROPERTYKEY PKEY_Device_FriendlyName = new PROPERTYKEY(new Guid("a45c254e-df1c-4efd-8020-67d146a850e0"), 14);
    public static PROPERTYKEY PKEY_Device_DeviceDesc = new PROPERTYKEY(new Guid("a45c254e-df1c-4efd-8020-67d146a850e0"), 2); 
    
    public enum HRESULT : int
    {
        S_OK = 0,
        S_FALSE = 1,
        E_NOINTERFACE = unchecked((int)0x80004002),
        E_NOTIMPL = unchecked((int)0x80004001),
        E_FAIL = unchecked((int)0x80004005)
    }
    
    [ComImport, Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IPropertyStore
    {
        HRESULT GetCount([Out] out uint propertyCount);
        HRESULT GetAt([In] uint propertyIndex, [Out, MarshalAs(UnmanagedType.Struct)] out PROPERTYKEY key);
        HRESULT GetValue([In, MarshalAs(UnmanagedType.Struct)] ref PROPERTYKEY key, [Out, MarshalAs(UnmanagedType.Struct)] out PROPVARIANT pv);
        HRESULT SetValue([In, MarshalAs(UnmanagedType.Struct)] ref PROPERTYKEY key, [In, MarshalAs(UnmanagedType.Struct)] ref PROPVARIANT pv);
        HRESULT Commit();
    }
    
    public const int STGM_READ        = 0x00000000;
    public const int STGM_WRITE       = 0x00000001;
    public const int STGM_READWRITE   = 0x00000002;
    
    public enum EDataFlow
    {
        eRender = 0,
        eCapture = (eRender + 1),
        eAll = (eCapture + 1),
        EDataFlow_enum_count = (eAll + 1)
    }
    public enum ERole
    {
        eConsole = 0,
        eMultimedia = (eConsole + 1),
        eCommunications = (eMultimedia + 1),
        ERole_enum_count = (eCommunications + 1)
    }
    
    [ComImport]
    [Guid("A95664D2-9614-4F35-A746-DE8DB63617E6")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IMMDeviceEnumerator
    {
        HRESULT EnumAudioEndpoints(EDataFlow dataFlow, int dwStateMask, out IMMDeviceCollection ppDevices);
        HRESULT GetDefaultAudioEndpoint(EDataFlow dataFlow, ERole role, out IMMDevice ppEndpoint);
        HRESULT GetDevice(string pwstrId,out IMMDevice ppDevice);
        HRESULT RegisterEndpointNotificationCallback(IMMNotificationClient pClient);
        HRESULT UnregisterEndpointNotificationCallback(IMMNotificationClient pClient);
    }
    
    public const int DEVICE_STATE_ACTIVE = 0x00000001;
    public const int DEVICE_STATE_DISABLED = 0x00000002;
    public const int DEVICE_STATE_NOTPRESENT = 0x00000004;
    public const int DEVICE_STATE_UNPLUGGED = 0x00000008;
    public const int DEVICE_STATEMASK_ALL = 0x0000000f;
    
    [ComImport]
    [Guid("0BD7A1BE-7A1A-44DB-8397-CC5392387B5E")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IMMDeviceCollection
    {
        HRESULT GetCount(out uint pcDevices);
        HRESULT Item(uint nDevice,  out IMMDevice ppDevice);
    }
    
    [ComImport]
    [Guid("D666063F-1587-4E43-81F1-B948E807363F")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IMMDevice
    {
        [PreserveSig]
        HRESULT Activate(ref Guid iid, int dwClsCtx, ref PROPVARIANT pActivationParams, out IntPtr ppInterface);
        //HRESULT Activate(ref Guid iid, int dwClsCtx, IntPtr pActivationParams, out IntPtr ppInterface);
    
        HRESULT OpenPropertyStore(int stgmAccess, out IPropertyStore ppProperties);
    
        //HRESULT GetId(StringBuilder ppstrId);
        HRESULT GetId(out IntPtr ppstrId);
        HRESULT GetState(out int pdwState);
    }
    
    [ComImport]
    [Guid("7991EEC9-7E89-4D85-8390-6C703CEC60C0")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IMMNotificationClient
    {
        HRESULT OnDeviceStateChanged(string pwstrDeviceId, int dwNewState);
        HRESULT OnDeviceAdded(string pwstrDeviceId);
        HRESULT OnDeviceRemoved(string pwstrDeviceId);
        HRESULT OnDefaultDeviceChanged(EDataFlow flow, ERole role, string pwstrDefaultDeviceId);
        HRESULT OnPropertyValueChanged(string pwstrDeviceId, ref PROPERTYKEY key);
    }
    
    [ComImport]
    [Guid("1BE09788-6894-4089-8586-9A2A6C265AC5")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IMMEndpoint
    {
        HRESULT GetDataFlow(out EDataFlow pDataFlow);
    }
    
    public struct PROPERTYKEY
    {
        public PROPERTYKEY(Guid InputId, UInt32 InputPid)
        {
            fmtid = InputId;
            pid = InputPid;
        }
        Guid fmtid;
        uint pid;
    };
    
    [StructLayout(LayoutKind.Sequential)]
    public struct PROPARRAY
    {
        public UInt32 cElems;
        public IntPtr pElems;
    }
    
    [StructLayout(LayoutKind.Explicit, Pack = 1)]
    public struct PROPVARIANT
    {
        [FieldOffset(0)]
        public ushort varType;
        [FieldOffset(2)]
        public ushort wReserved1;
        [FieldOffset(4)]
        public ushort wReserved2;
        [FieldOffset(6)]
        public ushort wReserved3;
    
        [FieldOffset(8)]
        public byte bVal;
        [FieldOffset(8)]
        public sbyte cVal;
        [FieldOffset(8)]
        public ushort uiVal;
        [FieldOffset(8)]
        public short iVal;
        [FieldOffset(8)]
        public UInt32 uintVal;
        [FieldOffset(8)]
        public Int32 intVal;
        [FieldOffset(8)]
        public UInt64 ulVal;
        [FieldOffset(8)]
        public Int64 lVal;
        [FieldOffset(8)]
        public float fltVal;
        [FieldOffset(8)]
        public double dblVal;
        [FieldOffset(8)]
        public short boolVal;
        [FieldOffset(8)]
        public IntPtr pclsidVal; // GUID ID pointer
        [FieldOffset(8)]
        public IntPtr pszVal; // Ansi string pointer
        [FieldOffset(8)]
        public IntPtr pwszVal; // Unicode string pointer
        [FieldOffset(8)]
        public IntPtr punkVal; // punkVal (interface pointer)
        [FieldOffset(8)]
        public PROPARRAY ca;
        [FieldOffset(8)]
        public System.Runtime.InteropServices.ComTypes.FILETIME filetime;
    }
    
    [ComImport]
    [Guid("5CDF2C82-841E-4546-9722-0CF74078229A")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IAudioEndpointVolume
    {
        HRESULT RegisterControlChangeNotify(IAudioEndpointVolumeCallback pNotify);
        HRESULT UnregisterControlChangeNotify(IAudioEndpointVolumeCallback pNotify);
        HRESULT GetChannelCount(out uint pnChannelCount);
        HRESULT SetMasterVolumeLevel(float fLevelDB, ref Guid pguidEventContext);
        HRESULT SetMasterVolumeLevelScalar(float fLevel, ref Guid pguidEventContext);
        HRESULT GetMasterVolumeLevel(out float pfLevelDB);
        HRESULT GetMasterVolumeLevelScalar(out float pfLevel);
        HRESULT SetChannelVolumeLevel(uint nChannel, float fLevelDB, ref Guid pguidEventContext);
        HRESULT SetChannelVolumeLevelScalar(uint nChannel, float fLevel, ref Guid pguidEventContext);
        HRESULT GetChannelVolumeLevel(uint nChannel, out float pfLevelDB);
        HRESULT GetChannelVolumeLevelScalar(uint nChannel, out float pfLevel);
        HRESULT SetMute(bool bMute, ref Guid pguidEventContext);
        HRESULT GetMute(out bool pbMute);
        HRESULT GetVolumeStepInfo(out uint pnStep,out uint pnStepCount);
        HRESULT VolumeStepUp(ref Guid pguidEventContext);
        HRESULT VolumeStepDown(ref Guid pguidEventContext);
        HRESULT QueryHardwareSupport(out int pdwHardwareSupportMask);
        HRESULT GetVolumeRange(out float pflVolumeMindB, out float pflVolumeMaxdB, out float pflVolumeIncrementdB);
    }
    
    [ComImport]
    [Guid("657804FA-D6AD-4496-8A60-352752AF4F89")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IAudioEndpointVolumeCallback
    {
        HRESULT OnNotify(IntPtr pNotify);          
    }
    
    
    [ComImport]
    [Guid("f8679f50-850a-41cf-9c72-430f290290c8")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IPolicyConfig
    {
        HRESULT GetMixFormat([In] [MarshalAs(UnmanagedType.LPWStr)] string pszDeviceName, out WAVEFORMATEXTENSIBLE ppFormat);
        HRESULT GetDeviceFormat([In] [MarshalAs(UnmanagedType.LPWStr)] string pszDeviceName, [In] [MarshalAs(UnmanagedType.Bool)] bool bDefault, out WAVEFORMATEXTENSIBLE ppFormat);
        HRESULT ResetDeviceFormat([In] [MarshalAs(UnmanagedType.LPWStr)] string pszDeviceName);
        HRESULT SetDeviceFormat([In] [MarshalAs(UnmanagedType.LPWStr)] string pszDeviceName, [In] [MarshalAs(UnmanagedType.LPStruct)] WAVEFORMATEXTENSIBLE pEndpointFormat, [In] [MarshalAs(UnmanagedType.LPStruct)] WAVEFORMATEXTENSIBLE pMixFormat);
        HRESULT GetProcessingPeriod([In] [MarshalAs(UnmanagedType.LPWStr)] string pszDeviceName, [In] [MarshalAs(UnmanagedType.Bool)] bool bDefault, out Int64 pmftDefaultPeriod, out Int64 pmftMinimumPeriod);
        HRESULT SetProcessingPeriod([In] [MarshalAs(UnmanagedType.LPWStr)] string pszDeviceName, Int64 pmftPeriod);
        HRESULT GetShareMode([In] [MarshalAs(UnmanagedType.LPWStr)] string pszDeviceName, [Out] out DeviceShareMode pMode);
        HRESULT SetShareMode([In] [MarshalAs(UnmanagedType.LPWStr)] string pszDeviceName, [In] DeviceShareMode mode);
        HRESULT GetPropertyValue([In] [MarshalAs(UnmanagedType.LPWStr)] string pszDeviceName, [In] [MarshalAs(UnmanagedType.Bool)] bool bFxStore, ref PROPERTYKEY pKey, out PROPVARIANT pv);
        HRESULT SetPropertyValue([In] [MarshalAs(UnmanagedType.LPWStr)] string pszDeviceName, [In] [MarshalAs(UnmanagedType.Bool)] bool bFxStore, [In] ref PROPERTYKEY pKey, ref PROPVARIANT pv);
        HRESULT SetDefaultEndpoint([In] [MarshalAs(UnmanagedType.LPWStr)] string pszDeviceName, [In] [MarshalAs(UnmanagedType.U4)] ERole role);
        HRESULT SetEndpointVisibility([In] [MarshalAs(UnmanagedType.LPWStr)] string pszDeviceName, [In] [MarshalAs(UnmanagedType.Bool)] bool bVisible);
    }
    
    [StructLayout(LayoutKind.Explicit, Pack = 1)]
    public class WAVEFORMATEXTENSIBLE : WAVEFORMATEX
    {
        [FieldOffset(0)]
        public short wValidBitsPerSample;
        [FieldOffset(0)]
        public short wSamplesPerBlock;
        [FieldOffset(0)]
        public short wReserved;
        [FieldOffset(2)]
        public WaveMask dwChannelMask;
        [FieldOffset(6)]
        public Guid SubFormat;
    }
    
    [Flags]
    public enum WaveMask
    {
        None = 0x0,
        FrontLeft = 0x1,
        FrontRight = 0x2,
        FrontCenter = 0x4,
        LowFrequency = 0x8,
        BackLeft = 0x10,
        BackRight = 0x20,
        FrontLeftOfCenter = 0x40,
        FrontRightOfCenter = 0x80,
        BackCenter = 0x100,
        SideLeft = 0x200,
        SideRight = 0x400,
        TopCenter = 0x800,
        TopFrontLeft = 0x1000,
        TopFrontCenter = 0x2000,
        TopFrontRight = 0x4000,
        TopBackLeft = 0x8000,
        TopBackCenter = 0x10000,
        TopBackRight = 0x20000
    }
    
    [StructLayout(LayoutKind.Sequential, Pack = 2)]
    public class WAVEFORMATEX
    {
        public short wFormatTag;
        public short nChannels;
        public int nSamplesPerSec;
        public int nAvgBytesPerSec;
        public short nBlockAlign;
        public short wBitsPerSample;
        public short cbSize;
    }
    
    public enum DeviceShareMode
    {
        Shared,
        Exclusive
    }
    

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.