/* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; const TEST_ROOT = getRootDirectory(gTestPath).replace( "chrome://mochitests/content/", "https://example.com/" ); const TEST_PAGE = TEST_ROOT + "get_user_media.html"; const MUTE_TOPICS = [ "getUserMedia:muteVideo", "getUserMedia:unmuteVideo", "getUserMedia:muteAudio", "getUserMedia:unmuteAudio", ]; add_setup(async function () { let prefs = [ [PREF_PERMISSION_FAKE, true], [PREF_AUDIO_LOOPBACK, ""], [PREF_VIDEO_LOOPBACK, ""], [PREF_FAKE_STREAMS, true], [PREF_FOCUS_SOURCE, false], ["privacy.webrtc.globalMuteToggles", true], ]; await SpecialPowers.pushPrefEnv({ set: prefs }); }); /** * Returns a Promise that resolves when the content process for * fires the right observer notification based on the * value of isMuted for the camera. * * Note: Callers must ensure that they first call * BrowserTestUtils.startObservingTopics to monitor the mute and * unmute observer notifications for this to work properly. * * @param {} browser - The browser running in the content process * to be monitored. * @param {Boolean} isMuted - True if the muted topic should be fired. * @return {Promise} * @resolves {undefined} When the notification fires. */ function waitForCameraMuteState(browser, isMuted) { let topic = isMuted ? "getUserMedia:muteVideo" : "getUserMedia:unmuteVideo"; return BrowserTestUtils.contentTopicObserved(browser.browsingContext, topic); } /** * Returns a Promise that resolves when the content process for * fires the right observer notification based on the * value of isMuted for the microphone. * * Note: Callers must ensure that they first call * BrowserTestUtils.startObservingTopics to monitor the mute and * unmute observer notifications for this to work properly. * * @param {} browser - The browser running in the content process * to be monitored. * @param {Boolean} isMuted - True if the muted topic should be fired. * @return {Promise} * @resolves {undefined} When the notification fires. */ function waitForMicrophoneMuteState(browser, isMuted) { let topic = isMuted ? "getUserMedia:muteAudio" : "getUserMedia:unmuteAudio"; return BrowserTestUtils.contentTopicObserved(browser.browsingContext, topic); } /** * Tests that the global mute toggles fire the right observer * notifications in pre-existing content processes. */ add_task(async function test_notifications() { await BrowserTestUtils.withNewTab(TEST_PAGE, async browser => { let indicatorPromise = promiseIndicatorWindow(); await shareDevices(browser, true /* camera */, true /* microphone */); let indicator = await indicatorPromise; let doc = indicator.document; let microphoneMute = doc.getElementById("microphone-mute-toggle"); let cameraMute = doc.getElementById("camera-mute-toggle"); Assert.ok( !microphoneMute.checked, "Microphone toggle should not start checked." ); Assert.ok(!cameraMute.checked, "Camera toggle should not start checked."); await BrowserTestUtils.startObservingTopics( browser.browsingContext, MUTE_TOPICS ); info("Muting microphone..."); let microphoneMuted = waitForMicrophoneMuteState(browser, true); microphoneMute.click(); await microphoneMuted; info("Microphone successfully muted."); info("Muting camera..."); let cameraMuted = waitForCameraMuteState(browser, true); cameraMute.click(); await cameraMuted; info("Camera successfully muted."); Assert.ok( microphoneMute.checked, "Microphone toggle should now be checked." ); Assert.ok(cameraMute.checked, "Camera toggle should now be checked."); info("Unmuting microphone..."); let microphoneUnmuted = waitForMicrophoneMuteState(browser, false); microphoneMute.click(); await microphoneUnmuted; info("Microphone successfully unmuted."); info("Unmuting camera..."); let cameraUnmuted = waitForCameraMuteState(browser, false); cameraMute.click(); await cameraUnmuted; info("Camera successfully unmuted."); await BrowserTestUtils.stopObservingTopics( browser.browsingContext, MUTE_TOPICS ); }); }); /** * Tests that if sharing stops while muted, and the indicator closes, * then the mute state is reset. */ add_task(async function test_closing_indicator_resets_mute() { await BrowserTestUtils.withNewTab(TEST_PAGE, async browser => { let indicatorPromise = promiseIndicatorWindow(); await shareDevices(browser, true /* camera */, true /* microphone */); let indicator = await indicatorPromise; let doc = indicator.document; let microphoneMute = doc.getElementById("microphone-mute-toggle"); let cameraMute = doc.getElementById("camera-mute-toggle"); Assert.ok( !microphoneMute.checked, "Microphone toggle should not start checked." ); Assert.ok(!cameraMute.checked, "Camera toggle should not start checked."); await BrowserTestUtils.startObservingTopics( browser.browsingContext, MUTE_TOPICS ); info("Muting microphone..."); let microphoneMuted = waitForMicrophoneMuteState(browser, true); microphoneMute.click(); await microphoneMuted; info("Microphone successfully muted."); info("Muting camera..."); let cameraMuted = waitForCameraMuteState(browser, true); cameraMute.click(); await cameraMuted; info("Camera successfully muted."); Assert.ok( microphoneMute.checked, "Microphone toggle should now be checked." ); Assert.ok(cameraMute.checked, "Camera toggle should now be checked."); let allUnmuted = Promise.all([ waitForMicrophoneMuteState(browser, false), waitForCameraMuteState(browser, false), ]); await closeStream(); await allUnmuted; await BrowserTestUtils.stopObservingTopics( browser.browsingContext, MUTE_TOPICS ); }); }); /** * Test that if the global mute state is set, then newly created * content processes also have their tracks muted after sending * a getUserMedia request. */ add_task(async function test_new_processes() { let tab1 = await BrowserTestUtils.openNewForegroundTab({ gBrowser, url: TEST_PAGE, }); let browser1 = tab1.linkedBrowser; let indicatorPromise = promiseIndicatorWindow(); await shareDevices(browser1, true /* camera */, true /* microphone */); let indicator = await indicatorPromise; let doc = indicator.document; let microphoneMute = doc.getElementById("microphone-mute-toggle"); let cameraMute = doc.getElementById("camera-mute-toggle"); Assert.ok( !microphoneMute.checked, "Microphone toggle should not start checked." ); Assert.ok(!cameraMute.checked, "Camera toggle should not start checked."); await BrowserTestUtils.startObservingTopics( browser1.browsingContext, MUTE_TOPICS ); info("Muting microphone..."); let microphoneMuted = waitForMicrophoneMuteState(browser1, true); microphoneMute.click(); await microphoneMuted; info("Microphone successfully muted."); info("Muting camera..."); let cameraMuted = waitForCameraMuteState(browser1, true); cameraMute.click(); await cameraMuted; info("Camera successfully muted."); // We'll make sure a new process is being launched by observing // for the ipc:content-created notification. let processLaunched = TestUtils.topicObserved("ipc:content-created"); let tab2 = await BrowserTestUtils.openNewForegroundTab({ gBrowser, url: TEST_PAGE, forceNewProcess: true, }); let browser2 = tab2.linkedBrowser; await processLaunched; await BrowserTestUtils.startObservingTopics( browser2.browsingContext, MUTE_TOPICS ); let microphoneMuted2 = waitForMicrophoneMuteState(browser2, true); let cameraMuted2 = waitForCameraMuteState(browser2, true); info("Sharing the microphone and camera from a new process."); await shareDevices(browser2, true /* camera */, true /* microphone */); await Promise.all([microphoneMuted2, cameraMuted2]); info("Unmuting microphone..."); let microphoneUnmuted = Promise.all([ waitForMicrophoneMuteState(browser1, false), waitForMicrophoneMuteState(browser2, false), ]); microphoneMute.click(); await microphoneUnmuted; info("Microphone successfully unmuted."); info("Unmuting camera..."); let cameraUnmuted = Promise.all([ waitForCameraMuteState(browser1, false), waitForCameraMuteState(browser2, false), ]); cameraMute.click(); await cameraUnmuted; info("Camera successfully unmuted."); await BrowserTestUtils.stopObservingTopics( browser1.browsingContext, MUTE_TOPICS ); await BrowserTestUtils.stopObservingTopics( browser2.browsingContext, MUTE_TOPICS ); BrowserTestUtils.removeTab(tab2); BrowserTestUtils.removeTab(tab1); });