Jump to content

Get Audio/Microphone Devices [Solved]


Subz
 Share

Recommended Posts

Hello all.

in the process of packaging an application (Voip) and looking at trying to automate capturing the following information to add to a config.xml file:

Default: Playback Device Name and Guid
Example:
Name: Speakers (Realtek High Definition Audio)
Guid: {0.0.0.00000000}.{a46ce930-4dd3-49b5-8e8e-7c8a2fdc3925}

Default Microphone Device Name and Guid
Example:
Name: Microphone (Realtek High Definition Audio)
Guid: {0.0.1.00000000}.{cff6f838-33ce-4c2d-9f77-98f4e19e4a75}

I've seen the following post by @trancexx, which gives me the Default Audit Device Name, but unsure how to get the Guid or the Microphone Name and Guid.  I believe to get the Guid, I would need to use PKEY_AudioEndpoint_GUID but unsure how to code this.  If anyone can assist or point me in the right direction it would be much appreciated.

Cheers Subz

 

Edited by Subz
Link to comment
Share on other sites

Thats a nice example from Trancexx there

I believe you just need to pass the Correct Property Key

Global Const $sPKEY_Device_FriendlyName = "{a45c254e-df1c-4efd-8020-67d146a850e0}, 14"
Global Const $sPKEY_Audio_Endpoint_GUID = "{1DA5D803-D492-4EDD-8C23-E0C0FFEE7F0E}, 4"

like literally use $sPKEY_Audio_Endpoint_GUID instead of $sPKEY_Device_FriendlyName

Link to comment
Share on other sites

sorry I missed the part about you wanting the microphone as well

#include <WinAPICOM.au3>


Global Const $sCLSID_MMDeviceEnumerator = "{BCDE0395-E52F-467C-8E3D-C4579291692E}"
Global Const $sIID_IMMDeviceEnumerator = "{A95664D2-9614-4F35-A746-DE8DB63617E6}"
Global Const $tagIMMDeviceEnumerator = "EnumAudioEndpoints hresult(int;int;ptr*);" & _
        "GetDefaultAudioEndpoint hresult(int;int;ptr*);" & _
        "GetDevice hresult(wstr;ptr*);" & _
        "RegisterEndpointNotificationCallback hresult(ptr);" & _
        "UnregisterEndpointNotificationCallback hresult(ptr);"

Global Const $IID_IMMDevice = "{D666063F-1587-4E43-81F1-B948E807363F}"
Global Const $tagIMMDevice = "Activate hresult(ptr;dword;variant*;ptr*);" & _
        "OpenPropertyStore hresult(dword;ptr*);" & _
        "GetId hresult(ptr*);" & _
        "GetState hresult(dword*);"

Global Const $IID_IPropertyStore = "{886d8eeb-8cf2-4446-8d02-cdba1dbdcf99}"
Global Const $tagIPropertyStore = "GetCount hresult(dword*);" & _
        "GetAt hresult(dword;ptr*);" & _
        "GetValue hresult(struct*;variant*);" & _
        "SetValue hresult(struct*;variant);" & _
        "Commit hresult();"

Global Const $sPKEY_Device_FriendlyName = "{a45c254e-df1c-4efd-8020-67d146a850e0}, 14"
Global Const $sPKEY_Audio_Endpoint_GUID = "{1DA5D803-D492-4EDD-8C23-E0C0FFEE7F0E}, 4"

Global Const $STGM_READ = 0
Global Const $DEVICE_STATE_ACTIVE = 0x00000001

Global Const $eRender = 0
Global Const $eCapture = 1
Global Const $eAll = 2
Global Const $EDataFlow_enum_count = 3

Global Const $eConsole = 0
Global Const $eMultimedia = 1
Global Const $eCommunications = 2
Global Const $ERole_enum_count = 3

Func _WinAPI_PKEYFromString($sPKEY, $pID = Default)
    Local $tPKEY = DllStructCreate("byte GUID[16]; dword PID;")
    DllCall("propsys.dll", "long", "PSPropertyKeyFromString", "wstr", $sPKEY, "struct*", $tPKEY)
    If $pID <> Default Then DllStructSetData($tPKEY, "PID", $pID)
    Return $tPKEY
EndFunc
;==========================================================

Local $oEnumerator = ObjCreateInterface($sCLSID_MMDeviceEnumerator, $sIID_IMMDeviceEnumerator, $tagIMMDeviceEnumerator)

Local $pDefaultEndpoint
$oEnumerator.GetDefaultAudioEndpoint($eRender, $DEVICE_STATE_ACTIVE, $pDefaultEndpoint)

Local $oEndpoint = ObjCreateInterface($pDefaultEndpoint, $IID_IMMDevice, $tagIMMDevice)

; PropertyStore stores properties
Local $pProps
$oEndpoint.OpenPropertyStore($STGM_READ, $pProps)
$oProps = ObjCreateInterface($pProps, $IID_IPropertyStore, $tagIPropertyStore)

; Collect FriendlyName property
Local $tPKEY_Device_FriendlyName = _WinAPI_PKEYFromString($sPKEY_Device_FriendlyName)
Local $sName
$oProps.GetValue($tPKEY_Device_FriendlyName, $sName)

ConsoleWrite($sName & @CRLF)

Local $tPKEY_Audio_Endpoint_GUID = _WinAPI_PKEYFromString($sPKEY_Audio_Endpoint_GUID)
Local $sGuid
$oProps.GetValue($tPKEY_Audio_Endpoint_GUID, $sGuid)

ConsoleWrite($sGuid & @CRLF)

;------------MICROPHONE
$oEnumerator.GetDefaultAudioEndpoint($eCapture, $DEVICE_STATE_ACTIVE, $pDefaultEndpoint)

$oEndpoint = ObjCreateInterface($pDefaultEndpoint, $IID_IMMDevice, $tagIMMDevice)

; PropertyStore stores properties
$oEndpoint.OpenPropertyStore($STGM_READ, $pProps)

$oProps = ObjCreateInterface($pProps, $IID_IPropertyStore, $tagIPropertyStore)

; Collect FriendlyName property
$tPKEY_Device_FriendlyName = _WinAPI_PKEYFromString($sPKEY_Device_FriendlyName)

$oProps.GetValue($tPKEY_Device_FriendlyName, $sName)

ConsoleWrite($sName & @CRLF)

$tPKEY_Audio_Endpoint_GUID = _WinAPI_PKEYFromString($sPKEY_Audio_Endpoint_GUID)

$oProps.GetValue($tPKEY_Audio_Endpoint_GUID, $sGuid)

ConsoleWrite($sGuid & @CRLF)

 

Edited by Bilgus
Link to comment
Share on other sites

Thanks Bilgus

Sorry for the delay, it turned out I required the Instance ID rather than the Guid, was attempting to get this when I found another post by Trancexx which included the instance id and I was able to make a few adjustments to return the instance Id, Type (Microphone or Playback) and the name. (see code below)

nb: I tried to figure out how to use the ERoles to determine the type but reverted to using the registry as not very familiar with converting C++ into AutoIt code.

Thanks again.

#include <Array.au3>
#include <WinAPI.au3>
#include <Constants.au3>

Global Const $sCLSID_MMDeviceEnumerator = "{BCDE0395-E52F-467C-8E3D-C4579291692E}"
Global Const $sIID_IMMDeviceEnumerator = "{A95664D2-9614-4F35-A746-DE8DB63617E6}"

Global Const $tagIMMDeviceEnumerator = "EnumAudioEndpoints hresult(dword;dword;ptr*);" & _
    "GetDefaultAudioEndpoint hresult(dword;dword;ptr*);" & _
    "GetDevice hresult(wstr;ptr*);" & _
    "RegisterEndpointNotificationCallback hresult(ptr);" & _
    "UnregisterEndpointNotificationCallback hresult(ptr);"

Global Const $sCLSID_CPolicyConfigClient = "{870af99c-171d-4f9e-af0d-e63df40c2bc9}"
Global Const $sIID_IPolicyConfig = "{f8679f50-850a-41cf-9c72-430f290290c8}"

Global Const $tagIPolicyConfig = "GetMixFormat hresult(wstr;ptr*);" & _
    "GetDeviceFormat hresult(wstr;int;ptr*);" & _
    "ResetDeviceFormat hresult(wstr);" & _
    "SetDeviceFormat hresult(wstr;ptr;ptr);" & _
    "GetProcessingPeriod hresult(wstr;int;int64*;int64*);" & _
    "SetProcessingPeriod hresult(wstr;int64*);" & _
    "GetShareMode hresult(wstr;ptr);" & _
    "SetShareMode hresult(wstr;ptr);" & _
    "GetPropertyValue hresult(wstr;struct;variant*);" & _
    "SetPropertyValue hresult(wstr;struct;variant*);" & _
    "SetDefaultEndpoint hresult(wstr;int);" & _
    "SetEndpointVisibility hresult(wstr;int);"

Global Const $IID_IMMDevice = "{D666063F-1587-4E43-81F1-B948E807363F}"
Global Const $tagIMMDevice = "Activate hresult(ptr;dword;variant*;ptr*);" & _
    "OpenPropertyStore hresult(dword;ptr*);" & _
    "GetId hresult(ptr*);" & _
    "GetState hresult(dword*);"

Global Const $IID_IMMDeviceCollection = "{0BD7A1BE-7A1A-44DB-8397-CC5392387B5E}"
Global Const $tagIMMDeviceCollection = "GetCount hresult(uint*);" & _
    "Item hresult(uint;ptr*)"

Global Const $IID_IPropertyStore = "{886d8eeb-8cf2-4446-8d02-cdba1dbdcf99}"
Global Const $tagIPropertyStore = "GetCount hresult(dword*);" & _
    "GetAt hresult(dword;ptr*);" & _
    "GetValue hresult(ptr;variant*);" & _
    "SetValue hresult(ptr;variant);" & _
    "Commit hresult();"

Global Const $sPKEY_Device_FriendlyName = "{a45c254e-df1c-4efd-8020-67d146a850e0} 14"

Global Const $STGM_READ = 0
Global Const $DEVICE_STATE_ACTIVE = 0x00000001

Global Const $eRender = 0
Global Const $eCapture = 1
Global Const $eAll = 2
Global Const $EDataFlow_enum_count = 3

Global Const $eConsole = 0
Global Const $eMultimedia = 1
Global Const $eCommunications = 2
Global Const $ERole_enum_count = 3
;==========================================================
Global $aArray = _EnumerateDevices()
_ArrayDisplay($aArray)


Func _EnumerateDevices()
    ;~ Error monitoring
    Local $oErrorHandler = ObjEvent("AutoIt.Error", "_ErrFunc")
        #forceref $oErrorHandler

;~ Registry Key for Audio Devices
    Local $sRegAudio = @OSArch = "x64" ? "HKLM64\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio" : "HKLM64\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio"

    ;~ Create MMDeviceEnumerator object
    Local $oEnumerator = ObjCreateInterface($sCLSID_MMDeviceEnumerator, $sIID_IMMDeviceEnumerator, $tagIMMDeviceEnumerator)

    ;~ Get collection out of it
    Local $pCollection
    $oEnumerator.EnumAudioEndpoints($eAll, $DEVICE_STATE_ACTIVE, $pCollection)
    ;~ Turn it into object
    Local $oCollection = ObjCreateInterface($pCollection, $IID_IMMDeviceCollection, $tagIMMDeviceCollection)

    ;~ Check the number of devices in collection
    Local $iCount
    $oCollection.GetCount($iCount)

    ;~ Array for out
    Local $aArray[$iCount][4]
    Local $pEndpoint, $oEndpoint
    Local $pID, $sId, $pProps, $oProps
    Local $sName
    Local $tPKEY_Device_FriendlyName = _WinAPI_PKEYFromString($sPKEY_Device_FriendlyName)

    ;~ Actual enumeration
    For $i = 0 To $iCount - 1
    ;~ Item at "i" index is audio endpoint device
        $oCollection.Item($i, $pEndpoint)
        $oEndpoint = ObjCreateInterface($pEndpoint, $IID_IMMDevice, $tagIMMDevice)

    ;~ Collect ID
        $oEndpoint.GetId($pID)
        $sId = DllStructGetData(DllStructCreate("wchar ID[" & _WinAPI_PtrStringLenW($pID) & "]", $pID), "ID")
        _WinAPI_CoTaskMemFree($pID)
        $aArray[$i][2] = $sId

    ;~ Detect Instance ID is Microphone(capture) or Playback(render)
        $aGuid = StringSplit($sId, ".")
        $aArray[$i][1] = $aGuid[$aGuid[0]]
        $aArray[$i][0] = RegRead($sRegAudio & "\Capture\" & $aGuid[$aGuid[0]], "DeviceState") >= 1 ? "Microphone" : ""
        If $aArray[$i][0] = "" Then $aArray[$i][0] = RegRead($sRegAudio & "\Render\" & $aGuid[$aGuid[0]], "DeviceState") >= 1 ? "Playback" : ""

    ;~ PropertyStore stores properties, lol
        $oEndpoint.OpenPropertyStore($STGM_READ, $pProps)
        $oProps = ObjCreateInterface($pProps, $IID_IPropertyStore, $tagIPropertyStore)

    ;~ Collect FriendlyName property
        $sName = 0
        $oProps.GetValue(DllStructGetPtr($tPKEY_Device_FriendlyName), $sName)
        $aArray[$i][3] = $sName
    Next
    Return $aArray
EndFunc ;==>_EnumerateDevices

Func _SwitchToDevice($sId)
    Local $oPolicyConfig = ObjCreateInterface($sCLSID_CPolicyConfigClient, $sIID_IPolicyConfig, $tagIPolicyConfig)
    Local $hResult = $oPolicyConfig.SetDefaultEndpoint($sId, $eConsole)
    If $hResult = $S_OK Then $hResult = $oPolicyConfig.SetDefaultEndpoint($sId, $eCommunications)
    Return $hResult = $S_OK
EndFunc ;==>_SwitchToDevice


Func _WinAPI_PKEYFromString($sPKEY, $pID = Default)
    Local $tPKEY = DllStructCreate("byte GUID[16]; dword PID;")
    DllCall("propsys.dll", "long", "PSPropertyKeyFromString", "wstr", $sPKEY, "ptr", DllStructGetPtr($tPKEY))
    If @error Then ; alternative for unsupported systems
        Local $tGUID = _WinAPI_GUIDFromString($sPKEY)
        If Not @error Then
            DllStructSetData($tPKEY, "GUID", DllStructGetData(DllStructCreate("byte Data[16]", DllStructGetPtr($tGUID)), 1))
        EndIf
        DllStructSetData($tPKEY, "PID", Number(StringRegExpReplace($sPKEY, ".*?}", "")))
    EndIf
    If $pID <> Default Then DllStructSetData($tPKEY, "PID", $pID)
    Return $tPKEY
EndFunc ;==>_WinAPI_PKEYFromString

Func _WinAPI_PtrStringLenW($pString)
    Local $aCall = DllCall("kernel32.dll", "dword", "lstrlenW", "ptr", $pString)
        If @error Then Return SetError(1, 0, 0)
    Return $aCall[0]
EndFunc ;==>_WinAPI_PtrStringLenW

Func _WinAPI_CoTaskMemFree($pMem)
    DllCall("ole32.dll", "none", "CoTaskMemFree", "ptr", $pMem)
    If @error Then Return SetError(1, 0, False)
    Return True
EndFunc ;==>_WinAPI_CoTaskMemFree

Func _ErrFunc($oError)
    ConsoleWrite("COM Error, ScriptLine(" & $oError.scriptline & ") : Number 0x" & Hex($oError.number, 8) & " - " & $oError.windescription & @CRLF)
EndFunc ;==>_ErrFunc

 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...