browser_active_mediasession_among_tabs.js (6730B)
1 /* eslint-disable no-undef */ 2 "use strict"; 3 4 const PAGE = 5 "https://example.com/browser/dom/media/mediasession/test/file_media_session.html"; 6 7 const ACTION = "previoustrack"; 8 9 add_task(async function setupTestingPref() { 10 await SpecialPowers.pushPrefEnv({ 11 set: [["media.mediacontrol.testingevents.enabled", true]], 12 }); 13 }); 14 15 /** 16 * When multiple tabs are all having media session, the latest created one would 17 * become an active session. When the active media session is destroyed via 18 * closing the tab, the previous active session would become current active 19 * session again. 20 */ 21 add_task(async function testActiveSessionWhenClosingTab() { 22 info(`open tab1 and load media session test page`); 23 const tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE); 24 await startMediaPlaybackAndWaitMedisSessionBecomeActiveSession(tab1); 25 26 info(`pressing '${ACTION}' key`); 27 MediaControlService.generateMediaControlKey(ACTION); 28 29 info(`session in tab1 should become active session`); 30 await checkIfActionReceived(tab1, ACTION); 31 32 info(`open tab2 and load media session test page`); 33 const tab2 = await BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE); 34 await startMediaPlaybackAndWaitMedisSessionBecomeActiveSession(tab2); 35 36 info(`pressing '${ACTION}' key`); 37 MediaControlService.generateMediaControlKey(ACTION); 38 39 info(`session in tab2 should become active session`); 40 await checkIfActionReceived(tab2, ACTION); 41 await checkIfActionNotReceived(tab1, ACTION); 42 43 info(`remove tab2`); 44 const controllerChanged = waitUntilMainMediaControllerChanged(); 45 BrowserTestUtils.removeTab(tab2); 46 await controllerChanged; 47 48 info(`pressing '${ACTION}' key`); 49 MediaControlService.generateMediaControlKey(ACTION); 50 51 info(`session in tab1 should become active session again`); 52 await checkIfActionReceived(tab1, ACTION); 53 54 info(`remove tab1`); 55 BrowserTestUtils.removeTab(tab1); 56 }); 57 58 /** 59 * This test is similar with `testActiveSessionWhenClosingTab`, the difference 60 * is that the way we use to destroy active session is via naviagation, not 61 * closing tab. 62 */ 63 add_task(async function testActiveSessionWhenNavigatingTab() { 64 info(`open tab1 and load media session test page`); 65 const tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE); 66 await startMediaPlaybackAndWaitMedisSessionBecomeActiveSession(tab1); 67 68 info(`pressing '${ACTION}' key`); 69 MediaControlService.generateMediaControlKey(ACTION); 70 71 info(`session in tab1 should become active session`); 72 await checkIfActionReceived(tab1, ACTION); 73 74 info(`open tab2 and load media session test page`); 75 const tab2 = await BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE); 76 await startMediaPlaybackAndWaitMedisSessionBecomeActiveSession(tab2); 77 78 info(`pressing '${ACTION}' key`); 79 MediaControlService.generateMediaControlKey(ACTION); 80 81 info(`session in tab2 should become active session`); 82 await checkIfActionReceived(tab2, ACTION); 83 await checkIfActionNotReceived(tab1, ACTION); 84 85 info(`navigate tab2 to blank page`); 86 const controllerChanged = waitUntilMainMediaControllerChanged(); 87 BrowserTestUtils.startLoadingURIString(tab2.linkedBrowser, "about:blank"); 88 await controllerChanged; 89 90 info(`pressing '${ACTION}' key`); 91 MediaControlService.generateMediaControlKey(ACTION); 92 93 info(`session in tab1 should become active session`); 94 await checkIfActionReceived(tab1, ACTION); 95 96 info(`remove tabs`); 97 BrowserTestUtils.removeTab(tab1); 98 BrowserTestUtils.removeTab(tab2); 99 }); 100 101 /** 102 * If we create a media session in a tab where no any playing media exists, then 103 * that session would not involve in global active media session selection. The 104 * current active media session would remain unchanged. 105 */ 106 add_task(async function testCreatingSessionWithoutPlayingMedia() { 107 info(`open tab1 and load media session test page`); 108 const tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE); 109 await startMediaPlaybackAndWaitMedisSessionBecomeActiveSession(tab1); 110 111 info(`pressing '${ACTION}' key`); 112 MediaControlService.generateMediaControlKey(ACTION); 113 114 info(`session in tab1 should become active session`); 115 await checkIfActionReceived(tab1, ACTION); 116 117 info(`open tab2 and load media session test page`); 118 const tab2 = await BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE); 119 120 info(`pressing '${ACTION}' key`); 121 MediaControlService.generateMediaControlKey(ACTION); 122 123 info( 124 `session in tab1 is still an active session because there is no media playing in tab2` 125 ); 126 await checkIfActionReceived(tab1, ACTION); 127 await checkIfActionNotReceived(tab2, ACTION); 128 129 info(`remove tabs`); 130 BrowserTestUtils.removeTab(tab1); 131 BrowserTestUtils.removeTab(tab2); 132 }); 133 134 /** 135 * The following are helper functions 136 */ 137 async function startMediaPlaybackAndWaitMedisSessionBecomeActiveSession(tab) { 138 await Promise.all([ 139 BrowserUtils.promiseObserved("active-media-session-changed"), 140 SpecialPowers.spawn(tab.linkedBrowser, [], () => { 141 const video = content.document.getElementById("testVideo"); 142 if (!video) { 143 ok(false, `can't get the media element!`); 144 } 145 video.play(); 146 }), 147 ]); 148 } 149 150 async function checkIfActionReceived(tab, action) { 151 await SpecialPowers.spawn(tab.linkedBrowser, [action], expectedAction => { 152 return new Promise(resolve => { 153 const result = content.document.getElementById("result"); 154 if (!result) { 155 ok(false, `can't get the element for showing result!`); 156 } 157 158 function checkAction() { 159 is( 160 result.innerHTML, 161 expectedAction, 162 `received '${expectedAction}' correctly` 163 ); 164 // Reset the result after finishing checking result, then we can dispatch 165 // same action again without worrying about previous result. 166 result.innerHTML = ""; 167 resolve(); 168 } 169 170 if (result.innerHTML == "") { 171 info(`wait until receiving action`); 172 result.addEventListener("actionChanged", () => checkAction(), { 173 once: true, 174 }); 175 } else { 176 checkAction(); 177 } 178 }); 179 }); 180 } 181 182 async function checkIfActionNotReceived(tab, action) { 183 await SpecialPowers.spawn(tab.linkedBrowser, [action], expectedAction => { 184 return new Promise(resolve => { 185 const result = content.document.getElementById("result"); 186 if (!result) { 187 ok(false, `can't get the element for showing result!`); 188 } 189 is(result.innerHTML, "", `should not receive any action`); 190 ok(result.innerHTML != expectedAction, `not receive '${expectedAction}'`); 191 resolve(); 192 }); 193 }); 194 } 195 196 function waitUntilMainMediaControllerChanged() { 197 return BrowserUtils.promiseObserved("main-media-controller-changed"); 198 }