summaryrefslogtreecommitdiffstats
path: root/dom/media/mediacontrol/tests/browser/browser_media_control_audio_focus_within_a_page.js
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/mediacontrol/tests/browser/browser_media_control_audio_focus_within_a_page.js')
-rw-r--r--dom/media/mediacontrol/tests/browser/browser_media_control_audio_focus_within_a_page.js358
1 files changed, 358 insertions, 0 deletions
diff --git a/dom/media/mediacontrol/tests/browser/browser_media_control_audio_focus_within_a_page.js b/dom/media/mediacontrol/tests/browser/browser_media_control_audio_focus_within_a_page.js
new file mode 100644
index 0000000000..5db37059dd
--- /dev/null
+++ b/dom/media/mediacontrol/tests/browser/browser_media_control_audio_focus_within_a_page.js
@@ -0,0 +1,358 @@
+const mainPageURL =
+ "https://example.com/browser/dom/media/mediacontrol/tests/browser/file_main_frame_with_multiple_child_session_frames.html";
+const frameURL =
+ "https://example.com/browser/dom/media/mediacontrol/tests/browser/file_iframe_media.html";
+
+const frame1 = "frame1";
+const frame2 = "frame2";
+
+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 the behaviors when we play media from different
+ * frames. When a page contains multiple frames, if those frames are using the
+ * media session and set the metadata, then we have to know which frame owns the
+ * audio focus that would be the last tab playing media. When the frame owns
+ * audio focus, it means its metadata would be displayed on the virtual control
+ * interface if it has a media session.
+ */
+add_task(async function testAudioFocusChangesAmongMultipleFrames() {
+ /**
+ * Play the media from the main frame, so it would own the audio focus and
+ * its metadata should be shown on the virtual control interface. As the main
+ * frame doesn't use media session, the current metadata would be the default
+ * metadata.
+ */
+ const tab = await createLoadedTabWrapper(mainPageURL);
+ await playAndWaitUntilMetadataChanged(tab);
+ await isGivenTabUsingDefaultMetadata(tab);
+
+ /**
+ * Play media for frame1, so the audio focus switches to frame1 because it's
+ * the last tab playing media and frame1's metadata should be displayed.
+ */
+ await loadPageForFrame(tab, frame1, frameURL);
+ let metadata = await setMetadataAndGetReturnResult(tab, frame1);
+ await playAndWaitUntilMetadataChanged(tab, frame1);
+ isCurrentMetadataEqualTo(metadata);
+
+ /**
+ * Play media for frame2, so the audio focus switches to frame2 because it's
+ * the last tab playing media and frame2's metadata should be displayed.
+ */
+ await loadPageForFrame(tab, frame2, frameURL);
+ metadata = await setMetadataAndGetReturnResult(tab, frame2);
+ await playAndWaitUntilMetadataChanged(tab, frame2);
+ isCurrentMetadataEqualTo(metadata);
+
+ /**
+ * Remove tab and end test.
+ */
+ await tab.close();
+});
+
+add_task(async function testAudioFocusChangesAfterPausingAudioFocusOwner() {
+ /**
+ * Play the media from the main frame, so it would own the audio focus and
+ * its metadata should be shown on the virtual control interface. As the main
+ * frame doesn't use media session, the current metadata would be the default
+ * metadata.
+ */
+ const tab = await createLoadedTabWrapper(mainPageURL);
+ await playAndWaitUntilMetadataChanged(tab);
+ await isGivenTabUsingDefaultMetadata(tab);
+
+ /**
+ * Play media for frame1, so the audio focus switches to frame1 because it's
+ * the last tab playing media and frame1's metadata should be displayed.
+ */
+ await loadPageForFrame(tab, frame1, frameURL);
+ let metadata = await setMetadataAndGetReturnResult(tab, frame1);
+ await playAndWaitUntilMetadataChanged(tab, frame1);
+ isCurrentMetadataEqualTo(metadata);
+
+ /**
+ * Pause media for frame1, so the audio focus switches back to the main frame
+ * which is still playing media.
+ */
+ await pauseAndWaitUntilMetadataChangedFrom(tab, frame1);
+ await isGivenTabUsingDefaultMetadata(tab);
+
+ /**
+ * Remove tab and end test.
+ */
+ await tab.close();
+});
+
+add_task(async function testAudioFocusUnchangesAfterPausingAudioFocusOwner() {
+ /**
+ * Play the media from the main frame, so it would own the audio focus and
+ * its metadata should be shown on the virtual control interface. As the main
+ * frame doesn't use media session, the current metadata would be the default
+ * metadata.
+ */
+ const tab = await createLoadedTabWrapper(mainPageURL);
+ await playAndWaitUntilMetadataChanged(tab);
+ await isGivenTabUsingDefaultMetadata(tab);
+
+ /**
+ * Play media for frame1, so the audio focus switches to frame1 because it's
+ * the last tab playing media and frame1's metadata should be displayed.
+ */
+ await loadPageForFrame(tab, frame1, frameURL);
+ let metadata = await setMetadataAndGetReturnResult(tab, frame1);
+ await playAndWaitUntilMetadataChanged(tab, frame1);
+ isCurrentMetadataEqualTo(metadata);
+
+ /**
+ * Pause main frame's media first. When pausing frame1's media, there are not
+ * other frames playing media, so frame1 still owns the audio focus and its
+ * metadata should be displayed.
+ */
+ await pauseMediaFrom(tab);
+ isCurrentMetadataEqualTo(metadata);
+
+ /**
+ * Remove tab and end test.
+ */
+ await tab.close();
+});
+
+add_task(
+ async function testSwitchAudioFocusToMainFrameAfterRemovingAudioFocusOwner() {
+ /**
+ * Play the media from the main frame, so it would own the audio focus and
+ * its metadata should be displayed on the virtual control interface. As the
+ * main frame doesn't use media session, the current metadata would be the
+ * default metadata.
+ */
+ const tab = await createLoadedTabWrapper(mainPageURL);
+ await playAndWaitUntilMetadataChanged(tab);
+ await isGivenTabUsingDefaultMetadata(tab);
+
+ /**
+ * Play media for frame1, so the audio focus switches to frame1 because it's
+ * the last tab playing media and frame1's metadata should be displayed.
+ */
+ await loadPageForFrame(tab, frame1, frameURL);
+ let metadata = await setMetadataAndGetReturnResult(tab, frame1);
+ await playAndWaitUntilMetadataChanged(tab, frame1);
+ isCurrentMetadataEqualTo(metadata);
+
+ /**
+ * Remove frame1, the audio focus would switch to the main frame which
+ * metadata should be displayed.
+ */
+ await Promise.all([
+ waitUntilDisplayedMetadataChanged(),
+ removeFrame(tab, frame1),
+ ]);
+ await isGivenTabUsingDefaultMetadata(tab);
+
+ /**
+ * Remove tab and end test.
+ */
+ await tab.close();
+ }
+);
+
+add_task(
+ async function testSwitchAudioFocusToIframeAfterRemovingAudioFocusOwner() {
+ /**
+ * Play media for frame1, so frame1 owns the audio focus and frame1's metadata
+ * should be displayed.
+ */
+ const tab = await createLoadedTabWrapper(mainPageURL);
+ await loadPageForFrame(tab, frame1, frameURL);
+ let metadataFrame1 = await setMetadataAndGetReturnResult(tab, frame1);
+ await playAndWaitUntilMetadataChanged(tab, frame1);
+ isCurrentMetadataEqualTo(metadataFrame1);
+
+ /**
+ * Play media for frame2, so the audio focus switches to frame2 because it's
+ * the last tab playing media and frame2's metadata should be displayed.
+ */
+ await loadPageForFrame(tab, frame2, frameURL);
+ let metadataFrame2 = await setMetadataAndGetReturnResult(tab, frame2);
+ await playAndWaitUntilMetadataChanged(tab, frame2);
+ isCurrentMetadataEqualTo(metadataFrame2);
+
+ /**
+ * Remove frame2, the audio focus would switch to frame1 which metadata should
+ * be displayed.
+ */
+ await Promise.all([
+ waitUntilDisplayedMetadataChanged(),
+ removeFrame(tab, frame2),
+ ]);
+ isCurrentMetadataEqualTo(metadataFrame1);
+
+ /**
+ * Remove tab and end test.
+ */
+ await tab.close();
+ }
+);
+
+add_task(async function testNoAudioFocusAfterRemovingAudioFocusOwner() {
+ /**
+ * Play the media from the main frame, so it would own the audio focus and
+ * its metadata should be shown on the virtual control interface. As the main
+ * frame doesn't use media session, the current metadata would be the default
+ * metadata.
+ */
+ const tab = await createLoadedTabWrapper(mainPageURL);
+ await playAndWaitUntilMetadataChanged(tab);
+ await isGivenTabUsingDefaultMetadata(tab);
+
+ /**
+ * Play media for frame1, so the audio focus switches to frame1 because it's
+ * the last tab playing media and frame1's metadata should be displayed.
+ */
+ await loadPageForFrame(tab, frame1, frameURL);
+ let metadata = await setMetadataAndGetReturnResult(tab, frame1);
+ await playAndWaitUntilMetadataChanged(tab, frame1);
+ isCurrentMetadataEqualTo(metadata);
+
+ /**
+ * Pause media in main frame and then remove frame1. As the frame which owns
+ * the audio focus is removed and no frame is still playing media, the current
+ * metadata would be the default metadata.
+ */
+ await pauseMediaFrom(tab);
+ await Promise.all([
+ waitUntilDisplayedMetadataChanged(),
+ removeFrame(tab, frame1),
+ ]);
+ await isGivenTabUsingDefaultMetadata(tab);
+
+ /**
+ * Remove tab and end test.
+ */
+ await tab.close();
+});
+
+/**
+ * The following are helper functions.
+ */
+function loadPageForFrame(tab, frameId, pageUrl) {
+ info(`start to load page for ${frameId}`);
+ return SpecialPowers.spawn(
+ tab.linkedBrowser,
+ [frameId, pageUrl],
+ async (id, url) => {
+ const iframe = content.document.getElementById(id);
+ if (!iframe) {
+ ok(false, `can not get iframe '${id}'`);
+ }
+ iframe.src = url;
+ await new Promise(r => (iframe.onload = r));
+ // Set the document title that would be used as the value for properties
+ // in frame's medadata.
+ iframe.contentDocument.title = id;
+ }
+ );
+}
+
+function playMediaFrom(tab, frameId = undefined) {
+ return SpecialPowers.spawn(tab.linkedBrowser, [frameId], id => {
+ if (id == undefined) {
+ info(`start to play media from main frame`);
+ const video = content.document.getElementById("video");
+ if (!video) {
+ ok(false, `can't get the media element!`);
+ }
+ return video.play();
+ }
+
+ info(`start to play media from ${id}`);
+ const iframe = content.document.getElementById(id);
+ if (!iframe) {
+ ok(false, `can not get ${id}`);
+ }
+ iframe.contentWindow.postMessage("play", "*");
+ return new Promise(r => {
+ content.onmessage = event => {
+ is(event.data, "played", `media started playing in ${id}`);
+ r();
+ };
+ });
+ });
+}
+
+function playAndWaitUntilMetadataChanged(tab, frameId = undefined) {
+ const metadataChanged = frameId
+ ? new Promise(r => (tab.controller.onmetadatachange = r))
+ : waitUntilDisplayedMetadataChanged();
+ return Promise.all([metadataChanged, playMediaFrom(tab, frameId)]);
+}
+
+function pauseMediaFrom(tab, frameId = undefined) {
+ return SpecialPowers.spawn(tab.linkedBrowser, [frameId], id => {
+ if (id == undefined) {
+ info(`start to pause media from in frame`);
+ const video = content.document.getElementById("video");
+ if (!video) {
+ ok(false, `can't get the media element!`);
+ }
+ return video.pause();
+ }
+
+ info(`start to pause media in ${id}`);
+ const iframe = content.document.getElementById(id);
+ if (!iframe) {
+ ok(false, `can not get ${id}`);
+ }
+ iframe.contentWindow.postMessage("pause", "*");
+ return new Promise(r => {
+ content.onmessage = event => {
+ is(event.data, "paused", `media paused in ${id}`);
+ r();
+ };
+ });
+ });
+}
+
+function pauseAndWaitUntilMetadataChangedFrom(tab, frameId = undefined) {
+ const metadataChanged = waitUntilDisplayedMetadataChanged();
+ return Promise.all([metadataChanged, pauseMediaFrom(tab, frameId)]);
+}
+
+function setMetadataAndGetReturnResult(tab, frameId) {
+ info(`start to set metadata for ${frameId}`);
+ return SpecialPowers.spawn(tab.linkedBrowser, [frameId], id => {
+ const iframe = content.document.getElementById(id);
+ if (!iframe) {
+ ok(false, `can not get ${id}`);
+ }
+ iframe.contentWindow.postMessage("setMetadata", "*");
+ info(`wait until we get metadata for ${id}`);
+ return new Promise(r => {
+ content.onmessage = event => {
+ ok(
+ event.data.title && event.data.artist && event.data.album,
+ "correct return format"
+ );
+ r(event.data);
+ };
+ });
+ });
+}
+
+function removeFrame(tab, frameId) {
+ info(`remove ${frameId}`);
+ return SpecialPowers.spawn(tab.linkedBrowser, [frameId], id => {
+ const iframe = content.document.getElementById(id);
+ if (!iframe) {
+ ok(false, `can not get ${id}`);
+ }
+ content.document.body.removeChild(iframe);
+ });
+}