Determine the current Audio Output

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
noname6500
Posts: 18
Joined: 29 Oct 2021, 04:07

Determine the current Audio Output

02 Dec 2021, 06:53

Im using a script that changes the audio output using a script based on viewtopic.php?p=221751#p221751

I adapted it to have a single hotkey toggle between two audio outputs (speakers and headphones).

Code: Select all

+F18::


audiotoggle := !audiotoggle

If audiotoggle = 0
{
	audioswitcher(2)
	}
	
If audiotoggle = 1
	{
	audioswitcher(3)
}

;~ audiotoggle := !audiotoggle

return



audioswitcher(devicenum)
{
	
	
	Devices := {}
	IMMDeviceEnumerator := ComObjCreate("{BCDE0395-E52F-467C-8E3D-C4579291692E}", "{A95664D2-9614-4F35-A746-DE8DB63617E6}")
	
; IMMDeviceEnumerator::EnumAudioEndpoints
; eRender = 0, eCapture, eAll
; 0x1 = DEVICE_STATE_ACTIVE
	DllCall(NumGet(NumGet(IMMDeviceEnumerator+0)+3*A_PtrSize), "UPtr", IMMDeviceEnumerator, "UInt", 0, "UInt", 0x1, "UPtrP", IMMDeviceCollection, "UInt")
	ObjRelease(IMMDeviceEnumerator)
	
; IMMDeviceCollection::GetCount
	DllCall(NumGet(NumGet(IMMDeviceCollection+0)+3*A_PtrSize), "UPtr", IMMDeviceCollection, "UIntP", Count, "UInt")
	Loop % (Count)
	{
    ; IMMDeviceCollection::Item
		DllCall(NumGet(NumGet(IMMDeviceCollection+0)+4*A_PtrSize), "UPtr", IMMDeviceCollection, "UInt", A_Index-1, "UPtrP", IMMDevice, "UInt")
		
    ; IMMDevice::GetId
		DllCall(NumGet(NumGet(IMMDevice+0)+5*A_PtrSize), "UPtr", IMMDevice, "UPtrP", pBuffer, "UInt")
		DeviceID := StrGet(pBuffer, "UTF-16"), DllCall("Ole32.dll\CoTaskMemFree", "UPtr", pBuffer)
		
    ; IMMDevice::OpenPropertyStore
    ; 0x0 = STGM_READ
		DllCall(NumGet(NumGet(IMMDevice+0)+4*A_PtrSize), "UPtr", IMMDevice, "UInt", 0x0, "UPtrP", IPropertyStore, "UInt")
		ObjRelease(IMMDevice)
		
    ; IPropertyStore::GetValue
		VarSetCapacity(PROPVARIANT, A_PtrSize == 4 ? 16 : 24)
		VarSetCapacity(PROPERTYKEY, 20)
		DllCall("Ole32.dll\CLSIDFromString", "Str", "{A45C254E-DF1C-4EFD-8020-67D146A850E0}", "UPtr", &PROPERTYKEY)
		NumPut(14, &PROPERTYKEY + 16, "UInt")
		DllCall(NumGet(NumGet(IPropertyStore+0)+5*A_PtrSize), "UPtr", IPropertyStore, "UPtr", &PROPERTYKEY, "UPtr", &PROPVARIANT, "UInt")
		DeviceName := StrGet(NumGet(&PROPVARIANT + 8), "UTF-16")    ; LPWSTR PROPVARIANT.pwszVal
		DllCall("Ole32.dll\CoTaskMemFree", "UPtr", NumGet(&PROPVARIANT + 8))    ; LPWSTR PROPVARIANT.pwszVal
		ObjRelease(IPropertyStore)
		
		ObjRawSet(Devices, DeviceName, DeviceID)
	}
	ObjRelease(IMMDeviceCollection)
	
	
	Devices2 := {}
	For DeviceName, DeviceID in Devices
		List .= "(" . A_Index . ") " . DeviceName . "`n", ObjRawSet(Devices2, A_Index, DeviceID)

;~ MsgBox % List
;~ InputBox n,, % List,,,,,,,, 1 ;Use to determine device number

;~ MsgBox % Devices2[n]  ; Use to determine device number


	
;NONAME NOTE. change value of [n] to specific device number (devicenum)
	
;IPolicyConfig::SetDefaultEndpoint
	IPolicyConfig := ComObjCreate("{870af99c-171d-4f9e-af0d-e63df40c2bc9}", "{F8679F50-850A-41CF-9C72-430F290290C8}") ;00000102-0000-0000-C000-000000000046 00000000-0000-0000-C000-000000000046
	R := DllCall(NumGet(NumGet(IPolicyConfig+0)+13*A_PtrSize), "UPtr", IPolicyConfig, "Str", Devices2[devicenum], "UInt", 0, "UInt")
	ObjRelease(IPolicyConfig)
	;~ MsgBox % Format("0x{:08X}", R) ;error message 
	
	
	return
	
}
My issue is that upon the first run of the script (like after starting up the computer). I have to click the hotkey 2,3 times to make it switch. (After that it toggles as intended).
I think the problem is with my toggle method, where I cant set the initial toggle value of 0 or 1 depending on the audio output during that time.

My question, Is there a way to determine the initial audio output when the script starts?
The DllCall stuff is too high level for me to figure out.
User avatar
mikeyww
Posts: 26848
Joined: 09 Sep 2014, 18:38

Re: Determine the current Audio Output

03 Dec 2021, 09:51

I cheat and use SoundVolumeView.

Code: Select all

out = %A_ScriptDir%\sound.txt
RunWait, D:\utils\soundVolumeView\SoundVolumeView.exe /scomma %out%
FileRead, str, %out%
FileRecycle, %out%
For each, line in StrSplit(str, "`n")
 Loop, Parse, line, CSV
  Switch A_Index {
   Case 4: device  := A_LoopField                               ; Field: Device name
   Case 5: speaker := A_LoopField = "Render" ? device : speaker ; Field: Default
  }
MsgBox, 64, Speaker, %speaker%

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: gongnl, Rohwedder and 243 guests