Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Get "Volume Mixer" Application Specific Mute Button State



  • Please log in to reply
26 replies to this topic
soulkobk
  • Members
  • 10 posts
  • Last active: Jan 09 2016 04:30 AM
  • Joined: 26 Dec 2014

Hey all, I'm new to this AHK scripting thing.. but here is what I am trying to do.

 

I currently have a script to mute/unmute and change volume to a specific application if it is found within volume mixer, which works great, but i want to read the current state of the mute so i can put an OSD overlay whilst I'm gaming.

 

For the current volume level, I parse "SendMessage, 0x0400,,,msctls_trackbar%msctls_trackbarNumber%, ahk_class #32770" which works great, as it returns a number between 0 and 100. 100 being full volume on the trackbar/slider.

 

As for the state of whether the application is muted or not... I have absolutely no idea how to do it... I've spent hours and hours researching, testing, failing, repeat.

 

What I need is to be able to get/read the current state of the mute button (at the bottom of the volume mixer, underneath the trackbar/slider) for a specific application. I can set mute, set unmute no problem, but actually reading the mute state is not happening for me. I press NumpadMult to mute/unmute the specific application, but I want to read the state for use with an OSD.

 

I hope that makes sense in what I'm trying to achieve, thanks in advance.



garry
  • Spam Officer
  • 3219 posts
  • Last active: Sep 20 2018 02:47 PM
  • Joined: 19 Apr 2005

was trying this , set volume level slider and ON/OFF

MODIFIED=20141226
;- test volumex sliderx XP

SM4=95                         ; preset volume level
soundset,0,WAVE,mute           ; WAVE ON
SoundSet,%SM4%,WAVE            ; WAVE
Gui,2:Font,s12, Lucida Console
Gui,2:Color,Black
Gui,2:Color,ControlColor, Black
Gui,2:Add, Slider  , x10  y30 w40  h190     altsubmit    vVOL11a gVOL11 Range0-100  Vertical invert thick30 cRed left line10,%sm4%
Gui,2:add, text    , x70  y50 w100 cWhite  vT1,
Gui,2:add, text    , x10  y10 w100 cYellow vT2,
Gui,2:Show,x10 y10 h230 w200 ,use F1 or F2=ON/OFF
GuiControl,2:Text,T1,%sm4%
GuiControl,2:Text,T2,ON
f1=c:\test.mp3
ifexist,%f1%
    run,%f1%
return
2Guiclose:
exitapp

;----- volumex ----------
VOL11:
GuiControlGet, VOL11a
SoundSet,%vol11a%,WAVE
GuiControl,2:Text,T1,%vol11a%
return
;------------------------

;- toggle F1 soundlevel
F1::
t:= !t
if !(t)
  {
  SoundSet,%sm4%,WAVE
  GuiControl,2:Text,T1,%sm4%
  GuiControl,2:,vol11a,%sm4%
  }
else
  {
  SoundSet,20,WAVE
  GuiControl,2:Text,T1,20
  GuiControl,2:,vol11a,20
  }
return

;- toggle F2 sound ON/OFF
F2::
h:= !h
if !(h)
  {
  soundset,0,WAVE,mute
  GuiControl,2:Text,T2,ON
  }
else
  {
  soundset,1,WAVE,mute
  GuiControl,2:Text,T2,OFF
  }
return
;======================================



soulkobk
  • Members
  • 10 posts
  • Last active: Jan 09 2016 04:30 AM
  • Joined: 26 Dec 2014

Not exactly sure what your response is garry. Trying what?

 

Let me explain myself again in what I am trying to achieve.

 

"Volume Mixer" consists of Master/Wave/etc... but I do NOT want to control these... I know how to do that for the most part. What I am trying to achieve is to read the mute status of a specified application only, not master, not wave.

 

In volume mixer it shows each application, its trackbar (slider) and a button underneath which is the MUTE/UNMUTE button. I want to read this as either a number, 1 = audio unmuted or 0 = audio muted. I am unsure of how to pull this data from the GUI window.

 

When I use the 'WindowSpy', it shows when I hover the mute button on the specific application, CLASSNN "ToolBarWindow<number>" and TEXT "Mute For <application>", when you hover the button (tooltip), it either reads "Mute <application>" or "Unmute <application>"... I am wondering how to read this into a variable so then I can use the variable in my script, or if on each press of the mute button, it sets a flag/variable as 'mute' or 'unmuted' or 1 or 0.

 

Read mute button to see what 'state' it is in... is it muted? is it unmuted?

 

Maybe I could even do it another way and check if the trackbar is active for the application, if it is, sound is unmuted, if the trackbar is inactive then sound is muted.

 

Whatever the case, I need to read the mute state for the specific application.

 

Thanks.



soulkobk
  • Members
  • 10 posts
  • Last active: Jan 09 2016 04:30 AM
  • Joined: 26 Dec 2014

No one? Anyone?....



T_Lube
  • Members
  • 640 posts
  • Last active: Sep 09 2016 02:19 AM
  • Joined: 16 Oct 2014

I am willing to try helping you. You can try ControlGet or ControlGetText. these may help you out, i'm not totally sure what you are seeing though. The syntax would be an example that may be helpful for you.

ControlGetText, OutputVar, Control, WinTitle

OR you can try WinGet which should give you the list of controls used correctly:

WinGet, TheWinControls, ControlList, WinTitle

 

In the above "OutputVar" and "TheWinControls" are now a variable which contains the control name or text depending on what you use. Since the name of the application is probably unique within the controls in that window you can use that to identify it as needed to get it's state since it will say "Mute <application>" or "Unmute <application>" I hope this makes sense to you.



soulkobk
  • Members
  • 10 posts
  • Last active: Jan 09 2016 04:30 AM
  • Joined: 26 Dec 2014

Hey, I tried the suggestions, but I'm still unable to get the mute status. I have no idea how to do this, as there is no window text or such to suggest which state it is in. The only part to show what mute state the application is in is via a hover of the mute button to get the tooltip which either says "Mute <application>" or "UnMute <application>"... and I have absolutely no idea on how to extract the text.

 

All I've been able to extract so far is the text "Mute For Arma 3"... which isn't very helpful.

 

Here is a screenshot of the information below...

 

bCAotdP.png

 

As you can see the tool tip showing the state of the button on the right... but I have no idea on how to actually extract this information into a variable, as it's only there when I hover the mouse.

 

I was able to extract the position of the slider ok (from 0 to 100), but I want to be able to extract the mute status of the application to complete the script, as I have introduced an OSD to show volume status whilst the game window is focused (no more alt + tabbing, or using in game menu volume control via mouse).

 

Thanks in advance.



T_Lube
  • Members
  • 640 posts
  • Last active: Sep 09 2016 02:19 AM
  • Joined: 16 Oct 2014

try this script on the window and see what comes up. Paste the results or maybe this will be enough to help you out with what you are doing.

!t::
WinGetActiveTitle, CurrWin
WinGet, MyCtrls, ControlList, %CurrWin%
Loop, Parse, MyCtrls, `n
{
	ControlGetText, ThisStr, %A_LoopField%, %CurrWin%
	If StrLen(ThisStr)
		NewStr .= A_LoopField . ": " . ThisStr . ".`n"
}
Msgbox % "This is on the Clipboard now`n" . Clipboard := NewStr
Return

This will make a list of all the controls on the window and get text for each one, putting onto the list of there is text for that control.



soulkobk
  • Members
  • 10 posts
  • Last active: Jan 09 2016 04:30 AM
  • Joined: 26 Dec 2014

The output of that is...

 

Static2: System Sounds.
Static3: Volume for System Sounds.
ToolbarWindow322: Mute for System Sounds.
Static5: Mozilla Firefox.
Static6: Volume for Mozilla Firefox.
ToolbarWindow324: Mute for Mozilla Firefox.
Static8: Steam Client Bootstrapper.
Static9: Volume for Steam Client Bootstrapper.
ToolbarWindow326: Mute for Steam Client Bootstrapper.
Static11: WinFast Wizard.
Static12: Volume for WinFast Wizard.
ToolbarWindow328: Mute for WinFast Wizard.
Static14: Arma 3.
Static15: Volume for Arma 3.
ToolbarWindow3210: Mute for Arma 3.
Static16: No audio device is installed.
Static17: Main &Volume.
ToolbarWindow3213: Mute Speakers.
SPD_GroupBox1: Applications.
SPD_GroupBox2: &Device.
 



T_Lube
  • Members
  • 640 posts
  • Last active: Sep 09 2016 02:19 AM
  • Joined: 16 Oct 2014

Alright so what happens if you send a ControlClick to ToolBarWindow3210?

 

Also I want you to download Winspector so that we can start looking at the window messages as well, maybe a SendMessage solution is in order.



Masonjar13
  • Members
  • 1517 posts
  • Last active:
  • Joined: 16 Sep 2012
Seemed kind of obvious to me.. Try actually clicking the mute button. You'll notice the text change to "Unmute." Pretty easy from there; ControlClick, Unmute %winName% to change it. To get the current state:
SetTitleMatchMode 2
ControlGetText, controlText, %winName%
if(inStr(controlText, "Unmute"))
    msgbox Muted
else
    msgbox Not muted
Edit: the mixer has static controls with matching text. Use the following method instead.
 
ControlGetText, controlText, Unmute %winName%
if(errorlevel){
    ControlGetText, controlText, Mute %winName%
    if(errorlevel){
        msgbox Window not found in mixer.
        return
    }
    else{
        msgbox Not muted
        return
    }
}
else
    msgbox Muted
return

OS: Windows 7 Ultimate / Windows 8.1 Pro | Editor: Notepad++


Linear Spoon
  • Members
  • 842 posts
  • Last active: Sep 29 2015 03:56 AM
  • Joined: 29 Oct 2011

I've forgotten where this code came from, but I've used it in the past to detect mute states. Not sure how to get the volume level with it though. Requires VA.ahk.

 

Edit: GeekDude originally posted it here

#Include VA.ahk

!m::  ;Alt + m hotkey - toggle mute state of active window
  WinGet, ActivePid, PID, A
  if !(Volume := GetVolumeObject(ActivePid))
    MsgBox, There was a problem retrieving the application volume interface
  VA_ISimpleAudioVolume_GetMute(Volume, Mute)  ;Get mute state
  Msgbox % "Application " ActivePID " is currently " (mute ? "muted" : "not muted")
  VA_ISimpleAudioVolume_SetMute(Volume, !Mute) ;Toggle mute state
  ObjRelease(Volume)
return

;Required for app specific mute
GetVolumeObject(Param = 0)
{
    static IID_IASM2 := "{77AA99A0-1BD6-484F-8BC7-2C654C9A9B6F}"
    , IID_IASC2 := "{bfb7ff88-7239-4fc9-8fa2-07c950be9c6d}"
    , IID_ISAV := "{87CE5498-68D6-44E5-9215-6DA47EF883D8}"
    
    ; Get PID from process name
    if Param is not Integer
    {
        Process, Exist, %Param%
        Param := ErrorLevel
    }
    
    ; GetDefaultAudioEndpoint
    DAE := VA_GetDevice()
    
    ; activate the session manager
    VA_IMMDevice_Activate(DAE, IID_IASM2, 0, 0, IASM2)
    
    ; enumerate sessions for on this device
    VA_IAudioSessionManager2_GetSessionEnumerator(IASM2, IASE)
    VA_IAudioSessionEnumerator_GetCount(IASE, Count)
    
    ; search for an audio session with the required name
    Loop, % Count
    {
        ; Get the IAudioSessionControl object
        VA_IAudioSessionEnumerator_GetSession(IASE, A_Index-1, IASC)
        
        ; Query the IAudioSessionControl for an IAudioSessionControl2 object
        IASC2 := ComObjQuery(IASC, IID_IASC2)
        ObjRelease(IASC)
        
        ; Get the session's process ID
        VA_IAudioSessionControl2_GetProcessID(IASC2, SPID)
        
        ; If the process name is the one we are looking for
        if (SPID == Param)
        {
            ; Query for the ISimpleAudioVolume
            ISAV := ComObjQuery(IASC2, IID_ISAV)
            
            ObjRelease(IASC2)
            break
        }
        ObjRelease(IASC2)
    }
    ObjRelease(IASE)
    ObjRelease(IASM2)
    ObjRelease(DAE)
    return ISAV
}
 
;
; ISimpleAudioVolume : {87CE5498-68D6-44E5-9215-6DA47EF883D8}
;
VA_ISimpleAudioVolume_SetMasterVolume(this, ByRef fLevel, GuidEventContext="") {
    return DllCall(NumGet(NumGet(this+0)+3*A_PtrSize), "ptr", this, "float", fLevel, "ptr", VA_GUID(GuidEventContext))
}
VA_ISimpleAudioVolume_GetMasterVolume(this, ByRef fLevel) {
    return DllCall(NumGet(NumGet(this+0)+4*A_PtrSize), "ptr", this, "float*", fLevel)
}
VA_ISimpleAudioVolume_SetMute(this, ByRef Muted, GuidEventContext="") {
    return DllCall(NumGet(NumGet(this+0)+5*A_PtrSize), "ptr", this, "int", Muted, "ptr", VA_GUID(GuidEventContext))
}
VA_ISimpleAudioVolume_GetMute(this, ByRef Muted) {
    return DllCall(NumGet(NumGet(this+0)+6*A_PtrSize), "ptr", this, "int*", Muted)
}

Join us at the new forum - http://www.ahkscript.org/

 


soulkobk
  • Members
  • 10 posts
  • Last active: Jan 09 2016 04:30 AM
  • Joined: 26 Dec 2014

@T_Lube, ControlClick works correctly...

ToggleMute()
{
	IfWinExist, Arma 3
	{
		ToolbarWindowNumber = 322
		msctls_trackbarNumber = 321
		ControlGetPos, refX, refY, refW, refH, Arma 3, ahk_class #32770
		x = -1
		while ( x != "")
		{
			tbIDX := (A_Index * 2)
			ControlGetPos, x, y, w, h, ToolbarWindow32%tbIDX%, ahk_class #32770
			diff := x - refX
			if (diff > 0 && diff < refW)
			{
			ControlClick, ToolbarWindow32%tbIDX%, ahk_class #32770
			Break
			}
		}
	}
	Return
}

If I put the line in... "ControlGetText, MuteState, ToolbarWindow32%tbIDX%, ahk_class #32770", I can extract "Mute For Arma 3", but that is NOT the information I need. I need the information of the tooltip which is shown when you hover the mouse over the button... but no idea how to extract it (and no, the volume mixer will not be focused).

 

Wininspector screen shot of the button I need to read the mute state from is below. I still have no idea on how to read if the volume is muted or not. When you hover the button with your mouse, there is a tooltip... mute/unmute, but I can not extract that information with the window active, but not shown. Everything is suppose to happen whilst the game window is in focus.

 

CyUzRMi.png

 

@Masonjar13, thanks for that... I tried the script, but it failed to extract any text from the window. I have no idea how to extract the mute state from the volume mixer window... I've tried and tried and tried, with no success. :/

 

@Linear Spoon, thanks, but I don't want to double up on scripts/functions for now... I just want to extract the mute state within my own script.



Masonjar13
  • Members
  • 1517 posts
  • Last active:
  • Joined: 16 Sep 2012

Oh, now I'm remembering.... The mixer is the WORST to have to work with. After looking around the registry, I couldn't find anything on SndVol in terms of mute status. Since it carries cross-session, the data file has to be stored somewhere on the system. Find that file and you're good to go.

 

EDIT:
I keep finding references to places that don't seem to exist..

M.i.c.r.o.s.o.f.t.\.W.i.n.d.o.w.s.\.M.u.l.t.i.m.e.d.i.a

M.i.c.r.o.s.o.f.t.\.W.i.n.d.o.w.s. .A.u.d.i.o

S.o.f.t.w.a.r.e.\.M.i.c.r.o.s.o.f.t.\.M.u.l.t.i.m.e.d.i.a.\.A.u.d.i.o.\.S.n.d.V.o.l

c.o.n.t.r.o.l...e.x.e...m.m.s.y.s...c.p.l.,.,.%.s.,.g.e.n.e.r.a.l.......A.p.p.E.v.e.n.t.s.\.S.c.h.e.m.e.s.\.A.p.p.s.\...D.e.f.a.u.l.t.\...D.e.f.a.u.l.t.\...C.u.r.r.e.n.t

SndVol.pdb

 

Kind of just throwing info out there, seeing if it may help. If you want to keep looking, I left off on line 1002F, just throw SndVol into a hex editor.


OS: Windows 7 Ultimate / Windows 8.1 Pro | Editor: Notepad++


Linear Spoon
  • Members
  • 842 posts
  • Last active: Sep 29 2015 03:56 AM
  • Joined: 29 Oct 2011

 

@Linear Spoon, thanks, but I don't want to double up on scripts/functions for now... I just want to extract the mute state within my own script.

 

That's pretty much what the script I posted does. How would you toggle the mute state of a process if you couldn't extract it's current state? 


Join us at the new forum - http://www.ahkscript.org/

 


Masonjar13
  • Members
  • 1517 posts
  • Last active:
  • Joined: 16 Sep 2012

I've forgotten where this code came from, but I've used it in the past to detect mute states. Not sure how to get the volume level with it though. Requires VA.ahk.

#Include VA.ahk

!m::  ;Alt + m hotkey - toggle mute state of active window
  WinGet, ActivePid, PID, A
  if !(Volume := GetVolumeObject(ActivePid))
    MsgBox, There was a problem retrieving the application volume interface
  VA_ISimpleAudioVolume_GetMute(Volume, Mute)  ;Get mute state
  Msgbox % "Application " ActivePID " is currently " (mute ? "muted" : "not muted")
  VA_ISimpleAudioVolume_SetMute(Volume, !Mute) ;Toggle mute state
  ObjRelease(Volume)
return

;Required for app specific mute
GetVolumeObject(Param = 0)
{
    static IID_IASM2 := "{77AA99A0-1BD6-484F-8BC7-2C654C9A9B6F}"
    , IID_IASC2 := "{bfb7ff88-7239-4fc9-8fa2-07c950be9c6d}"
    , IID_ISAV := "{87CE5498-68D6-44E5-9215-6DA47EF883D8}"
    
    ; Get PID from process name
    if Param is not Integer
    {
        Process, Exist, %Param%
        Param := ErrorLevel
    }
    
    ; GetDefaultAudioEndpoint
    DAE := VA_GetDevice()
    
    ; activate the session manager
    VA_IMMDevice_Activate(DAE, IID_IASM2, 0, 0, IASM2)
    
    ; enumerate sessions for on this device
    VA_IAudioSessionManager2_GetSessionEnumerator(IASM2, IASE)
    VA_IAudioSessionEnumerator_GetCount(IASE, Count)
    
    ; search for an audio session with the required name
    Loop, % Count
    {
        ; Get the IAudioSessionControl object
        VA_IAudioSessionEnumerator_GetSession(IASE, A_Index-1, IASC)
        
        ; Query the IAudioSessionControl for an IAudioSessionControl2 object
        IASC2 := ComObjQuery(IASC, IID_IASC2)
        ObjRelease(IASC)
        
        ; Get the session's process ID
        VA_IAudioSessionControl2_GetProcessID(IASC2, SPID)
        
        ; If the process name is the one we are looking for
        if (SPID == Param)
        {
            ; Query for the ISimpleAudioVolume
            ISAV := ComObjQuery(IASC2, IID_ISAV)
            
            ObjRelease(IASC2)
            break
        }
        ObjRelease(IASC2)
    }
    ObjRelease(IASE)
    ObjRelease(IASM2)
    ObjRelease(DAE)
    return ISAV
}
 
;
; ISimpleAudioVolume : {87CE5498-68D6-44E5-9215-6DA47EF883D8}
;
VA_ISimpleAudioVolume_SetMasterVolume(this, ByRef fLevel, GuidEventContext="") {
    return DllCall(NumGet(NumGet(this+0)+3*A_PtrSize), "ptr", this, "float", fLevel, "ptr", VA_GUID(GuidEventContext))
}
VA_ISimpleAudioVolume_GetMasterVolume(this, ByRef fLevel) {
    return DllCall(NumGet(NumGet(this+0)+4*A_PtrSize), "ptr", this, "float*", fLevel)
}
VA_ISimpleAudioVolume_SetMute(this, ByRef Muted, GuidEventContext="") {
    return DllCall(NumGet(NumGet(this+0)+5*A_PtrSize), "ptr", this, "int", Muted, "ptr", VA_GUID(GuidEventContext))
}
VA_ISimpleAudioVolume_GetMute(this, ByRef Muted) {
    return DllCall(NumGet(NumGet(this+0)+6*A_PtrSize), "ptr", this, "int*", Muted)
}

Forget everything I said and use this. Works perfectly.

OS: Windows 7 Ultimate / Windows 8.1 Pro | Editor: Notepad++