DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (b6d82b1a6b02)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
<!DOCTYPE HTML>
<html>
<head>
  <script src="mediaStreamPlayback.js"></script>
  <script src="constraints.js"></script>
</head>
<body>
<pre id="test">
<script type="application/javascript">
createHTML({ title: "Test getUserMedia constraints", bug: "882145" });
/**
  Tests covering gUM constraints API for audio, video and fake video. Exercise
  successful parsing code and ensure that unknown required constraints and
  overconstraining cases produce appropriate errors.
*/
var tests = [
  // Each test here tests a different constraint or codepath.
  { message: "unknown required constraint on video ignored",
    constraints: { video: { somethingUnknown: { exact: 0 } } },
    error: null },
  { message: "unknown required constraint on audio ignored",
    constraints: { audio: { somethingUnknown: { exact: 0 } } },
    error: null },
  { message: "audio overconstrained by facingMode ignored",
    constraints: { audio: { facingMode: { exact: 'left' } } },
    error: null },
  { message: "full screensharing requires permission",
    constraints: { video: { mediaSource: 'screen' } },
    error: "NotAllowedError" },
  { message: "application screensharing no longer exists",
    constraints: { video: { mediaSource: 'application' } },
    error: "OverconstrainedError" },
  { message: "window screensharing requires permission",
    constraints: { video: { mediaSource: 'window' } },
    error: "NotAllowedError" },
  { message: "browser screensharing requires permission",
    constraints: { video: { mediaSource: 'browser' } },
    error: "NotAllowedError" },
  { message: "unknown mediaSource in video fails",
    constraints: { video: { mediaSource: 'uncle' } },
    error: "OverconstrainedError",
    constraint: "mediaSource" },
  { message: "unknown mediaSource in audio fails",
    constraints: { audio: { mediaSource: 'uncle' } },
    error: "OverconstrainedError",
    constraint: "mediaSource" },
  { message: "emtpy constraint fails",
    constraints: { },
    error: "TypeError" },
  { message: "Triggering mock failure in default video device fails",
    constraints: { video: { deviceId: 'bad device' } },
    error: "NotReadableError" },
  { message: "Triggering mock failure in default audio device fails",
    constraints: { audio: { deviceId: 'bad device' } },
    error: "NotReadableError" },
  { message: "Success-path: optional video facingMode + audio ignoring facingMode",
    constraints: { audio: { mediaSource: 'microphone',
                            facingMode: 'left',
                            foo: 0,
                            advanced: [{ facingMode: 'environment' },
                                       { facingMode: 'user' },
                                       { bar: 0 }] },
                   video: { mediaSource: 'camera',
                            foo: 0,
                            advanced: [{ facingMode: 'environment' },
                                       { facingMode: ['user'] },
                                       { facingMode: ['left', 'right', 'user'] },
                                       { bar: 0 }] } },
    error: null },
  { message: "legacy facingMode ignored",
    constraints: { video: { mandatory: { facingMode: 'left' } } },
    error: null },
];

var mustSupport = [
  'width', 'height', 'frameRate', 'facingMode', 'deviceId', 'groupId',
  'echoCancellation', 'noiseSuppression', 'autoGainControl', 'channelCount',

  // Yet to add:
  //  'aspectRatio', 'volume', 'sampleRate', 'sampleSize', 'latency'

  // http://fluffy.github.io/w3c-screen-share/#screen-based-video-constraints
  // OBE by http://w3c.github.io/mediacapture-screen-share
  'mediaSource',

  // Experimental https://bugzilla.mozilla.org/show_bug.cgi?id=1131568#c3
  'browserWindow', 'scrollWithPage',
  'viewportOffsetX', 'viewportOffsetY', 'viewportWidth', 'viewportHeight',
];

var mustFailWith = (msg, reason, constraint, f) =>
  f().then(() => ok(false, msg + " must fail"), e => {
    is(e.name, reason, msg + " must fail: " + e.message);
    if (constraint !== undefined) {
      is(e.constraint, constraint, msg + " must fail w/correct constraint.");
    }
  });

/**
 * Starts the test run by running through each constraint
 * test by verifying that the right resolution and rejection is fired.
 */

runTest(() => pushPrefs(
    // This test expects fake devices, particularly for the 'triggering mock
    // failure *' steps. So explicitly disable loopback and setup fakes
    ['media.audio_loopback_dev', ''],
    ['media.video_loopback_dev', ''],
    ['media.navigator.streams.fake', true]
  )
  .then(() => {
    // Check supported constraints first.
    var dict = navigator.mediaDevices.getSupportedConstraints();
    var supported = Object.keys(dict);

    mustSupport.forEach(key => ok(supported.includes(key) && dict[key],
                                  "Supports " + key));

    var unexpected = supported.filter(key => !mustSupport.includes(key));
    is(unexpected.length, 0,
       "Unanticipated support (please update test): " + unexpected);
  })
  .then(() => pushPrefs(["media.getusermedia.browser.enabled", false],
                        ["media.getusermedia.screensharing.enabled", false]))
  .then(() => tests.reduce((p, test) => p.then(() => getUserMedia(test.constraints))
    .then(stream => {
      is(null, test.error, test.message);
      stream.getTracks().forEach(t => t.stop());
    }, e => {
      is(e.name, test.error, test.message + ": " + e.message);
      if (test.constraint) {
        is(e.constraint, test.constraint,
           test.message + " w/correct constraint.");
      }
    }), Promise.resolve()))
  .then(() => getUserMedia({video: true, audio: true}))
  .then(stream => stream.getVideoTracks()[0].applyConstraints({ width: 320 })
    .then(() => stream.getAudioTracks()[0].applyConstraints({ }))
    .then(() => {
      stream.getTracks().forEach(track => track.stop());
      ok(true, "applyConstraints code exercised");
    }))
  // TODO: Test outcome once fake devices support constraints (Bug 1088621)
  .then(() => mustFailWith("applyConstraints fails on non-Gum tracks",
                           "OverconstrainedError", "",
                           () => (new AudioContext())
                               .createMediaStreamDestination().stream
                               .getAudioTracks()[0].applyConstraints()))
  .then(() => mustFailWith(
      "getUserMedia with unsatisfied required constraint",
      "OverconstrainedError", "deviceId",
      () => getUserMedia({ audio: true,
                           video: { deviceId: { exact: "unheardof" } } })))
  .then(() => mustFailWith(
      "getUserMedia with unsatisfied required constraint array",
      "OverconstrainedError", "deviceId",
      () => getUserMedia({ audio: true,
                           video: { deviceId: { exact: ["a", "b"] } } }))));
</script>
</pre>
</body>
</html>