diff options
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.js | 358 |
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); + }); +} |