blob: 50d35dd230cb705c740a4995493a13af1b8e55db [file] [log] [blame]
<!DOCTYPE HTML>
<html>
<head>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<script>
// If a constraint is set with applyConstraints, it should come back in
// getConstraints().
promise_test(() => {
return navigator.mediaDevices.getUserMedia({video: {width: {exact: 800}}})
.then(s => {
var track = s.getVideoTracks()[0];
var constraints = track.getConstraints();
assert_equals(Object.keys(constraints).length, 1);
assert_true(constraints.hasOwnProperty('width'));
assert_equals(constraints.width.exact, 800);
return track.applyConstraints({width: {exact: 640}})
.then(() => {
constraints = track.getConstraints();
assert_equals(Object.keys(constraints).length, 1);
assert_true(constraints.hasOwnProperty('width'));
assert_equals(constraints.width.exact, 640);
})
});
}, 'applyConstraints() sets the value of a constraint set by getUserMedia()');
// The deviceId constraint must be rejected, since the source of a track cannot
// be changed with applyConstraints.
promise_test(test => {
return promise_rejects(test,
new OverconstrainedError('deviceId', ''),
navigator.mediaDevices.getUserMedia({audio: true})
.then(s => {
return s.getAudioTracks()[0].applyConstraints(
{ deviceId: {exact: 'mydevice-id'}});
}));
}, 'Attempting to change the deviceId with applyConstraints() fails');
promise_test(() => {
let track;
return navigator.mediaDevices.getUserMedia({video: true})
.then(s => {
track = s.getVideoTracks()[0];
return track.getSettings();
}).then(settings => {
return track.applyConstraints(
{ width: { exact: settings.width }, notKnownName: { exact: true }})
}).then(() => {
constraints = track.getConstraints();
assert_equals(Object.keys(constraints).length, 1);
assert_false(constraints.hasOwnProperty('notKnownName'));
});
}, 'An unsupported constraint is ignored by applyConstraints()');
function constraintElementsEqual(a, b) {
if (a === b)
return true;
if (!(a instanceof Object))
return false;
if (!(b instanceof Object))
return false;
if (Object.keys(a).length != Object.keys(b).length)
return false;
for (var p in a) {
if (!a.hasOwnProperty(p))
continue; // Skip prototypes and such things.
if (!b.hasOwnProperty(p))
return false;
if (a[p] instanceof Object && b[p] instanceof Object) {
if (!constraintElementsEqual(a[p], b[p]))
return false;
continue;
}
if (a[p] !== b[p]) return false; // Simple types.
}
return true;
}
promise_test(() => {
// Construct a constraint set that covers constraints that make sense for
// video.
const complexConstraintSet = {
width: { min: 30, max: 480 },
height: { min: 30, max: 480, exact: 350 },
};
// These constraints are syntactically valid, but may cause rejection.
// They are included in an "advanced" constraint.
// The particular values chosen are picked to exercise multiple parser paths,
// but the most important is that all legal names are represented.
const ignorableConstraintSet = {
frameRate: { ideal: 30.0 },
facingMode: { ideal: "user" },
aspectRatio: { ideal: 1.3333333, exact: 1.4444 },
volume: 1.0,
sampleRate: { ideal: 42, min: 31, max: 54 },
sampleSize: 3,
echoCancellation: { ideal: false, exact: true },
latency: 0.22,
channelCount: 2,
deviceId: { ideal: ["foo", "fooz"] },
groupId: ["bar", "baz"]
};
let complexConstraints = complexConstraintSet;
complexConstraints.advanced = [ ignorableConstraintSet ];
return navigator.mediaDevices.getUserMedia({video: true})
.then(s => {
var track = s.getVideoTracks()[0];
return track.applyConstraints(complexConstraints).then(() => {
constraints = track.getConstraints();
assert_true(constraintElementsEqual(constraints, complexConstraints),
"Unexpected result: In: " +
JSON.stringify(complexConstraints, null, 2) +
" Out: " + JSON.stringify(constraints, null, 2));
});
});
}, 'All valid keys are returned for complex constraints');
// Syntax tests for constraints.
// These work by putting the constraints into an advanced constraint
// (so that they can be ignored), calling getUserMedia, and then
// inspecting the constraints.
// In advanced constraints, naked values mean "exact", and "exact" values
// are thus unwrapped, which is the opposite behavior from the "basic"
// constraint set (outside advanced).
function constraintSyntaxTestWithChange(name, constraints, expected_result) {
promise_test(() => {
return navigator.mediaDevices.getUserMedia(
{'video': true})
.then(s => {
var track = s.getVideoTracks()[0];
track.applyConstraints({ 'advanced': [ constraints ]}).then(() => {
var constraints_out = track.getConstraints().advanced[0];
assert_true(constraintElementsEqual(expected_result, constraints_out),
"Unexpected result: Expected: " +
JSON.stringify(expected_result, null, 2) +
" Out: " + JSON.stringify(constraints_out, null, 2));
})
})
}, name);
}
function constraintSyntaxTest(name, constraints) {
constraintSyntaxTestWithChange(name, constraints, constraints);
}
constraintSyntaxTest('Simple integer', { height: 42 });
constraintSyntaxTest('Ideal integer', { height: { ideal: 42 }});
constraintSyntaxTest('Min/max integer', { height: { min: 42, max: 43 }});
constraintSyntaxTestWithChange('Exact unwrapped integer',
{ height: { exact: 42 } }, { height: 42 });
constraintSyntaxTest('Simple double', { aspectRatio: 1.5 });
constraintSyntaxTest('Ideal double', { aspectRatio: { ideal: 1.5 }});
constraintSyntaxTest('Min/max double', { aspectRatio: { min: 1.5, max: 2.0 }});
constraintSyntaxTestWithChange(
'Exact unwrapped double',
{ aspectRatio: { exact: 1.5 } }, { aspectRatio: 1.5 });
constraintSyntaxTest('Simple String', { facingMode: "user1" });
constraintSyntaxTest('Ideal String', { facingMode: { ideal: "user2" }});
constraintSyntaxTest('Multiple String in Brackets',
{ facingMode: { ideal: ["user3", "left3"]}});
constraintSyntaxTest('Multiple Bracketed Naked String',
{ facingMode: ["user4", "left4"] });
constraintSyntaxTestWithChange(
'Single Bracketed string unwrapped',
{ 'facingMode': ["user5"]}, { facingMode: "user5" });
constraintSyntaxTest('Both Ideal and Exact string',
{ facingMode: { ideal: "user6", exact: "left6" }});
constraintSyntaxTest('Simple boolean', { echoCancellation: true });
constraintSyntaxTest('Ideal boolean', { echoCancellation: { ideal: true }});
constraintSyntaxTestWithChange('Exact unwrapped boolean',
{ echoCancellation: { exact: true } }, { echoCancellation: true });
</script>
</body>
</html>