mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-28 12:45:27 +00:00
0ccb51ddc8
--HG-- extra : rebase_source : bac0027f4bf5d75b8730c44a10141c114002633b
122 lines
3.8 KiB
JavaScript
122 lines
3.8 KiB
JavaScript
(function(global) {
|
|
'use strict';
|
|
|
|
// an invertible check on the condition.
|
|
// if the constraint is applied, then the check is direct
|
|
// if not applied, then the result should be reversed
|
|
function check(constraintApplied, condition, message) {
|
|
var good = constraintApplied ? condition : !condition;
|
|
message = (constraintApplied ? 'with' : 'without') +
|
|
' constraint: should ' + (constraintApplied ? '' : 'not ') +
|
|
message + ' = ' + (good ? 'OK' : 'waiting...');
|
|
info(message);
|
|
return good;
|
|
}
|
|
|
|
function mkElement(type) {
|
|
// This makes an unattached element.
|
|
// It's not rendered to save the cycles that costs on b2g emulator
|
|
// and it gets dropped (and GC'd) when the test is done.
|
|
var e = document.createElement(type);
|
|
e.width = 32;
|
|
e.height = 24;
|
|
document.getElementById('display').appendChild(e);
|
|
return e;
|
|
}
|
|
|
|
// Runs checkFunc until it reports success.
|
|
// This is kludgy, but you have to wait for media to start flowing, and it
|
|
// can't be any old media, it has to include real data, for which we have no
|
|
// reliable signals to use as a trigger.
|
|
function periodicCheck(checkFunc) {
|
|
var resolve;
|
|
var done = false;
|
|
// This returns a function so that we create 10 closures in the loop, not
|
|
// one; and so that the timers don't all start straight away
|
|
var waitAndCheck = counter => () => {
|
|
if (done) {
|
|
return Promise.resolve();
|
|
}
|
|
return new Promise(r => setTimeout(r, 200 << counter))
|
|
.then(() => {
|
|
if (checkFunc()) {
|
|
done = true;
|
|
resolve();
|
|
}
|
|
});
|
|
};
|
|
|
|
var chain = Promise.resolve();
|
|
for (var i = 0; i < 10; ++i) {
|
|
chain = chain.then(waitAndCheck(i));
|
|
}
|
|
return new Promise(r => resolve = r);
|
|
}
|
|
|
|
function isSilence(audioData) {
|
|
var silence = true;
|
|
for (var i = 0; i < audioData.length; ++i) {
|
|
if (audioData[i] !== 128) {
|
|
silence = false;
|
|
}
|
|
}
|
|
return silence;
|
|
}
|
|
|
|
function checkAudio(constraintApplied, stream) {
|
|
var audio = mkElement('audio');
|
|
audio.srcObject = stream;
|
|
audio.play();
|
|
|
|
var context = new AudioContext();
|
|
var source = context.createMediaStreamSource(stream);
|
|
var analyser = context.createAnalyser();
|
|
source.connect(analyser);
|
|
analyser.connect(context.destination);
|
|
|
|
return periodicCheck(() => {
|
|
var sampleCount = analyser.frequencyBinCount;
|
|
info('got some audio samples: ' + sampleCount);
|
|
var buffer = new Uint8Array(sampleCount);
|
|
analyser.getByteTimeDomainData(buffer);
|
|
|
|
var silent = check(constraintApplied, isSilence(buffer),
|
|
'be silence for audio');
|
|
return sampleCount > 0 && silent;
|
|
}).then(() => {
|
|
source.disconnect();
|
|
analyser.disconnect();
|
|
audio.pause();
|
|
ok(true, 'audio is ' + (constraintApplied ? '' : 'not ') + 'silent');
|
|
});
|
|
}
|
|
|
|
function checkVideo(constraintApplied, stream) {
|
|
var video = mkElement('video');
|
|
video.srcObject = stream;
|
|
video.play();
|
|
|
|
return periodicCheck(() => {
|
|
try {
|
|
var canvas = mkElement('canvas');
|
|
var ctx = canvas.getContext('2d');
|
|
// Have to guard drawImage with the try as well, due to bug 879717. If
|
|
// we get an error, this round fails, but that failure is usually just
|
|
// transitory.
|
|
ctx.drawImage(video, 0, 0);
|
|
ctx.getImageData(0, 0, 1, 1);
|
|
return check(constraintApplied, false, 'throw on getImageData for video');
|
|
} catch (e) {
|
|
return check(constraintApplied, e.name === 'SecurityError',
|
|
'get a security error: ' + e.name);
|
|
}
|
|
}).then(() => {
|
|
video.pause();
|
|
ok(true, 'video is ' + (constraintApplied ? '' : 'not ') + 'protected');
|
|
});
|
|
}
|
|
|
|
global.audioIsSilence = checkAudio;
|
|
global.videoIsBlack = checkVideo;
|
|
}(this));
|