Skip to content
This repository has been archived by the owner on Oct 20, 2021. It is now read-only.

Commit

Permalink
WBC-1775: Update Hive Plugin to v4.1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
mi-rsc committed Aug 24, 2018
1 parent 02cab11 commit fe6e7bf
Show file tree
Hide file tree
Showing 8 changed files with 480 additions and 412 deletions.
315 changes: 164 additions & 151 deletions dist/mi-angular-bitdash-player.js

Large diffs are not rendered by default.

64 changes: 45 additions & 19 deletions dist/mi-angular-bitdash-player.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion interface/interfaces.ts
Expand Up @@ -59,6 +59,6 @@ export interface IConfig {
tweaks: {context_menu_entries: any};
logs: {bitmovin: boolean};
events: object;
source?: {dash: string, hls: string, hiveServiceUrl: string};
source?: {dash: string, hls?: string, hls_ticket?: string};
style?: {ux: boolean};
}
290 changes: 159 additions & 131 deletions lib/hive/bitmovin.hive.min.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions src/bitdash-controller.ts
Expand Up @@ -52,7 +52,7 @@ class BitmovinController {
return webcast.useDVRPlaybackInPostlive && webcast.state === 'postlive' ?
this.getDVRPlaybackToPostlive(webcast)
: this.getPlayerConfigSourceByState(webcast)
;
;
}

private getDVRPlaybackToPostlive(webcast: any): any {
Expand Down Expand Up @@ -94,7 +94,7 @@ class BitmovinController {
hls += `${offsetPrefix}start=${offset}`;
}
}
return {hls, title, hiveServiceUrl};
return hiveServiceUrl ? {title, hls_ticket: hiveServiceUrl} : {hls, title};
}

private getHiveServiceUrlByLang(webcast: any): string {
Expand Down
131 changes: 60 additions & 71 deletions src/bitdash-directive.ts
Expand Up @@ -3,85 +3,74 @@ import {IMIUIConfig} from '../interface/interfaces';
import {IBitdashDirective, IBitmovinUIManager, IConfig, IMyElement, IPlayer, IReason, IWindow} from './../interface/interfaces';

const BitdashDirective = ($window: IWindow, $log: angular.ILogService) => ({
controller: 'MiBitdashController',
controllerAs: 'bitdashVm',
replace: true,
restrict: 'EA',
scope: {
config: '=',
options: '=?',
webcast: '=',
},
template: `<div id="mi-bitdash-player" width="100%" height="auto"></div>`,
link(scope: IBitdashDirective): void {
let bitmovinPlayer: IPlayer;
let bitmovinUIManager: IBitmovinUIManager;
let bitmovinControlbar: IMyElement;
const config: IConfig = scope.config;
const webcast: any = scope.webcast;
const stateData: any = scope.state.data;
buildPlayer();
controller: 'MiBitdashController',
controllerAs: 'bitdashVm',
replace: true,
restrict: 'EA',
scope: {
config: '=',
options: '=?',
webcast: '=',
},
template: `<div id="mi-bitdash-player" width="100%" height="auto"></div>`,
link(scope: IBitdashDirective): void {
let bitmovinPlayer: IPlayer;
let bitmovinUIManager: IBitmovinUIManager;
let bitmovinControlbar: IMyElement;
const config: IConfig = scope.config;
const webcast: any = scope.webcast;
buildPlayer();

function buildPlayer(): void {
bitmovinPlayer = $window.window.bitmovin.player('mi-bitdash-player');
if (angular.isDefined(bitmovinPlayer) && bitmovinPlayer.isReady() === true) {
bitmovinPlayer.destroy();
bitmovinPlayer = $window.window.bitmovin.player('mi-bitdash-player');
}
function buildPlayer(): void {
bitmovinPlayer = $window.window.bitmovin.player('mi-bitdash-player');

if ((webcast.state === 'live') && config.source.hiveServiceUrl) {
// Get a hive-enabled player through bitdash.initHiveSDN
$window.window.bitmovin.initHiveSDN(bitmovinPlayer, {debugLevel: 'off'});
// Configure and Setup bitmovin in initSession callback
bitmovinPlayer.initSession(config.source.hiveServiceUrl).then((session) => {
const hiveConfig: IConfig = angular.copy(config);
hiveConfig.source.hls = session.manifest;
loadPlayer(hiveConfig);
}, (reason: IReason) => {
// Handle the case if Hive init fails
$log.warn(`Hive init fails: ${reason.code} - ${reason.message}`);
loadPlayer(config);
});
} else {
loadPlayer(config);
}
}
if (angular.isDefined(bitmovinPlayer) && bitmovinPlayer.isReady() === true) {
bitmovinPlayer.destroy();
bitmovinPlayer = $window.window.bitmovin.player('mi-bitdash-player');
}

function getAudioOnlyPlayerConfig(): IMIUIConfig {
return webcast.theme.audioOnlyFileUrl ? {audioOnlyOverlayConfig: {backgroundImageUrl: webcast.theme.audioOnlyFileUrl, hiddeIndicator: true}} : {};
}
if ((webcast.state === 'live') && config.source.hls_ticket) {
// Get a hive-enabled player through bitdash.initHiveSDN
$window.window.bitmovin.initHiveSDN(bitmovinPlayer, {debugLevel: 'off'});
}

function loadPlayer(conf: IConfig): void {
bitmovinPlayer
.setup(conf)
.then(() => {
bitmovinUIManager = $window.window.bitmovin.playerui.UIManager.Factory;
loadPlayer(config);
}

if (isAudioOnly()) {
bitmovinUIManager.buildAudioOnlyUI(bitmovinPlayer, getAudioOnlyPlayerConfig());
} else {
bitmovinUIManager.buildAudioVideoUI(bitmovinPlayer);
}
function getAudioOnlyPlayerConfig(): IMIUIConfig {
return webcast.theme.audioOnlyFileUrl ? {audioOnlyOverlayConfig: {backgroundImageUrl: webcast.theme.audioOnlyFileUrl, hiddeIndicator: true}} : {};
}

bitmovinControlbar = getElementsByClassName('bitmovinplayer-container');
if (bitmovinControlbar) {
bitmovinControlbar.style.minWidth = '175px';
bitmovinControlbar.style.minHeight = '101px';
document.getElementById('bitmovinplayer-video-mi-bitdash-player').setAttribute('title', webcast.name);
}
}, (reason: IReason) => {
$log.log(`Error: ${reason.code} - ${reason.message}`);
});
}
function loadPlayer(conf: IConfig): void {
bitmovinPlayer.setup(conf)
.then(() => {
bitmovinUIManager = $window.window.bitmovin.playerui.UIManager.Factory;

function isAudioOnly(): boolean {
return webcast.layout.layout === 'audio-only';
}
if (isAudioOnly()) {
bitmovinUIManager.buildAudioOnlyUI(bitmovinPlayer, getAudioOnlyPlayerConfig());
} else {
bitmovinUIManager.buildAudioVideoUI(bitmovinPlayer);
}

function getElementsByClassName(className: string): IMyElement {
return document.getElementsByClassName(className)[0] as IMyElement;
}
}
bitmovinControlbar = getElementsByClassName('bitmovinplayer-container');
if (bitmovinControlbar) {
bitmovinControlbar.style.minWidth = '175px';
bitmovinControlbar.style.minHeight = '101px';
document.getElementById('bitmovinplayer-video-mi-bitdash-player').setAttribute('title', webcast.name);
}
}, (reason: IReason) => {
$log.log(`Error: ${reason.code} - ${reason.message}`);
});
}

function isAudioOnly(): boolean {
return webcast.layout.layout === 'audio-only';
}

function getElementsByClassName(className: string): IMyElement {
return document.getElementsByClassName(className)[0] as IMyElement;
}
}

} as angular.IDirective);

Expand Down
12 changes: 5 additions & 7 deletions test/bitdash-controller.spec.ts
Expand Up @@ -23,7 +23,6 @@ describe('BitdashController', () => {
languages: [
{
downloadablePresentation: {id: '5980695293768a02487b519e'},
hiveServiceUrl: 'https://api-test.hivestreaming.com/v1/events/9021/597f2ca593768a02465dGxK',
hiveTicketId: 'sohJ3g8isHjlJGxK',
language: 'de',
ondemandStateData: {
Expand Down Expand Up @@ -82,14 +81,13 @@ describe('BitdashController', () => {
});

it('should init the Controller', () => {
$scope.webcast.languages[0].hiveServiceUrl = 'https://api-test.hivestreaming.com/v1/events/9021/597f2ca593768a02465dGxK';

const vm = new createController();
vm.$onInit();
expect(vm.config).toEqual($scope.config);
expect($scope.config.key).toBeDefined();
expect(vm.config.source.hls).toBe(
'http://hd2.cdn.edge-cdn.net/i/videodb/519/videodb_519_76439_7579412_16x9_hd.mp4/master.m3u8'
);
expect(vm.config.source.hiveServiceUrl).toBe('https://api-test.hivestreaming.com/v1/events/9021/597f2ca593768a02465dGxK');
expect(vm.config.source.hls_ticket).toBe('https://api-test.hivestreaming.com/v1/events/9021/597f2ca593768a02465dGxK');
expect(vm.config.source.title).toBe('Webcast Excample (3)');
});

Expand All @@ -101,15 +99,15 @@ describe('BitdashController', () => {
expect(vm.config).toEqual($scope.config);
expect(vm.config.key).toBeDefined();
expect(vm.config.source.hls).toBe('https://hlsdvr-origin.edge-cdn.net/webcast/myStreamDvr/playlist.m3u8?DVR');
expect(vm.config.source.hiveServiceUrl).toBeUndefined();
expect(vm.config.source.hls_ticket).toBeUndefined();
expect(vm.config.source.title).toBe('Webcast Excample (3)');
});

it('should configure the player DVR Record in postlive', () => {
$scope.webcast.useDVRPlaybackInPostlive = true;
const vm = new createController();
vm.$onInit();
expect(vm.config.source.hiveServiceUrl).toBeUndefined();
expect(vm.config.source.hls_ticket).toBeUndefined();
expect(vm.config.source.hls).toContain('Dvr/playlist.m3u8?DVR');
});

Expand Down
74 changes: 44 additions & 30 deletions test/bitdash-directive.spec.ts
Expand Up @@ -15,18 +15,19 @@ describe('BitdashDirective', () => {
let configMock;
let stateMock;

const playerFuncSpy: string [] = ['isReady', 'setup', 'destroy', 'initSession', 'addEventHandler'];
const playerFuncSpy: string [] = ['isReady', 'setup', 'destroy', 'addEventHandler'];
const playerUISpy: string [] = ['buildAudioOnlyUI', 'buildAudioVideoUI'];
const bitmovinPlayer = jasmine.createSpyObj('player', playerFuncSpy);
const Factory: IBitmovinUIManager = jasmine.createSpyObj('Factory', playerUISpy);
const windowSpy = {window: {
bitmovin: {
initHiveSDN: () => true,
player: () => bitmovinPlayer as IPlayer,
playerui: {UIManager: {Factory}}
}
}
};
const windowSpy = {
window: {
bitmovin: {
initHiveSDN: () => true,
player: () => bitmovinPlayer as IPlayer,
playerui: {UIManager: {Factory}}
}
}
};
const documentSpy: angular.IAugmentedJQuery = angular
.element(document)
.find('body')
Expand All @@ -47,23 +48,24 @@ describe('BitdashDirective', () => {
};

angular.mock.module(($compileProvider: any, $controllerProvider: any, $provide: any) => {
$compileProvider.directive('miBitdashPlayer', BitdashDirective);
$controllerProvider.register('MiBitdashController', ($scope) => { $scope.state = stateMock; return; });
$provide.value('document', documentSpy);
$provide.value('$window', windowSpy);
$compileProvider.directive('miBitdashPlayer', BitdashDirective);
$controllerProvider.register('MiBitdashController', ($scope) => {
$scope.state = stateMock;
return;
});
$provide.value('document', documentSpy);
$provide.value('$window', windowSpy);
});
angular.mock.inject(($injector: angular.auto.IInjectorService) => {
$q = $injector.get('$q');
$compile = $injector.get('$compile');
$rootScope = $injector.get('$rootScope') as IRootScope;
$log = $injector.get('$log');
$q = $injector.get('$q');
$compile = $injector.get('$compile');
$rootScope = $injector.get('$rootScope') as IRootScope;
$log = $injector.get('$log');
});

configMock = {
foo: 'bar',
source: {
hiveServiceUrl: null
}
source: {}
};

$rootScope.webcastMainVm = {
Expand All @@ -87,8 +89,10 @@ describe('BitdashDirective', () => {
spyOn($log, 'log').and.callThrough();
bitmovinPlayer.setup.and.returnValue($q.reject({code: 404, message: 'stream not found'}));
bitmovinPlayer.isReady.and.returnValue(false);

$compile(template)($rootScope);
$rootScope.$apply();

expect(bitmovinPlayer.setup).toHaveBeenCalledWith(configMock);
expect(bitmovinPlayer.destroy).not.toHaveBeenCalled();
expect(document.getElementsByClassName).not.toHaveBeenCalled();
Expand All @@ -100,8 +104,10 @@ describe('BitdashDirective', () => {
$rootScope.webcastMainVm.webcast.layout.layout = 'split-p-s';
spyOn(document, 'getElementsByClassName').and.callThrough();
spyOn(document, 'getElementById').and.callThrough();

$compile(template)($rootScope);
$rootScope.$apply();

expect(bitmovinPlayer.setup).toHaveBeenCalledWith(configMock);
expect(bitmovinPlayer.destroy).toHaveBeenCalled();
expect(document.getElementsByClassName).toHaveBeenCalledTimes(1);
Expand All @@ -116,8 +122,10 @@ describe('BitdashDirective', () => {
it('Should set up the player for audio only', () => {
$rootScope.webcastMainVm.webcast.layout.layout = 'audio-only';
spyOn(document, 'getElementsByClassName').and.callThrough();

$compile(template)($rootScope);
$rootScope.$apply();

expect(bitmovinPlayer.setup).toHaveBeenCalledWith(configMock);
expect(bitmovinPlayer.destroy).toHaveBeenCalled();
expect(document.getElementsByClassName).toHaveBeenCalledTimes(1);
Expand All @@ -132,8 +140,10 @@ describe('BitdashDirective', () => {
$rootScope.webcastMainVm.webcast.layout.layout = 'audio-only';
$rootScope.webcastMainVm.webcast.theme.audioOnlyFileUrl = 'https://www.ima.ge/image.jpg';
spyOn(document, 'getElementsByClassName').and.callThrough();

$compile(template)($rootScope);
$rootScope.$apply();

expect(bitmovinPlayer.setup).toHaveBeenCalledWith(configMock);
expect(bitmovinPlayer.destroy).toHaveBeenCalled();
expect(document.getElementsByClassName).toHaveBeenCalledTimes(1);
Expand All @@ -148,8 +158,10 @@ describe('BitdashDirective', () => {
const audioOnlyOverlayConfig = {audioOnlyOverlayConfig: {backgroundImageUrl: 'https://www.ima.ge/image.jpg', hiddeIndicator: true}};
$rootScope.webcastMainVm.webcast.layout.layout = 'split-p-s';
spyOn(document, 'getElementsByClassName').and.callThrough();

const element = $compile(template)($rootScope);
$rootScope.$apply();

const scope = element.isolateScope() as IBitdashDirective;
expect(document.getElementsByClassName).toHaveBeenCalledTimes(1);
expect(Factory.buildAudioOnlyUI).toHaveBeenCalledWith(bitmovinPlayer, audioOnlyOverlayConfig);
Expand All @@ -159,12 +171,14 @@ describe('BitdashDirective', () => {
it('Should set up the player video audio with options and forced state', () => {
spyOn(document, 'getElementsByClassName').and.callThrough();
template = '<mi-bitdash-player config="webcastMainVm.playerConfig" ' +
'webcast="webcastMainVm.webcast" ' +
'options="webcastMainVm.options">' +
'</mi-bitdash-player>';
'webcast="webcastMainVm.webcast" ' +
'options="webcastMainVm.options">' +
'</mi-bitdash-player>';
$rootScope.webcastMainVm.options = {forcedState: 'live'};

const element = $compile(angular.element(template))($rootScope);
$rootScope.$apply();

const scope = element.isolateScope() as IBitdashDirective;
expect(document.getElementsByClassName).toHaveBeenCalledTimes(1);
expect(Factory.buildAudioOnlyUI).toHaveBeenCalledWith(bitmovinPlayer, {});
Expand All @@ -180,21 +194,22 @@ describe('BitdashDirective', () => {
},
state: 'live'
};

$compile(angular.element(template))($rootScope);
$rootScope.$apply();

expect(document.getElementsByClassName).toHaveBeenCalledTimes(1);
expect(Factory.buildAudioVideoUI).toHaveBeenCalledWith(bitmovinPlayer);
});

it('Should fails to load player for hive stream', () => {
bitmovinPlayer.initSession.and.returnValue($q.reject({code: 345, message: 'connection failed'}));
$rootScope.webcastMainVm.webcast.state = 'live';
$rootScope.webcastMainVm.webcast.layout.layout = 'split-p-s';
$rootScope.webcastMainVm.playerConfig.source.hiveServiceUrl = 'https://api-test.hivestreaming.com/v1/events/9021/597f';
configMock.source.hiveServiceUrl = 'https://api-test.hivestreaming.com/v1/events/9021/597f';
spyOn(document, 'getElementsByClassName').and.callThrough();

$compile(template)($rootScope);
$rootScope.$apply();

expect(bitmovinPlayer.setup).toHaveBeenCalledWith(configMock);
expect(bitmovinPlayer.destroy).toHaveBeenCalled();
expect(document.getElementsByClassName).toHaveBeenCalledTimes(1);
Expand All @@ -205,15 +220,14 @@ describe('BitdashDirective', () => {
});

it('Should load player for hive stream', () => {
bitmovinPlayer.initSession.and.returnValue($q.when({manifest: 'https://api-hive.hive'}));
$rootScope.webcastMainVm.webcast.state = 'live';
$rootScope.webcastMainVm.webcast.layout.layout = 'split-p-s';
$rootScope.webcastMainVm.playerConfig.source.hiveServiceUrl = 'https://api-test.hivestreaming.com/v1/events/9021/597f';
configMock.source.hiveServiceUrl = 'https://api-test.hivestreaming.com/v1/events/9021/597f';
configMock.source.hls = 'https://api-hive.hive';
configMock.source.hls_ticket = 'https://api-test.hivestreaming.com/v1/events/9021/597f';
spyOn(document, 'getElementsByClassName').and.callThrough();

$compile(template)($rootScope);
$rootScope.$apply();

expect(bitmovinPlayer.setup).toHaveBeenCalledWith(configMock);
expect(bitmovinPlayer.destroy).toHaveBeenCalled();
expect(document.getElementsByClassName).toHaveBeenCalledTimes(1);
Expand Down

0 comments on commit fe6e7bf

Please sign in to comment.