const PAGE_URL = "https://example.com/browser/dom/media/mediacontrol/tests/browser/file_non_autoplay.html"; const IFRAME_URL = "https://example.com/browser/dom/media/mediacontrol/tests/browser/file_iframe_media.html"; const testVideoId = "video"; add_task(async function setupTestingPref() { await SpecialPowers.pushPrefEnv({ set: [ ["media.mediacontrol.testingevents.enabled", true], ["dom.media.mediasession.enabled", true], ], }); }); /** * This test is used to check if we can receive correct position state change, * when we set the position state to the media session. */ add_task(async function testSetPositionState() { info(`open media page`); const tab = await createLoadedTabWrapper(PAGE_URL); info(`start media`); await playMedia(tab, testVideoId); info(`set duration only`); await setPositionState(tab, { duration: 60, }); info(`set duration and playback rate`); await setPositionState(tab, { duration: 50, playbackRate: 2.0, }); info(`set duration, playback rate and position`); await setPositionState(tab, { duration: 40, playbackRate: 3.0, position: 10, }); info(`remove tab`); await tab.close(); }); add_task(async function testSetPositionStateFromInactiveMediaSession() { info(`open media page`); const tab = await createLoadedTabWrapper(PAGE_URL); info(`start media`); await playMedia(tab, testVideoId); info( `add an event listener to measure how many times the position state changes` ); let positionChangedNum = 0; const controller = tab.linkedBrowser.browsingContext.mediaController; controller.onpositionstatechange = () => positionChangedNum++; info(`set position state on the main page which has an active media session`); await setPositionState(tab, { duration: 60, }); info(`set position state on the iframe which has an inactive media session`); await setPositionStateOnInactiveMediaSession(tab); info(`set position state on the main page again`); await setPositionState(tab, { duration: 60, }); is( positionChangedNum, 2, `We should only receive two times of position change, because ` + `the second one which performs on inactive media session is effectless` ); info(`remove tab`); await tab.close(); }); /** * The following are helper functions. */ async function setPositionState(tab, positionState) { const controller = tab.linkedBrowser.browsingContext.mediaController; const positionStateChanged = new Promise(r => { controller.addEventListener( "positionstatechange", event => { const { duration, playbackRate, position } = positionState; // duration is mandatory. is( event.duration, duration, `expected duration ${event.duration} is equal to ${duration}` ); // Playback rate is optional, if it's not present, default should be 1.0 if (playbackRate) { is( event.playbackRate, playbackRate, `expected playbackRate ${event.playbackRate} is equal to ${playbackRate}` ); } else { is(event.playbackRate, 1.0, `expected default playbackRate is 1.0`); } // Position state is optional, if it's not present, default should be 0.0 if (position) { is( event.position, position, `expected position ${event.position} is equal to ${position}` ); } else { is(event.position, 0.0, `expected default position is 0.0`); } r(); }, { once: true } ); }); await SpecialPowers.spawn( tab.linkedBrowser, [positionState], positionState => { content.navigator.mediaSession.setPositionState(positionState); } ); await positionStateChanged; } async function setPositionStateOnInactiveMediaSession(tab) { return SpecialPowers.spawn(tab.linkedBrowser, [IFRAME_URL], async url => { info(`create iframe and wait until it finishes loading`); const iframe = content.document.getElementById("iframe"); iframe.src = url; await new Promise(r => (iframe.onload = r)); info(`trigger media in iframe entering into fullscreen`); iframe.contentWindow.postMessage("setPositionState", "*"); }); }