; =============================================================================================================================== ; WebView2_Media_Browser.au3 - a small browser whose labels answer one question: what is this page doing with sound? ; ; Three bands of truth, from the cheapest to the most detailed: ; the sound band - $WV2_EVENT_PLAYING_AUDIO_CHANGED (18), the state the runtime reports for the whole document. ; No script, no click, nothing polled: the new state arrives inside the event. ; the element band - what the media element in the page says: playing, paused, stopped, ended, position, duration, ; volume, rate. WebView2 raises no event for an HTMLMediaElement, so one function is injected: ; it wires the element, pushes a marker to the host with postMessage, and the host then reads the ; whole state back through _WV2_ExecuteScript. ; the screen band - $WV2_EVENT_FULLSCREEN_CHANGED (20) and $WV2_EVENT_MUTED_CHANGED (19), the mute the host makes. ; ; The sound band and the element band disagree on purpose. A view the host muted is inaudible and still reports ; "audio playing", because Chromium keeps feeding a silent sink; a page whose own volume is 0 reports "no audio" while ; its element is "playing". Reading both is the only way to tell which of the two the user is complaining about. ; ; The start page is written into @TempDir with a real 440 Hz tone, so the labels have something to react to without ; going on the network. Its Play button is a real button: Chromium refuses sound before a user gesture, which is one ; more reason to hear about it from an event instead of asking. Run the file with --auto and it drives itself - ; mute, play, pause, stop, fullscreen - and prints PASS or FAIL; the test lifts the autoplay gate with a browser ; argument set before the view exists, because a script call is not a gesture. ; ; Exit code: the number of failures. --auto writes its log next to itself. ; =============================================================================================================================== #include #include "WebView2.au3" Opt("MustDeclareVars", 1) Opt("GUIOnEventMode", 1) Global Const $g_bAuto = (StringInStr($CmdLineRaw, "--auto") > 0) Global Const $g_iBandTop = 78 ; the three label rows above the page Global Const $g_iBandBot = 42 ; the two event rows below it Global Const $g_sTemp = @TempDir & "\WebView2_Media_Browser\" Global Const $g_sPage = $g_sTemp & "media.html" Global Const $g_sTone = $g_sTemp & "tone.wav" Global Const $g_sLog = @ScriptDir & "\WebView2_Media_Browser.log" Global $g_hGui = 0, $g_iWV = 0, $g_hLog = 0 Global $g_idBack = 0, $g_idFwd = 0, $g_idReload = 0, $g_idUrl = 0, $g_idGo = 0 Global $g_idAudio = 0, $g_idFs = 0, $g_idMute = 0, $g_idMedia = 0, $g_idProbe = 0 Global $g_idLine1 = 0, $g_idLine2 = 0 Global $g_sFirstUrl = "", $g_sBrowser = "" Global $g_sLine1 = "", $g_sLine2 = "" Global $g_bProbe = False, $g_bHasMedia = False Global $g_tProbe = 0, $g_tStart = 0 Global $g_iPass = 0, $g_iFail = 0 ; ---- the two files the start page needs, written fresh every run ---- Func _MakeTone($sPath) ; 8 kHz mono 16-bit, three seconds of 440 Hz. 16-bit PCM is signed and AutoIt has no signed 16-bit type, ; so a negative sample is written modulo 65536 - the same two bytes either way. Local Const $iRate = 8000, $n = $iRate * 3, $iAmp = 9000 Local $tH = DllStructCreate("char[4];dword;char[4];char[4];dword;word;word;dword;dword;word;word;char[4];dword") DllStructSetData($tH, 1, "RIFF") DllStructSetData($tH, 2, 36 + $n * 2) DllStructSetData($tH, 3, "WAVE") DllStructSetData($tH, 4, "fmt ") DllStructSetData($tH, 5, 16) DllStructSetData($tH, 6, 1) DllStructSetData($tH, 7, 1) DllStructSetData($tH, 8, $iRate) DllStructSetData($tH, 9, $iRate * 2) DllStructSetData($tH, 10, 2) DllStructSetData($tH, 11, 16) DllStructSetData($tH, 12, "data") DllStructSetData($tH, 13, $n * 2) Local $tS = DllStructCreate("word[" & $n & "]") Local $i, $v For $i = 1 To $n $v = Int($iAmp * Sin(2 * 3.141592653589793 * 440 * ($i - 1) / $iRate)) If $v < 0 Then $v += 65536 DllStructSetData($tS, 1, $v, $i) Next Local $bH = DllStructGetData(DllStructCreate("byte[" & DllStructGetSize($tH) & "]", DllStructGetPtr($tH)), 1) Local $bD = DllStructGetData(DllStructCreate("byte[" & $n * 2 & "]", DllStructGetPtr($tS)), 1) ; Mode 2: 8, 16 and 24 all refuse to create a file that is not there yet. Local $h = FileOpen($sPath, 2) If $h = -1 Then Return False FileWrite($h, $bH) FileWrite($h, $bD) FileClose($h) Return FileExists($sPath) And FileGetSize($sPath) = 44 + $n * 2 EndFunc ;==>_MakeTone Func _MakePage($sPath) Local $h = FileOpen($sPath, 2) If $h = -1 Then Return False FileWriteLine($h, 'start page') FileWriteLine($h, '') FileWriteLine($h, '
') FileWriteLine($h, '

Sound the labels can see

') FileWriteLine($h, '

Press Play. The band above this page reads the state the runtime reports.

') FileWriteLine($h, '') FileWriteLine($h, ' ') FileWriteLine($h, ' ') FileWriteLine($h, ' ') FileWriteLine($h, ' ') FileWriteLine($h, '') FileWriteLine($h, '
the full screen target
') FileWriteLine($h, '

') FileWriteLine($h, '
') FileClose($h) Return FileExists($sPath) EndFunc ;==>_MakePage ; ---- the injected half of the element band ---- ; One probe returns the whole state as one flat string (no JSON to parse on this side), and every state change ; of the element pushes a short marker. The observer is what keeps working on a site that rebuilds its player - ; YouTube replaces the video element between clips, and a listener wired once would simply stop reporting. Func _g_sInjectJs() Return _ '(function(){' & _ 'if(!window.__wvProbe){' & _ 'window.__wvProbe=function(){var v=document.querySelector("video")||document.querySelector("audio");' & _ 'if(!v)return "found=0";' & _ 'var d=(v.duration&&isFinite(v.duration))?Math.round(v.duration):0;' & _ 'return "found=1|paused="+(v.paused?1:0)+"|ended="+(v.ended?1:0)+"|ct="+Math.round(v.currentTime*10)/10' & _ '+"|dur="+d+"|vol="+Math.round((v.volume==null?1:v.volume)*100)+"|muted="+(v.muted?1:0)' & _ '+"|rate="+v.playbackRate+"|rs="+v.readyState+"|loop="+(v.loop?1:0);};' & _ 'window.__wvArm=function(){var e=document.querySelectorAll("video,audio");' & _ 'for(var i=0;i_g_sInjectJs Func _Probe() Local $sOut = "" _WV2_ExecuteScript($g_iWV, "window.__wvProbe()", $sOut, 6000) If @error Then Return "" Return StringStripWS(StringReplace($sOut, '"', ""), 3) EndFunc ;==>_Probe Func _ReArm() Local $sOut = "" _WV2_ExecuteScript($g_iWV, _g_sInjectJs(), $sOut, 8000) $g_bProbe = True Return $sOut EndFunc ;==>_ReArm Func _StateGet($sState, $sKey) Local $a = StringRegExp($sState, "(?:^|\|)" & $sKey & "=([^|]*)", 1) If @error Or Not IsArray($a) Then Return "" Return $a[0] EndFunc ;==>_StateGet Func _FmtSec($s) If $s = "" Then Return "?" If StringRight($s, 2) = ".0" Then $s = StringTrimRight($s, 2) Return $s & "s" EndFunc ;==>_FmtSec ; The flat string becomes the sentence the element band shows. "stopped" is what HTML calls a pause at 0, ; which is why the sound band and this band can never tell those two apart on their own. Func _DescribeMedia($sState) If $sState = "" Then Return "no answer from the page" If _StateGet($sState, "found") <> "1" Then Return "no media element on this page" Local $sCt = _StateGet($sState, "ct") Local $sOut If _StateGet($sState, "paused") = "0" Then $sOut = "playing" ElseIf $sCt = "0" Then $sOut = "stopped" ElseIf _StateGet($sState, "ended") = "1" Then $sOut = "ended" Else $sOut = "paused" EndIf $sOut &= " " & _FmtSec($sCt) & "/" & _FmtSec(_StateGet($sState, "dur")) $sOut &= " vol " & _StateGet($sState, "vol") & "%" $sOut &= " " & (_StateGet($sState, "muted") = "1" ? "element muted" : "element audible") If _StateGet($sState, "rate") <> "1" Then $sOut &= " x" & _StateGet($sState, "rate") If _StateGet($sState, "loop") = "1" Then $sOut &= " loop" $sOut &= " readyState " & _StateGet($sState, "rs") Return $sOut EndFunc ;==>_DescribeMedia ; ---- the bands ---- Func _SetAudioLabel($iValue) GUICtrlSetData($g_idAudio, ($iValue = 1) ? "audio playing" : "no audio") EndFunc ;==>_SetAudioLabel Func _SetFsLabel($iValue) GUICtrlSetData($g_idFs, ($iValue = 1) ? "full screen" : "windowed") EndFunc ;==>_SetFsLabel Func _SetMuteLabel() If $g_iWV = 0 Then Return GUICtrlSetData($g_idMute, (_WV2_IsMuted($g_iWV) = 1) ? "view muted" : "view audible") EndFunc ;==>_SetMuteLabel Func _SetMediaLabel($sState) GUICtrlSetData($g_idMedia, _DescribeMedia($sState)) EndFunc ;==>_SetMediaLabel Func _Note($sText) $g_sLine2 = $g_sLine1 $g_sLine1 = $sText GUICtrlSetData($g_idLine2, $g_sLine2) GUICtrlSetData($g_idLine1, $g_sLine1) EndFunc ;==>_Note Func _Log($s) FileWriteLine($g_hLog, StringFormat("%7.1f s %s", TimerDiff($g_tStart) / 1000, $s)) EndFunc ;==>_Log ; ---- the queue: the only place anything is read from the runtime ---- Func _HandleEvent($iEvent, ByRef $sData, ByRef $iValue) Switch $iEvent Case $WV2_EVENT_PLAYING_AUDIO_CHANGED _SetAudioLabel($iValue) _Note("event 18 PLAYING_AUDIO_CHANGED value=" & $iValue & " - the state came inside the event") Case $WV2_EVENT_MUTED_CHANGED _SetMuteLabel() _Note("event 19 MUTED_CHANGED value=" & $iValue) Case $WV2_EVENT_FULLSCREEN_CHANGED _SetFsLabel($iValue) _Note("event 20 FULLSCREEN_CHANGED value=" & $iValue) Case $WV2_EVENT_WEB_MESSAGE If StringLeft($sData, 6) = "media:" Then $g_bHasMedia = True $g_bProbe = True _Note("event 3 web message " & $sData & " - the page pushed the change") ElseIf $sData <> "" Then _Note("event 3 web message " & StringLeft($sData, 70)) EndIf Case $WV2_EVENT_NAVIGATION_COMPLETED $g_bHasMedia = False GUICtrlSetData($g_idMedia, "waiting for a media element") If $iValue = 1 Then _ReArm() _Note("event 2 navigation completed " & StringLeft($sData, 60)) Case $WV2_EVENT_TITLE_CHANGED WinSetTitle($g_hGui, "", "Media browser - " & $sData) Case $WV2_EVENT_NEW_WINDOW If $sData <> "" Then GUICtrlSetData($g_idUrl, $sData) _WV2_Navigate($g_iWV, $sData) EndIf Case Else Return False EndSwitch Return True EndFunc ;==>_HandleEvent Func _Pump() Local $sData = "", $iValue = 0, $iEvent While 1 $iEvent = _WV2_GetEvent($g_iWV, $sData, $iValue) If $iEvent <= 0 Then ExitLoop _HandleEvent($iEvent, $sData, $iValue) WEnd ; The position of a media element moves with no event at all, so the element band is refreshed once a ; second - and only while this page has an element to ask. A marker from the page probes immediately. If $g_bProbe Or ($g_bHasMedia And TimerDiff($g_tProbe) > 1000) Then $g_bProbe = False $g_tProbe = TimerInit() Local $sState = _Probe() If $sState <> "" Then If _StateGet($sState, "found") = "1" Then $g_bHasMedia = True _SetMediaLabel($sState) EndIf EndIf EndFunc ;==>_Pump ; ---- toolbar ---- Func _Layout() Local $aC = WinGetClientSize($g_hGui) If @error Or Not IsArray($aC) Or $aC[0] <= 0 Then Return Local $iW = $aC[0], $iH = $aC[1] GUICtrlSetPos($g_idUrl, 214, 6, $iW - 214 - 196, 24) GUICtrlSetPos($g_idGo, $iW - 188, 6, 44, 24) GUICtrlSetPos($g_idProbe, $iW - 140, 6, 132, 24) GUICtrlSetPos($g_idMedia, 52, 58, $iW - 60, 16) GUICtrlSetPos($g_idLine1, 8, $iH - 38, $iW - 16, 16) GUICtrlSetPos($g_idLine2, 8, $iH - 20, $iW - 16, 16) _WV2_SetBounds($g_iWV, 0, $g_iBandTop, $iW, $iH - $g_iBandTop - $g_iBandBot) EndFunc ;==>_Layout Func _OnBack() _WV2_GoBack($g_iWV) EndFunc ;==>_OnBack Func _OnFwd() _WV2_GoForward($g_iWV) EndFunc ;==>_OnFwd Func _OnReload() _WV2_Reload($g_iWV) EndFunc ;==>_OnReload Func _OnGo() Local $sUrl = StringStripWS(GUICtrlRead($g_idUrl), 3) If $sUrl = "" Then Return If StringInStr($sUrl, "://") = 0 And StringLeft($sUrl, 11) <> "javascript:" Then $sUrl = "https://" & $sUrl _WV2_Navigate($g_iWV, $sUrl) EndFunc ;==>_OnGo Func _OnProbe() $g_bProbe = True EndFunc ;==>_OnProbe Func _OnResize() _Layout() EndFunc ;==>_OnResize Func _OnClose() _Pump() ; The window goes first: the browser needs a moment to leave and an empty frame reads as a freeze. GUISetState(@SW_HIDE, $g_hGui) _WV2_Destroy($g_iWV) $g_iWV = 0 GUIDelete($g_hGui) Exit 0 EndFunc ;==>_OnClose ; ---- build the window, the view and the six kinds it lives on ---- Func _Start($sFirstUrl) $g_hGui = GUICreate("Media browser", 1100, 720) $g_idBack = GUICtrlCreateButton("<-", 8, 6, 48, 24) $g_idFwd = GUICtrlCreateButton("->", 60, 6, 48, 24) $g_idReload = GUICtrlCreateButton("reload", 112, 6, 60, 24) $g_idUrl = GUICtrlCreateInput($sFirstUrl, 214, 6, 680, 24) $g_idGo = GUICtrlCreateButton("Go", 902, 6, 44, 24) $g_idProbe = GUICtrlCreateButton("read element", 952, 6, 132, 24) GUICtrlCreateLabel("sound:", 8, 38, 42, 16) $g_idAudio = GUICtrlCreateLabel("no audio", 50, 38, 100, 16) GUICtrlCreateLabel("screen:", 158, 38, 46, 16) $g_idFs = GUICtrlCreateLabel("windowed", 204, 38, 80, 16) GUICtrlCreateLabel("view:", 292, 38, 30, 16) $g_idMute = GUICtrlCreateLabel("view audible", 322, 38, 90, 16) GUICtrlCreateLabel("element:", 8, 58, 44, 16) $g_idMedia = GUICtrlCreateLabel("waiting for a media element", 52, 58, 1040, 16) $g_idLine1 = GUICtrlCreateLabel("", 8, 678, 1084, 16) $g_idLine2 = GUICtrlCreateLabel("", 8, 700, 1084, 16) GUISetOnEvent($GUI_EVENT_CLOSE, "_OnClose") GUISetOnEvent($GUI_EVENT_RESIZED, "_OnResize") GUISetOnEvent($GUI_EVENT_MAXIMIZE, "_OnResize") GUISetOnEvent($GUI_EVENT_RESTORE, "_OnResize") GUICtrlSetOnEvent($g_idBack, "_OnBack") GUICtrlSetOnEvent($g_idFwd, "_OnFwd") GUICtrlSetOnEvent($g_idReload, "_OnReload") GUICtrlSetOnEvent($g_idGo, "_OnGo") GUICtrlSetOnEvent($g_idUrl, "_OnGo") GUICtrlSetOnEvent($g_idProbe, "_OnProbe") GUISetState(@SW_SHOW, $g_hGui) Local $aC = WinGetClientSize($g_hGui) $g_iWV = _WV2_Create($g_hGui, 0, $g_iBandTop, $aC[0], $aC[1] - $g_iBandTop - $g_iBandBot, "", 120000) If $g_iWV = 0 Then Return False _WV2_EnableEvent($g_iWV, $WV2_EVENT_PLAYING_AUDIO_CHANGED) _WV2_EnableEvent($g_iWV, $WV2_EVENT_MUTED_CHANGED) _WV2_EnableEvent($g_iWV, $WV2_EVENT_FULLSCREEN_CHANGED) _WV2_EnableEvent($g_iWV, $WV2_EVENT_WEB_MESSAGE) _WV2_EnableEvent($g_iWV, $WV2_EVENT_NAVIGATION_COMPLETED) _WV2_EnableEvent($g_iWV, $WV2_EVENT_TITLE_CHANGED) ; Left alone, a target="_blank" link opens a window of its own, outside this toolbar and its history. _WV2_EnableEvent($g_iWV, $WV2_EVENT_NEW_WINDOW) _WV2_SetVisible($g_iWV, False) _WV2_Navigate($g_iWV, $sFirstUrl) _WV2_WaitNavigation($g_iWV, 60000) _WV2_SetVisible($g_iWV, True) ; The navigation-completed event may not be queued yet when the wait returns, so the page is armed here as ; well; the wiring is guarded by a flag inside the page and costs nothing the second time. _ReArm() _Layout() _SetAudioLabel(_WV2_IsPlayingAudio($g_iWV)) _SetFsLabel(_WV2_IsFullScreen($g_iWV)) _SetMuteLabel() $g_tProbe = TimerInit() Return True EndFunc ;==>_Start ; =============================================================================================================================== ; Body ; =============================================================================================================================== DirCreate($g_sTemp) $g_hLog = FileOpen($g_sLog, 2) $g_tStart = TimerInit() If Not _MakeTone($g_sTone) Then _Log("tone not written") If Not _MakePage($g_sPage) Then _Log("page not written") ; The autoplay gate has to be lifted before the browser process exists, and only for the test: the interactive ; mode keeps Chromium's real rule, where a click is what makes sound allowed. If $g_bAuto Then EnvSet("WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS", "--autoplay-policy=no-user-gesture-required") $g_sFirstUrl = "file:///" & StringReplace($g_sPage, "\", "/") If Not _Start($g_sFirstUrl) Then _Log("FATAL the view could not be created: " & _WV2_GetLastErrorMessage()) FileClose($g_hLog) Exit 99 EndIf $g_sBrowser = "" _WV2_GetBrowserVersion($g_iWV, $g_sBrowser) _Log(($g_bAuto ? "auto" : "interactive") & " run, browser " & $g_sBrowser) If $g_bAuto Then _AutoRun() Else While 1 _Pump() Sleep(40) WEnd EndIf ; =============================================================================================================================== ; --auto: the same labels, driven without a hand on the mouse. ; =============================================================================================================================== ; Read the queue until one kind arrives. Anything else that turns up goes through the same handler, so the ; bands stay in step with what the run is doing. Func _WaitForEvent($iEvent, $iMs, ByRef $sData, ByRef $iValue) Local $iT = TimerInit(), $iRc While TimerDiff($iT) < $iMs $iRc = _WV2_GetEvent($g_iWV, $sData, $iValue) If $iRc > 0 Then ; Whatever arrived goes through the same handler the interactive loop uses - including the kind ; this wait was looking for. Skipping it would empty the queue and leave the band unmoved, and ; the check would then pass on a label that never changed. _HandleEvent($iRc, $sData, $iValue) If $iRc = $iEvent Then Return 1 ContinueLoop EndIf Sleep(20) WEnd Return 0 EndFunc ;==>_WaitForEvent Func _Chk($sName, $bOk, $sDetail) If $bOk Then $g_iPass += 1 _Log("PASS " & $sName & " - " & $sDetail) Else $g_iFail += 1 _Log("FAIL " & $sName & " - " & $sDetail) EndIf EndFunc ;==>_Chk Func _Exec($sScript) Local $sOut = "" _WV2_ExecuteScript($g_iWV, $sScript, $sOut, 8000) Return $sOut EndFunc ;==>_Exec Func _AutoRun() Local $sData = "", $iValue = 0, $sState, $sLabel ; 1 - the start page and the injected probe. _Pump() $sState = _Probe() _Chk("element found on the start page", StringLeft($sState, 8) = "found=1|", "probe = " & $sState) $sLabel = GUICtrlRead($g_idMedia) _Chk("element band describes it", StringLeft($sLabel, 7) = "stopped", "band = " & $sLabel) ; 2 - Gianni's case at rest: the runtime itself says nothing plays. $iValue = _WV2_IsPlayingAudio($g_iWV) _Chk("no audio at rest", $iValue = 0, "IsPlayingAudio=" & $iValue) _Chk("sound band reads no audio", GUICtrlRead($g_idAudio) = "no audio", "band = " & GUICtrlRead($g_idAudio)) ; 3 - the host mutes the view, and the band moves because of the event. _WV2_SetMuted($g_iWV, True) _Chk("mute event carries 1", _WaitForEvent($WV2_EVENT_MUTED_CHANGED, 8000, $sData, $iValue) And $iValue = 1, "value=" & $iValue) _Chk("view band reads muted", GUICtrlRead($g_idMute) = "view muted", "band = " & GUICtrlRead($g_idMute)) ; 4 - play from the script. This is the release in one line: the state arrives by itself. _Exec("tone()") _Chk("playing event carries 1", _WaitForEvent($WV2_EVENT_PLAYING_AUDIO_CHANGED, 15000, $sData, $iValue) And $iValue = 1, "value=" & $iValue) _Chk("sound band flipped", GUICtrlRead($g_idAudio) = "audio playing", "band = " & GUICtrlRead($g_idAudio)) _Chk("state survives the host mute", _WV2_IsPlayingAudio($g_iWV) = 1, "the silent sink keeps the document audible") ; 5 - the element band, with the position no runtime event ever raises. $sState = _Probe() _Chk("element band reads playing", StringInStr($sState, "paused=0") > 0, "probe = " & $sState) _SetMediaLabel($sState) _Chk("element band says playing", StringLeft(GUICtrlRead($g_idMedia), 8) = "playing ", "band = " & GUICtrlRead($g_idMedia)) ; 6 - pause: the page pushes the marker, then the document state goes to 0. _Exec("hush()") _Chk("page pushed the pause", _WaitForEvent($WV2_EVENT_WEB_MESSAGE, 8000, $sData, $iValue) And _ StringLeft($sData, 11) = "media:pause", "message = " & $sData) _Chk("no-audio event carries 0", _WaitForEvent($WV2_EVENT_PLAYING_AUDIO_CHANGED, 15000, $sData, $iValue) And $iValue = 0, "value=" & $iValue) _Chk("sound band back to no audio", GUICtrlRead($g_idAudio) = "no audio", "band = " & GUICtrlRead($g_idAudio)) ; 7 - stop is a pause at 0. The sound band cannot tell the two apart; the element band can. _Exec("stopper()") $sState = _Probe() _Chk("stopped reads as position 0", StringInStr($sState, "|paused=1|") > 0 And _StateGet($sState, "ct") = "0", _ "probe = " & $sState) _Chk("element band says stopped", StringLeft(_DescribeMedia($sState), 7) = "stopped", "band = " & _DescribeMedia($sState)) ; 8 - the screen band, on the box the page owns. _Exec("fs()") _Chk("fullscreen event carries 1", _WaitForEvent($WV2_EVENT_FULLSCREEN_CHANGED, 12000, $sData, $iValue) And $iValue = 1, "value=" & $iValue) _Chk("screen band flipped", GUICtrlRead($g_idFs) = "full screen", "band = " & GUICtrlRead($g_idFs)) _Exec("exitfs()") _Chk("fullscreen event carries 0", _WaitForEvent($WV2_EVENT_FULLSCREEN_CHANGED, 12000, $sData, $iValue) And $iValue = 0, "value=" & $iValue) _Chk("screen band back to windowed", GUICtrlRead($g_idFs) = "windowed", "band = " & GUICtrlRead($g_idFs)) ; 9 - the host unmutes, and the two bands are in agreement again. _WV2_SetMuted($g_iWV, False) _Chk("unmute event carries 0", _WaitForEvent($WV2_EVENT_MUTED_CHANGED, 8000, $sData, $iValue) And $iValue = 0, "value=" & $iValue) _Chk("view band reads audible", GUICtrlRead($g_idMute) = "view audible", "band = " & GUICtrlRead($g_idMute)) ; 10 - teardown. _Pump() _Chk("destroy", _WV2_Destroy($g_iWV) = 1, "err=" & @error) $g_iWV = 0 GUIDelete($g_hGui) _Log("Media browser auto: " & $g_iPass & " passed, " & $g_iFail & " failed in " & _ StringFormat("%.1f", TimerDiff($g_tStart) / 1000) & " s") ConsoleWrite($g_iPass & " passed, " & $g_iFail & " failed" & @CRLF) FileClose($g_hLog) Exit $g_iFail EndFunc ;==>_AutoRun