Share via


Change audio input

Question

Thursday, December 21, 2017 10:02 PM | 1 vote

There is some way to change the audio input of my sistem ??

I lista the audio with :

Function GetAudioCardList() As List(Of String)
        'Add a reference to System.Management dll
        'Return audio list
        Dim Questions As New List(Of String)()
        Dim objSearcher As New ManagementObjectSearcher("SELECT * FROM Win32_SoundDevice")
        Dim objCollection As ManagementObjectCollection = objSearcher.Get()

        For Each obj As ManagementObject In objCollection
            Questions.Add(obj.GetPropertyValue("Caption").ToString())
        Next

        Return Questions
    End Function

A want to change with my code.

All replies (10)

Tuesday, January 9, 2018 9:49 PM âś…Answered | 1 vote

Ran-jj,  If your question has been answered,  then please do not forget to mark the post or posts that have answered your question as the answer(s).  Thanks.  8)

Also,  here is a slightly upgraded version of my prior example.  The first example i posted would only set the selected device as the (default device).  This new example allows you to set the selected device as the (default communications device) and/or the (default device).

 This is the updated AudioEndPoints class code.  I explained in the last example how to add the class to your project.

Imports System.Runtime.InteropServices

Public Class AudioEndPoints
    ''' <summary>Sets the specified device as the default device and/or the default communications device.</summary>
    ''' <param name="devId">The string Id for the input or output device to set.</param>
    ''' <param name="SetAsDefaultDevice">Set to True to set this device as the default device.</param>
    ''' <param name="SetAsDefaultCommunicationDevice">Set to True to set this device as the default communications device.</param>
    Public Shared Sub SetDefaultEndPoint(devId As String, SetAsDefaultDevice As Boolean, SetAsDefaultCommunicationDevice As Boolean)
        Dim IPCV As IPolicyConfigVista = Nothing
        Dim oIPCV As Object = Nothing
        Try
            Dim IID_IPolicyConfigVista As Guid = New Guid("568b9108-44bf-40b4-9006-86afe5b5a620")
            Dim CLSID_CPolicyConfigVistaClient As Guid = New Guid("294935CE-F637-4E7C-A41B-AB255460B862")
            If CoCreateInstance(CLSID_CPolicyConfigVistaClient, Nothing, CLSCTX.CLSCTX_INPROC_SERVER, IID_IPolicyConfigVista, oIPCV) <> 0 Then
                Throw New Exception("Failed:  CoCreateInstance")
            Else
                IPCV = CType(oIPCV, IPolicyConfigVista)
                If IPCV Is Nothing Then Throw New Exception("Failed: COM cast to IPolicyConfigVista")
            End If
            If SetAsDefaultDevice Then
                IPCV.SetDefaultEndpoint(devId, ERole.eConsole)
            End If
            If SetAsDefaultCommunicationDevice Then
                IPCV.SetDefaultEndpoint(devId, ERole.eCommunications)
            End If
        Finally
            If (IPCV IsNot Nothing) Then
                While Marshal.ReleaseComObject(IPCV) > 0
                End While
                IPCV = Nothing
            End If
            If (oIPCV IsNot Nothing) Then
                While Marshal.ReleaseComObject(oIPCV) > 0
                End While
                oIPCV = Nothing
            End If
        End Try
    End Sub

    ''' <summary>Returns an array of EndPointDeviceInfo classes which contain the information for each device found for the specified types.</summary>
    ''' <param name="DevType">Can be (eRender) to get only output devices, (eCapture) to get only the input devices, or (eAll) to get all input and output devices.</param>
    Public Shared Function GetEndPointNames(ByVal DevType As EDataFlow) As EndPointDeviceInfo()
        Dim immdevcolptr As IntPtr = IntPtr.Zero
        Dim devcnt As UInteger = 0
        Dim immdevcol As IMMDeviceCollection = Nothing
        Dim dvInfo As New List(Of EndPointDeviceInfo)
        Dim IMMDE As IMMDeviceEnumerator = Nothing
        Dim oIMMDE As Object = Nothing
        Try
            Dim IID_IUnknown As Guid = New Guid("00000000-0000-0000-C000-000000000046")
            Dim IMMDE_clsid As Guid = New Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")
            If CoCreateInstance(IMMDE_clsid, Nothing, CLSCTX.CLSCTX_INPROC_SERVER, IID_IUnknown, oIMMDE) <> 0 Then
                Throw New Exception("Failed:  CoCreateInstance")
            Else
                IMMDE = CType(oIMMDE, IMMDeviceEnumerator)
                If IMMDE Is Nothing Then Throw New Exception("Failed: COM cast to IMMDeviceEnumerator")
            End If

            Dim res As Integer = IMMDE.EnumAudioEndpoints(DevType, IMMDeviceStatesFlags.DEVICE_STATE_ACTIVE, immdevcolptr)
            If res <> 0 Then
                Throw New Exception("EnumAudioEndpoints Failed with error: 0x" & res.ToString("X"))
            End If

            immdevcol = CType(Marshal.GetObjectForIUnknown(immdevcolptr), IMMDeviceCollection)

            res = immdevcol.GetCount(devcnt)
            If res <> 0 Then
                Throw New Exception("GetCount Failed with error: 0x" & res.ToString("X"))
            End If

            If devcnt > 0 Then
                For i As UInteger = 0 To devcnt - 1UI
                    Dim immdevptr As IntPtr = IntPtr.Zero
                    res = immdevcol.Item(i, immdevptr)
                    If res = 0 Then
                        Dim immdev As IMMDevice = CType(Marshal.GetObjectForIUnknown(immdevptr), IMMDevice)
                        If immdev IsNot Nothing Then
                            Dim propstrptr As IntPtr = IntPtr.Zero
                            res = immdev.OpenPropertyStore(STGM_READ, propstrptr)
                            If res = 0 Then
                                Dim propstor As IPropertyStore = CType(Marshal.GetObjectForIUnknown(propstrptr), IPropertyStore)
                                If propstor IsNot Nothing Then
                                    Dim FriendlyName As String = ""
                                    Using varnt As New PropVariant
                                        propstor.GetValue(Device_FriendlyName, varnt)
                                        FriendlyName = varnt.Value
                                    End Using

                                    Dim Description As String = ""
                                    Using vrnt As New PropVariant
                                        propstor.GetValue(Device_DeviceDesc, vrnt)
                                        Description = vrnt.Value
                                    End Using

                                    Dim idString As String = ""
                                    immdev.GetId(idString)

                                    dvInfo.Add(New EndPointDeviceInfo(FriendlyName, idString, Description))

                                    Marshal.ReleaseComObject(propstor)
                                    propstor = Nothing
                                End If
                            End If
                            Marshal.ReleaseComObject(immdev)
                            immdev = Nothing
                        End If
                    End If
                Next
            End If
        Finally
            If immdevcol IsNot Nothing Then
                Marshal.ReleaseComObject(immdevcol)
                immdevcol = Nothing
            End If
            If (IMMDE IsNot Nothing) Then
                While Marshal.ReleaseComObject(IMMDE) > 0
                End While
                IMMDE = Nothing
            End If
            If (oIMMDE IsNot Nothing) Then
                While Marshal.ReleaseComObject(oIMMDE) > 0
                End While
                oIMMDE = Nothing
            End If
        End Try
        Return dvInfo.ToArray
    End Function


    Private Shared SPDRP_Guid As New Guid(&HA45C254EUI, &HDF1C, &H4EFD, &H80, &H20, &H67, &HD1, &H46, &HA8, &H50, &HE0)
    Private Shared ReadOnly Property Device_Manufacturer As PropertyKey
        Get
            Return New PropertyKey(SPDRP_Guid, 13)
        End Get
    End Property
    Private Shared ReadOnly Property Device_DeviceDesc As PropertyKey
        Get
            Return New PropertyKey(SPDRP_Guid, 2)
        End Get
    End Property
    Private Shared ReadOnly Property Device_FriendlyName As PropertyKey
        Get
            Return New PropertyKey(SPDRP_Guid, 14)
        End Get
    End Property

    Private Const STGM_READ As Integer = &H0 'used for the (stgmAccess) parameter of the (OpenPropertyStore) function in the (IMMDevice) interface.

    <ComImport(), Guid("0BD7A1BE-7A1A-44DB-8397-CC5392387B5E"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
    Private Interface IMMDeviceCollection
        Function GetCount(ByRef pcDevices As UInteger) As Integer
        Function Item(ByVal nDevice As UInteger, ByRef ppDevice As IntPtr) As Integer
    End Interface

    <ComImport(), Guid("A95664D2-9614-4F35-A746-DE8DB63617E6"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
    Private Interface IMMDeviceEnumerator
        Function EnumAudioEndpoints(<ComAliasName("MMDeviceAPILib.EDataFlow")> ByVal dataFlow As EDataFlow, ByVal dwStateMask As Integer, ByRef ppDevices As IntPtr) As Integer
        Function GetDefaultAudioEndpoint(<ComAliasName("MMDeviceAPILib.EDataFlow")> ByVal dataFlow As EDataFlow, <ComAliasName("MMDeviceAPILib.ERole")> ByVal role As ERole, ByRef ppEndpoint As IntPtr) As Boolean
        Function GetDevice(ByVal pwstrId As String, ByRef ppDevice As IntPtr) As Integer
        Function RegisterEndpointNotificationCallback(ByVal pClient As IMMNotificationClient) As Integer
        Function UnregisterEndpointNotificationCallback(ByVal pClient As IMMNotificationClient) As Integer
    End Interface

    <ComImport(), Guid("7991EEC9-7E89-4D85-8390-6C703CEC60C0"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
    Private Interface IMMNotificationClient
        Sub OnDeviceStateChanged(<MarshalAs(UnmanagedType.LPWStr)> ByVal pwstrDeviceId As String, ByVal dwNewState As UInteger)
        Sub OnDeviceAdded(<MarshalAs(UnmanagedType.LPWStr)> ByVal pwstrDeviceId As String)
        Sub OnDeviceRemoved(<MarshalAs(UnmanagedType.LPWStr)> ByVal pwstrDeviceId As String)
        Sub OnDefaultDeviceChanged(<ComAliasName("MMDeviceAPILib.EDataFlow")> ByVal flow As EDataFlow, <ComAliasName("MMDeviceAPILib.ERole")> ByVal role As ERole, <MarshalAs(UnmanagedType.LPWStr)> ByVal pwstrDefaultDeviceId As String)
        Sub OnPropertyValueChanged(<MarshalAs(UnmanagedType.LPWStr)> ByVal pwstrDeviceId As String, ByVal key As PropertyKey)
    End Interface

    <ComImport(), Guid("D666063F-1587-4E43-81F1-B948E807363F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
    Private Interface IMMDevice
        Function Activate(ByRef iid As Guid, ByVal dwClsCtx As Integer, ByVal pActivationParams As IntPtr, ByRef ppInterface As IntPtr) As Boolean
        Function OpenPropertyStore(ByVal stgmAccess As Integer, ByRef ppProperties As IntPtr) As Integer
        Function GetId(<MarshalAs(UnmanagedType.LPWStr)> ByRef ppstrId As String) As Integer
        Function GetState(ByRef pdwState As IMMDeviceStatesFlags) As Integer
    End Interface

    <ComImport(), Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
    Private Interface IPropertyStore
        Function GetCount(ByRef cProps As UInteger) As UInteger
        Function GetAt(ByVal iProp As UInteger, ByRef pkey As PropertyKey) As UInteger
        Function GetValue(ByRef key As PropertyKey, ByVal pv As PropVariant) As UInteger
        Function SetValue(ByRef key As PropertyKey, ByVal pv As PropVariant) As UInteger
        Function Commit() As UInteger
    End Interface

    <ComImport(), Guid("568b9108-44bf-40b4-9006-86afe5b5a620"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
    Private Interface IPolicyConfigVista
        Function GetMixFormat(<MarshalAs(UnmanagedType.LPWStr)> ByVal wszDeviceId As String, ByRef param1 As IntPtr) As Integer 'not available on Windows 7, use method from IPolicyConfig
        Function GetDeviceFormat(<MarshalAs(UnmanagedType.LPWStr)> ByVal wszDeviceId As String, ByVal param1 As Integer, ByRef wfx As tWAVEFORMATEX) As Integer
        Function SetDeviceFormat(<MarshalAs(UnmanagedType.LPWStr)> ByVal wszDeviceId As String, ByRef wfx1 As tWAVEFORMATEX, ByRef wfx2 As tWAVEFORMATEX) As Integer
        Function GetProcessingPeriod(<MarshalAs(UnmanagedType.LPWStr)> ByVal wszDeviceId As String, ByVal param1 As Integer, ByRef param2 As Long, ByRef param3 As Long) As Integer 'not available on Windows 7, use method from IPolicyConfig
        Function SetProcessingPeriod(<MarshalAs(UnmanagedType.LPWStr)> ByVal wszDeviceId As String, ByRef param1 As Long) As Integer 'not available on Windows 7, use method from IPolicyConfig
        Function GetShareMode(<MarshalAs(UnmanagedType.LPWStr)> ByVal wszDeviceId As String, ByRef DeviceShareMode As IntPtr) As Integer 'not available on Windows 7, use method from IPolicyConfig
        Function SetShareMode(<MarshalAs(UnmanagedType.LPWStr)> ByVal wszDeviceId As String, ByRef DeviceShareMode As IntPtr) As Integer 'not available on Windows 7, use method from IPolicyConfig
        Function GetPropertyValue(<MarshalAs(UnmanagedType.LPWStr)> ByVal wszDeviceId As String, ByRef propKey As PropertyKey, ByRef propVar As PropVariant) As Integer
        Function SetPropertyValue(<MarshalAs(UnmanagedType.LPWStr)> ByVal wszDeviceId As String, ByRef propKey As PropertyKey, ByRef propVar As PropVariant) As Integer
        Function SetDefaultEndpoint(<MarshalAs(UnmanagedType.LPWStr)> ByVal wszDeviceId As String, ByVal eRole As ERole) As Integer
        Function SetEndpointVisibility(<MarshalAs(UnmanagedType.LPWStr)> ByVal wszDeviceId As String, ByVal param1 As Integer) As Integer 'not available on Windows 7, use method from IPolicyConfig
    End Interface

    <Flags()>
    Private Enum IMMDeviceStatesFlags As Integer
        DEVICE_STATE_ACTIVE = &H1
        DEVICE_STATE_DISABLED = &H2
        DEVICE_STATE_NOTPRESENT = &H4
        DEVICE_STATE_UNPLUGGED = &H8
        DEVICE_STATE_ALL = &HF
    End Enum

    Public Enum EDataFlow As Integer
        eRender = &H0
        eCapture = &H1
        eAll = &H2
        EDataFlow_enum_count = &H3
    End Enum

    Private Enum ERole As Integer
        eConsole = &H0
        eMultimedia = &H1
        eCommunications = &H2
        ERole_enum_count = &H3
    End Enum

    <Flags()>
    Private Enum CLSCTX
        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_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

    <StructLayout(LayoutKind.Sequential, Pack:=4)>
    Private Structure PropertyKey
        Private m_formatId As Guid
        Private m_propertyId As Integer
        Public ReadOnly Property FormatId() As Guid
            Get
                Return Me.m_formatId
            End Get
        End Property
        Public ReadOnly Property PropertyId() As Integer
            Get
                Return Me.m_propertyId
            End Get
        End Property
        Public Sub New(ByVal formatId As Guid, ByVal propertyId As Integer)
            Me.m_formatId = formatId
            Me.m_propertyId = propertyId
        End Sub
    End Structure

    <StructLayout(LayoutKind.Sequential)>
    Private Structure tWAVEFORMATEX
        Public wFormatTag As UShort
        Public nChannels As UShort
        Public nSamplesPerSec As UInteger
        Public nAvgBytesPerSec As UInteger
        Public nBlockAlign As UShort
        Public wBitsPerSample As UShort
        Public cbSize As UShort
    End Structure

    <StructLayout(LayoutKind.Explicit)>
    Private NotInheritable Class PropVariant
        Implements IDisposable

        <FieldOffset(0)> Private valueType As UShort
        <FieldOffset(8)> Private ptr As IntPtr

        Public Property VarType() As VarEnum
            Get
                Return DirectCast(CInt(Me.valueType), VarEnum)
            End Get
            Set(ByVal value As VarEnum)
                Me.valueType = CUShort(value)
            End Set
        End Property

        Public ReadOnly Property IsNullOrEmpty() As Boolean
            Get
                Return (Me.valueType = CUShort(VarEnum.VT_EMPTY) OrElse Me.valueType = CUShort(VarEnum.VT_NULL))
            End Get
        End Property

        Public ReadOnly Property Value() As String
            Get
                Return Marshal.PtrToStringUni(Me.ptr)
            End Get
        End Property

        Public Sub New()
        End Sub

        Public Sub New(ByVal value As String)
            If value Is Nothing Then
                Throw New ArgumentNullException("value")
            End If

            Me.valueType = CUShort(VarEnum.VT_LPWSTR)
            Me.ptr = Marshal.StringToCoTaskMemUni(value)
        End Sub

        Protected Overrides Sub Finalize()
            Try
                Dispose()
            Finally
                MyBase.Finalize()
            End Try
        End Sub

        Public Sub Dispose() Implements IDisposable.Dispose
            PropVariantClear(Me)
            GC.SuppressFinalize(Me)
        End Sub
    End Class

    <DllImport("Ole32.dll", PreserveSig:=False)> Private Shared Sub PropVariantClear(<[In](), Out()> ByVal pvar As PropVariant)
    End Sub

    <DllImport("ole32.Dll")>
    Private Shared Function CoCreateInstance(ByRef clsid As Guid, <MarshalAs(UnmanagedType.IUnknown)> ByVal inner As Object, ByVal context As Integer, ByRef uuid As Guid, <MarshalAs(UnmanagedType.IUnknown)> ByRef rReturnedComObject As Object) As Integer
    End Function
End Class


Public Class EndPointDeviceInfo
    Public ReadOnly Property FriendlyName As String
    Public ReadOnly Property Description As String
    Public ReadOnly Property Id As String

    Public Sub New(devName As String, devId As String, devDescription As String)
        _FriendlyName = devName
        _Id = devId
        _Description = devDescription
    End Sub

    Public Overrides Function ToString() As String
        Return FriendlyName
    End Function
End Class

 

 I have also set up the example form differently too.  So,  these are the controls and the names of them that are required to replicate my example form as seen in the animated gif at the bottom of this post.

 Add 2 RadioButton controls and name them (RadioButton_OutputDevices) and (RadioButton_InputDevices).

 Add 2 CheckBox controls and name them (CheckBox_DefaultDevice) and (CheckBox_DefaultCommunicationsDevice).

 Add 1 ComboBox control and name it (ComboBox_EndPointDevices).

 Add 1 Button control and name it (Button_SetDefault).

 Now you can add this code to the form class....

Public Class Form1
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        RadioButton_OutputDevices.Checked = True
        ComboBox_EndPointDevices.DropDownStyle = ComboBoxStyle.DropDownList
    End Sub

    Private Sub Button_SetDefault_Click(sender As Object, e As EventArgs) Handles Button_SetDefault.Click
        If ComboBox_EndPointDevices.SelectedItem IsNot Nothing AndAlso (CheckBox_DefaultDevice.Checked OrElse CheckBox_DefaultCommunicationsDevice.Checked) Then
            Dim epdi As EndPointDeviceInfo = CType(ComboBox_EndPointDevices.SelectedItem, EndPointDeviceInfo)
            AudioEndPoints.SetDefaultEndPoint(epdi.Id, CheckBox_DefaultDevice.Checked, CheckBox_DefaultCommunicationsDevice.Checked)
        End If
    End Sub

    Private Sub RadioButton_OutputDevices_CheckedChanged(sender As Object, e As EventArgs) Handles RadioButton_OutputDevices.CheckedChanged
        If RadioButton_OutputDevices.Checked Then
            ComboBox_EndPointDevices.DataSource = AudioEndPoints.GetEndPointNames(AudioEndPoints.EDataFlow.eRender)
        Else
            ComboBox_EndPointDevices.DataSource = AudioEndPoints.GetEndPointNames(AudioEndPoints.EDataFlow.eCapture)
        End If
    End Sub
End Class

 

 This shows it setting the the Venus microphone as the default device and the default communications device.  Then setting the SigmaTel microphone as the default communications device.  Lastly, i set the SigmaTel microphone as the default device.  This can be done for the Input or Output devices.

If you say it can`t be done then i`ll try it


Friday, December 22, 2017 5:25 AM

Hi Ran-jj,

I test your code and get list.count=0, so I think there is some error in your code, I use the flowing code to get audio devices.

<DllImport("winmm.dll", SetLastError:=True)>
    Private Shared Function waveOutGetNumDevs() As UInteger
    End Function

    <DllImport("winmm.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
    Public Shared Function waveOutGetDevCaps(ByVal hwo As UInteger, ByRef pwoc As WAVEOUTCAPS, ByVal cbwoc As UInteger) As UInteger
    End Function

    <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)>
    Public Structure WAVEOUTCAPS

        Public wMid As UShort

        Public wPid As UShort

        Public vDriverVersion As UInteger

        <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=32)>
        Public szPname As String

        Public dwFormats As UInteger

        Public wChannels As UShort

        Public wReserved1 As UShort

        Public dwSupport As UInteger
    End Structure


 Public Shared Function GetSoundDevices() As String()
        Dim devices As UInteger = waveOutGetNumDevs()
        Dim result As String() = New String(devices - 1) {}
        Dim caps As WAVEOUTCAPS = New WAVEOUTCAPS()
        For i As UInteger = 0 To devices - 1
            waveOutGetDevCaps(i, caps, CUInt(Marshal.SizeOf(caps)))
            result(i) = caps.szPname
        Next

        Return result
    End Function

And you said that you wan to change audio input of the system, your mean that you want to change the audio devices in the system?

Best Regards,

Cherry

MSDN Community Support
Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact [email protected].


Thursday, January 4, 2018 1:37 AM

So i want to switch the audio card default.

The default Playback divice


Thursday, January 4, 2018 2:41 PM

So i want to switch the audio card default.

The default Playback divice

This is actually a lot more complicated than it should be, due to the lack of API function calls, but the project below should help:

https://sdae.codeplex.com/

Paul ~~~~ Microsoft MVP (Visual Basic)


Thursday, January 4, 2018 2:50 PM

Windows uses IPolicyConfig.SetDefaultEndpoint

Not officially documented but you can find samples on Google...


Friday, January 5, 2018 2:48 PM

 As Paul said,  it is much more complex than it should be since they started using Core Audio APIs.  They started using these in windows Vista and any newer OS's.  Using them in managed code like Vb.Net adds even more complexity to it because you need to create all the signatures for the Interfaces,  Enumerations,  Structures,  and Functions in your code.

 As Castorix31 said,  you can use the IPolicyConfig interface which MS seems to have mysteriously forgotten to document.  However,  you need to use much more than that interface just to get the device names and most important,  the device Id.  This specific Id is needed in order to call the SetDefaultEndpoint function of the IPolicyConfig interface.

 Here is an example that has basically only what you need to get a list of the audio Capture and/or Render devices and allow you to set the Default devices.  Capture devices are the input devices and Render devices are the output devices.

 You can test this by creating a new Form project with 2 ComboBoxes and 2 Buttons added to the form.  Name the ComboBoxes as "ComboBox_RendererEndPoints" and "ComboBox_CaptureEndPoints".  Name the two buttons as "Button_SetDefaultRenderer" and "Button_SetDefaultCapture".

 I would set the Text of the buttons and there locations so you know which button is for setting the default Capture devices and which is for Renderer devices.

 Now add a Class to your project by clicking (Project) on the VS menu and selecting (Add Class).  Change it's name from "Class1.vb" to "AudioEndPoints.vb" and click the (Add) button.  Then copy this code into it...

Imports System.Runtime.InteropServices

Public Class AudioEndPoints
    Public Shared Sub SetDefaultEndPoint(devId As String)
        Dim IPCV As IPolicyConfigVista = Nothing
        Dim oIPCV As Object = Nothing
        Try
            Dim IID_IPolicyConfigVista As Guid = New Guid("568b9108-44bf-40b4-9006-86afe5b5a620")
            Dim CLSID_CPolicyConfigVistaClient As Guid = New Guid("294935CE-F637-4E7C-A41B-AB255460B862")
            If CoCreateInstance(CLSID_CPolicyConfigVistaClient, Nothing, CLSCTX.CLSCTX_INPROC_SERVER, IID_IPolicyConfigVista, oIPCV) <> 0 Then
                Throw New Exception("Failed:  CoCreateInstance")
            Else
                IPCV = CType(oIPCV, IPolicyConfigVista)
                If IPCV Is Nothing Then Throw New Exception("Failed: COM cast to IPolicyConfigVista")
            End If
            IPCV.SetDefaultEndpoint(devId, ERole.eConsole)
        Finally
            If (IPCV IsNot Nothing) Then
                While Marshal.ReleaseComObject(IPCV) > 0
                End While
                IPCV = Nothing
            End If
            If (oIPCV IsNot Nothing) Then
                While Marshal.ReleaseComObject(oIPCV) > 0
                End While
                oIPCV = Nothing
            End If
        End Try
    End Sub

    Public Shared Function GetEndPointNames(ByVal DevType As EDataFlow) As EndPointDeviceInfo()
        Dim immdevcolptr As IntPtr = IntPtr.Zero
        Dim devcnt As UInteger = 0
        Dim immdevcol As IMMDeviceCollection = Nothing
        Dim dvInfo As New List(Of EndPointDeviceInfo)
        Dim IMMDE As IMMDeviceEnumerator = Nothing
        Dim oIMMDE As Object = Nothing
        Try
            Dim IID_IUnknown As Guid = New Guid("00000000-0000-0000-C000-000000000046")
            Dim IMMDE_clsid As Guid = New Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")
            If CoCreateInstance(IMMDE_clsid, Nothing, CLSCTX.CLSCTX_INPROC_SERVER, IID_IUnknown, oIMMDE) <> 0 Then
                Throw New Exception("Failed:  CoCreateInstance")
            Else
                IMMDE = CType(oIMMDE, IMMDeviceEnumerator)
                If IMMDE Is Nothing Then Throw New Exception("Failed: COM cast to IMMDeviceEnumerator")
            End If

            Dim res As Integer = IMMDE.EnumAudioEndpoints(DevType, IMMDeviceStatesFlags.DEVICE_STATE_ACTIVE, immdevcolptr)
            If res <> 0 Then
                Throw New Exception("EnumAudioEndpoints Failed with error: " & res.ToString)
            End If

            immdevcol = CType(Marshal.GetObjectForIUnknown(immdevcolptr), IMMDeviceCollection)

            res = immdevcol.GetCount(devcnt)
            If res <> 0 Then
                Throw New Exception("GetCount Failed with error: " & res.ToString)
            End If

            If devcnt > 0 Then
                For i As UInteger = 0 To devcnt - 1UI

                    Dim immdevptr As IntPtr = IntPtr.Zero
                    res = immdevcol.Item(i, immdevptr)
                    If res = 0 Then

                        Dim immdev As IMMDevice = CType(Marshal.GetObjectForIUnknown(immdevptr), IMMDevice)
                        If immdev IsNot Nothing Then

                            Dim propstrptr As IntPtr = IntPtr.Zero
                            res = immdev.OpenPropertyStore(STGM_READ, propstrptr)
                            If res = 0 Then

                                Dim propstor As IPropertyStore = CType(Marshal.GetObjectForIUnknown(propstrptr), IPropertyStore)
                                If propstor IsNot Nothing Then

                                    Dim FriendlyName As String = ""
                                    Using varnt As New PropVariant
                                        propstor.GetValue(Device_FriendlyName, varnt)
                                        FriendlyName = varnt.Value
                                    End Using

                                    Dim Description As String = ""
                                    Using vrnt As New PropVariant
                                        propstor.GetValue(Device_DeviceDesc, vrnt)
                                        Description = vrnt.Value
                                    End Using

                                    Dim idString As String = ""
                                    immdev.GetId(idString)

                                    dvInfo.Add(New EndPointDeviceInfo(FriendlyName, idString, Description))

                                    Marshal.ReleaseComObject(propstor)
                                    propstor = Nothing
                                End If

                            End If

                            Marshal.ReleaseComObject(immdev)
                            immdev = Nothing
                        End If

                    End If
                Next

            End If
        Finally
            If immdevcol IsNot Nothing Then
                Marshal.ReleaseComObject(immdevcol)
                immdevcol = Nothing
            End If
            If (IMMDE IsNot Nothing) Then
                While Marshal.ReleaseComObject(IMMDE) > 0
                End While
                IMMDE = Nothing
            End If
            If (oIMMDE IsNot Nothing) Then
                While Marshal.ReleaseComObject(oIMMDE) > 0
                End While
                oIMMDE = Nothing
            End If
        End Try
        Return dvInfo.ToArray
    End Function


    Private Shared SPDRP_Guid As New Guid(&HA45C254EUI, &HDF1C, &H4EFD, &H80, &H20, &H67, &HD1, &H46, &HA8, &H50, &HE0)
    Private Shared ReadOnly Property Device_Manufacturer As PropertyKey
        Get
            Return New PropertyKey(SPDRP_Guid, 13)
        End Get
    End Property
    Private Shared ReadOnly Property Device_DeviceDesc As PropertyKey
        Get
            Return New PropertyKey(SPDRP_Guid, 2)
        End Get
    End Property
    Private Shared ReadOnly Property Device_FriendlyName As PropertyKey
        Get
            Return New PropertyKey(SPDRP_Guid, 14)
        End Get
    End Property

    Private Const STGM_READ As Integer = &H0

    <Guid("0BD7A1BE-7A1A-44DB-8397-CC5392387B5E"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
    Private Interface IMMDeviceCollection
        Function GetCount(ByRef pcDevices As UInteger) As Integer
        Function Item(ByVal nDevice As UInteger, ByRef ppDevice As IntPtr) As Integer
    End Interface

    <Guid("A95664D2-9614-4F35-A746-DE8DB63617E6"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
    Private Interface IMMDeviceEnumerator
        Function EnumAudioEndpoints(<ComAliasName("MMDeviceAPILib.EDataFlow")> ByVal dataFlow As EDataFlow, ByVal dwStateMask As Integer, ByRef ppDevices As IntPtr) As Integer
        Function GetDefaultAudioEndpoint(<ComAliasName("MMDeviceAPILib.EDataFlow")> ByVal dataFlow As EDataFlow, <ComAliasName("MMDeviceAPILib.ERole")> ByVal role As ERole, ByRef ppEndpoint As IntPtr) As Boolean
        Function GetDevice(ByVal pwstrId As String, ByRef ppDevice As IntPtr) As Integer
        Function RegisterEndpointNotificationCallback(ByVal pClient As IMMNotificationClient) As Integer
        Function UnregisterEndpointNotificationCallback(ByVal pClient As IMMNotificationClient) As Integer
    End Interface

    <Guid("7991EEC9-7E89-4D85-8390-6C703CEC60C0"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
    Private Interface IMMNotificationClient
        Sub OnDeviceStateChanged(<MarshalAs(UnmanagedType.LPWStr)> ByVal pwstrDeviceId As String, ByVal dwNewState As UInteger)
        Sub OnDeviceAdded(<MarshalAs(UnmanagedType.LPWStr)> ByVal pwstrDeviceId As String)
        Sub OnDeviceRemoved(<MarshalAs(UnmanagedType.LPWStr)> ByVal pwstrDeviceId As String)
        Sub OnDefaultDeviceChanged(<ComAliasName("MMDeviceAPILib.EDataFlow")> ByVal flow As EDataFlow, <ComAliasName("MMDeviceAPILib.ERole")> ByVal role As ERole, <MarshalAs(UnmanagedType.LPWStr)> ByVal pwstrDefaultDeviceId As String)
        Sub OnPropertyValueChanged(<MarshalAs(UnmanagedType.LPWStr)> ByVal pwstrDeviceId As String, ByVal key As PropertyKey)
    End Interface

    <Guid("D666063F-1587-4E43-81F1-B948E807363F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
    Private Interface IMMDevice
        Function Activate(ByRef iid As Guid, ByVal dwClsCtx As Integer, ByVal pActivationParams As IntPtr, ByRef ppInterface As IntPtr) As Boolean
        Function OpenPropertyStore(ByVal stgmAccess As Integer, ByRef ppProperties As IntPtr) As Integer
        Function GetId(<MarshalAs(UnmanagedType.LPWStr)> ByRef ppstrId As String) As Integer
        Function GetState(ByRef pdwState As IMMDeviceStatesFlags) As Integer
    End Interface

    <ComImport(), Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
    Private Interface IPropertyStore
        Function GetCount(ByRef cProps As UInteger) As UInteger
        Function GetAt(ByVal iProp As UInteger, ByRef pkey As PropertyKey) As UInteger
        Function GetValue(ByRef key As PropertyKey, ByVal pv As PropVariant) As UInteger
        Function SetValue(ByRef key As PropertyKey, ByVal pv As PropVariant) As UInteger
        Function Commit() As UInteger
    End Interface

    <ComImport(), Guid("568b9108-44bf-40b4-9006-86afe5b5a620"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
    Private Interface IPolicyConfigVista
        Function GetMixFormat(<MarshalAs(UnmanagedType.LPWStr)> ByVal wszDeviceId As String, ByRef param1 As IntPtr) As Integer 'not available on Windows 7, use method from IPolicyConfig
        Function GetDeviceFormat(<MarshalAs(UnmanagedType.LPWStr)> ByVal wszDeviceId As String, ByVal param1 As Integer, ByRef wfx As tWAVEFORMATEX) As Integer
        Function SetDeviceFormat(<MarshalAs(UnmanagedType.LPWStr)> ByVal wszDeviceId As String, ByRef wfx1 As tWAVEFORMATEX, ByRef wfx2 As tWAVEFORMATEX) As Integer
        Function GetProcessingPeriod(<MarshalAs(UnmanagedType.LPWStr)> ByVal wszDeviceId As String, ByVal param1 As Integer, ByRef param2 As Long, ByRef param3 As Long) As Integer 'not available on Windows 7, use method from IPolicyConfig
        Function SetProcessingPeriod(<MarshalAs(UnmanagedType.LPWStr)> ByVal wszDeviceId As String, ByRef param1 As Long) As Integer 'not available on Windows 7, use method from IPolicyConfig
        Function GetShareMode(<MarshalAs(UnmanagedType.LPWStr)> ByVal wszDeviceId As String, ByRef DeviceShareMode As IntPtr) As Integer 'not available on Windows 7, use method from IPolicyConfig
        Function SetShareMode(<MarshalAs(UnmanagedType.LPWStr)> ByVal wszDeviceId As String, ByRef DeviceShareMode As IntPtr) As Integer 'not available on Windows 7, use method from IPolicyConfig
        Function GetPropertyValue(<MarshalAs(UnmanagedType.LPWStr)> ByVal wszDeviceId As String, ByRef propKey As PropertyKey, ByRef propVar As PropVariant) As Integer
        Function SetPropertyValue(<MarshalAs(UnmanagedType.LPWStr)> ByVal wszDeviceId As String, ByRef propKey As PropertyKey, ByRef propVar As PropVariant) As Integer
        Function SetDefaultEndpoint(<MarshalAs(UnmanagedType.LPWStr)> ByVal wszDeviceId As String, ByVal eRole As ERole) As Integer
        Function SetEndpointVisibility(<MarshalAs(UnmanagedType.LPWStr)> ByVal wszDeviceId As String, ByVal param1 As Integer) As Integer 'not available on Windows 7, use method from IPolicyConfig
    End Interface

    <Flags()>
    Private Enum IMMDeviceStatesFlags As Integer
        DEVICE_STATE_ACTIVE = &H1
        DEVICE_STATE_DISABLED = &H2
        DEVICE_STATE_NOTPRESENT = &H4
        DEVICE_STATE_UNPLUGGED = &H8
        DEVICE_STATE_ALL = &HF
    End Enum

    Public Enum EDataFlow As Integer
        eRender = &H0
        eCapture = &H1
        eAll = &H2
        EDataFlow_enum_count = &H3
    End Enum

    Private Enum ERole As Integer
        eConsole = &H0
        eMultimedia = &H1
        eCommunications = &H2
        ERole_enum_count = &H3
    End Enum

    <Flags()>
    Private Enum CLSCTX
        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_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


    <StructLayout(LayoutKind.Sequential, Pack:=4)>
    Private Structure PropertyKey
        Private m_formatId As Guid
        Private m_propertyId As Integer

        Public ReadOnly Property FormatId() As Guid
            Get
                Return Me.m_formatId
            End Get
        End Property

        Public ReadOnly Property PropertyId() As Integer
            Get
                Return Me.m_propertyId
            End Get
        End Property

        Public Sub New(ByVal formatId As Guid, ByVal propertyId As Integer)
            Me.m_formatId = formatId
            Me.m_propertyId = propertyId
        End Sub
    End Structure

    <StructLayout(LayoutKind.Sequential)>
    Private Structure tWAVEFORMATEX
        Public wFormatTag As UShort
        Public nChannels As UShort
        Public nSamplesPerSec As UInteger
        Public nAvgBytesPerSec As UInteger
        Public nBlockAlign As UShort
        Public wBitsPerSample As UShort
        Public cbSize As UShort
    End Structure


    <StructLayout(LayoutKind.Explicit)>
    Private NotInheritable Class PropVariant
        Implements IDisposable

        <FieldOffset(0)> Private valueType As UShort
        <FieldOffset(8)> Private ptr As IntPtr

        Public Property VarType() As VarEnum
            Get
                Return DirectCast(CInt(Me.valueType), VarEnum)
            End Get
            Set(ByVal value As VarEnum)
                Me.valueType = CUShort(value)
            End Set
        End Property

        Public ReadOnly Property IsNullOrEmpty() As Boolean
            Get
                Return (Me.valueType = CUShort(VarEnum.VT_EMPTY) OrElse Me.valueType = CUShort(VarEnum.VT_NULL))
            End Get
        End Property

        Public ReadOnly Property Value() As String
            Get
                Return Marshal.PtrToStringUni(Me.ptr)
            End Get
        End Property

        Public Sub New()
        End Sub

        Public Sub New(ByVal value As String)
            If value Is Nothing Then
                Throw New ArgumentNullException("value")
            End If

            Me.valueType = CUShort(VarEnum.VT_LPWSTR)
            Me.ptr = Marshal.StringToCoTaskMemUni(value)
        End Sub

        Protected Overrides Sub Finalize()
            Try
                Dispose()
            Finally
                MyBase.Finalize()
            End Try
        End Sub

        Public Sub Dispose() Implements IDisposable.Dispose
            PropVariantClear(Me)
            GC.SuppressFinalize(Me)
        End Sub
    End Class

    <DllImport("Ole32.dll", PreserveSig:=False)> Private Shared Sub PropVariantClear(<[In](), Out()> ByVal pvar As PropVariant)
    End Sub

    <DllImport("ole32.Dll")>
    Private Shared Function CoCreateInstance(ByRef clsid As Guid, <MarshalAs(UnmanagedType.IUnknown)> ByVal inner As Object, ByVal context As Integer, ByRef uuid As Guid, <MarshalAs(UnmanagedType.IUnknown)> ByRef rReturnedComObject As Object) As Integer
    End Function
End Class


Public Class EndPointDeviceInfo
    Public ReadOnly Property FriendlyName As String
    Public ReadOnly Property Description As String
    Public ReadOnly Property Id As String

    Public Sub New(devName As String, devId As String, devDescription As String)
        _FriendlyName = devName
        _Id = devId
        _Description = devDescription
    End Sub

    Public Overrides Function ToString() As String
        Return FriendlyName
    End Function
End Class

 

 Now go back to your Form's code and add the following code.  Then you can run/debug the application and test it.

Public Class Form1
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        ComboBox_RendererEndPoints.DataSource = AudioEndPoints.GetEndPointNames(AudioEndPoints.EDataFlow.eRender)
        ComboBox_CaptureEndPoints.DataSource = AudioEndPoints.GetEndPointNames(AudioEndPoints.EDataFlow.eCapture)
    End Sub

    Private Sub Button_SetDefaultRenderer_Click(sender As Object, e As EventArgs) Handles Button_SetDefaultRenderer.Click
        Dim epdi As EndPointDeviceInfo = CType(ComboBox_RendererEndPoints.SelectedItem, EndPointDeviceInfo)
        AudioEndPoints.SetDefaultEndPoint(epdi.Id)
    End Sub

    Private Sub Button_SetDefaultCapture_Click(sender As Object, e As EventArgs) Handles Button_SetDefaultCapture.Click
        Dim epdi As EndPointDeviceInfo = CType(ComboBox_CaptureEndPoints.SelectedItem, EndPointDeviceInfo)
        AudioEndPoints.SetDefaultEndPoint(epdi.Id)
    End Sub
End Class

 

 Here you can see it sets the device as the "Default Device".   However,  it does not set the device as the "Default Communications Device".

If you say it can`t be done then i`ll try it


Tuesday, January 9, 2018 4:06 PM

Thanks, I will study this code :)


Monday, May 27, 2019 9:16 PM

IronRazerz, I stumbled across this class and it is working beautifully. One question I have is in regards to implementing the "GetDefaultAudioEndpoint". I'm attempting to access the existing default audio endpoint on form load, but not sure how to go about that.

Any further help would be greatly appreciated, thanks!


Thursday, November 14, 2019 8:37 PM

Thank you for the code, it also work perfectly for me but I am also wondering how to display the default audio device in the combo box upon form load.  Any help would be appreciated.

Thank you!


Friday, November 15, 2019 12:34 PM

Thank you for the code, it also work perfectly for me but I am also wondering how to display the default audio device in the combo box upon form load.  Any help would be appreciated.

Compare GetDefaultAudioEndpoint with GetId