From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- .../tabMediaIndicator/almostSilentAudioTrack.webm | Bin 0 -> 1699661 bytes .../base/content/test/tabMediaIndicator/audio.ogg | Bin 0 -> 14293 bytes .../tabMediaIndicator/audioEndedDuringPlaying.webm | Bin 0 -> 109366 bytes .../content/test/tabMediaIndicator/browser.ini | 33 +++ .../tabMediaIndicator/browser_destroy_iframe.js | 50 ++++ .../tabMediaIndicator/browser_mediaPlayback.js | 42 ++++ .../browser_mediaPlayback_mute.js | 118 ++++++++++ .../browser_mediaplayback_audibility_change.js | 258 +++++++++++++++++++++ .../content/test/tabMediaIndicator/browser_mute.js | 19 ++ .../test/tabMediaIndicator/browser_mute2.js | 32 +++ .../tabMediaIndicator/browser_mute_webAudio.js | 75 ++++++ .../browser_sound_indicator_silent_video.js | 88 +++++++ .../browser_webAudio_hideSoundPlayingIcon.js | 60 +++++ .../browser_webAudio_silentData.js | 57 +++++ .../browser_webaudio_audibility_change.js | 172 ++++++++++++++ .../file_almostSilentAudioTrack.html | 18 ++ .../tabMediaIndicator/file_autoplay_media.html | 9 + .../content/test/tabMediaIndicator/file_empty.html | 8 + .../test/tabMediaIndicator/file_mediaPlayback.html | 9 + .../tabMediaIndicator/file_mediaPlayback2.html | 14 ++ .../tabMediaIndicator/file_mediaPlaybackFrame.html | 2 + .../file_mediaPlaybackFrame2.html | 2 + .../tabMediaIndicator/file_silentAudioTrack.html | 18 ++ .../test/tabMediaIndicator/file_webAudio.html | 29 +++ .../base/content/test/tabMediaIndicator/gizmo.mp4 | Bin 0 -> 455255 bytes .../base/content/test/tabMediaIndicator/head.js | 158 +++++++++++++ .../content/test/tabMediaIndicator/noaudio.webm | Bin 0 -> 105755 bytes .../test/tabMediaIndicator/silentAudioTrack.webm | Bin 0 -> 224800 bytes 28 files changed, 1271 insertions(+) create mode 100644 browser/base/content/test/tabMediaIndicator/almostSilentAudioTrack.webm create mode 100644 browser/base/content/test/tabMediaIndicator/audio.ogg create mode 100644 browser/base/content/test/tabMediaIndicator/audioEndedDuringPlaying.webm create mode 100644 browser/base/content/test/tabMediaIndicator/browser.ini create mode 100644 browser/base/content/test/tabMediaIndicator/browser_destroy_iframe.js create mode 100644 browser/base/content/test/tabMediaIndicator/browser_mediaPlayback.js create mode 100644 browser/base/content/test/tabMediaIndicator/browser_mediaPlayback_mute.js create mode 100644 browser/base/content/test/tabMediaIndicator/browser_mediaplayback_audibility_change.js create mode 100644 browser/base/content/test/tabMediaIndicator/browser_mute.js create mode 100644 browser/base/content/test/tabMediaIndicator/browser_mute2.js create mode 100644 browser/base/content/test/tabMediaIndicator/browser_mute_webAudio.js create mode 100644 browser/base/content/test/tabMediaIndicator/browser_sound_indicator_silent_video.js create mode 100644 browser/base/content/test/tabMediaIndicator/browser_webAudio_hideSoundPlayingIcon.js create mode 100644 browser/base/content/test/tabMediaIndicator/browser_webAudio_silentData.js create mode 100644 browser/base/content/test/tabMediaIndicator/browser_webaudio_audibility_change.js create mode 100644 browser/base/content/test/tabMediaIndicator/file_almostSilentAudioTrack.html create mode 100644 browser/base/content/test/tabMediaIndicator/file_autoplay_media.html create mode 100644 browser/base/content/test/tabMediaIndicator/file_empty.html create mode 100644 browser/base/content/test/tabMediaIndicator/file_mediaPlayback.html create mode 100644 browser/base/content/test/tabMediaIndicator/file_mediaPlayback2.html create mode 100644 browser/base/content/test/tabMediaIndicator/file_mediaPlaybackFrame.html create mode 100644 browser/base/content/test/tabMediaIndicator/file_mediaPlaybackFrame2.html create mode 100644 browser/base/content/test/tabMediaIndicator/file_silentAudioTrack.html create mode 100644 browser/base/content/test/tabMediaIndicator/file_webAudio.html create mode 100644 browser/base/content/test/tabMediaIndicator/gizmo.mp4 create mode 100644 browser/base/content/test/tabMediaIndicator/head.js create mode 100644 browser/base/content/test/tabMediaIndicator/noaudio.webm create mode 100644 browser/base/content/test/tabMediaIndicator/silentAudioTrack.webm (limited to 'browser/base/content/test/tabMediaIndicator') diff --git a/browser/base/content/test/tabMediaIndicator/almostSilentAudioTrack.webm b/browser/base/content/test/tabMediaIndicator/almostSilentAudioTrack.webm new file mode 100644 index 0000000000..0b8f8f746f Binary files /dev/null and b/browser/base/content/test/tabMediaIndicator/almostSilentAudioTrack.webm differ diff --git a/browser/base/content/test/tabMediaIndicator/audio.ogg b/browser/base/content/test/tabMediaIndicator/audio.ogg new file mode 100644 index 0000000000..bed764fbf1 Binary files /dev/null and b/browser/base/content/test/tabMediaIndicator/audio.ogg differ diff --git a/browser/base/content/test/tabMediaIndicator/audioEndedDuringPlaying.webm b/browser/base/content/test/tabMediaIndicator/audioEndedDuringPlaying.webm new file mode 100644 index 0000000000..4f82b5da76 Binary files /dev/null and b/browser/base/content/test/tabMediaIndicator/audioEndedDuringPlaying.webm differ diff --git a/browser/base/content/test/tabMediaIndicator/browser.ini b/browser/base/content/test/tabMediaIndicator/browser.ini new file mode 100644 index 0000000000..a2ebf058fc --- /dev/null +++ b/browser/base/content/test/tabMediaIndicator/browser.ini @@ -0,0 +1,33 @@ +[DEFAULT] +subsuite = media-bc +tags = audiochannel +support-files = + almostSilentAudioTrack.webm + audio.ogg + audioEndedDuringPlaying.webm + file_almostSilentAudioTrack.html + file_autoplay_media.html + file_empty.html + file_mediaPlayback.html + file_mediaPlayback2.html + file_mediaPlaybackFrame.html + file_mediaPlaybackFrame2.html + file_silentAudioTrack.html + file_webAudio.html + gizmo.mp4 + head.js + noaudio.webm + silentAudioTrack.webm + +[browser_destroy_iframe.js] +https_first_disabled = true +[browser_mediaPlayback.js] +[browser_mediaPlayback_mute.js] +[browser_mediaplayback_audibility_change.js] +[browser_mute.js] +[browser_mute2.js] +[browser_mute_webAudio.js] +[browser_sound_indicator_silent_video.js] +[browser_webAudio_hideSoundPlayingIcon.js] +[browser_webAudio_silentData.js] +[browser_webaudio_audibility_change.js] diff --git a/browser/base/content/test/tabMediaIndicator/browser_destroy_iframe.js b/browser/base/content/test/tabMediaIndicator/browser_destroy_iframe.js new file mode 100644 index 0000000000..f977d1d664 --- /dev/null +++ b/browser/base/content/test/tabMediaIndicator/browser_destroy_iframe.js @@ -0,0 +1,50 @@ +const EMPTY_PAGE_URL = GetTestWebBasedURL("file_empty.html"); +const AUTPLAY_PAGE_URL = GetTestWebBasedURL("file_autoplay_media.html"); +const CORS_AUTPLAY_PAGE_URL = GetTestWebBasedURL( + "file_autoplay_media.html", + true +); + +/** + * When an iframe that has audible media gets destroyed, if there is no other + * audible playing media existing in the page, then the sound indicator should + * disappear. + */ +add_task(async function testDestroyAudibleIframe() { + const iframesURL = [AUTPLAY_PAGE_URL, CORS_AUTPLAY_PAGE_URL]; + for (let iframeURL of iframesURL) { + info(`open a tab, create an iframe and load an autoplay media page inside`); + const tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + EMPTY_PAGE_URL + ); + await createIframeAndLoadURL(tab, iframeURL); + + info(`sound indicator should appear because of audible playing media`); + await waitForTabSoundIndicatorAppears(tab); + + info(`sound indicator should disappear after destroying iframe`); + await removeIframe(tab); + await waitForTabSoundIndicatorDisappears(tab); + + info("remove tab"); + BrowserTestUtils.removeTab(tab); + } +}); + +function createIframeAndLoadURL(tab, url) { + // eslint-disable-next-line no-shadow + return SpecialPowers.spawn(tab.linkedBrowser, [url], async url => { + const iframe = content.document.createElement("iframe"); + content.document.body.appendChild(iframe); + iframe.src = url; + info(`load ${url} for iframe`); + await new Promise(r => (iframe.onload = r)); + }); +} + +function removeIframe(tab) { + return SpecialPowers.spawn(tab.linkedBrowser, [], _ => { + content.document.getElementsByTagName("iframe")[0].remove(); + }); +} diff --git a/browser/base/content/test/tabMediaIndicator/browser_mediaPlayback.js b/browser/base/content/test/tabMediaIndicator/browser_mediaPlayback.js new file mode 100644 index 0000000000..9a5f457403 --- /dev/null +++ b/browser/base/content/test/tabMediaIndicator/browser_mediaPlayback.js @@ -0,0 +1,42 @@ +const PAGE = GetTestWebBasedURL("file_mediaPlayback.html"); +const FRAME = GetTestWebBasedURL("file_mediaPlaybackFrame.html"); + +function wait_for_event(browser, event) { + return BrowserTestUtils.waitForEvent(browser, event, false, e => { + is( + e.originalTarget, + browser, + "Event must be dispatched to correct browser." + ); + ok(!e.cancelable, "The event should not be cancelable"); + return true; + }); +} + +async function test_on_browser(url, browser) { + info(`run test for ${url}`); + const startPromise = wait_for_event(browser, "DOMAudioPlaybackStarted"); + BrowserTestUtils.loadURIString(browser, url); + await startPromise; + await wait_for_event(browser, "DOMAudioPlaybackStopped"); +} + +add_task(async function test_page() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: "about:blank", + }, + test_on_browser.bind(undefined, PAGE) + ); +}); + +add_task(async function test_frame() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: "about:blank", + }, + test_on_browser.bind(undefined, FRAME) + ); +}); diff --git a/browser/base/content/test/tabMediaIndicator/browser_mediaPlayback_mute.js b/browser/base/content/test/tabMediaIndicator/browser_mediaPlayback_mute.js new file mode 100644 index 0000000000..05999a37cd --- /dev/null +++ b/browser/base/content/test/tabMediaIndicator/browser_mediaPlayback_mute.js @@ -0,0 +1,118 @@ +const PAGE = GetTestWebBasedURL("file_mediaPlayback2.html"); +const FRAME = GetTestWebBasedURL("file_mediaPlaybackFrame2.html"); + +function wait_for_event(browser, event) { + return BrowserTestUtils.waitForEvent(browser, event, false, e => { + is( + e.originalTarget, + browser, + "Event must be dispatched to correct browser." + ); + return true; + }); +} + +function test_audio_in_browser() { + function get_audio_element() { + var doc = content.document; + var list = doc.getElementsByTagName("audio"); + if (list.length == 1) { + return list[0]; + } + + // iframe? + list = doc.getElementsByTagName("iframe"); + + var iframe = list[0]; + list = iframe.contentDocument.getElementsByTagName("audio"); + return list[0]; + } + + var audio = get_audio_element(); + return { + computedVolume: audio.computedVolume, + computedMuted: audio.computedMuted, + }; +} + +async function test_on_browser(url, browser) { + BrowserTestUtils.loadURIString(browser, url); + await wait_for_event(browser, "DOMAudioPlaybackStarted"); + + var result = await SpecialPowers.spawn(browser, [], test_audio_in_browser); + is(result.computedVolume, 1, "Audio volume is 1"); + is(result.computedMuted, false, "Audio is not muted"); + + ok(!browser.audioMuted, "Audio should not be muted by default"); + browser.mute(); + ok(browser.audioMuted, "Audio should be muted now"); + + await wait_for_event(browser, "DOMAudioPlaybackStopped"); + + result = await SpecialPowers.spawn(browser, [], test_audio_in_browser); + is(result.computedVolume, 0, "Audio volume is 0 when muted"); + is(result.computedMuted, true, "Audio is muted"); +} + +async function test_visibility(url, browser) { + BrowserTestUtils.loadURIString(browser, url); + await wait_for_event(browser, "DOMAudioPlaybackStarted"); + + var result = await SpecialPowers.spawn(browser, [], test_audio_in_browser); + is(result.computedVolume, 1, "Audio volume is 1"); + is(result.computedMuted, false, "Audio is not muted"); + + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: "about:blank", + }, + function () {} + ); + + ok(!browser.audioMuted, "Audio should not be muted by default"); + browser.mute(); + ok(browser.audioMuted, "Audio should be muted now"); + + await wait_for_event(browser, "DOMAudioPlaybackStopped"); + + result = await SpecialPowers.spawn(browser, [], test_audio_in_browser); + is(result.computedVolume, 0, "Audio volume is 0 when muted"); + is(result.computedMuted, true, "Audio is muted"); +} + +add_task(async function () { + await SpecialPowers.pushPrefEnv({ + set: [["media.useAudioChannelService.testing", true]], + }); +}); + +add_task(async function test_page() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: "about:blank", + }, + test_on_browser.bind(undefined, PAGE) + ); +}); + +add_task(async function test_frame() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: "about:blank", + }, + test_on_browser.bind(undefined, FRAME) + ); +}); + +add_task(async function test_frame() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: "about:blank", + }, + test_visibility.bind(undefined, PAGE) + ); +}); diff --git a/browser/base/content/test/tabMediaIndicator/browser_mediaplayback_audibility_change.js b/browser/base/content/test/tabMediaIndicator/browser_mediaplayback_audibility_change.js new file mode 100644 index 0000000000..87186ca838 --- /dev/null +++ b/browser/base/content/test/tabMediaIndicator/browser_mediaplayback_audibility_change.js @@ -0,0 +1,258 @@ +/** + * When media changes its audible state, the sound indicator should be + * updated as well, which should appear only when web audio is audible. + */ +add_task(async function testUpdateSoundIndicatorWhenMediaPlaybackChanges() { + info("create a tab loading media document"); + const tab = await createBlankForegroundTab(); + await initMediaPlaybackDocument(tab, "audio.ogg"); + + info(`sound indicator should appear when audible audio starts playing`); + await playMedia(tab); + await waitForTabSoundIndicatorAppears(tab); + + info(`sound indicator should disappear when audio stops playing`); + await pauseMedia(tab); + await waitForTabSoundIndicatorDisappears(tab); + + info("remove tab"); + BrowserTestUtils.removeTab(tab); +}); + +add_task(async function testUpdateSoundIndicatorWhenMediaBecomeSilent() { + info("create a tab loading media document"); + const tab = await createBlankForegroundTab(); + await initMediaPlaybackDocument(tab, "audioEndedDuringPlaying.webm"); + + info(`sound indicator should appear when audible audio starts playing`); + await playMedia(tab); + await waitForTabSoundIndicatorAppears(tab); + + info(`sound indicator should disappear when audio becomes silent`); + await waitForTabSoundIndicatorDisappears(tab); + + info("remove tab"); + BrowserTestUtils.removeTab(tab); +}); + +add_task(async function testSoundIndicatorWouldWorkForMediaWithoutPreload() { + info("create a tab loading media document"); + const tab = await createBlankForegroundTab(); + await initMediaPlaybackDocument(tab, "audio.ogg", { preload: "none" }); + + info(`sound indicator should appear when audible audio starts playing`); + await playMedia(tab); + await waitForTabSoundIndicatorAppears(tab); + + info(`sound indicator should disappear when audio stops playing`); + await pauseMedia(tab); + await waitForTabSoundIndicatorDisappears(tab); + + info("remove tab"); + BrowserTestUtils.removeTab(tab); +}); + +add_task(async function testSoundIndicatorShouldDisappearAfterTabNavigation() { + info("create a tab loading media document"); + const tab = await createBlankForegroundTab(); + await initMediaPlaybackDocument(tab, "audio.ogg"); + + info(`sound indicator should appear when audible audio starts playing`); + await playMedia(tab); + await waitForTabSoundIndicatorAppears(tab); + + info(`sound indicator should disappear after navigating tab to blank page`); + BrowserTestUtils.loadURIString(tab.linkedBrowser, "about:blank"); + await waitForTabSoundIndicatorDisappears(tab); + + info("remove tab"); + BrowserTestUtils.removeTab(tab); +}); + +add_task(async function testSoundIndicatorForAudioStream() { + info("create a tab loading media document"); + const tab = await createBlankForegroundTab(); + await initMediaStreamPlaybackDocument(tab); + + info(`sound indicator should appear when audible audio starts playing`); + await playMedia(tab); + await waitForTabSoundIndicatorAppears(tab); + + info(`sound indicator should disappear when audio stops playing`); + await pauseMedia(tab); + await waitForTabSoundIndicatorDisappears(tab); + + info("remove tab"); + BrowserTestUtils.removeTab(tab); +}); + +add_task(async function testPerformPlayOnMediaLoadingNewSource() { + info("create a tab loading media document"); + const tab = await createBlankForegroundTab(); + await initMediaPlaybackDocument(tab, "audio.ogg"); + + info(`sound indicator should appear when audible audio starts playing`); + await playMedia(tab); + await waitForTabSoundIndicatorAppears(tab); + + info(`sound indicator should disappear when audio stops playing`); + await pauseMedia(tab); + await waitForTabSoundIndicatorDisappears(tab); + + info(`reset media src and play it again should make sound indicator appear`); + await assignNewSourceForAudio(tab, "audio.ogg"); + await playMedia(tab); + await waitForTabSoundIndicatorAppears(tab); + + info("remove tab"); + BrowserTestUtils.removeTab(tab); +}); + +add_task(async function testSoundIndicatorShouldDisappearWhenAbortingMedia() { + info("create a tab loading media document"); + const tab = await createBlankForegroundTab(); + await initMediaPlaybackDocument(tab, "audio.ogg"); + + info(`sound indicator should appear when audible audio starts playing`); + await playMedia(tab); + await waitForTabSoundIndicatorAppears(tab); + + info(`sound indicator should disappear when aborting audio source`); + await assignNewSourceForAudio(tab, ""); + await waitForTabSoundIndicatorDisappears(tab); + + info("remove tab"); + BrowserTestUtils.removeTab(tab); +}); + +add_task(async function testNoSoundIndicatorForMediaWithoutAudioTrack() { + info("create a tab loading media document"); + const tab = await createBlankForegroundTab({ needObserver: true }); + await initMediaPlaybackDocument(tab, "noaudio.webm", { createVideo: true }); + + info(`no sound indicator should show for playing media without audio track`); + await playMedia(tab, { resolveOnTimeupdate: true }); + ok(!tab.observer.hasEverUpdated(), "didn't ever update sound indicator"); + + info("remove tab"); + BrowserTestUtils.removeTab(tab); +}); + +add_task(async function testSoundIndicatorWhenChangingMediaMuted() { + info("create a tab loading media document"); + const tab = await createBlankForegroundTab({ needObserver: true }); + await initMediaPlaybackDocument(tab, "audio.ogg", { muted: true }); + + info(`no sound indicator should show for playing muted media`); + await playMedia(tab, { resolveOnTimeupdate: true }); + ok(!tab.observer.hasEverUpdated(), "didn't ever update sound indicator"); + + info(`unmuted media should make sound indicator appear`); + await Promise.all([ + waitForTabSoundIndicatorAppears(tab), + updateMedia(tab, { muted: false }), + ]); + + info("remove tab"); + BrowserTestUtils.removeTab(tab); +}); + +add_task(async function testSoundIndicatorWhenChangingMediaVolume() { + info("create a tab loading media document"); + const tab = await createBlankForegroundTab({ needObserver: true }); + await initMediaPlaybackDocument(tab, "audio.ogg", { volume: 0.0 }); + + info(`no sound indicator should show for playing volume zero media`); + await playMedia(tab, { resolveOnTimeupdate: true }); + ok(!tab.observer.hasEverUpdated(), "didn't ever update sound indicator"); + + info(`unmuted media by setting volume should make sound indicator appear`); + await Promise.all([ + waitForTabSoundIndicatorAppears(tab), + updateMedia(tab, { volume: 1.0 }), + ]); + + info("remove tab"); + BrowserTestUtils.removeTab(tab); +}); + +/** + * Following are helper functions + */ +function initMediaPlaybackDocument( + tab, + fileName, + { preload, createVideo, muted = false, volume = 1.0 } = {} +) { + return SpecialPowers.spawn( + tab.linkedBrowser, + [fileName, preload, createVideo, muted, volume], + // eslint-disable-next-line no-shadow + async (fileName, preload, createVideo, muted, volume) => { + if (createVideo) { + content.media = content.document.createElement("video"); + } else { + content.media = content.document.createElement("audio"); + } + if (preload) { + content.media.preload = preload; + } + content.media.muted = muted; + content.media.volume = volume; + content.media.src = fileName; + } + ); +} + +function initMediaStreamPlaybackDocument(tab) { + return SpecialPowers.spawn(tab.linkedBrowser, [], async _ => { + content.media = content.document.createElement("audio"); + content.media.srcObject = + new content.AudioContext().createMediaStreamDestination().stream; + }); +} + +function playMedia(tab, { resolveOnTimeupdate } = {}) { + return SpecialPowers.spawn( + tab.linkedBrowser, + [resolveOnTimeupdate], + // eslint-disable-next-line no-shadow + async resolveOnTimeupdate => { + await content.media.play(); + if (resolveOnTimeupdate) { + await new Promise(r => (content.media.ontimeupdate = r)); + } + } + ); +} + +function pauseMedia(tab) { + return SpecialPowers.spawn(tab.linkedBrowser, [], async _ => { + content.media.pause(); + }); +} + +function assignNewSourceForAudio(tab, fileName) { + // eslint-disable-next-line no-shadow + return SpecialPowers.spawn(tab.linkedBrowser, [fileName], async fileName => { + content.media.src = ""; + content.media.removeAttribute("src"); + content.media.src = fileName; + }); +} + +function updateMedia(tab, { muted, volume } = {}) { + return SpecialPowers.spawn( + tab.linkedBrowser, + [muted, volume], + // eslint-disable-next-line no-shadow + (muted, volume) => { + if (muted != undefined) { + content.media.muted = muted; + } + if (volume != undefined) { + content.media.volume = volume; + } + } + ); +} diff --git a/browser/base/content/test/tabMediaIndicator/browser_mute.js b/browser/base/content/test/tabMediaIndicator/browser_mute.js new file mode 100644 index 0000000000..826e06c3db --- /dev/null +++ b/browser/base/content/test/tabMediaIndicator/browser_mute.js @@ -0,0 +1,19 @@ +const PAGE = "data:text/html,page"; + +function test_on_browser(browser) { + ok(!browser.audioMuted, "Audio should not be muted by default"); + browser.mute(); + ok(browser.audioMuted, "Audio should be muted now"); + browser.unmute(); + ok(!browser.audioMuted, "Audio should be unmuted now"); +} + +add_task(async function () { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: PAGE, + }, + test_on_browser + ); +}); diff --git a/browser/base/content/test/tabMediaIndicator/browser_mute2.js b/browser/base/content/test/tabMediaIndicator/browser_mute2.js new file mode 100644 index 0000000000..5e845454d3 --- /dev/null +++ b/browser/base/content/test/tabMediaIndicator/browser_mute2.js @@ -0,0 +1,32 @@ +const PAGE = "data:text/html,page"; + +async function test_on_browser(browser) { + ok(!browser.audioMuted, "Audio should not be muted by default"); + browser.mute(); + ok(browser.audioMuted, "Audio should be muted now"); + + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: PAGE, + }, + test_on_browser2 + ); + + browser.unmute(); + ok(!browser.audioMuted, "Audio should be unmuted now"); +} + +function test_on_browser2(browser) { + ok(!browser.audioMuted, "Audio should not be muted by default"); +} + +add_task(async function () { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: PAGE, + }, + test_on_browser + ); +}); diff --git a/browser/base/content/test/tabMediaIndicator/browser_mute_webAudio.js b/browser/base/content/test/tabMediaIndicator/browser_mute_webAudio.js new file mode 100644 index 0000000000..6f3e5f222f --- /dev/null +++ b/browser/base/content/test/tabMediaIndicator/browser_mute_webAudio.js @@ -0,0 +1,75 @@ +// The tab closing code leaves an uncaught rejection. This test has been +// whitelisted until the issue is fixed. +if (!gMultiProcessBrowser) { + const { PromiseTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/PromiseTestUtils.sys.mjs" + ); + PromiseTestUtils.expectUncaughtRejection(/is no longer, usable/); +} + +const PAGE = GetTestWebBasedURL("file_webAudio.html"); + +function start_webAudio() { + var startButton = content.document.getElementById("start"); + if (!startButton) { + ok(false, "Can't get the start button!"); + } + + startButton.click(); +} + +function stop_webAudio() { + var stopButton = content.document.getElementById("stop"); + if (!stopButton) { + ok(false, "Can't get the stop button!"); + } + + stopButton.click(); +} + +add_task(async function setup_test_preference() { + await SpecialPowers.pushPrefEnv({ + set: [ + ["media.useAudioChannelService.testing", true], + ["media.block-autoplay-until-in-foreground", true], + ], + }); +}); + +add_task(async function mute_web_audio() { + info("- open new tab -"); + let tab = await BrowserTestUtils.openNewForegroundTab( + window.gBrowser, + "about:blank" + ); + BrowserTestUtils.loadURIString(tab.linkedBrowser, PAGE); + await BrowserTestUtils.browserLoaded(tab.linkedBrowser); + + info("- tab should be audible -"); + await waitForTabSoundIndicatorAppears(tab); + + info("- mute browser -"); + ok(!tab.linkedBrowser.audioMuted, "Audio should not be muted by default"); + let tabContent = tab.querySelector(".tab-content"); + await hoverIcon(tabContent); + await clickIcon(tab.overlayIcon); + ok(tab.linkedBrowser.audioMuted, "Audio should be muted now"); + + info("- stop web audip -"); + await SpecialPowers.spawn(tab.linkedBrowser, [], stop_webAudio); + + info("- start web audio -"); + await SpecialPowers.spawn(tab.linkedBrowser, [], start_webAudio); + + info("- unmute browser -"); + ok(tab.linkedBrowser.audioMuted, "Audio should be muted now"); + await hoverIcon(tabContent); + await clickIcon(tab.overlayIcon); + ok(!tab.linkedBrowser.audioMuted, "Audio should be unmuted now"); + + info("- tab should be audible -"); + await waitForTabSoundIndicatorAppears(tab); + + info("- remove tab -"); + BrowserTestUtils.removeTab(tab); +}); diff --git a/browser/base/content/test/tabMediaIndicator/browser_sound_indicator_silent_video.js b/browser/base/content/test/tabMediaIndicator/browser_sound_indicator_silent_video.js new file mode 100644 index 0000000000..8f0d6961ca --- /dev/null +++ b/browser/base/content/test/tabMediaIndicator/browser_sound_indicator_silent_video.js @@ -0,0 +1,88 @@ +const SILENT_PAGE = GetTestWebBasedURL("file_silentAudioTrack.html"); +const ALMOST_SILENT_PAGE = GetTestWebBasedURL( + "file_almostSilentAudioTrack.html" +); + +function check_audio_playing_state(isPlaying) { + let autoPlay = content.document.getElementById("autoplay"); + if (!autoPlay) { + ok(false, "Can't get the audio element!"); + } + + is( + autoPlay.paused, + !isPlaying, + "The playing state of autoplay audio is correct." + ); + + // wait for a while to make sure the video is playing and related event has + // been dispatched (if any). + let PLAYING_TIME_SEC = 0.5; + ok(PLAYING_TIME_SEC < autoPlay.duration, "The playing time is valid."); + + return new Promise(resolve => { + autoPlay.ontimeupdate = function () { + if (autoPlay.currentTime > PLAYING_TIME_SEC) { + resolve(); + } + }; + }); +} + +add_task(async function should_not_show_sound_indicator_for_silent_video() { + info("- open new foreground tab -"); + let tab = await BrowserTestUtils.openNewForegroundTab( + window.gBrowser, + "about:blank" + ); + + info("- tab should not have sound indicator before playing silent video -"); + await waitForTabSoundIndicatorDisappears(tab); + + info("- loading autoplay silent video -"); + BrowserTestUtils.loadURIString(tab.linkedBrowser, SILENT_PAGE); + await BrowserTestUtils.browserLoaded(tab.linkedBrowser); + await SpecialPowers.spawn( + tab.linkedBrowser, + [true], + check_audio_playing_state + ); + + info("- tab should not have sound indicator after playing silent video -"); + await waitForTabSoundIndicatorDisappears(tab); + + info("- remove tab -"); + BrowserTestUtils.removeTab(tab); +}); + +add_task( + async function should_not_show_sound_indicator_for_almost_silent_video() { + info("- open new foreground tab -"); + let tab = await BrowserTestUtils.openNewForegroundTab( + window.gBrowser, + "about:blank" + ); + + info( + "- tab should not have sound indicator before playing almost silent video -" + ); + await waitForTabSoundIndicatorDisappears(tab); + + info("- loading autoplay almost silent video -"); + BrowserTestUtils.loadURIString(tab.linkedBrowser, ALMOST_SILENT_PAGE); + await BrowserTestUtils.browserLoaded(tab.linkedBrowser); + await SpecialPowers.spawn( + tab.linkedBrowser, + [true], + check_audio_playing_state + ); + + info( + "- tab should not have sound indicator after playing almost silent video -" + ); + await waitForTabSoundIndicatorDisappears(tab); + + info("- remove tab -"); + BrowserTestUtils.removeTab(tab); + } +); diff --git a/browser/base/content/test/tabMediaIndicator/browser_webAudio_hideSoundPlayingIcon.js b/browser/base/content/test/tabMediaIndicator/browser_webAudio_hideSoundPlayingIcon.js new file mode 100644 index 0000000000..be40f6e146 --- /dev/null +++ b/browser/base/content/test/tabMediaIndicator/browser_webAudio_hideSoundPlayingIcon.js @@ -0,0 +1,60 @@ +/** + * This test is used to ensure the 'sound-playing' icon would not disappear after + * sites call AudioContext.resume(). + */ +"use strict"; + +function setup_test_preference() { + return SpecialPowers.pushPrefEnv({ + set: [ + ["media.useAudioChannelService.testing", true], + ["browser.tabs.delayHidingAudioPlayingIconMS", 0], + ], + }); +} + +async function resumeAudioContext() { + const ac = content.ac; + await ac.resume(); + ok(true, "AudioContext is resumed."); +} + +async function testResumeRunningAudioContext() { + info(`- create new tab -`); + const tab = await BrowserTestUtils.openNewForegroundTab( + window.gBrowser, + "about:blank" + ); + const browser = tab.linkedBrowser; + + info(`- create audio context -`); + // We want the same audio context to be used across different content tasks. + await SpecialPowers.spawn(tab.linkedBrowser, [], () => { + content.ac = new content.AudioContext(); + const ac = content.ac; + const dest = ac.destination; + const osc = ac.createOscillator(); + osc.connect(dest); + osc.start(); + }); + + info(`- wait for 'sound-playing' icon showing -`); + await waitForTabSoundIndicatorAppears(tab); + + info(`- resume AudioContext -`); + await SpecialPowers.spawn(browser, [], resumeAudioContext); + + info(`- 'sound-playing' icon should still exist -`); + await waitForTabSoundIndicatorAppears(tab); + + info(`- remove tab -`); + await BrowserTestUtils.removeTab(tab); +} + +add_task(async function start_test() { + info("- setup test preference -"); + await setup_test_preference(); + + info("- start testing -"); + await testResumeRunningAudioContext(); +}); diff --git a/browser/base/content/test/tabMediaIndicator/browser_webAudio_silentData.js b/browser/base/content/test/tabMediaIndicator/browser_webAudio_silentData.js new file mode 100644 index 0000000000..5831d3c0ce --- /dev/null +++ b/browser/base/content/test/tabMediaIndicator/browser_webAudio_silentData.js @@ -0,0 +1,57 @@ +/** + * This test is used to make sure we won't show the sound indicator for silent + * web audio. + */ +/* eslint-disable mozilla/no-arbitrary-setTimeout */ +"use strict"; + +async function waitUntilAudioContextStarts() { + const ac = content.ac; + if (ac.state == "running") { + return; + } + + await new Promise(resolve => { + ac.onstatechange = () => { + if (ac.state == "running") { + ac.onstatechange = null; + resolve(); + } + }; + }); +} + +add_task(async function testSilentAudioContext() { + info(`- create new tab -`); + const tab = await BrowserTestUtils.openNewForegroundTab( + window.gBrowser, + "about:blank" + ); + const browser = tab.linkedBrowser; + + info(`- create audio context -`); + // We want the same audio context to be used across different content tasks + await SpecialPowers.spawn(tab.linkedBrowser, [], () => { + content.ac = new content.AudioContext(); + const ac = content.ac; + const dest = ac.destination; + const source = new content.OscillatorNode(content.ac); + const gain = new content.GainNode(content.ac); + gain.gain.value = 0.0; + source.connect(gain).connect(dest); + source.start(); + }); + info(`- check AudioContext's state -`); + await SpecialPowers.spawn(browser, [], waitUntilAudioContextStarts); + ok(true, `AudioContext is running.`); + + info(`- should not show sound indicator -`); + // If we do the next step too early, then we can't make sure whether that the + // reason of no showing sound indicator is because of silent web audio, or + // because the indicator is just not showing yet. + await new Promise(r => setTimeout(r, 1000)); + await waitForTabSoundIndicatorDisappears(tab); + + info(`- remove tab -`); + await BrowserTestUtils.removeTab(tab); +}); diff --git a/browser/base/content/test/tabMediaIndicator/browser_webaudio_audibility_change.js b/browser/base/content/test/tabMediaIndicator/browser_webaudio_audibility_change.js new file mode 100644 index 0000000000..8d8ce08551 --- /dev/null +++ b/browser/base/content/test/tabMediaIndicator/browser_webaudio_audibility_change.js @@ -0,0 +1,172 @@ +const EMPTY_PAGE_URL = GetTestWebBasedURL("file_empty.html"); + +/** + * When web audio changes its audible state, the sound indicator should be + * updated as well, which should appear only when web audio is audible. + */ +add_task( + async function testWebAudioAudibilityWouldAffectTheAppearenceOfTabSoundIndicator() { + info(`sound indicator should appear when web audio plays audible sound`); + const tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + EMPTY_PAGE_URL + ); + await initWebAudioDocument(tab); + await waitForTabSoundIndicatorAppears(tab); + + info(`sound indicator should disappear when suspending web audio`); + await suspendWebAudio(tab); + await waitForTabSoundIndicatorDisappears(tab); + + info(`sound indicator should appear when resuming web audio`); + await resumeWebAudio(tab); + await waitForTabSoundIndicatorAppears(tab); + + info(`sound indicator should disappear when muting web audio by docShell`); + await muteWebAudioByDocShell(tab); + await waitForTabSoundIndicatorDisappears(tab); + + info(`sound indicator should appear when unmuting web audio by docShell`); + await unmuteWebAudioByDocShell(tab); + await waitForTabSoundIndicatorAppears(tab); + + info(`sound indicator should disappear when muting web audio by gain node`); + await muteWebAudioByGainNode(tab); + await waitForTabSoundIndicatorDisappears(tab); + + info(`sound indicator should appear when unmuting web audio by gain node`); + await unmuteWebAudioByGainNode(tab); + await waitForTabSoundIndicatorAppears(tab); + + info(`sound indicator should disappear when closing web audio`); + await closeWebAudio(tab); + await waitForTabSoundIndicatorDisappears(tab); + + info("remove tab"); + BrowserTestUtils.removeTab(tab); + } +); + +add_task(async function testSoundIndicatorShouldDisappearAfterTabNavigation() { + info("create a tab loading media document"); + const tab = await createBlankForegroundTab(); + + info(`sound indicator should appear when audible web audio starts playing`); + await Promise.all([ + initWebAudioDocument(tab), + waitForTabSoundIndicatorAppears(tab), + ]); + + info(`sound indicator should disappear after navigating tab to blank page`); + await Promise.all([ + BrowserTestUtils.loadURIString(tab.linkedBrowser, "about:blank"), + waitForTabSoundIndicatorDisappears(tab), + ]); + + info("remove tab"); + BrowserTestUtils.removeTab(tab); +}); + +add_task( + async function testSoundIndicatorShouldDisappearAfterWebAudioBecomesSilent() { + info("create a tab loading media document"); + const tab = await createBlankForegroundTab(); + + info(`sound indicator should appear when audible web audio starts playing`); + await Promise.all([ + initWebAudioDocument(tab, { duration: 0.1 }), + waitForTabSoundIndicatorAppears(tab), + ]); + + info(`sound indicator should disappear after web audio become silent`); + await waitForTabSoundIndicatorDisappears(tab); + + info("remove tab"); + BrowserTestUtils.removeTab(tab); + } +); + +add_task(async function testNoSoundIndicatorWhenSimplyCreateAudioContext() { + info("create a tab loading media document"); + const tab = await createBlankForegroundTab({ needObserver: true }); + + info(`sound indicator should not appear when simply create an AudioContext`); + await SpecialPowers.spawn(tab.linkedBrowser, [], async _ => { + content.ac = new content.AudioContext(); + while (content.ac.state != "running") { + info(`wait until web audio starts running`); + await new Promise(r => (content.ac.onstatechange = r)); + } + }); + ok(!tab.observer.hasEverUpdated(), "didn't ever update sound indicator"); + + info("remove tab"); + BrowserTestUtils.removeTab(tab); +}); + +/** + * Following are helper functions + */ +function initWebAudioDocument(tab, { duration } = {}) { + // eslint-disable-next-line no-shadow + return SpecialPowers.spawn(tab.linkedBrowser, [duration], async duration => { + content.ac = new content.AudioContext(); + const ac = content.ac; + const dest = ac.destination; + const source = new content.OscillatorNode(ac); + source.start(ac.currentTime); + if (duration != undefined) { + source.stop(ac.currentTime + duration); + } + // create a gain node for future muting/unmuting + content.gainNode = ac.createGain(); + source.connect(content.gainNode); + content.gainNode.connect(dest); + while (ac.state != "running") { + info(`wait until web audio starts running`); + await new Promise(r => (ac.onstatechange = r)); + } + }); +} + +function suspendWebAudio(tab) { + return SpecialPowers.spawn(tab.linkedBrowser, [], async _ => { + await content.ac.suspend(); + }); +} + +function resumeWebAudio(tab) { + return SpecialPowers.spawn(tab.linkedBrowser, [], async _ => { + await content.ac.resume(); + }); +} + +function closeWebAudio(tab) { + return SpecialPowers.spawn(tab.linkedBrowser, [], async _ => { + await content.ac.close(); + }); +} + +function muteWebAudioByDocShell(tab) { + return SpecialPowers.spawn(tab.linkedBrowser, [], _ => { + content.docShell.allowMedia = false; + }); +} + +function unmuteWebAudioByDocShell(tab) { + return SpecialPowers.spawn(tab.linkedBrowser, [], _ => { + content.docShell.allowMedia = true; + }); +} + +function muteWebAudioByGainNode(tab) { + return SpecialPowers.spawn(tab.linkedBrowser, [], _ => { + content.gainNode.gain.setValueAtTime(0, content.ac.currentTime); + }); +} + +function unmuteWebAudioByGainNode(tab) { + return SpecialPowers.spawn(tab.linkedBrowser, [], _ => { + content.gainNode.gain.setValueAtTime(1.0, content.ac.currentTime); + }); +} diff --git a/browser/base/content/test/tabMediaIndicator/file_almostSilentAudioTrack.html b/browser/base/content/test/tabMediaIndicator/file_almostSilentAudioTrack.html new file mode 100644 index 0000000000..3ce9a68b98 --- /dev/null +++ b/browser/base/content/test/tabMediaIndicator/file_almostSilentAudioTrack.html @@ -0,0 +1,18 @@ + + + + + + + + + diff --git a/browser/base/content/test/tabMediaIndicator/file_autoplay_media.html b/browser/base/content/test/tabMediaIndicator/file_autoplay_media.html new file mode 100644 index 0000000000..f0dcfdab52 --- /dev/null +++ b/browser/base/content/test/tabMediaIndicator/file_autoplay_media.html @@ -0,0 +1,9 @@ + + + +autoplay media page + + + + + diff --git a/browser/base/content/test/tabMediaIndicator/file_empty.html b/browser/base/content/test/tabMediaIndicator/file_empty.html new file mode 100644 index 0000000000..13d5eeee78 --- /dev/null +++ b/browser/base/content/test/tabMediaIndicator/file_empty.html @@ -0,0 +1,8 @@ + + + +empty page + + + + diff --git a/browser/base/content/test/tabMediaIndicator/file_mediaPlayback.html b/browser/base/content/test/tabMediaIndicator/file_mediaPlayback.html new file mode 100644 index 0000000000..5df0bc1542 --- /dev/null +++ b/browser/base/content/test/tabMediaIndicator/file_mediaPlayback.html @@ -0,0 +1,9 @@ + + diff --git a/browser/base/content/test/tabMediaIndicator/file_mediaPlayback2.html b/browser/base/content/test/tabMediaIndicator/file_mediaPlayback2.html new file mode 100644 index 0000000000..890b494a05 --- /dev/null +++ b/browser/base/content/test/tabMediaIndicator/file_mediaPlayback2.html @@ -0,0 +1,14 @@ + + + + diff --git a/browser/base/content/test/tabMediaIndicator/file_mediaPlaybackFrame.html b/browser/base/content/test/tabMediaIndicator/file_mediaPlaybackFrame.html new file mode 100644 index 0000000000..119db62ecc --- /dev/null +++ b/browser/base/content/test/tabMediaIndicator/file_mediaPlaybackFrame.html @@ -0,0 +1,2 @@ + + diff --git a/browser/base/content/test/tabMediaIndicator/file_mediaPlaybackFrame2.html b/browser/base/content/test/tabMediaIndicator/file_mediaPlaybackFrame2.html new file mode 100644 index 0000000000..d96a4cd4e9 --- /dev/null +++ b/browser/base/content/test/tabMediaIndicator/file_mediaPlaybackFrame2.html @@ -0,0 +1,2 @@ + + diff --git a/browser/base/content/test/tabMediaIndicator/file_silentAudioTrack.html b/browser/base/content/test/tabMediaIndicator/file_silentAudioTrack.html new file mode 100644 index 0000000000..afdf2c5297 --- /dev/null +++ b/browser/base/content/test/tabMediaIndicator/file_silentAudioTrack.html @@ -0,0 +1,18 @@ + + + + + + + + + diff --git a/browser/base/content/test/tabMediaIndicator/file_webAudio.html b/browser/base/content/test/tabMediaIndicator/file_webAudio.html new file mode 100644 index 0000000000..f6fb5e7c07 --- /dev/null +++ b/browser/base/content/test/tabMediaIndicator/file_webAudio.html @@ -0,0 +1,29 @@ + + + + + + +

+
+
+
+
diff --git a/browser/base/content/test/tabMediaIndicator/gizmo.mp4 b/browser/base/content/test/tabMediaIndicator/gizmo.mp4
new file mode 100644
index 0000000000..87efad5ade
Binary files /dev/null and b/browser/base/content/test/tabMediaIndicator/gizmo.mp4 differ
diff --git a/browser/base/content/test/tabMediaIndicator/head.js b/browser/base/content/test/tabMediaIndicator/head.js
new file mode 100644
index 0000000000..8b82e21a43
--- /dev/null
+++ b/browser/base/content/test/tabMediaIndicator/head.js
@@ -0,0 +1,158 @@
+/**
+ * Global variables for testing.
+ */
+const gEMPTY_PAGE_URL = GetTestWebBasedURL("file_empty.html");
+
+/**
+ * Return a web-based URL for a given file based on the testing directory.
+ * @param {String} fileName
+ *        file that caller wants its web-based url
+ * @param {Boolean} cors [optional]
+ *        if set, then return a url with different origin
+ */
+function GetTestWebBasedURL(fileName, cors = false) {
+  // eslint-disable-next-line @microsoft/sdl/no-insecure-url
+  // eslint-disable-next-line @microsoft/sdl/no-insecure-url
+  const origin = cors ? "http://example.org" : "http://example.com";
+  return (
+    getRootDirectory(gTestPath).replace("chrome://mochitests/content", origin) +
+    fileName
+  );
+}
+
+/**
+ * Wait until tab sound indicator appears on the given tab.
+ * @param {tabbrowser} tab
+ *        given tab where tab sound indicator should appear
+ */
+async function waitForTabSoundIndicatorAppears(tab) {
+  if (!tab.soundPlaying) {
+    info("Tab sound indicator doesn't appear yet");
+    await BrowserTestUtils.waitForEvent(
+      tab,
+      "TabAttrModified",
+      false,
+      event => {
+        return event.detail.changed.includes("soundplaying");
+      }
+    );
+  }
+  ok(tab.soundPlaying, "Tab sound indicator appears");
+}
+
+/**
+ * Wait until tab sound indicator disappears on the given tab.
+ * @param {tabbrowser} tab
+ *        given tab where tab sound indicator should disappear
+ */
+async function waitForTabSoundIndicatorDisappears(tab) {
+  if (tab.soundPlaying) {
+    info("Tab sound indicator doesn't disappear yet");
+    await BrowserTestUtils.waitForEvent(
+      tab,
+      "TabAttrModified",
+      false,
+      event => {
+        return event.detail.changed.includes("soundplaying");
+      }
+    );
+  }
+  ok(!tab.soundPlaying, "Tab sound indicator disappears");
+}
+
+/**
+ * Return a new foreground tab loading with an empty file.
+ * @param {boolean} needObserver
+ *        If true, sets an observer property on the returned tab. This property
+ *        exposes `hasEverUpdated()` which will return a bool indicating if the
+ *        sound indicator has ever updated.
+ */
+async function createBlankForegroundTab({ needObserver } = {}) {
+  const tab = await BrowserTestUtils.openNewForegroundTab(
+    gBrowser,
+    gEMPTY_PAGE_URL
+  );
+  if (needObserver) {
+    tab.observer = createSoundIndicatorObserver(tab);
+  }
+  return tab;
+}
+
+function createSoundIndicatorObserver(tab) {
+  let hasEverUpdated = false;
+  let listener = event => {
+    if (event.detail.changed.includes("soundplaying")) {
+      hasEverUpdated = true;
+    }
+  };
+  tab.addEventListener("TabAttrModified", listener);
+  return {
+    hasEverUpdated: () => {
+      tab.removeEventListener("TabAttrModified", listener);
+      return hasEverUpdated;
+    },
+  };
+}
+
+/**
+ * Sythesize mouse hover on the given icon, which would sythesize `mouseover`
+ * and `mousemove` event on that. Return a promise that will be resolved when
+ * the tooptip element shows.
+ * @param {tab icon} icon
+ *        the icon on which we want to mouse hover
+ * @param {tooltip element} tooltip
+ *        the tab tooltip elementss
+ */
+function hoverIcon(icon, tooltip) {
+  disableNonTestMouse(true);
+
+  if (!tooltip) {
+    tooltip = document.getElementById("tabbrowser-tab-tooltip");
+  }
+
+  let popupShownPromise = BrowserTestUtils.waitForEvent(tooltip, "popupshown");
+  EventUtils.synthesizeMouse(icon, 1, 1, { type: "mouseover" });
+  EventUtils.synthesizeMouse(icon, 2, 2, { type: "mousemove" });
+  EventUtils.synthesizeMouse(icon, 3, 3, { type: "mousemove" });
+  EventUtils.synthesizeMouse(icon, 4, 4, { type: "mousemove" });
+  return popupShownPromise;
+}
+
+/**
+ * Leave mouse from the given icon, which would sythesize `mouseout`
+ * and `mousemove` event on that.
+ * @param {tab icon} icon
+ *        the icon on which we want to mouse hover
+ * @param {tooltip element} tooltip
+ *        the tab tooltip elementss
+ */
+function leaveIcon(icon) {
+  EventUtils.synthesizeMouse(icon, 0, 0, { type: "mouseout" });
+  EventUtils.synthesizeMouseAtCenter(document.documentElement, {
+    type: "mousemove",
+  });
+  EventUtils.synthesizeMouseAtCenter(document.documentElement, {
+    type: "mousemove",
+  });
+  EventUtils.synthesizeMouseAtCenter(document.documentElement, {
+    type: "mousemove",
+  });
+
+  disableNonTestMouse(false);
+}
+
+/**
+ * Sythesize mouse click on the given icon.
+ * @param {tab icon} icon
+ *        the icon on which we want to mouse hover
+ */
+async function clickIcon(icon) {
+  await hoverIcon(icon);
+  EventUtils.synthesizeMouseAtCenter(icon, { button: 0 });
+  leaveIcon(icon);
+}
+
+function disableNonTestMouse(disable) {
+  let utils = window.windowUtils;
+  utils.disableNonTestMouseEvents(disable);
+}
diff --git a/browser/base/content/test/tabMediaIndicator/noaudio.webm b/browser/base/content/test/tabMediaIndicator/noaudio.webm
new file mode 100644
index 0000000000..9207017fb6
Binary files /dev/null and b/browser/base/content/test/tabMediaIndicator/noaudio.webm differ
diff --git a/browser/base/content/test/tabMediaIndicator/silentAudioTrack.webm b/browser/base/content/test/tabMediaIndicator/silentAudioTrack.webm
new file mode 100644
index 0000000000..8e08a86c45
Binary files /dev/null and b/browser/base/content/test/tabMediaIndicator/silentAudioTrack.webm differ
-- 
cgit v1.2.3