1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
|
<!DOCTYPE HTML>
<html>
<head>
<title>Test window for triggering media session's action handler</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="MediaSessionTestUtils.js"></script>
</head>
<body>
<video id="testVideo" src="gizmo.mp4" loop></video>
<iframe id="childFrame"></iframe>
<script>
var triggeredActionNums = 0;
nextWindowMessage().then(
async (event) => {
const testInfo = event.data;
await createSession(testInfo);
// Media session would only become active if there is any media currently
// playing. Non-active media session won't receive any actions. Therefore,
// we start media playback before testing media session.
await startMediaPlayback(testInfo);
for (const action of gMediaSessionActions) {
await waitUntilActionHandlerTriggered(action, testInfo);
}
endTestAndReportResult();
});
/**
* The following are helper functions
*/
async function startMediaPlayback({shouldCreateFrom}) {
info(`wait until media starts playing`);
if (shouldCreateFrom == "main-frame") {
const video = document.getElementById("testVideo");
await video.play();
// As we can't observe `media-displayed-playback-changed` notification,
// that can only be observed in the chrome process. Therefore, we use a
// workaround instead which is to wait for a while to ensure that the
// controller has already been created in the chrome process.
let timeupdatecount = 0;
await new Promise(r => video.ontimeupdate = () => {
if (++timeupdatecount == 3) {
video.ontimeupdate = null;
r();
}
});
} else {
const iframe = document.getElementById("childFrame");
iframe.contentWindow.postMessage("play", "*");
await new Promise(r => {
window.onmessage = event => {
is(event.data, "played", `media started playing in child-frame`);
r();
};
});
}
}
async function createSession({shouldCreateFrom, origin}) {
info(`create media session in ${shouldCreateFrom}`);
if (shouldCreateFrom == "main-frame") {
// Simply referencing media session will create media session.
navigator.mediaSession;
return;
};
const frame = document.getElementById("childFrame");
const originURL = origin == "same-origin"
? "http://mochi.test:8888" : "http://example.org";
frame.src = originURL + "/tests/dom/media/mediasession/test/file_trigger_actionhanlder_frame.html";
await new Promise(r => frame.onload = r);
}
async function waitUntilActionHandlerTriggered(action, {shouldCreateFrom}) {
info(`wait until '${action}' handler of media session created in ` +
`${shouldCreateFrom} is triggered`);
if (shouldCreateFrom == "main-frame") {
let promise = new Promise(resolve => {
navigator.mediaSession.setActionHandler(action, () => {
ok(true, `Triggered ${action} handler`);
triggeredActionNums++;
resolve();
});
});
SpecialPowers.generateMediaControlKeyTestEvent(action);
await promise;
return;
}
SpecialPowers.generateMediaControlKeyTestEvent(action);
if ((await nextWindowMessage()).data == action) {
info(`Triggered ${action} handler in child-frame`);
triggeredActionNums++;
}
}
function endTestAndReportResult() {
const w = window.opener || window.parent;
if (triggeredActionNums == gMediaSessionActions.length) {
w.postMessage("success", "*");
} else {
w.postMessage("fail", "*");
}
}
</script>
</body>
</html>
|