blob: eaaf98b8fd6138f66b75a272d58b3a16cafd4e01 [file] [log] [blame]
<!DOCTYPE html>
<html>
<head>
<title>MediaStream Recoder Cros Test (w/ MediaSource)</title>
</head>
<body>
<div> Record Real-Time video content browser test.</div>
<video id="video" autoplay></video>
</body>
<script type="text/javascript" src="mediarecorder_test_utils.js"></script>
<script>
'use strict';
// This test must be run with experimental GetUserMedia flag on.
// The testcases are identical to the media recorder content browser test.
// Helper functions like failTest etc are implemented so they map to the
// CrOS test environment.
// Begin cros related code.
var testProgress = 0;
var result;
function failTest(reason) {
result = 'FAIL: ' + reason;
console.log('Test Failed:', reason);
testProgress = 1;
// Cause test termination.
throw reason;
}
function reportTestSuccess() {
result = 'PASS';
console.log('Test Passed');
testProgress = 1;
}
function assertEquals(expected, actual) {
if (actual != expected)
failTest("expected '" + expected + "', got '" + actual + "'.");
}
function assertTrue(booleanExpression, reason) {
if (!booleanExpression)
failTest(reason);
}
// End cros related code.
const DEFAULT_CONSTRAINTS = {audio: true, video: true};
const DEFAULT_RECORDER_MIME_TYPE = '';
const DEFAULT_TIME_SLICE = 100;
// Function assert_throws inspired from Blink's
// LayoutTests/resources/testharness.js
function assertThrows(func, description) {
try {
func.call(this);
failTest('Error:' + func + description + ' did not throw!');
} catch (e) {
console.log(e);
reportTestSuccess();
}
}
function createAndStartMediaRecorder(stream, mimeType, slice) {
return new Promise(function(resolve, reject) {
document.getElementById('video').src = URL.createObjectURL(stream);
var recorder = new MediaRecorder(stream, {'mimeType' : mimeType});
console.log('Recorder object created.');
if (slice != undefined) {
recorder.start(slice);
console.log('Recorder started with time slice', slice);
} else {
recorder.start();
}
resolve(recorder);
});
}
function createMediaRecorder(stream, mimeType) {
return new Promise(function(resolve, reject) {
var recorder = new MediaRecorder(stream, {'mimeType' : mimeType});
console.log('Recorder object created.');
resolve(recorder);
});
}
// Tests that the MediaRecorder's start() function will cause the |state| to be
// 'recording' and that a 'start' event is fired.
function testStartAndRecorderState() {
var startEventReceived = false;
navigator.mediaDevices.getUserMedia(DEFAULT_CONSTRAINTS)
.then(function(stream) {
return createMediaRecorder(stream, DEFAULT_RECORDER_MIME_TYPE);
})
.then(function(recorder) {
recorder.onstart = function(event) {
startEventReceived = true;
assertEquals('recording', recorder.state);
};
recorder.start();
})
.then(function() {
return waitFor('Start event',
function() {
return startEventReceived;
});
})
.catch(function(err) {
return failTest(err.toString());
})
.then(function() {
reportTestSuccess();
});
}
// Tests that the MediaRecorder's stop() function will effectively cause the
// |state| to be 'inactive' and that a 'stop' event is fired.
function testStartStopAndRecorderState() {
var stopEventReceived = false;
navigator.mediaDevices.getUserMedia(DEFAULT_CONSTRAINTS)
.then(function(stream) {
return createAndStartMediaRecorder(stream, DEFAULT_RECORDER_MIME_TYPE);
})
.then(function(recorder) {
recorder.onstop = function(event) {
stopEventReceived = true;
assertEquals('inactive', recorder.state);
};
recorder.stop();
})
.then(function() {
return waitFor('Stop event',
function() {
return stopEventReceived;
});
})
.catch(function(err) {
return failTest(err.toString());
})
.then(function() {
reportTestSuccess();
});
}
// Tests that when MediaRecorder's start() function is called, some data is
// made available by media recorder via dataavailable events, containing non
// empty blob data.
function testStartAndDataAvailable() {
var videoSize = 0;
var emptyBlobs = 0;
var timeStamps = [];
navigator.mediaDevices.getUserMedia(DEFAULT_CONSTRAINTS)
.then(function(stream) {
return createAndStartMediaRecorder(stream, DEFAULT_RECORDER_MIME_TYPE);
})
.then(function(recorder) {
// Save history of Blobs received via dataavailable.
recorder.ondataavailable = function(event) {
timeStamps.push(event.timeStamp);
if (event.data.size > 0)
videoSize += event.data.size;
else
emptyBlobs += 1;
};
})
.then(function() {
return waitFor('Make sure the recording has data',
function() {
return videoSize > 0;
});
})
.then(function() {
assertTrue(emptyBlobs == 0, 'Recording has ' + emptyBlobs +
' empty blobs, there should be no such empty blobs.');
})
.catch(function(err) {
return failTest(err.toString());
})
.then(function() {
reportTestSuccess();
});
}
// Tests that when MediaRecorder's start(timeSlice) is called, some data
// available events are fired containing non empty blob data.
function testStartWithTimeSlice() {
var videoSize = 0;
var emptyBlobs = 0;
var timeStamps = [];
navigator.mediaDevices.getUserMedia(DEFAULT_CONSTRAINTS)
.then(function(stream) {
return createAndStartMediaRecorder(stream, DEFAULT_RECORDER_MIME_TYPE,
DEFAULT_TIME_SLICE);
})
.then(function(recorder) {
recorder.ondataavailable = function(event) {
timeStamps.push(event.timeStamp);
if (event.data.size > 0)
videoSize += event.data.size;
else
emptyBlobs += 1;
};
})
.then(function() {
return waitFor('Making sure the recording has data',
function() {
return videoSize > 0 && timeStamps.length > 10;
});
})
.then(function() {
assertTrue(emptyBlobs == 0, 'Recording has ' + emptyBlobs +
' empty blobs, there should be no such empty blobs.');
})
.catch(function(err) {
return failTest(err.toString());
})
.then(function() {
reportTestSuccess();
});
}
// Tests that when a MediaRecorder's resume() is called, the |state| is
// 'recording' and a 'resume' event is fired.
function testResumeAndRecorderState() {
var theRecorder;
var resumeEventReceived = false;
navigator.mediaDevices.getUserMedia(DEFAULT_CONSTRAINTS)
.then(function(stream) {
return createAndStartMediaRecorder(stream, DEFAULT_RECORDER_MIME_TYPE);
})
.then(function(recorder) {
theRecorder = recorder;
theRecorder.pause();
})
.then(function() {
theRecorder.onresume = function(event) {
resumeEventReceived = true;
assertEquals('recording', theRecorder.state);
};
theRecorder.resume();
})
.then(function() {
return waitFor('Making sure the resume event has been received',
function() {
return resumeEventReceived;
});
})
.catch(function(err) {
return failTest(err.toString());
})
.then(function() {
reportTestSuccess();
});
}
// Tests that is it not possible to resume an inactive MediaRecorder.
function testIllegalResumeThrowsDOMError() {
navigator.mediaDevices.getUserMedia(DEFAULT_CONSTRAINTS)
.then(function(stream) {
return createMediaRecorder(stream, DEFAULT_RECORDER_MIME_TYPE);
})
.then(function(recorder) {
assertThrows(function() {recorder.resume()}, 'Calling resume() in' +
' inactive state should cause a DOM error');
});
}
// Tests that MediaRecorder sends data blobs when resume() is called.
function testResumeAndDataAvailable() {
var videoSize = 0;
var emptyBlobs = 0;
navigator.mediaDevices.getUserMedia(DEFAULT_CONSTRAINTS)
.then(function(stream) {
return createAndStartMediaRecorder(stream, DEFAULT_RECORDER_MIME_TYPE);
})
.then(function(recorder) {
recorder.pause();
recorder.ondataavailable = function(event) {
if (event.data.size > 0) {
videoSize += event.data.size;
} else {
console.log('This dataavailable event is empty', event);
emptyBlobs += 1;
}
};
recorder.resume();
})
.then(function() {
return waitFor('Make sure the recording has data after resuming',
function() {
return videoSize > 0;
});
})
.then(function() {
// There should be no empty blob while recording.
assertTrue(emptyBlobs == 0, 'Recording has ' + emptyBlobs +
' empty blobs, there should be no such empty blobs.');
})
.catch(function(err) {
return failTest(err.toString());
})
.then(function() {
reportTestSuccess();
});
}
</script>
</body>
</html>