test_getUserMedia_constraints.html (6992B)
1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <script src="mediaStreamPlayback.js"></script> 5 <script src="constraints.js"></script> 6 </head> 7 <body> 8 <pre id="test"> 9 <script type="application/javascript"> 10 createHTML({ title: "Test getUserMedia constraints", bug: "882145" }); 11 /** 12 Tests covering gUM constraints API for audio, video and fake video. Exercise 13 successful parsing code and ensure that unknown required constraints and 14 overconstraining cases produce appropriate errors. 15 */ 16 var tests = [ 17 // Each test here tests a different constraint or codepath. 18 { message: "unknown required constraint on video ignored", 19 constraints: { video: { somethingUnknown: { exact: 0 } } }, 20 error: null }, 21 { message: "unknown required constraint on audio ignored", 22 constraints: { audio: { somethingUnknown: { exact: 0 } } }, 23 error: null }, 24 { message: "audio overconstrained by facingMode ignored", 25 constraints: { audio: { facingMode: { exact: 'left' } } }, 26 error: null }, 27 { message: "full screensharing requires permission", 28 constraints: { video: { mediaSource: 'screen' } }, 29 error: "NotAllowedError" }, 30 { message: "application screensharing no longer exists", 31 constraints: { video: { mediaSource: 'application' } }, 32 error: "OverconstrainedError" }, 33 { message: "window screensharing requires permission", 34 constraints: { video: { mediaSource: 'window' } }, 35 error: "NotAllowedError" }, 36 { message: "browser screensharing requires permission", 37 constraints: { video: { mediaSource: 'browser' } }, 38 error: "NotAllowedError" }, 39 { message: "unknown mediaSource in video fails", 40 constraints: { video: { mediaSource: 'uncle' } }, 41 error: "OverconstrainedError", 42 constraint: "mediaSource" }, 43 { message: "unknown mediaSource in audio fails", 44 constraints: { audio: { mediaSource: 'uncle' } }, 45 error: "OverconstrainedError", 46 constraint: "mediaSource" }, 47 { message: "emtpy constraint fails", 48 constraints: { }, 49 error: "TypeError" }, 50 { message: "Triggering mock failure in default video device fails", 51 constraints: { video: { deviceId: 'bad device' } }, 52 error: "NotReadableError" }, 53 { message: "Triggering mock failure in default audio device fails", 54 constraints: { audio: { deviceId: 'bad device' } }, 55 error: "NotReadableError" }, 56 { message: "Success-path: optional video facingMode + audio ignoring facingMode", 57 constraints: { audio: { mediaSource: 'microphone', 58 facingMode: 'left', 59 foo: 0, 60 advanced: [{ facingMode: 'environment' }, 61 { facingMode: 'user' }, 62 { bar: 0 }] }, 63 video: { mediaSource: 'camera', 64 foo: 0, 65 advanced: [{ facingMode: 'environment' }, 66 { facingMode: ['user'] }, 67 { facingMode: ['left', 'right', 'user'] }, 68 { bar: 0 }] } }, 69 error: null }, 70 { message: "legacy facingMode ignored", 71 constraints: { video: { mandatory: { facingMode: 'left' } } }, 72 error: null }, 73 ]; 74 75 var mustSupport = [ 76 'width', 'height', 'frameRate', 'facingMode', 'deviceId', 'groupId', 77 'echoCancellation', 'noiseSuppression', 'autoGainControl', 'channelCount', 78 'resizeMode', 79 80 // Yet to add: 81 // 'aspectRatio', 'volume', 'sampleRate', 'sampleSize', 'latency' 82 83 // http://fluffy.github.io/w3c-screen-share/#screen-based-video-constraints 84 // OBE by http://w3c.github.io/mediacapture-screen-share 85 'mediaSource', 86 87 // Experimental https://bugzilla.mozilla.org/show_bug.cgi?id=1131568#c3 88 'browserWindow', 'scrollWithPage', 89 'viewportOffsetX', 'viewportOffsetY', 'viewportWidth', 'viewportHeight', 90 ]; 91 92 var mustFailWith = (msg, reason, constraint, f) => 93 f().then(() => ok(false, msg + " must fail"), e => { 94 is(e.name, reason, msg + " must fail: " + e.message); 95 if (constraint !== undefined) { 96 is(e.constraint, constraint, msg + " must fail w/correct constraint."); 97 } 98 }); 99 100 /** 101 * Starts the test run by running through each constraint 102 * test by verifying that the right resolution and rejection is fired. 103 */ 104 105 runTest(() => pushPrefs( 106 // This test expects fake devices, particularly for the 'triggering mock 107 // failure *' steps. So explicitly disable loopback and setup fakes 108 ['media.audio_loopback_dev', ''], 109 ['media.video_loopback_dev', ''], 110 ['media.navigator.streams.fake', true] 111 ) 112 .then(() => { 113 // Check supported constraints first. 114 var dict = navigator.mediaDevices.getSupportedConstraints(); 115 var supported = Object.keys(dict); 116 117 mustSupport.forEach(key => ok(supported.includes(key) && dict[key], 118 "Supports " + key)); 119 120 var unexpected = supported.filter(key => !mustSupport.includes(key)); 121 is(unexpected.length, 0, 122 "Unanticipated support (please update test): " + unexpected); 123 }) 124 .then(() => pushPrefs(["media.getusermedia.browser.enabled", false], 125 ["media.getusermedia.screensharing.enabled", false])) 126 .then(() => tests.reduce((p, test) => p.then( 127 () => { 128 SpecialPowers.wrap(document).notifyUserGestureActivation(); 129 return getUserMedia(test.constraints); 130 }) 131 .then(stream => { 132 is(null, test.error, test.message); 133 stream.getTracks().forEach(t => t.stop()); 134 }, e => { 135 is(e.name, test.error, test.message + ": " + e.message); 136 if (test.constraint) { 137 is(e.constraint, test.constraint, 138 test.message + " w/correct constraint."); 139 } 140 }), Promise.resolve())) 141 .then(() => getUserMedia({video: true, audio: true})) 142 .then(stream => stream.getVideoTracks()[0].applyConstraints({ width: 320 }) 143 .then(() => stream.getAudioTracks()[0].applyConstraints({ })) 144 .then(() => { 145 stream.getTracks().forEach(track => track.stop()); 146 ok(true, "applyConstraints code exercised"); 147 })) 148 // TODO: Test outcome once fake devices support constraints (Bug 1088621) 149 .then(() => mustFailWith("applyConstraints fails on non-Gum tracks", 150 "OverconstrainedError", "", 151 () => (new AudioContext()) 152 .createMediaStreamDestination().stream 153 .getAudioTracks()[0].applyConstraints())) 154 .then(() => mustFailWith( 155 "getUserMedia with unsatisfied required constraint", 156 "OverconstrainedError", "deviceId", 157 () => getUserMedia({ audio: true, 158 video: { deviceId: { exact: "unheardof" } } }))) 159 .then(() => mustFailWith( 160 "getUserMedia with unsatisfied required constraint array", 161 "OverconstrainedError", "deviceId", 162 () => getUserMedia({ audio: true, 163 video: { deviceId: { exact: ["a", "b"] } } })))); 164 </script> 165 </pre> 166 </body> 167 </html>