| 12
 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
 163
 164
 165
 166
 
 | <!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(
    () => {
      SpecialPowers.wrap(document).notifyUserGestureActivation();
      return 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>
 |