Skip to content
This repository was archived by the owner on Oct 20, 2021. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ coverage

# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
dist

# Dependency directory
node_modules
Expand Down
5,801 changes: 5,801 additions & 0 deletions dist/mi-angular-bitdash-player.js

Large diffs are not rendered by default.

66 changes: 66 additions & 0 deletions dist/mi-angular-bitdash-player.min.js

Large diffs are not rendered by default.

11 changes: 9 additions & 2 deletions interfaces/window.ts → interface/interfaces.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export interface IMyScope extends angular.IScope {
export interface IBitdashDirective extends angular.IScope {
config: any;
webcast: any;
options?: any;
Expand All @@ -14,6 +14,7 @@ export interface IWindow extends angular.IWindowService {

export interface IBitmovin {
playerui: any;
initHiveSDN(bitmovinPlayer: IPlayer, debug?: any): any;
player(id: string): IPlayer;
}

Expand All @@ -27,20 +28,26 @@ export interface IPlayer {
play(): void;
pause(): void;
destroy(): void;
initSession(hsl: string): any;
}

export interface IBitmovinUIManager {
buildAudioOnlyUI(player: IPlayer): void;
buildAudioVideoUI(player: IPlayer): void;
}

export interface IReason {
code: number;
message: string;
}

export interface IConfig {
key: string;
skin: string;
playback: {autoplay: boolean, playsInline: boolean, timeShift: boolean};
tweaks: {context_menu_entries: any};
logs: {bitmovin: boolean};
events: object;
source?: {dash: string, hls: string};
source?: {dash: string, hls: string, hiveServiceUrl: string};
style?: {ux: boolean};
}
6 changes: 3 additions & 3 deletions karma.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
const {resolve} = require('path');
const webpack = require('webpack');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const CleanCompiledJS = ['lib/**/*.js', 'src/**/*.js', 'lib/components/*.js', 'interfaces/*.js'];
const CleanCompiledJS = ['src/**/*.js', 'lib/uimanager/**/*.js', 'interface/*.js'];

module.exports = function (karma) {
karma.set({
Expand Down Expand Up @@ -34,8 +34,8 @@ module.exports = function (karma) {
warningWhitespaceBg: 'bgYellow',
warningFg: 'white',

defaultBg: '',
defaultFg: ''
defaultBg: 'bgBlue',
defaultFg: 'white'
},
pretty: false,
multiline: false,
Expand Down
79 changes: 79 additions & 0 deletions lib/hive/bitmovin.hive.min.js

Large diffs are not rendered by default.

File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"@types/karma": "^0.13.35",
"@types/karma-jasmine": "0.0.29",
"@types/node": "~7.0.22",
"@types/webpack": "^3.0.10",
"angular": "~1.5.8",
"angular-mocks": "~1.5.1",
"awesome-typescript-loader": "^3.1.3",
Expand Down Expand Up @@ -67,7 +68,8 @@
"tslint-eslint-rules": "^4.1.1",
"tslint-loader": "^3.5.3",
"typescript": "2.3.3",
"webpack": "2.6.1"
"uglifyjs-webpack-plugin": "^0.4.6",
"webpack": "3.4.1"
},
"scripts": {
"clean-web": "rimraf dist",
Expand All @@ -76,12 +78,10 @@
"build:js": "webpack --env.prod --display-error-details",
"build:js-min": "webpack --env.min --display-error-details",
"pretest": "rimraf coverage",
"prepare": "npm run build",
"prepublishOnly": "npm-run-all karma cover:check build",
"test": "npm-run-all karma cover:remap",
"karma": "karma start karma.config.js",
"cover:check": "istanbul check-coverage --statements 85 --branches 100 --functions 90 --lines 90",
"cover:remap": "remap-istanbul -i coverage/json/coverage-final.json -o coverage/html-ts -t html",
"cover:open": "opn \"./coverage/html-ts/src/index.html\"",
"validate": "npm-run-all cover:check"
"cover:open": "opn \"./coverage/html-ts/src/index.html\""
}
}
66 changes: 32 additions & 34 deletions src/bitdash-controller.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
import * as angular from 'angular';

interface IBitmovinControllerScope extends angular.IScope {
config: any;
options: any;
webcast: any;
}
import {IBitdashDirective} from './../interface/interfaces';

class BitmovinController {
public static $inject: string[] = ['$scope', '$log'];
private config: any = {};
private options: any = {};

constructor(private $scope: IBitmovinControllerScope, private $log: angular.ILogService) {
constructor(private $scope: IBitdashDirective, private $log: angular.ILogService) {
this.$scope = $scope;
this.$log = $log;
}
Expand All @@ -20,7 +15,7 @@ class BitmovinController {
if (angular.isDefined(this.$scope.config) && angular.isDefined(this.$scope.config.key)) {
this.config = this.$scope.config;
} else {
this.$log.error('basic config for bitdash player is missing!');
this.$log.error(`basic config for bitdash player is missing!`);
}
if (angular.isDefined(this.$scope.options)) {
this.options = this.$scope.options;
Expand All @@ -32,18 +27,18 @@ class BitmovinController {
}

public processWebcast(webcast: any): void {
let stateProperty = webcast.state + 'StateData';
let stateProperty = `${webcast.state}StateData`;

if (angular.isDefined(this.options.forcedState)) {
stateProperty = this.options.forcedState + 'StateData';
stateProperty = `${this.options.forcedState}StateData`;
}

this.config.source = this.getPlayerConfigSource(webcast, stateProperty);
this.config.style = {ux: false};
}

public getPlayerConfigSource(webcast: any , state: any): any {
if (webcast.useDVRPlaybackInPostlive === true && state === 'postliveStateData') {
if ((webcast.useDVRPlaybackInPostlive === true) && (state === 'postliveStateData')) {
return this.getDVRPlaybackToPostlive(webcast);
}
return this.getPlayerConfigSourceByState(webcast, state);
Expand All @@ -58,22 +53,16 @@ class BitmovinController {
const offset: number = parseInt(webcast['postliveStateData'].playout.offset, 10);

if (offset > 0) {
let offsetPrefix: string = '?';
let offsetPrefix: string;
const parser = document.createElement('a');
parser.href = webcast['liveStateData'].playout.hlsDvrUrl;
if (parser.search) {
offsetPrefix = '&';
}

hls += offsetPrefix + 'wowzadvrplayliststart=' + offset + '000';
offsetPrefix = (parser.search) ? '&' : '?';
hls += `${offsetPrefix}wowzadvrplayliststart=${offset}000`;

if (angular.isDefined(dash) && dash) {
offsetPrefix = '?';
parser.href = dash;
if (parser.search) {
offsetPrefix = '&';
}
dash += offsetPrefix + 'wowzadvrplayliststart=' + offset + '000';
offsetPrefix = (parser.search) ? '&' : '?';
dash += `${offsetPrefix}wowzadvrplayliststart=${offset}000`;
}
}
}
Expand All @@ -85,6 +74,8 @@ class BitmovinController {
let hls: string = webcast[state].playout.hlsUrl;
let dash: string = webcast[state].playout.dashUrl;
const title: string = webcast.name;
const hiveServiceUrl: string = this.getHiveServiceUrlByLang(webcast);

if (angular.isDefined(webcast[state].playout.videoManagerHlsUrl) && webcast[state].playout.videoManagerHlsUrl) {
hls = webcast[state].playout.videoManagerHlsUrl;
}
Expand All @@ -93,26 +84,33 @@ class BitmovinController {
const offset: number = parseInt(webcast[state].playout.offset, 10);

if (offset > 0) {
let offsetPrefix: string = '?';
let offsetPrefix: string;
const parser = document.createElement('a');
parser.href = hls;
if (parser.search) {
offsetPrefix = '&';
}

hls += offsetPrefix + 'start=' + offset;
offsetPrefix = (parser.search) ? '&' : '?';
hls += `${offsetPrefix}start=${offset}`;

if (angular.isDefined(dash) && dash) {
offsetPrefix = '?';
parser.href = dash;
if (parser.search) {
offsetPrefix = '&';
}
dash += offsetPrefix + 'start=' + offset;
offsetPrefix = (parser.search) ? '&' : '?';
dash += `${offsetPrefix}start=${offset}`;
}
}
}
return {dash, hls, title};
return {dash, hls, title, hiveServiceUrl};
}

public getHiveServiceUrlByLang(webcast: any): string {
let hiveServiceUrl = null;
if (webcast.languages && webcast.language) {
webcast.languages.forEach((item: any) => {
if (item.language === webcast.language) {
hiveServiceUrl = angular.copy(item.hiveServiceUrl);
}
});
}

return hiveServiceUrl;
}
}

Expand Down
51 changes: 33 additions & 18 deletions src/bitdash-directive.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@

import * as angular from 'angular';
import {IBitmovinUIManager, IConfig, IMyElement, IMyScope, IPlayer, IWindow} from '../interfaces/window';
import {IBitdashDirective, IBitmovinUIManager, IConfig, IMyElement, IPlayer, IReason, IWindow} from './../interface/interfaces';

const BitdashDirective = ($window: IWindow) => ({
const BitdashDirective = ($window: IWindow, $log: angular.ILogService) => ({
controller: 'MiBitdashController',
controllerAs: 'bitdashVm',
replace: true,
Expand All @@ -13,20 +12,43 @@ const BitdashDirective = ($window: IWindow) => ({
webcast: '=',
},
template: `<div id="mi-bitdash-player" width="100%" height="auto"></div>`,
link(scope: IMyScope): void {
link(scope: IBitdashDirective): void {
let bitmovinPlayer: IPlayer;
let bitmovinUIManager: IBitmovinUIManager;
let bitmovinControlbar: IMyElement;
const config: IConfig = scope.config;
const webcast: any = scope.webcast;
const state: string = scope.webcast.state + 'StateData';
const state: string = `${scope.webcast.state}StateData`;
buildPlayer();

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

if ((state === 'liveStateData') && 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);
}
}

function loadPlayer(conf: IConfig): void {
bitmovinPlayer
.setup(config)
.setup(conf)
.then(() => {
bitmovinUIManager = $window.window.bitmovin.playerui.UIManager.Factory;
if (isAudioOnly()) {
Expand All @@ -45,18 +67,11 @@ const BitdashDirective = ($window: IWindow) => ({
bitmovinControlbar.style.minHeight = '101px';
document.getElementById('bitmovinplayer-video-mi-bitdash-player').setAttribute('title', webcast.name);
}
}, (reason: { code: number, message: string}) => {
console.log('Error: ' + reason.code + ' - ' + reason.message);
}, (reason: IReason) => {
$log.log(`Error: ${reason.code} - ${reason.message}`);
});
}

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

function isAudioOnly(): boolean {
return angular.isDefined(scope.webcast[state].playout.audioOnly) &&
scope.webcast[state].playout.audioOnly;
Expand All @@ -66,7 +81,7 @@ const BitdashDirective = ($window: IWindow) => ({
if (angular.isDefined(scope.webcast[state].playout.audioOnlyStillUrl) &&
scope.webcast[state].playout.audioOnlyStillUrl !== '') {
const element = getElementsByClassName('bmpui-ui-audioonly-overlay') as IMyElement;
element.style.backgroundImage = 'url(' + scope.webcast[state].playout.audioOnlyStillUrl + ')';
element.style.backgroundImage = `url(${scope.webcast[state].playout.audioOnlyStillUrl})`;
element.style.backgroundSize = 'contain';
element.style.backgroundPosition = 'center';
}
Expand All @@ -81,4 +96,4 @@ const BitdashDirective = ($window: IWindow) => ({

export default BitdashDirective;

BitdashDirective.$inject = ['$window'];
BitdashDirective.$inject = ['$window', '$log'];
3 changes: 1 addition & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import * as angular from 'angular';
import BitdashController from './bitdash-controller';
import BitdashDirective from './bitdash-directive';

const moduleName = 'mi.BitdashPlayer';
export default angular.module(moduleName, [])
export default angular.module('mi.BitdashPlayer', [])
.controller('MiBitdashController', BitdashController)
.directive('miBitdashPlayer', BitdashDirective);
24 changes: 24 additions & 0 deletions test/bitdash-controller.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@ describe('BitdashController', () => {
webcast: {
customer: {id: '570b9ab86b756510008b4567', name: 'MovingIMAGE24 GmbH', type: 'admin'},
id: '570b9ab86b756510008b4578',
language: 'de',
languages: [
{
downloadablePresentation: {id: '5980695293768a02487b519e'},
hiveServiceUrl: 'https://api-test.hivestreaming.com/v1/events/9021/597f2ca593768a02465dGxK',
hiveTicketId: 'sohJ3g8isHjlJGxK',
language: 'de',
presentations: []
}
],
liveStateData: {
broadcast: {
serverUrl: 'rtmp://live-ingest.edge-cdn.net:1935/webcast/',
Expand Down Expand Up @@ -75,13 +85,27 @@ describe('BitdashController', () => {
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.title).toBe('Webcast Excample (3)');
});

it('should not add getHiveServiceUrl to config object', () => {
$scope.webcast.useDVRPlaybackInPostlive = true;
$scope.webcast.language = 'es';
const vm = new createController();
vm.$onInit();
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.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).toContain('Dvr/playlist.m3u8?DVR');
});

Expand Down
Loading