bigscreen-player
Advanced tools
Comparing version 2.10.0 to 2.11.0
{ | ||
"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; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
7455167
68166
97