mirror of
https://github.com/shaka-project/shaka-player.git
synced 2026-06-23 17:27:16 +03:00
f346ece22c
* Supports live streams of a fixed length. * Live streams that stop now correctly end the video. * Only uses local MPD when @availabilityStartTime is in the future. * Added configuration option liveStreamEndTimeout. A live stream is considered "ended" when the play-head moves past the last segment for liveStreamEndTimeout amount of time. This allows the MPD to be updated with new segments. Closes #139 Closes #140 Closes #145 Issue #172 Change-Id: I0675203931f35ca3e0dee60a87c54ba74cbdbaea
443 lines
14 KiB
JavaScript
443 lines
14 KiB
JavaScript
/**
|
|
* @license
|
|
* Copyright 2015 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.
|
|
*/
|
|
|
|
goog.require('shaka.player.Defaults');
|
|
goog.require('shaka.player.Restrictions');
|
|
goog.require('shaka.util.EventManager');
|
|
|
|
describe('Configuration', function() {
|
|
var video;
|
|
var player;
|
|
var eventManager;
|
|
var estimator;
|
|
|
|
beforeAll(integration.setUp);
|
|
afterAll(integration.tearDown);
|
|
|
|
beforeEach(function() {
|
|
// Create a video tag. This will be visible so that long tests do not
|
|
// create the illusion of the test-runner being hung.
|
|
video = createVideo();
|
|
document.body.appendChild(video);
|
|
|
|
player = createPlayer(video);
|
|
eventManager = new shaka.util.EventManager();
|
|
});
|
|
|
|
afterEach(function(done) {
|
|
eventManager.destroy();
|
|
eventManager = null;
|
|
|
|
player.destroy().then(function() {
|
|
player = null;
|
|
done();
|
|
});
|
|
|
|
// Remove the video tag from the DOM.
|
|
document.body.removeChild(video);
|
|
});
|
|
|
|
describe('configuring the preferredLanguage', function() {
|
|
it('changes the default tracks', function(done) {
|
|
var originalAudioId;
|
|
var originalTextId;
|
|
|
|
player.load(newSource(manifests.languagesManifest)).then(function() {
|
|
video.play();
|
|
return waitForMovement(video, eventManager);
|
|
}).then(function() {
|
|
var activeAudioTrack = getActiveAudioTrack(player);
|
|
expect(activeAudioTrack.lang).toBe('en');
|
|
originalAudioId = activeAudioTrack.id;
|
|
|
|
var activeTextTrack = getActiveTextTrack(player);
|
|
expect(activeTextTrack.lang).toBe('en');
|
|
originalTextId = activeTextTrack.id;
|
|
|
|
player.configure({'preferredLanguage': 'fr'});
|
|
return player.load(newSource(manifests.languagesManifest));
|
|
}).then(function() {
|
|
video.play();
|
|
return waitForMovement(video, eventManager);
|
|
}).then(function() {
|
|
var activeAudioTrack = getActiveAudioTrack(player);
|
|
expect(activeAudioTrack.lang).toBe('fr');
|
|
expect(activeAudioTrack.id).not.toBe(originalAudioId);
|
|
|
|
var activeTextTrack = getActiveTextTrack(player);
|
|
expect(activeTextTrack.lang).toBe('fr');
|
|
expect(activeTextTrack.id).not.toBe(originalTextId);
|
|
|
|
done();
|
|
}).catch(function(error) {
|
|
fail(error);
|
|
done();
|
|
});
|
|
});
|
|
|
|
it('enables text tracks when no matching audio is found', function(done) {
|
|
player.configure({'preferredLanguage': 'el'});
|
|
player.load(newSource(manifests.languagesManifest)).then(function() {
|
|
video.play();
|
|
return waitForMovement(video, eventManager);
|
|
}).then(function() {
|
|
var activeAudioTrack = getActiveAudioTrack(player);
|
|
expect(activeAudioTrack.lang).toBe('en');
|
|
|
|
var activeTextTrack = getActiveTextTrack(player);
|
|
expect(activeTextTrack.lang).toBe('el');
|
|
expect(activeTextTrack.enabled).toBe(true);
|
|
done();
|
|
}).catch(function(error) {
|
|
fail(error);
|
|
done();
|
|
});
|
|
});
|
|
|
|
it('disables text tracks when matching audio is found', function(done) {
|
|
player.configure({'preferredLanguage': 'fr'});
|
|
player.load(newSource(manifests.languagesManifest)).then(function() {
|
|
video.play();
|
|
return waitForMovement(video, eventManager);
|
|
}).then(function() {
|
|
var activeAudioTrack = getActiveAudioTrack(player);
|
|
expect(activeAudioTrack.lang).toBe('fr');
|
|
|
|
var activeTextTrack = getActiveTextTrack(player);
|
|
expect(activeTextTrack.lang).toBe('fr');
|
|
expect(activeTextTrack.enabled).toBe(false);
|
|
done();
|
|
}).catch(function(error) {
|
|
fail(error);
|
|
done();
|
|
});
|
|
});
|
|
|
|
it('respects the \'main\' attribute', function(done) {
|
|
// There are no Thai audio AdaptationSets in the MPD, but the English
|
|
// audio AdaptationSet is marked as main, so even though it is not the
|
|
// first AdaptationSet, it should be preferred.
|
|
player.configure({'preferredLanguage': 'th'});
|
|
|
|
player.load(newSource(manifests.languagesManifest)).then(function() {
|
|
video.play();
|
|
return waitForMovement(video, eventManager);
|
|
}).then(function() {
|
|
var activeAudioTrack = getActiveAudioTrack(player);
|
|
expect(activeAudioTrack.lang).toBe('en');
|
|
done();
|
|
}).catch(function(error) {
|
|
fail(error);
|
|
done();
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('configuring restrictions', function() {
|
|
it('ignores video tracks above the maximum height', function(done) {
|
|
player.load(newSource(manifests.encryptedManifest)).then(function() {
|
|
var hdVideoTrack = getVideoTrackByHeight(player, 720);
|
|
var sdVideoTrack = getVideoTrackByHeight(player, 480);
|
|
expect(hdVideoTrack).not.toBe(null);
|
|
expect(sdVideoTrack).not.toBe(null);
|
|
|
|
var restrictions = player.getConfiguration()['restrictions'];
|
|
restrictions.maxHeight = 480;
|
|
player.configure({'restrictions': restrictions});
|
|
|
|
hdVideoTrack = getVideoTrackByHeight(player, 720);
|
|
sdVideoTrack = getVideoTrackByHeight(player, 480);
|
|
expect(hdVideoTrack).toBe(null);
|
|
expect(sdVideoTrack).not.toBe(null);
|
|
done();
|
|
}).catch(function(error) {
|
|
fail(error);
|
|
done();
|
|
});
|
|
});
|
|
|
|
it('ignores video tracks above the maximum width', function(done) {
|
|
player.load(newSource(manifests.encryptedManifest)).then(function() {
|
|
var hdVideoTrack = getVideoTrackByHeight(player, 720);
|
|
var sdVideoTrack = getVideoTrackByHeight(player, 480);
|
|
expect(hdVideoTrack).not.toBe(null);
|
|
expect(sdVideoTrack).not.toBe(null);
|
|
|
|
var restrictions = player.getConfiguration()['restrictions'];
|
|
restrictions.maxWidth = 854;
|
|
player.configure({'restrictions': restrictions});
|
|
|
|
hdVideoTrack = getVideoTrackByHeight(player, 720);
|
|
sdVideoTrack = getVideoTrackByHeight(player, 480);
|
|
expect(hdVideoTrack).toBe(null);
|
|
expect(sdVideoTrack).not.toBe(null);
|
|
done();
|
|
}).catch(function(error) {
|
|
fail(error);
|
|
done();
|
|
});
|
|
});
|
|
|
|
it('takes effect before the source is loaded', function(done) {
|
|
var restrictions = player.getConfiguration()['restrictions'];
|
|
restrictions.maxHeight = 480;
|
|
player.configure({'restrictions': restrictions});
|
|
|
|
player.load(newSource(manifests.encryptedManifest)).then(function() {
|
|
var hdVideoTrack = getVideoTrackByHeight(player, 720);
|
|
var sdVideoTrack = getVideoTrackByHeight(player, 480);
|
|
expect(hdVideoTrack).toBe(null);
|
|
expect(sdVideoTrack).not.toBe(null);
|
|
|
|
var restrictions = player.getConfiguration()['restrictions'];
|
|
restrictions.maxHeight = null;
|
|
player.configure({'restrictions': restrictions});
|
|
|
|
hdVideoTrack = getVideoTrackByHeight(player, 720);
|
|
sdVideoTrack = getVideoTrackByHeight(player, 480);
|
|
expect(hdVideoTrack).not.toBe(null);
|
|
expect(sdVideoTrack).not.toBe(null);
|
|
done();
|
|
}).catch(function(error) {
|
|
fail(error);
|
|
done();
|
|
});
|
|
});
|
|
|
|
it('fires error if all tracks restricted while playing', function(done) {
|
|
player.removeEventListener('error', convertErrorToTestFailure, false);
|
|
var onError = jasmine.createSpy('onError');
|
|
player.addEventListener('error', onError, false);
|
|
|
|
player.load(newSource(manifests.plainManifest)).then(function() {
|
|
waitForMovement(video, eventManager);
|
|
}).then(function() {
|
|
var restrictions = player.getConfiguration()['restrictions'];
|
|
restrictions.maxBandwidth = 10000;
|
|
player.configure({'restrictions': restrictions});
|
|
|
|
expect(onError.calls.any()).toBe(true);
|
|
expect(player.getVideoTracks().length).toBe(0);
|
|
|
|
done();
|
|
}).catch(function(error) {
|
|
fail(error);
|
|
done();
|
|
});
|
|
});
|
|
|
|
it('fires error if all tracks restricted before playing', function(done) {
|
|
player.removeEventListener('error', convertErrorToTestFailure, false);
|
|
var onError = jasmine.createSpy('onError');
|
|
player.addEventListener('error', onError, false);
|
|
|
|
var restrictions = player.getConfiguration()['restrictions'];
|
|
restrictions.maxBandwidth = 10000;
|
|
player.configure({'restrictions': restrictions});
|
|
|
|
player.load(newSource(manifests.encryptedManifest)).then(function() {
|
|
fail();
|
|
}).catch(function(error) {
|
|
expect(onError.calls.any()).toBe(true);
|
|
done();
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('configure and getConfiguration', function() {
|
|
it('rejects an invalid enableAdaptation', function() {
|
|
var exception;
|
|
try {
|
|
player.configure({'enableAdaptation': 2});
|
|
fail();
|
|
} catch (e) {
|
|
exception = e;
|
|
}
|
|
expect(exception instanceof TypeError).toBe(true);
|
|
});
|
|
|
|
it('gets/sets stream buffer size', function() {
|
|
var original = player.getConfiguration()['streamBufferSize'];
|
|
expect(original).not.toBe(5);
|
|
expect(original).toBe(shaka.player.Defaults.STREAM_BUFFER_SIZE);
|
|
|
|
expect(player.getConfiguration()['streamBufferSize']).toBe(original);
|
|
|
|
player.configure({'streamBufferSize': 5});
|
|
expect(player.getConfiguration()['streamBufferSize']).toBe(5);
|
|
|
|
player.configure({'streamBufferSize': original});
|
|
expect(player.getConfiguration()['streamBufferSize']).toBe(original);
|
|
});
|
|
|
|
|
|
it('rejects an invalid streamBufferSize', function() {
|
|
var exception;
|
|
|
|
try {
|
|
player.configure({'streamBufferSize': 'three seconds'});
|
|
fail();
|
|
} catch (e) {
|
|
exception = e;
|
|
}
|
|
expect(exception instanceof TypeError).toBe(true);
|
|
|
|
try {
|
|
player.configure({'streamBufferSize': -1});
|
|
fail();
|
|
} catch (e) {
|
|
exception = e;
|
|
}
|
|
expect(exception instanceof RangeError).toBe(true);
|
|
});
|
|
|
|
it('gets/sets LicenseRequest timeout', function() {
|
|
var original = player.getConfiguration()['licenseRequestTimeout'];
|
|
expect(original).not.toBe(5);
|
|
expect(original).toBe(shaka.player.Defaults.LICENSE_REQUEST_TIMEOUT);
|
|
|
|
expect(player.getConfiguration()['licenseRequestTimeout']).toBe(original);
|
|
|
|
player.configure({'licenseRequestTimeout': 5});
|
|
expect(player.getConfiguration()['licenseRequestTimeout']).toBe(5);
|
|
|
|
player.configure({'licenseRequestTimeout': original});
|
|
expect(player.getConfiguration()['licenseRequestTimeout']).toBe(original);
|
|
});
|
|
|
|
it('rejects an invalid LicenseRequest timeout', function() {
|
|
var exception;
|
|
|
|
try {
|
|
player.configure({'licenseRequestTimeout': 'five seconds'});
|
|
fail();
|
|
} catch (e) {
|
|
exception = e;
|
|
}
|
|
expect(exception instanceof TypeError).toBe(true);
|
|
|
|
try {
|
|
player.configure({'licenseRequestTimeout': NaN});
|
|
fail();
|
|
} catch (e) {
|
|
exception = e;
|
|
}
|
|
expect(exception instanceof RangeError).toBe(true);
|
|
});
|
|
|
|
it('gets/sets MpdRequest timeout', function() {
|
|
var original = player.getConfiguration()['mpdRequestTimeout'];
|
|
expect(original).not.toBe(5);
|
|
expect(original).toBe(shaka.player.Defaults.MPD_REQUEST_TIMEOUT);
|
|
|
|
expect(player.getConfiguration()['mpdRequestTimeout']).toBe(original);
|
|
|
|
player.configure({'mpdRequestTimeout': 5});
|
|
expect(player.getConfiguration()['mpdRequestTimeout']).toBe(5);
|
|
|
|
player.configure({'mpdRequestTimeout': original});
|
|
expect(player.getConfiguration()['mpdRequestTimeout']).toBe(original);
|
|
});
|
|
|
|
it('rejects an invalid MpdRequest timeout', function() {
|
|
var exception;
|
|
|
|
try {
|
|
player.configure({'mpdRequestTimeout': 'seven seconds'});
|
|
fail();
|
|
} catch (e) {
|
|
exception = e;
|
|
}
|
|
expect(exception instanceof TypeError).toBe(true);
|
|
|
|
try {
|
|
player.configure({'mpdRequestTimeout': Number.NEGATIVE_INFINITY});
|
|
fail();
|
|
} catch (e) {
|
|
exception = e;
|
|
}
|
|
expect(exception instanceof RangeError).toBe(true);
|
|
});
|
|
|
|
it('gets/sets SegmentRequest timeout', function() {
|
|
var original = player.getConfiguration()['segmentRequestTimeout'];
|
|
expect(original).not.toBe(5);
|
|
expect(original).toBe(shaka.player.Defaults.SEGMENT_REQUEST_TIMEOUT);
|
|
|
|
expect(player.getConfiguration()['segmentRequestTimeout']).toBe(original);
|
|
|
|
player.configure({'segmentRequestTimeout': 5});
|
|
expect(player.getConfiguration()['segmentRequestTimeout']).toBe(5);
|
|
|
|
player.configure({'segmentRequestTimeout': original});
|
|
expect(player.getConfiguration()['segmentRequestTimeout']).toBe(original);
|
|
});
|
|
|
|
it('rejects an invalid SegmentRequest timeout', function() {
|
|
var exception;
|
|
|
|
try {
|
|
player.configure({'segmentRequestTimeout': 'eleven seconds'});
|
|
fail();
|
|
} catch (e) {
|
|
exception = e;
|
|
}
|
|
expect(exception instanceof TypeError).toBe(true);
|
|
|
|
try {
|
|
player.configure({'segmentRequestTimeout': Number.POSITIVE_INFINITY});
|
|
fail();
|
|
} catch (e) {
|
|
exception = e;
|
|
}
|
|
expect(exception instanceof RangeError).toBe(true);
|
|
});
|
|
|
|
it('rejects an invalid preferredLanguage', function() {
|
|
var exception;
|
|
try {
|
|
player.configure({'preferredLanguage': 13});
|
|
fail();
|
|
} catch (e) {
|
|
exception = e;
|
|
}
|
|
expect(exception instanceof TypeError).toBe(true);
|
|
});
|
|
|
|
it('gets/sets multiple options at once', function() {
|
|
var restrictions = new shaka.player.Restrictions();
|
|
restrictions.maxWidth = 1280;
|
|
var originalConfig = player.getConfiguration();
|
|
var config = {
|
|
'enableAdaptation': true,
|
|
'streamBufferSize': 17,
|
|
'liveStreamEndTimeout': 20,
|
|
'licenseRequestTimeout': 19,
|
|
'mpdRequestTimeout': 23,
|
|
'segmentRequestTimeout': 29,
|
|
'preferredLanguage': 'fr',
|
|
'restrictions': restrictions
|
|
};
|
|
player.configure(config);
|
|
expect(JSON.stringify(player.getConfiguration()))
|
|
.toBe(JSON.stringify(config));
|
|
player.configure(originalConfig);
|
|
});
|
|
});
|
|
});
|
|
|