Search code examples
c#.netvb.netwinapicore-audio

How to check if the system audio is muted?


I found this answer which recommends using the "core audio.dll" API with the following code:

private function getmute() as boolean
    Dim devenum As New MMDeviceEnumerator
    Dim device As MMDevice = devenum.GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eMultimedia)
    If device.AudioEndpointVolume.Mute = True Then
        Return True
    Else
        Return False
    End If
End Function

I tried that code but it doesn't work and I could not leave a comment on the other question.

When I try the above code, the following line throws an exception:

If device.AudioEndpointVolume.Mute = True Then

Here's the exception message:

AudioEndpointVolume is not a member of device.

I have already imported CoreAudioAPI, what else could be wrong?

I'm looking for a VB.NET or a C# solution.


Solution

  • VB.Net rewriting (+ Bonus) of the CoreAudio API implementation γηράσκω δ' αεί πολλά διδασκόμε posted.

    The code in wrapped in a Class (AudioDevice) and includes the original IsMuted() method, plus other methods I implemented on the fly (because, why not).

    More information on the Windows CoreAudio APIs on MSDN.
    GitHub NAudio CoreAudioApi implementation (C#).

    Methods implemented:

    IsMuted() As Integer
    Return the Muted status of the default Audio Device.

    SetMute(Boolean)
    Sets the Muted status of the default Audio Device (True/False)

    IsMediadPlaying() The default Audio Device is currently playing or not

    GetVolume() As Integer
    Get the Volume status of the default Audio Device. Values range from 0 to 100

    SetVolume(Integer)
    Set the Volume status of the default Audio Device to a values in the 0 to 100 range

    VolumeUp()
    Increases the Volume of the default Audio Device by one step (usually 2 units)

    VolumeDown()
    Decreases the Volume of the default Audio Device by one step.

    Usage:

     Dim isMuted As Boolean = AudioDevice.IsMuted()
    
     ' True=Mutes the Audio, False=Un-Mutes (?) it
     AudioDevice.SetMute(True)
    
     ' Checks whether the Media Device currently playing
     Dim isPlaying As Boolean = AudioDevice.IsMediadPlaying()
    
     Dim volume As Integer = AudioDevice.GetVolume()
    
     ' Sets the Audio level to 50%, returns the previous value
     Dim previousVolume As Integer = AudioDevice.SetVolume(50)
    
     ' Increases the Audio level by 1 Step
     AudioDevice.VolumeUp()
    
     ' Decreases the Audio level by 1 Step
     AudioDevice.VolumeDown()
    

    Declarations:

    Imports System
    Imports System.Runtime.InteropServices
    
    Public Class AudioDevice
        Friend Enum EDataFlow
            eRender
            eCapture
            eAll
            EDataFlow_enum_count
        End Enum
    
        Friend Enum ERole
            eConsole
            eMultimedia
            eCommunications
            ERole_enum_count
        End Enum
    
        <Flags>
        Public Enum CLSCTX As UInteger
            CLSCTX_INPROC_SERVER = &H1
            CLSCTX_INPROC_HANDLER = &H2
            CLSCTX_LOCAL_SERVER = &H4
            CLSCTX_INPROC_SERVER16 = &H8
            CLSCTX_REMOTE_SERVER = &H10
            CLSCTX_INPROC_HANDLER16 = &H20
            CLSCTX_RESERVED1 = &H40
            CLSCTX_RESERVED2 = &H80
            CLSCTX_RESERVED3 = &H100
            CLSCTX_RESERVED4 = &H200
            CLSCTX_NO_CODE_DOWNLOAD = &H400
            CLSCTX_RESERVED5 = &H800
            CLSCTX_NO_CUSTOM_MARSHAL = &H1000
            CLSCTX_ENABLE_CODE_DOWNLOAD = &H2000
            CLSCTX_NO_FAILURE_LOG = &H4000
            CLSCTX_DISABLE_AAA = &H8000
            CLSCTX_ENABLE_AAA = &H10000
            CLSCTX_FROM_DEFAULT_CONTEXT = &H20000
            CLSCTX_ACTIVATE_32_BIT_SERVER = &H40000
            CLSCTX_ACTIVATE_64_BIT_SERVER = &H80000
            CLSCTX_INPROC = CLSCTX_INPROC_SERVER Or CLSCTX_INPROC_HANDLER
            CLSCTX_SERVER = CLSCTX_INPROC_SERVER Or CLSCTX_LOCAL_SERVER Or CLSCTX_REMOTE_SERVER
            CLSCTX_ALL = CLSCTX_SERVER Or CLSCTX_INPROC_HANDLER
        End Enum
    
        <ComImport, Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")>
        Public Class MMDeviceEnumeratorComObject
        End Class
    
        <ComImport, Guid("A95664D2-9614-4F35-A746-DE8DB63617E6"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
        Friend Interface IMMDeviceEnumerator
            Function NotImpl1() As Integer
            Function GetDefaultAudioEndpoint(
                  dataFlow As EDataFlow,
                  role As ERole,
                  <Out> ByRef ppDevice As IMMDevice) As Integer
        End Interface
    
        <ComImport, Guid("D666063F-1587-4E43-81F1-B948E807363F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
        Public Interface IMMDevice
            Function Activate(<MarshalAs(UnmanagedType.LPStruct)> iid As Guid,
                              dwClsCtx As CLSCTX, pActivationParams As IntPtr) As <MarshalAs(UnmanagedType.IUnknown)> Object
        End Interface
    
        <ComImport, Guid("5CDF2C82-841E-4546-9722-0CF74078229A"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
        Public Interface IAudioEndpointVolume
            Function RegisterControlChangeNotify(pNotify As IAudioEndpointVolumeCallback) As Integer
            Function UnregisterControlChangeNotify(pNotify As IAudioEndpointVolumeCallback) As Integer
            Function GetChannelCount(ByRef channelCount As Integer) As Integer
            Function SetMasterVolumeLevel() As Integer
            Function SetMasterVolumeLevelScalar(level As Single, eventContext As Guid) As Integer
            Function GetMasterVolumeLevel(<Out> ByRef level As Single) As Integer
            Function GetMasterVolumeLevelScalar(<Out> ByRef level As Single) As Integer
            Function SetChannelVolumeLevel(channelNumber As Integer, level As Single, eventContext As Guid) As Integer
            Function SetChannelVolumeLevelScalar(channelNumber As Integer, level As Single, eventContext As Guid) As Integer
            Function GetChannelVolumeLevel(channelNumber As Integer, <Out> ByRef level As Single) As Integer
            Function GetChannelVolumeLevelScalar(channelNumber As Integer, <Out> ByRef level As Single) As Integer
            Function SetMute(<MarshalAs(UnmanagedType.Bool)> isMuted As Boolean, eventContext As Guid) As Integer
            Function GetMute(<Out> ByRef isMuted As Boolean) As Integer
            Function GetVolumeStepInfo(<Out> ByRef pnStep As Integer, ByRef pnStepCount As Integer) As Integer
            Function VolumeStepUp(eventContext As Guid) As Integer
            Function VolumeStepDown(eventContext As Guid) As Integer
            Function QueryHardwareSupport(<Out> ByRef hardwareSupportMask As Integer) As Integer
            Function GetVolumeRange(<Out> ByRef volumeMin As Single, <Out> ByRef volumeMax As Single, <Out> ByRef volumeStep As Single) As Integer
        End Interface
    
        <ComImport, Guid("657804FA-D6AD-4496-8A60-352752AF4F89"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
        Public Interface IAudioEndpointVolumeCallback
            <PreserveSig()>
            Function OnNotify(pNotifyData As IntPtr) As Integer  ' HRESULT
        End Interface
    
        <InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("C02216F6-8C67-4B5B-9D00-D008E73E0064")>
        Public Interface IAudioMeterInformation
            Function GetPeakValue() As Single
        End Interface
    
        Public Shared Function IsMuted() As Boolean
            Dim masterVol As IAudioEndpointVolume = GetMasterVolumeObject()
            Try
                If masterVol Is Nothing Then
                    Throw New ApplicationException("Master Volume not available")
                End If
    
                Dim isAudioMuted As Boolean
                masterVol.GetMute(isAudioMuted)
                Return isAudioMuted
            Finally
                If masterVol IsNot Nothing Then
                    If masterVol IsNot Nothing Then Marshal.ReleaseComObject(masterVol)
                End If
            End Try
        End Function
    
        Public Shared Sub SetMute(IsMute As Boolean)
            Dim masterVol As IAudioEndpointVolume = GetMasterVolumeObject()
            Try
                masterVol.SetMute(IsMute, Guid.Empty)
            Finally
                If masterVol IsNot Nothing Then
                    If masterVol IsNot Nothing Then Marshal.ReleaseComObject(masterVol)
                End If
            End Try
        End Sub
    
        Public Shared Function IsMediadPlaying() As Boolean
            Dim mediaDevice As IMMDevice = Nothing
            Try
                mediaDevice = GetDefaultAudioEndpoint()
                Dim meter = mediaDevice.Activate(GetType(IAudioMeterInformation).GUID, CLSCTX.CLSCTX_ALL, IntPtr.Zero)
                Dim value As Single = DirectCast(meter, IAudioMeterInformation).GetPeakValue()
                Return Not (value <= 0.0F)
            Finally
                If mediaDevice IsNot Nothing Then Marshal.ReleaseComObject(mediaDevice)
            End Try
        End Function
    
        Public Shared Function GetVolume() As Integer
            Dim fVolume As Single
            Dim masterVol As IAudioEndpointVolume = GetMasterVolumeObject()
            Try
                masterVol.GetMasterVolumeLevelScalar(fVolume)
                Return CType(fVolume * 100, Integer)
            Finally
                If masterVol IsNot Nothing Then Marshal.ReleaseComObject(masterVol)
            End Try
        End Function
    
        Public Shared Function SetVolume(volume As Integer) As Integer
            volume = Math.Max(Math.Min(volume, 100), 0)
            Dim masterVolume As IAudioEndpointVolume = GetMasterVolumeObject()
            Try
                Dim prevVolume = GetVolume()
                masterVolume.SetMasterVolumeLevelScalar(volume / 100.0F, Guid.Empty)
                Return prevVolume
            Finally
                If masterVolume IsNot Nothing Then Marshal.ReleaseComObject(masterVolume)
            End Try
        End Function
    
        Public Shared Sub VolumeUp()
            Dim masterVol As IAudioEndpointVolume = GetMasterVolumeObject()
            Try
                masterVol.VolumeStepUp(Guid.Empty)
            Finally
                If masterVol IsNot Nothing Then Marshal.ReleaseComObject(masterVol)
            End Try
        End Sub
    
        Public Shared Sub VolumeDown()
            Dim masterVol As IAudioEndpointVolume = GetMasterVolumeObject()
            Try
                masterVol.VolumeStepDown(Guid.Empty)
            Finally
                If masterVol IsNot Nothing Then Marshal.ReleaseComObject(masterVol)
            End Try
        End Sub
    
        Friend Shared Function GetMasterVolumeObject() As IAudioEndpointVolume
            Dim mediaDevice As IMMDevice = GetDefaultAudioEndpoint()
            Try
                Dim ppEndpoint = mediaDevice.Activate(GetType(IAudioEndpointVolume).GUID, CLSCTX.CLSCTX_ALL, IntPtr.Zero)
                Return DirectCast(ppEndpoint, IAudioEndpointVolume)
            Finally
                If mediaDevice IsNot Nothing Then Marshal.ReleaseComObject(mediaDevice)
            End Try
        End Function
    
        Public Shared Function GetDefaultAudioEndpoint() As IMMDevice
            Dim mediaDevice As IMMDevice = Nothing
            Dim deviceEnumerator = DirectCast(New MMDeviceEnumeratorComObject(), IMMDeviceEnumerator)
            Try
                deviceEnumerator.GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eMultimedia, mediaDevice)
                Return mediaDevice
            Finally
                If deviceEnumerator IsNot Nothing Then Marshal.ReleaseComObject(deviceEnumerator)
            End Try
        End Function
    End Class