Socket
Socket
Sign inDemoInstall

bigscreen-player

Package Overview
Dependencies
Maintainers
3
Versions
190
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

bigscreen-player - npm Package Compare versions

Comparing version 2.10.0 to 2.11.0

script-test/mediasourcestest.js

2

package.json
{
"name": "bigscreen-player",
"version": "2.10.0",
"version": "2.11.0",
"description": "Simplified media playback for bigscreen devices.",

@@ -5,0 +5,0 @@ "main": "script/bigscreenplayer.js",

@@ -19,14 +19,10 @@ require(

var liveSupport;
var forceManifestLoadError;
var successCallback = jasmine.createSpy('successCallback');
var errorCallback = jasmine.createSpy('errorCallback');
var successCallback;
var errorCallback;
var noCallbacks = false;
var mockEventHook;
var mockPlayerComponentInstance = jasmine.createSpyObj('playerComponentMock', [
'play', 'pause', 'isEnded', 'isPaused', 'setCurrentTime', 'getCurrentTime', 'getDuration', 'getSeekableRange',
'getPlayerElement', 'isSubtitlesAvailable', 'isSubtitlesEnabled', 'setSubtitlesEnabled', 'tearDown',
'getWindowStartTime', 'getWindowEndTime']);
var mockPlayerComponentInstance;
var mockPlayerComponent = function (playbackElement, bigscreenPlayerData, windowType, enableSubtitles, callback, device) {
var mockPlayerComponent = function (playbackElement, bigscreenPlayerData, mediaSources, windowType, enableSubtitles, callback, device) {
mockEventHook = callback;

@@ -42,3 +38,2 @@ return mockPlayerComponentInstance;

manifestData = {
transferFormat: options && options.transferFormat || 'dash',
time: options && options.time || {

@@ -50,15 +45,8 @@ windowStartTime: 724000,

};
mockPlayerComponentInstance.getWindowStartTime.and.returnValue(manifestData.time.windowStartTime);
mockPlayerComponentInstance.getWindowEndTime.and.returnValue(manifestData.time.windowStartTime);
}
var manifestLoaderMock = {
load: function (urls, serverDate, callbacks) {
if (forceManifestLoadError) {
callbacks.onError();
} else {
callbacks.onSuccess(manifestData);
}
}
};
var mediaSourcesMock;
var mediaSourcesCallbackSuccessSpy;
var mediaSourcesCallbackErrorSpy;
var forceMediaSourcesConstructionFailure = false;

@@ -90,11 +78,6 @@ function initialiseBigscreenPlayer (options) {

if (options.windowStartTime && options.windowEndTime) {
bigscreenPlayerData.time = {
manifestData.time = {
windowStartTime: options.windowStartTime,
windowEndTime: options.windowEndTime
};
mockPlayerComponentInstance.getWindowStartTime.and.returnValue(options.windowStartTime);
mockPlayerComponentInstance.getWindowEndTime.and.returnValue(options.windowEndTime);
} else {
mockPlayerComponentInstance.getWindowStartTime.and.returnValue(manifestData.time.windowStartTime);
mockPlayerComponentInstance.getWindowEndTime.and.returnValue(manifestData.time.windowEndTime);
}

@@ -115,9 +98,32 @@

beforeEach(function (done) {
mediaSourcesMock = function () {
return {
init: function (urls, serverDate, windowType, liveSupport, callbacks) {
mediaSourcesCallbackSuccessSpy = spyOn(callbacks, 'onSuccess').and.callThrough();
mediaSourcesCallbackErrorSpy = spyOn(callbacks, 'onError').and.callThrough();
if (forceMediaSourcesConstructionFailure) {
callbacks.onError();
} else {
callbacks.onSuccess();
}
},
time: function () {
return manifestData.time;
}
};
};
mockPlayerComponentInstance = jasmine.createSpyObj('playerComponentMock', [
'play', 'pause', 'isEnded', 'isPaused', 'setCurrentTime', 'getCurrentTime', 'getDuration', 'getSeekableRange',
'getPlayerElement', 'isSubtitlesAvailable', 'isSubtitlesEnabled', 'setSubtitlesEnabled', 'tearDown',
'getWindowStartTime', 'getWindowEndTime']);
successCallback = jasmine.createSpy('successCallback');
errorCallback = jasmine.createSpy('errorCallback');
setupManifestData();
liveSupport = LiveSupport.SEEKABLE;
forceManifestLoadError = false;
noCallbacks = false;
injector.mock({
'bigscreenplayer/manifest/manifestloader': manifestLoaderMock,
'bigscreenplayer/mediasources': mediaSourcesMock,
'bigscreenplayer/playercomponent': mockPlayerComponent,

@@ -139,2 +145,6 @@ 'bigscreenplayer/plugins': Plugins

errorCallback.calls.reset();
forceMediaSourcesConstructionFailure = false;
mediaSourcesCallbackSuccessSpy && mediaSourcesCallbackSuccessSpy.calls && mediaSourcesCallbackSuccessSpy.calls.reset();
mediaSourcesCallbackErrorSpy && mediaSourcesCallbackErrorSpy.calls && mediaSourcesCallbackErrorSpy.calls.reset();
bigscreenPlayer.tearDown();

@@ -185,2 +195,3 @@ });

expect(mediaSourcesCallbackSuccessSpy).toHaveBeenCalledTimes(1);
expect(successCallback).toHaveBeenCalledWith();

@@ -191,6 +202,7 @@ expect(errorCallback).not.toHaveBeenCalled();

it('should call the supplied error callback if manifest fails to load', function () {
forceManifestLoadError = true;
forceMediaSourcesConstructionFailure = true;
initialiseBigscreenPlayer({windowType: WindowTypes.SLIDING});
expect(errorCallback).toHaveBeenCalledWith({error: 'manifest'});
expect(mediaSourcesCallbackErrorSpy).toHaveBeenCalledTimes(1);
expect(errorCallback).toHaveBeenCalledTimes(1);
expect(successCallback).not.toHaveBeenCalled();

@@ -206,5 +218,5 @@ });

it('should not attempt to call onSuccess callback if one is not provided', function () {
it('should not attempt to call onError callback if one is not provided', function () {
noCallbacks = true;
forceManifestLoadError = true;
initialiseBigscreenPlayer({windowType: WindowTypes.SLIDING});

@@ -661,3 +673,3 @@

expect(mockPlayerComponentInstance.isSubtitlesEnabled).toHaveBeenCalled();
expect(mockPlayerComponentInstance.isSubtitlesEnabled).toHaveBeenCalledWith();
});

@@ -672,3 +684,3 @@ });

expect(mockPlayerComponentInstance.isSubtitlesAvailable).toHaveBeenCalled();
expect(mockPlayerComponentInstance.isSubtitlesAvailable).toHaveBeenCalledWith();
});

@@ -678,3 +690,3 @@ });

describe('canSeek', function () {
it('VOD should return true', function () {
it('should return true when in VOD playback', function () {
initialiseBigscreenPlayer();

@@ -745,3 +757,3 @@

describe('live', function () {
describe('LIVE', function () {
it('should return true when it can pause', function () {

@@ -757,3 +769,3 @@ liveSupport = LiveSupport.RESTARTABLE;

it('should return false when window length less than four minutes', function () {
it('should be false when window length less than four minutes', function () {
setupManifestData({

@@ -790,2 +802,9 @@ transferFormat: TransferFormats.DASH,

it('converts video time to epoch time when windowStartTime is supplied', function () {
setupManifestData({
time: {
windowStartTime: 4200,
windowEndTime: 150000000
}
});
initialiseBigscreenPlayer({

@@ -795,5 +814,2 @@ windowType: WindowTypes.SLIDING

mockPlayerComponentInstance.getWindowStartTime.and.returnValue(4200);
mockPlayerComponentInstance.getWindowEndTime.and.returnValue(150000000);
expect(bigscreenPlayer.convertVideoTimeSecondsToEpochMs(1000)).toBe(4200 + 1000000);

@@ -803,7 +819,11 @@ });

it('does not convert video time to epoch time when windowStartTime is not supplied', function () {
setupManifestData({
time: {
windowStartTime: undefined,
windowEndTime: undefined
}
});
initialiseBigscreenPlayer();
mockPlayerComponentInstance.getWindowStartTime.and.returnValue(undefined);
mockPlayerComponentInstance.getWindowEndTime.and.returnValue(undefined);
expect(bigscreenPlayer.convertVideoTimeSecondsToEpochMs(1000)).toBeUndefined();

@@ -815,2 +835,11 @@ });

it('converts epoch time to video time when windowStartTime is available', function () {
// windowStartTime - 16 January 2019 12:00:00
// windowEndTime - 16 January 2019 14:00:00
setupManifestData({
time: {
windowStartTime: 1547640000000,
windowEndTime: 1547647200000
}
});
initialiseBigscreenPlayer({

@@ -820,7 +849,2 @@ windowType: WindowTypes.SLIDING

// windowStartTime - 16 January 2019 12:00:00
// windowEndTime - 16 January 2019 14:00:00
mockPlayerComponentInstance.getWindowStartTime.and.returnValue(1547640000000);
mockPlayerComponentInstance.getWindowEndTime.and.returnValue(1547647200000);
// Time to convert - 16 January 2019 13:00:00 - one hour (3600 seconds)

@@ -831,7 +855,11 @@ expect(bigscreenPlayer.convertEpochMsToVideoTimeSeconds(1547643600000)).toBe(3600);

it('does not convert epoch time to video time when windowStartTime is not available', function () {
setupManifestData({
time: {
windowStartTime: undefined,
windowEndTime: undefined
}
});
initialiseBigscreenPlayer();
mockPlayerComponentInstance.getWindowStartTime.and.returnValue(undefined);
mockPlayerComponentInstance.getWindowEndTime.and.returnValue(undefined);
expect(bigscreenPlayer.convertEpochMsToVideoTimeSeconds(1547643600000)).toBeUndefined();

@@ -838,0 +866,0 @@ });

@@ -47,3 +47,3 @@ require(

expect(mockCaptionsSpy.start).toHaveBeenCalled();
expect(mockCaptionsSpy.start).toHaveBeenCalledWith();
});

@@ -55,3 +55,3 @@

expect(mockCaptionsSpy.start).not.toHaveBeenCalled();
expect(mockCaptionsSpy.start).not.toHaveBeenCalledWith();
});

@@ -62,3 +62,3 @@

expect(mockCaptionsSpy.start).toHaveBeenCalled();
expect(mockCaptionsSpy.start).toHaveBeenCalledWith();
});

@@ -69,3 +69,3 @@

expect(mockCaptionsSpy.start).not.toHaveBeenCalled();
expect(mockCaptionsSpy.start).not.toHaveBeenCalledWith();
});

@@ -79,3 +79,3 @@ });

expect(mockCaptionsSpy.stop).toHaveBeenCalled();
expect(mockCaptionsSpy.stop).toHaveBeenCalledWith();
});

@@ -87,3 +87,3 @@

expect(mockCaptionsSpy.stop).not.toHaveBeenCalled();
expect(mockCaptionsSpy.stop).not.toHaveBeenCalledWith();
});

@@ -90,0 +90,0 @@ });

@@ -27,2 +27,3 @@ require(

var chronicle = Chronicle.retrieve();
expect(chronicle.pop()).toEqual(expectedObject);

@@ -42,2 +43,3 @@ });

var chronicle = Chronicle.retrieve();
expect(chronicle.pop()).toEqual(expectedObject);

@@ -58,2 +60,3 @@ });

var chronicle = Chronicle.retrieve();
expect(chronicle.pop()).toEqual(expectedObject);

@@ -74,2 +77,3 @@ });

var chronicle = Chronicle.retrieve();
expect(chronicle.pop()).toEqual(expectedObject);

@@ -87,2 +91,3 @@ });

var chronicle = Chronicle.retrieve();
expect(chronicle.pop()).toEqual(expectedObject);

@@ -99,2 +104,3 @@ });

var chronicle = Chronicle.retrieve();
expect(chronicle.pop()).toEqual(expectedObject);

@@ -112,2 +118,3 @@ });

var chronicle = Chronicle.retrieve();
expect(chronicle.length).toEqual(2);

@@ -128,2 +135,3 @@ expect(chronicle.pop()).toEqual(expectedObject);

var chronicle = Chronicle.retrieve();
expect(chronicle.length).toEqual(4);

@@ -153,2 +161,3 @@ expect(chronicle.pop()).toEqual(expectedObject);

var chronicle = Chronicle.retrieve();
expect(chronicle.length).toEqual(7);

@@ -168,2 +177,3 @@ expect(chronicle).toEqual(expectedArray);

var chronicle = Chronicle.retrieve();
expect(chronicle.length).toEqual(2);

@@ -183,2 +193,3 @@ expect(chronicle).toEqual(expectedArray);

var chronicle = Chronicle.retrieve();
expect(chronicle.length).toEqual(2);

@@ -185,0 +196,0 @@ expect(chronicle).toEqual(expectedArray);

@@ -29,2 +29,3 @@ require(

};
expect(viewMock.render).toHaveBeenCalledWith(expectedObject);

@@ -46,2 +47,3 @@ });

};
expect(viewMock.render).toHaveBeenCalledWith(expectedObject);

@@ -59,2 +61,3 @@ });

};
expect(viewMock.render).toHaveBeenCalledWith(expectedObject);

@@ -76,2 +79,3 @@ });

};
expect(viewMock.render).toHaveBeenCalledWith(expectedObject);

@@ -96,2 +100,3 @@ });

};
expect(viewMock.render).toHaveBeenCalledWith(expectedObject);

@@ -111,2 +116,3 @@ });

};
expect(viewMock.render).toHaveBeenCalledWith(expectedObject);

@@ -126,2 +132,3 @@ });

};
expect(viewMock.render).toHaveBeenCalledWith(expectedObject);

@@ -141,16 +148,3 @@ });

};
expect(viewMock.render).toHaveBeenCalledWith(expectedObject);
});
it('parses long time to formatted string representation', function () {
presenter.update([
{type: 'time', currentTime: 788.9999, timestamp: 1518018558259}
]);
var expectedObject = {
static: [
],
dynamic: [
'2018-02-07T15:49:18.259Z - Video time: 789.00'
]
};
expect(viewMock.render).toHaveBeenCalledWith(expectedObject);

@@ -170,2 +164,3 @@ });

};
expect(viewMock.render).toHaveBeenCalledWith(expectedObject);

@@ -185,2 +180,3 @@ });

};
expect(viewMock.render).toHaveBeenCalledWith(expectedObject);

@@ -204,2 +200,3 @@ });

};
expect(viewMock.render).toHaveBeenCalledWith(expectedObject);

@@ -239,2 +236,3 @@ });

};
expect(viewMock.render).toHaveBeenCalledWith(expectedObject);

@@ -241,0 +239,0 @@ });

@@ -12,8 +12,8 @@ require(

describe('Manifest Loader', function () {
var loadUrl = jasmine.createSpy('loadUrl');
var injector = new Squire();
var loadUrl;
var mockedLoader;
beforeEach(function (done) {
var injector = new Squire();
loadUrl = jasmine.createSpy('loadUrl');
injector.mock({

@@ -33,8 +33,7 @@ 'bigscreenplayer/utils/loadurl': loadUrl

describe('With HLS media', function () {
it('Picks the first HLS url', function () {
var hlsUrl = 'first.m3u8';
var urls = [{ url: 'something_else' }, { url: hlsUrl }, { url: 'next.m3u8' }];
mockedLoader.load(urls, undefined, {});
it('Retrieves a matched HLS url', function () {
var url = 'hlsurl.m3u8';
mockedLoader.load(url, undefined, {});
expect(loadUrl).toHaveBeenCalledWith(hlsUrl, jasmine.anything());
expect(loadUrl).toHaveBeenCalledWith(url, jasmine.anything());
});

@@ -44,8 +43,7 @@ });

describe('With Dash Media', function () {
it('Picks the first dash url', function () {
var dashUrl = 'first.mpd';
var urls = [{ url: 'something_else' }, { url: dashUrl }, { url: 'next.mpd' }];
mockedLoader.load(urls, undefined, {});
it('Retrieves a matched DASH url', function () {
var url = 'dashurl.mpd';
mockedLoader.load(url, undefined, {});
expect(loadUrl).toHaveBeenCalledWith(dashUrl, jasmine.anything());
expect(loadUrl).toHaveBeenCalledWith(url, jasmine.anything());
});

@@ -59,4 +57,4 @@ });

};
var urls = [{ url: 'bad_url' }];
mockedLoader.load(urls, undefined, callbackSpies);
var url = 'bad_url';
mockedLoader.load(url, undefined, callbackSpies);

@@ -97,3 +95,3 @@ expect(callbackSpies.onError).toHaveBeenCalledWith('Invalid media url');

server.respondWith('GET', 'http://foo.bar/test.mpd', [200, { 'Content-Type': 'application/dash+xml' }, dashResponse]);
ManifestLoader.load([{ url: 'http://foo.bar/test.mpd' }], undefined, callbackSpies);
ManifestLoader.load('http://foo.bar/test.mpd', undefined, callbackSpies);
server.respond();

@@ -111,3 +109,3 @@

server.respondWith('GET', 'http://foo.bar/test.mpd', [200, {}, '']);
ManifestLoader.load([{ url: 'http://foo.bar/test.mpd' }], undefined, callbackSpies);
ManifestLoader.load('http://foo.bar/test.mpd', undefined, callbackSpies);
server.respond();

@@ -120,3 +118,3 @@

server.respondWith('GET', 'http://foo.bar/test.mpd', [404, {}, '']);
ManifestLoader.load([{ url: 'http://foo.bar/test.mpd' }], undefined, callbackSpies);
ManifestLoader.load('http://foo.bar/test.mpd', undefined, callbackSpies);
server.respond();

@@ -132,3 +130,3 @@

server.respondWith('GET', 'http://foo.bar/live.m3u8', [200, { 'Content-Type': 'application/vnd.apple.mpegurl' }, hlsLiveResponse]);
ManifestLoader.load([{ url: 'http://foo.bar/test.m3u8' }], undefined, callbackSpies);
ManifestLoader.load('http://foo.bar/test.m3u8', undefined, callbackSpies);
server.respond();

@@ -147,3 +145,3 @@ server.respond(); // need to respond twice, once for each unique url (above)

server.respondWith('GET', 'http://foo.bar/test.m3u8', [404, { 'Content-Type': 'application/vnd.apple.mpegurl' }, '']);
ManifestLoader.load([{ url: 'http://foo.bar/test.m3u8' }], undefined, callbackSpies);
ManifestLoader.load('http://foo.bar/test.m3u8', undefined, callbackSpies);
server.respond();

@@ -156,3 +154,3 @@

server.respondWith('GET', 'http://foo.bar/test.m3u8', [200, { 'Content-Type': 'application/vnd.apple.mpegurl' }, hlsInvalidResponse]);
ManifestLoader.load([{ url: 'http://foo.bar/test.m3u8' }], undefined, callbackSpies);
ManifestLoader.load('http://foo.bar/test.m3u8', undefined, callbackSpies);
server.respond();

@@ -166,3 +164,3 @@

server.respondWith('GET', 'http://foo.bar/live.m3u8', [200, { 'Content-Type': 'application/vnd.apple.mpegurl' }, '']);
ManifestLoader.load([{ url: 'http://foo.bar/test.m3u8' }], undefined, callbackSpies);
ManifestLoader.load('http://foo.bar/test.m3u8', undefined, callbackSpies);
server.respond();

@@ -177,3 +175,3 @@ server.respond(); // need to respond twice, once for each unique url (above)

server.respondWith('GET', 'http://foo.bar/live.m3u8', [404, { 'Content-Type': 'application/vnd.apple.mpegurl' }, '']);
ManifestLoader.load([{ url: 'http://foo.bar/test.m3u8' }], undefined, callbackSpies);
ManifestLoader.load('http://foo.bar/test.m3u8', undefined, callbackSpies);
server.respond();

@@ -180,0 +178,0 @@ server.respond(); // need to respond twice, once for each unique url (above)

@@ -323,4 +323,4 @@ require(

var sources = [
{ cdn: 'cdn-a', url: 'https://cdn-a.com/' },
{ cdn: 'cdn-b', url: 'https://cdn-b.com/' }
'https://cdn-a.com/',
'https://cdn-b.com/'
];

@@ -337,4 +337,4 @@

BaseURL_asArray: [
{ __text: 'https://cdn-a.com/dash/', 'dvb:priority': 0, serviceLocation: 'cdn-a' },
{ __text: 'https://cdn-b.com/dash/', 'dvb:priority': 1, serviceLocation: 'cdn-b' }
{ __text: 'https://cdn-a.com/dash/', 'dvb:priority': 0, serviceLocation: 'https://cdn-a.com/' },
{ __text: 'https://cdn-b.com/dash/', 'dvb:priority': 1, serviceLocation: 'https://cdn-b.com/' }
],

@@ -341,0 +341,0 @@ Period: {}

@@ -5,5 +5,7 @@ require(

'bigscreenplayer/models/windowtypes',
'bigscreenplayer/models/mediastate'
'bigscreenplayer/models/mediastate',
'bigscreenplayer/mediasources',
'bigscreenplayer/models/livesupport'
],
function (Squire, WindowTypes, MediaState) {
function (Squire, WindowTypes, MediaState, MediaSources, LiveSupport) {
var MediaPlayerEvent = {

@@ -37,2 +39,4 @@ STOPPED: 'stopped', // Event fired when playback is stopped

var eventCallbacks;
var mockGlitchCurtainInstance;
var testTimeCorrection = 0;

@@ -52,4 +56,2 @@ var cdnArray = [];

var mockGlitchCurtainInstance = jasmine.createSpyObj('mockGlitchCurtain', ['showCurtain', 'hideCurtain', 'tearDown']);
var mockGlitchCurtainConstructorInstance = function () {

@@ -60,2 +62,8 @@ return mockGlitchCurtainInstance;

beforeEach(function (done) {
mockGlitchCurtainInstance = jasmine.createSpyObj('mockGlitchCurtain', ['showCurtain', 'hideCurtain', 'tearDown']);
mediaPlayer = jasmine.createSpyObj('mediaPlayer', ['addEventCallback', 'initialiseMedia', 'beginPlayback',
'getState', 'resume', 'getPlayerElement', 'getSeekableRange',
'reset', 'stop', 'removeAllEventCallbacks', 'getSource',
'getMimeType', 'beginPlaybackFrom', 'playFrom', 'pause']);
injector.mock({

@@ -74,2 +82,3 @@ 'bigscreenplayer/playbackstrategy/liveglitchcurtain': mockGlitchCurtainConstructorInstance

mockGlitchCurtainInstance.tearDown.calls.reset();
testTimeCorrection = 0;
});

@@ -79,2 +88,11 @@

function setUpLegacyAdaptor (opts) {
var mockMediaSources = {
time: function () {
return {correction: testTimeCorrection};
},
currentSource: function () {
return cdnArray[0].url;
}
};
var options = opts || {};

@@ -86,9 +104,4 @@

var timeData = {correction: options.timeCorrection || 0};
var windowType = options.windowType || WindowTypes.STATIC;
var playableMediaPlayer = ['addEventCallback', 'initialiseMedia', 'beginPlayback', 'getState', 'resume', 'getPlayerElement', 'getSeekableRange', 'reset', 'stop', 'removeAllEventCallbacks', 'getSource', 'getMimeType'];
var seekableMediaPlayer = playableMediaPlayer.concat(['beginPlaybackFrom', 'playFrom', 'pause']);
mediaPlayer = jasmine.createSpyObj('mediaPlayer', options.playableDevice ? playableMediaPlayer : seekableMediaPlayer);
mediaPlayer.addEventCallback.and.callFake(function (component, callback) {

@@ -103,4 +116,3 @@ eventCallbacks = function (event) {

document.body.appendChild(videoContainer);
legacyAdaptor = squiredLegacyAdaptor(windowType, undefined, timeData, videoContainer, options.isUHD, config, mediaPlayer);
legacyAdaptor = squiredLegacyAdaptor(mockMediaSources, windowType, videoContainer, options.isUHD, config, mediaPlayer);
}

@@ -124,3 +136,3 @@ describe('transitions', function () {

legacyAdaptor.load(cdnArray, 'video/mp4', 0);
legacyAdaptor.load('video/mp4', 0);

@@ -131,5 +143,6 @@ expect(mediaPlayer.initialiseMedia).toHaveBeenCalledWith('video', cdnArray[0].url, 'video/mp4', videoContainer, jasmine.any(Object));

it('should begin playback from the passed in start time + time correction if we are watching live on a restartable device', function () {
setUpLegacyAdaptor({windowType: WindowTypes.SLIDING, timeCorrection: 10});
testTimeCorrection = 10;
setUpLegacyAdaptor({windowType: WindowTypes.SLIDING});
legacyAdaptor.load(cdnArray, 'video/mp4', 50);
legacyAdaptor.load('video/mp4', 50);

@@ -142,3 +155,3 @@ expect(mediaPlayer.beginPlaybackFrom).toHaveBeenCalledWith(60);

legacyAdaptor.load(cdnArray, 'video/mp4', undefined);
legacyAdaptor.load('video/mp4', undefined);

@@ -151,3 +164,3 @@ expect(mediaPlayer.beginPlayback).toHaveBeenCalledWith();

legacyAdaptor.load(cdnArray, 'video/mp4', 50);
legacyAdaptor.load('video/mp4', 50);

@@ -160,3 +173,3 @@ expect(mediaPlayer.beginPlaybackFrom).toHaveBeenCalledWith(50);

legacyAdaptor.load(cdnArray, 'video/mp4', undefined);
legacyAdaptor.load('video/mp4', undefined);

@@ -177,3 +190,3 @@ expect(mediaPlayer.beginPlaybackFrom).toHaveBeenCalledWith(0);

legacyAdaptor.load(cdnArray, 'video/mp4', undefined);
legacyAdaptor.load('video/mp4', undefined);

@@ -230,3 +243,4 @@ var properties = mediaPlayer.initialiseMedia.calls.mostRecent().args[4];

it('should play from the current time on live if we are not ended, paused or buffering', function () {
setUpLegacyAdaptor({windowType: WindowTypes.SLIDING, timeCorrection: 10});
testTimeCorrection = 10;
setUpLegacyAdaptor({windowType: WindowTypes.SLIDING});

@@ -253,3 +267,3 @@ eventCallbacks({type: MediaPlayerEvent.STATUS, currentTime: 10});

legacyAdaptor.load(cdnArray, 'application/dash+xml', undefined);
legacyAdaptor.load('application/dash+xml', undefined);

@@ -270,3 +284,3 @@ legacyAdaptor.setCurrentTime(10);

legacyAdaptor.load(cdnArray, 'video/mp4', undefined);
legacyAdaptor.load('video/mp4', undefined);

@@ -332,3 +346,3 @@ expect(legacyAdaptor.isPaused()).toEqual(false);

it('should be set to false when we get a playing event', function () {
it('should be set to false when we a playing event is recieved', function () {
setUpLegacyAdaptor();

@@ -412,3 +426,4 @@

it('should return the start/end from the player - time correction', function () {
setUpLegacyAdaptor({windowType: WindowTypes.SLIDING, playableDevice: false, timeCorrection: 10});
testTimeCorrection = 10;
setUpLegacyAdaptor({windowType: WindowTypes.SLIDING, playableDevice: false});

@@ -421,3 +436,4 @@ mediaPlayer.getSeekableRange.and.returnValue({start: 110, end: 1010});

it('should return the start/end from the player when the time correction is 0', function () {
setUpLegacyAdaptor({windowType: WindowTypes.SLIDING, playableDevice: false, timeCorrection: 0});
testTimeCorrection = 0;
setUpLegacyAdaptor({windowType: WindowTypes.SLIDING, playableDevice: false});

@@ -440,3 +456,4 @@ mediaPlayer.getSeekableRange.and.returnValue({start: 100, end: 1000});

it('should be set with time correction when we get a playing event', function () {
setUpLegacyAdaptor({windowType: WindowTypes.STATIC, timeCorrection: 5});
testTimeCorrection = 5;
setUpLegacyAdaptor({windowType: WindowTypes.STATIC});

@@ -457,3 +474,4 @@ eventCallbacks({type: MediaPlayerEvent.PLAYING, currentTime: 10});

it('should be set with time correction when we get a time update event', function () {
setUpLegacyAdaptor({windowType: WindowTypes.STATIC, timeCorrection: 5});
testTimeCorrection = 5;
setUpLegacyAdaptor({windowType: WindowTypes.STATIC});

@@ -492,3 +510,4 @@ eventCallbacks({type: MediaPlayerEvent.STATUS, currentTime: 10});

it('should seek to the time value passed in + time correction', function () {
setUpLegacyAdaptor({windowType: WindowTypes.SLIDING, timeCorrection: 10});
testTimeCorrection = 10;
setUpLegacyAdaptor({windowType: WindowTypes.SLIDING});

@@ -515,3 +534,3 @@ legacyAdaptor.setCurrentTime(10);

legacyAdaptor.load(cdnArray, 'application/dash+xml', undefined);
legacyAdaptor.load('application/dash+xml', undefined);

@@ -571,3 +590,3 @@ eventCallbacks({type: MediaPlayerEvent.PAUSED});

it('should set isEnded to false', function () {
it('should return isEnded as false', function () {
expect(legacyAdaptor.isEnded()).toEqual(false);

@@ -589,7 +608,7 @@ });

legacyAdaptor.load(cdnArray, 'video/mp4', 10);
legacyAdaptor.load('video/mp4', 10);
eventCallbacks({type: MediaPlayerEvent.SEEK_ATTEMPTED});
expect(mockGlitchCurtainInstance.showCurtain).toHaveBeenCalled();
expect(mockGlitchCurtainInstance.showCurtain).toHaveBeenCalledWith();
});

@@ -600,7 +619,7 @@

legacyAdaptor.load(cdnArray, 'video/mp4', 0);
legacyAdaptor.load('video/mp4', 0);
eventCallbacks({type: MediaPlayerEvent.SEEK_ATTEMPTED});
expect(mockGlitchCurtainInstance.showCurtain).toHaveBeenCalled();
expect(mockGlitchCurtainInstance.showCurtain).toHaveBeenCalledWith();
});

@@ -611,3 +630,3 @@

legacyAdaptor.load(cdnArray, 'video/mp4');
legacyAdaptor.load('video/mp4');

@@ -648,11 +667,11 @@ eventCallbacks({type: MediaPlayerEvent.SEEK_ATTEMPTED});

legacyAdaptor.load(cdnArray, 'video/mp4', 0);
legacyAdaptor.load('video/mp4', 0);
eventCallbacks({type: MediaPlayerEvent.SEEK_ATTEMPTED});
expect(mockGlitchCurtainInstance.showCurtain).toHaveBeenCalled();
expect(mockGlitchCurtainInstance.showCurtain).toHaveBeenCalledWith();
eventCallbacks({type: MediaPlayerEvent.SEEK_FINISHED});
expect(mockGlitchCurtainInstance.hideCurtain).toHaveBeenCalled();
expect(mockGlitchCurtainInstance.hideCurtain).toHaveBeenCalledWith();
});

@@ -663,3 +682,3 @@

legacyAdaptor.load(cdnArray, 'video/mp4', 0);
legacyAdaptor.load('video/mp4', 0);

@@ -670,3 +689,3 @@ eventCallbacks({type: MediaPlayerEvent.SEEK_ATTEMPTED});

expect(mockGlitchCurtainInstance.tearDown).toHaveBeenCalled();
expect(mockGlitchCurtainInstance.tearDown).toHaveBeenCalledWith();
});

@@ -676,7 +695,7 @@ });

describe('dash live on error after exiting seek', function () {
it('should reset the player', function () {
it('should have called reset on the player', function () {
setUpLegacyAdaptor({windowType: WindowTypes.SLIDING});
// set up the values handleErrorOnExitingSeek && exitingSeek so they are truthy then fire an error event so we restart.
legacyAdaptor.load(cdnArray, 'application/dash+xml', undefined);
legacyAdaptor.load('application/dash+xml', undefined);

@@ -693,3 +712,3 @@ legacyAdaptor.setCurrentTime(10);

legacyAdaptor.load(cdnArray, 'application/dash+xml', undefined);
legacyAdaptor.load('application/dash+xml', undefined);

@@ -706,3 +725,3 @@ legacyAdaptor.setCurrentTime(10);

legacyAdaptor.load(cdnArray, 'application/dash+xml', undefined);
legacyAdaptor.load('application/dash+xml', undefined);

@@ -717,5 +736,6 @@ legacyAdaptor.setCurrentTime(10);

it('should begin playback from the currentTime + time correction', function () {
setUpLegacyAdaptor({windowType: WindowTypes.SLIDING, timeCorrection: 10});
testTimeCorrection = 10;
setUpLegacyAdaptor({windowType: WindowTypes.SLIDING});
legacyAdaptor.load(cdnArray, 'application/dash+xml', undefined);
legacyAdaptor.load('application/dash+xml', undefined);

@@ -734,3 +754,3 @@ legacyAdaptor.setCurrentTime(10);

legacyAdaptor.load(cdnArray, 'application/dash+xml', undefined);
legacyAdaptor.load('application/dash+xml', undefined);

@@ -757,3 +777,3 @@ eventCallbacks({type: MediaPlayerEvent.PAUSED});

legacyAdaptor.load(cdnArray, 'video/mp4', undefined);
legacyAdaptor.load('video/mp4', undefined);

@@ -760,0 +780,0 @@ eventCallbacks({type: MediaPlayerEvent.PAUSED});

@@ -11,6 +11,20 @@ require(

var restartableMediaPlayer;
var testTime = {
windowStartTime: 0,
windowEndTime: 100000,
correction: 0
};
var mockMediaSources = {
time: function () {
return testTime;
},
refresh: function (successCallback, errorCallback) {
successCallback();
}
};
function initialiseRestartableMediaPlayer (config, windowType) {
windowType = windowType || WindowTypes.SLIDING;
restartableMediaPlayer = RestartableMediaPlayer(player, config, windowType, {windowStartTime: 0, windowEndTime: 100000});
restartableMediaPlayer = RestartableMediaPlayer(player, config, windowType, mockMediaSources);
}

@@ -17,0 +31,0 @@

@@ -6,51 +6,112 @@ require(

'bigscreenplayer/models/windowtypes',
'bigscreenplayer/pluginenums'
'bigscreenplayer/mediasources',
'bigscreenplayer/models/livesupport'
],
function (Squire, MediaKinds, WindowTypes, PluginEnums) {
function (Squire, MediaKinds, WindowTypes, MediaSources, LiveSupport) {
var injector = new Squire();
var MSEStrategy;
var mseStrategy;
var eventCallbacks;
var dashEventCallback;
var eventHandlers = {};
var playbackElement;
var cdnArray = [];
var mediaSources;
var mockDashjs;
var mockDashInstance;
var mockDashMediaPlayer;
var mockDashDebug;
var mockPlugins;
var mockPluginsInterface;
var mockAudioElement = document.createElement('audio');
var mockVideoElement = document.createElement('video');
var testManifestObject;
var dashjsMediaPlayerEvents = {
ERROR: 'error',
MANIFEST_LOADED: 'manifestLoaded',
MANIFEST_VALIDITY_CHANGED: 'manifestValidityChanged',
QUALITY_CHANGE_RENDERED: 'qualityChangeRendered',
BASE_URL_SELECTED: 'baseUrlSelected',
METRIC_ADDED: 'metricAdded',
METRIC_CHANGED: 'metricChanged'
};
var mockTimeModel;
describe('Media Source Extensions Playback Strategy', function () {
var injector = new Squire();
var playbackElement;
var MSEStrategy;
var mseStrategy;
var mockDashInstance;
var mockDashMediaPlayer;
var mockDashDebug;
var mockVideoElement;
var eventCallbacks;
var dashEventCallback;
var eventHandlers = {};
var mockPlugins;
var mockPluginsInterface;
var cdnArray = [];
beforeAll(function () {
mockDashjs = jasmine.createSpyObj('mockDashjs', ['MediaPlayer']);
mockDashMediaPlayer = jasmine.createSpyObj('mockDashMediaPlayer', ['create']);
mockDashDebug = jasmine.createSpyObj('mockDashDebug', ['setLogToBrowserConsole']);
mockDashInstance = jasmine.createSpyObj('mockDashInstance',
['initialize', 'retrieveManifest', 'getDebug', 'getSource', 'on', 'off', 'time', 'duration', 'attachSource',
'reset', 'isPaused', 'pause', 'play', 'seek', 'isReady', 'refreshManifest', 'getDashMetrics', 'getMetricsFor', 'setBufferToKeep',
'setBufferAheadToKeep', 'setBufferTimeAtTopQuality', 'setBufferTimeAtTopQualityLongForm', 'getBitrateInfoListFor', 'getAverageThroughput']);
mockPluginsInterface = jasmine.createSpyObj('interface', ['onErrorCleared', 'onBuffering', 'onBufferingCleared', 'onError', 'onFatalError', 'onErrorHandled', 'onPlayerInfoUpdated']);
mockPlugins = {
interface: mockPluginsInterface
};
var mockAudioElement = document.createElement('audio');
spyOn(mockVideoElement, 'addEventListener');
spyOn(mockVideoElement, 'removeEventListener');
var dashjsMediaPlayerEvents = {
ERROR: 'error',
MANIFEST_LOADED: 'manifestLoaded',
MANIFEST_VALIDITY_CHANGED: 'manifestValidityChanged',
QUALITY_CHANGE_RENDERED: 'qualityChangeRendered',
CDN_FAILOVER: 'baseUrlSelected',
METRIC_ADDED: 'metricAdded',
METRIC_CHANGED: 'metricChanged'
};
mockVideoElement.addEventListener.and.callFake(function (eventType, handler) {
eventHandlers[eventType] = handler;
var mockDashjs = jasmine.createSpyObj('mockDashjs', ['MediaPlayer']);
mockDashMediaPlayer = jasmine.createSpyObj('mockDashMediaPlayer', ['create']);
mockPluginsInterface = jasmine.createSpyObj('interface', ['onErrorCleared', 'onBuffering', 'onBufferingCleared', 'onError', 'onFatalError', 'onErrorHandled', 'onPlayerInfoUpdated']);
eventCallbacks = function (event) {
eventHandlers[event].call(event);
};
});
mockPlugins = {
interface: mockPluginsInterface
};
mockDashjs.MediaPlayer.and.returnValue(mockDashMediaPlayer);
mockDashMediaPlayer.create.and.returnValue(mockDashInstance);
var mockManifestFilter = {
filter: function () {}
};
// For DVRInfo Based Seekable Range
mockDashInstance.duration.and.returnValue(101);
mockDashInstance.isReady.and.returnValue(true);
mockDashInstance.getDebug.and.returnValue(mockDashDebug);
mockDashInstance.getMetricsFor.and.returnValue(true);
var testManifestObject;
mockDashInstance.on.and.callFake(function (eventType, handler) {
eventHandlers[eventType] = handler;
dashEventCallback = function (eventType, event) {
eventHandlers[eventType].call(eventType, event);
};
});
mockDashInstance.getDashMetrics.and.returnValue({
getCurrentDVRInfo: function () {
return {
range: {
start: 0,
end: 101
}
};
},
getCurrentBufferLevel: function () {
return 'buffer';
}
});
});
beforeEach(function (done) {
cdnArray = [];
cdnArray.push({url: 'http://testcdn1/test/', cdn: 'cdn1'});
window.dashjs = mockDashjs;
playbackElement = document.createElement('div');
playbackElement.id = 'app';
document.body.appendChild(playbackElement);
cdnArray = [
{ url: 'http://testcdn1/test/', cdn: 'http://testcdn1/test/' },
{ url: 'http://testcdn2/test/', cdn: 'http://testcdn2/test/' },
{ url: 'http://testcdn3/test/', cdn: 'http://testcdn3/test/' }
];
var mediaSourceCallbacks = jasmine.createSpyObj('mediaSourceCallbacks', ['onSuccess', 'onError']);
mediaSources = new MediaSources();
spyOn(mediaSources, 'time');
mediaSources.init(cdnArray, new Date(), WindowTypes.STATIC, LiveSupport.SEEKABLE, mediaSourceCallbacks);
testManifestObject = {

@@ -67,4 +128,3 @@ type: 'manifestLoaded',

'dashjs': mockDashjs,
'bigscreenplayer/plugins': mockPlugins,
'bigscreenplayer/manifest/manifestfilter': mockManifestFilter
'bigscreenplayer/plugins': mockPlugins
});

@@ -74,2 +134,10 @@

MSEStrategy = SquiredMSEStrategy;
spyOn(document, 'createElement').and.callFake(function (elementType) {
if (elementType === 'audio') {
return mockAudioElement;
} else if (elementType === 'video') {
return mockVideoElement;
}
});
done();

@@ -79,2 +147,9 @@ });

afterEach(function () {
mockVideoElement.currentTime = 0;
document.body.removeChild(playbackElement);
mockPluginsInterface.onErrorHandled.calls.reset();
mockDashInstance.attachSource.calls.reset();
});
function setUpMSE (timeCorrection, windowType, mediaKind, windowStartTimeMS, windowEndTimeMS) {

@@ -84,3 +159,3 @@ var defaultWindowType = windowType || WindowTypes.STATIC;

var timeModel = {
mockTimeModel = {
correction: timeCorrection || 0,

@@ -91,75 +166,5 @@ windowStartTime: windowStartTimeMS || 0,

mockVideoElement = document.createElement('video');
mockVideoElement.currentTime = 0;
spyOn(mockVideoElement, 'addEventListener');
spyOn(mockVideoElement, 'removeEventListener');
playbackElement = document.createElement('div');
playbackElement.id = 'app';
document.body.appendChild(playbackElement);
var mockCdnDebugOutput = jasmine.createSpyObj('mockCdnDebugOutput', ['update', 'tearDown']);
mseStrategy = MSEStrategy(defaultWindowType, defaultMediaKind, timeModel, playbackElement, {}, false, mockCdnDebugOutput);
mockDashDebug = jasmine.createSpyObj('mockDashDebug', ['setLogToBrowserConsole']);
mockDashInstance = jasmine.createSpyObj('mockDashInstance',
['initialize', 'retrieveManifest', 'getDebug', 'getSource', 'on', 'off', 'time', 'duration', 'attachSource',
'reset', 'isPaused', 'pause', 'play', 'seek', 'isReady', 'refreshManifest', 'getDashMetrics', 'getMetricsFor', 'setBufferToKeep',
'setBufferAheadToKeep', 'setBufferTimeAtTopQuality', 'setBufferTimeAtTopQualityLongForm', 'getBitrateInfoListFor', 'getAverageThroughput']);
mockDashInstance.duration.and.returnValue(101);
mockDashjs.MediaPlayer.and.returnValue(mockDashMediaPlayer);
mockDashMediaPlayer.create.and.returnValue(mockDashInstance);
mockDashInstance.on.and.callFake(function (eventType, handler) {
eventHandlers[eventType] = handler;
dashEventCallback = function (eventType, event) {
eventHandlers[eventType].call(eventType, event);
};
});
mockVideoElement.addEventListener.and.callFake(function (eventType, handler) {
eventHandlers[eventType] = handler;
eventCallbacks = function (event) {
eventHandlers[event].call(event);
};
});
// For DVRInfo Based Seekable Range
mockDashInstance.isReady.and.returnValue(true);
mockDashInstance.getDashMetrics.and.returnValue({
getCurrentDVRInfo: function () {
return {range: {
start: 0,
end: 101
}};
}
});
window.dashjs = mockDashjs;
spyOn(document, 'createElement').and.callFake(function (elementType) {
if (elementType === 'audio') {
return mockAudioElement;
} else if (elementType === 'video') {
return mockVideoElement;
}
});
mockDashInstance.getDebug.and.returnValue(mockDashDebug);
mseStrategy = MSEStrategy(mediaSources, defaultWindowType, defaultMediaKind, playbackElement, {}, false);
}
afterEach(function () {
mockVideoElement.currentTime = 0;
document.body.removeChild(playbackElement);
mockPluginsInterface.onErrorHandled.calls.reset();
});
describe('Transitions', function () {

@@ -185,3 +190,3 @@ it('canBePaused() Transition is true', function () {

mseStrategy.load(cdnArray, null, 0);
mseStrategy.load(null, 0);

@@ -197,3 +202,3 @@ expect(playbackElement.firstChild).toBe(mockVideoElement);

mseStrategy.load(cdnArray, null, 0);
mseStrategy.load(null, 0);

@@ -206,3 +211,3 @@ expect(playbackElement.firstChild).toBe(mockAudioElement);

setUpMSE();
mseStrategy.load(cdnArray, null, undefined);
mseStrategy.load(null, undefined);

@@ -215,4 +220,3 @@ expect(mockDashInstance.initialize).toHaveBeenCalledWith(mockVideoElement, null, true);

setUpMSE();
cdnArray.push({url: 'http://testcdn2/test/', cdn: 'cdn2'});
mseStrategy.load(cdnArray, null, 0);
mseStrategy.load(null, 0);

@@ -225,3 +229,3 @@ dashEventCallback(dashjsMediaPlayerEvents.MANIFEST_LOADED, testManifestObject);

'dvb:priority': 0,
serviceLocation: cdnArray[0].cdn
serviceLocation: cdnArray[0].url
},

@@ -231,3 +235,8 @@ {

'dvb:priority': 1,
serviceLocation: cdnArray[1].cdn
serviceLocation: cdnArray[1].url
},
{
__text: cdnArray[2].url + 'dash/',
'dvb:priority': 2,
serviceLocation: cdnArray[2].url
}

@@ -242,3 +251,3 @@ ];

setUpMSE();
mseStrategy.load(cdnArray, null, 0);
mseStrategy.load(null, 0);

@@ -251,3 +260,3 @@ expect(mockDashInstance.initialize).toHaveBeenCalledWith(mockVideoElement, null, true);

setUpMSE();
mseStrategy.load(cdnArray, null, 15);
mseStrategy.load(null, 15);

@@ -265,3 +274,3 @@ expect(mockDashInstance.initialize).toHaveBeenCalledWith(mockVideoElement, null, true);

mseStrategy.load(cdnArray, null, 0);
mseStrategy.load(null, 0);

@@ -277,3 +286,3 @@ expect(mockDashInstance.initialize).toHaveBeenCalledWith(mockVideoElement, null, true);

mseStrategy.load(cdnArray, null, 0.1);
mseStrategy.load(null, 0.1);

@@ -289,3 +298,3 @@ expect(mockDashInstance.initialize).toHaveBeenCalledWith(mockVideoElement, null, true);

mseStrategy.load(cdnArray, null, 100);
mseStrategy.load(null, 100);

@@ -298,8 +307,10 @@ expect(mockDashInstance.initialize).toHaveBeenCalledWith(mockVideoElement, null, true);

describe('for GROWING window', function () {
it('should initialise MediaPlayer with the expected parameters when startTime is zero', function () {
beforeEach(function () {
setUpMSE(0, WindowTypes.GROWING, MediaKinds.VIDEO, 100000, 200000);
mediaSources.time.and.returnValue(mockTimeModel);
mockDashInstance.getSource.and.returnValue('src');
});
mseStrategy.load(cdnArray, null, 0);
it('should initialise MediaPlayer with the expected parameters when startTime is zero', function () {
mseStrategy.load(null, 0);

@@ -311,8 +322,4 @@ expect(mockDashInstance.initialize).toHaveBeenCalledWith(mockVideoElement, null, true);

it('should initialise MediaPlayer with the expected parameters when startTime is set to 0.1', function () {
setUpMSE(0, WindowTypes.GROWING, MediaKinds.VIDEO, 100000, 200000);
mseStrategy.load(null, 0.1);
mockDashInstance.getSource.and.returnValue('src');
mseStrategy.load(cdnArray, null, 0.1);
expect(mockDashInstance.initialize).toHaveBeenCalledWith(mockVideoElement, null, true);

@@ -323,8 +330,4 @@ expect(mockDashInstance.attachSource).toHaveBeenCalledWith(cdnArray[0].url + '#t=101');

it('should initialise MediaPlayer with the expected parameters when startTime is set', function () {
setUpMSE(0, WindowTypes.GROWING, MediaKinds.VIDEO, 100000, 200000);
mseStrategy.load(null, 60);
mockDashInstance.getSource.and.returnValue('src');
mseStrategy.load(cdnArray, null, 60);
expect(mockDashInstance.initialize).toHaveBeenCalledWith(mockVideoElement, null, true);

@@ -337,3 +340,3 @@ expect(mockDashInstance.attachSource).toHaveBeenCalledWith(cdnArray[0].url + '#t=160');

setUpMSE();
mseStrategy.load(cdnArray, null, 0);
mseStrategy.load(null, 0);

@@ -356,11 +359,16 @@ expect(mockVideoElement.addEventListener).toHaveBeenCalledWith('timeupdate', jasmine.any(Function));

describe('Load when there a mediaPlayer exists (e.g. CDN failover)', function () {
describe('Load when a mediaPlayer exists (e.g. CDN failover)', function () {
var noop;
var failoverInfo;
beforeEach(function () {
noop = function () { };
failoverInfo = { errorMessage: 'failover', isBufferingTimeoutError: false };
});
it('should attach a new source with the expected parameters', function () {
setUpMSE();
cdnArray.push({url: 'http://testcdn2/test/', cdn: 'cdn2'});
mockDashInstance.getSource.and.returnValue('src');
mseStrategy.load(cdnArray, null, 0);
mseStrategy.load(null, 0);

@@ -370,18 +378,16 @@ expect(mockDashInstance.initialize).toHaveBeenCalledWith(mockVideoElement, null, true);

cdnArray.shift();
// Player component would do this with its buffering timeout logic
mediaSources.failover(noop, noop, failoverInfo);
mseStrategy.load(cdnArray, null, 0);
mseStrategy.load(null, 0);
expect(mockDashInstance.attachSource).toHaveBeenCalledWith(cdnArray[0].url);
expect(mockDashInstance.attachSource).toHaveBeenCalledWith(cdnArray[1].url);
});
it('should a new source with the expected parameters called before we have a valid currentTime', function () {
it('should attach a new source with the expected parameters called before we have a valid currentTime', function () {
setUpMSE();
cdnArray.push({url: 'http://testcdn2/test/', cdn: 'cdn2'});
cdnArray.push({url: 'http://testcdn3/test/', cdn: 'cdn3'});
mockDashInstance.getSource.and.returnValue('src');
mseStrategy.load(cdnArray, null, 45);
mseStrategy.load(null, 45);

@@ -391,13 +397,11 @@ expect(mockDashInstance.initialize).toHaveBeenCalledWith(mockVideoElement, null, true);

cdnArray.shift();
mediaSources.failover(noop, noop, failoverInfo);
mseStrategy.load(null, 0);
mseStrategy.load(cdnArray, null, 0);
expect(mockDashInstance.attachSource).toHaveBeenCalledWith(cdnArray[1].url + '#t=45');
expect(mockDashInstance.attachSource).toHaveBeenCalledWith(cdnArray[0].url + '#t=45');
mediaSources.failover(noop, noop, failoverInfo);
mseStrategy.load(null, 0);
cdnArray.shift();
mseStrategy.load(cdnArray, null, 0);
expect(mockDashInstance.attachSource).toHaveBeenCalledWith(cdnArray[0].url + '#t=45');
expect(mockDashInstance.attachSource).toHaveBeenCalledWith(cdnArray[2].url + '#t=45');
});

@@ -408,7 +412,5 @@

cdnArray.push({url: 'http://testcdn2/test/', cdn: 'cdn2'});
mockDashInstance.getSource.and.returnValue('src');
mseStrategy.load(cdnArray, null, 45);
mseStrategy.load(null, 45);

@@ -418,9 +420,9 @@ expect(mockDashInstance.initialize).toHaveBeenCalledWith(mockVideoElement, null, true);

cdnArray.shift();
mediaSources.failover(noop, noop, failoverInfo);
mockVideoElement.currentTime = 86;
eventHandlers.timeupdate();
mseStrategy.load(cdnArray, null, 0);
mseStrategy.load(null, 0);
expect(mockDashInstance.attachSource).toHaveBeenCalledWith(cdnArray[0].url + '#t=86');
expect(mockDashInstance.attachSource).toHaveBeenCalledWith(cdnArray[1].url + '#t=86');
});

@@ -437,9 +439,29 @@

expect(mockPluginsInterface.onErrorHandled).not.toHaveBeenCalled();
expect(mockPluginsInterface.onErrorHandled).not.toHaveBeenCalledWith();
});
it('should call plugin handler on dash baseUrl changed event', function () {
it('should call plugin handler on dash download manifest error', function () {
setUpMSE();
cdnArray.push({url: 'http://testcdn2/test/', cdn: 'cdn2'});
mseStrategy.load(cdnArray, WindowTypes.STATIC, 3);
var mockErrorCallback = jasmine.createSpy();
mseStrategy.addErrorCallback(null, mockErrorCallback);
mseStrategy.load(cdnArray, WindowTypes.GROWING, 3);
var testError = {
error: {
event: {
id: 'manifest'
}
}
};
dashEventCallback(dashjsMediaPlayerEvents.ERROR, testError);
expect(mockErrorCallback).toHaveBeenCalledWith(jasmine.objectContaining(testError));
});
it('should call mediaSources failover on dash baseUrl changed event', function () {
setUpMSE();
mseStrategy.load(WindowTypes.STATIC, 10);
expect(mediaSources.availableSources().length).toBe(3);
dashEventCallback(dashjsMediaPlayerEvents.MANIFEST_LOADED, testManifestObject);

@@ -454,7 +476,21 @@

expect(mockPluginsInterface.onErrorHandled).toHaveBeenCalledWith(jasmine.objectContaining({
cdn: 'cdn1',
newCdn: 'cdn2'
}));
expect(mediaSources.availableSources().length).toBe(2);
});
it('should call mediaSources failover on dash baseUrl changed event but do nothing on the current url', function () {
setUpMSE();
mseStrategy.load(WindowTypes.STATIC, 10);
expect(mediaSources.availableSources().length).toBe(3);
dashEventCallback(dashjsMediaPlayerEvents.MANIFEST_LOADED, testManifestObject);
eventHandlers.baseUrlSelected({
baseUrl: {
url: cdnArray[0].cdn,
serviceLocation: cdnArray[0].cdn
}
});
expect(mediaSources.availableSources().length).toBe(3);
});
});

@@ -465,5 +501,5 @@

setUpMSE();
mseStrategy.load(cdnArray, null, 45);
mseStrategy.load(null, 45);
expect(mseStrategy.getSeekableRange()).toEqual({start: 0, end: 101});
expect(mseStrategy.getSeekableRange()).toEqual({ start: 0, end: 101 });
});

@@ -477,3 +513,3 @@ });

mseStrategy.load(cdnArray, null, 0);
mseStrategy.load(null, 0);

@@ -494,3 +530,3 @@ expect(mseStrategy.getCurrentTime()).toBe(10);

mseStrategy.load(cdnArray, null, 0);
mseStrategy.load(null, 0);

@@ -500,3 +536,3 @@ expect(mseStrategy.getDuration()).toBe(101);

it('returns 0 when MediaPlayer is undefined', function () {
it('returns 0 when the MediaPlayer is undefined', function () {
setUpMSE();

@@ -511,7 +547,7 @@

setUpMSE();
mseStrategy.load(cdnArray, null, 0);
mseStrategy.load(null, 0);
mseStrategy.tearDown();
expect(mockDashInstance.reset).toHaveBeenCalled();
expect(mockDashInstance.reset).toHaveBeenCalledWith();
});

@@ -521,3 +557,3 @@

setUpMSE();
mseStrategy.load(cdnArray, null, 0);
mseStrategy.load(null, 0);

@@ -543,3 +579,3 @@ mseStrategy.tearDown();

setUpMSE();
mseStrategy.load(cdnArray, null, 0);
mseStrategy.load(null, 0);

@@ -557,3 +593,3 @@ expect(playbackElement.childElementCount).toBe(1);

setUpMSE();
mseStrategy.load(cdnArray, null, 0);
mseStrategy.load(null, 0);

@@ -565,3 +601,3 @@ expect(mseStrategy.isEnded()).toBe(false);

setUpMSE();
mseStrategy.load(cdnArray, null, 0);
mseStrategy.load(null, 0);

@@ -575,3 +611,3 @@ eventCallbacks('ended');

setUpMSE();
mseStrategy.load(cdnArray, null, 0);
mseStrategy.load(null, 0);

@@ -585,3 +621,3 @@ eventCallbacks('playing');

setUpMSE();
mseStrategy.load(cdnArray, null, 0);
mseStrategy.load(null, 0);

@@ -595,3 +631,3 @@ eventCallbacks('waiting');

setUpMSE();
mseStrategy.load(cdnArray, null, 0);
mseStrategy.load(null, 0);

@@ -611,3 +647,3 @@ eventCallbacks('ended');

setUpMSE();
mseStrategy.load(cdnArray, null, 0);
mseStrategy.load(null, 0);

@@ -621,3 +657,3 @@ mockDashInstance.isPaused.and.returnValue(false);

setUpMSE();
mseStrategy.load(cdnArray, null, 0);
mseStrategy.load(null, 0);

@@ -633,7 +669,7 @@ mockDashInstance.isPaused.and.returnValue(true);

setUpMSE();
mseStrategy.load(cdnArray, null, 0);
mseStrategy.load(null, 0);
mseStrategy.pause();
expect(mockDashInstance.pause).toHaveBeenCalled();
expect(mockDashInstance.pause).toHaveBeenCalledWith();
});

@@ -645,7 +681,7 @@ });

setUpMSE();
mseStrategy.load(cdnArray, null, 0);
mseStrategy.load(null, 0);
mseStrategy.play();
expect(mockDashInstance.play).toHaveBeenCalled();
expect(mockDashInstance.play).toHaveBeenCalledWith();
});

@@ -657,3 +693,3 @@ });

setUpMSE();
mseStrategy.load(cdnArray, null, 0);
mseStrategy.load(null, 0);

@@ -667,3 +703,3 @@ mseStrategy.setCurrentTime(12);

setUpMSE();
mseStrategy.load(cdnArray, null, 0);
mseStrategy.load(null, 0);

@@ -677,3 +713,3 @@ mseStrategy.setCurrentTime(-0.1);

setUpMSE();
mseStrategy.load(cdnArray, null, 0);
mseStrategy.load(null, 0);

@@ -688,3 +724,3 @@ mseStrategy.setCurrentTime(101);

setUpMSE(0, WindowTypes.SLIDING, MediaKinds.VIDEO);
mseStrategy.load(cdnArray, null, 0);
mseStrategy.load(null, 0);
});

@@ -698,3 +734,3 @@

it('should clamp the seek to the start of the seekable range', function () {
it('should always clamp the seek to the start of the seekable range', function () {
mseStrategy.setCurrentTime(-0.1);

@@ -705,3 +741,3 @@

it('should clamp the seek to 1.1s before the end of the seekable range', function () {
it('should always clamp the seek to 1.1s before the end of the seekable range', function () {
mseStrategy.setCurrentTime(101);

@@ -728,4 +764,4 @@

setUpMSE();
mockDashInstance.getBitrateInfoListFor.and.returnValue([{bitrate: 1000}, {bitrate: 2048}, {bitrate: 3000}]);
mseStrategy.load(cdnArray, null, 0);
mockDashInstance.getBitrateInfoListFor.and.returnValue([{ bitrate: 1000 }, { bitrate: 2048 }, { bitrate: 3000 }]);
mseStrategy.load(null, 0);

@@ -749,8 +785,8 @@ dashEventCallback(dashjsMediaPlayerEvents.QUALITY_CHANGE_RENDERED, mockEvent);

setUpMSE();
mockDashInstance.getBitrateInfoListFor.and.returnValue([{bitrate: 1000}, {bitrate: 2048}, {bitrate: 3000}]);
mseStrategy.load(cdnArray, null, 0);
mockDashInstance.getBitrateInfoListFor.and.returnValue([{ bitrate: 1000 }, { bitrate: 2048 }, { bitrate: 3000 }]);
mseStrategy.load(null, 0);
dashEventCallback(dashjsMediaPlayerEvents.QUALITY_CHANGE_RENDERED, mockEvent);
expect(mockPluginsInterface.onPlayerInfoUpdated).not.toHaveBeenCalled();
expect(mockPluginsInterface.onPlayerInfoUpdated).not.toHaveBeenCalledWith();
});

@@ -765,11 +801,4 @@

setUpMSE();
mseStrategy.load(cdnArray, null, 0);
mseStrategy.load(null, 0);
mockDashInstance.getMetricsFor.and.returnValue(true);
mockDashInstance.getDashMetrics.and.returnValue({
getCurrentBufferLevel: function () {
return 'buffer';
}
});
dashEventCallback(dashjsMediaPlayerEvents.METRIC_ADDED, mockBufferEvent);

@@ -790,35 +819,11 @@

setUpMSE();
mseStrategy.load(cdnArray, null, 0);
mseStrategy.load(null, 0);
mockDashInstance.getMetricsFor.and.returnValue(true);
mockDashInstance.getDashMetrics.and.returnValue({
getCurrentBufferLevel: function () {
return 'buffer';
}
});
dashEventCallback(dashjsMediaPlayerEvents.METRIC_ADDED, mockBufferEvent);
expect(mockPluginsInterface.onPlayerInfoUpdated).not.toHaveBeenCalled();
expect(mockPluginsInterface.onPlayerInfoUpdated).not.toHaveBeenCalledWith();
});
});
describe('dashJS CDN_FAILOVER event', function () {
var errorProperties = {
seekable_range: '0 to 101',
current_time: 0,
duration: 101,
error_mssg: 'download'
};
var pluginData = {
status: PluginEnums.STATUS.FAILOVER,
stateType: PluginEnums.TYPE.ERROR,
properties: errorProperties,
isBufferingTimeoutError: false,
cdn: 'cdn1',
isInitialPlay: undefined,
timeStamp: jasmine.any(Object)
};
describe('dashJS BASE_URL_SELECTED event', function () {
beforeEach(function () {

@@ -838,29 +843,9 @@ mockPluginsInterface.onErrorHandled.calls.reset();

setUpMSE();
mseStrategy.load(cdnArray, null, 0);
mseStrategy.load(null, 0);
dashEventCallback(dashjsMediaPlayerEvents.CDN_FAILOVER, mockEvent);
dashEventCallback(dashjsMediaPlayerEvents.BASE_URL_SELECTED, mockEvent);
expect(mockPluginsInterface.onErrorHandled).not.toHaveBeenCalled();
expect(mockPluginsInterface.onErrorHandled).not.toHaveBeenCalledWith();
});
it('should fire an error handled event on the plugins with the erroring CDN', function () {
var mockEvent = {
mediaType: 'video',
type: 'baseUrlSelected',
baseUrl: {
serviceLocation: 'cdn2'
}
};
setUpMSE();
cdnArray.push({url: 'http://testcdn2/test/', cdn: 'cdn2'});
mseStrategy.load(cdnArray, null, 0);
dashEventCallback(dashjsMediaPlayerEvents.MANIFEST_LOADED, testManifestObject);
dashEventCallback(dashjsMediaPlayerEvents.CDN_FAILOVER, mockEvent);
expect(mockPluginsInterface.onErrorHandled).toHaveBeenCalledWith(jasmine.objectContaining(pluginData));
});
it('should not fire CDN failover event on content download error', function () {

@@ -879,8 +864,8 @@ var mockEvent = {

cdnArray.push({url: 'http://testcdn2/test/', cdn: 'cdn2'});
mseStrategy.load(cdnArray, null, 0);
cdnArray.push({ url: 'http://testcdn2/test/', cdn: 'cdn2' });
mseStrategy.load(null, 0);
dashEventCallback(dashjsMediaPlayerEvents.ERROR, mockEvent);
expect(mockErrorCallback).not.toHaveBeenCalled();
expect(mockErrorCallback).not.toHaveBeenCalledWith();
});

@@ -901,4 +886,4 @@

cdnArray.push({url: 'http://testcdn2/test/', cdn: 'cdn2'});
mseStrategy.load(cdnArray, null, 0);
cdnArray.push({ url: 'http://testcdn2/test/', cdn: 'cdn2' });
mseStrategy.load(null, 0);

@@ -905,0 +890,0 @@ dashEventCallback(dashjsMediaPlayerEvents.ERROR, mockEvent);

@@ -5,5 +5,6 @@ require(

'bigscreenplayer/models/livesupport',
'bigscreenplayer/mediasources',
'squire'
],
function (WindowTypes, LiveSupport, Squire) {
function (WindowTypes, LiveSupport, MediaSources, Squire) {
describe('Native Strategy', function () {

@@ -20,7 +21,10 @@ var nativeStrategy;

var mediaKind = 'mediaKind';
var timeData = 'timeData';
var playbackElement = 'playbackElement';
var isUHD = 'isUHD';
var mediaSources;
beforeEach(function (done) {
var mediaSourceCallbacks = jasmine.createSpyObj('mediaSourceCallbacks', ['onSuccess', 'onError']);
mediaSources = new MediaSources([{url: 'http://a', cdn: 'supplierA'}], new Date(), WindowTypes.STATIC, LiveSupport.SEEKABLE, mediaSourceCallbacks);
var injector = new Squire();

@@ -60,7 +64,7 @@

var windowType = WindowTypes.STATIC;
nativeStrategy(windowType, mediaKind, timeData, playbackElement, isUHD, mockDevice);
nativeStrategy(mediaSources, windowType, mediaKind, playbackElement, isUHD, mockDevice);
expect(html5player).toHaveBeenCalledWith(mockConfig);
expect(mockLegacyAdapter).toHaveBeenCalledWith(windowType, mediaKind, timeData, playbackElement, isUHD, mockConfig, mediaPlayer);
expect(mockLegacyAdapter).toHaveBeenCalledWith(mediaSources, windowType, playbackElement, isUHD, mockConfig, mediaPlayer);
});

@@ -70,8 +74,8 @@

var windowType = WindowTypes.GROWING;
nativeStrategy(windowType, mediaKind, timeData, playbackElement, isUHD, mockDevice);
nativeStrategy(mediaSources, windowType, mediaKind, playbackElement, isUHD, mockDevice);
expect(html5player).toHaveBeenCalledWith(mockConfig);
expect(livePlayer).toHaveBeenCalledWith(mediaPlayer, mockConfig, WindowTypes.GROWING, timeData);
expect(livePlayer).toHaveBeenCalledWith(mediaPlayer, mockConfig, WindowTypes.GROWING, mediaSources);
expect(mockLegacyAdapter).toHaveBeenCalledWith(windowType, mediaKind, timeData, playbackElement, isUHD, mockConfig, mediaPlayer);
expect(mockLegacyAdapter).toHaveBeenCalledWith(mediaSources, windowType, playbackElement, isUHD, mockConfig, mediaPlayer);
});

@@ -81,10 +85,10 @@

var windowType = WindowTypes.SLIDING;
nativeStrategy(windowType, mediaKind, timeData, playbackElement, isUHD, mockDevice);
nativeStrategy(mediaSources, windowType, mediaKind, playbackElement, isUHD, mockDevice);
expect(html5player).toHaveBeenCalledWith(mockConfig);
expect(livePlayer).toHaveBeenCalledWith(mediaPlayer, mockConfig, WindowTypes.SLIDING, timeData);
expect(livePlayer).toHaveBeenCalledWith(mediaPlayer, mockConfig, WindowTypes.SLIDING, mediaSources);
expect(mockLegacyAdapter).toHaveBeenCalledWith(windowType, mediaKind, timeData, playbackElement, isUHD, mockConfig, mediaPlayer);
expect(mockLegacyAdapter).toHaveBeenCalledWith(mediaSources, windowType, playbackElement, isUHD, mockConfig, mediaPlayer);
});
});
});
require(
[
'bigscreenplayer/models/windowtypes',
'bigscreenplayer/mediasources',
'bigscreenplayer/models/livesupport',
'squire'
],
function (WindowTypes, Squire) {
function (WindowTypes, MediaSources, LiveSupport, Squire) {
describe('TAL Strategy', function () {

@@ -14,4 +16,8 @@ var injector = new Squire();

var mockDevice;
var mediaSources;
beforeEach(function (done) {
var mediaSourceCallbacks = jasmine.createSpyObj('mediaSourceCallbacks', ['onSuccess', 'onError']);
mediaSources = new MediaSources([{url: 'http://a', cdn: 'supplierA'}], new Date(), WindowTypes.STATIC, LiveSupport.SEEKABLE, mediaSourceCallbacks);
mockDevice = jasmine.createSpyObj('mockDevice', ['getMediaPlayer', 'getLivePlayer', 'getConfig']);

@@ -34,3 +40,3 @@ mediaPlayer = jasmine.createSpyObj('mockMediaPlayer', ['addEventCallback']);

it('calls LegacyAdapter with a static media player when called for STATIC window', function () {
TalStrategy(WindowTypes.STATIC, null, null, null, null, mockDevice);
TalStrategy(mediaSources, WindowTypes.STATIC, null, null, null, mockDevice);

@@ -42,3 +48,3 @@ // getMediaPlayer is called to get a non-live player

it('calls LegacyAdapter with a live media player when called for a GROWING window', function () {
TalStrategy(WindowTypes.GROWING, null, null, null, null, mockDevice);
TalStrategy(mediaSources, WindowTypes.GROWING, null, null, null, mockDevice);

@@ -50,3 +56,3 @@ // getMediaPlayer is called to get a non-live player

it('calls LegacyAdapter with a live media player when called for a SLIDING window', function () {
TalStrategy(WindowTypes.SLIDING, null, null, null, null, mockDevice);
TalStrategy(mediaSources, WindowTypes.SLIDING, null, null, null, mockDevice);

@@ -53,0 +59,0 @@ // getMediaPlayer is called to get a non-live player

@@ -28,4 +28,6 @@ require(

var liveSupport;
var manifestData;
var forceManifestLoadError;
var forceMediaSourcesError;
var mockMediaSources;
var testTime;
var updateTestTime = false;

@@ -43,3 +45,3 @@ // opts = streamType, playbackType, mediaType, subtitlesAvailable, subtitlesEnabled noStatsReporter, disableUi

codec: undefined,
urls: opts.multiCdn ? [{url: 'a', cdn: 'cdn-a'}, {url: 'b', cdn: 'cdn-b'}, {url: 'c', cdn: 'cdn-c'}] : [{url: 'a', cdn: 'cdn-a'}],
urls: [{url: 'a.mpd', cdn: 'cdn-a'}, {url: 'b.mpd', cdn: 'cdn-b'}, {url: 'c.mpd', cdn: 'cdn-c'}],
type: opts.type || 'application/dash+xml',

@@ -50,6 +52,32 @@ transferFormat: opts.transferFormat || TransferFormats.DASH,

},
time: {
windowStartTime: 724000,
windowEndTime: 4324000,
correction: 0
time: testTime
};
mockMediaSources = {
failover: function (successCallback, errorCallback, failoverParams) {
if (forceMediaSourcesError) {
errorCallback();
} else {
if (updateTestTime) {
testTime = {
windowStartTime: 744000,
windowEndTime: 4344000,
correction: 0
};
}
successCallback();
}
},
time: function () {
return testTime;
},
refresh: function (successCallback, errorCallback) {
if (updateTestTime) {
testTime = {
windowStartTime: 744000,
windowEndTime: 4344000,
correction: 0
};
}
successCallback();
}

@@ -65,2 +93,3 @@ };

corePlaybackData,
mockMediaSources,
windowType,

@@ -73,23 +102,2 @@ opts.subtitlesEnabled || false,

function setupManifestData (options) {
manifestData = {
transferFormat: options && options.transferFormat || 'dash',
time: options && options.time || {
windowStartTime: 724000,
windowEndTime: 4324000,
correction: 0
}
};
}
var manifestLoaderMock = {
load: function (urls, serverDate, callbacks) {
if (forceManifestLoadError) {
callbacks.onError();
} else {
callbacks.onSuccess(manifestData);
}
}
};
beforeEach(function (done) {

@@ -122,9 +130,4 @@ injector = new Squire();

'bigscreenplayer/playbackstrategy/mockstrategy': mockStrategyConstructor,
'bigscreenplayer/plugins': mockPlugins,
'bigscreenplayer/manifest/manifestloader': manifestLoaderMock
'bigscreenplayer/plugins': mockPlugins
});
spyOn(manifestLoaderMock, 'load');
manifestLoaderMock.load.and.callThrough();
injector.require(['bigscreenplayer/playercomponent'], function (PlayerComponent) {

@@ -135,3 +138,9 @@ PlayerComponentWithMocks = PlayerComponent;

forceManifestLoadError = false;
forceMediaSourcesError = false;
testTime = {
windowStartTime: 724000,
windowEndTime: 4324000,
correction: 0
};
updateTestTime = false;
});

@@ -307,2 +316,5 @@

currentStrategy = window.bigscreenPlayer.playbackStrategy;
spyOn(mockStrategy, 'setCurrentTime');
spyOn(mockStrategy, 'load');
});

@@ -312,25 +324,50 @@

window.bigscreenPlayer.playbackStrategy = currentStrategy;
mockStrategy.setCurrentTime.calls.reset();
mockStrategy.load.calls.reset();
mockStrategy.getSeekableRange.calls.reset();
});
it('should setCurrentTime on the strategy when in a seekable state', function () {
spyOn(mockStrategy, 'getSeekableRange').and.returnValue({start: 0, end: 100});
setUpPlayerComponent();
spyOn(mockStrategy, 'setCurrentTime');
mockStrategy.load.calls.reset();
playerComponent.setCurrentTime(10);
expect(mockStrategy.setCurrentTime).toHaveBeenCalledWith(10);
expect(mockStrategy.load).not.toHaveBeenCalled();
});
it('should reload the element if restartable', function () {
spyOn(mockStrategy, 'getSeekableRange').and.returnValue({start: 0, end: 100});
window.bigscreenPlayer.playbackStrategy = 'nativestrategy';
liveSupport = LiveSupport.RESTARTABLE;
setUpPlayerComponent({ windowType: WindowTypes.SLIDING });
setUpPlayerComponent({ windowType: WindowTypes.SLIDING, transferFormat: TransferFormats.HLS, type: 'applesomething' });
spyOn(mockStrategy, 'load');
spyOn(mockStrategy, 'getSeekableRange').and.returnValue({start: 0, end: 100});
playerComponent.setCurrentTime(10);
updateTestTime = true;
playerComponent.setCurrentTime(50);
expect(mockStrategy.load).toHaveBeenCalledWith([{ url: 'a', cdn: 'cdn-a' }], 'application/dash+xml', 10);
expect(mockStrategy.load).toHaveBeenCalledTimes(2);
expect(mockStrategy.load).toHaveBeenCalledWith('applesomething', 30);
});
it('should reload the element with no time if the new time is within 30 seconds of the end of the window', function () {
spyOn(mockStrategy, 'getSeekableRange').and.returnValue({start: 0, end: 70});
window.bigscreenPlayer.playbackStrategy = 'nativestrategy';
liveSupport = LiveSupport.RESTARTABLE;
setUpPlayerComponent({ windowType: WindowTypes.SLIDING, transferFormat: TransferFormats.HLS, type: 'applesomething' });
// this will move the window forward by 20 seconds from it's original position
testTime = {
windowStartTime: 744000,
windowEndTime: 4344000,
correction: 0
};
playerComponent.setCurrentTime(50);
expect(mockStrategy.load).toHaveBeenCalledTimes(2);
expect(mockStrategy.load).toHaveBeenCalledWith('applesomething', undefined);
});
});

@@ -398,3 +435,3 @@

// it is exptected to be cleared
mockStrategy.mockingHooks.fireErrorEvent({errorProperties: {}});
mockStrategy.mockingHooks.fireErrorEvent({errorProperties: {error_mssg: 'testError'}});

@@ -487,3 +524,3 @@ mockStrategy.mockingHooks.fireEvent(MediaState.PLAYING);

// it is exptected to be cleared
mockStrategy.mockingHooks.fireErrorEvent({errorProperties: {}});
mockStrategy.mockingHooks.fireErrorEvent({errorProperties: {error_mssg: 'testError'}});

@@ -692,3 +729,3 @@ mockStrategy.mockingHooks.fireEvent(MediaState.PAUSED);

// it is exptected to be cleared
mockStrategy.mockingHooks.fireErrorEvent({errorProperties: {}});
mockStrategy.mockingHooks.fireErrorEvent({errorProperties: {error_mssg: 'testError'}});

@@ -826,3 +863,3 @@ mockStrategy.mockingHooks.fireEvent(MediaState.ENDED);

mockStrategy.mockingHooks.fireErrorEvent({errorProperties: {}});
mockStrategy.mockingHooks.fireErrorEvent({errorProperties: {error_mssg: 'testError'}});

@@ -840,3 +877,3 @@ jasmine.clock().tick(1);

mockStrategy.mockingHooks.fireErrorEvent({errorProperties: {}});
mockStrategy.mockingHooks.fireErrorEvent({errorProperties: {error_mssg: 'testError'}});

@@ -875,20 +912,2 @@ expect(mockStateUpdateCallback.calls.mostRecent().args[0].data.state).toEqual(MediaState.WAITING);

});
// raise error
it('should start the fatal error timeout', function () {
jasmine.clock().install();
setUpPlayerComponent();
// trigger a error event to start the fatal error timeout,
// after 5 seconds it should fire a media state update of FATAL
// it is exptected to be cleared
mockStrategy.mockingHooks.fireErrorEvent({errorProperties: {}});
jasmine.clock().tick(5000);
expect(mockStateUpdateCallback.calls.mostRecent().args[0].data.state).toEqual(MediaState.FATAL_ERROR);
jasmine.clock().uninstall();
});
});

@@ -899,3 +918,3 @@ });

var errorProperties;
var pluginData;
var fatalErrorPluginData;
var currentTime;

@@ -911,6 +930,7 @@ var type;

current_time: 50,
duration: 100
duration: 100,
error_mssg: 'Fatal error'
};
pluginData = {
fatalErrorPluginData = {
status: PluginEnums.STATUS.FATAL,

@@ -921,2 +941,3 @@ stateType: PluginEnums.TYPE.ERROR,

cdn: undefined,
newCdn: undefined,
isInitialPlay: undefined,

@@ -930,6 +951,7 @@ timeStamp: jasmine.any(Object)

spyOn(mockStrategy, 'load');
spyOn(mockStrategy, 'reset');
spyOn(mockStrategy, 'getDuration').and.returnValue(100);
spyOn(mockStrategy, 'getSeekableRange').and.returnValue({start: 0, end: 100});
currentTimeSpy = spyOn(mockStrategy, 'getCurrentTime');
currentTimeSpy.and.returnValue(currentTime);
spyOn(mockStrategy, 'getDuration').and.returnValue(100);
spyOn(mockStrategy, 'getSeekableRange').and.returnValue({start: 0, end: 100});
currentStrategy = window.bigscreenPlayer.playbackStrategy;

@@ -944,4 +966,3 @@ });

it('should failover after buffering for 30 seconds on initial playback', function () {
setUpPlayerComponent({multiCdn: true});
setUpPlayerComponent();
mockStrategy.mockingHooks.fireEvent(MediaState.WAITING);

@@ -952,3 +973,2 @@

expect(mockStrategy.load).toHaveBeenCalledTimes(1);
expect(corePlaybackData.media.urls).toContain(jasmine.objectContaining({cdn: 'cdn-a'}));

@@ -958,14 +978,8 @@ jasmine.clock().tick(1);

expect(mockStrategy.load).toHaveBeenCalledTimes(2);
expect(mockStrategy.load).toHaveBeenCalledWith(corePlaybackData.media.urls, type, currentTime);
expect(corePlaybackData.media.urls.length).toBe(2);
expect(corePlaybackData.media.urls).not.toContain(jasmine.objectContaining({cdn: 'cdn-a'}));
expect(mockStrategy.load).toHaveBeenCalledWith(type, currentTime);
});
it('should failover after buffering for 20 seconds on normal playback', function () {
setUpPlayerComponent({multiCdn: true});
// Set playback cause to normal
mockStrategy.mockingHooks.fireEvent(MediaState.PLAYING);
setUpPlayerComponent();
mockStrategy.mockingHooks.fireEvent(MediaState.PLAYING); // Set playback cause to normal
mockStrategy.mockingHooks.fireEvent(MediaState.WAITING);

@@ -977,25 +991,15 @@

expect(corePlaybackData.media.urls.length).toBe(3);
expect(corePlaybackData.media.urls).toContain(jasmine.objectContaining({cdn: 'cdn-a'}));
jasmine.clock().tick(1);
expect(mockStrategy.load).toHaveBeenCalledTimes(2);
expect(mockStrategy.load).toHaveBeenCalledWith(corePlaybackData.media.urls, type, currentTime);
expect(corePlaybackData.media.urls.length).toBe(2);
expect(corePlaybackData.media.urls).not.toContain(jasmine.objectContaining({cdn: 'cdn-a'}));
expect(mockStrategy.load).toHaveBeenCalledWith(type, currentTime);
});
it('should failover after 5 seconds if we have not cleared an error from the device', function () {
setUpPlayerComponent({multiCdn: true});
setUpPlayerComponent();
mockStrategy.mockingHooks.fireErrorEvent({errorProperties: {error_mssg: 'testError'}});
mockStrategy.mockingHooks.fireErrorEvent({errorProperties: {}});
jasmine.clock().tick(4999);
expect(mockStrategy.load).toHaveBeenCalledTimes(1);
expect(corePlaybackData.media.urls.length).toBe(3);
expect(corePlaybackData.media.urls).toContain(jasmine.objectContaining({cdn: 'cdn-a'}));

@@ -1005,12 +1009,11 @@ jasmine.clock().tick(1);

expect(mockStrategy.load).toHaveBeenCalledTimes(2);
expect(mockStrategy.load).toHaveBeenCalledWith(corePlaybackData.media.urls, type, currentTime);
expect(corePlaybackData.media.urls.length).toBe(2);
expect(corePlaybackData.media.urls).not.toContain(jasmine.objectContaining({cdn: 'cdn-a'}));
expect(mockStrategy.load).toHaveBeenCalledWith(type, currentTime);
expect(mockStrategy.reset).toHaveBeenCalledWith();
});
it('should fire a fatal error on the plugins if there is only one cdn', function () {
it('should fire a fatal error on the plugins if failover is not possible', function () {
setUpPlayerComponent();
forceMediaSourcesError = true;
mockStrategy.mockingHooks.fireErrorEvent({errorProperties: {}});
mockStrategy.mockingHooks.fireErrorEvent({errorProperties: {error_mssg: 'testError'}});

@@ -1021,9 +1024,10 @@ jasmine.clock().tick(5000);

expect(mockPluginsInterface.onFatalError).toHaveBeenCalledWith(jasmine.objectContaining(pluginData));
expect(mockPluginsInterface.onFatalError).toHaveBeenCalledWith(jasmine.objectContaining(fatalErrorPluginData));
});
it('should publish a media state update of fatal if there is only one cdn', function () {
it('should publish a media state update of fatal if failover is not possible', function () {
setUpPlayerComponent();
forceMediaSourcesError = true;
mockStrategy.mockingHooks.fireErrorEvent({errorProperties: {}});
mockStrategy.mockingHooks.fireErrorEvent({errorProperties: {error_mssg: 'testError'}});

@@ -1037,29 +1041,6 @@ jasmine.clock().tick(5000);

it('should publish a media state update of fatal when failover is disabled', function () {
window.bigscreenPlayer.playbackStrategy = 'talstrategy';
liveSupport = LiveSupport.RESTARTABLE;
setUpPlayerComponent({multiCdn: true, transferFormat: TransferFormats.HLS, windowType: WindowTypes.GROWING});
it('should failover for with updated failover time when window time data has changed', function () {
setUpPlayerComponent({ windowType: WindowTypes.SLIDING, transferFormat: TransferFormats.HLS });
updateTestTime = true;
mockStrategy.mockingHooks.fireErrorEvent({errorProperties: {}});
jasmine.clock().tick(5000);
expect(mockStrategy.load).toHaveBeenCalledTimes(1);
expect(mockStateUpdateCallback.calls.mostRecent().args[0].data.state).toEqual(MediaState.FATAL_ERROR);
});
it('should failover for with updated failover time from manifest load', function () {
type = 'application/vnd.apple.mpegurl';
setUpPlayerComponent({multiCdn: true, transferFormat: TransferFormats.HLS, windowType: WindowTypes.SLIDING, type: type});
setupManifestData({
transferFormat: TransferFormats.HLS,
time: {
windowStartTime: 744000,
windowEndTime: 1000000
}
});
// Set playback cause to normal

@@ -1072,4 +1053,2 @@ mockStrategy.mockingHooks.fireEvent(MediaState.PLAYING);

expect(mockStrategy.load).toHaveBeenCalledTimes(1);
expect(corePlaybackData.media.urls.length).toBe(3);
expect(corePlaybackData.media.urls).toContain(jasmine.objectContaining({cdn: 'cdn-a'}));

@@ -1079,129 +1058,9 @@ jasmine.clock().tick(1);

expect(mockStrategy.load).toHaveBeenCalledTimes(2);
expect(mockStrategy.load).toHaveBeenCalledWith(corePlaybackData.media.urls, type, currentTime - 20);
expect(corePlaybackData.media.urls.length).toBe(2);
expect(corePlaybackData.media.urls).not.toContain(jasmine.objectContaining({cdn: 'cdn-a'}));
expect(mockStrategy.load).toHaveBeenCalledWith(type, currentTime - 20);
});
it('should failover for with updated failover time for multiple failovers', function () {
type = 'application/vnd.apple.mpegurl';
setUpPlayerComponent({multiCdn: true, transferFormat: TransferFormats.HLS, windowType: WindowTypes.SLIDING, type: type});
// Set playback cause to normal
mockStrategy.mockingHooks.fireEvent(MediaState.PLAYING);
mockStrategy.mockingHooks.fireEvent(MediaState.WAITING);
setupManifestData({
transferFormat: TransferFormats.HLS,
time: {
windowStartTime: 744000,
windowEndTime: 1000000
}
});
jasmine.clock().tick(20000);
expect(mockStrategy.load).toHaveBeenCalledTimes(2);
expect(mockStrategy.load).toHaveBeenCalledWith(corePlaybackData.media.urls, type, currentTime - 20);
currentTimeSpy.and.returnValue(currentTime - 20);
mockStrategy.mockingHooks.fireEvent(MediaState.PLAYING);
mockStrategy.mockingHooks.fireEvent(MediaState.WAITING);
setupManifestData({
transferFormat: TransferFormats.HLS,
time: {
windowStartTime: 764000,
windowEndTime: 1000000
}
});
jasmine.clock().tick(20000);
expect(mockStrategy.load).toHaveBeenCalledTimes(3);
expect(mockStrategy.load).toHaveBeenCalledWith(corePlaybackData.media.urls, type, currentTime - 40);
});
it('should failover on a without reloading the manifest', function () {
type = 'application/vnd.apple.mpegurl';
setUpPlayerComponent({multiCdn: true, manifestType: 'm3u8', windowType: WindowTypes.GROWING, type: type});
// Set playback cause to normal
mockStrategy.mockingHooks.fireEvent(MediaState.PLAYING);
mockStrategy.mockingHooks.fireEvent(MediaState.WAITING);
jasmine.clock().tick(19999);
expect(mockStrategy.load).toHaveBeenCalledTimes(1);
expect(corePlaybackData.media.urls.length).toBe(3);
expect(corePlaybackData.media.urls.length).toBe(3);
expect(corePlaybackData.media.urls).toContain(jasmine.objectContaining({cdn: 'cdn-a'}));
jasmine.clock().tick(1);
expect(manifestLoaderMock.load).not.toHaveBeenCalled();
expect(mockStrategy.load).toHaveBeenCalledTimes(2);
expect(mockStrategy.load).toHaveBeenCalledWith(corePlaybackData.media.urls, type, currentTime);
expect(corePlaybackData.media.urls.length).toBe(2);
expect(corePlaybackData.media.urls).not.toContain(jasmine.objectContaining({cdn: 'cdn-a'}));
});
it('should fire an error handled event on the plugins with the erroring CDN', function () {
setUpPlayerComponent({multiCdn: true});
mockStrategy.mockingHooks.fireErrorEvent({errorProperties: {}});
jasmine.clock().tick(5000);
var pluginData = {
status: PluginEnums.STATUS.FAILOVER,
stateType: PluginEnums.TYPE.ERROR,
properties: errorProperties,
isBufferingTimeoutError: false,
cdn: 'cdn-a',
newCdn: 'cdn-b',
isInitialPlay: undefined,
timeStamp: jasmine.any(Object)
};
expect(mockPluginsInterface.onErrorHandled).toHaveBeenCalledWith(jasmine.objectContaining(pluginData));
});
it('should fire a fatal error if the manifest fails to reload', function () {
forceManifestLoadError = true;
setUpPlayerComponent({multiCdn: true, transferFormat: TransferFormats.HLS, windowType: WindowTypes.SLIDING});
// Set playback cause to normal
mockStrategy.mockingHooks.fireEvent(MediaState.PLAYING);
mockStrategy.mockingHooks.fireEvent(MediaState.WAITING);
jasmine.clock().tick(20000);
expect(mockStrategy.load).toHaveBeenCalledTimes(1);
expect(mockPluginsInterface.onErrorHandled).not.toHaveBeenCalled();
expect(mockStateUpdateCallback.calls.mostRecent().args[0].data.state).toEqual(MediaState.FATAL_ERROR);
});
it('should reset the strategy', function () {
spyOn(mockStrategy, 'reset');
setUpPlayerComponent({multiCdn: true});
mockStrategy.mockingHooks.fireErrorEvent({errorProperties: {}});
jasmine.clock().tick(5000);
expect(mockStrategy.reset).toHaveBeenCalledWith();
});
// playout logic
it('should clear error timeout', function () {
setUpPlayerComponent({multiCdn: true});
it('should clear buffering timeout error timeout', function () {
setUpPlayerComponent();
forceMediaSourcesError = true;

@@ -1212,8 +1071,7 @@ // trigger a buffering event to start the error timeout,

mockStrategy.mockingHooks.fireEvent(MediaState.WAITING);
mockStrategy.mockingHooks.fireErrorEvent({errorProperties: {error_mssg: 'testError'}});
mockStrategy.mockingHooks.fireErrorEvent({errorProperties: {}});
jasmine.clock().tick(30000);
expect(mockStateUpdateCallback.calls.mostRecent().args[0].data.state).not.toEqual(MediaState.FATAL_ERROR);
expect(mockStateUpdateCallback.calls.mostRecent().args[0].isBufferingTimeoutError).toBe(false);
});

@@ -1223,3 +1081,3 @@

it('should clear fatal error timeout', function () {
setUpPlayerComponent({multiCdn: true});
setUpPlayerComponent();

@@ -1229,3 +1087,3 @@ // trigger a error event to start the fatal error timeout,

// it is exptected to be cleared
mockStrategy.mockingHooks.fireErrorEvent({errorProperties: {}});
mockStrategy.mockingHooks.fireErrorEvent({errorProperties: {error_mssg: 'testError'}});

@@ -1258,3 +1116,3 @@ jasmine.clock().tick(5000);

mockStrategy.mockingHooks.fireErrorEvent({errorProperties: {}});
mockStrategy.mockingHooks.fireErrorEvent({errorProperties: {error_mssg: 'testError'}});

@@ -1287,3 +1145,3 @@ jasmine.clock().tick(5000);

mockStrategy.mockingHooks.fireErrorEvent({errorProperties: {}});
mockStrategy.mockingHooks.fireErrorEvent({errorProperties: {error_mssg: 'testError'}});

@@ -1336,3 +1194,3 @@ jasmine.clock().tick(5000);

// it is exptected to be cleared
mockStrategy.mockingHooks.fireErrorEvent({errorProperties: {}});
mockStrategy.mockingHooks.fireErrorEvent({errorProperties: {error_mssg: 'testError'}});

@@ -1339,0 +1197,0 @@ playerComponent.tearDown();

@@ -12,7 +12,6 @@ define('bigscreenplayer/bigscreenplayer',

'bigscreenplayer/debugger/debugtool',
'bigscreenplayer/manifest/manifestloader',
'bigscreenplayer/utils/timeutils',
'bigscreenplayer/utils/livesupportutils'
'bigscreenplayer/mediasources'
],
function (MediaState, PlayerComponent, PauseTriggers, DynamicWindowUtils, WindowTypes, MockBigscreenPlayer, Plugins, Chronicle, DebugTool, ManifestLoader, SlidingWindowUtils, LiveSupportUtils) {
function (MediaState, PlayerComponent, PauseTriggers, DynamicWindowUtils, WindowTypes, MockBigscreenPlayer, Plugins, Chronicle, DebugTool, SlidingWindowUtils, MediaSources) {
'use strict';

@@ -31,2 +30,3 @@ function BigscreenPlayer () {

var device;
var mediaSources;

@@ -89,3 +89,4 @@ var END_OF_STREAM_TOLERANCE = 10;

function bigscreenPlayerDataLoaded (playbackElement, bigscreenPlayerData, enableSubtitles, device, successCallback) {
if (bigscreenPlayerData.time) {
if (windowType !== WindowTypes.STATIC) {
bigscreenPlayerData.time = mediaSources.time();
serverDate = bigscreenPlayerData.serverDate;

@@ -104,2 +105,3 @@

bigscreenPlayerData,
mediaSources,
windowType,

@@ -114,18 +116,10 @@ enableSubtitles,

}
var availableCdns = bigscreenPlayerData.media.urls.map(function (media) {
return media.cdn;
});
DebugTool.keyValue({key: 'available cdns', value: availableCdns});
DebugTool.keyValue({key: 'current cdn', value: bigscreenPlayerData.media.urls[0].cdn});
DebugTool.keyValue({key: 'url', value: bigscreenPlayerData.media.urls[0].url});
}
function getWindowStartTime () {
return playerComponent && playerComponent.getWindowStartTime();
return mediaSources && mediaSources.time().windowStartTime;
}
function getWindowEndTime () {
return playerComponent && playerComponent.getWindowEndTime();
return mediaSources && mediaSources.time().windowEndTime;
}

@@ -143,22 +137,15 @@

if (LiveSupportUtils.needToGetManifest(windowType, getLiveSupport(device)) && !bigscreenPlayerData.time) {
ManifestLoader.load(
bigscreenPlayerData.media.urls,
serverDate,
{
onSuccess: function (manifestData) {
bigscreenPlayerData.media.transferFormat = manifestData.transferFormat;
bigscreenPlayerData.time = manifestData.time;
bigscreenPlayerDataLoaded(playbackElement, bigscreenPlayerData, enableSubtitles, device, callbacks.onSuccess);
},
onError: function () {
if (callbacks.onError) {
callbacks.onError({error: 'manifest'});
}
}
var mediaSourceCallbacks = {
onSuccess: function () {
bigscreenPlayerDataLoaded(playbackElement, bigscreenPlayerData, enableSubtitles, device, callbacks.onSuccess);
},
onError: function (error) {
if (callbacks.onError) {
callbacks.onError(error);
}
);
} else {
bigscreenPlayerDataLoaded(playbackElement, bigscreenPlayerData, enableSubtitles, device, callbacks.onSuccess);
}
}
};
mediaSources = new MediaSources();
mediaSources.init(bigscreenPlayerData.media.urls, serverDate, windowType, getLiveSupport(device), mediaSourceCallbacks);
},

@@ -177,2 +164,3 @@

windowType = undefined;
mediaSources = undefined;
this.unregisterPlugin();

@@ -230,2 +218,3 @@ DebugTool.tearDown();

}
return {

@@ -232,0 +221,0 @@ windowStartTime: getWindowStartTime(),

@@ -10,24 +10,2 @@ define(

function filterHLS (urls) {
var filtered = [];
for (var i = 0; i < urls.length; i++) {
var isHLS = /\.m3u8($|\?.*$)/.test(urls[i].url);
if (isHLS) {
filtered.push(urls[i].url);
}
}
return filtered;
}
function filterDash (urls) {
var filtered = [];
for (var i = 0; i < urls.length; i++) {
var isDash = /\.mpd($|\?.*$)/.test(urls[i].url);
if (isDash) {
filtered.push(urls[i].url);
}
}
return filtered;
}
function retrieveDashManifest (url, dateWithOffset, callbacks) {

@@ -124,10 +102,7 @@ var xhr = LoadUrl(

return {
load: function (mediaUrls, serverDate, callbacks) {
var hlsUrl = filterHLS(mediaUrls)[0];
var dashUrl = filterDash(mediaUrls)[0];
if (hlsUrl) {
retrieveHLSManifest(hlsUrl, serverDate, callbacks);
} else if (dashUrl) {
retrieveDashManifest(dashUrl, serverDate, callbacks);
load: function (mediaUrl, serverDate, callbacks) {
if (/\.m3u8($|\?.*$)/.test(mediaUrl)) {
retrieveHLSManifest(mediaUrl, serverDate, callbacks);
} else if (/\.mpd($|\?.*$)/.test(mediaUrl)) {
retrieveDashManifest(mediaUrl, serverDate, callbacks);
} else {

@@ -134,0 +109,0 @@ callbacks.onError('Invalid media url');

@@ -49,7 +49,7 @@ define('bigscreenplayer/manifest/manifestmodifier',

var baseUrls = sources.map(function (source, priority) {
var sourceUrl = new URL(baseUrl, source.url);
var sourceUrl = new URL(baseUrl, source);
return {
__text: sourceUrl.href,
'dvb:priority': priority,
serviceLocation: source.cdn
serviceLocation: source
};

@@ -56,0 +56,0 @@ });

@@ -10,10 +10,10 @@ define('bigscreenplayer/playbackstrategy/hybridstrategy',

function (Native, MSE, StrategyPicker, LiveSupport, PlaybackStrategy) {
var HybridStrategy = function (windowType, mediaKind, timeCorrection, videoElement, isUHD, device, cdnDebugOutput) {
var HybridStrategy = function (mediaSources, windowType, mediaKind, videoElement, isUHD, device) {
var strategy = StrategyPicker(windowType, isUHD);
if (strategy === PlaybackStrategy.MSE) {
return MSE(windowType, mediaKind, timeCorrection, videoElement, isUHD, device, cdnDebugOutput);
return MSE(mediaSources, windowType, mediaKind, videoElement, isUHD, device);
}
return Native(windowType, mediaKind, timeCorrection, videoElement, isUHD, device, cdnDebugOutput);
return Native(mediaSources, windowType, mediaKind, videoElement, isUHD, device);
};

@@ -20,0 +20,0 @@

@@ -10,3 +10,3 @@ define('bigscreenplayer/playbackstrategy/legacyplayeradapter',

function (AllowedMediaTransitions, MediaState, WindowTypes, DebugTool, LiveGlitchCurtain) {
return function (windowType, mediaKind, timeData, playbackElement, isUHD, deviceConfig, player) {
return function (mediaSources, windowType, playbackElement, isUHD, deviceConfig, player) {
var EVENT_HISTORY_LENGTH = 2;

@@ -21,3 +21,3 @@

var currentTime;
var timeCorrection = timeData && timeData.correction || 0;
var timeCorrection = mediaSources.time() && mediaSources.time().correction || 0;
var duration = 0;

@@ -94,3 +94,10 @@ var isPaused;

isPaused = false;
currentTime = event.currentTime - timeCorrection;
// Note: Multiple consecutive CDN failover logic
// A newly loaded video element will always report a 0 time update
// This is slightly unhelpful if we want to continue from a later point but consult currentTime as the source of truth.
if (parseInt(event.currentTime) !== 0) {
currentTime = event.currentTime - timeCorrection;
}
// Must publish this time update before checkSeekSucceded - which could cause a pause event

@@ -248,4 +255,3 @@ // This is a device specific event ordering issue.

},
load: function (cdns, mimeType, startTime) {
var source = cdns[0].url;
load: function (mimeType, startTime) {
setupExitSeekWorkarounds(mimeType);

@@ -257,3 +263,3 @@ isPaused = false;

mediaPlayer.initialiseMedia('video', source, mimeType, playbackElement, setSourceOpts);
mediaPlayer.initialiseMedia('video', mediaSources.currentSource(), mimeType, playbackElement, setSourceOpts);
if (mediaPlayer.beginPlaybackFrom && !isPlaybackFromLivePoint) {

@@ -260,0 +266,0 @@ currentTime = startTime;

@@ -78,3 +78,3 @@ define('bigscreenplayer/playbackstrategy/mockstrategy',

var MockStrategy = function (playbackFrame, playbackType, streamType, mediaType, timeData, videoContainer) {
var MockStrategy = function (mediaSources, windowType, mediaKind, timeData, playbackElement, isUHD, device) {
return instance;

@@ -81,0 +81,0 @@ };

@@ -11,7 +11,7 @@ define(

function RestartableLivePlayer (mediaPlayer, deviceConfig, windowType, timeData) {
function RestartableLivePlayer (mediaPlayer, deviceConfig, windowType, mediaSources) {
var callbacksMap = [];
var startTime;
var fakeTimer = {};
var timeCorrection = timeData.correction || 0;
var timeCorrection = mediaSources.time().correction || 0;
addEventCallback(this, updateFakeTimer);

@@ -71,3 +71,3 @@

function getSeekableRange () {
var windowLength = (timeData.windowEndTime - timeData.windowStartTime) / 1000;
var windowLength = (mediaSources.time().windowEndTime - mediaSources.time().windowStartTime) / 1000;
var delta = (Date.now() - startTime) / 1000;

@@ -85,3 +85,3 @@ return {

startTime = Date.now();
fakeTimer.currentTime = (timeData.windowEndTime - timeData.windowStartTime) / 1000;
fakeTimer.currentTime = (mediaSources.time().windowEndTime - mediaSources.time().windowStartTime) / 1000;

@@ -88,0 +88,0 @@ if (config && config.streaming && config.streaming.overrides && config.streaming.overrides.forceBeginPlaybackToEndOfWindow) {

@@ -8,6 +8,3 @@ define('bigscreenplayer/playbackstrategy/msestrategy',

'bigscreenplayer/plugins',
'bigscreenplayer/plugindata',
'bigscreenplayer/pluginenums',
'bigscreenplayer/manifest/manifestmodifier',
'bigscreenplayer/utils/playbackutils',
'bigscreenplayer/models/livesupport',

@@ -18,4 +15,4 @@

],
function (MediaState, WindowTypes, DebugTool, MediaKinds, Plugins, PluginData, PluginEnums, ManifestModifier, PlaybackUtils, LiveSupport) {
var MSEStrategy = function (windowType, mediaKind, timeData, playbackElement, isUHD, device, cdnDebugOutput) {
function (MediaState, WindowTypes, DebugTool, MediaKinds, Plugins, ManifestModifier, LiveSupport) {
var MSEStrategy = function (mediaSources, windowType, mediaKind, playbackElement, isUHD, device) {
var mediaPlayer;

@@ -28,3 +25,3 @@ var mediaElement;

var timeCorrection = timeData && timeData.correction || 0;
var timeCorrection = mediaSources.time() && mediaSources.time().correction || 0;
var failoverTime;

@@ -37,4 +34,2 @@ var isEnded = false;

var mediaSources;
var playerMetadata = {

@@ -54,3 +49,3 @@ playbackBitrate: undefined,

QUALITY_CHANGE_RENDERED: 'qualityChangeRendered',
CDN_FAILOVER: 'baseUrlSelected',
BASE_URL_SELECTED: 'baseUrlSelected',
METRIC_ADDED: 'metricAdded',

@@ -91,3 +86,10 @@ METRIC_CHANGED: 'metricChanged'

} else {
failoverTime = mediaElement.currentTime;
var time = mediaElement.currentTime;
// Note: Multiple consecutive CDN failover logic
// A newly loaded video element will always report a 0 time update
// This is slightly unhelpful if we want to continue from a later point but consult failoverTime as the source of truth.
if (parseInt(time) !== 0) {
failoverTime = time;
}
}

@@ -132,3 +134,3 @@

ManifestModifier.filter(manifest, window.bigscreenPlayer.representationOptions || {}, window.bigscreenPlayer.oldDashCodecRequired);
ManifestModifier.generateBaseUrls(manifest, mediaSources);
ManifestModifier.generateBaseUrls(manifest, mediaSources.availableSources());
}

@@ -159,40 +161,21 @@ }

function createPlaybackProperties () {
return {
seekable_range: getSeekableRange().start + ' to ' + getSeekableRange().end,
current_time: getCurrentTime(),
duration: getDuration()
/**
* Base url selected events are fired from dash.js whenever a priority weighted url is selected from a manifest
* Note: we ignore the initial selection as it isn't a failover.
* @param {*} event
*/
function onBaseUrlSelected (event) {
var failoverInfo = {
errorMessage: 'download',
isBufferingTimeoutError: false
};
}
function propagateCdnFailover (event, cdn) {
// Initial playback
if (mediaSources.length <= 1 || cdn !== mediaSources[1].cdn) return;
function log () {
DebugTool.info('BaseUrl selected: ' + event.baseUrl.url);
}
var errorProperties = PlaybackUtils.merge(createPlaybackProperties(), event.errorProperties);
var evt = new PluginData({
status: PluginEnums.STATUS.FAILOVER,
stateType: PluginEnums.TYPE.ERROR,
properties: errorProperties,
isBufferingTimeoutError: false,
cdn: mediaSources[0].cdn,
newCdn: mediaSources[1].cdn
});
// urls -> sources -> mediaSources (shift the cdns for correct behaviour with buffering timeout failover)
// TODO: Remove this horrible mutation when failover is pushed down per strategy.
Plugins.interface.onErrorHandled(evt);
mediaSources.shift();
cdnDebugOutput.update();
failoverInfo.serviceLocation = event.baseUrl.serviceLocation;
mediaSources.failover(log, log, failoverInfo);
}
function onCdnFailover (event) {
var pluginEvent = {
errorProperties: {
error_mssg: 'download'
}
};
propagateCdnFailover(pluginEvent, event.baseUrl.serviceLocation);
}
function onMetricAdded (event) {

@@ -255,3 +238,3 @@ if (event.mediaType === 'video') {

function setUpMediaPlayer (sources, playbackTime) {
function setUpMediaPlayer (playbackTime) {
mediaPlayer = dashjs.MediaPlayer().create();

@@ -267,9 +250,7 @@ mediaPlayer.getDebug().setLogToBrowserConsole(false);

mediaPlayer.initialize(mediaElement, null, true);
modifySource(sources, playbackTime);
modifySource(playbackTime);
}
function modifySource (sources, playbackTime) {
mediaSources = sources;
var initialSource = calculateSourceAnchor(sources[0].url, playbackTime);
mediaPlayer.attachSource(initialSource);
function modifySource (playbackTime) {
mediaPlayer.attachSource(calculateSourceAnchor(mediaSources.currentSource(), playbackTime));
}

@@ -290,3 +271,3 @@

mediaPlayer.on(DashJSEvents.QUALITY_CHANGE_RENDERED, onQualityChangeRendered);
mediaPlayer.on(DashJSEvents.CDN_FAILOVER, onCdnFailover);
mediaPlayer.on(DashJSEvents.BASE_URL_SELECTED, onBaseUrlSelected);
mediaPlayer.on(DashJSEvents.METRIC_ADDED, onMetricAdded);

@@ -319,3 +300,3 @@ }

if (windowType === WindowTypes.GROWING) {
var windowStartTimeSeconds = (timeData.windowStartTime / 1000);
var windowStartTimeSeconds = (mediaSources.time().windowStartTime / 1000);
var srcWithTimeAnchor = source + '#t=';

@@ -372,12 +353,10 @@

},
load: function (sources, mimeType, playbackTime) {
if (sources && sources.length === 0) return;
load: function (mimeType, playbackTime) {
if (!mediaPlayer) {
failoverTime = playbackTime;
setUpMediaElement(playbackElement);
setUpMediaPlayer(sources, playbackTime);
setUpMediaPlayer(playbackTime);
setUpMediaListeners();
} else {
modifySource(sources, failoverTime);
modifySource(failoverTime);
}

@@ -404,3 +383,3 @@ },

mediaPlayer.off(DashJSEvents.METRIC_ADDED, onMetricAdded);
mediaPlayer.off(DashJSEvents.CDN_FAILOVER, onCdnFailover);
mediaPlayer.off(DashJSEvents.BASE_URL_SELECTED, onBaseUrlSelected);

@@ -420,3 +399,2 @@ mediaElement.parentElement.removeChild(mediaElement);

dashMetrics = undefined;
mediaSources = undefined;
},

@@ -423,0 +401,0 @@ reset: function () {

@@ -9,3 +9,3 @@ define('bigscreenplayer/playbackstrategy/nativestrategy',

function (LegacyAdapter, WindowTypes, MediaPlayer, LivePlayer) {
var NativeStrategy = function (windowType, mediaKind, timeData, playbackElement, isUHD, device) {
var NativeStrategy = function (mediaSources, windowType, mediaKind, playbackElement, isUHD, device) {
var mediaPlayer;

@@ -16,6 +16,6 @@ var tempConfig = device.getConfig();

if (windowType !== WindowTypes.STATIC) {
mediaPlayer = LivePlayer(mediaPlayer, tempConfig, windowType, timeData);
mediaPlayer = LivePlayer(mediaPlayer, tempConfig, windowType, mediaSources);
}
return LegacyAdapter(windowType, mediaKind, timeData, playbackElement, isUHD, device.getConfig(), mediaPlayer);
return LegacyAdapter(mediaSources, windowType, playbackElement, isUHD, device.getConfig(), mediaPlayer);
};

@@ -22,0 +22,0 @@

@@ -7,3 +7,3 @@ define('bigscreenplayer/playbackstrategy/talstrategy',

function (LegacyAdapter, WindowTypes) {
var TALStrategy = function (windowType, mediaKind, timeData, playbackElement, isUHD, device) {
var TALStrategy = function (mediaSources, windowType, mediaKind, playbackElement, isUHD, device) {
var mediaPlayer;

@@ -17,3 +17,3 @@

return LegacyAdapter(windowType, mediaKind, timeData, playbackElement, isUHD, device.getConfig(), mediaPlayer);
return LegacyAdapter(mediaSources, windowType, playbackElement, isUHD, device.getConfig(), mediaPlayer);
};

@@ -20,0 +20,0 @@

@@ -11,14 +11,10 @@ define(

'bigscreenplayer/plugins',
'bigscreenplayer/debugger/debugtool',
'bigscreenplayer/models/transferformats',
'bigscreenplayer/manifest/manifestloader',
'bigscreenplayer/utils/livesupportutils',
'bigscreenplayer/mediaresilience',
'bigscreenplayer/debugger/cdndebugoutput',
'bigscreenplayer/models/livesupport'
'bigscreenplayer/models/livesupport',
'bigscreenplayer/models/playbackstrategy'
],
function (MediaState, CaptionsContainer, PlaybackStrategy, WindowTypes, PlaybackUtils, PluginData, PluginEnums, Plugins, DebugTool, TransferFormats, ManifestLoader, LiveSupportUtils, MediaResilience, CdnDebugOutput, LiveSupport) {
function (MediaState, CaptionsContainer, PlaybackStrategy, WindowTypes, PlaybackUtils, PluginData, PluginEnums, Plugins, TransferFormats, LiveSupport, PlaybackStrategyModel) {
'use strict';
var PlayerComponent = function (playbackElement, bigscreenPlayerData, windowType, enableSubtitles, callback, device) {
var PlayerComponent = function (playbackElement, bigscreenPlayerData, mediaSources, windowType, enableSubtitles, callback, device) {
var isInitialPlay = true;

@@ -36,13 +32,11 @@ var captionsURL = bigscreenPlayerData.media.captionsUrl;

var fatalError;
var cdnDebugOutput = new CdnDebugOutput(bigscreenPlayerData.media.urls);
var transferFormat = bigscreenPlayerData.media.transferFormat;
playbackStrategy = PlaybackStrategy(
mediaSources,
windowType,
mediaKind,
bigscreenPlayerData.time,
playbackElement,
bigscreenPlayerData.media.isUHD,
device,
cdnDebugOutput
device
);

@@ -83,7 +77,7 @@

function getWindowStartTime () {
return bigscreenPlayerData.time && bigscreenPlayerData.time.windowStartTime;
return mediaSources && mediaSources.time().windowStartTime;
}
function getWindowEndTime () {
return bigscreenPlayerData.time && bigscreenPlayerData.time.windowEndTime;
return mediaSources && mediaSources.time().windowEndTime;
}

@@ -133,22 +127,32 @@

if (transitions().canBeginSeek()) {
if (windowType !== WindowTypes.STATIC && getLiveSupport(device) === LiveSupport.RESTARTABLE && window.bigscreenPlayer.playbackStrategy === 'nativestrategy') {
reloadMediaElement(time);
} else {
playbackStrategy.setCurrentTime(time);
}
isNativeHLSRestartable() ? reloadMediaElement(time) : playbackStrategy.setCurrentTime(time);
}
}
function isNativeHLSRestartable () {
return window.bigscreenPlayer.playbackStrategy === PlaybackStrategyModel.NATIVE &&
transferFormat === TransferFormats.HLS &&
windowType !== WindowTypes.STATIC &&
getLiveSupport(device) === LiveSupport.RESTARTABLE;
}
function reloadMediaElement (time) {
function doSeek (time) {
var originalWindowStartOffset = getWindowStartTime();
var doSeek = function () {
var windowOffset = mediaSources.time().windowStartTime - originalWindowStartOffset;
var seekToTime = time - windowOffset / 1000;
var thenPause = playbackStrategy.isPaused();
var seekableRange = playbackStrategy.getSeekableRange();
tearDownMediaElement();
if (time > seekableRange.end - seekableRange.start - 30) {
time = undefined;
if (seekToTime > seekableRange.end - seekableRange.start - 30) {
seekToTime = undefined;
thenPause = false;
}
loadMedia(mediaMetaData.urls, mediaMetaData.type, time, thenPause);
}
var errorCallback = function () {
loadMedia(mediaMetaData.type, seekToTime, thenPause);
};
var onError = function (errorMessage) {
tearDownMediaElement();

@@ -158,3 +162,3 @@ bubbleFatalError(createPlaybackErrorProperties(event), false);

reloadManifest(time, doSeek, errorCallback);
mediaSources.refresh(doSeek, onError);
}

@@ -204,3 +208,3 @@

var playbackProperties = createPlaybackProperties();
startErrorTimeout(playbackProperties);
startBufferingErrorTimeout(playbackProperties);
bubbleErrorCleared(playbackProperties);

@@ -226,9 +230,9 @@ bubbleBufferingRaised(playbackProperties);

var playbackErrorProperties = createPlaybackErrorProperties(event);
raiseError(playbackErrorProperties, false);
raiseError(playbackErrorProperties);
}
function startErrorTimeout (properties) {
function startBufferingErrorTimeout (properties) {
var bufferingTimeout = isInitialPlay ? 30000 : 20000;
var bufferingClearedProperties = PlaybackUtils.clone(properties);
clearErrorTimeout();
clearBufferingErrorTimeout();
errorTimeoutID = setTimeout(function () {

@@ -242,10 +246,10 @@ bufferingClearedProperties.dismissed_by = 'timeout';

function raiseError (properties, bufferingTimeoutError) {
clearErrorTimeout();
function raiseError (properties) {
clearBufferingErrorTimeout();
publishMediaStateUpdate(MediaState.WAITING);
bubbleErrorRaised(properties, bufferingTimeoutError);
startFatalErrorTimeout(properties, bufferingTimeoutError);
bubbleErrorRaised(properties);
startFatalErrorTimeout(properties);
}
function startFatalErrorTimeout (errorProperties, bufferingTimeoutError) {
function startFatalErrorTimeout (errorProperties) {
if (!fatalErrorTimeout && !fatalError) {

@@ -255,3 +259,4 @@ fatalErrorTimeout = setTimeout(function () {

fatalError = true;
attemptCdnFailover(errorProperties, bufferingTimeoutError);
errorProperties.error_mssg = 'Fatal error';
attemptCdnFailover(errorProperties, false);
}, 5000);

@@ -262,56 +267,27 @@ }

function attemptCdnFailover (errorProperties, bufferingTimeoutError) {
var shouldFailover = MediaResilience.shouldFailover(mediaMetaData.urls.length, getDuration(), getCurrentTime(), getLiveSupport(device), windowType, transferFormat);
var time = getCurrentTime();
var oldWindowStartTime = getWindowStartTime();
var failover = function (time) {
cdnFailover(time, thenPause, errorProperties, bufferingTimeoutError);
var failoverParams = {
errorMessage: errorProperties.error_mssg,
isBufferingTimeoutError: bufferingTimeoutError,
currentTime: getCurrentTime(),
duration: getDuration()
};
var errorCallback = function () {
bubbleFatalError(errorProperties, bufferingTimeoutError);
};
if (shouldFailover) {
var thenPause = playbackStrategy.isPaused();
var doLoadMedia = function () {
var thenPause = isPaused();
var windowOffset = (mediaSources.time().windowStartTime - oldWindowStartTime) / 1000;
var failoverTime = time - (windowOffset || 0);
tearDownMediaElement();
loadMedia(mediaMetaData.type, failoverTime, thenPause);
};
var failoverTime = getCurrentTime();
reloadManifest(failoverTime, failover, errorCallback);
} else {
errorCallback();
}
}
var doErrorCallback = function () {
bubbleFatalError(errorProperties, bufferingTimeoutError);
};
function reloadManifest (time, successCallback, errorCallback) {
if (transferFormat === TransferFormats.HLS && LiveSupportUtils.needToGetManifest(windowType, getLiveSupport(device))) {
ManifestLoader.load(
bigscreenPlayerData.media.urls,
bigscreenPlayerData.serverDate,
{
onSuccess: function (manifestData) {
var windowOffset = manifestData.time.windowStartTime - getWindowStartTime();
bigscreenPlayerData.time = manifestData.time;
successCallback(time - windowOffset / 1000);
},
onError: errorCallback
}
);
} else {
successCallback(time);
}
mediaSources.failover(doLoadMedia, doErrorCallback, failoverParams);
}
function cdnFailover (failoverTime, thenPause, errorProperties, bufferingTimeoutError) {
var evt = new PluginData({
status: PluginEnums.STATUS.FAILOVER,
stateType: PluginEnums.TYPE.ERROR,
properties: errorProperties,
isBufferingTimeoutError: bufferingTimeoutError,
cdn: mediaMetaData.urls[0].cdn,
newCdn: mediaMetaData.urls[1].cdn
});
Plugins.interface.onErrorHandled(evt);
mediaMetaData.urls.shift();
cdnDebugOutput.update();
loadMedia(mediaMetaData.urls, mediaMetaData.type, failoverTime, thenPause);
}
function clearFatalErrorTimeout () {

@@ -324,3 +300,3 @@ if (fatalErrorTimeout !== null) {

function clearErrorTimeout () {
function clearBufferingErrorTimeout () {
if (errorTimeoutID !== null) {

@@ -333,3 +309,3 @@ clearTimeout(errorTimeoutID);

function playout (playbackProperties) {
clearErrorTimeout();
clearBufferingErrorTimeout();
clearFatalErrorTimeout();

@@ -355,4 +331,4 @@ fatalError = false;

function bubbleErrorRaised (errorProperties, bufferingTimeoutError) {
var evt = new PluginData({ status: PluginEnums.STATUS.STARTED, stateType: PluginEnums.TYPE.ERROR, properties: errorProperties, isBufferingTimeoutError: bufferingTimeoutError });
function bubbleErrorRaised (errorProperties) {
var evt = new PluginData({ status: PluginEnums.STATUS.STARTED, stateType: PluginEnums.TYPE.ERROR, properties: errorProperties, isBufferingTimeoutError: false });
Plugins.interface.onError(evt);

@@ -415,3 +391,3 @@ }

mediaMetaData = media;
loadMedia(media.urls, media.type, startTime);
loadMedia(media.type, startTime);

@@ -423,4 +399,4 @@ if (!captionsContainer) {

function loadMedia (urls, type, startTime, thenPause) {
playbackStrategy.load(urls, type, startTime);
function loadMedia (type, startTime, thenPause) {
playbackStrategy.load(type, startTime);
if (thenPause) {

@@ -444,7 +420,2 @@ pause();

if (cdnDebugOutput) {
cdnDebugOutput.tearDown();
cdnDebugOutput = undefined;
}
isInitialPlay = true;

@@ -451,0 +422,0 @@ captionsURL = undefined;

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc