CYCho Posted March 8 Share Posted March 8 Hi, I'm trying to synchronize my zPlayer's volume controls with Windows Volume Mixer. I have done the volume part alright using waveOutSetVolume function, but I am stuck on mute/unmute part. I can mute zPlayer with winmm.dll command string (mciSendString("set myMedia audio all off"). If I issue this command, Windows Volume Mixer turns down the volume to 0, not turning the speaker icon to mute state. Conversely, I want zPlayer to detect if the user mutes the sound by clicking the speaker icon in Windows Volume Mixer. So could anyone please guide me to the method of getting and setting the mute state of Windows Volume Mixer, usng only standard AutoIt UDFs if at all possible? Thanks in advance. zPlayer - A Small Audio and Video Player Time Sync + SystemTimeAdjustment Link to comment Share on other sites More sharing options...
argumentum Posted March 8 Share Posted March 8 would this do it ? Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting. Link to comment Share on other sites More sharing options...
CYCho Posted March 8 Author Share Posted March 8 (edited) 24 minutes ago, argumentum said: would this do it ? Thanks for your prompt response. My answer to your question is maybe and maybe not. I have no mic connected to my PC, so your code stops probably trying to detect a mic. I thought I would need a simple code snippet and your code seems to be an overkill for my small task. Edited March 8 by CYCho zPlayer - A Small Audio and Video Player Time Sync + SystemTimeAdjustment Link to comment Share on other sites More sharing options...
argumentum Posted March 8 Share Posted March 8 (edited) if you single click the icon it can popup the volume mixer even if there's no mic. installed. Unless I missed something in my code. Edited March 8 by argumentum CYCho 1 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting. Link to comment Share on other sites More sharing options...
Moderators SmOke_N Posted March 8 Moderators Share Posted March 8 _SetMute(False/True) ; verify with _GetMute() ... This still works on my system... it's the _AudioEndpointVolume.au3 download from the first post. Although, I believe that's only windows os specific, I believe I saw one once that does it per app. CYCho 1 Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer. Link to comment Share on other sites More sharing options...
CYCho Posted March 8 Author Share Posted March 8 (edited) 38 minutes ago, SmOke_N said: This still works on my system... it's the _AudioEndpointVolume.au3 download from the first post. Although, I believe that's only windows os specific, I believe I saw one once that does it per app. Thanks, it works on my Windows 11, too. However, it acts on Windows master volume rather than on app specific volume. Have you tried to make it apply only to a certain app? Maybe some of the golbal constants need to be changed. Edited March 8 by CYCho zPlayer - A Small Audio and Video Player Time Sync + SystemTimeAdjustment Link to comment Share on other sites More sharing options...
Moderators SmOke_N Posted March 8 Moderators Share Posted March 8 1 hour ago, CYCho said: Thanks, it works on my Windows 11, too. However, it acts on Windows master volume rather than on app specific volume. Have you tried to make it apply only to a certain app? Maybe some of the golbal constants need to be changed. I've never had a need or desire unfortunately. Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer. Link to comment Share on other sites More sharing options...
Nine Posted March 8 Share Posted March 8 Try this version. https://www.autoitscript.com/forum/topic/201808-control-application-sound-volume/#comment-1447975 In SimpleAudioVolume, there is a SetMute method. I did not test the code, but it looks right to me...Should work. SmOke_N 1 “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Screen Scraping Multi-Threading Made Easy Link to comment Share on other sites More sharing options...
Moderators SmOke_N Posted March 8 Moderators Share Posted March 8 2 hours ago, Nine said: Try this version. https://www.autoitscript.com/forum/topic/201808-control-application-sound-volume/#comment-1447975 In SimpleAudioVolume, there is a SetMute method. I did not test the code, but it looks right to me...Should work. That's the one I was talking about... nice find Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer. Link to comment Share on other sites More sharing options...
CYCho Posted March 8 Author Share Posted March 8 2 hours ago, Nine said: Try this version. https://www.autoitscript.com/forum/topic/201808-control-application-sound-volume/#comment-1447975 I am trying to understand what it does. It seems to be able to adjust the volume from outside of the process. waveOutSetVolume can do it only from inside of a process. As far as my task is concerned, waveOutSetVolume is good enough for volume adjustment. 3 hours ago, Nine said: In SimpleAudioVolume, there is a SetMute method. I did not test the code, but it looks right to me...Should work. I read it, too. My problem is I can't implement it. I coudn't find an example of setMute code implemented in AutoIt. @SmOke_N and @Nine, Thanks for your kind attention. It's late at night now. I will come back tomorrow. zPlayer - A Small Audio and Video Player Time Sync + SystemTimeAdjustment Link to comment Share on other sites More sharing options...
Gianni Posted March 8 Share Posted March 8 I don't remember where I found it and I don't know if it can be useful here: if you save the following command line in a file with the .vbs extension and then execute it, each time it is executed it switches the audio from ON to OFF and vice versa (it toggles the audio state with each execution) CreateObject("WScript.Shell").SendKeys(chr(173)) Chimp small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt.... Link to comment Share on other sites More sharing options...
argumentum Posted March 8 Share Posted March 8 (edited) Gash darn, am slow. You wanna have a mute button in your script. The simplest would be to run SoundVolumeView (NirSoft) via command line. Internally I've seen an AKH but it'd need translation to au3. hopefully it can be translated by someone that understand all these DLL stuff. Edit: it was here all along I guess https://www.autoitscript.com/forum/topic/200529-unmute-autoit-application/ https://www.autoitscript.com/forum/topic/202969-how-to-change-any-program-volume-by-it-handle/?do=findComment&comment=1457263 Edited March 8 by argumentum Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting. Link to comment Share on other sites More sharing options...
CYCho Posted March 9 Author Share Posted March 9 (edited) 8 hours ago, Gianni said: if you save the following command line in a file with the .vbs extension and then execute it I don't quite get it. I don't know vbs and, even if I do, this code seems to be affecting the master volume, not specific to a single process. 7 hours ago, argumentum said: Gash darn, am slow. You wanna have a mute button in your script. A mute button should turn the sound off, not reducing the volume level to 0. In that sense, I have my mute button and it works. The problem is that I cannot sync the mute state with Windows Volume Mixer. If I click tmy mute button, the sound is off but the mute button in Windows Volume Mixer for my app remains unchanged. Conversely, if the mute button in Windows Volume Mixer is clicked, I have no way to detect it and sync my mute button. I'm sorry I cannot make a short reproducible code. You can download my zPlayer, even though it is a bit long, and do the test. Edited March 9 by CYCho argumentum 1 zPlayer - A Small Audio and Video Player Time Sync + SystemTimeAdjustment Link to comment Share on other sites More sharing options...
Solution CYCho Posted March 9 Author Solution Share Posted March 9 (edited) Based on the posts by @Danyfirex and @careca , I created the following example code. If this code is compiled and executed, it shows the results of SetVolume, GetVolume, SetMute and GetMute commands of ISimpleAudioVolume interface. With this, I would consider my problem SOLVED. Thank you everyone for your kind support. Edit: The code was revised to work in uncompiled script. too. expandcollapse popup; File name: VolumeControlForProcess_Example.au3 #AutoIt3Wrapper_Outfile=VolumeControlForProcess_Example.exe #include-once #include <WinAPIProc.au3> #include <Array.au3> #include <Misc.au3> #include <Sound.au3> Global Const $sCLSID_MMDeviceEnumerator = "{BCDE0395-E52F-467C-8E3D-C4579291692E}" Global Const $sIID_IMMDeviceEnumerator = "{A95664D2-9614-4F35-A746-DE8DB63617E6}" Global Const $sTagIMMDeviceEnumerator = _ "EnumAudioEndpoints hresult(int;dword;ptr*);" & _ "GetDefaultAudioEndpoint hresult(int;int;ptr*);" & _ "GetDevice hresult(wstr;ptr*);" & _ "RegisterEndpointNotificationCallback hresult(ptr);" & _ "UnregisterEndpointNotificationCallback hresult(ptr)" Global Const $sIID_IMMDevice = "{D666063F-1587-4E43-81F1-B948E807363F}" Global Const $sTagIMMDevice = _ "Activate hresult(struct*;dword;ptr;ptr*);" & _ "OpenPropertyStore hresult(dword;ptr*);" & _ "GetId hresult(wstr*);" & _ "GetState hresult(dword*)" Global Const $sIID_IAudioSessionManager2 = "{77aa99a0-1bd6-484f-8bc7-2c654c9a9b6f}" Global Const $sTagIAudioSessionManager = "GetAudioSessionControl hresult(ptr;dword;ptr*);" & _ "GetSimpleAudioVolume hresult(ptr;dword;ptr*);" Global Const $sTagIAudioSessionManager2 = $sTagIAudioSessionManager & "GetSessionEnumerator hresult(ptr*);" & _ "RegisterSessionNotification hresult(ptr);" & _ "UnregisterSessionNotification hresult(ptr);" & _ "RegisterDuckNotification hresult(wstr;ptr);" & _ "UnregisterDuckNotification hresult(ptr)" Global Const $sIID_IAudioSessionEnumerator = "{e2f5bb11-0570-40ca-acdd-3aa01277dee8}" Global Const $sTagIAudioSessionEnumerator = "GetCount hresult(int*);GetSession hresult(int;ptr*)" Global Const $sIID_IAudioSessionControl = "{f4b1a599-7266-4319-a8ca-e70acb11e8cd}" Global Const $sTagIAudioSessionControl = "GetState hresult(int*);GetDisplayName hresult(ptr);" & _ "SetDisplayName hresult(wstr);GetIconPath hresult(ptr);" & _ "SetIconPath hresult(wstr;ptr);GetGroupingParam hresult(ptr*);" & _ "SetGroupingParam hresult(ptr;ptr);RegisterAudioSessionNotification hresult(ptr);" & _ "UnregisterAudioSessionNotification hresult(ptr);" Global Const $sIID_IAudioSessionControl2 = "{bfb7ff88-7239-4fc9-8fa2-07c950be9c6d}" Global Const $sTagIAudioSessionControl2 = $sTagIAudioSessionControl & "GetSessionIdentifier hresult(ptr)" & _ "GetSessionInstanceIdentifier hresult(ptr);" & _ "GetProcessId hresult(dword*);IsSystemSoundsSession hresult();" & _ "SetDuckingPreferences hresult(bool);" ; http://answers.awesomium.com/questions/3398/controlling-the-sound-using-pinvoke-the-volume-mix.html Global Const $sIID_ISimpleAudioVolume = "{87CE5498-68D6-44E5-9215-6DA47EF883D8}" Global Const $sTagISimpleAudioVolume = _ "SetMasterVolume hresult(float;ptr);" & _ "GetMasterVolume hresult(float*);" & _ "SetMute hresult(int;ptr);" & _ "GetMute hresult(int*)" Global $__oIAudioSessionManager2, $gPID = @AutoItPID, $muteState Opt("WinTitleMatchMode", 2) $sFile = "D:\Music\Phone\Pops\Adele - Hello.mp3" ; full path of your mp3 file $aSound = _SoundOpen($sFile) If @error Then MsgBox(0, 'Open Error', "The file cannot be opened.") Exit EndIf ProcessClose("sndvol.exe") Run(@SystemDir &"\sndvol.exe") $hWnd = WinWaitActive(" Mixer - ") Sleep(3000) _SoundPlay($aSound) Sleep(5000) $muteState = _Audio_Action("GetMute", $gPID, "") If $muteState <> 0 Then _Audio_Action("SetMute", $gPID, False) EndIf _Audio_Action("SetVolume", $gPID, 50/100) $iVolume = Round(_Audio_Action("GetVolume", $gPID, "")*100) MsgBox(0, '', "Initial Volume: " & $iVolume) _Audio_Action("SetVolume", $gPID, 100/100) $iVolume = Round(_Audio_Action("GetVolume", $gPID, "")*100) MsgBox(0, '', "Final Volume: " & $iVolume) _Audio_Action("SetMute", $gPID, True) $muteState = _Audio_Action("GetMute", $gPID, "") ; 1 if muted, 0 if unmuted ; 0 if unmuted, 1 if muted via Mixer, -1 if muted via SetMute If $muteState = 0 Then $muteState = "Unmuted" ElseIf $muteState = -1 Then $muteState = "Muted" EndIf MsgBox(0, '', "Result of GetMute Command: " & $muteState) _Audio_Action("SetMute", $gPID, False) $muteState = _Audio_Action("GetMute", $gPID, "") ; 0 if unmuted, 1 if muted via Mixer, -1 if muted via SetMute If $muteState = 0 Then $muteState = "Unmuted" ElseIf $muteState = -1 Then $muteState = "Muted" EndIf MsgBox(0, '', "Result of GetMute Command: " & $muteState) Sleep(5000) _SoundClose($aSound) Func _Audio_Action($action, $pid, $value) ; Each action takes about 6 milliseconds If Not IsObj($__oIAudioSessionManager2) Then $__oIAudioSessionManager2 = Audio_GetIAudioSessionManager2() EndIf If Not IsObj($__oIAudioSessionManager2) Then Return Local $pIAudioSessionEnumerator, $oIAudioSessionEnumerator If $__oIAudioSessionManager2.GetSessionEnumerator($pIAudioSessionEnumerator) < 0 Then Return $oIAudioSessionEnumerator = ObjCreateInterface($pIAudioSessionEnumerator, $sIID_IAudioSessionEnumerator, $sTagIAudioSessionEnumerator) If Not IsObj($oIAudioSessionEnumerator) Then Return SetError(1) Local $i, $nSessions, $pIAudioSessionControl2, $oIAudioSessionControl2 Local $ProcessID, $oISimpleAudioVolume Local $bMute = 0, $error = 1 If $oIAudioSessionEnumerator.GetCount($nSessions) >= 0 Then For $i = 0 To $nSessions - 1 If $oIAudioSessionEnumerator.GetSession($i, $pIAudioSessionControl2) >= 0 Then $oIAudioSessionControl2 = ObjCreateInterface($pIAudioSessionControl2, $sIID_IAudioSessionControl2, $sTagIAudioSessionControl2) If @error Then ContinueLoop $oIAudioSessionControl2.GetProcessId($ProcessID) If $ProcessID = $pid Then $oISimpleAudioVolume = ObjCreateInterface($pIAudioSessionControl2, $sIID_ISimpleAudioVolume, $sTagISimpleAudioVolume) If @error Then ContinueLoop $oIAudioSessionControl2.AddRef() ;stabilize Switch $action Case "SetVolume" If $oISimpleAudioVolume.SetMasterVolume($value, 0) >= 0 Then $error = 0 ExitLoop EndIf Case "GetVolume" If $oISimpleAudioVolume.GetMasterVolume($value) >= 0 Then $error = 0 ExitLoop EndIf Case "SetMute" If $oISimpleAudioVolume.SetMute($value, Null) >= 0 Then $error = 0 ExitLoop EndIf Case "GetMute" If $oISimpleAudioVolume.GetMute($value) >= 0 Then $error = 0 ExitLoop EndIf EndSwitch EndIf EndIf Next EndIf $oISimpleAudioVolume = 0 $oIAudioSessionControl2 = 0 $oIAudioSessionEnumerator = 0 Return SetError($error, 0, $value) EndFunc ;==>_Audio_Action Func Audio_GetIAudioSessionManager2() Local $oIAudioSessionManager2 = 0 Local Const $eMultimedia = 1, $CLSCTX_INPROC_SERVER = 0x01 Local $pIMMDevice, $oMMDevice, $pIAudioSessionManager2 Local $oMMDeviceEnumerator = ObjCreateInterface($sCLSID_MMDeviceEnumerator, $sIID_IMMDeviceEnumerator, $sTagIMMDeviceEnumerator) If IsObj($oMMDeviceEnumerator) Then If $oMMDeviceEnumerator.GetDefaultAudioEndpoint(0, $eMultimedia, $pIMMDevice) >= 0 Then $oMMDevice = ObjCreateInterface($pIMMDevice, $sIID_IMMDevice, $sTagIMMDevice) If IsObj($oMMDevice) Then If $oMMDevice.Activate(_CLSIDFromString($sIID_IAudioSessionManager2), $CLSCTX_INPROC_SERVER, 0, $pIAudioSessionManager2) >= 0 Then $oIAudioSessionManager2 = ObjCreateInterface($pIAudioSessionManager2, $sIID_IAudioSessionManager2, $sTagIAudioSessionManager2) EndIf $oMMDevice = 0 EndIf EndIf $oMMDeviceEnumerator = 0 EndIf If IsObj($oIAudioSessionManager2) Then Return $oIAudioSessionManager2 EndIf EndFunc ;==>Audio_GetIAudioSessionManager2 Func _CLSIDFromString($sGUID) Local $tGUID = DllStructCreate("ulong Data1;ushort Data2;ushort Data3;byte Data4[8]") DllCall("ole32.dll", "long", "CLSIDFromString", "wstr", $sGUID, "struct*", $tGUID) Return $tGUID EndFunc ;==>CLSIDFromString Edited June 16 by CYCho argumentum and Danyfirex 1 1 zPlayer - A Small Audio and Video Player Time Sync + SystemTimeAdjustment Link to comment Share on other sites More sharing options...
CYCho Posted March 9 Author Share Posted March 9 (edited) According to my observation, 3 AutoIt3.exe processes are created when I run an uncompiled script. I would conjecture that ProcessList() function lists the processes in chronological order. Out of these 3 processes, I found that the 2nd from the last was the one registered in Windows Volume Mixer. So I revised the code in the previous post so that it works in both compiled and uncompiled scripts. Edit: @AutoItPID macro is the best answer. Edited June 16 by CYCho argumentum 1 zPlayer - A Small Audio and Video Player Time Sync + SystemTimeAdjustment 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