зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1325049 - Fix the global webrtc sharing indicator to work with multiple content processes, r=felipe.
This commit is contained in:
Родитель
c7c5b5fa85
Коммит
f55f3ce4a0
|
@ -9,6 +9,8 @@ support-files =
|
|||
skip-if = (os == "linux" && debug) # linux: bug 976544
|
||||
[browser_devices_get_user_media_anim.js]
|
||||
[browser_devices_get_user_media_in_frame.js]
|
||||
[browser_devices_get_user_media_multi_process.js]
|
||||
skip-if = (e10s && debug) # bug 1347625
|
||||
[browser_devices_get_user_media_screen.js]
|
||||
skip-if = (e10s && debug) || (os == "linux") || (os == "win" && !debug) # bug 1320754 for e10s debug, and bug 1320994 for linux opt, bug 1338038 for windows and linux debug
|
||||
[browser_devices_get_user_media_tear_off_tab.js]
|
||||
|
|
|
@ -0,0 +1,153 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
var gTests = [
|
||||
|
||||
{
|
||||
desc: "getUserMedia audio in a first process + video in a second process",
|
||||
run: function* checkMultiProcess() {
|
||||
// The main purpose of this test is to ensure webrtc sharing indicators
|
||||
// work with multiple content processes, but it makes sense to run this
|
||||
// test without e10s too to ensure using webrtc devices in two different
|
||||
// tabs is handled correctly.
|
||||
|
||||
// Request audio in the first tab.
|
||||
let promise = promisePopupNotificationShown("webRTC-shareDevices");
|
||||
yield promiseRequestDevice(true);
|
||||
yield promise;
|
||||
yield expectObserverCalled("getUserMedia:request");
|
||||
|
||||
checkDeviceSelectors(true);
|
||||
|
||||
let indicator = promiseIndicatorWindow();
|
||||
yield promiseMessage("ok", () => {
|
||||
PopupNotifications.panel.firstChild.button.click();
|
||||
});
|
||||
yield expectObserverCalled("getUserMedia:response:allow");
|
||||
yield expectObserverCalled("recording-device-events");
|
||||
Assert.deepEqual((yield getMediaCaptureState()), {audio: true},
|
||||
"expected microphone to be shared");
|
||||
|
||||
yield indicator;
|
||||
yield checkSharingUI({audio: true});
|
||||
|
||||
ok(webrtcUI.showGlobalIndicator, "webrtcUI wants the global indicator shown");
|
||||
ok(!webrtcUI.showCameraIndicator, "webrtcUI wants the camera indicator hidden");
|
||||
ok(webrtcUI.showMicrophoneIndicator, "webrtcUI wants the mic indicator shown");
|
||||
is(webrtcUI.getActiveStreams(false, true).length, 1, "1 active audio stream");
|
||||
is(webrtcUI.getActiveStreams(true, true, true).length, 1, "1 active stream");
|
||||
|
||||
yield expectNoObserverCalled();
|
||||
|
||||
// If we have reached the max process count already, increase it to ensure
|
||||
// our new tab can have its own content process.
|
||||
var ppmm = Cc["@mozilla.org/parentprocessmessagemanager;1"]
|
||||
.getService(Ci.nsIMessageBroadcaster);
|
||||
ppmm.QueryInterface(Ci.nsIProcessScriptLoader);
|
||||
let childCount = ppmm.childCount;
|
||||
let maxContentProcess = Services.prefs.getIntPref("dom.ipc.processCount");
|
||||
// The first check is because if we are on a branch where e10s-multi is
|
||||
// disabled, we want to keep testing e10s with a single content process.
|
||||
// The + 1 is because ppmm.childCount also counts the chrome process
|
||||
// (which also runs process scripts).
|
||||
if (maxContentProcess > 1 && childCount == maxContentProcess + 1) {
|
||||
yield SpecialPowers.pushPrefEnv({"set": [["dom.ipc.processCount",
|
||||
childCount]]});
|
||||
}
|
||||
|
||||
// Open a new tab with a different hostname.
|
||||
let url = gBrowser.currentURI.spec.replace("https://example.com/",
|
||||
"http://127.0.0.1:8888/");
|
||||
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, url);
|
||||
tab.linkedBrowser.messageManager.loadFrameScript(CONTENT_SCRIPT_HELPER, true);
|
||||
|
||||
// Request video.
|
||||
promise = promisePopupNotificationShown("webRTC-shareDevices");
|
||||
yield promiseRequestDevice(false, true);
|
||||
yield promise;
|
||||
yield expectObserverCalled("getUserMedia:request");
|
||||
|
||||
checkDeviceSelectors(false, true);
|
||||
|
||||
yield promiseMessage("ok", () => {
|
||||
PopupNotifications.panel.firstChild.button.click();
|
||||
});
|
||||
yield expectObserverCalled("getUserMedia:response:allow");
|
||||
yield expectObserverCalled("recording-device-events");
|
||||
|
||||
yield checkSharingUI({video: true}, window, {audio: true, video: true});
|
||||
|
||||
ok(webrtcUI.showGlobalIndicator, "webrtcUI wants the global indicator shown");
|
||||
ok(webrtcUI.showCameraIndicator, "webrtcUI wants the camera indicator shown");
|
||||
ok(webrtcUI.showMicrophoneIndicator, "webrtcUI wants the mic indicator shown");
|
||||
is(webrtcUI.getActiveStreams(false, true).length, 1, "1 active audio stream");
|
||||
is(webrtcUI.getActiveStreams(true).length, 1, "1 active video stream");
|
||||
is(webrtcUI.getActiveStreams(true, true, true).length, 2, "2 active streams");
|
||||
|
||||
info("removing the second tab");
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
|
||||
// Check that we still show the sharing indicators for the first tab's stream.
|
||||
yield promiseWaitForCondition(() => !webrtcUI.showCameraIndicator);
|
||||
ok(webrtcUI.showGlobalIndicator, "webrtcUI wants the global indicator shown");
|
||||
ok(!webrtcUI.showCameraIndicator, "webrtcUI wants the camera indicator hidden");
|
||||
ok(webrtcUI.showMicrophoneIndicator, "webrtcUI wants the mic indicator shown");
|
||||
is(webrtcUI.getActiveStreams(false, true).length, 1, "1 active audio stream");
|
||||
is(webrtcUI.getActiveStreams(true, true, true).length, 1, "1 active stream");
|
||||
|
||||
yield checkSharingUI({audio: true});
|
||||
|
||||
// When both tabs use the same content process, the frame script for the
|
||||
// first tab receives observer notifications for things happening in the
|
||||
// second tab, so let's clear the observer call counts before we cleanup
|
||||
// in the first tab.
|
||||
yield ignoreObserversCalled();
|
||||
|
||||
// Close the first tab's stream and verify that all indicators are removed.
|
||||
yield closeStream();
|
||||
|
||||
ok(!webrtcUI.showGlobalIndicator, "webrtcUI wants the global indicator hidden");
|
||||
is(webrtcUI.getActiveStreams(true, true, true).length, 0, "0 active streams");
|
||||
}
|
||||
},
|
||||
|
||||
];
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
let tab = gBrowser.addTab();
|
||||
gBrowser.selectedTab = tab;
|
||||
let browser = tab.linkedBrowser;
|
||||
|
||||
browser.messageManager.loadFrameScript(CONTENT_SCRIPT_HELPER, true);
|
||||
|
||||
browser.addEventListener("load", function() {
|
||||
is(PopupNotifications._currentNotifications.length, 0,
|
||||
"should start the test without any prior popup notification");
|
||||
ok(gIdentityHandler._identityPopup.hidden,
|
||||
"should start the test with the control center hidden");
|
||||
|
||||
Task.spawn(function* () {
|
||||
yield SpecialPowers.pushPrefEnv({"set": [[PREF_PERMISSION_FAKE, true]]});
|
||||
|
||||
for (let testCase of gTests) {
|
||||
info(testCase.desc);
|
||||
yield testCase.run();
|
||||
}
|
||||
}).then(finish, ex => {
|
||||
Cu.reportError(ex);
|
||||
ok(false, "Unexpected Exception: " + ex);
|
||||
finish();
|
||||
});
|
||||
}, {capture: true, once: true});
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
rootDir = rootDir.replace("chrome://mochitests/content/",
|
||||
"https://example.com/");
|
||||
content.location = rootDir + "get_user_media.html";
|
||||
}
|
|
@ -241,6 +241,18 @@ function expectNoObserverCalled(aIgnoreDeviceEvents = false) {
|
|||
});
|
||||
}
|
||||
|
||||
function ignoreObserversCalled() {
|
||||
return new Promise(resolve => {
|
||||
let mm = _mm();
|
||||
mm.addMessageListener("Test:ExpectNoObserverCalled:Reply",
|
||||
function listener() {
|
||||
mm.removeMessageListener("Test:ExpectNoObserverCalled:Reply", listener);
|
||||
resolve();
|
||||
});
|
||||
mm.sendAsyncMessage("Test:ExpectNoObserverCalled");
|
||||
});
|
||||
}
|
||||
|
||||
function promiseMessageReceived() {
|
||||
return new Promise((resolve, reject) => {
|
||||
let mm = _mm();
|
||||
|
@ -439,7 +451,9 @@ function checkDeviceSelectors(aAudio, aVideo, aScreen) {
|
|||
ok(screenSelector.hidden, "screen selector hidden");
|
||||
}
|
||||
|
||||
function* checkSharingUI(aExpected, aWin = window) {
|
||||
// aExpected is for the current tab,
|
||||
// aExpectedGlobal is for all tabs.
|
||||
function* checkSharingUI(aExpected, aWin = window, aExpectedGlobal = null) {
|
||||
let doc = aWin.document;
|
||||
// First check the icon above the control center (i) icon.
|
||||
let identityBox = doc.getElementById("identity-box");
|
||||
|
@ -483,7 +497,7 @@ function* checkSharingUI(aExpected, aWin = window) {
|
|||
aWin.gIdentityHandler._identityPopup.hidden = true;
|
||||
|
||||
// Check the global indicators.
|
||||
yield* assertWebRTCIndicatorStatus(aExpected);
|
||||
yield* assertWebRTCIndicatorStatus(aExpectedGlobal || aExpected);
|
||||
}
|
||||
|
||||
function* checkNotSharing() {
|
||||
|
|
|
@ -154,6 +154,13 @@ this.webrtcUI = {
|
|||
webrtcUI.forgetActivePermissionsFromBrowser(aBrowser);
|
||||
},
|
||||
|
||||
forgetStreamsFromProcess(aProcessMM) {
|
||||
// stream.processMM is null when e10s is disabled.
|
||||
this._streams =
|
||||
this._streams.filter(stream => stream.processMM &&
|
||||
stream.processMM != aProcessMM);
|
||||
},
|
||||
|
||||
showSharingDoorhanger(aActiveStream) {
|
||||
let browserWindow = aActiveStream.browser.ownerGlobal;
|
||||
if (aActiveStream.tab) {
|
||||
|
@ -279,30 +286,40 @@ this.webrtcUI = {
|
|||
removePrompt(aMessage.target, aMessage.data);
|
||||
break;
|
||||
case "webrtc:UpdatingIndicators":
|
||||
webrtcUI._streams = [];
|
||||
webrtcUI.forgetStreamsFromProcess(aMessage.target);
|
||||
break;
|
||||
case "webrtc:UpdateGlobalIndicators":
|
||||
updateIndicators(aMessage.data, aMessage.target);
|
||||
break;
|
||||
case "webrtc:UpdateBrowserIndicators":
|
||||
let id = aMessage.data.windowId;
|
||||
aMessage.targetFrameLoader.QueryInterface(Ci.nsIFrameLoader);
|
||||
let processMM =
|
||||
aMessage.targetFrameLoader.messageManager.processMessageManager;
|
||||
let index;
|
||||
for (index = 0; index < webrtcUI._streams.length; ++index) {
|
||||
if (webrtcUI._streams[index].state.windowId == id)
|
||||
let stream = webrtcUI._streams[index];
|
||||
if (stream.state.windowId == id && stream.processMM == processMM)
|
||||
break;
|
||||
}
|
||||
// If there's no documentURI, the update is actually a removal of the
|
||||
// stream, triggered by the recording-window-ended notification.
|
||||
if (!aMessage.data.documentURI && index < webrtcUI._streams.length)
|
||||
if (!aMessage.data.documentURI && index < webrtcUI._streams.length) {
|
||||
webrtcUI._streams.splice(index, 1);
|
||||
else
|
||||
webrtcUI._streams[index] = {browser: aMessage.target, state: aMessage.data};
|
||||
} else {
|
||||
webrtcUI._streams[index] = {
|
||||
browser: aMessage.target,
|
||||
processMM,
|
||||
state: aMessage.data
|
||||
};
|
||||
}
|
||||
let tabbrowser = aMessage.target.ownerGlobal.gBrowser;
|
||||
if (tabbrowser)
|
||||
tabbrowser.setBrowserSharing(aMessage.target, aMessage.data);
|
||||
break;
|
||||
case "child-process-shutdown":
|
||||
webrtcUI.processIndicators.delete(aMessage.target);
|
||||
webrtcUI.forgetStreamsFromProcess(aMessage.target);
|
||||
updateIndicators(null, null);
|
||||
break;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче