tor-browser

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

MediaStreamTrack-independent-clones.https.html (8393B)


      1 <!doctype html>
      2 <title>MediaStreamTrack clones have independent settings. Assumes Mozilla's fake camera source with 480p and 720p capabilities.</title>
      3 <meta name="timeout" content="long">
      4 <p class="instructions">When prompted, accept to share your video stream.</p>
      5 <script src=/resources/testharness.js></script>
      6 <script src=/resources/testharnessreport.js></script>
      7 <script src=/resources/testdriver.js></script>
      8 <script src=/resources/testdriver-vendor.js></script>
      9 <script src=../mediacapture-streams/settings-helper.js></script>
     10 <script src=../mediacapture-streams/video-test-helper.js></script>
     11 <script>
     12  "use strict"
     13 
     14  setup(() => assert_implements("getDisplayMedia" in navigator.mediaDevices, "getDisplayMedia() not supported"));
     15 
     16  // Note these gDM tests will fail if our own window is on a screen different
     17  // than the system's first screen. They're functions in case the browser
     18  // window needs to be moved to the first screen during the test in order to
     19  // pass.
     20  function screenPixelRatio() { return SpecialPowers.wrap(window).desktopToDeviceScale; }
     21  function screenWidth() { return window.screen.width * window.devicePixelRatio; }
     22  function screenHeight() { return window.screen.height * window.devicePixelRatio; }
     23  function desktopWidth() {
     24    // TODO: Bug 1965499 - scale down by screenPixelRatio by default in resizeMode: crop-and-scale.
     25    // return screenWidth() / screenPixelRatio();
     26    return screenWidth();
     27  }
     28  function desktopHeight() {
     29    // TODO: Bug 1965499 - scale down by screenPixelRatio by default in resizeMode: crop-and-scale.
     30    // return screenHeight() / screenPixelRatio();
     31    return screenHeight();
     32  }
     33 
     34  // TODO: By default we shouldn't be multiplying with window.devicePixelRatio (bug 1703991).
     35  function defaultScreen() {
     36    return {
     37      resizeMode: "crop-and-scale",
     38      width: screenWidth(),
     39      height: screenHeight(),
     40      frameRate: 30,
     41    };
     42  }
     43  // TODO: Should get the source's real refresh rate for frameRate (bug 1984363).
     44  function nativeScreen() {
     45    return {
     46      resizeMode: "none",
     47      width: screenWidth(),
     48      height: screenHeight(),
     49      frameRate: 60
     50    };
     51  }
     52 
     53  [
     54    [
     55      [{resizeMode: "none", width: 100}, {resizeMode: "none", height: 500}],
     56      [nativeScreen, nativeScreen],
     57    ],
     58    [
     59      [{resizeMode: "none", frameRate: 50}, {resizeMode: "none", frameRate: 1}],
     60      [nativeScreen, nativeScreen],
     61    ],
     62    [
     63      [{resizeMode: "none"}, {resizeMode: "crop-and-scale"}],
     64      [nativeScreen, defaultScreen],
     65    ],
     66    [
     67      [{resizeMode: "crop-and-scale"}, {resizeMode: "crop-and-scale", height: 100}],
     68      [
     69        defaultScreen,
     70        () => ({
     71          resizeMode: "crop-and-scale",
     72          width: Math.round(screenWidth() / screenHeight() * 100),
     73          height: 100,
     74          frameRate: 30
     75        }),
     76      ],
     77    ],
     78    [
     79      [{resizeMode: "crop-and-scale", height: 100}, {resizeMode: "crop-and-scale"}],
     80      [
     81        () => ({
     82          resizeMode: "crop-and-scale",
     83          width: Math.round(screenWidth() / screenHeight() * 100),
     84          height: 100,
     85          frameRate: 30
     86        }),
     87        defaultScreen,
     88      ],
     89    ],
     90    [
     91      [{resizeMode: "crop-and-scale", frameRate: 5}, {resizeMode: "crop-and-scale", frameRate: 50}],
     92      [
     93        () => {
     94          const { width, height } = defaultScreen();
     95          return { width, height, frameRate: 5};
     96        },
     97        () => {
     98          const { width, height } = defaultScreen();
     99          return { width, height, frameRate: 50};
    100        },
    101      ],
    102      [[2, 7], [2, 50]],
    103    ],
    104    [
    105      [{resizeMode: "crop-and-scale", frameRate: 50}, {resizeMode: "crop-and-scale", frameRate: 5}],
    106      [
    107        () => {
    108          const { width, height } = defaultScreen();
    109          return { width, height, frameRate: 50};
    110        },
    111        () => {
    112          const { width, height } = defaultScreen();
    113          return { width, height, frameRate: 5};
    114        },
    115        [[2, 50], [2, 7]]
    116      ],
    117    ],
    118    [
    119      [{resizeMode: "none"}, {resizeMode: "crop-and-scale", frameRate: 5000}, {}],
    120      [
    121        nativeScreen,
    122        () => {
    123          const { width, height } = defaultScreen();
    124          return { width, height, frameRate: 120};
    125        },
    126      ]
    127    ],
    128  ].forEach(
    129    ([
    130      [video, cloneVideo],
    131      [expectedFunc, cloneExpectedFunc],
    132      [testFramerate, cloneTestFramerate] = [null, null]
    133    ]) => {
    134      let expected, cloneExpected;
    135      promise_test(async t => {
    136          expected = expectedFunc();
    137          cloneExpected = cloneExpectedFunc();
    138          await test_driver.bless('getDisplayMedia()');
    139          const stream = await navigator.mediaDevices.getDisplayMedia({video});
    140          const [track] = stream.getTracks();
    141          const clone = track.clone();
    142          t.add_cleanup(() => {
    143            track.stop();
    144            clone.stop();
    145          });
    146          let settings = track.getSettings();
    147          let cloneSettings = clone.getSettings();
    148          for (const key of Object.keys(expected)) {
    149            assert_equals(settings[key], expected[key], `original: ${key}`);
    150            assert_equals(cloneSettings[key], expected[key], `clone: ${key}`);
    151          }
    152          await clone.applyConstraints(cloneVideo);
    153          settings = track.getSettings();
    154          cloneSettings = clone.getSettings();
    155          for (const key of Object.keys(expected)) {
    156            assert_equals(settings[key], expected[key], `original-post: ${key}`);
    157          }
    158          for (const key of Object.keys(cloneExpected)) {
    159            assert_equals(cloneSettings[key], cloneExpected[key], `clone-post: ${key}`);
    160          }
    161          await test_resolution_equals(t, track, settings.width, settings.height);
    162          await test_resolution_equals(t, clone, cloneSettings.width, cloneSettings.height);
    163          if (testFramerate) {
    164            const [low, high] = testFramerate;
    165            await test_framerate_between_exclusive(t, track, low, high);
    166          }
    167          if (cloneTestFramerate) {
    168            const [low, high] = cloneTestFramerate;
    169            await test_framerate_between_exclusive(t, clone, low, high);
    170          }
    171        }, `gDM gets expected modes by ${JSON.stringify(video)} + (cloned) ${JSON.stringify(cloneVideo)}`);
    172    });
    173 
    174  promise_test(async t => {
    175    await test_driver.bless('getDisplayMedia()');
    176    const stream = await navigator.mediaDevices.getDisplayMedia({video: {resizeMode: "none"}});
    177    const [track] = stream.getTracks();
    178    const clone = track.clone();
    179    t.add_cleanup(() => {
    180      track.stop();
    181      clone.stop();
    182    });
    183    await clone.applyConstraints(
    184      {
    185        resizeMode: "crop-and-scale",
    186        width: 400,
    187        height: 400
    188      }
    189    );
    190    const expected = findFittestResolutionSetting(
    191      screenWidth(),
    192      screenHeight(),
    193      clone.getConstraints()
    194    );
    195    assert_equals(clone.getSettings().width, expected.width, "width");
    196    assert_equals(clone.getSettings().height, expected.height, "height");
    197    await test_resolution_equals(t, clone, clone.getSettings().width, clone.getSettings().height);
    198    assert_approx_equals(
    199      clone.getSettings().width / clone.getSettings().height,
    200      desktopWidth() / desktopHeight(),
    201      0.01,
    202      "aspect ratio"
    203    );
    204    assert_equals(clone.getSettings().resizeMode, "crop-and-scale", "resizeMode");
    205  }, "applyConstraints on gDM clone doesn't crop with only ideal dimensions");
    206 
    207  promise_test(async t => {
    208    await test_driver.bless('getDisplayMedia()');
    209    const stream = await navigator.mediaDevices.getDisplayMedia({video: {resizeMode: "none"}});
    210    const [track] = stream.getTracks();
    211    const clone = track.clone();
    212    t.add_cleanup(() => {
    213      track.stop();
    214      clone.stop();
    215    });
    216    await clone.applyConstraints(
    217      {
    218        resizeMode: "crop-and-scale",
    219        width: {max: 400},
    220        height: {ideal: 400}
    221      }
    222    );
    223    assert_equals(clone.getSettings().width, 400, "width");
    224    assert_equals(
    225      clone.getSettings().height,
    226      Math.round(screenHeight() / screenWidth() * 400),
    227      "height"
    228    );
    229    await test_resolution_equals(t, clone, clone.getSettings().width, clone.getSettings().height);
    230    assert_equals(clone.getSettings().resizeMode, "crop-and-scale", "resizeMode");
    231  }, "applyConstraints on gDM clone doesn't crop with ideal and max dimensions");
    232 </script>