Bug 1436523 - Update dom/media/test/ tests to better handle loopback + gUM device config. r=achronop

This changeset adds a gUM_support.js to dom/media/test/. This file provides
functions to setup prefs for loopback or fake device selection before gUM calls
are made. This is useful for configuring tests and providing an explicit point
of reference for settings, rather than the implicit ones provided by the
harness.

Updates tests so that the new helper functions are called before gUM. This
will result in loopback prefs being set if loopback device names are detected,
if not then fake devices will be used. This also removes the use of the fake
constraint in gUM calls.

Update touched tests to use some more modern JS. No behavioural changes were
made (except in minor cases, but functionality should be the same). These
changes are largely as follows:
- var -> let
- async is used in places where I felt it improved readability
- semicolons added to various event handler assignments

MozReview-Commit-ID: 1HuE8thBA6w

--HG--
extra : rebase_source : b866056b2821436cf34ea683421c200b4bb4e55f
This commit is contained in:
Bryce Van Dyk 2018-02-21 09:11:29 -05:00
parent aa68bc0511
commit 898975f341
10 changed files with 491 additions and 399 deletions

View File

@ -0,0 +1,87 @@
// Support script for test that use getUserMedia. This allows explicit
// configuration of prefs which affect gUM. See also
// `testing/mochitest/runtests.py` for how the harness configures values.
// Setup preconditions for tests using getUserMedia. This functions helps
// manage different prefs that affect gUM calls in tests and makes explicit
// the expected state before test runs.
async function pushGetUserMediaTestPrefs({
fakeAudio = false,
fakeVideo = false,
loopbackAudio = false,
loopbackVideo = false}) {
// Make sure we have sensical arguments
if (!fakeAudio && !loopbackAudio) {
throw new Error("pushGetUserMediaTestPrefs: Should have fake or loopback audio!");
} else if (fakeAudio && loopbackAudio) {
throw new Error("pushGetUserMediaTestPrefs: Should not have both fake and loopback audio!");
}
if (!fakeVideo && !loopbackVideo) {
throw new Error("pushGetUserMediaTestPrefs: Should have fake or loopback video!");
} else if (fakeVideo && loopbackVideo) {
throw new Error("pushGetUserMediaTestPrefs: Should not have both fake and loopback video!");
}
let testPrefs = [];
if (fakeAudio) {
// Unset the loopback device so it doesn't take precedence
testPrefs.push(["media.audio_loopback_dev", ""]);
// Setup fake streams pref
testPrefs.push(["media.navigator.streams.fake", true]);
}
if (loopbackAudio) {
// If audio loopback is requested we expect the test harness to have set
// the loopback device pref, make sure it's set
let audioLoopDev = SpecialPowers.getCharPref("media.audio_loopback_dev", "");
if (!audioLoopDev) {
throw new Error("pushGetUserMediaTestPrefs: Loopback audio requested but " +
"media.audio_loopback_dev does not appear to be set!");
}
}
if (fakeVideo) {
// Unset the loopback device so it doesn't take precedence
testPrefs.push(["media.video_loopback_dev", ""]);
// Setup fake streams pref
testPrefs.push(["media.navigator.streams.fake", true]);
}
if (loopbackVideo) {
// If video loopback is requested we expect the test harness to have set
// the loopback device pref, make sure it's set
let videoLoopDev = SpecialPowers.getCharPref("media.video_loopback_dev", "");
if (!videoLoopDev) {
throw new Error("pushGetUserMediaTestPrefs: Loopback video requested but " +
"media.video_loopback_dev does not appear to be set!");
}
}
if (loopbackAudio || loopbackVideo) {
// Prevent gUM permission prompt. Since loopback devices are considered
// real devices we need to set prefs so the gUM prompt isn't presented.
testPrefs.push(['media.navigator.permission.disabled', true]);
}
return SpecialPowers.pushPrefEnv({set: testPrefs});
}
// Setup preconditions for tests using getUserMedia. This function will
// configure prefs to select loopback device(s) if it can find loopback device
// names already set in the prefs. If no loopback device name can be found then
// prefs are setup such that a fake device is used.
async function setupGetUserMediaTestPrefs() {
prefRequests = {};
let audioLoopDev = SpecialPowers.getCharPref("media.audio_loopback_dev", "");
if (audioLoopDev) {
prefRequests.fakeAudio = false;
prefRequests.loopbackAudio = true;
} else {
prefRequests.fakeAudio = true;
prefRequests.loopbackAudio = false;
}
let videoLoopDev = SpecialPowers.getCharPref("media.video_loopback_dev", "");
if (videoLoopDev) {
prefRequests.fakeVideo = false;
prefRequests.loopbackVideo = true;
} else {
prefRequests.fakeVideo = true;
prefRequests.loopbackVideo = false;
}
return pushGetUserMediaTestPrefs(prefRequests);
}

View File

@ -457,6 +457,7 @@ support-files =
gizmo.webm^headers^
gizmo-noaudio.webm
gizmo-noaudio.webm^headers^
gUM_support.js
gzipped_mp4.sjs
huge-id3.mp3
huge-id3.mp3^headers^

View File

@ -8,20 +8,21 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1041393
<title>ImageCapture tests</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="gUM_support.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1041393">ImageCapture tests</a>
<script type="application/javascript">
var repeat = 100;
var count;
let repeat = 100;
let count;
// Check if the callback returns even no JS reference on it.
function gcTest(track) {
return new Promise(function(resolve, reject) {
count = 0;
var i;
var imageCapture;
let i;
let imageCapture;
for(i = 0; i < repeat; i++) {
imageCapture = new ImageCapture(track);
imageCapture.onphoto = function(blob) {
@ -46,7 +47,7 @@ function gcTest(track) {
// Continue calling takePhoto() in rapid succession.
function rapidTest(track) {
return new Promise(function(resolve, reject) {
var imageCapture = new ImageCapture(track);
let imageCapture = new ImageCapture(track);
imageCapture.onphoto = function(blob) {
count++;
if (count == repeat) {
@ -60,7 +61,7 @@ function rapidTest(track) {
};
count = 0;
var i;
let i;
for(i = 0; i < repeat; i++) {
imageCapture.takePhoto();
}
@ -70,17 +71,17 @@ function rapidTest(track) {
// Check if the blob is decodable.
function blobTest(track) {
return new Promise(function(resolve, reject) {
var imageCapture = new ImageCapture(track);
let imageCapture = new ImageCapture(track);
imageCapture.onphoto = function(blob) {
var img = new Image();
let img = new Image();
img.onerror = function() {
ok(false, "fail to decode blob");
reject();
}
};
img.onload = function() {
ok(true, "decode blob success");
resolve(track);
}
};
img.src = URL.createObjectURL(blob.data);
};
imageCapture.onerror = function(error) {
@ -94,7 +95,7 @@ function blobTest(track) {
// It should return an error event after disabling video track.
function trackTest(track) {
return new Promise(function(resolve, reject) {
var imageCapture = new ImageCapture(track);
let imageCapture = new ImageCapture(track);
imageCapture.onphoto = function(blob) {
ok(false, "expect error when video track is disable");
reject();
@ -106,42 +107,33 @@ function trackTest(track) {
};
track.enabled = false;
imageCapture.takePhoto()
imageCapture.takePhoto();
});
}
function init() {
return new Promise(function(resolve, reject) {
// use fake camera, MediaStreamGraph will be the backend of ImageCapture.
var constraints = {video: true, fake: true}
window.navigator.mozGetUserMedia(
constraints,
function(stream) {
var track = stream.getVideoTracks()[0];
resolve(track);
},
function(err) {
reject(err);
}
);
});
async function init() {
// use loopback camera if available, otherwise fake, MediaStreamGraph will be the backend of ImageCapture.
await setupGetUserMediaTestPrefs();
let stream = await navigator.mediaDevices.getUserMedia({video: true});
return stream.getVideoTracks()[0];
}
function start() {
init().then(function(track) {
async function start() {
try {
let track = await init();
info("ImageCapture track disable test.");
return trackTest(track);
}).then(function(track) {
track = await trackTest(track);
info("ImageCapture blob test.");
return blobTest(track);
}).then(function(track) {
track = await blobTest(track);
info("ImageCapture rapid takePhoto() test.");
return rapidTest(track);
}).then(function(track) {
track = await rapidTest(track);
info("ImageCapture multiple instances test.");
return gcTest(track);
}).then(SimpleTest.finish);
await gcTest(track);
} catch (e) {
ok(false, "Unexpected error during test: " + e);
} finally {
SimpleTest.finish();
}
}
SimpleTest.requestCompleteLog();

View File

@ -4,18 +4,19 @@
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="text/javascript" src="manifest.js"></script>
<script type="text/javascript" src="gUM_support.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=897776">Mozill
a Bug 897776</a>
<pre id="test">
<script class="testbody" type="text/javascript">
function startTest() {
navigator.mozGetUserMedia({audio: true, fake: true}, function(stream) {
var mediaRecorder = new MediaRecorder(stream);
var count = 0;
mediaRecorder.start();
info("mediaRecorder start");
async function startTest() {
try {
await setupGetUserMediaTestPrefs();
let stream = await navigator.mediaDevices.getUserMedia({audio: true});
let mediaRecorder = new MediaRecorder(stream);
let count = 0;
mediaRecorder.onerror = function () {
ok(false, 'Unexpected onerror callback fired');
SimpleTest.finish();
@ -35,17 +36,19 @@ function startTest() {
info("requestData again");
mediaRecorder.requestData();
}
}
mediaRecorder.requestData();
info("mediaRecorder requestData");
};
mediaRecorder.onstop = function () {
ok(true, "requestData within ondataavailable successfully avoided infinite recursion");
SimpleTest.finish();
}
}, function(err) {
ok(false, 'Unexpected error fired with: ' + err);
};
mediaRecorder.start();
info("mediaRecorder start");
mediaRecorder.requestData();
info("mediaRecorder requestData");
} catch (e) {
ok(false, 'Unexpected error fired with: ' + e);
SimpleTest.finish();
});
}
}
SimpleTest.waitForExplicitFinish();

View File

@ -4,6 +4,7 @@
<title>Test MediaRecorder Record gUM video with Timeslice</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="text/javascript" src="gUM_support.js"></script>
</head>
<body>
<pre id="test">
@ -11,10 +12,12 @@
</div>
<script class="testbody" type="text/javascript">
function startTest() {
navigator.mozGetUserMedia({audio: true, video: true, fake: true}, function(stream) {
var dataAvailableCount = 0;
var onDataAvailableFirst = false;
async function startTest() {
try {
await setupGetUserMediaTestPrefs();
let stream = await navigator.mediaDevices.getUserMedia({audio: true, video: true});
let dataAvailableCount = 0;
let onDataAvailableFirst = false;
mediaRecorder = new MediaRecorder(stream);
is(mediaRecorder.stream, stream,
@ -73,10 +76,10 @@ function startTest() {
mediaRecorder.start(250);
is(mediaRecorder.state, 'recording', 'Media recorder should be recording');
}, function(err) {
} catch (err) {
ok(false, 'Unexpected error fired with: ' + err);
SimpleTest.finish();
});
}
}
SimpleTest.waitForExplicitFinish();

View File

@ -4,6 +4,7 @@
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="text/javascript" src="manifest.js"></script>
<script type="text/javascript" src="gUM_support.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=957439">Mozilla Bug 957439</a>
@ -11,7 +12,7 @@
<script class="testbody" type="text/javascript">
function startTest() {
async function startTest() {
// also do general checks on mimetype support for audio-only
ok(MediaRecorder.isTypeSupported("audio/ogg"), 'Should support audio/ogg');
ok(MediaRecorder.isTypeSupported('audio/ogg; codecs="opus"'), 'Should support audio/ogg+opus');
@ -19,73 +20,72 @@ function startTest() {
ok(!MediaRecorder.isTypeSupported("video/webm"), 'Should not support video/webm');
ok(!MediaRecorder.isTypeSupported("video/mp4"), 'Should not support video/mp4');
navigator.mozGetUserMedia({audio: false, video: true, fake: true},
function(stream) {
try {
await setupGetUserMediaTestPrefs();
let stream = await navigator.mediaDevices.getUserMedia({audio: false, video: true});
// Expected callback sequence should be:
// 1. onerror (from start)
// 2. ondataavailable
// 3. onstop
var callbackStep = 0;
var mediaRecorder = new MediaRecorder(stream);
// Expected callback sequence should be:
// 1. onerror (from start)
// 2. ondataavailable
// 3. onstop
let callbackStep = 0;
let mediaRecorder = new MediaRecorder(stream);
is(mediaRecorder.stream, stream, 'Stream should be provided on creation');
is(mediaRecorder.stream, stream, 'Stream should be provided on creation');
mediaRecorder.onerror = function (e) {
callbackStep++;
info('onerror callback fired');
if (callbackStep == 1) {
try {
mediaRecorder.pause();
ok(false, 'pause should fire an exception if called on an inactive recorder');
} catch(e) {
ok(e instanceof DOMException, 'pause should fire an exception ' +
'if called on an inactive recorder');
is(e.name, 'InvalidStateError', 'Exception name should be InvalidStateError');
}
mediaRecorder.onerror = function (e) {
callbackStep++;
info('onerror callback fired');
if (callbackStep == 1) {
try {
mediaRecorder.pause();
ok(false, 'pause should fire an exception if called on an inactive recorder');
} catch(e) {
ok(e instanceof DOMException, 'pause should fire an exception ' +
'if called on an inactive recorder');
is(e.name, 'InvalidStateError', 'Exception name should be InvalidStateError');
}
ok(callbackStep == 1, 'onerror callback should handle be the 1st event fired');
is(e.error.name, 'UnknownError', 'Error name should be UnknownError.');
ok(e.error.stack.includes('test_mediarecorder_unsupported_src.html'),
'Events fired from onerror should include an error with a stack trace indicating ' +
'an error in this test');
is(mediaRecorder.mimeType, '', 'mimetype should be empty');
is(mediaRecorder.state, 'inactive', 'state is inactive');
};
mediaRecorder.onwarning = function () {
ok(false, 'Unexpected onwarning callback fired.');
};
mediaRecorder.ondataavailable = function (evt) {
callbackStep++;
info('ondataavailable callback fired');
is(callbackStep, 2, 'ondataavailable callback should handle the 2nd event fired');
is(evt.data.size, 0, 'data size should be zero');
ok(evt instanceof BlobEvent,
'Events fired from ondataavailable should be BlobEvent');
is(evt.data.type, '', 'encoder start fail, blob miemType should be empty');
};
mediaRecorder.onstop = function() {
callbackStep++;
info('onstop callback fired');
is(mediaRecorder.state, 'inactive', 'state should be inactive');
is(callbackStep, 3, 'onstop callback should handle the 3rd event fired');
SimpleTest.finish();
};
try {
mediaRecorder.start();
} catch(e) {
ok(false, 'Should not get exception in start call.');
}
},
function(err) {
ok(false, 'Unexpected error fired with: ' + err);
ok(callbackStep == 1, 'onerror callback should handle be the 1st event fired');
is(e.error.name, 'UnknownError', 'Error name should be UnknownError.');
ok(e.error.stack.includes('test_mediarecorder_unsupported_src.html'),
'Events fired from onerror should include an error with a stack trace indicating ' +
'an error in this test');
is(mediaRecorder.mimeType, '', 'mimetype should be empty');
is(mediaRecorder.state, 'inactive', 'state is inactive');
};
mediaRecorder.onwarning = function () {
ok(false, 'Unexpected onwarning callback fired.');
};
mediaRecorder.ondataavailable = function (evt) {
callbackStep++;
info('ondataavailable callback fired');
is(callbackStep, 2, 'ondataavailable callback should handle the 2nd event fired');
is(evt.data.size, 0, 'data size should be zero');
ok(evt instanceof BlobEvent,
'Events fired from ondataavailable should be BlobEvent');
is(evt.data.type, '', 'encoder start fail, blob miemType should be empty');
};
mediaRecorder.onstop = function() {
callbackStep++;
info('onstop callback fired');
is(mediaRecorder.state, 'inactive', 'state should be inactive');
is(callbackStep, 3, 'onstop callback should handle the 3rd event fired');
SimpleTest.finish();
};
try {
mediaRecorder.start();
} catch(e) {
ok(false, 'Should not get exception in start call.');
}
);
} catch (err) {
ok(false, 'Unexpected error fired with: ' + err);
SimpleTest.finish();
}
}
SimpleTest.waitForExplicitFinish();

View File

@ -5,140 +5,141 @@
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="text/javascript" src="manifest.js"></script>
<script type="text/javascript" src="gUM_support.js"></script>
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
function startTest() {
navigator.mozGetUserMedia({audio:true, video:true, fake:true},
function(stream) {
var element = document.createElement("video");
async function startTest() {
let steps = 0;
let audioOnchange = 0;
let audioOnaddtrack = 0;
let audioOnremovetrack = 0;
let videoOnchange = 0;
let videoOnaddtrack = 0;
let videoOnremovetrack = 0;
let isPlaying = false;
let element = document.createElement("video");
let stream;
try {
await setupGetUserMediaTestPrefs();
stream = await navigator.mediaDevices.getUserMedia({audio: true, video: true});
} catch (err) {
ok(false, 'Unexpected error fired with: ' + err);
SimpleTest.finish();
return;
}
var audioOnchange = 0;
var audioOnaddtrack = 0;
var audioOnremovetrack = 0;
var videoOnchange = 0;
var videoOnaddtrack = 0;
var videoOnremovetrack = 0;
var isPlaying = false;
element.audioTracks.onaddtrack = function(e) {
audioOnaddtrack++;
};
element.audioTracks.onaddtrack = function(e) {
audioOnaddtrack++;
}
element.audioTracks.onremovetrack = function(e) {
audioOnremovetrack++;
};
element.audioTracks.onremovetrack = function(e) {
audioOnremovetrack++;
}
element.audioTracks.onchange = function(e) {
audioOnchange++;
};
element.audioTracks.onchange = function(e) {
audioOnchange++;
}
element.videoTracks.onaddtrack = function(e) {
videoOnaddtrack++;
};
element.videoTracks.onaddtrack = function(e) {
videoOnaddtrack++;
}
element.videoTracks.onremovetrack = function(e) {
videoOnremovetrack++;
};
element.videoTracks.onremovetrack = function(e) {
videoOnremovetrack++;
}
element.videoTracks.onchange = function(e) {
videoOnchange++;
};
element.videoTracks.onchange = function(e) {
videoOnchange++;
}
function checkTrackRemoved() {
if (isPlaying) {
is(element.audioTracks.length, 0, 'The length of audioTracks should be 0.');
is(element.videoTracks.length, 0, 'The length of videoTracks should be 0.');
}
}
function checkTrackRemoved() {
if (isPlaying) {
is(element.audioTracks.length, 0, 'The length of audioTracks should be 0.');
is(element.videoTracks.length, 0, 'The length of videoTracks should be 0.');
}
}
element.onended = function() {
ok(true, 'Event ended is expected to be fired on element.');
checkTrackRemoved();
element.onended = null;
element.onplaying = null;
element.onpause = null;
SimpleTest.finish();
}
function onended() {
ok(true, 'Event ended is expected to be fired on element.');
checkTrackRemoved();
element.onended = null;
element.onplaying = null;
element.onpause = null;
SimpleTest.finish();
}
function checkTrackAdded() {
isPlaying = true;
is(audioOnaddtrack, 1, 'Calls of onaddtrack on audioTracks should be 1.');
is(element.audioTracks.length, 1, 'The length of audioTracks should be 1.');
ok(element.audioTracks[0].enabled, 'Audio track should be enabled as default.');
is(videoOnaddtrack, 1, 'Calls of onaddtrack on videoTracks should be 1.');
is(element.videoTracks.length, 1, 'The length of videoTracks should be 1.');
is(element.videoTracks.selectedIndex, 0,
'The first video track is set selected as default.');
}
function checkTrackAdded() {
isPlaying = true;
is(audioOnaddtrack, 1, 'Calls of onaddtrack on audioTracks should be 1.');
is(element.audioTracks.length, 1, 'The length of audioTracks should be 1.');
ok(element.audioTracks[0].enabled, 'Audio track should be enabled as default.');
is(videoOnaddtrack, 1, 'Calls of onaddtrack on videoTracks should be 1.');
is(element.videoTracks.length, 1, 'The length of videoTracks should be 1.');
is(element.videoTracks.selectedIndex, 0,
'The first video track is set selected as default.');
}
function setTrackEnabled(enabled) {
element.audioTracks[0].enabled = enabled;
element.videoTracks[0].selected = enabled;
}
function setTrackEnabled(enabled) {
element.audioTracks[0].enabled = enabled;
element.videoTracks[0].selected = enabled;
}
function checkTrackChanged(calls, enabled) {
is(audioOnchange, calls, 'Calls of onchange on audioTracks should be '+calls);
is(element.audioTracks[0].enabled, enabled,
'Enabled value of the audio track should be ' +enabled);
is(videoOnchange, calls, 'Calls of onchange on videoTracks should be '+calls);
is(element.videoTracks[0].selected, enabled,
'Selected value of the video track should be ' +enabled);
var index = enabled ? 0 : -1;
is(element.videoTracks.selectedIndex, index,
'SelectedIndex of video tracks should be ' +index);
}
function checkTrackChanged(calls, enabled) {
is(audioOnchange, calls, 'Calls of onchange on audioTracks should be '+calls);
is(element.audioTracks[0].enabled, enabled,
'Enabled value of the audio track should be ' +enabled);
is(videoOnchange, calls, 'Calls of onchange on videoTracks should be '+calls);
is(element.videoTracks[0].selected, enabled,
'Selected value of the video track should be ' +enabled);
var index = enabled ? 0 : -1;
is(element.videoTracks.selectedIndex, index,
'SelectedIndex of video tracks should be ' +index);
}
function onpause() {
element.onpause = null;
if (element.ended) {
return;
}
if (steps == 1) {
setTrackEnabled(false);
element.onplaying = onplaying;
element.play();
steps++;
} else if (steps == 2) {
setTrackEnabled(true);
element.onplaying = onplaying;
element.play();
steps++;
}
}
function onplaying() {
element.onplaying = null;
if (element.ended) {
return;
}
if (steps == 1) {
element.onpause = onpause;
element.pause();
checkTrackAdded();
} else if (steps == 2) {
element.onpause = onpause;
element.pause();
checkTrackChanged(1, false);
} else if (steps == 3) {
checkTrackChanged(2, true);
stream.stop();
}
}
var steps = 0;
element.srcObject = stream;
function onpause() {
element.onpause = null;
if (element.ended) {
return;
}
if (steps == 1) {
setTrackEnabled(false);
element.onplaying = onplaying;
element.play();
steps++;
} else if (steps == 2) {
setTrackEnabled(true);
element.onplaying = onplaying;
element.onended = onended;
element.play();
steps++;
},
function(err) {
ok(false, 'Unexpected error fired with: ' + err);
SimpleTest.finish();
}
);
}
function onplaying() {
element.onplaying = null;
if (element.ended) {
return;
}
if (steps == 1) {
element.onpause = onpause;
element.pause();
checkTrackAdded();
} else if (steps == 2) {
element.onpause = onpause;
element.pause();
checkTrackChanged(1, false);
} else if (steps == 3) {
checkTrackChanged(2, true);
stream.stop();
}
}
element.onplaying = onplaying;
element.srcObject = stream;
steps++;
await element.play();
}
SimpleTest.waitForExplicitFinish();

View File

@ -5,118 +5,120 @@
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="text/javascript" src="manifest.js"></script>
<script type="text/javascript" src="gUM_support.js"></script>
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
function startTest() {
navigator.mozGetUserMedia({audio:true, video:true, fake:true},
function(stream) {
var element = document.createElement("video");
async function startTest() {
let steps = 0;
let element = document.createElement("video");
let stream;
try {
await setupGetUserMediaTestPrefs();
stream = await navigator.mediaDevices.getUserMedia({audio: true, video: true});
} catch (err) {
ok(false, 'Unexpected error fired with: ' + err);
SimpleTest.finish();
return;
}
isnot(element.audioTracks, undefined,
'HTMLMediaElement::AudioTracks() property should be available.');
isnot(element.videoTracks, undefined,
'HTMLMediaElement::VideoTracks() property should be available.');
function verifyEvent(e, type) {
is(e.type, type, "Event type should be " + type);
ok(e.isTrusted, "Event should be trusted.");
ok(!e.bubbles, "Event shouldn't bubble.");
ok(!e.cancelable, "Event shouldn't be cancelable.");
}
function verifyEvent(e, type) {
is(e.type, type, "Event type should be " + type);
ok(e.isTrusted, "Event should be trusted.");
ok(!e.bubbles, "Event shouldn't bubble.");
ok(!e.cancelable, "Event shouldn't be cancelable.");
}
element.audioTracks.onaddtrack = function(e) {
ok(e instanceof TrackEvent, "Event fired from onaddtrack should be a TrackEvent");
ok(true, 'onaddtrack is expected to be called from audioTracks.');
verifyEvent(e, "addtrack");
};
element.audioTracks.onaddtrack = function(e) {
ok(e instanceof TrackEvent, "Event fired from onaddtrack should be a TrackEvent");
ok(true, 'onaddtrack is expected to be called from audioTracks.');
verifyEvent(e, "addtrack");
}
element.audioTracks.onremovetrack = function(e) {
ok(e instanceof TrackEvent, "Event fired from onremovetrack should be a TrackEvent");
ok(true, 'onremovetrack is expected to be called from audioTracks.');
verifyEvent(e, "removetrack");
};
element.audioTracks.onremovetrack = function(e) {
ok(e instanceof TrackEvent, "Event fired from onremovetrack should be a TrackEvent");
ok(true, 'onremovetrack is expected to be called from audioTracks.');
verifyEvent(e, "removetrack");
}
element.audioTracks.onchange = function(e) {
ok(e instanceof window.Event, "Event fired from onchange should be a simple event.");
ok(true, 'onchange is expected to be called from audioTracks.');
verifyEvent(e, "change");
};
element.audioTracks.onchange = function(e) {
ok(e instanceof window.Event, "Event fired from onchange should be a simple event.");
ok(true, 'onchange is expected to be called from audioTracks.');
verifyEvent(e, "change");
}
element.videoTracks.onaddtrack = function(e) {
ok(e instanceof TrackEvent, "Event fired from onaddtrack should be a TrackEvent");
ok(true, 'onaddtrack is expected to be called from videoTracks.');
verifyEvent(e, "addtrack");
};
element.videoTracks.onaddtrack = function(e) {
ok(e instanceof TrackEvent, "Event fired from onaddtrack should be a TrackEvent");
ok(true, 'onaddtrack is expected to be called from videoTracks.');
verifyEvent(e, "addtrack");
}
element.videoTracks.onremovetrack = function(e) {
ok(e instanceof TrackEvent, "Event fired from onremovetrack should be a TrackEvent");
ok(true, 'onremovetrack is expected to be called from videoTracks.');
verifyEvent(e, "removetrack");
};
element.videoTracks.onremovetrack = function(e) {
ok(e instanceof TrackEvent, "Event fired from onremovetrack should be a TrackEvent");
ok(true, 'onremovetrack is expected to be called from videoTracks.');
verifyEvent(e, "removetrack");
}
element.videoTracks.onchange = function(e) {
ok(e instanceof window.Event, "Event fired from onchange should be a simple event.");
ok(true, 'onchange is expected to be called from videoTracks.');
verifyEvent(e, "change");
};
element.videoTracks.onchange = function(e) {
ok(e instanceof window.Event, "Event fired from onchange should be a simple event.");
ok(true, 'onchange is expected to be called from videoTracks.');
verifyEvent(e, "change");
}
element.onended = function() {
ok(true, 'Event ended is expected to be fired on element.');
element.onended = null;
element.onplaying = null;
element.onpause = null;
//This helps to prevent these events from firing after SimpleTest.finish()
//on B2G ICS Emulator, but not sure they have been run at all, then
element.audioTracks.onremovetrack = null;
element.audioTracks.onaddtrack = null;
element.audioTracks.onchange = null;
element.videoTracks.onremovetrack = null;
element.videoTracks.onaddtrack = null;
element.videoTracks.onchange = null;
SimpleTest.finish();
}
function onended() {
ok(true, 'Event ended is expected to be fired on element.');
element.onended = null;
element.onplaying = null;
element.onpause = null;
//This helps to prevent these events from firing after SimpleTest.finish()
//on B2G ICS Emulator, but not sure they have been run at all, then
element.audioTracks.onremovetrack = null;
element.audioTracks.onaddtrack = null;
element.audioTracks.onchange = null;
element.videoTracks.onremovetrack = null;
element.videoTracks.onaddtrack = null;
element.videoTracks.onchange = null;
SimpleTest.finish();
}
function onpause() {
element.onpause = null;
if (element.ended) {
return;
}
if (steps == 1) {
element.audioTracks[0].enabled = false;
element.videoTracks[0].selected = false;
element.onplaying = onplaying;
element.play();
steps++;
}
}
function onplaying() {
element.onplaying = null;
if (element.ended) {
return;
}
if (steps == 1) {
element.onpause = onpause;
element.pause();
} else if (steps == 2) {
stream.stop();
}
}
var steps = 0;
element.srcObject = stream;
function onpause() {
element.onpause = null;
if (element.ended) {
return;
}
if (steps == 1) {
element.audioTracks[0].enabled = false;
element.videoTracks[0].selected = false;
element.onplaying = onplaying;
element.onended = onended;
element.play();
steps++;
},
function(err) {
ok(false, 'Unexpected error fired with: ' + err);
SimpleTest.finish();
}
);
}
function onplaying() {
element.onplaying = null;
if (element.ended) {
return;
}
if (steps == 1) {
element.onpause = onpause;
element.pause();
} else if (steps == 2) {
stream.stop();
}
}
element.onplaying = onplaying;
element.srcObject = stream;
isnot(element.audioTracks, undefined,
'HTMLMediaElement::AudioTracks() property should be available.');
isnot(element.videoTracks, undefined,
'HTMLMediaElement::VideoTracks() property should be available.');
steps++;
await element.play();
}
SimpleTest.waitForExplicitFinish();

View File

@ -5,17 +5,19 @@
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="text/javascript" src="manifest.js"></script>
<script type="text/javascript" src="gUM_support.js"></script>
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
function startTest() {
navigator.mediaDevices.getUserMedia({audio:true, video:true, fake:true})
.then(function(orgStream) {
var a = orgStream.getAudioTracks()[0];
var v = orgStream.getVideoTracks()[0];
var stream = new MediaStream([a, a, a, a, v, v, v].map(track => track.clone()));
var element = document.createElement("video");
async function startTest() {
try {
await setupGetUserMediaTestPrefs();
let orgStream = await navigator.mediaDevices.getUserMedia({audio: true, video: true});
let a = orgStream.getAudioTracks()[0];
let v = orgStream.getVideoTracks()[0];
let stream = new MediaStream([a, a, a, a, v, v, v].map(track => track.clone()));
let element = document.createElement("video");
element.onloadedmetadata = function() {
is(stream.getAudioTracks().length, 4, 'Length of audio tracks should be 4.');
@ -25,11 +27,10 @@ function startTest() {
element.srcObject = stream;
element.play();
})
.catch(function(reason) {
ok(false, "unexpected error = " + reason.message);
} catch (err) {
ok(false, 'Unexpected error fired with: ' + err);
SimpleTest.finish();
});
}
}
SimpleTest.waitForExplicitFinish();

View File

@ -5,75 +5,77 @@
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="text/javascript" src="manifest.js"></script>
<script type="text/javascript" src="gUM_support.js"></script>
</head>
<body>
<video id="video1" autoplay></video>
<video id="video2" autoplay></video>
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
async function startTest() {
function getVideoImagePixelData(v) {
let canvas = document.createElement("canvas");
let ctx = canvas.getContext("2d");
ctx.drawImage(v, 0, 0);
let imgData = ctx.getImageData(canvas.width/2, canvas.height/2, 1, 1).data;
return "r" + imgData[0] +
"g" + imgData[1] +
"b" + imgData[2] +
"a" + imgData[3];
}
var getVideoImagePixelData = function(v) {
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
ctx.drawImage(v, 0, 0);
var imgData = ctx.getImageData(canvas.width/2, canvas.height/2, 1, 1).data;
return "r" + imgData[0] +
"g" + imgData[1] +
"b" + imgData[2] +
"a" + imgData[3];
try {
// This test expects fake devices so that the video color will change
// over time, explicitly request fakes.
await pushGetUserMediaTestPrefs({fakeAudio: true, fakeVideo: true});
let stream = await navigator.mediaDevices.getUserMedia({video: true});
let video1 = document.getElementById('video1');
let video2 = document.getElementById('video2');
let src = URL.createObjectURL(stream);
video1.src = src;
video2.src = src;
video1.onplaying = () => video1.pause();
let v1PausedImageData;
let v2PausedImageData;
video1.onpause = function() {
v1PausedImageData = getVideoImagePixelData(video1);
v2PausedImageData = getVideoImagePixelData(video2);
v2TimesToTest = 3;
video2.ontimeupdate = function() {
if (getVideoImagePixelData(video2) === v2PausedImageData) {
// Wait until video2 has progressed it's video.
// If it doesn't, we'll time out and fail.
info("video2 has not progressed. Waiting.");
return;
}
if (--v2TimesToTest > 0) {
// Wait for a while to be sure video1 would have gotten a frame
// if it is playing.
info("video2 progressed OK");
return;
}
video2.ontimeupdate = null;
ok(true, "video2 is playing");
isnot(video1.currentTime, video2.currentTime,
"v1 and v2 should not be at the same currentTime");
is(v1PausedImageData, getVideoImagePixelData(video1),
"video1 video frame should not have updated since video1 paused");
SimpleTest.finish();
};
};
} catch (error) {
ok(false, "getUserMedia should not fail, got " + error.name);
SimpleTest.finish();
}
}
// This test does not appear to work with the "Dummy video source" provided on
// linux through the "media.video_loopback_dev" pref in the tree test environment.
// We force a stream always by requesting `fake: true` here.
navigator.mozGetUserMedia({video: true, fake: true },
function(stream) {
var stream = stream;
var video1 = document.getElementById('video1');
var video2 = document.getElementById('video2');
var src = URL.createObjectURL(stream);
video1.src = src;
video2.src = src;
video1.onplaying = () => video1.pause();
var v1PausedImageData;
var v2PausedImageData;
video1.onpause = function() {
v1PausedImageData = getVideoImagePixelData(video1);
v2PausedImageData = getVideoImagePixelData(video2);
v2TimesToTest = 3;
video2.ontimeupdate = function() {
if (getVideoImagePixelData(video2) === v2PausedImageData) {
// Wait until video2 has progressed it's video.
// If it doesn't, we'll time out and fail.
info("video2 has not progressed. Waiting.");
return;
}
if (--v2TimesToTest > 0) {
// Wait for a while to be sure video1 would have gotten a frame
// if it is playing.
info("video2 progressed OK");
return;
}
video2.ontimeupdate = null;
ok(true, "video2 is playing");
isnot(video1.currentTime, video2.currentTime,
"v1 and v2 should not be at the same currentTime");
is(v1PausedImageData, getVideoImagePixelData(video1),
"video1 video frame should not have updated since video1 paused");
SimpleTest.finish();
};
};
}, function(error) {
ok(false, "getUserMedia should not fail, got " + error.name);
SimpleTest.finish();
});
SimpleTest.waitForExplicitFinish();
startTest();
</script>
</body>
</html>