зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1809985 - part1 : add a test to ensure that playback can be recovered from crash. r=jolin
Differential Revision: https://phabricator.services.mozilla.com/D166721
This commit is contained in:
Родитель
9ebf1f03a8
Коммит
b6fd1283a6
|
@ -98,6 +98,7 @@ BROWSER_CHROME_MANIFESTS += [
|
|||
"mediacontrol/tests/browser/browser.ini",
|
||||
"mediasession/test/browser.ini",
|
||||
"test/browser/browser.ini",
|
||||
"test/browser/wmfme/browser.ini",
|
||||
]
|
||||
|
||||
if CONFIG["MOZ_WEBRTC"]:
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
[DEFAULT]
|
||||
subsuite = media-bc
|
||||
tags = media-engine-compatible
|
||||
run-if = wmfme
|
||||
support-files =
|
||||
head.js
|
||||
file_video.html
|
||||
../../gizmo.mp4
|
||||
|
||||
[browser_wmfme_crash.js]
|
|
@ -0,0 +1,52 @@
|
|||
"use strict";
|
||||
|
||||
/**
|
||||
* This test aims to ensure that the media engine playback will recover from a
|
||||
* crash and keep playing without any problem.
|
||||
*/
|
||||
add_task(async function setupTestingPref() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["media.wmf.media-engine.enabled", true],
|
||||
["media.wmf.media-engine.channel-decoder.enabled", true],
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
const VIDEO_PAGE = GetTestWebBasedURL("file_video.html");
|
||||
|
||||
add_task(async function testPlaybackRecoveryFromCrash() {
|
||||
info(`Create a tab and load test page`);
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(
|
||||
window.gBrowser,
|
||||
"about:blank"
|
||||
);
|
||||
BrowserTestUtils.loadURI(tab.linkedBrowser, VIDEO_PAGE);
|
||||
await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
|
||||
|
||||
await playVideo(tab);
|
||||
|
||||
info("Ensure video is running via the media engine framework");
|
||||
await assertRunningProcessAndDecoderName(tab, {
|
||||
expectedProcess: "Utility MF Media Engine CDM",
|
||||
expectedDecoder: "media engine video stream",
|
||||
});
|
||||
|
||||
const pidBeforeCrash = await getMFCDMProcessId();
|
||||
await crashUtilityProcess(pidBeforeCrash);
|
||||
|
||||
info("The CDM process should be recreated which makes media keep playing");
|
||||
await assertRunningProcessAndDecoderName(tab, {
|
||||
expectedProcess: "Utility MF Media Engine CDM",
|
||||
expectedDecoder: "media engine video stream",
|
||||
});
|
||||
|
||||
const pidAfterCrash = await getMFCDMProcessId();
|
||||
isnot(
|
||||
pidBeforeCrash,
|
||||
pidAfterCrash,
|
||||
`new process ${pidAfterCrash} is not previous crashed one ${pidBeforeCrash}`
|
||||
);
|
||||
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
});
|
|
@ -0,0 +1,9 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>video</title>
|
||||
</head>
|
||||
<body>
|
||||
<video id="v" src="gizmo.mp4" controls loop></video>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,163 @@
|
|||
"use strict";
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
const origin = "https://example.com";
|
||||
return (
|
||||
getRootDirectory(gTestPath).replace("chrome://mochitests/content", origin) +
|
||||
fileName
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return current process Id for the Media Foundation CDM process.
|
||||
*/
|
||||
async function getMFCDMProcessId() {
|
||||
const process = (await ChromeUtils.requestProcInfo()).children.find(
|
||||
p =>
|
||||
p.type === "utility" &&
|
||||
p.utilityActors.find(a => a.actorName === "mfMediaEngineCDM")
|
||||
);
|
||||
return process.pid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the utility process with given process id crash.
|
||||
* @param {int} pid
|
||||
* the process id for the process which is going to crash
|
||||
*/
|
||||
async function crashUtilityProcess(utilityPid) {
|
||||
info(`Crashing process ${utilityPid}`);
|
||||
SimpleTest.expectChildProcessCrash();
|
||||
|
||||
const crashMan = Services.crashmanager;
|
||||
const utilityProcessGone = TestUtils.topicObserved(
|
||||
"ipc:utility-shutdown",
|
||||
(subject, data) => {
|
||||
info(`ipc:utility-shutdown: data=${data} subject=${subject}`);
|
||||
return parseInt(data, 10) === utilityPid;
|
||||
}
|
||||
);
|
||||
|
||||
info("Prune any previous crashes");
|
||||
const future = new Date(Date.now() + 1000 * 60 * 60 * 24);
|
||||
await crashMan.pruneOldCrashes(future);
|
||||
|
||||
info("Crash Utility Process");
|
||||
const ProcessTools = Cc["@mozilla.org/processtools-service;1"].getService(
|
||||
Ci.nsIProcessToolsService
|
||||
);
|
||||
|
||||
info(`Crash Utility Process ${utilityPid}`);
|
||||
ProcessTools.crash(utilityPid);
|
||||
|
||||
info(`Waiting for utility process ${utilityPid} to go away.`);
|
||||
let [subject, data] = await utilityProcessGone;
|
||||
ok(
|
||||
parseInt(data, 10) === utilityPid,
|
||||
`Should match the crashed PID ${utilityPid} with ${data}`
|
||||
);
|
||||
ok(
|
||||
subject instanceof Ci.nsIPropertyBag2,
|
||||
"Subject needs to be a nsIPropertyBag2 to clean up properly"
|
||||
);
|
||||
|
||||
const dumpID = subject.getPropertyAsAString("dumpID");
|
||||
ok(dumpID, "There should be a dumpID");
|
||||
|
||||
await crashMan.ensureCrashIsPresent(dumpID);
|
||||
await crashMan.getCrashes().then(crashes => {
|
||||
is(crashes.length, 1, "There should be only one record");
|
||||
const crash = crashes[0];
|
||||
ok(
|
||||
crash.isOfType(
|
||||
crashMan.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_UTILITY],
|
||||
crashMan.CRASH_TYPE_CRASH
|
||||
),
|
||||
"Record should be a utility process crash"
|
||||
);
|
||||
ok(crash.id === dumpID, "Record should have an ID");
|
||||
});
|
||||
|
||||
let minidumpDirectory = Services.dirsvc.get("ProfD", Ci.nsIFile);
|
||||
minidumpDirectory.append("minidumps");
|
||||
|
||||
let dumpfile = minidumpDirectory.clone();
|
||||
dumpfile.append(dumpID + ".dmp");
|
||||
if (dumpfile.exists()) {
|
||||
info(`Removal of ${dumpfile.path}`);
|
||||
dumpfile.remove(false);
|
||||
}
|
||||
|
||||
let extrafile = minidumpDirectory.clone();
|
||||
extrafile.append(dumpID + ".extra");
|
||||
info(`Removal of ${extrafile.path}`);
|
||||
if (extrafile.exists()) {
|
||||
extrafile.remove(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make video in the tab play.
|
||||
* @param {object} tab
|
||||
* the tab contains at least one video element
|
||||
*/
|
||||
async function playVideo(tab) {
|
||||
return SpecialPowers.spawn(tab.linkedBrowser, [], async _ => {
|
||||
const video = content.document.querySelector("video");
|
||||
ok(
|
||||
await video.play().then(
|
||||
() => true,
|
||||
() => false
|
||||
),
|
||||
"video started playing"
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the video playback is performed in the right process and right decoder.
|
||||
* @param {object} tab
|
||||
* the tab which has a playing video
|
||||
* @param {string} expectedProcess
|
||||
* the expected process name
|
||||
* @param {string} expectedDecoder
|
||||
* the expected decoder name
|
||||
*/
|
||||
async function assertRunningProcessAndDecoderName(
|
||||
tab,
|
||||
{ expectedProcess, expectedDecoder } = {}
|
||||
) {
|
||||
return SpecialPowers.spawn(
|
||||
tab.linkedBrowser,
|
||||
[expectedProcess, expectedDecoder],
|
||||
// eslint-disable-next-line no-shadow
|
||||
async (expectedProcess, expectedDecoder) => {
|
||||
const video = content.document.querySelector("video");
|
||||
ok(!video.paused, "checking a playing video");
|
||||
|
||||
const debugInfo = await SpecialPowers.wrap(video).mozRequestDebugInfo();
|
||||
const videoDecoderName = debugInfo.decoder.reader.videoDecoderName;
|
||||
|
||||
const isExpectedDecoder =
|
||||
videoDecoderName.indexOf(`${expectedDecoder}`) == 0;
|
||||
ok(
|
||||
isExpectedDecoder,
|
||||
`Playback running by decoder '${videoDecoderName}', expected '${expectedDecoder}'`
|
||||
);
|
||||
|
||||
const isExpectedProcess =
|
||||
videoDecoderName.indexOf(`(${expectedProcess} remote)`) > 0;
|
||||
ok(
|
||||
isExpectedProcess,
|
||||
`Playback running in process '${videoDecoderName}', expected '${expectedProcess}'`
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
Загрузка…
Ссылка в новой задаче