dohanin Posted July 23, 2013 Share Posted July 23, 2013 I have been searching for a while for a script to toggle the default sound device, so that i can easily switch between Speakers and Headphones. Some added a tray icon and keep running on background, some will call up the control panel briefly, while some need to call nircmd externally. I ended up gathered some cool scripts (sorry, i failed to recall the original source) and modified for my own taste. It will get the current default playback device, and then set to the next one. It will print an icon on the screen, and then will just exit. Good to use with shortcut key on keyboards, etc. Feel free to try. I was able to retrieve the actual icons info but found it not satisfactory to draw the icon using GUI. So, I simply use SplashText with Webdings font. expandcollapse popup;========================================================== ; Set Default Playback Device ; to the next available one ;========================================================== #NoTrayIcon #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} 2" Global Const $sPKEY_Device_Icon = "{259abffc-50a7-47ce-af08-68c9a7d73366} 12" Global Const $STGM_READ = 0 Global Const $DEVICE_STATE_ACTIVE = 0x00000001 Global Const $S_OK = 0 Global Const $E_INVALIDARG = 0x80070057 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 ;========================================================== If @OSVersion <> "WIN_7" Then Exit ; God knows what $tagIPolicyConfig is for other systems ; First generate array filled with devices data Global $aArray = _EnumerateDevices() ; FY: Get default device id Global $sDefID = _GetDefaultDevice() ; Set next device as default device $nDev = UBound($aArray, 2) ; no. of devices For $i = 0 to $nDev -1 If $aArray[0][$i]=$sDefID Then $sDev=$i+1 Next If $sDev >= $nDev Then $sDev = 0 _SwitchToDevice($aArray[0][$sDev]) $logo = "U" if $aArray[1][$sDev] = "Headphones" Then $logo=chr(178) $xTT = @DesktopWidth/2-50 $yTT = @DesktopHeight/2-70 ToolTip(" ", $xTT, $yTT, $aArray[1][$sDev],0) SplashTextOn("",$logo, 100, 100, -1, -1, 33, "Webdings", 80) Sleep(2000) SplashOff() Exit ; THE END Func _GetDefaultDevice() ; Error monitoring Local $oErrorHandler = ObjEvent("AutoIt.Error", "_ErrFunc") #forceref $oErrorHandler ; MMDeviceEnumerator Local $oMMDeviceEnumerator = ObjCreateInterface($sCLSID_MMDeviceEnumerator, $sIID_IMMDeviceEnumerator, $tagIMMDeviceEnumerator) Local $pDefaultDevice $oMMDeviceEnumerator.GetDefaultAudioEndpoint($eRender, $eConsole, $pDefaultDevice) Local $oDefaultDevice = ObjCreateInterface($pDefaultDevice, $IID_IMMDevice, $tagIMMDevice) Local $pDefID, $sDefId $oDefaultDevice.GetId($pDefID) $sDefId = DllStructGetData(DllStructCreate("wchar ID[" & _WinAPI_PtrStringLenW($pDefID) & "]", $pDefID), "ID") _WinAPI_CoTaskMemFree($pDefID) Return $sDefID EndFunc ;==>_GetDefaultDevice Func _EnumerateDevices() ; Error monitoring Local $oErrorHandler = ObjEvent("AutoIt.Error", "_ErrFunc") #forceref $oErrorHandler ; Creae MMDeviceEnumerator object Local $oEnumerator = ObjCreateInterface($sCLSID_MMDeviceEnumerator, $sIID_IMMDeviceEnumerator, $tagIMMDeviceEnumerator) ; Get collection out of it Local $pCollection $oEnumerator.EnumAudioEndpoints($eRender, $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[2][$iCount] Local $pEndpoint, $oEndpoint Local $pID, $sId, $pProps, $oProps Local $sName Local $tPKEY_Device_FriendlyName = _WinAPI_PKEYFromString($sPKEY_Device_FriendlyName) Local $tPKEY_Device_Icon = _WinAPI_PKEYFromString($sPKEY_Device_Icon) ; 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[0][$i] = $sId ; PropertyStore stores properties, lol $oEndpoint.OpenPropertyStore($STGM_READ, $pProps) $oProps = ObjCreateInterface($pProps, $IID_IPropertyStore, $tagIPropertyStore) ; Collect FriendlyName property $sName = 0 $sIcon = 0 $oProps.GetValue(DllStructGetPtr($tPKEY_Device_FriendlyName), $sName) $oProps.GetValue(DllStructGetPtr($tPKEY_Device_Icon), $sIcon) $aArray[1][$i] = $sName Next Return $aArray EndFunc ;==>_EnumerateDevices Func _SwitchToDevice($sId) Local $oPolicyConfig = ObjCreateInterface($sCLSID_CPolicyConfigClient, $sIID_IPolicyConfig, $tagIPolicyConfig) Local $hResult $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 pat4005 and amin84 2 Link to comment Share on other sites More sharing options...
pat4005 Posted May 10, 2015 Share Posted May 10, 2015 Thank you, dohanin, this script helps me a lot with my two devices: optical and speakers. Works great on Windows 8.1. Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now