blob: 036d81aeeb0487a395827ae48190e3c7b370c21c [file] [log] [blame]
var MediaSourceTest = {};
var mediaSource = new WebKitMediaSource();
MediaSourceTest.SegmentHelper = function(segmentInfo, fullDuration)
{
this.MediaSegmentsToLoad = 0;
this.sourceBuffer = null;
this.videoTag = null;
this.segmentInfo = segmentInfo;
this.initSegment = null;
this.mediaSegments = [];
// Limit how many media segments we load based on time.
var maxDuration = 3;
for (var i in this.segmentInfo.media) {
if (!fullDuration && this.segmentInfo.media[i].timecode > maxDuration)
break;
this.MediaSegmentsToLoad++;
}
// Require 3 or more segments for testing. This guarantees that there are at least 3 random
// access points in the content.
if (this.MediaSegmentsToLoad < 3)
consoleWrite("Need more media segments for testing. " + this.MediaSegmentsToLoad + " is not enough");
};
MediaSourceTest.SegmentHelper.prototype.init = function(videoTag, doneCallback)
{
if (!videoTag) {
doneCallback(false);
return;
}
this.videoTag = videoTag;
var t = this;
var getDataCallback = function(data) { t.getInitSegmentDone_(doneCallback, data); };
this.getData_(this.segmentInfo.url,
this.segmentInfo.init.offset, this.segmentInfo.init.size,
getDataCallback);
};
MediaSourceTest.SegmentHelper.prototype.getInitSegmentDone_ = function(doneCallback, data)
{
if (!data) {
doneCallback(false);
return;
}
this.initSegment = data;
this.downloadMediaSegment_(0, doneCallback);
};
MediaSourceTest.SegmentHelper.prototype.downloadMediaSegment_ = function(index, doneCallback)
{
var t = this;
var getDataCallback = function(data) { t.downloadMediaSegmentDone_(index, doneCallback, data); };
this.getData_(this.segmentInfo.url,
this.segmentInfo.media[index].offset,
this.segmentInfo.media[index].size,
getDataCallback);
};
MediaSourceTest.SegmentHelper.prototype.downloadMediaSegmentDone_ = function(index, doneCallback, data)
{
if (!data) {
doneCallback(false);
return;
}
this.mediaSegments.push(data);
if (this.mediaSegments.length == this.MediaSegmentsToLoad) {
doneCallback(true);
return;
}
this.downloadMediaSegment_(index + 1, doneCallback);
};
MediaSourceTest.SegmentHelper.prototype.getData_ = function (url, start, length, callback)
{
var request = new XMLHttpRequest();
request.open("GET", url, true);
if (start && start < 0) {
failTest("Invalid start parameter " + start);
return;
}
if (length && length <= 0) {
failTest("Invalid length parameter " + length);
return;
}
var expectedStatus = 200;
if (start >= 0) {
var startOffset = start;
var rangeString = 'bytes=' + startOffset + '-';
if (length && length > 0) {
var endOffset = startOffset + length - 1;
rangeString += endOffset;
}
expectedStatus = 206;
request.setRequestHeader('Range', rangeString);
}
request.responseType = 'arraybuffer';
request.onload = function()
{
if (request.status != expectedStatus) {
failTest("Unexpected status code " + request.status + " for " + url);
callback(null);
return;
}
callback(new Uint8Array(request.response));
};
request.send();
};
MediaSourceTest.SegmentHelper.prototype.addSourceBuffer = function()
{
this.sourceBuffer = mediaSource.addSourceBuffer(this.segmentInfo.type);
};
MediaSourceTest.SegmentHelper.prototype.appendInitSegment = function()
{
this.sourceBuffer.append(this.initSegment);
};
MediaSourceTest.SegmentHelper.prototype.appendMediaSegment = function(index)
{
this.sourceBuffer.append(this.mediaSegments[index]);
};
MediaSourceTest.SegmentHelper.prototype.appendAllMediaSegments = function()
{
for (var i = 0; i < this.mediaSegments.length; i++)
this.appendMediaSegment(i);
};
MediaSourceTest.SegmentHelper.prototype.appendUntilEndOfStream = function(startIndex)
{
if (!this.sourceBuffer) {
failTest("MediaSource API is not available");
return;
}
for (var index = startIndex; index < this.mediaSegments.length; index++)
this.appendMediaSegment(index);
mediaSource.endOfStream();
};
MediaSourceTest.SegmentHelper.prototype.getTimeForMediaSegment = function(index)
{
return this.segmentInfo.media[index].timecode;
};
MediaSourceTest.SegmentHelper.prototype.getMediaSegmentIndexForTimestamp = function(timestamp)
{
if (timestamp <= this.getTimeForMediaSegment(0))
return 0;
for (var index = 1; index < this.mediaSegments.length; index++) {
if (timestamp < this.getTimeForMediaSegment(index)) {
return index - 1;
}
}
return this.mediaSegments.length - 1;
};
MediaSourceTest.setSrcToMediaSourceTestURL = function(videoTag)
{
if (!mediaSource) {
failTest("MediaSource is not available");
return;
}
videoTag.src = webkitURL.createObjectURL(mediaSource);
};
MediaSourceTest.mediaErrorString = function(videoTag)
{
var errorString = "UNKNOWN";
switch(videoTag.error.code) {
case MediaError.MEDIA_ERR_ABORTED:
errorString = "MEDIA_ERR_ABORTED";
break;
case MediaError.MEDIA_ERR_NETWORK:
errorString = "MEDIA_ERR_NETWORK";
break;
case MediaError.MEDIA_ERR_DECODE:
errorString = "MEDIA_ERR_DECODE";
break;
case MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED:
errorString = "MEDIA_ERR_SRC_NOT_SUPPORTED";
break;
}
return errorString;
};
MediaSourceTest.defaultOnErrorChecks = function(event)
{
var videoTag = event.target;
consoleWrite("EVENT(error) : " + MediaSourceTest.mediaErrorString(videoTag));
if (mediaSource.readyState != "closed") {
consoleWrite("Unexpected source state. Expected 'closed'" +
" got " + mediaSource.readyState);
}
};
MediaSourceTest.runNext_ = function(videoTag, testCaseIndex, tests, testWrapperFunction)
{
if (testCaseIndex >= tests.length) {
endTest();
return;
}
var onOpenFunction = tests[testCaseIndex];
var functionName = onOpenFunction.name;
var runNextFunction = function()
{
MediaSourceTest.runNext_(videoTag, testCaseIndex + 1, tests, testWrapperFunction);
};
var errorEventHandler = function(event)
{
event.target.removeEventListener('error', errorEventHandler);
MediaSourceTest.defaultOnErrorChecks(event);
runNextFunction();
};
videoTag.addEventListener('error', errorEventHandler);
consoleWrite("");
consoleWrite("running " + functionName);
if (testWrapperFunction) {
onOpenFunction = testWrapperFunction(onOpenFunction);
}
onOpenFunction(runNextFunction, videoTag);
};
MediaSourceTest.startTesting = function(videoTag, tests)
{
MediaSourceTest.runNext_(videoTag, 0, tests);
};
MediaSourceTest.startSourceOpenTesting = function(videoTag, tests)
{
// Wrapper function that executes the test function when the
// source open event has fired.
var testWrapperFunction = function(testFunction)
{
return function(runNextFunction, videoTag)
{
MediaSourceTest.runOnSourceOpen(videoTag, function()
{
testFunction(runNextFunction, videoTag);
});
};
};
MediaSourceTest.runNext_(videoTag, 0, tests, testWrapperFunction);
};
MediaSourceTest.runOnSourceOpen = function(videoTag, onOpenFunction)
{
var eventHandlerFunction = function (event)
{
if (videoTag.networkState != HTMLMediaElement.NETWORK_LOADING &&
videoTag.networkState != HTMLMediaElement.NETWORK_IDLE) {
failTest("Unexpected network state. Expected " +
HTMLMediaElement.NETWORK_LOADING + " or " +
HTMLMediaElement.NETWORK_IDLE +
" got " + videoTag.readyState);
}
event.target.removeEventListener('webkitsourceopen', eventHandlerFunction);
onOpenFunction();
};
mediaSource.addEventListener('webkitsourceopen', eventHandlerFunction);
MediaSourceTest.setSrcToMediaSourceTestURL(videoTag);
};
MediaSourceTest.logSourceState = function(mediaSource)
{
consoleWrite("webkitSourceState : " + mediaSource.readyState);
};
MediaSourceTest.expectSourceState = function(mediaSource, expected)
{
if (mediaSource.readyState != expected) {
failTest("Unexpected source state. Expected " + expected +
" got " + mediaSource.readyState);
}
};
MediaSourceTest.expectReadyState = function(videoTag, expected)
{
if (videoTag.readyState != expected) {
failTest("Unexpected ready state. Expected " +
MediaSourceTest.getReadyStateName(expected) +
" got " + MediaSourceTest.getReadyStateName(videoTag.readyState));
}
};
MediaSourceTest.roundedEquals_ = function(expected, actual)
{
return expected.toFixed(3) == actual.toFixed(3);
};
MediaSourceTest.expectDuration = function(videoTag, mediaSource, expected)
{
if (!this.roundedEquals_(expected, videoTag.duration))
failTest("Unexpected duration. Expected " + expected + " got " + videoTag.duration);
if (!this.roundedEquals_(expected, mediaSource.duration))
failTest("Unexpected duration. Expected " + expected + " got " + mediaSource.duration);
};
MediaSourceTest.expectBufferedRange = function(sourceBuffer, expected)
{
if (sourceBuffer.buffered.length != expected.length)
failTest("Unexpected number of buffered regions. Expected " + expected.length + " got " + sourceBuffer.buffered.length);
for (var i = 0; i < expected.length; i++) {
var expectedStart = expected[i][0];
var expectedEnd = expected[i][1];
var actualStart = sourceBuffer.buffered.start(i);
var actualEnd = sourceBuffer.buffered.end(i);
if (!this.roundedEquals_(expectedStart, actualStart) ||
!this.roundedEquals_(expectedEnd, actualEnd)) {
failTest("Unexpected buffered region. Expected (" + expectedStart + ", " + expectedEnd + ") got ("
+ actualStart + ", " + actualEnd +")");
}
}
};
MediaSourceTest.getReadyStateName = function(state)
{
var stateName = "UNKNOWN";
switch (state) {
case HTMLMediaElement.HAVE_NOTHING:
stateName = "HAVE_NOTHING";
break;
case HTMLMediaElement.HAVE_METADATA:
stateName = "HAVE_METADATA";
break;
case HTMLMediaElement.HAVE_CURRENT_DATA:
stateName = "HAVE_CURRENT_DATA";
break;
case HTMLMediaElement.HAVE_FUTURE_DATA:
stateName = "HAVE_FUTURE_DATA";
break;
case HTMLMediaElement.HAVE_ENOUGH_DATA:
stateName = "HAVE_ENOUGH_DATA";
break;
}
return stateName;
};