tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

browser_media_control_non_eligible_media.js (6759B)


      1 const PAGE_NON_ELIGIBLE_MEDIA =
      2  "https://example.com/browser/dom/media/mediacontrol/tests/browser/file_non_eligible_media.html";
      3 
      4 // Import this in order to use `triggerPictureInPicture()`.
      5 Services.scriptloader.loadSubScript(
      6  "chrome://mochitests/content/browser/toolkit/components/pictureinpicture/tests/head.js",
      7  this
      8 );
      9 
     10 // Bug 1673509 - This test requests a lot of fullscreen for media elements,
     11 // which sometime Gecko would take longer time to fulfill.
     12 requestLongerTimeout(2);
     13 
     14 // This array contains the elements' id in `file_non_eligible_media.html`.
     15 const gNonEligibleElementIds = [
     16  "muted",
     17  "volume-0",
     18  "silent-audio-track",
     19  "no-audio-track",
     20  "short-duration",
     21  "inaudible-captured-media",
     22 ];
     23 
     24 /**
     25 * This test is used to test couples of things about what kinds of media is
     26 * eligible for being controlled by media control keys.
     27 * (1) If media is inaudible all the time, then we would not control it.
     28 * (2) If media starts inaudibly, we would not try to control it. But once it
     29 * becomes audible later, we would keep controlling it until it's destroyed.
     30 * (3) If media's duration is too short (<3s), then we would not control it.
     31 */
     32 add_setup(async function setupTestingPref() {
     33  await SpecialPowers.pushPrefEnv({
     34    set: [
     35      ["media.mediacontrol.testingevents.enabled", true],
     36      ["test.wait300msAfterTabSwitch", true],
     37    ],
     38  });
     39 });
     40 
     41 add_task(
     42  async function testNonAudibleMediaCantActivateControllerButAudibleMediaCan() {
     43    for (const elementId of gNonEligibleElementIds) {
     44      info(`open new tab with non eligible media elements`);
     45      const tab = await createLoadedTabWrapper(PAGE_NON_ELIGIBLE_MEDIA, {
     46        needCheck: couldElementBecomeEligible(elementId),
     47      });
     48 
     49      info(`although media is playing but it won't activate controller`);
     50      await Promise.all([
     51        startNonEligibleMedia(tab, elementId),
     52        checkIfMediaIsStillPlaying(tab, elementId),
     53      ]);
     54      ok(!tab.controller.isActive, "controller is still inactive");
     55 
     56      if (couldElementBecomeEligible(elementId)) {
     57        info(`make element ${elementId} audible would activate controller`);
     58        await Promise.all([
     59          makeElementEligible(tab, elementId),
     60          checkOrWaitUntilControllerBecomeActive(tab),
     61        ]);
     62      }
     63 
     64      info(`remove tab`);
     65      await tab.close();
     66    }
     67  }
     68 );
     69 
     70 /**
     71 * Normally those media are not able to being controlled, however, once they
     72 * enter fullsceen or Picture-in-Picture mode, then they can be controlled.
     73 */
     74 add_task(async function testNonEligibleMediaEnterFullscreen() {
     75  info(`open new tab with non eligible media elements`);
     76  const tab = await createLoadedTabWrapper(PAGE_NON_ELIGIBLE_MEDIA);
     77 
     78  for (const elementId of gNonEligibleElementIds) {
     79    await startNonEligibleMedia(tab, elementId);
     80 
     81    info(`entering fullscreen should activate the media controller`);
     82    await enterFullScreen(tab, elementId);
     83    await checkOrWaitUntilControllerBecomeActive(tab);
     84    ok(true, `fullscreen ${elementId} media is able to being controlled`);
     85 
     86    info(`leave fullscreen`);
     87    await leaveFullScreen(tab);
     88  }
     89  info(`remove tab`);
     90  await tab.close();
     91 });
     92 
     93 add_task(async function testNonEligibleMediaEnterPIPMode() {
     94  info(`open new tab with non eligible media elements`);
     95  const tab = await createLoadedTabWrapper(PAGE_NON_ELIGIBLE_MEDIA);
     96 
     97  for (const elementId of gNonEligibleElementIds) {
     98    await startNonEligibleMedia(tab, elementId);
     99 
    100    info(`media entering PIP mode should activate the media controller`);
    101    const winPIP = await triggerPictureInPicture(tab.linkedBrowser, elementId);
    102    await checkOrWaitUntilControllerBecomeActive(tab);
    103    ok(true, `PIP ${elementId} media is able to being controlled`);
    104 
    105    info(`stop PIP mode`);
    106    await BrowserTestUtils.closeWindow(winPIP);
    107  }
    108  info(`remove tab`);
    109  await tab.close();
    110 });
    111 
    112 /**
    113 * The following are helper functions.
    114 */
    115 function startNonEligibleMedia(tab, elementId) {
    116  return SpecialPowers.spawn(tab.linkedBrowser, [elementId], Id => {
    117    const video = content.document.getElementById(Id);
    118    if (!video) {
    119      ok(false, `can't get the media element!`);
    120    }
    121    if (Id == "volume-0") {
    122      video.volume = 0.0;
    123    }
    124    if (Id == "inaudible-captured-media") {
    125      const context = new content.AudioContext();
    126      context.createMediaElementSource(video);
    127    }
    128    info(`start non eligible media ${Id}`);
    129    return video.play();
    130  });
    131 }
    132 
    133 function checkIfMediaIsStillPlaying(tab, elementId) {
    134  return SpecialPowers.spawn(tab.linkedBrowser, [elementId], Id => {
    135    const video = content.document.getElementById(Id);
    136    if (!video) {
    137      ok(false, `can't get the media element!`);
    138    }
    139    return new Promise(r => {
    140      // In order to test "media isn't affected by media control", we would not
    141      // only check `mPaused`, we would also oberve "timeupdate" event multiple
    142      // times to ensure that video is still playing continually.
    143      let timeUpdateCount = 0;
    144      ok(!video.paused);
    145      video.ontimeupdate = () => {
    146        if (++timeUpdateCount == 3) {
    147          video.ontimeupdate = null;
    148          r();
    149        }
    150      };
    151    });
    152  });
    153 }
    154 
    155 function couldElementBecomeEligible(elementId) {
    156  return elementId == "muted" || elementId == "volume-0";
    157 }
    158 
    159 function makeElementEligible(tab, elementId) {
    160  return SpecialPowers.spawn(tab.linkedBrowser, [elementId], Id => {
    161    const video = content.document.getElementById(Id);
    162    if (!video) {
    163      ok(false, `can't get the media element!`);
    164    }
    165    // to turn inaudible media become audible in order to be controlled.
    166    video.volume = 1.0;
    167    video.muted = false;
    168  });
    169 }
    170 
    171 function waitUntilMediaPaused(tab, elementId) {
    172  return SpecialPowers.spawn(tab.linkedBrowser, [elementId], Id => {
    173    const video = content.document.getElementById(Id);
    174    if (!video) {
    175      ok(false, `can't get the media element!`);
    176    }
    177    if (video.paused) {
    178      ok(true, "media has been paused");
    179      return Promise.resolve();
    180    }
    181    return new Promise(r => (video.onpaused = r));
    182  });
    183 }
    184 
    185 function enterFullScreen(tab, elementId) {
    186  return SpecialPowers.spawn(tab.linkedBrowser, [elementId], Id => {
    187    return new Promise(r => {
    188      const element = content.document.getElementById(Id);
    189      element.requestFullscreen();
    190      element.onfullscreenchange = () => {
    191        element.onfullscreenchange = null;
    192        element.onfullscreenerror = null;
    193        r();
    194      };
    195      element.onfullscreenerror = () => {
    196        // Retry until the element successfully enters fullscreen.
    197        element.requestFullscreen();
    198      };
    199    });
    200  });
    201 }
    202 
    203 function leaveFullScreen(tab) {
    204  return SpecialPowers.spawn(tab.linkedBrowser, [], _ => {
    205    return content.document.exitFullscreen();
    206  });
    207 }