mirror of
https://github.com/shaka-project/shaka-player.git
synced 2026-06-26 17:46:26 +03:00
3e300d25ae
The live-edge calculation in PresentationTimeline needs to take into account the duration of the current segment since the current segment is not available until it has ended. To do this we use MPD@maxSegmentDuration when available, and compute our own maxSegmentDuration when it's not (as specified by the DASH spec). Change-Id: Ic5b8478dbbff8eac93cf123a00a8b02db140cf15
737 lines
25 KiB
JavaScript
737 lines
25 KiB
JavaScript
/**
|
|
* @license
|
|
* Copyright 2016 Google Inc.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
// Test basic manifest parsing functionality.
|
|
describe('DashParser.Manifest', function() {
|
|
var Dash;
|
|
var fakeNetEngine;
|
|
var parser;
|
|
var filterPeriod = function() {};
|
|
|
|
beforeEach(function() {
|
|
fakeNetEngine = new shaka.test.FakeNetworkingEngine();
|
|
parser = shaka.test.Dash.makeDashParser();
|
|
});
|
|
|
|
beforeAll(function() {
|
|
Dash = shaka.test.Dash;
|
|
});
|
|
|
|
/**
|
|
* Makes a series of tests for the given manifest type.
|
|
*
|
|
* @param {!Array.<string>} startLines
|
|
* @param {!Array.<string>} endLines
|
|
* @param {shakaExtern.Manifest} expected
|
|
*/
|
|
function makeTestsForEach(startLines, endLines, expected) {
|
|
/**
|
|
* Makes manifest text for testing.
|
|
*
|
|
* @param {!Array.<string>} lines
|
|
* @return {string}
|
|
*/
|
|
function makeTestManifest(lines) {
|
|
return startLines.concat(lines, endLines).join('\n');
|
|
};
|
|
|
|
/**
|
|
* Tests that the parser produces the correct results.
|
|
*
|
|
* @param {function()} done
|
|
* @param {string} manifestText
|
|
*/
|
|
function testDashParser(done, manifestText) {
|
|
fakeNetEngine.setResponseMapAsText({'dummy://foo': manifestText});
|
|
parser.start('dummy://foo', fakeNetEngine, filterPeriod, fail)
|
|
.then(function(actual) { expect(actual).toEqual(expected); })
|
|
.catch(fail)
|
|
.then(done);
|
|
};
|
|
|
|
it('with SegmentBase', function(done) {
|
|
var source = makeTestManifest([
|
|
' <SegmentBase indexRange="100-200" timescale="9000">',
|
|
' <Initialization sourceURL="init.mp4" range="201-300" />',
|
|
' </SegmentBase>'
|
|
]);
|
|
testDashParser(done, source);
|
|
});
|
|
|
|
it('with SegmentList', function(done) {
|
|
var source = makeTestManifest([
|
|
' <SegmentList startNumber="1" duration="10">',
|
|
' <Initialization sourceURL="init.mp4" range="201-300" />',
|
|
' <SegmentURL media="s1.mp4" />',
|
|
' </SegmentList>'
|
|
]);
|
|
testDashParser(done, source);
|
|
});
|
|
|
|
it('with SegmentTemplate', function(done) {
|
|
var source = makeTestManifest([
|
|
' <SegmentTemplate startNumber="1" media="l-$Number$.mp4"',
|
|
' initialization="init.mp4">',
|
|
' <Initialization sourceURL="init.mp4" range="201-300" />',
|
|
' <SegmentTimeline>',
|
|
' <S t="0" d="30" />',
|
|
' </SegmentTimeline>',
|
|
' </SegmentTemplate>'
|
|
]);
|
|
testDashParser(done, source);
|
|
});
|
|
};
|
|
|
|
describe('parses and inherits attributes', function() {
|
|
makeTestsForEach(
|
|
[
|
|
'<MPD minBufferTime="PT75S">',
|
|
' <Period id="1" duration="PT30S">',
|
|
' <BaseURL>http://example.com</BaseURL>'
|
|
],
|
|
[
|
|
' <AdaptationSet contentType="video" mimeType="video/mp4"',
|
|
' codecs="avc1.4d401f" lang="en">',
|
|
' <Representation bandwidth="100" width="768" height="576" />',
|
|
' <Representation bandwidth="50" width="576" height="432" />',
|
|
' </AdaptationSet>',
|
|
' <AdaptationSet mimeType="text/vtt" codecs="mp4a.40.29"',
|
|
' lang="es">',
|
|
' <Role value="caption" />',
|
|
' <Representation bandwidth="100" />',
|
|
' </AdaptationSet>',
|
|
' <AdaptationSet mimeType="audio/mp4">',
|
|
' <Role value="main" />',
|
|
' <Representation />',
|
|
' </AdaptationSet>',
|
|
' </Period>',
|
|
'</MPD>'
|
|
],
|
|
/** @type {shakaExtern.Manifest} */ ({
|
|
minBufferTime: 75,
|
|
presentationTimeline: jasmine.any(shaka.media.PresentationTimeline),
|
|
periods: [
|
|
{
|
|
startTime: 0,
|
|
streamSets: [
|
|
{
|
|
language: 'en',
|
|
type: 'video',
|
|
primary: false,
|
|
drmInfos: [],
|
|
streams: [
|
|
jasmine.objectContaining({
|
|
id: jasmine.any(Number),
|
|
createSegmentIndex: jasmine.any(Function),
|
|
findSegmentPosition: jasmine.any(Function),
|
|
getSegmentReference: jasmine.any(Function),
|
|
initSegmentReference:
|
|
jasmine.any(shaka.media.InitSegmentReference),
|
|
mimeType: 'video/mp4',
|
|
codecs: 'avc1.4d401f',
|
|
bandwidth: 100,
|
|
width: 768,
|
|
height: 576,
|
|
keyId: null
|
|
}),
|
|
jasmine.objectContaining({
|
|
id: jasmine.any(Number),
|
|
createSegmentIndex: jasmine.any(Function),
|
|
findSegmentPosition: jasmine.any(Function),
|
|
getSegmentReference: jasmine.any(Function),
|
|
initSegmentReference:
|
|
jasmine.any(shaka.media.InitSegmentReference),
|
|
mimeType: 'video/mp4',
|
|
codecs: 'avc1.4d401f',
|
|
bandwidth: 50,
|
|
width: 576,
|
|
height: 432,
|
|
keyId: null
|
|
})
|
|
]
|
|
},
|
|
{
|
|
language: 'es',
|
|
type: 'text',
|
|
primary: false,
|
|
drmInfos: [],
|
|
streams: [
|
|
jasmine.objectContaining({
|
|
id: jasmine.any(Number),
|
|
createSegmentIndex: jasmine.any(Function),
|
|
findSegmentPosition: jasmine.any(Function),
|
|
getSegmentReference: jasmine.any(Function),
|
|
initSegmentReference:
|
|
jasmine.any(shaka.media.InitSegmentReference),
|
|
mimeType: 'text/vtt',
|
|
codecs: 'mp4a.40.29',
|
|
bandwidth: 100,
|
|
keyId: null,
|
|
kind: 'caption'
|
|
})
|
|
]
|
|
},
|
|
{
|
|
language: '',
|
|
type: 'audio',
|
|
primary: true,
|
|
drmInfos: [],
|
|
streams: [
|
|
jasmine.objectContaining({
|
|
id: jasmine.any(Number),
|
|
createSegmentIndex: jasmine.any(Function),
|
|
findSegmentPosition: jasmine.any(Function),
|
|
getSegmentReference: jasmine.any(Function),
|
|
initSegmentReference:
|
|
jasmine.any(shaka.media.InitSegmentReference),
|
|
mimeType: 'audio/mp4',
|
|
codecs: '',
|
|
keyId: null
|
|
})
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}));
|
|
});
|
|
|
|
describe('squashes stream sets by AdaptationSetSwitching', function() {
|
|
makeTestsForEach(
|
|
[
|
|
'<MPD minBufferTime="PT75S">',
|
|
' <Period id="1" duration="PT30S">',
|
|
' <BaseURL>http://example.com</BaseURL>'
|
|
],
|
|
[
|
|
' <AdaptationSet id="1" mimeType="video/mp4" lang="en">',
|
|
' <SupplementalProperty value="2"',
|
|
'schemeIdURI="http://dashif.org/descriptor/AdaptationSetSwitching"/>',
|
|
' <Representation bandwidth="100" />',
|
|
' </AdaptationSet>',
|
|
' <AdaptationSet id="2" mimeType="video/mp4" lang="en">',
|
|
' <Representation bandwidth="200" />',
|
|
' </AdaptationSet>',
|
|
' </Period>',
|
|
'</MPD>'
|
|
],
|
|
shaka.test.Dash.makeManifestFromStreamSets([
|
|
{
|
|
language: 'en',
|
|
type: 'video',
|
|
primary: false,
|
|
drmInfos: [],
|
|
streams: [
|
|
jasmine.objectContaining({bandwidth: 100}),
|
|
jasmine.objectContaining({bandwidth: 200})
|
|
]
|
|
}
|
|
]));
|
|
});
|
|
|
|
describe('ignores unrecognized IDs in AdaptationSetSwitching', function() {
|
|
makeTestsForEach(
|
|
[
|
|
'<MPD minBufferTime="PT75S">',
|
|
' <Period id="1" duration="PT30S">',
|
|
' <BaseURL>http://example.com</BaseURL>'
|
|
],
|
|
[
|
|
' <AdaptationSet mimeType="video/mp4" lang="en" id="1">',
|
|
' <SupplementalProperty value="4"',
|
|
'schemeIdURI="http://dashif.org/descriptor/AdaptationSetSwitching"/>',
|
|
' <Representation bandwidth="100" />',
|
|
' </AdaptationSet>',
|
|
' <AdaptationSet mimeType="video/mp4" lang="en" id="2">',
|
|
' <Representation bandwidth="200" />',
|
|
' </AdaptationSet>',
|
|
' </Period>',
|
|
'</MPD>'
|
|
],
|
|
shaka.test.Dash.makeManifestFromStreamSets([
|
|
{
|
|
language: 'en',
|
|
type: 'video',
|
|
primary: false,
|
|
drmInfos: [],
|
|
streams: [
|
|
jasmine.objectContaining({bandwidth: 100})
|
|
]
|
|
},
|
|
{
|
|
language: 'en',
|
|
type: 'video',
|
|
primary: false,
|
|
drmInfos: [],
|
|
streams: [
|
|
jasmine.objectContaining({bandwidth: 200})
|
|
]
|
|
}
|
|
]));
|
|
});
|
|
|
|
describe('does not squash different languages', function() {
|
|
makeTestsForEach(
|
|
[
|
|
'<MPD minBufferTime="PT75S">',
|
|
' <Period id="1" duration="PT30S">',
|
|
' <BaseURL>http://example.com</BaseURL>'
|
|
],
|
|
[
|
|
' <AdaptationSet mimeType="video/mp4" lang="en" id="1">',
|
|
' <SupplementalProperty value="2"',
|
|
'schemeIdURI="http://dashif.org/descriptor/AdaptationSetSwitching"/>',
|
|
' <Representation bandwidth="100" />',
|
|
' </AdaptationSet>',
|
|
' <AdaptationSet mimeType="video/mp4" lang="es" id="2">',
|
|
' <SupplementalProperty value="1"',
|
|
'schemeIdURI="http://dashif.org/descriptor/AdaptationSetSwitching"/>',
|
|
' <Representation bandwidth="200" />',
|
|
' </AdaptationSet>',
|
|
' </Period>',
|
|
'</MPD>'
|
|
],
|
|
shaka.test.Dash.makeManifestFromStreamSets([
|
|
{
|
|
language: 'en',
|
|
type: 'video',
|
|
primary: false,
|
|
drmInfos: [],
|
|
streams: [
|
|
jasmine.objectContaining({bandwidth: 100})
|
|
]
|
|
},
|
|
{
|
|
language: 'es',
|
|
type: 'video',
|
|
primary: false,
|
|
drmInfos: [],
|
|
streams: [
|
|
jasmine.objectContaining({bandwidth: 200})
|
|
]
|
|
}
|
|
]));
|
|
});
|
|
|
|
describe('does not squash different content types', function() {
|
|
makeTestsForEach(
|
|
[
|
|
'<MPD minBufferTime="PT75S">',
|
|
' <Period id="1" duration="PT30S">',
|
|
' <BaseURL>http://example.com</BaseURL>'
|
|
],
|
|
[
|
|
' <AdaptationSet mimeType="video/mp4" lang="en" id="1">',
|
|
' <SupplementalProperty value="2"',
|
|
'schemeIdURI="http://dashif.org/descriptor/AdaptationSetSwitching"/>',
|
|
' <Representation bandwidth="100" />',
|
|
' </AdaptationSet>',
|
|
' <AdaptationSet mimeType="audio/mp4" lang="en" id="2">',
|
|
' <SupplementalProperty value="1"',
|
|
'schemeIdURI="http://dashif.org/descriptor/AdaptationSetSwitching"/>',
|
|
' <Representation bandwidth="200" />',
|
|
' </AdaptationSet>',
|
|
' </Period>',
|
|
'</MPD>'
|
|
],
|
|
shaka.test.Dash.makeManifestFromStreamSets([
|
|
{
|
|
language: 'en',
|
|
type: 'video',
|
|
primary: false,
|
|
drmInfos: [],
|
|
streams: [
|
|
jasmine.objectContaining({bandwidth: 100})
|
|
]
|
|
},
|
|
{
|
|
language: 'en',
|
|
type: 'audio',
|
|
primary: false,
|
|
drmInfos: [],
|
|
streams: [
|
|
jasmine.objectContaining({bandwidth: 200})
|
|
]
|
|
}
|
|
]));
|
|
});
|
|
|
|
it('skips any periods after one without duration', function(done) {
|
|
var periodContents = [
|
|
' <AdaptationSet mimeType="video/mp4" lang="en" group="1">',
|
|
' <Representation bandwidth="100">',
|
|
' <SegmentBase presentationTimeOffset="1" indexRange="100-200">',
|
|
' <Initialization sourceURL="init.mp4" range="201-300" />',
|
|
' </SegmentBase>',
|
|
' </Representation>',
|
|
' </AdaptationSet>'
|
|
].join('\n');
|
|
var template = [
|
|
'<MPD minBufferTime="PT75S">',
|
|
' <Period id="1">',
|
|
'%(periodContents)s',
|
|
' </Period>',
|
|
' <Period id="2">',
|
|
'%(periodContents)s',
|
|
' </Period>',
|
|
'</MPD>'
|
|
].join('\n');
|
|
var source = sprintf(template, {periodContents: periodContents});
|
|
|
|
fakeNetEngine.setResponseMapAsText({'dummy://foo': source});
|
|
parser.start('dummy://foo', fakeNetEngine, filterPeriod, fail)
|
|
.then(function(manifest) {
|
|
expect(manifest.periods.length).toBe(1);
|
|
})
|
|
.catch(fail)
|
|
.then(done);
|
|
});
|
|
|
|
it('calculates Period times when missing', function(done) {
|
|
var periodContents = [
|
|
' <AdaptationSet mimeType="video/mp4" lang="en" group="1">',
|
|
' <Representation bandwidth="100">',
|
|
' <SegmentBase presentationTimeOffset="1" indexRange="100-200">',
|
|
' <Initialization sourceURL="init.mp4" range="201-300" />',
|
|
' </SegmentBase>',
|
|
' </Representation>',
|
|
' </AdaptationSet>'
|
|
].join('\n');
|
|
var template = [
|
|
'<MPD mediaPresentationDuration="PT75S">',
|
|
' <Period id="1" start="PT10S">',
|
|
'%(periodContents)s',
|
|
' </Period>',
|
|
' <Period id="2" start="PT20S" duration="PT10S">',
|
|
'%(periodContents)s',
|
|
' </Period>',
|
|
' <Period id="3" duration="PT10S">',
|
|
'%(periodContents)s',
|
|
' </Period>',
|
|
'</MPD>'
|
|
].join('\n');
|
|
var source = sprintf(template, {periodContents: periodContents});
|
|
|
|
fakeNetEngine.setResponseMapAsText({'dummy://foo': source});
|
|
parser.start('dummy://foo', fakeNetEngine, filterPeriod, fail)
|
|
.then(function(manifest) {
|
|
expect(manifest.periods.length).toBe(3);
|
|
expect(manifest.periods[0].startTime).toBe(10);
|
|
expect(manifest.periods[1].startTime).toBe(20);
|
|
expect(manifest.periods[2].startTime).toBe(30);
|
|
})
|
|
.catch(fail)
|
|
.then(done);
|
|
});
|
|
|
|
it('defaults to SegmentBase with multiple Segment*', function(done) {
|
|
var source = Dash.makeSimpleManifestText([
|
|
'<SegmentBase presentationTimeOffset="1" indexRange="100-200">',
|
|
' <Initialization sourceURL="init.mp4" range="201-300" />',
|
|
'</SegmentBase>',
|
|
'<SegmentList presentationTimeOffset="2" duration="10">',
|
|
' <Initialization sourceURL="init.mp4" range="201-300" />',
|
|
' <SegmentURL media="s1.mp4" />',
|
|
'</SegmentList>'
|
|
]);
|
|
|
|
fakeNetEngine.setResponseMapAsText({'dummy://foo': source});
|
|
parser.start('dummy://foo', fakeNetEngine, filterPeriod, fail)
|
|
.then(function(manifest) {
|
|
var stream = manifest.periods[0].streamSets[0].streams[0];
|
|
expect(stream.presentationTimeOffset).toBe(1);
|
|
})
|
|
.catch(fail)
|
|
.then(done);
|
|
});
|
|
|
|
it('defaults to SegmentList with SegmentTemplate', function(done) {
|
|
var source = Dash.makeSimpleManifestText([
|
|
'<SegmentList presentationTimeOffset="2" duration="10">',
|
|
' <Initialization sourceURL="init.mp4" range="201-300" />',
|
|
' <SegmentURL media="s1.mp4" />',
|
|
'</SegmentList>',
|
|
'<SegmentTemplate startNumber="1" media="l-$Number$.mp4"',
|
|
' presentationTimeOffset="3" initialization="init.mp4">',
|
|
' <Initialization sourceURL="init.mp4" range="201-300" />',
|
|
' <SegmentTimeline>',
|
|
' <S t="0" d="30" />',
|
|
' </SegmentTimeline>',
|
|
'</SegmentTemplate>'
|
|
]);
|
|
|
|
fakeNetEngine.setResponseMapAsText({'dummy://foo': source});
|
|
parser.start('dummy://foo', fakeNetEngine, filterPeriod, fail)
|
|
.then(function(manifest) {
|
|
var stream = manifest.periods[0].streamSets[0].streams[0];
|
|
expect(stream.presentationTimeOffset).toBe(2);
|
|
})
|
|
.catch(fail)
|
|
.then(done);
|
|
});
|
|
|
|
it('generates a correct index for non-segmented text', function(done) {
|
|
var source = [
|
|
'<MPD mediaPresentationDuration="PT30S">',
|
|
' <Period>',
|
|
' <AdaptationSet mimeType="text/vtt" lang="de">',
|
|
' <Representation>',
|
|
' <BaseURL>http://example.com/de.vtt</BaseURL>',
|
|
' </Representation>',
|
|
' </AdaptationSet>',
|
|
' </Period>',
|
|
'</MPD>'
|
|
].join('\n');
|
|
|
|
fakeNetEngine.setResponseMapAsText({'dummy://foo': source});
|
|
|
|
var stream;
|
|
parser.start('dummy://foo', fakeNetEngine, filterPeriod, fail)
|
|
.then(function(manifest) {
|
|
stream = manifest.periods[0].streamSets[0].streams[0];
|
|
return stream.createSegmentIndex();
|
|
}).then(function() {
|
|
expect(stream.initSegmentReference).toBe(null);
|
|
expect(stream.findSegmentPosition(0)).toBe(1);
|
|
expect(stream.getSegmentReference(1)).toEqual(
|
|
jasmine.objectContaining({
|
|
startTime: 0,
|
|
endTime: 30,
|
|
uris: ['http://example.com/de.vtt'],
|
|
startByte: 0,
|
|
endByte: null
|
|
}));
|
|
}).catch(fail).then(done);
|
|
});
|
|
|
|
it('correctly parses UTF-8', function(done) {
|
|
var source = [
|
|
'<MPD>',
|
|
' <Period duration="PT30M">',
|
|
' <AdaptationSet mimeType="video/mp4" lang="\u2603">',
|
|
' <Representation bandwidth="500">',
|
|
' <BaseURL>http://example.com</BaseURL>',
|
|
' <SegmentTemplate media="2.mp4" duration="1"',
|
|
' initialization="\u0227.mp4" />',
|
|
' </Representation>',
|
|
' </AdaptationSet>',
|
|
' </Period>',
|
|
'</MPD>'
|
|
].join('\n');
|
|
|
|
fakeNetEngine.setResponseMapAsText({'dummy://foo': source});
|
|
|
|
parser.start('dummy://foo', fakeNetEngine, filterPeriod, fail)
|
|
.then(function(manifest) {
|
|
var streamSet = manifest.periods[0].streamSets[0];
|
|
var stream = streamSet.streams[0];
|
|
expect(stream.initSegmentReference.uris[0])
|
|
.toBe('http://example.com/%C8%A7.mp4');
|
|
expect(streamSet.language).toBe('\u2603');
|
|
}).catch(fail).then(done);
|
|
});
|
|
|
|
describe('supports UTCTiming', function() {
|
|
var originalNow;
|
|
|
|
beforeAll(function() {
|
|
originalNow = Date.now;
|
|
Date.now = function() { return 10 * 1000; };
|
|
});
|
|
|
|
afterAll(function() {
|
|
Date.now = originalNow;
|
|
});
|
|
|
|
/**
|
|
* @param {!Array.<string>} lines
|
|
* @return {string}
|
|
*/
|
|
function makeManifest(lines) {
|
|
var template = [
|
|
'<MPD type="dynamic"',
|
|
' availabilityStartTime="1970-01-01T00:00:00Z"',
|
|
' maxSegmentDuration="PT5S"',
|
|
' suggestedPresentationDelay="PT0S">',
|
|
' %s',
|
|
' <Period duration="PT30M">',
|
|
' <AdaptationSet mimeType="video/mp4">',
|
|
' <Representation bandwidth="500">',
|
|
' <BaseURL>http://example.com</BaseURL>',
|
|
' <SegmentTemplate media="2.mp4" duration="1" />',
|
|
' </Representation>',
|
|
' </AdaptationSet>',
|
|
' </Period>',
|
|
'</MPD>'
|
|
].join('\n');
|
|
return sprintf(template, lines.join('\n'));
|
|
}
|
|
|
|
/**
|
|
* @param {function()} done
|
|
* @param {number} expectedTime
|
|
*/
|
|
function runTest(done, expectedTime) {
|
|
parser.start('http://foo.bar/manifest', fakeNetEngine, filterPeriod, fail)
|
|
.then(function(manifest) {
|
|
expect(manifest.presentationTimeline).toBeTruthy();
|
|
expect(manifest.presentationTimeline.getSegmentAvailabilityEnd())
|
|
.toBe(expectedTime);
|
|
})
|
|
.catch(fail)
|
|
.then(done);
|
|
}
|
|
|
|
it('with direct', function(done) {
|
|
var source = makeManifest([
|
|
'<UTCTiming schemeIdUri="urn:mpeg:dash:utc:direct:2014"',
|
|
' value="1970-01-01T00:00:30Z" />'
|
|
]);
|
|
|
|
fakeNetEngine.setResponseMapAsText({'http://foo.bar/manifest': source});
|
|
runTest(done, 25);
|
|
});
|
|
|
|
it('does not produce errors', function(done) {
|
|
var source = makeManifest([
|
|
'<UTCTiming schemeIdUri="unknown scheme" value="foobar" />'
|
|
]);
|
|
|
|
fakeNetEngine.setResponseMapAsText({'http://foo.bar/manifest': source});
|
|
runTest(done, 5);
|
|
});
|
|
|
|
it('tries multiple sources', function(done) {
|
|
var source = makeManifest([
|
|
'<UTCTiming schemeIdUri="unknown scheme" value="foobar" />',
|
|
'<UTCTiming schemeIdUri="urn:mpeg:dash:utc:direct:2014"',
|
|
' value="1970-01-01T00:00:55Z" />'
|
|
]);
|
|
|
|
fakeNetEngine.setResponseMapAsText({'http://foo.bar/manifest': source});
|
|
runTest(done, 50);
|
|
});
|
|
|
|
it('with HEAD', function(done) {
|
|
var source = makeManifest([
|
|
'<UTCTiming schemeIdUri="urn:mpeg:dash:utc:http-head:2014"',
|
|
' value="http://foo.bar/date" />'
|
|
]);
|
|
|
|
fakeNetEngine.request.and.callFake(function(type, request) {
|
|
if (request.uris[0] == 'http://foo.bar/manifest') {
|
|
var data = shaka.util.StringUtils.toUTF8(source);
|
|
return Promise.resolve({data: data, headers: {}, uri: ''});
|
|
} else {
|
|
expect(request.uris[0]).toBe('http://foo.bar/date');
|
|
return Promise.resolve({
|
|
data: new ArrayBuffer(0),
|
|
headers: {'date': '1970-01-01T00:00:40Z'},
|
|
uri: ''
|
|
});
|
|
}
|
|
});
|
|
runTest(done, 35);
|
|
});
|
|
|
|
it('with xsdate', function(done) {
|
|
var source = makeManifest([
|
|
'<UTCTiming schemeIdUri="urn:mpeg:dash:utc:http-xsdate:2014"',
|
|
' value="http://foo.bar/date" />'
|
|
]);
|
|
|
|
fakeNetEngine.setResponseMapAsText({
|
|
'http://foo.bar/manifest': source,
|
|
'http://foo.bar/date': '1970-01-01T00:00:50Z'
|
|
});
|
|
runTest(done, 45);
|
|
});
|
|
});
|
|
|
|
describe('fails for', function() {
|
|
it('invalid XML', function(done) {
|
|
var source = '<not XML';
|
|
var error = new shaka.util.Error(
|
|
shaka.util.Error.Category.MANIFEST,
|
|
shaka.util.Error.Code.DASH_INVALID_XML);
|
|
Dash.testFails(done, source, error);
|
|
});
|
|
|
|
it('failed network requests', function(done) {
|
|
var expectedError = new shaka.util.Error(
|
|
shaka.util.Error.Category.NETWORK,
|
|
shaka.util.Error.Code.BAD_HTTP_STATUS);
|
|
|
|
fakeNetEngine.request.and.returnValue(Promise.reject(expectedError));
|
|
parser.start('', fakeNetEngine, filterPeriod, fail)
|
|
.then(fail)
|
|
.catch(function(error) { expect(error).toEqual(expectedError); })
|
|
.then(done);
|
|
});
|
|
|
|
it('missing MPD element', function(done) {
|
|
var source = '<XML></XML>';
|
|
var error = new shaka.util.Error(
|
|
shaka.util.Error.Category.MANIFEST,
|
|
shaka.util.Error.Code.DASH_INVALID_XML);
|
|
Dash.testFails(done, source, error);
|
|
});
|
|
|
|
it('empty Representation', function(done) {
|
|
var source = [
|
|
'<MPD minBufferTime="PT75S">',
|
|
' <Period id="1" duration="PT30S">',
|
|
' <AdaptationSet mimeType="video/mp4" lang="en" group="1">',
|
|
' <Representation bandwidth="100" />',
|
|
' </AdaptationSet>',
|
|
' </Period>',
|
|
'</MPD>'
|
|
].join('\n');
|
|
var error = new shaka.util.Error(
|
|
shaka.util.Error.Category.MANIFEST,
|
|
shaka.util.Error.Code.DASH_NO_SEGMENT_INFO);
|
|
Dash.testFails(done, source, error);
|
|
});
|
|
|
|
it('empty AdaptationSet', function(done) {
|
|
var source = [
|
|
'<MPD minBufferTime="PT75S">',
|
|
' <Period id="1" duration="PT30S">',
|
|
' <AdaptationSet mimeType="video/mp4" lang="en" group="1" />',
|
|
' </Period>',
|
|
'</MPD>'
|
|
].join('\n');
|
|
var error = new shaka.util.Error(
|
|
shaka.util.Error.Category.MANIFEST,
|
|
shaka.util.Error.Code.DASH_EMPTY_ADAPTATION_SET);
|
|
Dash.testFails(done, source, error);
|
|
});
|
|
|
|
it('empty Period', function(done) {
|
|
var source = [
|
|
'<MPD minBufferTime="PT75S">',
|
|
' <Period id="1" duration="PT30S" />',
|
|
'</MPD>'
|
|
].join('\n');
|
|
var error = new shaka.util.Error(
|
|
shaka.util.Error.Category.MANIFEST,
|
|
shaka.util.Error.Code.DASH_EMPTY_PERIOD);
|
|
Dash.testFails(done, source, error);
|
|
});
|
|
});
|
|
});
|