aboutsummaryrefslogtreecommitdiff
path: root/assets
diff options
context:
space:
mode:
authorMaZderMind2016-12-22 20:25:35 +0100
committerMaZderMind2016-12-22 20:25:35 +0100
commitd00fda4353e943c249354edf6e11cccfdc089d83 (patch)
treed8ab8848b2f08f5289d117b349de50b824438a4f /assets
parentefdae0713ec5890aab5358747ffc304d97ab058b (diff)
working example of minimal dash player
Diffstat (limited to 'assets')
-rw-r--r--assets/dashjs/dash.all.debug.js38530
1 files changed, 38530 insertions, 0 deletions
diff --git a/assets/dashjs/dash.all.debug.js b/assets/dashjs/dash.all.debug.js
new file mode 100644
index 0000000..4705a73
--- /dev/null
+++ b/assets/dashjs/dash.all.debug.js
@@ -0,0 +1,38530 @@
+(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
+/* $Date: 2007-06-12 18:02:31 $ */
+
+// from: http://bannister.us/weblog/2007/06/09/simple-base64-encodedecode-javascript/
+// Handles encode/decode of ASCII and Unicode strings.
+
+'use strict';
+
+var UTF8 = {};
+UTF8.encode = function (s) {
+ var u = [];
+ for (var i = 0; i < s.length; ++i) {
+ var c = s.charCodeAt(i);
+ if (c < 0x80) {
+ u.push(c);
+ } else if (c < 0x800) {
+ u.push(0xC0 | c >> 6);
+ u.push(0x80 | 63 & c);
+ } else if (c < 0x10000) {
+ u.push(0xE0 | c >> 12);
+ u.push(0x80 | 63 & c >> 6);
+ u.push(0x80 | 63 & c);
+ } else {
+ u.push(0xF0 | c >> 18);
+ u.push(0x80 | 63 & c >> 12);
+ u.push(0x80 | 63 & c >> 6);
+ u.push(0x80 | 63 & c);
+ }
+ }
+ return u;
+};
+UTF8.decode = function (u) {
+ var a = [];
+ var i = 0;
+ while (i < u.length) {
+ var v = u[i++];
+ if (v < 0x80) {
+ // no need to mask byte
+ } else if (v < 0xE0) {
+ v = (31 & v) << 6;
+ v |= 63 & u[i++];
+ } else if (v < 0xF0) {
+ v = (15 & v) << 12;
+ v |= (63 & u[i++]) << 6;
+ v |= 63 & u[i++];
+ } else {
+ v = (7 & v) << 18;
+ v |= (63 & u[i++]) << 12;
+ v |= (63 & u[i++]) << 6;
+ v |= 63 & u[i++];
+ }
+ a.push(String.fromCharCode(v));
+ }
+ return a.join('');
+};
+
+var BASE64 = {};
+(function (T) {
+ var encodeArray = function encodeArray(u) {
+ var i = 0;
+ var a = [];
+ var n = 0 | u.length / 3;
+ while (0 < n--) {
+ var v = (u[i] << 16) + (u[i + 1] << 8) + u[i + 2];
+ i += 3;
+ a.push(T.charAt(63 & v >> 18));
+ a.push(T.charAt(63 & v >> 12));
+ a.push(T.charAt(63 & v >> 6));
+ a.push(T.charAt(63 & v));
+ }
+ if (2 == u.length - i) {
+ var v = (u[i] << 16) + (u[i + 1] << 8);
+ a.push(T.charAt(63 & v >> 18));
+ a.push(T.charAt(63 & v >> 12));
+ a.push(T.charAt(63 & v >> 6));
+ a.push('=');
+ } else if (1 == u.length - i) {
+ var v = u[i] << 16;
+ a.push(T.charAt(63 & v >> 18));
+ a.push(T.charAt(63 & v >> 12));
+ a.push('==');
+ }
+ return a.join('');
+ };
+ var R = (function () {
+ var a = [];
+ for (var i = 0; i < T.length; ++i) {
+ a[T.charCodeAt(i)] = i;
+ }
+ a['='.charCodeAt(0)] = 0;
+ return a;
+ })();
+ var decodeArray = function decodeArray(s) {
+ var i = 0;
+ var u = [];
+ var n = 0 | s.length / 4;
+ while (0 < n--) {
+ var v = (R[s.charCodeAt(i)] << 18) + (R[s.charCodeAt(i + 1)] << 12) + (R[s.charCodeAt(i + 2)] << 6) + R[s.charCodeAt(i + 3)];
+ u.push(255 & v >> 16);
+ u.push(255 & v >> 8);
+ u.push(255 & v);
+ i += 4;
+ }
+ if (u) {
+ if ('=' == s.charAt(i - 2)) {
+ u.pop();
+ u.pop();
+ } else if ('=' == s.charAt(i - 1)) {
+ u.pop();
+ }
+ }
+ return u;
+ };
+ var ASCII = {};
+ ASCII.encode = function (s) {
+ var u = [];
+ for (var i = 0; i < s.length; ++i) {
+ u.push(s.charCodeAt(i));
+ }
+ return u;
+ };
+ ASCII.decode = function (u) {
+ for (var i = 0; i < s.length; ++i) {
+ a[i] = String.fromCharCode(a[i]);
+ }
+ return a.join('');
+ };
+ BASE64.decodeArray = function (s) {
+ var u = decodeArray(s);
+ return new Uint8Array(u);
+ };
+ BASE64.encodeASCII = function (s) {
+ var u = ASCII.encode(s);
+ return encodeArray(u);
+ };
+ BASE64.decodeASCII = function (s) {
+ var a = decodeArray(s);
+ return ASCII.decode(a);
+ };
+ BASE64.encode = function (s) {
+ var u = UTF8.encode(s);
+ return encodeArray(u);
+ };
+ BASE64.decode = function (s) {
+ var u = decodeArray(s);
+ return UTF8.decode(u);
+ };
+})("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
+
+/*The following polyfills are not used in dash.js but have caused multiplayer integration issues.
+ Therefore commenting them out.
+if (undefined === btoa) {
+ var btoa = BASE64.encode;
+}
+if (undefined === atob) {
+ var atob = BASE64.decode;
+}
+*/
+
+if (typeof exports !== 'undefined') {
+ exports.decode = BASE64.decode;
+ exports.decodeArray = BASE64.decodeArray;
+}
+
+},{}],2:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2015-2016, DASH Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * 2. Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+(function (exports) {
+
+ "use strict";
+
+ /**
+ * Exceptions from regular ASCII. CodePoints are mapped to UTF-16 codes
+ */
+
+ var specialCea608CharsCodes = {
+ 0x2a: 0xe1, // lowercase a, acute accent
+ 0x5c: 0xe9, // lowercase e, acute accent
+ 0x5e: 0xed, // lowercase i, acute accent
+ 0x5f: 0xf3, // lowercase o, acute accent
+ 0x60: 0xfa, // lowercase u, acute accent
+ 0x7b: 0xe7, // lowercase c with cedilla
+ 0x7c: 0xf7, // division symbol
+ 0x7d: 0xd1, // uppercase N tilde
+ 0x7e: 0xf1, // lowercase n tilde
+ 0x7f: 0x2588, // Full block
+ // THIS BLOCK INCLUDES THE 16 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS
+ // THAT COME FROM HI BYTE=0x11 AND LOW BETWEEN 0x30 AND 0x3F
+ // THIS MEANS THAT \x50 MUST BE ADDED TO THE VALUES
+ 0x80: 0xae, // Registered symbol (R)
+ 0x81: 0xb0, // degree sign
+ 0x82: 0xbd, // 1/2 symbol
+ 0x83: 0xbf, // Inverted (open) question mark
+ 0x84: 0x2122, // Trademark symbol (TM)
+ 0x85: 0xa2, // Cents symbol
+ 0x86: 0xa3, // Pounds sterling
+ 0x87: 0x266a, // Music 8'th note
+ 0x88: 0xe0, // lowercase a, grave accent
+ 0x89: 0x20, // transparent space (regular)
+ 0x8a: 0xe8, // lowercase e, grave accent
+ 0x8b: 0xe2, // lowercase a, circumflex accent
+ 0x8c: 0xea, // lowercase e, circumflex accent
+ 0x8d: 0xee, // lowercase i, circumflex accent
+ 0x8e: 0xf4, // lowercase o, circumflex accent
+ 0x8f: 0xfb, // lowercase u, circumflex accent
+ // THIS BLOCK INCLUDES THE 32 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS
+ // THAT COME FROM HI BYTE=0x12 AND LOW BETWEEN 0x20 AND 0x3F
+ 0x90: 0xc1, // capital letter A with acute
+ 0x91: 0xc9, // capital letter E with acute
+ 0x92: 0xd3, // capital letter O with acute
+ 0x93: 0xda, // capital letter U with acute
+ 0x94: 0xdc, // capital letter U with diaresis
+ 0x95: 0xfc, // lowercase letter U with diaeresis
+ 0x96: 0x2018, // opening single quote
+ 0x97: 0xa1, // inverted exclamation mark
+ 0x98: 0x2a, // asterisk
+ 0x99: 0x2019, // closing single quote
+ 0x9a: 0x2501, // box drawings heavy horizontal
+ 0x9b: 0xa9, // copyright sign
+ 0x9c: 0x2120, // Service mark
+ 0x9d: 0x2022, // (round) bullet
+ 0x9e: 0x201c, // Left double quotation mark
+ 0x9f: 0x201d, // Right double quotation mark
+ 0xa0: 0xc0, // uppercase A, grave accent
+ 0xa1: 0xc2, // uppercase A, circumflex
+ 0xa2: 0xc7, // uppercase C with cedilla
+ 0xa3: 0xc8, // uppercase E, grave accent
+ 0xa4: 0xca, // uppercase E, circumflex
+ 0xa5: 0xcb, // capital letter E with diaresis
+ 0xa6: 0xeb, // lowercase letter e with diaresis
+ 0xa7: 0xce, // uppercase I, circumflex
+ 0xa8: 0xcf, // uppercase I, with diaresis
+ 0xa9: 0xef, // lowercase i, with diaresis
+ 0xaa: 0xd4, // uppercase O, circumflex
+ 0xab: 0xd9, // uppercase U, grave accent
+ 0xac: 0xf9, // lowercase u, grave accent
+ 0xad: 0xdb, // uppercase U, circumflex
+ 0xae: 0xab, // left-pointing double angle quotation mark
+ 0xaf: 0xbb, // right-pointing double angle quotation mark
+ // THIS BLOCK INCLUDES THE 32 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS
+ // THAT COME FROM HI BYTE=0x13 AND LOW BETWEEN 0x20 AND 0x3F
+ 0xb0: 0xc3, // Uppercase A, tilde
+ 0xb1: 0xe3, // Lowercase a, tilde
+ 0xb2: 0xcd, // Uppercase I, acute accent
+ 0xb3: 0xcc, // Uppercase I, grave accent
+ 0xb4: 0xec, // Lowercase i, grave accent
+ 0xb5: 0xd2, // Uppercase O, grave accent
+ 0xb6: 0xf2, // Lowercase o, grave accent
+ 0xb7: 0xd5, // Uppercase O, tilde
+ 0xb8: 0xf5, // Lowercase o, tilde
+ 0xb9: 0x7b, // Open curly brace
+ 0xba: 0x7d, // Closing curly brace
+ 0xbb: 0x5c, // Backslash
+ 0xbc: 0x5e, // Caret
+ 0xbd: 0x5f, // Underscore
+ 0xbe: 0x7c, // Pipe (vertical line)
+ 0xbf: 0x223c, // Tilde operator
+ 0xc0: 0xc4, // Uppercase A, umlaut
+ 0xc1: 0xe4, // Lowercase A, umlaut
+ 0xc2: 0xd6, // Uppercase O, umlaut
+ 0xc3: 0xf6, // Lowercase o, umlaut
+ 0xc4: 0xdf, // Esszett (sharp S)
+ 0xc5: 0xa5, // Yen symbol
+ 0xc6: 0xa4, // Generic currency sign
+ 0xc7: 0x2503, // Box drawings heavy vertical
+ 0xc8: 0xc5, // Uppercase A, ring
+ 0xc9: 0xe5, // Lowercase A, ring
+ 0xca: 0xd8, // Uppercase O, stroke
+ 0xcb: 0xf8, // Lowercase o, strok
+ 0xcc: 0x250f, // Box drawings heavy down and right
+ 0xcd: 0x2513, // Box drawings heavy down and left
+ 0xce: 0x2517, // Box drawings heavy up and right
+ 0xcf: 0x251b // Box drawings heavy up and left
+ };
+
+ /**
+ * Get Unicode Character from CEA-608 byte code
+ */
+ var getCharForByte = function getCharForByte(byte) {
+ var charCode = byte;
+ if (specialCea608CharsCodes.hasOwnProperty(byte)) {
+ charCode = specialCea608CharsCodes[byte];
+ }
+ return String.fromCharCode(charCode);
+ };
+
+ var NR_ROWS = 15,
+ NR_COLS = 32;
+ // Tables to look up row from PAC data
+ var rowsLowCh1 = { 0x11: 1, 0x12: 3, 0x15: 5, 0x16: 7, 0x17: 9, 0x10: 11, 0x13: 12, 0x14: 14 };
+ var rowsHighCh1 = { 0x11: 2, 0x12: 4, 0x15: 6, 0x16: 8, 0x17: 10, 0x13: 13, 0x14: 15 };
+ var rowsLowCh2 = { 0x19: 1, 0x1A: 3, 0x1D: 5, 0x1E: 7, 0x1F: 9, 0x18: 11, 0x1B: 12, 0x1C: 14 };
+ var rowsHighCh2 = { 0x19: 2, 0x1A: 4, 0x1D: 6, 0x1E: 8, 0x1F: 10, 0x1B: 13, 0x1C: 15 };
+
+ var backgroundColors = ['white', 'green', 'blue', 'cyan', 'red', 'yellow', 'magenta', 'black', 'transparent'];
+
+ /**
+ * Simple logger class to be able to write with time-stamps and filter on level.
+ */
+ var logger = {
+ verboseFilter: { 'DATA': 3, 'DEBUG': 3, 'INFO': 2, 'WARNING': 2, 'TEXT': 1, 'ERROR': 0 },
+ time: null,
+ verboseLevel: 0, // Only write errors
+ setTime: function setTime(newTime) {
+ this.time = newTime;
+ },
+ log: function log(severity, msg) {
+ var minLevel = this.verboseFilter[severity];
+ if (this.verboseLevel >= minLevel) {
+ console.log(this.time + " [" + severity + "] " + msg);
+ }
+ }
+ };
+
+ var numArrayToHexArray = function numArrayToHexArray(numArray) {
+ var hexArray = [];
+ for (var j = 0; j < numArray.length; j++) {
+ hexArray.push(numArray[j].toString(16));
+ }
+ return hexArray;
+ };
+
+ /**
+ * State of CEA-608 pen or character
+ * @constructor
+ */
+ var PenState = function PenState(foreground, underline, italics, background, flash) {
+ this.foreground = foreground || "white";
+ this.underline = underline || false;
+ this.italics = italics || false;
+ this.background = background || "black";
+ this.flash = flash || false;
+ };
+
+ PenState.prototype = {
+
+ reset: function reset() {
+ this.foreground = "white";
+ this.underline = false;
+ this.italics = false;
+ this.background = "black";
+ this.flash = false;
+ },
+
+ setStyles: function setStyles(styles) {
+ var attribs = ["foreground", "underline", "italics", "background", "flash"];
+ for (var i = 0; i < attribs.length; i++) {
+ var style = attribs[i];
+ if (styles.hasOwnProperty(style)) {
+ this[style] = styles[style];
+ }
+ }
+ },
+
+ isDefault: function isDefault() {
+ return this.foreground === "white" && !this.underline && !this.italics && this.background === "black" && !this.flash;
+ },
+
+ equals: function equals(other) {
+ return this.foreground === other.foreground && this.underline === other.underline && this.italics === other.italics && this.background === other.background && this.flash === other.flash;
+ },
+
+ copy: function copy(newPenState) {
+ this.foreground = newPenState.foreground;
+ this.underline = newPenState.underline;
+ this.italics = newPenState.italics;
+ this.background = newPenState.background;
+ this.flash = newPenState.flash;
+ },
+
+ toString: function toString() {
+ return "color=" + this.foreground + ", underline=" + this.underline + ", italics=" + this.italics + ", background=" + this.background + ", flash=" + this.flash;
+ }
+ };
+
+ /**
+ * Unicode character with styling and background.
+ * @constructor
+ */
+ var StyledUnicodeChar = function StyledUnicodeChar(uchar, foreground, underline, italics, background, flash) {
+ this.uchar = uchar || ' '; // unicode character
+ this.penState = new PenState(foreground, underline, italics, background, flash);
+ };
+
+ StyledUnicodeChar.prototype = {
+
+ reset: function reset() {
+ this.uchar = ' ';
+ this.penState.reset();
+ },
+
+ setChar: function setChar(uchar, newPenState) {
+ this.uchar = uchar;
+ this.penState.copy(newPenState);
+ },
+
+ setPenState: function setPenState(newPenState) {
+ this.penState.copy(newPenState);
+ },
+
+ equals: function equals(other) {
+ return this.uchar === other.uchar && this.penState.equals(other.penState);
+ },
+
+ copy: function copy(newChar) {
+ this.uchar = newChar.uchar;
+ this.penState.copy(newChar.penState);
+ },
+
+ isEmpty: function isEmpty() {
+ return this.uchar === ' ' && this.penState.isDefault();
+ }
+ };
+
+ /**
+ * CEA-608 row consisting of NR_COLS instances of StyledUnicodeChar.
+ * @constructor
+ */
+ var Row = function Row() {
+ this.chars = [];
+ for (var i = 0; i < NR_COLS; i++) {
+ this.chars.push(new StyledUnicodeChar());
+ }
+ this.pos = 0;
+ this.currPenState = new PenState();
+ };
+
+ Row.prototype = {
+
+ equals: function equals(other) {
+ var equal = true;
+ for (var i = 0; i < NR_COLS; i++) {
+ if (!this.chars[i].equals(other.chars[i])) {
+ equal = false;
+ break;
+ }
+ }
+ return equal;
+ },
+
+ copy: function copy(other) {
+ for (var i = 0; i < NR_COLS; i++) {
+ this.chars[i].copy(other.chars[i]);
+ }
+ },
+
+ isEmpty: function isEmpty() {
+ var empty = true;
+ for (var i = 0; i < NR_COLS; i++) {
+ if (!this.chars[i].isEmpty()) {
+ empty = false;
+ break;
+ }
+ }
+ return empty;
+ },
+
+ /**
+ * Set the cursor to a valid column.
+ */
+ setCursor: function setCursor(absPos) {
+ if (this.pos !== absPos) {
+ this.pos = absPos;
+ }
+ if (this.pos < 0) {
+ logger.log("ERROR", "Negative cursor position " + this.pos);
+ this.pos = 0;
+ } else if (this.pos > NR_COLS) {
+ logger.log("ERROR", "Too large cursor position " + this.pos);
+ this.pos = NR_COLS;
+ }
+ },
+
+ /**
+ * Move the cursor relative to current position.
+ */
+ moveCursor: function moveCursor(relPos) {
+ var newPos = this.pos + relPos;
+ if (relPos > 1) {
+ for (var i = this.pos + 1; i < newPos + 1; i++) {
+ this.chars[i].setPenState(this.currPenState);
+ }
+ }
+ this.setCursor(newPos);
+ },
+
+ /**
+ * Backspace, move one step back and clear character.
+ */
+ backSpace: function backSpace() {
+ this.moveCursor(-1);
+ this.chars[this.pos].setChar(' ', this.currPenState);
+ },
+
+ insertChar: function insertChar(byte) {
+ if (byte >= 0x90) {
+ //Extended char
+ this.backSpace();
+ }
+ var char = getCharForByte(byte);
+ if (this.pos >= NR_COLS) {
+ logger.log("ERROR", "Cannot insert " + byte.toString(16) + " (" + char + ") at position " + this.pos + ". Skipping it!");
+ return;
+ }
+ this.chars[this.pos].setChar(char, this.currPenState);
+ this.moveCursor(1);
+ },
+
+ clearFromPos: function clearFromPos(startPos) {
+ var i;
+ for (i = startPos; i < NR_COLS; i++) {
+ this.chars[i].reset();
+ }
+ },
+
+ clear: function clear() {
+ this.clearFromPos(0);
+ this.pos = 0;
+ this.currPenState.reset();
+ },
+
+ clearToEndOfRow: function clearToEndOfRow() {
+ this.clearFromPos(this.pos);
+ },
+
+ getTextString: function getTextString() {
+ var chars = [];
+ var empty = true;
+ for (var i = 0; i < NR_COLS; i++) {
+ var char = this.chars[i].uchar;
+ if (char !== " ") {
+ empty = false;
+ }
+ chars.push(char);
+ }
+ if (empty) {
+ return "";
+ } else {
+ return chars.join("");
+ }
+ },
+
+ setPenStyles: function setPenStyles(styles) {
+ this.currPenState.setStyles(styles);
+ var currChar = this.chars[this.pos];
+ currChar.setPenState(this.currPenState);
+ }
+ };
+
+ /**
+ * Keep a CEA-608 screen of 32x15 styled characters
+ * @constructor
+ */
+ var CaptionScreen = function CaptionScreen() {
+
+ this.rows = [];
+ for (var i = 0; i < NR_ROWS; i++) {
+ this.rows.push(new Row()); // Note that we use zero-based numbering (0-14)
+ }
+ this.currRow = NR_ROWS - 1;
+ this.nrRollUpRows = null;
+ this.reset();
+ };
+
+ CaptionScreen.prototype = {
+
+ reset: function reset() {
+ for (var i = 0; i < NR_ROWS; i++) {
+ this.rows[i].clear();
+ }
+ this.currRow = NR_ROWS - 1;
+ },
+
+ equals: function equals(other) {
+ var equal = true;
+ for (var i = 0; i < NR_ROWS; i++) {
+ if (!this.rows[i].equals(other.rows[i])) {
+ equal = false;
+ break;
+ }
+ }
+ return equal;
+ },
+
+ copy: function copy(other) {
+ for (var i = 0; i < NR_ROWS; i++) {
+ this.rows[i].copy(other.rows[i]);
+ }
+ },
+
+ isEmpty: function isEmpty() {
+ var empty = true;
+ for (var i = 0; i < NR_ROWS; i++) {
+ if (!this.rows[i].isEmpty()) {
+ empty = false;
+ break;
+ }
+ }
+ return empty;
+ },
+
+ backSpace: function backSpace() {
+ var row = this.rows[this.currRow];
+ row.backSpace();
+ },
+
+ clearToEndOfRow: function clearToEndOfRow() {
+ var row = this.rows[this.currRow];
+ row.clearToEndOfRow();
+ },
+
+ /**
+ * Insert a character (without styling) in the current row.
+ */
+ insertChar: function insertChar(char) {
+ var row = this.rows[this.currRow];
+ row.insertChar(char);
+ },
+
+ setPen: function setPen(styles) {
+ var row = this.rows[this.currRow];
+ row.setPenStyles(styles);
+ },
+
+ moveCursor: function moveCursor(relPos) {
+ var row = this.rows[this.currRow];
+ row.moveCursor(relPos);
+ },
+
+ setCursor: function setCursor(absPos) {
+ logger.log("INFO", "setCursor: " + absPos);
+ var row = this.rows[this.currRow];
+ row.setCursor(absPos);
+ },
+
+ setPAC: function setPAC(pacData) {
+ logger.log("INFO", "pacData = " + JSON.stringify(pacData));
+ var newRow = pacData.row - 1;
+ if (this.nrRollUpRows && newRow < this.nrRollUpRows - 1) {
+ newRow = this.nrRollUpRows - 1;
+ }
+ this.currRow = newRow;
+ var row = this.rows[this.currRow];
+ if (pacData.indent !== null) {
+ var indent = pacData.indent;
+ var prevPos = Math.max(indent - 1, 0);
+ row.setCursor(pacData.indent);
+ pacData.color = row.chars[prevPos].penState.foreground;
+ }
+ var styles = { foreground: pacData.color, underline: pacData.underline, italics: pacData.italics, background: 'black', flash: false };
+ this.setPen(styles);
+ },
+
+ /**
+ * Set background/extra foreground, but first do back_space, and then insert space (backwards compatibility).
+ */
+ setBkgData: function setBkgData(bkgData) {
+
+ logger.log("INFO", "bkgData = " + JSON.stringify(bkgData));
+ this.backSpace();
+ this.setPen(bkgData);
+ this.insertChar(0x20); //Space
+ },
+
+ setRollUpRows: function setRollUpRows(nrRows) {
+ this.nrRollUpRows = nrRows;
+ },
+
+ rollUp: function rollUp() {
+ if (this.nrRollUpRows === null) {
+ logger.log("DEBUG", "roll_up but nrRollUpRows not set yet");
+ return; //Not properly setup
+ }
+ logger.log("TEXT", this.getDisplayText());
+ var topRowIndex = this.currRow + 1 - this.nrRollUpRows;
+ var topRow = this.rows.splice(topRowIndex, 1)[0];
+ topRow.clear();
+ this.rows.splice(this.currRow, 0, topRow);
+ logger.log("INFO", "Rolling up");
+ //logger.log("TEXT", this.get_display_text())
+ },
+
+ /**
+ * Get all non-empty rows with as unicode text.
+ */
+ getDisplayText: function getDisplayText(asOneRow) {
+ asOneRow = asOneRow || false;
+ var displayText = [];
+ var text = "";
+ var rowNr = -1;
+ for (var i = 0; i < NR_ROWS; i++) {
+ var rowText = this.rows[i].getTextString();
+ if (rowText) {
+ rowNr = i + 1;
+ if (asOneRow) {
+ displayText.push("Row " + rowNr + ': "' + rowText + '"');
+ } else {
+ displayText.push(rowText.trim());
+ }
+ }
+ }
+ if (displayText.length > 0) {
+ if (asOneRow) {
+ text = "[" + displayText.join(" | ") + "]";
+ } else {
+ text = displayText.join("\n");
+ }
+ }
+ return text;
+ },
+
+ getTextAndFormat: function getTextAndFormat() {
+ return this.rows;
+ }
+ };
+
+ /**
+ * Handle a CEA-608 channel and send decoded data to outputFilter
+ * @constructor
+ * @param {Number} channelNumber (1 or 2)
+ * @param {CueHandler} outputFilter Output from channel1 newCue(startTime, endTime, captionScreen)
+ */
+ var Cea608Channel = function Cea608Channel(channelNumber, outputFilter) {
+
+ this.chNr = channelNumber;
+ this.outputFilter = outputFilter;
+ this.mode = null;
+ this.verbose = 0;
+ this.displayedMemory = new CaptionScreen();
+ this.nonDisplayedMemory = new CaptionScreen();
+ this.lastOutputScreen = new CaptionScreen();
+ this.currRollUpRow = this.displayedMemory.rows[NR_ROWS - 1];
+ this.writeScreen = this.displayedMemory;
+ this.mode = null;
+ this.cueStartTime = null; // Keeps track of where a cue started.
+ };
+
+ Cea608Channel.prototype = {
+
+ modes: ["MODE_ROLL-UP", "MODE_POP-ON", "MODE_PAINT-ON", "MODE_TEXT"],
+
+ reset: function reset() {
+ this.mode = null;
+ this.displayedMemory.reset();
+ this.nonDisplayedMemory.reset();
+ this.lastOutputScreen.reset();
+ this.currRollUpRow = this.displayedMemory.rows[NR_ROWS - 1];
+ this.writeScreen = this.displayedMemory;
+ this.mode = null;
+ this.cueStartTime = null;
+ this.lastCueEndTime = null;
+ },
+
+ getHandler: function getHandler() {
+ return this.outputFilter;
+ },
+
+ setHandler: function setHandler(newHandler) {
+ this.outputFilter = newHandler;
+ },
+
+ setPAC: function setPAC(pacData) {
+ this.writeScreen.setPAC(pacData);
+ },
+
+ setBkgData: function setBkgData(bkgData) {
+ this.writeScreen.setBkgData(bkgData);
+ },
+
+ setMode: function setMode(newMode) {
+ if (newMode === this.mode) {
+ return;
+ }
+ this.mode = newMode;
+ logger.log("INFO", "MODE=" + newMode);
+ if (this.mode == "MODE_POP-ON") {
+ this.writeScreen = this.nonDisplayedMemory;
+ } else {
+ this.writeScreen = this.displayedMemory;
+ this.writeScreen.reset();
+ }
+ if (this.mode !== "MODE_ROLL-UP") {
+ this.displayedMemory.nrRollUpRows = null;
+ this.nonDisplayedMemory.nrRollUpRows = null;
+ }
+ this.mode = newMode;
+ },
+
+ insertChars: function insertChars(chars) {
+ for (var i = 0; i < chars.length; i++) {
+ this.writeScreen.insertChar(chars[i]);
+ }
+ var screen = this.writeScreen === this.displayedMemory ? "DISP" : "NON_DISP";
+ logger.log("INFO", screen + ": " + this.writeScreen.getDisplayText(true));
+ if (this.mode === "MODE_PAINT-ON" || this.mode === "MODE_ROLL-UP") {
+ logger.log("TEXT", "DISPLAYED: " + this.displayedMemory.getDisplayText(true));
+ this.outputDataUpdate();
+ }
+ },
+
+ cc_RCL: function cc_RCL() {
+ // Resume Caption Loading (switch mode to Pop On)
+ logger.log("INFO", "RCL - Resume Caption Loading");
+ this.setMode("MODE_POP-ON");
+ },
+ cc_BS: function cc_BS() {
+ // BackSpace
+ logger.log("INFO", "BS - BackSpace");
+ if (this.mode === "MODE_TEXT") {
+ return;
+ }
+ this.writeScreen.backSpace();
+ if (this.writeScreen === this.displayedMemory) {
+ this.outputDataUpdate();
+ }
+ },
+ cc_AOF: function cc_AOF() {
+ // Reserved (formerly Alarm Off)
+ return;
+ },
+ cc_AON: function cc_AON() {
+ // Reserved (formerly Alarm On)
+ return;
+ },
+ cc_DER: function cc_DER() {
+ // Delete to End of Row
+ logger.log("INFO", "DER- Delete to End of Row");
+ this.writeScreen.clearToEndOfRow();
+ this.outputDataUpdate();
+ },
+ cc_RU: function cc_RU(nrRows) {
+ //Roll-Up Captions-2,3,or 4 Rows
+ logger.log("INFO", "RU(" + nrRows + ") - Roll Up");
+ this.writeScreen = this.displayedMemory;
+ this.setMode("MODE_ROLL-UP");
+ this.writeScreen.setRollUpRows(nrRows);
+ },
+ cc_FON: function cc_FON() {
+ //Flash On
+ logger.log("INFO", "FON - Flash On");
+ this.writeScreen.setPen({ flash: true });
+ },
+ cc_RDC: function cc_RDC() {
+ // Resume Direct Captioning (switch mode to PaintOn)
+ logger.log("INFO", "RDC - Resume Direct Captioning");
+ this.setMode("MODE_PAINT-ON");
+ },
+ cc_TR: function cc_TR() {
+ // Text Restart in text mode (not supported, however)
+ logger.log("INFO", "TR");
+ this.setMode("MODE_TEXT");
+ },
+ cc_RTD: function cc_RTD() {
+ // Resume Text Display in Text mode (not supported, however)
+ logger.log("INFO", "RTD");
+ this.setMode("MODE_TEXT");
+ },
+ cc_EDM: function cc_EDM() {
+ // Erase Displayed Memory
+ logger.log("INFO", "EDM - Erase Displayed Memory");
+ this.displayedMemory.reset();
+ this.outputDataUpdate();
+ },
+ cc_CR: function cc_CR() {
+ // Carriage Return
+ logger.log("CR - Carriage Return");
+ this.writeScreen.rollUp();
+ this.outputDataUpdate();
+ },
+ cc_ENM: function cc_ENM() {
+ //Erase Non-Displayed Memory
+ logger.log("INFO", "ENM - Erase Non-displayed Memory");
+ this.nonDisplayedMemory.reset();
+ },
+ cc_EOC: function cc_EOC() {
+ //End of Caption (Flip Memories)
+ logger.log("INFO", "EOC - End Of Caption");
+ if (this.mode === "MODE_POP-ON") {
+ var tmp = this.displayedMemory;
+ this.displayedMemory = this.nonDisplayedMemory;
+ this.nonDisplayedMemory = tmp;
+ this.writeScreen = this.nonDisplayedMemory;
+ logger.log("TEXT", "DISP: " + this.displayedMemory.getDisplayText());
+ }
+ this.outputDataUpdate();
+ },
+ cc_TO: function cc_TO(nrCols) {
+ // Tab Offset 1,2, or 3 columns
+ logger.log("INFO", "TO(" + nrCols + ") - Tab Offset");
+ this.writeScreen.moveCursor(nrCols);
+ },
+ cc_MIDROW: function cc_MIDROW(secondByte) {
+ // Parse MIDROW command
+ var styles = { flash: false };
+ styles.underline = secondByte % 2 === 1;
+ styles.italics = secondByte >= 0x2e;
+ if (!styles.italics) {
+ var colorIndex = Math.floor(secondByte / 2) - 0x10;
+ var colors = ["white", "green", "blue", "cyan", "red", "yellow", "magenta"];
+ styles.foreground = colors[colorIndex];
+ } else {
+ styles.foreground = "white";
+ }
+ logger.log("INFO", "MIDROW: " + JSON.stringify(styles));
+ this.writeScreen.setPen(styles);
+ },
+
+ outputDataUpdate: function outputDataUpdate() {
+ var t = logger.time;
+ if (t === null) {
+ return;
+ }
+ if (this.outputFilter) {
+ if (this.outputFilter.updateData) {
+ this.outputFilter.updateData(t, this.displayedMemory);
+ }
+ if (this.cueStartTime === null && !this.displayedMemory.isEmpty()) {
+ // Start of a new cue
+ this.cueStartTime = t;
+ } else {
+ if (!this.displayedMemory.equals(this.lastOutputScreen)) {
+ if (this.outputFilter.newCue) {
+ this.outputFilter.newCue(this.cueStartTime, t, this.lastOutputScreen);
+ }
+ this.cueStartTime = this.displayedMemory.isEmpty() ? null : t;
+ }
+ }
+ this.lastOutputScreen.copy(this.displayedMemory);
+ }
+ },
+
+ cueSplitAtTime: function cueSplitAtTime(t) {
+ if (this.outputFilter) {
+ if (!this.displayedMemory.isEmpty()) {
+ if (this.outputFilter.newCue) {
+ this.outputFilter.newCue(this.cueStartTime, t, this.displayedMemory);
+ }
+ this.cueStartTime = t;
+ }
+ }
+ }
+ };
+
+ /**
+ * Parse CEA-608 data and send decoded data to out1 and out2.
+ * @constructor
+ * @param {Number} field CEA-608 field (1 or 2)
+ * @param {CueHandler} out1 Output from channel1 newCue(startTime, endTime, captionScreen)
+ * @param {CueHandler} out2 Output from channel2 newCue(startTime, endTime, captionScreen)
+ */
+ var Cea608Parser = function Cea608Parser(field, out1, out2) {
+ this.field = field || 1;
+ this.outputs = [out1, out2];
+ this.channels = [new Cea608Channel(1, out1), new Cea608Channel(2, out2)];
+ this.currChNr = -1; // Will be 1 or 2
+ this.lastCmdA = null; // First byte of last command
+ this.lastCmdB = null; // Second byte of last command
+ this.bufferedData = [];
+ this.startTime = null;
+ this.lastTime = null;
+ this.dataCounters = { 'padding': 0, 'char': 0, 'cmd': 0, 'other': 0 };
+ };
+
+ Cea608Parser.prototype = {
+
+ getHandler: function getHandler(index) {
+ return this.channels[index].getHandler();
+ },
+
+ setHandler: function setHandler(index, newHandler) {
+ this.channels[index].setHandler(newHandler);
+ },
+
+ /**
+ * Add data for time t in forms of list of bytes (unsigned ints). The bytes are treated as pairs.
+ */
+ addData: function addData(t, byteList) {
+ var cmdFound,
+ a,
+ b,
+ charsFound = false;
+
+ this.lastTime = t;
+ logger.setTime(t);
+
+ for (var i = 0; i < byteList.length; i += 2) {
+ a = byteList[i] & 0x7f;
+ b = byteList[i + 1] & 0x7f;
+ if (a === 0 && b === 0) {
+ this.dataCounters.padding += 2;
+ continue;
+ } else {
+ logger.log("DATA", "[" + numArrayToHexArray([byteList[i], byteList[i + 1]]) + "] -> (" + numArrayToHexArray([a, b]) + ")");
+ }
+ cmdFound = this.parseCmd(a, b);
+ if (!cmdFound) {
+ cmdFound = this.parseMidrow(a, b);
+ }
+ if (!cmdFound) {
+ cmdFound = this.parsePAC(a, b);
+ }
+ if (!cmdFound) {
+ cmdFound = this.parseBackgroundAttributes(a, b);
+ }
+ if (!cmdFound) {
+ charsFound = this.parseChars(a, b);
+ if (charsFound) {
+ if (this.currChNr && this.currChNr >= 0) {
+ var channel = this.channels[this.currChNr - 1];
+ channel.insertChars(charsFound);
+ } else {
+ logger.log("WARNING", "No channel found yet. TEXT-MODE?");
+ }
+ }
+ }
+ if (cmdFound) {
+ this.dataCounters.cmd += 2;
+ } else if (charsFound) {
+ this.dataCounters.char += 2;
+ } else {
+ this.dataCounters.other += 2;
+ logger.log("WARNING", "Couldn't parse cleaned data " + numArrayToHexArray([a, b]) + " orig: " + numArrayToHexArray([byteList[i], byteList[i + 1]]));
+ }
+ }
+ },
+
+ /**
+ * Parse Command.
+ * @returns {Boolean} Tells if a command was found
+ */
+ parseCmd: function parseCmd(a, b) {
+ var chNr = null;
+
+ var cond1 = (a === 0x14 || a === 0x1C) && 0x20 <= b && b <= 0x2F;
+ var cond2 = (a === 0x17 || a === 0x1F) && 0x21 <= b && b <= 0x23;
+ if (!(cond1 || cond2)) {
+ return false;
+ }
+
+ if (a === this.lastCmdA && b === this.lastCmdB) {
+ this.lastCmdA = null;
+ this.lastCmdB = null; // Repeated commands are dropped (once)
+ logger.log("DEBUG", "Repeated command (" + numArrayToHexArray([a, b]) + ") is dropped");
+ return true;
+ }
+
+ if (a === 0x14 || a === 0x17) {
+ chNr = 1;
+ } else {
+ chNr = 2; // (a === 0x1C || a=== 0x1f)
+ }
+
+ var channel = this.channels[chNr - 1];
+
+ if (a === 0x14 || a === 0x1C) {
+ if (b === 0x20) {
+ channel.cc_RCL();
+ } else if (b === 0x21) {
+ channel.cc_BS();
+ } else if (b === 0x22) {
+ channel.cc_AOF();
+ } else if (b === 0x23) {
+ channel.cc_AON();
+ } else if (b === 0x24) {
+ channel.cc_DER();
+ } else if (b === 0x25) {
+ channel.cc_RU(2);
+ } else if (b === 0x26) {
+ channel.cc_RU(3);
+ } else if (b === 0x27) {
+ channel.cc_RU(4);
+ } else if (b === 0x28) {
+ channel.cc_FON();
+ } else if (b === 0x29) {
+ channel.cc_RDC();
+ } else if (b === 0x2A) {
+ channel.cc_TR();
+ } else if (b === 0x2B) {
+ channel.cc_RTD();
+ } else if (b === 0x2C) {
+ channel.cc_EDM();
+ } else if (b === 0x2D) {
+ channel.cc_CR();
+ } else if (b === 0x2E) {
+ channel.cc_ENM();
+ } else if (b === 0x2F) {
+ channel.cc_EOC();
+ }
+ } else {
+ //a == 0x17 || a == 0x1F
+ channel.cc_TO(b - 0x20);
+ }
+ this.lastCmdA = a;
+ this.lastCmdB = b;
+ this.currChNr = chNr;
+ return true;
+ },
+
+ /**
+ * Parse midrow styling command
+ * @returns {Boolean}
+ */
+ parseMidrow: function parseMidrow(a, b) {
+ var chNr = null;
+
+ if ((a === 0x11 || a === 0x19) && 0x20 <= b && b <= 0x2f) {
+ if (a === 0x11) {
+ chNr = 1;
+ } else {
+ chNr = 2;
+ }
+ if (chNr !== this.currChNr) {
+ logger.log("ERROR", "Mismatch channel in midrow parsing");
+ return false;
+ }
+ var channel = this.channels[chNr - 1];
+ channel.cc_MIDROW(b);
+ logger.log("DEBUG", "MIDROW (" + numArrayToHexArray([a, b]) + ")");
+ return true;
+ }
+ return false;
+ },
+ /**
+ * Parse Preable Access Codes (Table 53).
+ * @returns {Boolean} Tells if PAC found
+ */
+ parsePAC: function parsePAC(a, b) {
+
+ var chNr = null;
+ var row = null;
+
+ var case1 = (0x11 <= a && a <= 0x17 || 0x19 <= a && a <= 0x1F) && 0x40 <= b && b <= 0x7F;
+ var case2 = (a === 0x10 || a === 0x18) && 0x40 <= b && b <= 0x5F;
+ if (!(case1 || case2)) {
+ return false;
+ }
+
+ if (a === this.lastCmdA && b === this.lastCmdB) {
+ this.lastCmdA = null;
+ this.lastCmdB = null;
+ return true; // Repeated commands are dropped (once)
+ }
+
+ chNr = a <= 0x17 ? 1 : 2;
+
+ if (0x40 <= b && b <= 0x5F) {
+ row = chNr === 1 ? rowsLowCh1[a] : rowsLowCh2[a];
+ } else {
+ // 0x60 <= b <= 0x7F
+ row = chNr === 1 ? rowsHighCh1[a] : rowsHighCh2[a];
+ }
+ var pacData = this.interpretPAC(row, b);
+ var channel = this.channels[chNr - 1];
+ channel.setPAC(pacData);
+ this.lastCmdA = a;
+ this.lastCmdB = b;
+ this.currChNr = chNr;
+ return true;
+ },
+
+ /**
+ * Interpret the second byte of the pac, and return the information.
+ * @returns {Object} pacData with style parameters.
+ */
+ interpretPAC: function interpretPAC(row, byte) {
+ var pacIndex = byte;
+ var pacData = { color: null, italics: false, indent: null, underline: false, row: row };
+
+ if (byte > 0x5F) {
+ pacIndex = byte - 0x60;
+ } else {
+ pacIndex = byte - 0x40;
+ }
+ pacData.underline = (pacIndex & 1) === 1;
+ if (pacIndex <= 0xd) {
+ pacData.color = ['white', 'green', 'blue', 'cyan', 'red', 'yellow', 'magenta', 'white'][Math.floor(pacIndex / 2)];
+ } else if (pacIndex <= 0xf) {
+ pacData.italics = true;
+ pacData.color = 'white';
+ } else {
+ pacData.indent = Math.floor((pacIndex - 0x10) / 2) * 4;
+ }
+ return pacData; // Note that row has zero offset. The spec uses 1.
+ },
+
+ /**
+ * Parse characters.
+ * @returns An array with 1 to 2 codes corresponding to chars, if found. null otherwise.
+ */
+ parseChars: function parseChars(a, b) {
+
+ var channelNr = null,
+ charCodes = null,
+ charCode1 = null,
+ charCode2 = null;
+
+ if (a >= 0x19) {
+ channelNr = 2;
+ charCode1 = a - 8;
+ } else {
+ channelNr = 1;
+ charCode1 = a;
+ }
+ if (0x11 <= charCode1 && charCode1 <= 0x13) {
+ // Special character
+ var oneCode = b;
+ if (charCode1 === 0x11) {
+ oneCode = b + 0x50;
+ } else if (charCode1 === 0x12) {
+ oneCode = b + 0x70;
+ } else {
+ oneCode = b + 0x90;
+ }
+ logger.log("INFO", "Special char '" + getCharForByte(oneCode) + "' in channel " + channelNr);
+ charCodes = [oneCode];
+ } else if (0x20 <= a && a <= 0x7f) {
+ charCodes = b === 0 ? [a] : [a, b];
+ }
+ if (charCodes) {
+ var hexCodes = numArrayToHexArray(charCodes);
+ logger.log("DEBUG", "Char codes = " + hexCodes.join(","));
+ this.lastCmdA = null;
+ this.lastCmdB = null;
+ }
+ return charCodes;
+ },
+
+ /**
+ * Parse extended background attributes as well as new foreground color black.
+ * @returns{Boolean} Tells if background attributes are found
+ */
+ parseBackgroundAttributes: function parseBackgroundAttributes(a, b) {
+ var bkgData, index, chNr, channel;
+
+ var case1 = (a === 0x10 || a === 0x18) && 0x20 <= b && b <= 0x2f;
+ var case2 = (a === 0x17 || a === 0x1f) && 0x2d <= b && b <= 0x2f;
+ if (!(case1 || case2)) {
+ return false;
+ }
+ bkgData = {};
+ if (a === 0x10 || a === 0x18) {
+ index = Math.floor((b - 0x20) / 2);
+ bkgData.background = backgroundColors[index];
+ if (b % 2 === 1) {
+ bkgData.background = bkgData.background + "_semi";
+ }
+ } else if (b === 0x2d) {
+ bkgData.background = "transparent";
+ } else {
+ bkgData.foreground = "black";
+ if (b === 0x2f) {
+ bkgData.underline = true;
+ }
+ }
+ chNr = a < 0x18 ? 1 : 2;
+ channel = this.channels[chNr - 1];
+ channel.setBkgData(bkgData);
+ this.lastCmdA = null;
+ this.lastCmdB = null;
+ return true;
+ },
+
+ /**
+ * Reset state of parser and its channels.
+ */
+ reset: function reset() {
+ for (var i = 0; i < this.channels.length; i++) {
+ if (this.channels[i]) {
+ this.channels[i].reset();
+ }
+ }
+ this.lastCmdA = null;
+ this.lastCmdB = null;
+ },
+
+ /**
+ * Trigger the generation of a cue, and the start of a new one if displayScreens are not empty.
+ */
+ cueSplitAtTime: function cueSplitAtTime(t) {
+ for (var i = 0; i < this.channels.length; i++) {
+ if (this.channels[i]) {
+ this.channels[i].cueSplitAtTime(t);
+ }
+ }
+ }
+ };
+
+ /**
+ * Find ranges corresponding to SEA CEA-608 NALUS in sizeprepended NALU array.
+ * @param {raw} dataView of binary data
+ * @param {startPos} start position in raw
+ * @param {size} total size of data in raw to consider
+ * @returns
+ */
+ var findCea608Nalus = function findCea608Nalus(raw, startPos, size) {
+ var nalSize = 0,
+ cursor = startPos,
+ nalType = 0,
+ cea608NaluRanges = [],
+
+ // Check SEI data according to ANSI-SCTE 128
+ isCEA608SEI = function isCEA608SEI(payloadType, payloadSize, raw, pos) {
+ if (payloadType !== 4 || payloadSize < 8) {
+ return null;
+ }
+ var countryCode = raw.getUint8(pos);
+ var providerCode = raw.getUint16(pos + 1);
+ var userIdentifier = raw.getUint32(pos + 3);
+ var userDataTypeCode = raw.getUint8(pos + 7);
+ return countryCode == 0xB5 && providerCode == 0x31 && userIdentifier == 0x47413934 && userDataTypeCode == 0x3;
+ };
+ while (cursor < startPos + size) {
+ nalSize = raw.getUint32(cursor);
+ nalType = raw.getUint8(cursor + 4) & 0x1F;
+ //console.log(time + " NAL " + nalType);
+ if (nalType === 6) {
+ // SEI NAL Unit. The NAL header is the first byte
+ //console.log("SEI NALU of size " + nalSize + " at time " + time);
+ var pos = cursor + 5;
+ var payloadType = -1;
+ while (pos < cursor + 4 + nalSize - 1) {
+ // The last byte should be rbsp_trailing_bits
+ payloadType = 0;
+ var b = 0xFF;
+ while (b === 0xFF) {
+ b = raw.getUint8(pos);
+ payloadType += b;
+ pos++;
+ }
+ var payloadSize = 0;
+ b = 0xFF;
+ while (b === 0xFF) {
+ b = raw.getUint8(pos);
+ payloadSize += b;
+ pos++;
+ }
+ if (isCEA608SEI(payloadType, payloadSize, raw, pos)) {
+ //console.log("CEA608 SEI " + time + " " + payloadSize);
+ cea608NaluRanges.push([pos, payloadSize]);
+ }
+ pos += payloadSize;
+ }
+ }
+ cursor += nalSize + 4;
+ }
+ return cea608NaluRanges;
+ };
+
+ var extractCea608DataFromRange = function extractCea608DataFromRange(raw, cea608Range) {
+ var pos = cea608Range[0];
+ var fieldData = [[], []];
+
+ pos += 8; // Skip the identifier up to userDataTypeCode
+ var ccCount = raw.getUint8(pos) & 0x1f;
+ pos += 2; // Advance 1 and skip reserved byte
+
+ for (var i = 0; i < ccCount; i++) {
+ var byte = raw.getUint8(pos);
+ var ccValid = byte & 0x4;
+ var ccType = byte & 0x3;
+ pos++;
+ var ccData1 = raw.getUint8(pos); // Keep parity bit
+ pos++;
+ var ccData2 = raw.getUint8(pos); // Keep parity bit
+ pos++;
+ if (ccValid && (ccData1 & 0x7f) + (ccData2 & 0x7f) !== 0) {
+ //Check validity and non-empty data
+ if (ccType === 0) {
+ fieldData[0].push(ccData1);
+ fieldData[0].push(ccData2);
+ } else if (ccType === 1) {
+ fieldData[1].push(ccData1);
+ fieldData[1].push(ccData2);
+ }
+ }
+ }
+ return fieldData;
+ };
+
+ exports.logger = logger;
+ exports.PenState = PenState;
+ exports.CaptionScreen = CaptionScreen;
+ exports.Cea608Parser = Cea608Parser;
+ exports.findCea608Nalus = findCea608Nalus;
+ exports.extractCea608DataFromRange = extractCea608DataFromRange;
+})(typeof exports === 'undefined' ? undefined.cea608parser = {} : exports);
+
+},{}],3:[function(_dereq_,module,exports){
+/*
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * author Digital Primates
+ * copyright dash-if 2012
+ */
+
+/*
+ * var parent,
+ * child,
+ * properties = [
+ {
+ name: 'profiles',
+ merge: false
+ }
+ ];
+ *
+ * parent = {};
+ * parent.name = "ParentNode";
+ * parent.isRoor = false;
+ * parent.isArray = false;
+ * parent.children = [];
+ * parent.properties = properties;
+ *
+ * child = {};
+ * child.name = "ChildNode";
+ * child.isRoor = false;
+ * child.isArray = true;
+ * child.children = null;
+ * child.properties = properties;
+ * parent.children.push(child);
+ *
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+function ObjectIron(map) {
+
+ var lookup, len, i;
+
+ // create a list of top level items to search for
+ lookup = [];
+ for (i = 0, len = map.length; i < len; i += 1) {
+ if (map[i].isRoot) {
+ lookup.push("root");
+ } else {
+ lookup.push(map[i].name);
+ }
+ }
+
+ var mergeValues = function mergeValues(parentItem, childItem) {
+ var name, parentValue, childValue;
+
+ if (parentItem === null || childItem === null) {
+ return;
+ }
+
+ for (name in parentItem) {
+ if (parentItem.hasOwnProperty(name)) {
+ if (!childItem.hasOwnProperty(name)) {
+ childItem[name] = parentItem[name];
+ }
+ }
+ }
+ },
+ mapProperties = function mapProperties(properties, parent, child) {
+ var i, len, property, parentValue, childValue;
+
+ if (properties === null || properties.length === 0) {
+ return;
+ }
+
+ for (i = 0, len = properties.length; i < len; i += 1) {
+ property = properties[i];
+
+ if (parent.hasOwnProperty(property.name)) {
+ if (child.hasOwnProperty(property.name)) {
+ // check to see if we should merge
+ if (property.merge) {
+ parentValue = parent[property.name];
+ childValue = child[property.name];
+
+ // complex objects; merge properties
+ if (typeof parentValue === 'object' && typeof childValue === 'object') {
+ mergeValues(parentValue, childValue);
+ }
+ // simple objects; merge them together
+ else {
+ if (property.mergeFunction != null) {
+ child[property.name] = property.mergeFunction(parentValue, childValue);
+ } else {
+ child[property.name] = parentValue + childValue;
+ }
+ }
+ }
+ } else {
+ // just add the property
+ child[property.name] = parent[property.name];
+ }
+ }
+ }
+ },
+ mapItem = function mapItem(obj, node) {
+ var item = obj,
+ i,
+ len,
+ v,
+ len2,
+ array,
+ childItem,
+ childNode,
+ property;
+
+ if (item.children === null || item.children.length === 0) {
+ return;
+ }
+
+ for (i = 0, len = item.children.length; i < len; i += 1) {
+ childItem = item.children[i];
+
+ if (node.hasOwnProperty(childItem.name)) {
+ if (childItem.isArray) {
+ array = node[childItem.name + "_asArray"];
+ for (v = 0, len2 = array.length; v < len2; v += 1) {
+ childNode = array[v];
+ mapProperties(item.properties, node, childNode);
+ mapItem(childItem, childNode);
+ }
+ } else {
+ childNode = node[childItem.name];
+ mapProperties(item.properties, node, childNode);
+ mapItem(childItem, childNode);
+ }
+ }
+ }
+ },
+ performMapping = function performMapping(source) {
+ var i, len, pi, pp, item, node, array;
+
+ if (source === null) {
+ return source;
+ }
+
+ if (typeof source !== 'object') {
+ return source;
+ }
+
+ // first look to see if anything cares about the root node
+ for (i = 0, len = lookup.length; i < len; i += 1) {
+ if (lookup[i] === "root") {
+ item = map[i];
+ node = source;
+ mapItem(item, node);
+ }
+ }
+
+ // iterate over the objects and look for any of the items we care about
+ for (pp in source) {
+ if (source.hasOwnProperty(pp) && pp != "__children") {
+ pi = lookup.indexOf(pp);
+ if (pi !== -1) {
+ item = map[pi];
+
+ if (item.isArray) {
+ array = source[pp + "_asArray"];
+ for (i = 0, len = array.length; i < len; i += 1) {
+ node = array[i];
+ mapItem(item, node);
+ }
+ } else {
+ node = source[pp];
+ mapItem(item, node);
+ }
+ }
+ // now check this to see if he has any of the properties we care about
+ performMapping(source[pp]);
+ }
+ }
+
+ return source;
+ };
+
+ return {
+ run: performMapping
+ };
+}
+
+exports['default'] = ObjectIron;
+module.exports = exports['default'];
+
+},{}],4:[function(_dereq_,module,exports){
+/*
+ Copyright 2011 Abdulla Abdurakhmanov
+ Original sources are available at https://code.google.com/p/x2js/
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+/*
+ Modified to keep track of children nodes in order in attribute __children.
+*/
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+function X2JS(matchers, attrPrefix, ignoreRoot) {
+ if (attrPrefix === null || attrPrefix === undefined) {
+ attrPrefix = "_";
+ }
+
+ if (ignoreRoot === null || ignoreRoot === undefined) {
+ ignoreRoot = false;
+ }
+
+ var VERSION = "1.0.11";
+ var escapeMode = false;
+
+ var DOMNodeTypes = {
+ ELEMENT_NODE: 1,
+ TEXT_NODE: 3,
+ CDATA_SECTION_NODE: 4,
+ COMMENT_NODE: 8,
+ DOCUMENT_NODE: 9
+ };
+
+ function getNodeLocalName(node) {
+ var nodeLocalName = node.localName;
+ if (nodeLocalName == null) // Yeah, this is IE!!
+ nodeLocalName = node.baseName;
+ if (nodeLocalName == null || nodeLocalName == "") // =="" is IE too
+ nodeLocalName = node.nodeName;
+ return nodeLocalName;
+ }
+
+ function getNodePrefix(node) {
+ return node.prefix;
+ }
+
+ function escapeXmlChars(str) {
+ if (typeof str == "string") return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#x27;').replace(/\//g, '&#x2F;');else return str;
+ }
+
+ function unescapeXmlChars(str) {
+ return str.replace(/&amp;/g, '&').replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&quot;/g, '"').replace(/&#x27;/g, "'").replace(/&#x2F;/g, '\/');
+ }
+
+ function parseDOMChildren(node) {
+ if (node.nodeType == DOMNodeTypes.DOCUMENT_NODE) {
+ var result,
+ child = node.firstChild,
+ i,
+ len;
+
+ // get the first node that isn't a comment
+ for (i = 0, len = node.childNodes.length; i < len; i += 1) {
+ if (node.childNodes[i].nodeType !== DOMNodeTypes.COMMENT_NODE) {
+ child = node.childNodes[i];
+ break;
+ }
+ }
+
+ if (ignoreRoot) {
+ result = parseDOMChildren(child);
+ } else {
+ result = {};
+ var childName = getNodeLocalName(child);
+ result[childName] = parseDOMChildren(child);
+ }
+
+ return result;
+ } else if (node.nodeType == DOMNodeTypes.ELEMENT_NODE) {
+ var result = new Object();
+ result.__cnt = 0;
+
+ var children = [];
+
+ var nodeChildren = node.childNodes;
+
+ // Children nodes
+ for (var cidx = 0; cidx < nodeChildren.length; cidx++) {
+ var child = nodeChildren.item(cidx); // nodeChildren[cidx];
+ var childName = getNodeLocalName(child);
+
+ result.__cnt++;
+ if (result[childName] == null) {
+ var c = parseDOMChildren(child);
+ if (childName != "#text" || /[^\s]/.test(c)) {
+ var o = {};
+ o[childName] = c;
+ children.push(o);
+ }
+ result[childName] = c;
+ result[childName + "_asArray"] = new Array(1);
+ result[childName + "_asArray"][0] = result[childName];
+ } else {
+ if (result[childName] != null) {
+ if (!(result[childName] instanceof Array)) {
+ var tmpObj = result[childName];
+ result[childName] = new Array();
+ result[childName][0] = tmpObj;
+
+ result[childName + "_asArray"] = result[childName];
+ }
+ }
+ var aridx = 0;
+ while (result[childName][aridx] != null) aridx++;
+
+ var c = parseDOMChildren(child);
+ if (childName != "#text" || /[^\s]/.test(c)) {
+ // Don't add white-space text nodes
+ var o = {};
+ o[childName] = c;
+ children.push(o);
+ }
+ result[childName][aridx] = c;
+ }
+ }
+
+ result.__children = children;
+
+ // Attributes
+ for (var aidx = 0; aidx < node.attributes.length; aidx++) {
+ var attr = node.attributes.item(aidx); // [aidx];
+ result.__cnt++;
+
+ var value2 = attr.value;
+ for (var m = 0, ml = matchers.length; m < ml; m++) {
+ var matchobj = matchers[m];
+ if (matchobj.test(attr)) {
+ value2 = matchobj.converter(attr.value);
+ }
+ }
+
+ result[attrPrefix + attr.name] = value2;
+ }
+
+ // Node namespace prefix
+ var nodePrefix = getNodePrefix(node);
+ if (nodePrefix != null && nodePrefix != "") {
+ result.__cnt++;
+ result.__prefix = nodePrefix;
+ }
+
+ if (result.__cnt == 1 && result["#text"] != null) {
+ result = result["#text"];
+ }
+
+ if (result["#text"] != null) {
+ result.__text = result["#text"];
+ if (escapeMode) result.__text = unescapeXmlChars(result.__text);
+ delete result["#text"];
+ delete result["#text_asArray"];
+ }
+ if (result["#cdata-section"] != null) {
+ result.__cdata = result["#cdata-section"];
+ delete result["#cdata-section"];
+ delete result["#cdata-section_asArray"];
+ }
+
+ if (result.__text != null || result.__cdata != null) {
+ result.toString = function () {
+ return (this.__text != null ? this.__text : '') + (this.__cdata != null ? this.__cdata : '');
+ };
+ }
+ return result;
+ } else if (node.nodeType == DOMNodeTypes.TEXT_NODE || node.nodeType == DOMNodeTypes.CDATA_SECTION_NODE) {
+ return node.nodeValue;
+ } else if (node.nodeType == DOMNodeTypes.COMMENT_NODE) {
+ return null;
+ }
+ }
+
+ function startTag(jsonObj, element, attrList, closed) {
+ var resultStr = "<" + (jsonObj != null && jsonObj.__prefix != null ? jsonObj.__prefix + ":" : "") + element;
+ if (attrList != null) {
+ for (var aidx = 0; aidx < attrList.length; aidx++) {
+ var attrName = attrList[aidx];
+ var attrVal = jsonObj[attrName];
+ resultStr += " " + attrName.substr(1) + "='" + attrVal + "'";
+ }
+ }
+ if (!closed) resultStr += ">";else resultStr += "/>";
+ return resultStr;
+ }
+
+ function endTag(jsonObj, elementName) {
+ return "</" + (jsonObj.__prefix != null ? jsonObj.__prefix + ":" : "") + elementName + ">";
+ }
+
+ function endsWith(str, suffix) {
+ return str.indexOf(suffix, str.length - suffix.length) !== -1;
+ }
+
+ function jsonXmlSpecialElem(jsonObj, jsonObjField) {
+ if (endsWith(jsonObjField.toString(), "_asArray") || jsonObjField.toString().indexOf("_") == 0 || jsonObj[jsonObjField] instanceof Function) return true;else return false;
+ }
+
+ function jsonXmlElemCount(jsonObj) {
+ var elementsCnt = 0;
+ if (jsonObj instanceof Object) {
+ for (var it in jsonObj) {
+ if (jsonXmlSpecialElem(jsonObj, it)) continue;
+ elementsCnt++;
+ }
+ }
+ return elementsCnt;
+ }
+
+ function parseJSONAttributes(jsonObj) {
+ var attrList = [];
+ if (jsonObj instanceof Object) {
+ for (var ait in jsonObj) {
+ if (ait.toString().indexOf("__") == -1 && ait.toString().indexOf("_") == 0) {
+ attrList.push(ait);
+ }
+ }
+ }
+ return attrList;
+ }
+
+ function parseJSONTextAttrs(jsonTxtObj) {
+ var result = "";
+
+ if (jsonTxtObj.__cdata != null) {
+ result += "<![CDATA[" + jsonTxtObj.__cdata + "]]>";
+ }
+
+ if (jsonTxtObj.__text != null) {
+ if (escapeMode) result += escapeXmlChars(jsonTxtObj.__text);else result += jsonTxtObj.__text;
+ }
+ return result;
+ }
+
+ function parseJSONTextObject(jsonTxtObj) {
+ var result = "";
+
+ if (jsonTxtObj instanceof Object) {
+ result += parseJSONTextAttrs(jsonTxtObj);
+ } else if (jsonTxtObj != null) {
+ if (escapeMode) result += escapeXmlChars(jsonTxtObj);else result += jsonTxtObj;
+ }
+
+ return result;
+ }
+
+ function parseJSONArray(jsonArrRoot, jsonArrObj, attrList) {
+ var result = "";
+ if (jsonArrRoot.length == 0) {
+ result += startTag(jsonArrRoot, jsonArrObj, attrList, true);
+ } else {
+ for (var arIdx = 0; arIdx < jsonArrRoot.length; arIdx++) {
+ result += startTag(jsonArrRoot[arIdx], jsonArrObj, parseJSONAttributes(jsonArrRoot[arIdx]), false);
+ result += parseJSONObject(jsonArrRoot[arIdx]);
+ result += endTag(jsonArrRoot[arIdx], jsonArrObj);
+ }
+ }
+ return result;
+ }
+
+ function parseJSONObject(jsonObj) {
+ var result = "";
+
+ var elementsCnt = jsonXmlElemCount(jsonObj);
+
+ if (elementsCnt > 0) {
+ for (var it in jsonObj) {
+
+ if (jsonXmlSpecialElem(jsonObj, it)) continue;
+
+ var subObj = jsonObj[it];
+
+ var attrList = parseJSONAttributes(subObj);
+
+ if (subObj == null || subObj == undefined) {
+ result += startTag(subObj, it, attrList, true);
+ } else if (subObj instanceof Object) {
+
+ if (subObj instanceof Array) {
+ result += parseJSONArray(subObj, it, attrList);
+ } else {
+ var subObjElementsCnt = jsonXmlElemCount(subObj);
+ if (subObjElementsCnt > 0 || subObj.__text != null || subObj.__cdata != null) {
+ result += startTag(subObj, it, attrList, false);
+ result += parseJSONObject(subObj);
+ result += endTag(subObj, it);
+ } else {
+ result += startTag(subObj, it, attrList, true);
+ }
+ }
+ } else {
+ result += startTag(subObj, it, attrList, false);
+ result += parseJSONTextObject(subObj);
+ result += endTag(subObj, it);
+ }
+ }
+ }
+ result += parseJSONTextObject(jsonObj);
+
+ return result;
+ }
+
+ this.parseXmlString = function (xmlDocStr) {
+ var xmlDoc, parser, ns;
+
+ if (window.DOMParser) {
+ parser = new window.DOMParser();
+
+ try {
+ ns = parser.parseFromString('<', 'text/xml').getElementsByTagName("parsererror")[0].namespaceURI;
+ } catch (e) {
+ // IE11 will definitely throw SyntaxError here
+ // ns will be undefined
+ }
+
+ try {
+ xmlDoc = parser.parseFromString(xmlDocStr, "text/xml");
+
+ if (ns) {
+ if (xmlDoc.getElementsByTagNameNS(ns, 'parsererror').length) {
+ xmlDoc = undefined;
+ }
+ }
+ } catch (e) {
+ // IE11 may throw SyntaxError here if xmlDocStr is
+ // not well formed. xmlDoc will be undefined
+ }
+ } else {
+ // IE :(
+ if (xmlDocStr.indexOf("<?") == 0) {
+ xmlDocStr = xmlDocStr.substr(xmlDocStr.indexOf("?>") + 2);
+ }
+ xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
+ xmlDoc.async = "false";
+ xmlDoc.loadXML(xmlDocStr);
+ }
+ return xmlDoc;
+ };
+
+ this.xml2json = function (xmlDoc) {
+ return parseDOMChildren(xmlDoc);
+ };
+
+ this.xml_str2json = function (xmlDocStr) {
+ var xmlDoc = this.parseXmlString(xmlDocStr);
+ return xmlDoc ? this.xml2json(xmlDoc) : undefined;
+ };
+
+ this.json2xml_str = function (jsonObj) {
+ return parseJSONObject(jsonObj);
+ };
+
+ this.json2xml = function (jsonObj) {
+ var xmlDocStr = this.json2xml_str(jsonObj);
+ return this.parseXmlString(xmlDocStr);
+ };
+
+ this.getVersion = function () {
+ return VERSION;
+ };
+
+ this.escapeMode = function (enabled) {
+ escapeMode = enabled;
+ };
+}
+exports["default"] = X2JS;
+module.exports = exports["default"];
+
+},{}],5:[function(_dereq_,module,exports){
+(function (global){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _srcStreamingMediaPlayer = _dereq_(51);
+
+var _srcStreamingMediaPlayer2 = _interopRequireDefault(_srcStreamingMediaPlayer);
+
+var _srcStreamingProtectionProtection = _dereq_(106);
+
+var _srcStreamingProtectionProtection2 = _interopRequireDefault(_srcStreamingProtectionProtection);
+
+var _srcStreamingMetricsMetricsReporting = _dereq_(75);
+
+var _srcStreamingMetricsMetricsReporting2 = _interopRequireDefault(_srcStreamingMetricsMetricsReporting);
+
+var _srcStreamingMediaPlayerFactory = _dereq_(53);
+
+var _srcStreamingMediaPlayerFactory2 = _interopRequireDefault(_srcStreamingMediaPlayerFactory);
+
+var _srcCoreVersion = _dereq_(11);
+
+// Shove both of these into the global scope
+var context = window || global;
+
+var dashjs = context.dashjs;
+if (!dashjs) {
+ dashjs = context.dashjs = {};
+}
+
+dashjs.MediaPlayer = _srcStreamingMediaPlayer2['default'];
+dashjs.Protection = _srcStreamingProtectionProtection2['default'];
+dashjs.MetricsReporting = _srcStreamingMetricsMetricsReporting2['default'];
+dashjs.MediaPlayerFactory = _srcStreamingMediaPlayerFactory2['default'];
+dashjs.Version = (0, _srcCoreVersion.getVersionString)();
+
+exports['default'] = dashjs;
+exports.MediaPlayer = _srcStreamingMediaPlayer2['default'];
+exports.Protection = _srcStreamingProtectionProtection2['default'];
+exports.MetricsReporting = _srcStreamingMetricsMetricsReporting2['default'];
+exports.MediaPlayerFactory = _srcStreamingMediaPlayerFactory2['default'];
+
+}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
+
+},{"106":106,"11":11,"51":51,"53":53,"75":75}],6:[function(_dereq_,module,exports){
+/*! codem-isoboxer v0.2.2 https://github.com/madebyhiro/codem-isoboxer/blob/master/LICENSE.txt */
+var ISOBoxer = {};
+
+ISOBoxer.parseBuffer = function(arrayBuffer) {
+ return new ISOFile(arrayBuffer).parse();
+};
+
+ISOBoxer.Utils = {};
+ISOBoxer.Utils.dataViewToString = function(dataView, encoding) {
+ var impliedEncoding = encoding || 'utf-8'
+ if (typeof TextDecoder !== 'undefined') {
+ return new TextDecoder(impliedEncoding).decode(dataView);
+ }
+ var a = [];
+ var i = 0;
+
+ if (impliedEncoding === 'utf-8') {
+ /* The following algorithm is essentially a rewrite of the UTF8.decode at
+ http://bannister.us/weblog/2007/simple-base64-encodedecode-javascript/
+ */
+
+ while (i < dataView.byteLength) {
+ var c = dataView.getUint8(i++);
+ if (c < 0x80) {
+ // 1-byte character (7 bits)
+ } else if (c < 0xe0) {
+ // 2-byte character (11 bits)
+ c = (c & 0x1f) << 6;
+ c |= (dataView.getUint8(i++) & 0x3f);
+ } else if (c < 0xf0) {
+ // 3-byte character (16 bits)
+ c = (c & 0xf) << 12;
+ c |= (dataView.getUint8(i++) & 0x3f) << 6;
+ c |= (dataView.getUint8(i++) & 0x3f);
+ } else {
+ // 4-byte character (21 bits)
+ c = (c & 0x7) << 18;
+ c |= (dataView.getUint8(i++) & 0x3f) << 12;
+ c |= (dataView.getUint8(i++) & 0x3f) << 6;
+ c |= (dataView.getUint8(i++) & 0x3f);
+ }
+ a.push(String.fromCharCode(c));
+ }
+ } else { // Just map byte-by-byte (probably wrong)
+ while (i < dataView.byteLength) {
+ a.push(String.fromCharCode(dataView.getUint8(i++)));
+ }
+ }
+ return a.join('');
+};
+
+if (typeof exports !== 'undefined') {
+ exports.parseBuffer = ISOBoxer.parseBuffer;
+ exports.Utils = ISOBoxer.Utils;
+};
+ISOBoxer.Cursor = function(initialOffset) {
+ this.offset = (typeof initialOffset == 'undefined' ? 0 : initialOffset);
+};
+var ISOFile = function(arrayBuffer) {
+ this._raw = new DataView(arrayBuffer);
+ this._cursor = new ISOBoxer.Cursor();
+ this.boxes = [];
+}
+
+ISOFile.prototype.fetch = function(type) {
+ var result = this.fetchAll(type, true);
+ return (result.length ? result[0] : null);
+}
+
+ISOFile.prototype.fetchAll = function(type, returnEarly) {
+ var result = [];
+ ISOFile._sweep.call(this, type, result, returnEarly);
+ return result;
+}
+
+ISOFile.prototype.parse = function() {
+ this._cursor.offset = 0;
+ this.boxes = [];
+ while (this._cursor.offset < this._raw.byteLength) {
+ var box = ISOBox.parse(this);
+
+ // Box could not be parsed
+ if (typeof box.type === 'undefined') break;
+
+ this.boxes.push(box);
+ }
+ return this;
+}
+
+ISOFile._sweep = function(type, result, returnEarly) {
+ if (this.type && this.type == type) result.push(this);
+ for (var box in this.boxes) {
+ if (result.length && returnEarly) return;
+ ISOFile._sweep.call(this.boxes[box], type, result, returnEarly);
+ }
+};
+var ISOBox = function() {
+ this._cursor = new ISOBoxer.Cursor();
+}
+
+ISOBox.parse = function(parent) {
+ var newBox = new ISOBox();
+ newBox._offset = parent._cursor.offset;
+ newBox._root = (parent._root ? parent._root : parent);
+ newBox._raw = parent._raw;
+ newBox._parent = parent;
+ newBox._parseBox();
+ parent._cursor.offset = newBox._raw.byteOffset + newBox._raw.byteLength;
+ return newBox;
+}
+
+ISOBox.prototype._readInt = function(size) {
+ var result = null;
+ switch(size) {
+ case 8:
+ result = this._raw.getInt8(this._cursor.offset - this._raw.byteOffset);
+ break;
+ case 16:
+ result = this._raw.getInt16(this._cursor.offset - this._raw.byteOffset);
+ break;
+ case 32:
+ result = this._raw.getInt32(this._cursor.offset - this._raw.byteOffset);
+ break;
+ case 64:
+ // Warning: JavaScript cannot handle 64-bit integers natively.
+ // This will give unexpected results for integers >= 2^53
+ var s1 = this._raw.getInt32(this._cursor.offset - this._raw.byteOffset);
+ var s2 = this._raw.getInt32(this._cursor.offset - this._raw.byteOffset + 4);
+ result = (s1 * Math.pow(2,32)) + s2;
+ break;
+ }
+ this._cursor.offset += (size >> 3);
+ return result;
+}
+
+ISOBox.prototype._readUint = function(size) {
+ var result = null;
+ switch(size) {
+ case 8:
+ result = this._raw.getUint8(this._cursor.offset - this._raw.byteOffset);
+ break;
+ case 16:
+ result = this._raw.getUint16(this._cursor.offset - this._raw.byteOffset);
+ break;
+ case 24:
+ var s1 = this._raw.getUint16(this._cursor.offset - this._raw.byteOffset);
+ var s2 = this._raw.getUint8(this._cursor.offset - this._raw.byteOffset + 2);
+ result = (s1 << 8) + s2;
+ break;
+ case 32:
+ result = this._raw.getUint32(this._cursor.offset - this._raw.byteOffset);
+ break;
+ case 64:
+ // Warning: JavaScript cannot handle 64-bit integers natively.
+ // This will give unexpected results for integers >= 2^53
+ var s1 = this._raw.getUint32(this._cursor.offset - this._raw.byteOffset);
+ var s2 = this._raw.getUint32(this._cursor.offset - this._raw.byteOffset + 4);
+ result = (s1 * Math.pow(2,32)) + s2;
+ break;
+ }
+ this._cursor.offset += (size >> 3);
+ return result;
+}
+
+ISOBox.prototype._readString = function(length) {
+ var str = '';
+ for (var c = 0; c < length; c++) {
+ var char = this._readUint(8);
+ str += String.fromCharCode(char);
+ }
+ return str;
+}
+
+ISOBox.prototype._readTerminatedString = function() {
+ var str = '';
+ while (true) {
+ var char = this._readUint(8);
+ if (char == 0) break;
+ str += String.fromCharCode(char);
+ }
+ return str;
+}
+
+ISOBox.prototype._readTemplate = function(size) {
+ var pre = this._readUint(size / 2);
+ var post = this._readUint(size / 2);
+ return pre + (post / Math.pow(2, size / 2));
+}
+
+ISOBox.prototype._parseBox = function() {
+ this._cursor.offset = this._offset;
+
+ // return immediately if there are not enough bytes to read the header
+ if (this._offset + 8 > this._raw.buffer.byteLength) {
+ this._root._incomplete = true;
+ return;
+ }
+
+ this.size = this._readUint(32);
+ this.type = this._readString(4);
+
+ if (this.size == 1) { this.largesize = this._readUint(64); }
+ if (this.type == 'uuid') { this.usertype = this._readString(16); }
+
+ switch(this.size) {
+ case 0:
+ this._raw = new DataView(this._raw.buffer, this._offset, (this._raw.byteLength - this._cursor.offset));
+ break;
+ case 1:
+ if (this._offset + this.size > this._raw.buffer.byteLength) {
+ this._incomplete = true;
+ this._root._incomplete = true;
+ } else {
+ this._raw = new DataView(this._raw.buffer, this._offset, this.largesize);
+ }
+ break;
+ default:
+ if (this._offset + this.size > this._raw.buffer.byteLength) {
+ this._incomplete = true;
+ this._root._incomplete = true;
+ } else {
+ this._raw = new DataView(this._raw.buffer, this._offset, this.size);
+ }
+ }
+
+ // additional parsing
+ if (!this._incomplete && this._boxParsers[this.type]) this._boxParsers[this.type].call(this);
+}
+
+ISOBox.prototype._parseFullBox = function() {
+ this.version = this._readUint(8);
+ this.flags = this._readUint(24);
+}
+
+ISOBox.prototype._boxParsers = {};;
+// Simple container boxes, all from ISO/IEC 14496-12:2012 except vttc which is from 14496-30.
+[
+ 'moov', 'trak', 'tref', 'mdia', 'minf', 'stbl', 'edts', 'dinf',
+ 'mvex', 'moof', 'traf', 'mfra', 'udta', 'meco', 'strk', 'vttc'
+].forEach(function(boxType) {
+ ISOBox.prototype._boxParsers[boxType] = function() {
+ this.boxes = [];
+ while (this._cursor.offset - this._raw.byteOffset < this._raw.byteLength) {
+ this.boxes.push(ISOBox.parse(this));
+ }
+ }
+})
+;
+// ISO/IEC 14496-12:2012 - 8.6.6 Edit List Box
+ISOBox.prototype._boxParsers['elst'] = function() {
+ this._parseFullBox();
+ this.entry_count = this._readUint(32);
+ this.entries = [];
+
+ for (var i=1; i <= this.entry_count; i++) {
+ var entry = {};
+ if (this.version == 1) {
+ entry.segment_duration = this._readUint(64);
+ entry.media_time = this._readInt(64);
+ } else {
+ entry.segment_duration = this._readUint(32);
+ entry.media_time = this._readInt(32);
+ }
+ entry.media_rate_integer = this._readInt(16);
+ entry.media_rate_fraction = this._readInt(16);
+ this.entries.push(entry);
+ }
+};
+// ISO/IEC 23009-1:2014 - 5.10.3.3 Event Message Box
+ISOBox.prototype._boxParsers['emsg'] = function() {
+ this._parseFullBox();
+ this.scheme_id_uri = this._readTerminatedString();
+ this.value = this._readTerminatedString();
+ this.timescale = this._readUint(32);
+ this.presentation_time_delta = this._readUint(32);
+ this.event_duration = this._readUint(32);
+ this.id = this._readUint(32);
+ this.message_data = new DataView(this._raw.buffer, this._cursor.offset, this._raw.byteLength - (this._cursor.offset - this._offset));
+};
+// ISO/IEC 14496-12:2012 - 8.1.2 Free Space Box
+ISOBox.prototype._boxParsers['free'] = ISOBox.prototype._boxParsers['skip'] = function() {
+ this.data = new DataView(this._raw.buffer, this._cursor.offset, this._raw.byteLength - (this._cursor.offset - this._offset));
+};
+// ISO/IEC 14496-12:2012 - 4.3 File Type Box / 8.16.2 Segment Type Box
+ISOBox.prototype._boxParsers['ftyp'] = ISOBox.prototype._boxParsers['styp'] = function() {
+ this.major_brand = this._readString(4);
+ this.minor_versions = this._readUint(32);
+ this.compatible_brands = [];
+
+ while (this._cursor.offset - this._raw.byteOffset < this._raw.byteLength) {
+ this.compatible_brands.push(this._readString(4));
+ }
+};
+// ISO/IEC 14496-12:2012 - 8.4.3 Handler Reference Box
+ISOBox.prototype._boxParsers['hdlr'] = function() {
+ this._parseFullBox();
+ this.pre_defined = this._readUint(32);
+ this.handler_type = this._readString(4);
+ this.reserved = [this._readUint(32), this._readUint(32), this._readUint(32)]
+ this.name = this._readTerminatedString()
+};
+// ISO/IEC 14496-12:2012 - 8.1.1 Media Data Box
+ISOBox.prototype._boxParsers['mdat'] = function() {
+ this.data = new DataView(this._raw.buffer, this._cursor.offset, this._raw.byteLength - (this._cursor.offset - this._offset));
+};
+// ISO/IEC 14496-12:2012 - 8.4.2 Media Header Box
+ISOBox.prototype._boxParsers['mdhd'] = function() {
+ this._parseFullBox();
+ if (this.version == 1) {
+ this.creation_time = this._readUint(64);
+ this.modification_time = this._readUint(64);
+ this.timescale = this._readUint(32);
+ this.duration = this._readUint(64);
+ } else {
+ this.creation_time = this._readUint(32);
+ this.modification_time = this._readUint(32);
+ this.timescale = this._readUint(32);
+ this.duration = this._readUint(32);
+ }
+ var language = this._readUint(16);
+ this.pad = (language >> 15);
+ this.language = String.fromCharCode(
+ ((language >> 10) & 0x1F) + 0x60,
+ ((language >> 5) & 0x1F) + 0x60,
+ (language & 0x1F) + 0x60
+ );
+ this.pre_defined = this._readUint(16);
+};
+// ISO/IEC 14496-12:2012 - 8.8.5 Movie Fragment Header Box
+ISOBox.prototype._boxParsers['mfhd'] = function() {
+ this._parseFullBox();
+ this.sequence_number = this._readUint(32);
+};
+// ISO/IEC 14496-12:2012 - 8.2.2 Movie Header Box
+ISOBox.prototype._boxParsers['mvhd'] = function() {
+ this._parseFullBox();
+
+ if (this.version == 1) {
+ this.creation_time = this._readUint(64);
+ this.modification_time = this._readUint(64);
+ this.timescale = this._readUint(32);
+ this.duration = this._readUint(64);
+ } else {
+ this.creation_time = this._readUint(32);
+ this.modification_time = this._readUint(32);
+ this.timescale = this._readUint(32);
+ this.duration = this._readUint(32);
+ }
+
+ this.rate = this._readTemplate(32);
+ this.volume = this._readTemplate(16);
+ this.reserved1 = this._readUint(16);
+ this.reserved2 = [ this._readUint(32), this._readUint(32) ];
+ this.matrix = [];
+ for (var i=0; i<9; i++) {
+ this.matrix.push(this._readTemplate(32));
+ }
+ this.pre_defined = [];
+ for (var i=0; i<6; i++) {
+ this.pre_defined.push(this._readUint(32));
+ }
+ this.next_track_ID = this._readUint(32);
+};
+// ISO/IEC 14496-30:2014 - WebVTT Cue Payload Box.
+ISOBox.prototype._boxParsers['payl'] = function() {
+ var cue_text_raw = new DataView(this._raw.buffer, this._cursor.offset, this._raw.byteLength - (this._cursor.offset - this._offset));
+ this.cue_text = ISOBoxer.Utils.dataViewToString(cue_text_raw);
+}
+;
+// ISO/IEC 14496-12:2012 - 8.16.3 Segment Index Box
+ISOBox.prototype._boxParsers['sidx'] = function() {
+ this._parseFullBox();
+ this.reference_ID = this._readUint(32);
+ this.timescale = this._readUint(32);
+ if (this.version == 0) {
+ this.earliest_presentation_time = this._readUint(32);
+ this.first_offset = this._readUint(32);
+ } else {
+ this.earliest_presentation_time = this._readUint(64);
+ this.first_offset = this._readUint(64);
+ }
+ this.reserved = this._readUint(16);
+ this.reference_count = this._readUint(16);
+ this.references = [];
+ for (var i=0; i<this.reference_count; i++) {
+ var ref = {};
+ var reference = this._readUint(32);
+ ref.reference_type = (reference >> 31) & 0x1;
+ ref.referenced_size = reference & 0x7FFFFFFF;
+ ref.subsegment_duration = this._readUint(32);
+ var sap = this._readUint(32);
+ ref.starts_with_SAP = (sap >> 31) & 0x1;
+ ref.SAP_type = (sap >> 28) & 0x7;
+ ref.SAP_delta_time = sap & 0xFFFFFFF;
+ this.references.push(ref);
+ }
+};
+// ISO/IEC 14496-12:2012 - 8.16.4 Subsegment Index Box
+ISOBox.prototype._boxParsers['ssix'] = function() {
+ this._parseFullBox();
+ this.subsegment_count = this._readUint(32);
+ this.subsegments = [];
+
+ for (var i=0; i<this.subsegment_count; i++) {
+ var subsegment = {};
+ subsegment.ranges_count = this._readUint(32);
+ subsegment.ranges = [];
+
+ for (var j=0; j<subsegment.ranges_count; j++) {
+ var range = {};
+ range.level = this._readUint(8);
+ range.range_size = this._readUint(24);
+ subsegment.ranges.push(range);
+ }
+ this.subsegments.push(subsegment);
+ }
+};
+// ISO/IEC 14496-12:2012 - 8.8.12 Track Fragmnent Decode Time
+ISOBox.prototype._boxParsers['tfdt'] = function() {
+ this._parseFullBox();
+ if (this.version == 1) {
+ this.baseMediaDecodeTime = this._readUint(64);
+ } else {
+ this.baseMediaDecodeTime = this._readUint(32);
+ }
+};
+// ISO/IEC 14496-12:2012 - 8.8.7 Track Fragment Header Box
+ISOBox.prototype._boxParsers['tfhd'] = function() {
+ this._parseFullBox();
+ this.track_ID = this._readUint(32);
+ if (this.flags & 0x1) this.base_data_offset = this._readUint(64);
+ if (this.flags & 0x2) this.sample_description_offset = this._readUint(32);
+ if (this.flags & 0x8) this.default_sample_duration = this._readUint(32);
+ if (this.flags & 0x10) this.default_sample_size = this._readUint(32);
+ if (this.flags & 0x20) this.default_sample_flags = this._readUint(32);
+};
+// ISO/IEC 14496-12:2012 - 8.3.2 Track Header Box
+ISOBox.prototype._boxParsers['tkhd'] = function() {
+ this._parseFullBox();
+
+ if (this.version == 1) {
+ this.creation_time = this._readUint(64);
+ this.modification_time = this._readUint(64);
+ this.track_ID = this._readUint(32);
+ this.reserved1 = this._readUint(32);
+ this.duration = this._readUint(64);
+ } else {
+ this.creation_time = this._readUint(32);
+ this.modification_time = this._readUint(32);
+ this.track_ID = this._readUint(32);
+ this.reserved1 = this._readUint(32);
+ this.duration = this._readUint(32);
+ }
+
+ this.reserved2 = [
+ this._readUint(32),
+ this._readUint(32)
+ ];
+ this.layer = this._readUint(16);
+ this.alternate_group = this._readUint(16);
+ this.volume = this._readTemplate(16);
+ this.reserved3 = this._readUint(16);
+ this.matrix = [];
+ for (var i=0; i<9; i++) {
+ this.matrix.push(this._readTemplate(32));
+ }
+ this.width = this._readUint(32);
+ this.height = this._readUint(32);
+};
+// ISO/IEC 14496-12:2012 - 8.8.8 Track Run Box
+// Note: the 'trun' box has a direct relation to the 'tfhd' box for defaults.
+// These defaults are not set explicitly here, but are left to resolve for the user.
+ISOBox.prototype._boxParsers['trun'] = function() {
+ this._parseFullBox();
+ this.sample_count = this._readUint(32);
+ if (this.flags & 0x1) this.data_offset = this._readInt(32);
+ if (this.flags & 0x4) this.first_sample_flags = this._readUint(32);
+ this.samples = [];
+ for (var i=0; i<this.sample_count; i++) {
+ var sample = {};
+ if (this.flags & 0x100) sample.sample_duration = this._readUint(32);
+ if (this.flags & 0x200) sample.sample_size = this._readUint(32);
+ if (this.flags & 0x400) sample.sample_flags = this._readUint(32);
+ if (this.flags & 0x800) {
+ if (this.version == 0) {
+ sample.sample_composition_time_offset = this._readUint(32);
+ } else {
+ sample.sample_composition_time_offset = this._readInt(32);
+ }
+ }
+ this.samples.push(sample);
+ }
+};
+// ISO/IEC 14496-30:2014 - WebVTT Source Label Box
+ISOBox.prototype._boxParsers['vlab'] = function() {
+ var source_label_raw = new DataView(this._raw.buffer, this._cursor.offset, this._raw.byteLength - (this._cursor.offset - this._offset));
+ this.source_label = ISOBoxer.Utils.dataViewToString(source_label_raw);
+}
+;
+// ISO/IEC 14496-30:2014 - WebVTT Configuration Box
+ISOBox.prototype._boxParsers['vttC'] = function() {
+ var config_raw = new DataView(this._raw.buffer, this._cursor.offset, this._raw.byteLength - (this._cursor.offset - this._offset));
+ this.config = ISOBoxer.Utils.dataViewToString(config_raw);
+}
+;
+// ISO/IEC 14496-30:2014 - WebVTT Empty Sample Box
+ISOBox.prototype._boxParsers['vtte'] = function() {
+ // Nothing should happen here.
+}
+
+},{}],7:[function(_dereq_,module,exports){
+/**
+ * Decimal adjustment of a number.
+ *
+ * @param {String} type The type of adjustment.
+ * @param {Number} value The number.
+ * @param {Integer} exp The exponent (the 10 logarithm of the adjustment base).
+ * @returns {Number} The adjusted value.
+ */
+var decimalAdjust = exports.decimalAdjust = function(type, value, exp) {
+ // If the exp is undefined or zero...
+ if (typeof exp === 'undefined' || +exp === 0) {
+ return Math[type](value);
+ }
+ value = +value;
+ exp = +exp;
+ // If the value is not a number or the exp is not an integer...
+ if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0)) {
+ return NaN;
+ }
+ // Shift
+ value = value.toString().split('e');
+ value = Math[type](+(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp)));
+ // Shift back
+ value = value.toString().split('e');
+ return +(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp));
+}
+
+module.exports = {
+ round10: function(value, exp) {
+ return decimalAdjust('round', value, exp);
+ },
+ floor10: function(value, exp) {
+ return decimalAdjust('floor', value, exp);
+ },
+ ceil10: function(value, exp) {
+ return decimalAdjust('ceil', value, exp);
+ },
+};
+
+module.exports.polyfill = function() {
+ // Decimal round
+ if (!Math.round10) {
+ Math.round10 = module.exports.round10;
+ }
+ // Decimal floor
+ if (!Math.floor10) {
+ Math.floor10 = module.exports.floor10;
+ }
+ // Decimal ceil
+ if (!Math.ceil10) {
+ Math.ceil10 = module.exports.ceil10;
+ }
+};
+
+},{}],8:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _EventBus = _dereq_(9);
+
+var _EventBus2 = _interopRequireDefault(_EventBus);
+
+var _eventsEvents = _dereq_(13);
+
+var _eventsEvents2 = _interopRequireDefault(_eventsEvents);
+
+var _FactoryMaker = _dereq_(10);
+
+var _FactoryMaker2 = _interopRequireDefault(_FactoryMaker);
+
+/**
+ * @module Debug
+ */
+function Debug() {
+
+ var context = this.context;
+ var eventBus = (0, _EventBus2['default'])(context).getInstance();
+
+ var instance = undefined,
+ logToBrowserConsole = undefined,
+ showLogTimestamp = undefined,
+ startTime = undefined;
+
+ function setup() {
+ logToBrowserConsole = true;
+ showLogTimestamp = true;
+ startTime = new Date().getTime();
+ }
+
+ /**
+ * Prepends a timestamp in milliseconds to each log message.
+ * @param {boolean} value Set to true if you want to see a timestamp in each log message.
+ * @default false
+ * @memberof module:Debug
+ * @instance
+ */
+ function setLogTimestampVisible(value) {
+ showLogTimestamp = value;
+ }
+ /**
+ * Toggles logging to the browser's javascript console. If you set to false you will still receive a log event with the same message.
+ * @param {boolean} value Set to false if you want to turn off logging to the browser's console.
+ * @default true
+ * @memberof module:Debug
+ * @instance
+ */
+ function setLogToBrowserConsole(value) {
+ logToBrowserConsole = value;
+ }
+ /**
+ * Use this method to get the state of logToBrowserConsole.
+ * @returns {boolean} The current value of logToBrowserConsole
+ * @memberof module:Debug
+ * @instance
+ */
+ function getLogToBrowserConsole() {
+ return logToBrowserConsole;
+ }
+ /**
+ * This method will allow you send log messages to either the browser's console and/or dispatch an event to capture at the media player level.
+ * @param {...*} arguments The message you want to log. The Arguments object is supported for this method so you can send in comma separated logging items.
+ * @memberof module:Debug
+ * @instance
+ */
+ function log() {
+
+ var message = '';
+ var logTime = null;
+
+ if (showLogTimestamp) {
+ logTime = new Date().getTime();
+ message += '[' + (logTime - startTime) + ']';
+ }
+
+ if (message.length > 0) {
+ message += ' ';
+ }
+
+ Array.apply(null, arguments).forEach(function (item) {
+ message += item + ' ';
+ });
+
+ if (logToBrowserConsole) {
+ console.log(message);
+ }
+
+ eventBus.trigger(_eventsEvents2['default'].LOG, { message: message });
+ }
+
+ instance = {
+ log: log,
+ setLogTimestampVisible: setLogTimestampVisible,
+ setLogToBrowserConsole: setLogToBrowserConsole,
+ getLogToBrowserConsole: getLogToBrowserConsole
+ };
+
+ setup();
+
+ return instance;
+}
+
+Debug.__dashjs_factory_name = 'Debug';
+exports['default'] = _FactoryMaker2['default'].getSingletonFactory(Debug);
+module.exports = exports['default'];
+
+},{"10":10,"13":13,"9":9}],9:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _FactoryMaker = _dereq_(10);
+
+var _FactoryMaker2 = _interopRequireDefault(_FactoryMaker);
+
+var EVENT_PRIORITY_LOW = 0;
+var EVENT_PRIORITY_HIGH = 5000;
+
+function EventBus() {
+
+ var handlers = {};
+
+ function on(type, listener, scope) {
+ var priority = arguments.length <= 3 || arguments[3] === undefined ? EVENT_PRIORITY_LOW : arguments[3];
+
+ if (!type) {
+ throw new Error('event type cannot be null or undefined');
+ }
+ if (!listener || typeof listener !== 'function') {
+ throw new Error('listener must be a function: ' + listener);
+ }
+
+ if (getHandlerIdx(type, listener, scope) >= 0) return;
+
+ handlers[type] = handlers[type] || [];
+
+ var handler = {
+ callback: listener,
+ scope: scope,
+ priority: priority
+ };
+
+ var inserted = handlers[type].some(function (item, idx) {
+ if (priority > item.priority) {
+ handlers[type].splice(idx, 0, handler);
+ return true;
+ }
+ });
+
+ if (!inserted) {
+ handlers[type].push(handler);
+ }
+ }
+
+ function off(type, listener, scope) {
+ if (!type || !listener || !handlers[type]) return;
+ var idx = getHandlerIdx(type, listener, scope);
+ if (idx < 0) return;
+ handlers[type].splice(idx, 1);
+ }
+
+ function trigger(type, payload) {
+ if (!type || !handlers[type]) return;
+
+ payload = payload || {};
+
+ if (payload.hasOwnProperty('type')) throw new Error('\'type\' is a reserved word for event dispatching');
+
+ payload.type = type;
+
+ handlers[type].forEach(function (handler) {
+ return handler.callback.call(handler.scope, payload);
+ });
+ }
+
+ function getHandlerIdx(type, listener, scope) {
+
+ var idx = -1;
+
+ if (!handlers[type]) return idx;
+
+ handlers[type].some(function (item, index) {
+ if (item.callback === listener && (!scope || scope === item.scope)) {
+ idx = index;
+ return true;
+ }
+ });
+ return idx;
+ }
+
+ function reset() {
+ handlers = {};
+ }
+
+ var instance = {
+ on: on,
+ off: off,
+ trigger: trigger,
+ reset: reset
+ };
+
+ return instance;
+}
+
+EventBus.__dashjs_factory_name = 'EventBus';
+var factory = _FactoryMaker2['default'].getSingletonFactory(EventBus);
+factory.EVENT_PRIORITY_LOW = EVENT_PRIORITY_LOW;
+factory.EVENT_PRIORITY_HIGH = EVENT_PRIORITY_HIGH;
+exports['default'] = factory;
+module.exports = exports['default'];
+
+},{"10":10}],10:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @module FactoryMaker
+ */
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+var FactoryMaker = (function () {
+
+ var instance = undefined;
+ var extensions = [];
+ var singletonContexts = [];
+
+ function extend(name, childInstance, override, context) {
+ var extensionContext = getExtensionContext(context);
+ if (!extensionContext[name] && childInstance) {
+ extensionContext[name] = { instance: childInstance, override: override };
+ }
+ }
+
+ /**
+ * Use this method from your extended object. this.factory is injected into your object.
+ * this.factory.getSingletonInstance(this.context, 'VideoModel')
+ * will return the video model for use in the extended object.
+ *
+ * @param {Object} context - injected into extended object as this.context
+ * @param {string} className - string name found in all dash.js objects
+ * with name __dashjs_factory_name Will be at the bottom. Will be the same as the object's name.
+ * @returns {*} Context aware instance of specified singleton name.
+ * @memberof module:FactoryMaker
+ * @instance
+ */
+ function getSingletonInstance(context, className) {
+ for (var i in singletonContexts) {
+ var obj = singletonContexts[i];
+ if (obj.context === context && obj.name === className) {
+ return obj.instance;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Use this method to add an singleton instance to the system. Useful for unit testing to mock objects etc.
+ *
+ * @param {Object} context
+ * @param {string} className
+ * @param {Object} instance
+ * @memberof module:FactoryMaker
+ * @instance
+ */
+ function setSingletonInstance(context, className, instance) {
+ for (var i in singletonContexts) {
+ var obj = singletonContexts[i];
+ if (obj.context === context && obj.name === className) {
+ singletonContexts[i].instance = instance;
+ return;
+ }
+ }
+ singletonContexts.push({ name: className, context: context, instance: instance });
+ }
+
+ function getClassFactory(classConstructor) {
+ return function (context) {
+ if (context === undefined) {
+ context = {};
+ }
+ return {
+ create: function create() {
+ return merge(classConstructor.__dashjs_factory_name, classConstructor.apply({ context: context }, arguments), context, arguments);
+ }
+ };
+ };
+ }
+
+ function getSingletonFactory(classConstructor) {
+ return function (context) {
+ var instance = undefined;
+ if (context === undefined) {
+ context = {};
+ }
+ return {
+ getInstance: function getInstance() {
+ // If we don't have an instance yet check for one on the context
+ if (!instance) {
+ instance = getSingletonInstance(context, classConstructor.__dashjs_factory_name);
+ }
+ // If there's no instance on the context then create one
+ if (!instance) {
+ instance = merge(classConstructor.__dashjs_factory_name, classConstructor.apply({ context: context }, arguments), context, arguments);
+ singletonContexts.push({ name: classConstructor.__dashjs_factory_name, context: context, instance: instance });
+ }
+ return instance;
+ }
+ };
+ };
+ }
+
+ function merge(name, classConstructor, context, args) {
+ var extensionContext = getExtensionContext(context);
+ var extensionObject = extensionContext[name];
+ if (extensionObject) {
+ var extension = extensionObject.instance;
+ if (extensionObject.override) {
+ //Override public methods in parent but keep parent.
+ extension = extension.apply({ context: context, factory: instance, parent: classConstructor }, args);
+ for (var prop in extension) {
+ if (classConstructor.hasOwnProperty(prop)) {
+ classConstructor[prop] = extension[prop];
+ }
+ }
+ } else {
+ //replace parent object completely with new object. Same as dijon.
+ return extension.apply({ context: context, factory: instance }, args);
+ }
+ }
+ return classConstructor;
+ }
+
+ function getExtensionContext(context) {
+ var extensionContext = undefined;
+ extensions.forEach(function (obj) {
+ if (obj === context) {
+ extensionContext = obj;
+ }
+ });
+ if (!extensionContext) {
+ extensionContext = extensions.push(context);
+ }
+ return extensionContext;
+ }
+
+ instance = {
+ extend: extend,
+ getSingletonInstance: getSingletonInstance,
+ setSingletonInstance: setSingletonInstance,
+ getSingletonFactory: getSingletonFactory,
+ getClassFactory: getClassFactory
+ };
+
+ return instance;
+})();
+
+exports["default"] = FactoryMaker;
+module.exports = exports["default"];
+
+},{}],11:[function(_dereq_,module,exports){
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+exports.getVersionString = getVersionString;
+var VERSION = '2.3.0';
+
+function getVersionString() {
+ return VERSION;
+}
+
+},{}],12:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+var _EventsBase2 = _dereq_(14);
+
+var _EventsBase3 = _interopRequireDefault(_EventsBase2);
+
+/**
+ * @class
+ * @ignore
+ */
+
+var CoreEvents = (function (_EventsBase) {
+ _inherits(CoreEvents, _EventsBase);
+
+ function CoreEvents() {
+ _classCallCheck(this, CoreEvents);
+
+ _get(Object.getPrototypeOf(CoreEvents.prototype), 'constructor', this).call(this);
+ this.AST_IN_FUTURE = 'astinfuture';
+ this.BUFFERING_COMPLETED = 'bufferingCompleted';
+ this.BUFFER_CLEARED = 'bufferCleared';
+ this.BUFFER_LEVEL_UPDATED = 'bufferLevelUpdated';
+ this.BYTES_APPENDED = 'bytesAppended';
+ this.CHECK_FOR_EXISTENCE_COMPLETED = 'checkForExistenceCompleted';
+ this.CHUNK_APPENDED = 'chunkAppended';
+ this.CURRENT_TRACK_CHANGED = 'currenttrackchanged';
+ this.DATA_UPDATE_COMPLETED = 'dataUpdateCompleted';
+ this.DATA_UPDATE_STARTED = 'dataUpdateStarted';
+ this.FRAGMENT_LOADING_COMPLETED = 'fragmentLoadingCompleted';
+ this.FRAGMENT_LOADING_STARTED = 'fragmentLoadingStarted';
+ this.FRAGMENT_LOADING_ABANDONED = 'fragmentLoadingAbandoned';
+ this.INITIALIZATION_LOADED = 'initializationLoaded';
+ this.INIT_FRAGMENT_LOADED = 'initFragmentLoaded';
+ this.INIT_REQUESTED = 'initRequested';
+ this.INTERNAL_MANIFEST_LOADED = 'internalManifestLoaded';
+ this.LIVE_EDGE_SEARCH_COMPLETED = 'liveEdgeSearchCompleted';
+ this.LOADING_COMPLETED = 'loadingCompleted';
+ this.LOADING_PROGRESS = 'loadingProgress';
+ this.MANIFEST_UPDATED = 'manifestUpdated';
+ this.MEDIA_FRAGMENT_LOADED = 'mediaFragmentLoaded';
+ this.QUOTA_EXCEEDED = 'quotaExceeded';
+ this.REPRESENTATION_UPDATED = 'representationUpdated';
+ this.SEGMENTS_LOADED = 'segmentsLoaded';
+ this.SERVICE_LOCATION_BLACKLIST_CHANGED = 'serviceLocationBlacklistChanged';
+ this.SOURCEBUFFER_APPEND_COMPLETED = 'sourceBufferAppendCompleted';
+ this.SOURCEBUFFER_REMOVE_COMPLETED = 'sourceBufferRemoveCompleted';
+ this.STREAMS_COMPOSED = 'streamsComposed';
+ this.STREAM_BUFFERING_COMPLETED = 'streamBufferingCompleted';
+ this.STREAM_COMPLETED = 'streamCompleted';
+ this.STREAM_INITIALIZED = 'streaminitialized';
+ this.STREAM_TEARDOWN_COMPLETE = 'streamTeardownComplete';
+ this.TIMED_TEXT_REQUESTED = 'timedTextRequested';
+ this.TIME_SYNCHRONIZATION_COMPLETED = 'timeSynchronizationComplete';
+ this.URL_RESOLUTION_FAILED = 'urlResolutionFailed';
+ this.WALLCLOCK_TIME_UPDATED = 'wallclockTimeUpdated';
+ this.XLINK_ALL_ELEMENTS_LOADED = 'xlinkAllElementsLoaded';
+ this.XLINK_ELEMENT_LOADED = 'xlinkElementLoaded';
+ this.XLINK_READY = 'xlinkReady';
+ }
+
+ return CoreEvents;
+})(_EventsBase3['default']);
+
+exports['default'] = CoreEvents;
+module.exports = exports['default'];
+
+},{"14":14}],13:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @class
+ * @ignore
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+var _CoreEvents2 = _dereq_(12);
+
+var _CoreEvents3 = _interopRequireDefault(_CoreEvents2);
+
+var Events = (function (_CoreEvents) {
+ _inherits(Events, _CoreEvents);
+
+ function Events() {
+ _classCallCheck(this, Events);
+
+ _get(Object.getPrototypeOf(Events.prototype), 'constructor', this).apply(this, arguments);
+ }
+
+ return Events;
+})(_CoreEvents3['default']);
+
+var events = new Events();
+exports['default'] = events;
+module.exports = exports['default'];
+
+},{"12":12}],14:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @class
+ * @ignore
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+
+var EventsBase = (function () {
+ function EventsBase() {
+ _classCallCheck(this, EventsBase);
+ }
+
+ _createClass(EventsBase, [{
+ key: 'extend',
+ value: function extend(events, config) {
+ if (!events) return;
+
+ var override = config ? config.override : false;
+ var publicOnly = config ? config.publicOnly : false;
+
+ for (var evt in events) {
+ if (!events.hasOwnProperty(evt) || this[evt] && !override) continue;
+ if (publicOnly && events[evt].indexOf('public_') === -1) continue;
+ this[evt] = events[evt];
+ }
+ }
+ }]);
+
+ return EventsBase;
+})();
+
+exports['default'] = EventsBase;
+module.exports = exports['default'];
+
+},{}],15:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _streamingVoTrackInfo = _dereq_(172);
+
+var _streamingVoTrackInfo2 = _interopRequireDefault(_streamingVoTrackInfo);
+
+var _streamingVoMediaInfo = _dereq_(167);
+
+var _streamingVoMediaInfo2 = _interopRequireDefault(_streamingVoMediaInfo);
+
+var _streamingVoStreamInfo = _dereq_(169);
+
+var _streamingVoStreamInfo2 = _interopRequireDefault(_streamingVoStreamInfo);
+
+var _streamingVoManifestInfo = _dereq_(166);
+
+var _streamingVoManifestInfo2 = _interopRequireDefault(_streamingVoManifestInfo);
+
+var _voEvent = _dereq_(41);
+
+var _voEvent2 = _interopRequireDefault(_voEvent);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _externalsCea608Parser = _dereq_(2);
+
+var _externalsCea608Parser2 = _interopRequireDefault(_externalsCea608Parser);
+
+var _constantsDashMetricsList = _dereq_(20);
+
+var METRIC_LIST = _interopRequireWildcard(_constantsDashMetricsList);
+
+function DashAdapter() {
+
+ //let context = this.context;
+
+ var instance = undefined,
+ dashManifestModel = undefined,
+ periods = undefined,
+ adaptations = undefined;
+
+ function setConfig(config) {
+ if (!config) return;
+
+ if (config.dashManifestModel) {
+ dashManifestModel = config.dashManifestModel;
+ }
+ }
+
+ function initialize() {
+ periods = [];
+ adaptations = {};
+ }
+
+ function getRepresentationForTrackInfo(trackInfo, representationController) {
+ return representationController.getRepresentationForQuality(trackInfo.quality);
+ }
+
+ function getAdaptationForMediaInfo(mediaInfo) {
+ return adaptations[mediaInfo.streamInfo.id][mediaInfo.index];
+ }
+
+ function getPeriodForStreamInfo(streamInfo) {
+ var ln = periods.length;
+
+ for (var i = 0; i < ln; i++) {
+ var period = periods[i];
+
+ if (streamInfo.id === period.id) return period;
+ }
+
+ return null;
+ }
+
+ function convertRepresentationToTrackInfo(manifest, representation) {
+ var trackInfo = new _streamingVoTrackInfo2['default']();
+ var a = representation.adaptation.period.mpd.manifest.Period_asArray[representation.adaptation.period.index].AdaptationSet_asArray[representation.adaptation.index];
+ var r = dashManifestModel.getRepresentationFor(representation.index, a);
+
+ trackInfo.id = representation.id;
+ trackInfo.quality = representation.index;
+ trackInfo.bandwidth = dashManifestModel.getBandwidth(r);
+ trackInfo.DVRWindow = representation.segmentAvailabilityRange;
+ trackInfo.fragmentDuration = representation.segmentDuration || (representation.segments && representation.segments.length > 0 ? representation.segments[0].duration : NaN);
+ trackInfo.MSETimeOffset = representation.MSETimeOffset;
+ trackInfo.useCalculatedLiveEdgeTime = representation.useCalculatedLiveEdgeTime;
+ trackInfo.mediaInfo = convertAdaptationToMediaInfo(manifest, representation.adaptation);
+
+ return trackInfo;
+ }
+
+ function convertAdaptationToMediaInfo(manifest, adaptation) {
+ var mediaInfo = new _streamingVoMediaInfo2['default']();
+ var a = adaptation.period.mpd.manifest.Period_asArray[adaptation.period.index].AdaptationSet_asArray[adaptation.index];
+ var viewpoint;
+
+ mediaInfo.id = adaptation.id;
+ mediaInfo.index = adaptation.index;
+ mediaInfo.type = adaptation.type;
+ mediaInfo.streamInfo = convertPeriodToStreamInfo(manifest, adaptation.period);
+ mediaInfo.representationCount = dashManifestModel.getRepresentationCount(a);
+ mediaInfo.lang = dashManifestModel.getLanguageForAdaptation(a);
+ viewpoint = dashManifestModel.getViewpointForAdaptation(a);
+ mediaInfo.viewpoint = viewpoint ? viewpoint.value : undefined;
+ mediaInfo.accessibility = dashManifestModel.getAccessibilityForAdaptation(a).map(function (accessibility) {
+ var accessibilityValue = accessibility.value;
+ var accessibilityData = accessibilityValue;
+ if (accessibility.schemeIdUri && accessibility.schemeIdUri.search('cea-608') >= 0 && typeof _externalsCea608Parser2['default'] !== 'undefined') {
+ if (accessibilityValue) {
+ accessibilityData = 'cea-608:' + accessibilityValue;
+ } else {
+ accessibilityData = 'cea-608';
+ }
+ mediaInfo.embeddedCaptions = true;
+ }
+ return accessibilityData;
+ });
+ mediaInfo.audioChannelConfiguration = dashManifestModel.getAudioChannelConfigurationForAdaptation(a).map(function (audioChannelConfiguration) {
+ return audioChannelConfiguration.value;
+ });
+ mediaInfo.roles = dashManifestModel.getRolesForAdaptation(a).map(function (role) {
+ return role.value;
+ });
+ mediaInfo.codec = dashManifestModel.getCodec(a);
+ mediaInfo.mimeType = dashManifestModel.getMimeType(a);
+ mediaInfo.contentProtection = dashManifestModel.getContentProtectionData(a);
+ mediaInfo.bitrateList = dashManifestModel.getBitrateListForAdaptation(a);
+
+ if (mediaInfo.contentProtection) {
+ mediaInfo.contentProtection.forEach(function (item) {
+ item.KID = dashManifestModel.getKID(item);
+ });
+ }
+
+ mediaInfo.isText = dashManifestModel.getIsTextTrack(mediaInfo.mimeType);
+
+ return mediaInfo;
+ }
+
+ function convertVideoInfoToEmbeddedTextInfo(mediaInfo, channel, lang) {
+ mediaInfo.id = channel; // CC1, CC2, CC3, or CC4
+ mediaInfo.index = 100 + parseInt(channel.substring(2, 3));
+ mediaInfo.type = 'embeddedText';
+ mediaInfo.codec = 'cea-608-in-SEI';
+ mediaInfo.isText = true;
+ mediaInfo.isEmbedded = true;
+ mediaInfo.lang = channel + ' ' + lang;
+ mediaInfo.roles = ['caption'];
+ }
+
+ function convertPeriodToStreamInfo(manifest, period) {
+ var streamInfo = new _streamingVoStreamInfo2['default']();
+ var THRESHOLD = 1;
+
+ streamInfo.id = period.id;
+ streamInfo.index = period.index;
+ streamInfo.start = period.start;
+ streamInfo.duration = period.duration;
+ streamInfo.manifestInfo = convertMpdToManifestInfo(manifest, period.mpd);
+ streamInfo.isLast = manifest.Period_asArray.length === 1 || Math.abs(streamInfo.start + streamInfo.duration - streamInfo.manifestInfo.duration) < THRESHOLD;
+ streamInfo.isFirst = manifest.Period_asArray.length === 1 || dashManifestModel.getRegularPeriods(manifest, dashManifestModel.getMpd(manifest))[0].id === period.id;
+
+ return streamInfo;
+ }
+
+ function convertMpdToManifestInfo(manifest, mpd) {
+ var manifestInfo = new _streamingVoManifestInfo2['default']();
+
+ manifestInfo.DVRWindowSize = mpd.timeShiftBufferDepth;
+ manifestInfo.loadedTime = mpd.manifest.loadedTime;
+ manifestInfo.availableFrom = mpd.availabilityStartTime;
+ manifestInfo.minBufferTime = mpd.manifest.minBufferTime;
+ manifestInfo.maxFragmentDuration = mpd.maxSegmentDuration;
+ manifestInfo.duration = dashManifestModel.getDuration(manifest);
+ manifestInfo.isDynamic = dashManifestModel.getIsDynamic(manifest);
+
+ return manifestInfo;
+ }
+
+ function getMediaInfoForType(manifest, streamInfo, type) {
+
+ var data = dashManifestModel.getAdaptationForType(manifest, streamInfo.index, type, streamInfo);
+ if (!data) return null;
+
+ var periodInfo = getPeriodForStreamInfo(streamInfo);
+ var periodId = periodInfo.id;
+ var idx = dashManifestModel.getIndexForAdaptation(data, manifest, streamInfo.index);
+
+ adaptations[periodId] = adaptations[periodId] || dashManifestModel.getAdaptationsForPeriod(manifest, periodInfo);
+
+ return convertAdaptationToMediaInfo(manifest, adaptations[periodId][idx]);
+ }
+
+ function getAllMediaInfoForType(manifest, streamInfo, type) {
+ var periodInfo = getPeriodForStreamInfo(streamInfo);
+ var periodId = periodInfo.id;
+ var adaptationsForType = dashManifestModel.getAdaptationsForType(manifest, streamInfo.index, type !== 'embeddedText' ? type : 'video');
+
+ var mediaArr = [];
+
+ var data, media, idx, i, j, ln;
+
+ if (!adaptationsForType) return mediaArr;
+
+ adaptations[periodId] = adaptations[periodId] || dashManifestModel.getAdaptationsForPeriod(manifest, periodInfo);
+
+ for (i = 0, ln = adaptationsForType.length; i < ln; i++) {
+ data = adaptationsForType[i];
+ idx = dashManifestModel.getIndexForAdaptation(data, manifest, streamInfo.index);
+ media = convertAdaptationToMediaInfo(manifest, adaptations[periodId][idx]);
+
+ if (type === 'embeddedText') {
+ var accessibilityLength = media.accessibility.length;
+ for (j = 0; j < accessibilityLength; j++) {
+ if (!media) {
+ continue;
+ }
+ var accessibility = media.accessibility[j];
+ if (accessibility.indexOf('cea-608:') === 0) {
+ var value = accessibility.substring(8);
+ var parts = value.split(';');
+ if (parts[0].substring(0, 2) === 'CC') {
+ for (j = 0; j < parts.length; j++) {
+ if (!media) {
+ media = convertAdaptationToMediaInfo.call(this, manifest, adaptations[periodId][idx]);
+ }
+ convertVideoInfoToEmbeddedTextInfo(media, parts[j].substring(0, 3), parts[j].substring(4));
+ mediaArr.push(media);
+ media = null;
+ }
+ } else {
+ for (j = 0; j < parts.length; j++) {
+ // Only languages for CC1, CC2, ...
+ if (!media) {
+ media = convertAdaptationToMediaInfo.call(this, manifest, adaptations[periodId][idx]);
+ }
+ convertVideoInfoToEmbeddedTextInfo(media, 'CC' + (j + 1), parts[j]);
+ mediaArr.push(media);
+ media = null;
+ }
+ }
+ } else if (accessibility.indexOf('cea-608') === 0) {
+ // Nothing known. We interpret it as CC1=eng
+ convertVideoInfoToEmbeddedTextInfo(media, 'CC1', 'eng');
+ mediaArr.push(media);
+ media = null;
+ }
+ }
+ }
+ if (media && type !== 'embeddedText') {
+ mediaArr.push(media);
+ }
+ }
+
+ return mediaArr;
+ }
+
+ function getStreamsInfo(manifest) {
+ var streams = [];
+ var mpd, ln, i;
+
+ if (!manifest) return null;
+
+ mpd = dashManifestModel.getMpd(manifest);
+ periods = dashManifestModel.getRegularPeriods(manifest, mpd);
+ mpd.checkTime = dashManifestModel.getCheckTime(manifest, periods[0]);
+ adaptations = {};
+ ln = periods.length;
+
+ for (i = 0; i < ln; i++) {
+ streams.push(convertPeriodToStreamInfo(manifest, periods[i]));
+ }
+
+ return streams;
+ }
+
+ function getManifestInfo(manifest) {
+ var mpd = dashManifestModel.getMpd(manifest);
+
+ return convertMpdToManifestInfo(manifest, mpd);
+ }
+
+ function getInitRequest(streamProcessor, quality) {
+ var representation = streamProcessor.getRepresentationController().getRepresentationForQuality(quality);
+ return streamProcessor.getIndexHandler().getInitRequest(representation);
+ }
+
+ function getNextFragmentRequest(streamProcessor, trackInfo) {
+ var representation = getRepresentationForTrackInfo(trackInfo, streamProcessor.getRepresentationController());
+ return streamProcessor.getIndexHandler().getNextSegmentRequest(representation);
+ }
+
+ function getFragmentRequestForTime(streamProcessor, trackInfo, time, options) {
+ var representation = getRepresentationForTrackInfo(trackInfo, streamProcessor.getRepresentationController());
+ return streamProcessor.getIndexHandler().getSegmentRequestForTime(representation, time, options);
+ }
+
+ function generateFragmentRequestForTime(streamProcessor, trackInfo, time) {
+ var representation = getRepresentationForTrackInfo(trackInfo, streamProcessor.getRepresentationController());
+ return streamProcessor.getIndexHandler().generateSegmentRequestForTime(representation, time);
+ }
+
+ function getIndexHandlerTime(streamProcessor) {
+ return streamProcessor.getIndexHandler().getCurrentTime();
+ }
+
+ function setIndexHandlerTime(streamProcessor, value) {
+ return streamProcessor.getIndexHandler().setCurrentTime(value);
+ }
+
+ function updateData(manifest, streamProcessor) {
+ var periodInfo = getPeriodForStreamInfo(streamProcessor.getStreamInfo());
+ var mediaInfo = streamProcessor.getMediaInfo();
+ var adaptation = getAdaptationForMediaInfo(mediaInfo);
+ var type = streamProcessor.getType();
+
+ var id, data;
+
+ id = mediaInfo.id;
+ data = id ? dashManifestModel.getAdaptationForId(id, manifest, periodInfo.index) : dashManifestModel.getAdaptationForIndex(mediaInfo.index, manifest, periodInfo.index);
+ streamProcessor.getRepresentationController().updateData(data, adaptation, type);
+ }
+
+ function getRepresentationInfoForQuality(manifest, representationController, quality) {
+ var representation = representationController.getRepresentationForQuality(quality);
+ return representation ? convertRepresentationToTrackInfo(manifest, representation) : null;
+ }
+
+ function getCurrentRepresentationInfo(manifest, representationController) {
+ var representation = representationController.getCurrentRepresentation();
+ return representation ? convertRepresentationToTrackInfo(manifest, representation) : null;
+ }
+
+ function getEvent(eventBox, eventStreams, startTime) {
+ var event = new _voEvent2['default']();
+ var schemeIdUri = eventBox.scheme_id_uri;
+ var value = eventBox.value;
+ var timescale = eventBox.timescale;
+ var presentationTimeDelta = eventBox.presentation_time_delta;
+ var duration = eventBox.event_duration;
+ var id = eventBox.id;
+ var messageData = eventBox.message_data;
+ var presentationTime = startTime * timescale + presentationTimeDelta;
+
+ if (!eventStreams[schemeIdUri]) return null;
+
+ event.eventStream = eventStreams[schemeIdUri];
+ event.eventStream.value = value;
+ event.eventStream.timescale = timescale;
+ event.duration = duration;
+ event.id = id;
+ event.presentationTime = presentationTime;
+ event.messageData = messageData;
+ event.presentationTimeDelta = presentationTimeDelta;
+
+ return event;
+ }
+
+ function getEventsFor(manifest, info, streamProcessor) {
+ var events = [];
+
+ if (info instanceof _streamingVoStreamInfo2['default']) {
+ events = dashManifestModel.getEventsForPeriod(manifest, getPeriodForStreamInfo(info));
+ } else if (info instanceof _streamingVoMediaInfo2['default']) {
+ events = dashManifestModel.getEventStreamForAdaptationSet(manifest, getAdaptationForMediaInfo(info));
+ } else if (info instanceof _streamingVoTrackInfo2['default']) {
+ events = dashManifestModel.getEventStreamForRepresentation(manifest, getRepresentationForTrackInfo(info, streamProcessor.getRepresentationController()));
+ }
+
+ return events;
+ }
+
+ function reset() {
+ periods = [];
+ adaptations = {};
+ }
+
+ instance = {
+ initialize: initialize,
+ convertDataToTrack: convertRepresentationToTrackInfo,
+ convertDataToMedia: convertAdaptationToMediaInfo,
+ convertDataToStream: convertPeriodToStreamInfo,
+ getDataForTrack: getRepresentationForTrackInfo,
+ getDataForMedia: getAdaptationForMediaInfo,
+ getDataForStream: getPeriodForStreamInfo,
+ getStreamsInfo: getStreamsInfo,
+ getManifestInfo: getManifestInfo,
+ getMediaInfoForType: getMediaInfoForType,
+ getAllMediaInfoForType: getAllMediaInfoForType,
+ getCurrentRepresentationInfo: getCurrentRepresentationInfo,
+ getRepresentationInfoForQuality: getRepresentationInfoForQuality,
+ updateData: updateData,
+ getInitRequest: getInitRequest,
+ getNextFragmentRequest: getNextFragmentRequest,
+ getFragmentRequestForTime: getFragmentRequestForTime,
+ generateFragmentRequestForTime: generateFragmentRequestForTime,
+ getIndexHandlerTime: getIndexHandlerTime,
+ setIndexHandlerTime: setIndexHandlerTime,
+ getEventsFor: getEventsFor,
+ getEvent: getEvent,
+ setConfig: setConfig,
+ reset: reset,
+ metricsList: METRIC_LIST
+ };
+
+ return instance;
+}
+
+DashAdapter.__dashjs_factory_name = 'DashAdapter';
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(DashAdapter);
+module.exports = exports['default'];
+
+},{"10":10,"166":166,"167":167,"169":169,"172":172,"2":2,"20":20,"41":41}],16:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _streamingVoFragmentRequest = _dereq_(163);
+
+var _streamingVoFragmentRequest2 = _interopRequireDefault(_streamingVoFragmentRequest);
+
+var _streamingVoError = _dereq_(162);
+
+var _streamingVoError2 = _interopRequireDefault(_streamingVoError);
+
+var _streamingVoMetricsHTTPRequest = _dereq_(179);
+
+var _coreEventsEvents = _dereq_(13);
+
+var _coreEventsEvents2 = _interopRequireDefault(_coreEventsEvents);
+
+var _coreEventBus = _dereq_(9);
+
+var _coreEventBus2 = _interopRequireDefault(_coreEventBus);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _coreDebug = _dereq_(8);
+
+var _coreDebug2 = _interopRequireDefault(_coreDebug);
+
+var _streamingUtilsURLUtils = _dereq_(158);
+
+var _streamingUtilsURLUtils2 = _interopRequireDefault(_streamingUtilsURLUtils);
+
+var _utilsSegmentsUtils = _dereq_(35);
+
+var _utilsSegmentsGetter = _dereq_(34);
+
+var _utilsSegmentsGetter2 = _interopRequireDefault(_utilsSegmentsGetter);
+
+var SEGMENTS_UNAVAILABLE_ERROR_CODE = 1;
+
+function DashHandler(config) {
+
+ var context = this.context;
+ var log = (0, _coreDebug2['default'])(context).getInstance().log;
+ var eventBus = (0, _coreEventBus2['default'])(context).getInstance();
+ var urlUtils = (0, _streamingUtilsURLUtils2['default'])(context).getInstance();
+
+ var segmentBaseLoader = config.segmentBaseLoader;
+ var timelineConverter = config.timelineConverter;
+ var dashMetrics = config.dashMetrics;
+ var metricsModel = config.metricsModel;
+ var baseURLController = config.baseURLController;
+
+ var instance = undefined,
+ index = undefined,
+ requestedTime = undefined,
+ isDynamic = undefined,
+ type = undefined,
+ currentTime = undefined,
+ earliestTime = undefined,
+ streamProcessor = undefined,
+ segmentsGetter = undefined;
+
+ function setup() {
+ index = -1;
+ currentTime = 0;
+ earliestTime = NaN;
+ eventBus.on(_coreEventsEvents2['default'].INITIALIZATION_LOADED, onInitializationLoaded, instance);
+ eventBus.on(_coreEventsEvents2['default'].SEGMENTS_LOADED, onSegmentsLoaded, instance);
+ }
+
+ function initialize(StreamProcessor) {
+ streamProcessor = StreamProcessor;
+ type = streamProcessor.getType();
+ isDynamic = streamProcessor.isDynamic();
+
+ segmentsGetter = (0, _utilsSegmentsGetter2['default'])(context).create(config, isDynamic);
+ }
+
+ function getStreamProcessor() {
+ return streamProcessor;
+ }
+
+ function setCurrentTime(value) {
+ currentTime = value;
+ }
+
+ function getCurrentTime() {
+ return currentTime;
+ }
+
+ function getCurrentIndex() {
+ return index;
+ }
+
+ function getEarliestTime() {
+ return earliestTime;
+ }
+
+ function reset() {
+ segmentsGetter = null;
+ currentTime = 0;
+ earliestTime = NaN;
+ requestedTime = NaN;
+ index = -1;
+ isDynamic = null;
+ type = null;
+ streamProcessor = null;
+ eventBus.off(_coreEventsEvents2['default'].INITIALIZATION_LOADED, onInitializationLoaded, instance);
+ eventBus.off(_coreEventsEvents2['default'].SEGMENTS_LOADED, onSegmentsLoaded, instance);
+ }
+
+ function unescapeDollarsInTemplate(url) {
+ return url.split('$$').join('$');
+ }
+
+ function replaceIDForTemplate(url, value) {
+ if (value === null || url.indexOf('$RepresentationID$') === -1) {
+ return url;
+ }
+ var v = value.toString();
+ return url.split('$RepresentationID$').join(v);
+ }
+
+ function setRequestUrl(request, destination, representation) {
+ var baseURL = baseURLController.resolve(representation.path);
+ var url;
+ var serviceLocation;
+
+ if (!baseURL || destination === baseURL.url || !urlUtils.isRelative(destination)) {
+ url = destination;
+ } else {
+ url = baseURL.url;
+ serviceLocation = baseURL.serviceLocation;
+
+ if (destination) {
+ url += destination;
+ }
+ }
+
+ if (urlUtils.isRelative(url)) {
+ return false;
+ }
+
+ request.url = url;
+ request.serviceLocation = serviceLocation;
+
+ return true;
+ }
+
+ function generateInitRequest(representation, mediaType) {
+ var request = new _streamingVoFragmentRequest2['default']();
+ var period, presentationStartTime;
+
+ period = representation.adaptation.period;
+
+ request.mediaType = mediaType;
+ request.type = _streamingVoMetricsHTTPRequest.HTTPRequest.INIT_SEGMENT_TYPE;
+ request.range = representation.range;
+ presentationStartTime = period.start;
+ request.availabilityStartTime = timelineConverter.calcAvailabilityStartTimeFromPresentationTime(presentationStartTime, representation.adaptation.period.mpd, isDynamic);
+ request.availabilityEndTime = timelineConverter.calcAvailabilityEndTimeFromPresentationTime(presentationStartTime + period.duration, period.mpd, isDynamic);
+ request.quality = representation.index;
+ request.mediaInfo = streamProcessor.getMediaInfo();
+
+ if (setRequestUrl(request, representation.initialization, representation)) {
+ return request;
+ }
+ }
+
+ function getInitRequest(representation) {
+ var request;
+
+ if (!representation) return null;
+
+ request = generateInitRequest(representation, type);
+
+ //log("Got an initialization.");
+
+ return request;
+ }
+
+ function isMediaFinished(representation) {
+ var period = representation.adaptation.period;
+ var segmentInfoType = representation.segmentInfoType;
+
+ var isFinished = false;
+
+ var sDuration, seg, fTime;
+
+ if (index < 0) {
+ isFinished = false;
+ } else if (isDynamic || index < representation.availableSegmentsNumber) {
+ seg = (0, _utilsSegmentsUtils.getSegmentByIndex)(index, representation);
+
+ if (seg) {
+ fTime = seg.presentationStartTime - period.start;
+ sDuration = representation.adaptation.period.duration;
+ log(representation.segmentInfoType + ': ' + fTime + ' / ' + sDuration);
+ isFinished = segmentInfoType === 'SegmentTimeline' && isDynamic ? false : fTime >= sDuration;
+ }
+ } else {
+ isFinished = true;
+ }
+
+ return isFinished;
+ }
+
+ function updateSegments(representation) {
+ return segmentsGetter.getSegments(representation, requestedTime, index, onSegmentListUpdated);
+ }
+
+ function onSegmentListUpdated(representation, segments) {
+
+ representation.segments = segments;
+
+ if (segments && segments.length > 0) {
+ earliestTime = isNaN(earliestTime) ? segments[0].presentationStartTime : Math.min(segments[0].presentationStartTime, earliestTime);
+ }
+
+ if (isDynamic && isNaN(timelineConverter.getExpectedLiveEdge())) {
+ var lastIdx = segments.length - 1;
+ var lastSegment = segments[lastIdx];
+ var liveEdge = lastSegment.presentationStartTime;
+ var metrics = metricsModel.getMetricsFor('stream');
+ // the last segment is supposed to be a live edge
+ timelineConverter.setExpectedLiveEdge(liveEdge);
+ metricsModel.updateManifestUpdateInfo(dashMetrics.getCurrentManifestUpdate(metrics), { presentationStartTime: liveEdge });
+ }
+ }
+
+ function updateSegmentList(representation) {
+
+ if (!representation) {
+ throw new _streamingVoError2['default']('no representation');
+ }
+
+ representation.segments = null;
+
+ updateSegments(representation);
+
+ return representation;
+ }
+
+ function updateRepresentation(representation, keepIdx) {
+ var hasInitialization = representation.initialization;
+ var hasSegments = representation.segmentInfoType !== 'BaseURL' && representation.segmentInfoType !== 'SegmentBase' && !representation.indexRange;
+ var error;
+
+ if (!representation.segmentDuration && !representation.segments) {
+ updateSegmentList(representation);
+ }
+
+ representation.segmentAvailabilityRange = null;
+ representation.segmentAvailabilityRange = timelineConverter.calcSegmentAvailabilityRange(representation, isDynamic);
+
+ if (representation.segmentAvailabilityRange.end < representation.segmentAvailabilityRange.start && !representation.useCalculatedLiveEdgeTime) {
+ error = new _streamingVoError2['default'](SEGMENTS_UNAVAILABLE_ERROR_CODE, 'no segments are available yet', { availabilityDelay: representation.segmentAvailabilityRange.start - representation.segmentAvailabilityRange.end });
+ eventBus.trigger(_coreEventsEvents2['default'].REPRESENTATION_UPDATED, { sender: this, representation: representation, error: error });
+ return;
+ }
+
+ if (!keepIdx) index = -1;
+
+ if (representation.segmentDuration) {
+ updateSegmentList(representation);
+ }
+
+ if (!hasInitialization) {
+ segmentBaseLoader.loadInitialization(representation);
+ }
+
+ if (!hasSegments) {
+ segmentBaseLoader.loadSegments(representation, type, representation.indexRange);
+ }
+
+ if (hasInitialization && hasSegments) {
+ eventBus.trigger(_coreEventsEvents2['default'].REPRESENTATION_UPDATED, { sender: this, representation: representation });
+ }
+ }
+
+ function getIndexForSegments(time, representation, timeThreshold) {
+ var segments = representation.segments;
+ var ln = segments ? segments.length : null;
+
+ var idx = -1;
+ var epsilon, frag, ft, fd, i;
+
+ if (segments && ln > 0) {
+ for (i = 0; i < ln; i++) {
+ frag = segments[i];
+ ft = frag.presentationStartTime;
+ fd = frag.duration;
+ epsilon = timeThreshold === undefined || timeThreshold === null ? fd / 2 : timeThreshold;
+ if (time + epsilon >= ft && time - epsilon < ft + fd) {
+ idx = frag.availabilityIdx;
+ break;
+ }
+ }
+ }
+
+ return idx;
+ }
+
+ function getRequestForSegment(segment) {
+ if (segment === null || segment === undefined) {
+ return null;
+ }
+
+ var request = new _streamingVoFragmentRequest2['default']();
+ var representation = segment.representation;
+ var bandwidth = representation.adaptation.period.mpd.manifest.Period_asArray[representation.adaptation.period.index].AdaptationSet_asArray[representation.adaptation.index].Representation_asArray[representation.index].bandwidth;
+ var url = segment.media;
+
+ url = (0, _utilsSegmentsUtils.replaceTokenForTemplate)(url, 'Number', segment.replacementNumber);
+ url = (0, _utilsSegmentsUtils.replaceTokenForTemplate)(url, 'Time', segment.replacementTime);
+ url = (0, _utilsSegmentsUtils.replaceTokenForTemplate)(url, 'Bandwidth', bandwidth);
+ url = replaceIDForTemplate(url, representation.id);
+ url = unescapeDollarsInTemplate(url);
+
+ request.mediaType = type;
+ request.type = _streamingVoMetricsHTTPRequest.HTTPRequest.MEDIA_SEGMENT_TYPE;
+ request.range = segment.mediaRange;
+ request.startTime = segment.presentationStartTime;
+ request.duration = segment.duration;
+ request.timescale = representation.timescale;
+ request.availabilityStartTime = segment.availabilityStartTime;
+ request.availabilityEndTime = segment.availabilityEndTime;
+ request.wallStartTime = segment.wallStartTime;
+ request.quality = representation.index;
+ request.index = segment.availabilityIdx;
+ request.mediaInfo = streamProcessor.getMediaInfo();
+ request.adaptationIndex = representation.adaptation.index;
+
+ if (setRequestUrl(request, url, representation)) {
+ return request;
+ }
+ }
+
+ function getSegmentRequestForTime(representation, time, options) {
+ var request, segment, finished;
+
+ var idx = index;
+
+ var keepIdx = options ? options.keepIdx : false;
+ var timeThreshold = options ? options.timeThreshold : null;
+ var ignoreIsFinished = options && options.ignoreIsFinished ? true : false;
+
+ if (!representation) {
+ return null;
+ }
+
+ if (requestedTime !== time) {
+ // When playing at live edge with 0 delay we may loop back with same time and index until it is available. Reduces verboseness of logs.
+ requestedTime = time;
+ log('Getting the request for ' + type + ' time : ' + time);
+ }
+
+ index = getIndexForSegments(time, representation, timeThreshold);
+ //Index may be -1 if getSegments needs to update. So after getSegments is called and updated then try to get index again.
+ updateSegments(representation);
+ if (index < 0) {
+ index = getIndexForSegments(time, representation, timeThreshold);
+ }
+
+ if (index > 0) {
+ log('Index for ' + type + ' time ' + time + ' is ' + index);
+ }
+
+ finished = !ignoreIsFinished ? isMediaFinished(representation) : false;
+ if (finished) {
+ request = new _streamingVoFragmentRequest2['default']();
+ request.action = _streamingVoFragmentRequest2['default'].ACTION_COMPLETE;
+ request.index = index;
+ request.mediaType = type;
+ request.mediaInfo = streamProcessor.getMediaInfo();
+ log('Signal complete.', request);
+ } else {
+ segment = (0, _utilsSegmentsUtils.getSegmentByIndex)(index, representation);
+ request = getRequestForSegment(segment);
+ }
+
+ if (keepIdx && idx >= 0) {
+ index = representation.segmentInfoType === 'SegmentTimeline' && isDynamic ? index : idx;
+ }
+
+ return request;
+ }
+
+ function generateSegmentRequestForTime(representation, time) {
+ var step = (representation.segmentAvailabilityRange.end - representation.segmentAvailabilityRange.start) / 2;
+
+ representation.segments = null;
+ representation.segmentAvailabilityRange = { start: time - step, end: time + step };
+ return getSegmentRequestForTime(representation, time, { keepIdx: false, ignoreIsFinished: true });
+ }
+
+ function getNextSegmentRequest(representation) {
+ var request, segment, finished;
+
+ if (!representation || index === -1) {
+ return null;
+ }
+
+ requestedTime = null;
+ index++;
+
+ log('Getting the next request at index: ' + index);
+
+ finished = isMediaFinished(representation);
+ if (finished) {
+ request = new _streamingVoFragmentRequest2['default']();
+ request.action = _streamingVoFragmentRequest2['default'].ACTION_COMPLETE;
+ request.index = index;
+ request.mediaType = type;
+ request.mediaInfo = streamProcessor.getMediaInfo();
+ log('Signal complete.');
+ } else {
+ updateSegments(representation);
+ segment = (0, _utilsSegmentsUtils.getSegmentByIndex)(index, representation);
+ request = getRequestForSegment(segment);
+ if (!segment && isDynamic) {
+ /*
+ Sometimes when playing dynamic streams with 0 fragment delay at live edge we ask for
+ an index before it is available so we decrement index back and send null request
+ which triggers the validate loop to rerun and the next time the segment should be
+ available.
+ */
+ index--;
+ }
+ }
+
+ return request;
+ }
+
+ function onInitializationLoaded(e) {
+ var representation = e.representation;
+ //log("Got an initialization.");
+ if (!representation.segments) return;
+
+ eventBus.trigger(_coreEventsEvents2['default'].REPRESENTATION_UPDATED, { sender: this, representation: representation });
+ }
+
+ function onSegmentsLoaded(e) {
+ if (e.error || type !== e.mediaType) return;
+
+ var fragments = e.segments;
+ var representation = e.representation;
+ var segments = [];
+ var count = 0;
+
+ var i, len, s, seg;
+
+ for (i = 0, len = fragments.length; i < len; i++) {
+ s = fragments[i];
+
+ seg = (0, _utilsSegmentsUtils.getTimeBasedSegment)(timelineConverter, isDynamic, representation, s.startTime, s.duration, s.timescale, s.media, s.mediaRange, count);
+
+ segments.push(seg);
+ seg = null;
+ count++;
+ }
+
+ representation.segmentAvailabilityRange = { start: segments[0].presentationStartTime, end: segments[len - 1].presentationStartTime };
+ representation.availableSegmentsNumber = len;
+
+ onSegmentListUpdated(representation, segments);
+
+ if (!representation.initialization) return;
+
+ eventBus.trigger(_coreEventsEvents2['default'].REPRESENTATION_UPDATED, { sender: this, representation: representation });
+ }
+
+ instance = {
+ initialize: initialize,
+ getStreamProcessor: getStreamProcessor,
+ getInitRequest: getInitRequest,
+ getSegmentRequestForTime: getSegmentRequestForTime,
+ getNextSegmentRequest: getNextSegmentRequest,
+ generateSegmentRequestForTime: generateSegmentRequestForTime,
+ updateRepresentation: updateRepresentation,
+ setCurrentTime: setCurrentTime,
+ getCurrentTime: getCurrentTime,
+ getCurrentIndex: getCurrentIndex,
+ getEarliestTime: getEarliestTime,
+ reset: reset
+ };
+
+ setup();
+
+ return instance;
+}
+
+DashHandler.__dashjs_factory_name = 'DashHandler';
+var factory = _coreFactoryMaker2['default'].getClassFactory(DashHandler);
+factory.SEGMENTS_UNAVAILABLE_ERROR_CODE = SEGMENTS_UNAVAILABLE_ERROR_CODE;
+exports['default'] = factory;
+module.exports = exports['default'];
+
+},{"10":10,"13":13,"158":158,"162":162,"163":163,"179":179,"34":34,"35":35,"8":8,"9":9}],17:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _streamingVoMetricsHTTPRequest = _dereq_(179);
+
+var _streamingModelsManifestModel = _dereq_(100);
+
+var _streamingModelsManifestModel2 = _interopRequireDefault(_streamingModelsManifestModel);
+
+var _modelsDashManifestModel = _dereq_(22);
+
+var _modelsDashManifestModel2 = _interopRequireDefault(_modelsDashManifestModel);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _constantsDashMetricsList = _dereq_(20);
+
+var MetricsList = _interopRequireWildcard(_constantsDashMetricsList);
+
+var _round10 = _dereq_(7);
+
+/**
+ * @module DashMetrics
+ */
+function DashMetrics() {
+
+ var instance = undefined;
+ var context = this.context;
+ var manifestModel = (0, _streamingModelsManifestModel2['default'])(context).getInstance(); //TODO Need to pass this in not bake in
+
+ function getBandwidthForRepresentation(representationId, periodId) {
+ var representation;
+ var manifest = manifestModel.getValue();
+ var period = manifest.Period_asArray[periodId];
+
+ representation = findRepresentation(period, representationId);
+
+ if (representation === null) {
+ return null;
+ }
+
+ return representation.bandwidth;
+ }
+
+ /**
+ *
+ * @param {string} representationId
+ * @param {number} periodIdx
+ * @returns {*}
+ */
+ function getIndexForRepresentation(representationId, periodIdx) {
+ var representationIndex;
+ var manifest = manifestModel.getValue();
+ var period = manifest.Period_asArray[periodIdx];
+
+ representationIndex = findRepresentationIndex(period, representationId);
+ return representationIndex;
+ }
+
+ /**
+ * This method returns the current max index based on what is defined in the MPD.
+ *
+ * @param {string} bufferType - String 'audio' or 'video',
+ * @param {number} periodIdx - Make sure this is the period index not id
+ * @return {number}
+ * @memberof module:DashMetrics
+ * @instance
+ */
+ function getMaxIndexForBufferType(bufferType, periodIdx) {
+ var maxIndex;
+ var manifest = manifestModel.getValue();
+ var period = manifest.Period_asArray[periodIdx];
+
+ maxIndex = findMaxBufferIndex(period, bufferType);
+ return maxIndex;
+ }
+
+ /**
+ * @param {MetricsList} metrics
+ * @returns {*}
+ * @memberof module:DashMetrics
+ * @instance
+ */
+ function getCurrentRepresentationSwitch(metrics) {
+ return getCurrent(metrics, MetricsList.TRACK_SWITCH);
+ }
+
+ /**
+ * @param {MetricsList} metrics
+ * @returns {*}
+ * @memberof module:DashMetrics
+ * @instance
+ */
+ function getLatestBufferLevelVO(metrics) {
+ return getCurrent(metrics, MetricsList.BUFFER_LEVEL);
+ }
+
+ /**
+ * @param {MetricsList} metrics
+ * @returns {number}
+ * @memberof module:DashMetrics
+ * @instance
+ */
+ function getCurrentBufferLevel(metrics) {
+ var vo = getLatestBufferLevelVO(metrics);
+
+ if (vo) {
+ return (0, _round10.round10)(vo.level / 1000, -3);
+ }
+
+ return 0;
+ }
+
+ /**
+ * @param {MetricsList} metrics
+ * @returns {null|*|vo}
+ * @memberof module:DashMetrics
+ * @instance
+ */
+ function getRequestsQueue(metrics) {
+ return metrics.RequestsQueue;
+ }
+
+ /**
+ * @param {MetricsList} metrics
+ * @returns {*}
+ * @memberof module:DashMetrics
+ * @instance
+ */
+ function getCurrentHttpRequest(metrics) {
+ if (metrics === null) {
+ return null;
+ }
+
+ var httpList = metrics.HttpList;
+ var currentHttpList = null;
+
+ var httpListLength, httpListLastIndex;
+
+ if (httpList === null || httpList.length <= 0) {
+ return null;
+ }
+
+ httpListLength = httpList.length;
+ httpListLastIndex = httpListLength - 1;
+
+ while (httpListLastIndex >= 0) {
+ if (httpList[httpListLastIndex].responsecode) {
+ currentHttpList = httpList[httpListLastIndex];
+ break;
+ }
+ httpListLastIndex--;
+ }
+ return currentHttpList;
+ }
+
+ /**
+ * @param {MetricsList} metrics
+ * @returns {*}
+ * @memberof module:DashMetrics
+ * @instance
+ */
+ function getHttpRequests(metrics) {
+ if (metrics === null) {
+ return [];
+ }
+
+ return !!metrics.HttpList ? metrics.HttpList : [];
+ }
+
+ /**
+ * @param {MetricsList} metrics
+ * @param {string} metricName
+ * @returns {*}
+ * @memberof module:DashMetrics
+ * @instance
+ */
+ function getCurrent(metrics, metricName) {
+ if (metrics === null) {
+ return null;
+ }
+
+ var list = metrics[metricName];
+
+ if (list === null) {
+ return null;
+ }
+
+ var length = list.length;
+
+ if (length <= 0) {
+ return null;
+ }
+
+ return list[length - 1];
+ }
+
+ /**
+ * @param {MetricsList} metrics
+ * @returns {*}
+ * @memberof module:DashMetrics
+ * @instance
+ */
+ function getCurrentDroppedFrames(metrics) {
+ return getCurrent(metrics, MetricsList.DROPPED_FRAMES);
+ }
+
+ /**
+ * @param {MetricsList} metrics
+ * @returns {*}
+ * @memberof module:DashMetrics
+ * @instance
+ */
+ function getCurrentSchedulingInfo(metrics) {
+ return getCurrent(metrics, MetricsList.SCHEDULING_INFO);
+ }
+
+ /**
+ * @param {MetricsList} metrics
+ * @returns {*}
+ * @memberof module:DashMetrics
+ * @instance
+ */
+ function getCurrentManifestUpdate(metrics) {
+ return getCurrent(metrics, MetricsList.MANIFEST_UPDATE);
+ }
+
+ /**
+ * @param {MetricsList} metrics
+ * @returns {*}
+ * @memberof module:DashMetrics
+ * @instance
+ */
+ function getCurrentDVRInfo(metrics) {
+ return getCurrent(metrics, MetricsList.DVR_INFO);
+ }
+
+ /**
+ * @param {MetricsList} metrics
+ * @param {string} id
+ * @returns {*}
+ * @memberof module:DashMetrics
+ * @instance
+ */
+ function getLatestMPDRequestHeaderValueByID(metrics, id) {
+ var headers = {};
+ var httpRequestList, httpRequest, i;
+
+ if (metrics === null) {
+ return null;
+ }
+
+ httpRequestList = getHttpRequests(metrics);
+
+ for (i = httpRequestList.length - 1; i >= 0; i--) {
+ httpRequest = httpRequestList[i];
+
+ if (httpRequest.type === _streamingVoMetricsHTTPRequest.HTTPRequest.MPD_TYPE) {
+ headers = parseResponseHeaders(httpRequest._responseHeaders);
+ break;
+ }
+ }
+
+ return headers[id] === undefined ? null : headers[id];
+ }
+
+ /**
+ * @param {MetricsList} metrics
+ * @param {string} id
+ * @returns {*}
+ * @memberof module:DashMetrics
+ * @instance
+ */
+ function getLatestFragmentRequestHeaderValueByID(metrics, id) {
+
+ if (metrics === null) return null;
+
+ var httpRequest = getCurrentHttpRequest(metrics);
+ var headers;
+
+ if (httpRequest === null || httpRequest._responseHeaders === null) return null;
+
+ headers = parseResponseHeaders(httpRequest._responseHeaders);
+ return headers[id] === undefined ? null : headers[id];
+ }
+
+ function parseResponseHeaders(headerStr) {
+ var headers = {};
+ if (!headerStr) {
+ return headers;
+ }
+ var headerPairs = headerStr.split('\r\n');
+ for (var i = 0, ilen = headerPairs.length; i < ilen; i++) {
+ var headerPair = headerPairs[i];
+ var index = headerPair.indexOf(': ');
+ if (index > 0) {
+ headers[headerPair.substring(0, index)] = headerPair.substring(index + 2);
+ }
+ }
+ return headers;
+ }
+
+ function findRepresentationIndex(period, representationId) {
+ var index = findRepresentation(period, representationId, true);
+
+ if (index !== null) {
+ return index;
+ }
+
+ return -1;
+ }
+
+ function findRepresentation(period, representationId, returnIndex) {
+ var adaptationSet, adaptationSetArray, representation, representationArray, adaptationSetArrayIndex, representationArrayIndex;
+
+ adaptationSetArray = period.AdaptationSet_asArray;
+ for (adaptationSetArrayIndex = 0; adaptationSetArrayIndex < adaptationSetArray.length; adaptationSetArrayIndex = adaptationSetArrayIndex + 1) {
+ adaptationSet = adaptationSetArray[adaptationSetArrayIndex];
+ representationArray = adaptationSet.Representation_asArray;
+ for (representationArrayIndex = 0; representationArrayIndex < representationArray.length; representationArrayIndex = representationArrayIndex + 1) {
+ representation = representationArray[representationArrayIndex];
+ if (representationId === representation.id) {
+ if (returnIndex) {
+ return representationArrayIndex;
+ } else {
+ return representation;
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ function adaptationIsType(adaptation, bufferType) {
+ return (0, _modelsDashManifestModel2['default'])(context).getInstance().getIsTypeOf(adaptation, bufferType);
+ }
+
+ function findMaxBufferIndex(period, bufferType) {
+ var adaptationSet, adaptationSetArray, representationArray, adaptationSetArrayIndex;
+
+ if (!period || !bufferType) return -1;
+
+ adaptationSetArray = period.AdaptationSet_asArray;
+ for (adaptationSetArrayIndex = 0; adaptationSetArrayIndex < adaptationSetArray.length; adaptationSetArrayIndex = adaptationSetArrayIndex + 1) {
+ adaptationSet = adaptationSetArray[adaptationSetArrayIndex];
+ representationArray = adaptationSet.Representation_asArray;
+ if (adaptationIsType(adaptationSet, bufferType)) {
+ return representationArray.length;
+ }
+ }
+
+ return -1;
+ }
+
+ instance = {
+ getBandwidthForRepresentation: getBandwidthForRepresentation,
+ getIndexForRepresentation: getIndexForRepresentation,
+ getMaxIndexForBufferType: getMaxIndexForBufferType,
+ getCurrentRepresentationSwitch: getCurrentRepresentationSwitch,
+ getLatestBufferLevelVO: getLatestBufferLevelVO,
+ getCurrentBufferLevel: getCurrentBufferLevel,
+ getCurrentHttpRequest: getCurrentHttpRequest,
+ getHttpRequests: getHttpRequests,
+ getCurrentDroppedFrames: getCurrentDroppedFrames,
+ getCurrentSchedulingInfo: getCurrentSchedulingInfo,
+ getCurrentDVRInfo: getCurrentDVRInfo,
+ getCurrentManifestUpdate: getCurrentManifestUpdate,
+ getLatestFragmentRequestHeaderValueByID: getLatestFragmentRequestHeaderValueByID,
+ getLatestMPDRequestHeaderValueByID: getLatestMPDRequestHeaderValueByID,
+ getRequestsQueue: getRequestsQueue
+ };
+
+ return instance;
+}
+
+DashMetrics.__dashjs_factory_name = 'DashMetrics';
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(DashMetrics);
+module.exports = exports['default'];
+
+},{"10":10,"100":100,"179":179,"20":20,"22":22,"7":7}],18:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _streamingUtilsRequestModifier = _dereq_(156);
+
+var _streamingUtilsRequestModifier2 = _interopRequireDefault(_streamingUtilsRequestModifier);
+
+var _voSegment = _dereq_(46);
+
+var _voSegment2 = _interopRequireDefault(_voSegment);
+
+var _streamingVoError = _dereq_(162);
+
+var _streamingVoError2 = _interopRequireDefault(_streamingVoError);
+
+var _streamingUtilsErrorHandler = _dereq_(151);
+
+var _streamingUtilsErrorHandler2 = _interopRequireDefault(_streamingUtilsErrorHandler);
+
+var _coreEventsEvents = _dereq_(13);
+
+var _coreEventsEvents2 = _interopRequireDefault(_coreEventsEvents);
+
+var _coreEventBus = _dereq_(9);
+
+var _coreEventBus2 = _interopRequireDefault(_coreEventBus);
+
+var _streamingUtilsBoxParser = _dereq_(146);
+
+var _streamingUtilsBoxParser2 = _interopRequireDefault(_streamingUtilsBoxParser);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _coreDebug = _dereq_(8);
+
+var _coreDebug2 = _interopRequireDefault(_coreDebug);
+
+function SegmentBaseLoader() {
+
+ var context = this.context;
+ var log = (0, _coreDebug2['default'])(context).getInstance().log;
+ var eventBus = (0, _coreEventBus2['default'])(context).getInstance();
+
+ var instance = undefined,
+ errHandler = undefined,
+ boxParser = undefined,
+ requestModifier = undefined,
+ baseURLController = undefined;
+
+ function initialize() {
+ errHandler = (0, _streamingUtilsErrorHandler2['default'])(context).getInstance();
+ boxParser = (0, _streamingUtilsBoxParser2['default'])(context).getInstance();
+ requestModifier = (0, _streamingUtilsRequestModifier2['default'])(context).getInstance();
+ }
+
+ function setConfig(config) {
+ if (config.baseURLController) {
+ baseURLController = config.baseURLController;
+ }
+ }
+
+ function loadInitialization(representation, loadingInfo) {
+ var needFailureReport = true;
+ var initRange = null;
+ var isoFile = null;
+ var request = new XMLHttpRequest();
+ var baseUrl = baseURLController.resolve(representation.path);
+ var info = loadingInfo || {
+ url: baseUrl ? baseUrl.url : undefined,
+ range: {
+ start: 0,
+ end: 1500
+ },
+ searching: false,
+ bytesLoaded: 0,
+ bytesToLoad: 1500,
+ request: request
+ };
+
+ log('Start searching for initialization.');
+
+ request.onload = function () {
+ if (request.status < 200 || request.status > 299) return;
+
+ needFailureReport = false;
+
+ info.bytesLoaded = info.range.end;
+ isoFile = boxParser.parse(request.response);
+ initRange = findInitRange(isoFile);
+
+ if (initRange) {
+ representation.range = initRange;
+ representation.initialization = info.url;
+ eventBus.trigger(_coreEventsEvents2['default'].INITIALIZATION_LOADED, { representation: representation });
+ } else {
+ info.range.end = info.bytesLoaded + info.bytesToLoad;
+ loadInitialization(representation, info);
+ }
+ };
+
+ request.onloadend = request.onerror = function () {
+ if (!needFailureReport) return;
+ needFailureReport = false;
+
+ errHandler.downloadError('initialization', info.url, request);
+ eventBus.trigger(_coreEventsEvents2['default'].INITIALIZATION_LOADED, { representation: representation });
+ };
+
+ sendRequest(request, info);
+ log('Perform init search: ' + info.url);
+ }
+
+ function loadSegments(representation, type, range, loadingInfo, callback) {
+ if (range && (range.start === undefined || range.end === undefined)) {
+ var parts = range ? range.toString().split('-') : null;
+ range = parts ? { start: parseFloat(parts[0]), end: parseFloat(parts[1]) } : null;
+ }
+
+ callback = !callback ? onLoaded : callback;
+ var needFailureReport = true;
+ var isoFile = null;
+ var sidx = null;
+ var hasRange = !!range;
+ var request = new XMLHttpRequest();
+ var baseUrl = baseURLController.resolve(representation.path);
+ var info = {
+ url: baseUrl ? baseUrl.url : undefined,
+ range: hasRange ? range : { start: 0, end: 1500 },
+ searching: !hasRange,
+ bytesLoaded: loadingInfo ? loadingInfo.bytesLoaded : 0,
+ bytesToLoad: 1500,
+ request: request
+ };
+
+ request.onload = function () {
+ if (request.status < 200 || request.status > 299) return;
+
+ var extraBytes = info.bytesToLoad;
+ var loadedLength = request.response.byteLength;
+
+ needFailureReport = false;
+ info.bytesLoaded = info.range.end - info.range.start;
+ isoFile = boxParser.parse(request.response);
+ sidx = isoFile.getBox('sidx');
+
+ if (!sidx || !sidx.isComplete) {
+ if (sidx) {
+ info.range.start = sidx.offset || info.range.start;
+ info.range.end = info.range.start + (sidx.size || extraBytes);
+ } else if (loadedLength < info.bytesLoaded) {
+ // if we have reached a search limit or if we have reached the end of the file we have to stop trying to find sidx
+ callback(null, representation, type);
+ return;
+ } else {
+ var lastBox = isoFile.getLastBox();
+
+ if (lastBox && lastBox.size) {
+ info.range.start = lastBox.offset + lastBox.size;
+ info.range.end = info.range.start + extraBytes;
+ } else {
+ info.range.end += extraBytes;
+ }
+ }
+ loadSegments(representation, type, info.range, info, callback);
+ } else {
+ var ref = sidx.references;
+ var loadMultiSidx, segments;
+
+ if (ref !== null && ref !== undefined && ref.length > 0) {
+ loadMultiSidx = ref[0].reference_type === 1;
+ }
+
+ if (loadMultiSidx) {
+ log('Initiate multiple SIDX load.');
+ info.range.end = info.range.start + sidx.size;
+
+ var j, len, ss, se, r;
+ var segs = [];
+ var count = 0;
+ var offset = (sidx.offset || info.range.start) + sidx.size;
+ var tmpCallback = function tmpCallback(result) {
+ if (result) {
+ segs = segs.concat(result);
+ count++;
+
+ if (count >= len) {
+ callback(segs, representation, type);
+ }
+ } else {
+ callback(null, representation, type);
+ }
+ };
+
+ for (j = 0, len = ref.length; j < len; j++) {
+ ss = offset;
+ se = offset + ref[j].referenced_size - 1;
+ offset = offset + ref[j].referenced_size;
+ r = { start: ss, end: se };
+ loadSegments(representation, null, r, info, tmpCallback);
+ }
+ } else {
+ log('Parsing segments from SIDX.');
+ segments = getSegmentsForSidx(sidx, info);
+ callback(segments, representation, type);
+ }
+ }
+ };
+
+ request.onloadend = request.onerror = function () {
+ if (!needFailureReport) return;
+
+ needFailureReport = false;
+ errHandler.downloadError('SIDX', info.url, request);
+ callback(null, representation, type);
+ };
+
+ sendRequest(request, info);
+ log('Perform SIDX load: ' + info.url);
+ }
+
+ function reset() {
+ errHandler = null;
+ boxParser = null;
+ requestModifier = null;
+ log = null;
+ }
+
+ function getSegmentsForSidx(sidx, info) {
+
+ var refs = sidx.references;
+ var len = refs.length;
+ var timescale = sidx.timescale;
+ var time = sidx.earliest_presentation_time;
+ var start = info.range.start + sidx.offset + sidx.first_offset + sidx.size;
+ var segments = [];
+ var segment, end, duration, size;
+
+ for (var i = 0; i < len; i++) {
+ duration = refs[i].subsegment_duration;
+ size = refs[i].referenced_size;
+
+ segment = new _voSegment2['default']();
+ segment.duration = duration;
+ segment.media = info.url;
+ segment.startTime = time;
+ segment.timescale = timescale;
+ end = start + size - 1;
+ segment.mediaRange = start + '-' + end;
+ segments.push(segment);
+ time += duration;
+ start += size;
+ }
+
+ return segments;
+ }
+
+ function findInitRange(isoFile) {
+ var ftyp = isoFile.getBox('ftyp');
+ var moov = isoFile.getBox('moov');
+
+ var initRange = null;
+ var start, end;
+
+ log('Searching for initialization.');
+
+ if (moov && moov.isComplete) {
+ start = ftyp ? ftyp.offset : moov.offset;
+ end = moov.offset + moov.size - 1;
+ initRange = start + '-' + end;
+
+ log('Found the initialization. Range: ' + initRange);
+ }
+
+ return initRange;
+ }
+
+ function sendRequest(request, info) {
+ if (!info.url) {
+ return;
+ }
+
+ request.open('GET', requestModifier.modifyRequestURL(info.url));
+ request.responseType = 'arraybuffer';
+ request.setRequestHeader('Range', 'bytes=' + info.range.start + '-' + info.range.end);
+ request = requestModifier.modifyRequestHeader(request);
+ request.send(null);
+ }
+
+ function onLoaded(segments, representation, type) {
+ if (segments) {
+ eventBus.trigger(_coreEventsEvents2['default'].SEGMENTS_LOADED, { segments: segments, representation: representation, mediaType: type });
+ } else {
+ eventBus.trigger(_coreEventsEvents2['default'].SEGMENTS_LOADED, { segments: null, representation: representation, mediaType: type, error: new _streamingVoError2['default'](null, 'error loading segments', null) });
+ }
+ }
+
+ instance = {
+ setConfig: setConfig,
+ initialize: initialize,
+ loadInitialization: loadInitialization,
+ loadSegments: loadSegments,
+ reset: reset
+ };
+
+ return instance;
+}
+
+SegmentBaseLoader.__dashjs_factory_name = 'SegmentBaseLoader';
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(SegmentBaseLoader);
+module.exports = exports['default'];
+
+},{"10":10,"13":13,"146":146,"151":151,"156":156,"162":162,"46":46,"8":8,"9":9}],19:[function(_dereq_,module,exports){
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreEventsEvents = _dereq_(13);
+
+var _coreEventsEvents2 = _interopRequireDefault(_coreEventsEvents);
+
+var _coreEventBus = _dereq_(9);
+
+var _coreEventBus2 = _interopRequireDefault(_coreEventBus);
+
+var _streamingUtilsEBMLParser = _dereq_(150);
+
+var _streamingUtilsEBMLParser2 = _interopRequireDefault(_streamingUtilsEBMLParser);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _coreDebug = _dereq_(8);
+
+var _coreDebug2 = _interopRequireDefault(_coreDebug);
+
+var _streamingUtilsErrorHandler = _dereq_(151);
+
+var _streamingUtilsErrorHandler2 = _interopRequireDefault(_streamingUtilsErrorHandler);
+
+var _streamingUtilsRequestModifier = _dereq_(156);
+
+var _streamingUtilsRequestModifier2 = _interopRequireDefault(_streamingUtilsRequestModifier);
+
+var _voSegment = _dereq_(46);
+
+var _voSegment2 = _interopRequireDefault(_voSegment);
+
+var _streamingVoMetricsHTTPRequest = _dereq_(179);
+
+var _streamingVoFragmentRequest = _dereq_(163);
+
+var _streamingVoFragmentRequest2 = _interopRequireDefault(_streamingVoFragmentRequest);
+
+var _streamingXHRLoader = _dereq_(58);
+
+var _streamingXHRLoader2 = _interopRequireDefault(_streamingXHRLoader);
+
+function WebmSegmentBaseLoader() {
+
+ var context = this.context;
+ var log = (0, _coreDebug2['default'])(context).getInstance().log;
+ var eventBus = (0, _coreEventBus2['default'])(context).getInstance();
+
+ var instance = undefined,
+ WebM = undefined,
+ errHandler = undefined,
+ requestModifier = undefined,
+ metricsModel = undefined,
+ xhrLoader = undefined,
+ baseURLController = undefined;
+
+ function setup() {
+ WebM = {
+ EBML: {
+ tag: 0x1A45DFA3,
+ required: true
+ },
+ Segment: {
+ tag: 0x18538067,
+ required: true,
+ SeekHead: {
+ tag: 0x114D9B74,
+ required: true
+ },
+ Info: {
+ tag: 0x1549A966,
+ required: true,
+ TimecodeScale: {
+ tag: 0x2AD7B1,
+ required: true,
+ parse: 'getMatroskaUint'
+ },
+ Duration: {
+ tag: 0x4489,
+ required: true,
+ parse: 'getMatroskaFloat'
+ }
+ },
+ Tracks: {
+ tag: 0x1654AE6B,
+ required: true
+ },
+ Cues: {
+ tag: 0x1C53BB6B,
+ required: true,
+ CuePoint: {
+ tag: 0xBB,
+ required: true,
+ CueTime: {
+ tag: 0xB3,
+ required: true,
+ parse: 'getMatroskaUint'
+ },
+ CueTrackPositions: {
+ tag: 0xB7,
+ required: true,
+ CueTrack: {
+ tag: 0xF7,
+ required: true,
+ parse: 'getMatroskaUint'
+ },
+ CueClusterPosition: {
+ tag: 0xF1,
+ required: true,
+ parse: 'getMatroskaUint'
+ },
+ CueBlockNumber: {
+ tag: 0x5378
+ }
+ }
+ }
+ }
+ },
+ Void: {
+ tag: 0xEC,
+ required: true
+ }
+ };
+ }
+
+ function initialize() {
+ errHandler = (0, _streamingUtilsErrorHandler2['default'])(context).getInstance();
+ requestModifier = (0, _streamingUtilsRequestModifier2['default'])(context).getInstance();
+ xhrLoader = (0, _streamingXHRLoader2['default'])(context).create({
+ errHandler: errHandler,
+ metricsModel: metricsModel,
+ requestModifier: requestModifier
+ });
+ }
+
+ function setConfig(config) {
+ if (!config.baseURLController || !config.metricsModel) {
+ throw new Error('Missing config parameter(s)');
+ }
+
+ baseURLController = config.baseURLController;
+ metricsModel = config.metricsModel;
+ }
+
+ function parseCues(ab) {
+ var cues = [];
+ var cue = undefined;
+ var cueSize = undefined;
+ var cueTrack = undefined;
+ var ebmlParser = (0, _streamingUtilsEBMLParser2['default'])(context).create({ data: ab });
+ var numSize = undefined;
+
+ ebmlParser.consumeTag(WebM.Segment.Cues);
+ cueSize = ebmlParser.getMatroskaCodedNum();
+
+ while (ebmlParser.moreData() && ebmlParser.consumeTagAndSize(WebM.Segment.Cues.CuePoint, true)) {
+ cue = {};
+
+ cue.CueTime = ebmlParser.parseTag(WebM.Segment.Cues.CuePoint.CueTime);
+
+ cue.CueTracks = [];
+ while (ebmlParser.moreData() && ebmlParser.consumeTagAndSize(WebM.Segment.Cues.CuePoint.CueTrackPositions, true)) {
+ cueTrack = {};
+
+ cueTrack.Track = ebmlParser.parseTag(WebM.Segment.Cues.CuePoint.CueTrackPositions.CueTrack);
+ if (cueTrack.Track === 0) {
+ throw new Error('Cue track cannot be 0');
+ }
+
+ cueTrack.ClusterPosition = ebmlParser.parseTag(WebM.Segment.Cues.CuePoint.CueTrackPositions.CueClusterPosition);
+
+ // block number is strictly optional.
+ // we also have to make sure we don't go beyond the end
+ // of the cues
+ if (ebmlParser.getPos() + 4 > cueSize || !ebmlParser.consumeTag(WebM.Segment.Cues.CuePoint.CueTrackPositions.CueBlockNumber, true)) {
+ cue.CueTracks.push(cueTrack);
+ } else {
+ // since we have already consumed the tag, get the size of
+ // the tag's payload, and manually parse an unsigned int
+ // from the bit stream
+ numSize = ebmlParser.getMatroskaCodedNum();
+ cueTrack.BlockNumber = ebmlParser.getMatroskaUint(numSize);
+
+ cue.CueTracks.push(cueTrack);
+ }
+ }
+
+ if (cue.CueTracks.length === 0) {
+ throw new Error('Mandatory cuetrack not found');
+ }
+ cues.push(cue);
+ }
+
+ if (cues.length === 0) {
+ throw new Error('mandatory cuepoint not found');
+ }
+ return cues;
+ }
+
+ function parseSegments(data, media, segmentStart, segmentEnd, segmentDuration) {
+ var duration = undefined;
+ var parsed = undefined;
+ var segments = undefined;
+ var segment = undefined;
+ var i = undefined;
+ var len = undefined;
+ var start = undefined;
+ var end = undefined;
+
+ parsed = parseCues(data);
+ segments = [];
+
+ // we are assuming one cue track per cue point
+ // both duration and media range require the i + 1 segment
+ // the final segment has to use global segment parameters
+ for (i = 0, len = parsed.length; i < len; i += 1) {
+ segment = new _voSegment2['default']();
+ duration = 0;
+
+ if (i < parsed.length - 1) {
+ duration = parsed[i + 1].CueTime - parsed[i].CueTime;
+ } else {
+ duration = segmentDuration - parsed[i].CueTime;
+ }
+
+ segment.duration = duration;
+ segment.media = media;
+ segment.startTime = parsed[i].CueTime;
+ segment.timescale = 1000; // hardcoded for ms
+ start = parsed[i].CueTracks[0].ClusterPosition + segmentStart;
+
+ if (i < parsed.length - 1) {
+ end = parsed[i + 1].CueTracks[0].ClusterPosition + segmentStart - 1;
+ } else {
+ end = segmentEnd - 1;
+ }
+
+ segment.mediaRange = start + '-' + end;
+ segments.push(segment);
+ }
+
+ log('Parsed cues: ' + segments.length + ' cues.');
+
+ return segments;
+ }
+
+ function parseEbmlHeader(data, media, theRange, callback) {
+ var ebmlParser = (0, _streamingUtilsEBMLParser2['default'])(context).create({ data: data });
+ var duration = undefined;
+ var segments = undefined;
+ var parts = theRange.split('-');
+ var request = null;
+ var info = {
+ url: media,
+ range: {
+ start: parseFloat(parts[0]),
+ end: parseFloat(parts[1])
+ },
+ request: request
+ };
+ var segmentEnd = undefined;
+ var segmentStart = undefined;
+
+ log('Parse EBML header: ' + info.url);
+
+ // skip over the header itself
+ ebmlParser.skipOverElement(WebM.EBML);
+ ebmlParser.consumeTag(WebM.Segment);
+
+ // segments start here
+ segmentEnd = ebmlParser.getMatroskaCodedNum();
+ segmentEnd += ebmlParser.getPos();
+ segmentStart = ebmlParser.getPos();
+
+ // skip over any top level elements to get to the segment info
+ while (ebmlParser.moreData() && !ebmlParser.consumeTagAndSize(WebM.Segment.Info, true)) {
+ if (!(ebmlParser.skipOverElement(WebM.Segment.SeekHead, true) || ebmlParser.skipOverElement(WebM.Segment.Tracks, true) || ebmlParser.skipOverElement(WebM.Segment.Cues, true) || ebmlParser.skipOverElement(WebM.Void, true))) {
+ throw new Error('no valid top level element found');
+ }
+ }
+
+ // we only need one thing in segment info, duration
+ while (duration === undefined) {
+ var infoTag = ebmlParser.getMatroskaCodedNum(true);
+ var infoElementSize = ebmlParser.getMatroskaCodedNum();
+
+ switch (infoTag) {
+ case WebM.Segment.Info.Duration.tag:
+ duration = ebmlParser[WebM.Segment.Info.Duration.parse](infoElementSize);
+ break;
+ default:
+ ebmlParser.setPos(ebmlParser.getPos() + infoElementSize);
+ break;
+ }
+ }
+
+ // once we have what we need from segment info, we jump right to the
+ // cues
+
+ request = getFragmentRequest(info);
+
+ var onload = function onload(response) {
+ segments = parseSegments(response, info.url, segmentStart, segmentEnd, duration);
+ callback(segments);
+ };
+
+ var onloadend = function onloadend() {
+ log('Download Error: Cues ' + info.url);
+ callback(null);
+ };
+
+ xhrLoader.load({ request: request, success: onload, error: onloadend });
+
+ log('Perform cues load: ' + info.url + ' bytes=' + info.range.start + '-' + info.range.end);
+ }
+
+ function loadInitialization(representation, loadingInfo) {
+ var request = null;
+ var baseUrl = baseURLController.resolve(representation.path);
+ var media = baseUrl ? baseUrl.url : undefined;
+ var initRange = representation.range.split('-');
+ var info = loadingInfo || {
+ range: {
+ start: parseFloat(initRange[0]),
+ end: parseFloat(initRange[1])
+ },
+ request: request,
+ url: media,
+ init: true
+ };
+
+ log('Start loading initialization.');
+
+ request = getFragmentRequest(info);
+
+ var onload = function onload() {
+ representation.initialization = info.url;
+ eventBus.trigger(_coreEventsEvents2['default'].INITIALIZATION_LOADED, { representation: representation });
+ };
+
+ var onloadend = function onloadend() {
+ eventBus.trigger(_coreEventsEvents2['default'].INITIALIZATION_LOADED, { representation: representation });
+ };
+
+ xhrLoader.load({ request: request, success: onload, error: onloadend });
+
+ log('Perform init load: ' + info.url);
+ }
+
+ function loadSegments(representation, type, theRange, callback) {
+ var request = null;
+ var baseUrl = baseURLController.resolve(representation.path);
+ var media = baseUrl ? baseUrl.url : undefined;
+ var bytesToLoad = 8192;
+ var info = {
+ bytesLoaded: 0,
+ bytesToLoad: bytesToLoad,
+ range: {
+ start: 0,
+ end: bytesToLoad
+ },
+ request: request,
+ url: media,
+ init: false
+ };
+
+ callback = !callback ? onLoaded : callback;
+ request = getFragmentRequest(info);
+
+ // first load the header, but preserve the manifest range so we can
+ // load the cues after parsing the header
+ // NOTE: we expect segment info to appear in the first 8192 bytes
+ log('Parsing ebml header');
+
+ var onload = function onload(response) {
+ parseEbmlHeader(response, media, theRange, function (segments) {
+ callback(segments, representation, type);
+ });
+ };
+
+ var onloadend = function onloadend() {
+ callback(null, representation, type);
+ };
+
+ xhrLoader.load({ request: request, success: onload, error: onloadend });
+ }
+
+ function onLoaded(segments, representation, type) {
+ if (segments) {
+ eventBus.trigger(_coreEventsEvents2['default'].SEGMENTS_LOADED, { segments: segments, representation: representation, mediaType: type });
+ } else {
+ eventBus.trigger(_coreEventsEvents2['default'].SEGMENTS_LOADED, { segments: null, representation: representation, mediaType: type, error: new Error(null, 'error loading segments', null) });
+ }
+ }
+
+ function getFragmentRequest(info) {
+ var request = new _streamingVoFragmentRequest2['default']();
+
+ request.type = info.init ? _streamingVoMetricsHTTPRequest.HTTPRequest.INIT_SEGMENT_TYPE : _streamingVoMetricsHTTPRequest.HTTPRequest.MEDIA_SEGMENT_TYPE;
+ request.url = info.url;
+ request.range = info.range.start + '-' + info.range.end;
+
+ return request;
+ }
+
+ function reset() {
+ errHandler = null;
+ requestModifier = null;
+ log = null;
+ }
+
+ instance = {
+ setConfig: setConfig,
+ initialize: initialize,
+ loadInitialization: loadInitialization,
+ loadSegments: loadSegments,
+ reset: reset
+ };
+
+ setup();
+
+ return instance;
+}
+
+WebmSegmentBaseLoader.__dashjs_factory_name = 'WebmSegmentBaseLoader';
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(WebmSegmentBaseLoader);
+module.exports = exports['default'];
+
+},{"10":10,"13":13,"150":150,"151":151,"156":156,"163":163,"179":179,"46":46,"58":58,"8":8,"9":9}],20:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+var TCP_CONNECTION = 'TcpList';
+exports.TCP_CONNECTION = TCP_CONNECTION;
+var HTTP_REQUEST = 'HttpList';
+exports.HTTP_REQUEST = HTTP_REQUEST;
+var TRACK_SWITCH = 'RepSwitchList';
+exports.TRACK_SWITCH = TRACK_SWITCH;
+var BUFFER_LEVEL = 'BufferLevel';
+exports.BUFFER_LEVEL = BUFFER_LEVEL;
+var BUFFER_STATE = 'BufferState';
+exports.BUFFER_STATE = BUFFER_STATE;
+var DVR_INFO = 'DVRInfo';
+exports.DVR_INFO = DVR_INFO;
+var DROPPED_FRAMES = 'DroppedFrames';
+exports.DROPPED_FRAMES = DROPPED_FRAMES;
+var SCHEDULING_INFO = 'SchedulingInfo';
+exports.SCHEDULING_INFO = SCHEDULING_INFO;
+var REQUESTS_QUEUE = 'RequestsQueue';
+exports.REQUESTS_QUEUE = REQUESTS_QUEUE;
+var MANIFEST_UPDATE = 'ManifestUpdate';
+exports.MANIFEST_UPDATE = MANIFEST_UPDATE;
+var MANIFEST_UPDATE_STREAM_INFO = 'ManifestUpdatePeriodInfo';
+exports.MANIFEST_UPDATE_STREAM_INFO = MANIFEST_UPDATE_STREAM_INFO;
+var MANIFEST_UPDATE_TRACK_INFO = 'ManifestUpdateRepresentationInfo';
+exports.MANIFEST_UPDATE_TRACK_INFO = MANIFEST_UPDATE_TRACK_INFO;
+var PLAY_LIST = 'PlayList';
+exports.PLAY_LIST = PLAY_LIST;
+var DVB_ERRORS = 'DVBErrors';
+exports.DVB_ERRORS = DVB_ERRORS;
+
+},{}],21:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _modelsDashManifestModel = _dereq_(22);
+
+var _modelsDashManifestModel2 = _interopRequireDefault(_modelsDashManifestModel);
+
+var _DashMetrics = _dereq_(17);
+
+var _DashMetrics2 = _interopRequireDefault(_DashMetrics);
+
+var _utilsTimelineConverter = _dereq_(37);
+
+var _utilsTimelineConverter2 = _interopRequireDefault(_utilsTimelineConverter);
+
+var _streamingControllersAbrController = _dereq_(60);
+
+var _streamingControllersAbrController2 = _interopRequireDefault(_streamingControllersAbrController);
+
+var _streamingControllersPlaybackController = _dereq_(68);
+
+var _streamingControllersPlaybackController2 = _interopRequireDefault(_streamingControllersPlaybackController);
+
+var _streamingControllersStreamController = _dereq_(71);
+
+var _streamingControllersStreamController2 = _interopRequireDefault(_streamingControllersStreamController);
+
+var _streamingModelsManifestModel = _dereq_(100);
+
+var _streamingModelsManifestModel2 = _interopRequireDefault(_streamingModelsManifestModel);
+
+var _streamingModelsMetricsModel = _dereq_(102);
+
+var _streamingModelsMetricsModel2 = _interopRequireDefault(_streamingModelsMetricsModel);
+
+var _streamingModelsMediaPlayerModel = _dereq_(101);
+
+var _streamingModelsMediaPlayerModel2 = _interopRequireDefault(_streamingModelsMediaPlayerModel);
+
+var _streamingUtilsDOMStorage = _dereq_(149);
+
+var _streamingUtilsDOMStorage2 = _interopRequireDefault(_streamingUtilsDOMStorage);
+
+var _streamingVoError = _dereq_(162);
+
+var _streamingVoError2 = _interopRequireDefault(_streamingVoError);
+
+var _coreEventBus = _dereq_(9);
+
+var _coreEventBus2 = _interopRequireDefault(_coreEventBus);
+
+var _coreEventsEvents = _dereq_(13);
+
+var _coreEventsEvents2 = _interopRequireDefault(_coreEventsEvents);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+function RepresentationController() {
+
+ var SEGMENTS_UPDATE_FAILED_ERROR_CODE = 1;
+
+ var context = this.context;
+ var eventBus = (0, _coreEventBus2['default'])(context).getInstance();
+
+ var instance = undefined,
+ data = undefined,
+ dataIndex = undefined,
+ updating = undefined,
+ availableRepresentations = undefined,
+ currentRepresentation = undefined,
+ streamProcessor = undefined,
+ abrController = undefined,
+ indexHandler = undefined,
+ streamController = undefined,
+ playbackController = undefined,
+ manifestModel = undefined,
+ metricsModel = undefined,
+ domStorage = undefined,
+ timelineConverter = undefined,
+ dashManifestModel = undefined,
+ dashMetrics = undefined,
+ mediaPlayerModel = undefined;
+
+ function setup() {
+ data = null;
+ dataIndex = -1;
+ updating = true;
+ availableRepresentations = [];
+
+ abrController = (0, _streamingControllersAbrController2['default'])(context).getInstance();
+ streamController = (0, _streamingControllersStreamController2['default'])(context).getInstance();
+ playbackController = (0, _streamingControllersPlaybackController2['default'])(context).getInstance();
+ manifestModel = (0, _streamingModelsManifestModel2['default'])(context).getInstance();
+ metricsModel = (0, _streamingModelsMetricsModel2['default'])(context).getInstance();
+ domStorage = (0, _streamingUtilsDOMStorage2['default'])(context).getInstance();
+ timelineConverter = (0, _utilsTimelineConverter2['default'])(context).getInstance();
+ dashManifestModel = (0, _modelsDashManifestModel2['default'])(context).getInstance();
+ dashMetrics = (0, _DashMetrics2['default'])(context).getInstance();
+ mediaPlayerModel = (0, _streamingModelsMediaPlayerModel2['default'])(context).getInstance();
+
+ eventBus.on(_coreEventsEvents2['default'].QUALITY_CHANGE_REQUESTED, onQualityChanged, instance);
+ eventBus.on(_coreEventsEvents2['default'].REPRESENTATION_UPDATED, onRepresentationUpdated, instance);
+ eventBus.on(_coreEventsEvents2['default'].WALLCLOCK_TIME_UPDATED, onWallclockTimeUpdated, instance);
+ eventBus.on(_coreEventsEvents2['default'].BUFFER_LEVEL_UPDATED, onBufferLevelUpdated, instance);
+ eventBus.on(_coreEventsEvents2['default'].LIVE_EDGE_SEARCH_COMPLETED, onLiveEdgeSearchCompleted, instance);
+ }
+
+ function setConfig(config) {
+ // allow the abrController created in setup to be overidden
+ if (config.abrController) {
+ abrController = config.abrController;
+ }
+ }
+
+ function initialize(StreamProcessor) {
+ streamProcessor = StreamProcessor;
+ indexHandler = streamProcessor.getIndexHandler();
+ }
+
+ function getStreamProcessor() {
+ return streamProcessor;
+ }
+
+ function getData() {
+ return data;
+ }
+
+ function getDataIndex() {
+ return dataIndex;
+ }
+
+ function isUpdating() {
+ return updating;
+ }
+
+ function getCurrentRepresentation() {
+ return currentRepresentation;
+ }
+
+ function reset() {
+
+ eventBus.off(_coreEventsEvents2['default'].QUALITY_CHANGE_REQUESTED, onQualityChanged, instance);
+ eventBus.off(_coreEventsEvents2['default'].REPRESENTATION_UPDATED, onRepresentationUpdated, instance);
+ eventBus.off(_coreEventsEvents2['default'].WALLCLOCK_TIME_UPDATED, onWallclockTimeUpdated, instance);
+ eventBus.off(_coreEventsEvents2['default'].BUFFER_LEVEL_UPDATED, onBufferLevelUpdated, instance);
+ eventBus.off(_coreEventsEvents2['default'].LIVE_EDGE_SEARCH_COMPLETED, onLiveEdgeSearchCompleted, instance);
+
+ data = null;
+ dataIndex = -1;
+ updating = true;
+ availableRepresentations = [];
+ abrController = null;
+ streamController = null;
+ playbackController = null;
+ manifestModel = null;
+ metricsModel = null;
+ domStorage = null;
+ timelineConverter = null;
+ dashManifestModel = null;
+ dashMetrics = null;
+ mediaPlayerModel = null;
+ }
+
+ function updateData(dataValue, adaptation, type) {
+ var quality, averageThroughput;
+
+ var bitrate = null;
+ var streamInfo = streamProcessor.getStreamInfo();
+ var maxQuality = abrController.getTopQualityIndexFor(type, streamInfo.id);
+
+ updating = true;
+ eventBus.trigger(_coreEventsEvents2['default'].DATA_UPDATE_STARTED, { sender: this });
+
+ availableRepresentations = updateRepresentations(adaptation);
+
+ if (data === null && type !== 'fragmentedText') {
+ averageThroughput = abrController.getAverageThroughput(type);
+ bitrate = averageThroughput || abrController.getInitialBitrateFor(type, streamInfo);
+ quality = abrController.getQualityForBitrate(streamProcessor.getMediaInfo(), bitrate);
+ } else {
+ quality = abrController.getQualityFor(type, streamInfo);
+ }
+
+ if (quality > maxQuality) {
+ quality = maxQuality;
+ }
+
+ currentRepresentation = getRepresentationForQuality(quality);
+ data = dataValue;
+
+ if (type !== 'video' && type !== 'audio' && type !== 'fragmentedText') {
+ updating = false;
+ eventBus.trigger(_coreEventsEvents2['default'].DATA_UPDATE_COMPLETED, { sender: this, data: data, currentRepresentation: currentRepresentation });
+ return;
+ }
+
+ for (var i = 0; i < availableRepresentations.length; i++) {
+ indexHandler.updateRepresentation(availableRepresentations[i], true);
+ }
+ }
+
+ function addRepresentationSwitch() {
+ var now = new Date();
+ var currentRepresentation = getCurrentRepresentation();
+ var currentVideoTimeMs = playbackController.getTime() * 1000;
+
+ metricsModel.addRepresentationSwitch(currentRepresentation.adaptation.type, now, currentVideoTimeMs, currentRepresentation.id);
+ }
+
+ function addDVRMetric() {
+ var range = timelineConverter.calcSegmentAvailabilityRange(currentRepresentation, streamProcessor.isDynamic());
+ metricsModel.addDVRInfo(streamProcessor.getType(), playbackController.getTime(), streamProcessor.getStreamInfo().manifestInfo, range);
+ }
+
+ function getRepresentationForQuality(quality) {
+ return availableRepresentations[quality];
+ }
+
+ function getQualityForRepresentation(representation) {
+ return availableRepresentations.indexOf(representation);
+ }
+
+ function isAllRepresentationsUpdated() {
+ for (var i = 0, ln = availableRepresentations.length; i < ln; i++) {
+ var segmentInfoType = availableRepresentations[i].segmentInfoType;
+ if (availableRepresentations[i].segmentAvailabilityRange === null || availableRepresentations[i].initialization === null || (segmentInfoType === 'SegmentBase' || segmentInfoType === 'BaseURL') && !availableRepresentations[i].segments) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ function updateRepresentations(adaptation) {
+ var reps;
+ var manifest = manifestModel.getValue();
+
+ dataIndex = dashManifestModel.getIndexForAdaptation(data, manifest, adaptation.period.index);
+ reps = dashManifestModel.getRepresentationsForAdaptation(manifest, adaptation);
+
+ return reps;
+ }
+
+ function updateAvailabilityWindow(isDynamic) {
+ var rep;
+
+ for (var i = 0, ln = availableRepresentations.length; i < ln; i++) {
+ rep = availableRepresentations[i];
+ rep.segmentAvailabilityRange = timelineConverter.calcSegmentAvailabilityRange(rep, isDynamic);
+ }
+ }
+
+ function resetAvailabilityWindow() {
+ availableRepresentations.forEach(function (rep) {
+ rep.segmentAvailabilityRange = null;
+ });
+ }
+
+ function postponeUpdate(postponeTimePeriod) {
+ var delay = postponeTimePeriod;
+ var update = function update() {
+ if (isUpdating()) return;
+
+ updating = true;
+ eventBus.trigger(_coreEventsEvents2['default'].DATA_UPDATE_STARTED, { sender: instance });
+
+ // clear the segmentAvailabilityRange for all reps.
+ // this ensures all are updated before the live edge search starts
+ resetAvailabilityWindow();
+
+ for (var i = 0; i < availableRepresentations.length; i++) {
+ indexHandler.updateRepresentation(availableRepresentations[i], true);
+ }
+ };
+
+ updating = false;
+ eventBus.trigger(_coreEventsEvents2['default'].AST_IN_FUTURE, { delay: delay });
+ setTimeout(update, delay);
+ }
+
+ function onRepresentationUpdated(e) {
+ if (e.sender.getStreamProcessor() !== streamProcessor || !isUpdating()) return;
+
+ var r = e.representation;
+ var streamMetrics = metricsModel.getMetricsFor('stream');
+ var metrics = metricsModel.getMetricsFor(getCurrentRepresentation().adaptation.type);
+ var manifestUpdateInfo = dashMetrics.getCurrentManifestUpdate(streamMetrics);
+ var alreadyAdded = false;
+ var postponeTimePeriod = 0;
+ var repInfo;
+ var err;
+ var repSwitch;
+
+ if (r.adaptation.period.mpd.manifest.type === 'dynamic') {
+ var segmentAvailabilityTimePeriod = r.segmentAvailabilityRange.end - r.segmentAvailabilityRange.start;
+ // We must put things to sleep unless till e.g. the startTime calculation in ScheduleController.onLiveEdgeSearchCompleted fall after the segmentAvailabilityRange.start
+ var liveDelay = playbackController.computeLiveDelay(currentRepresentation.segmentDuration, streamProcessor.getStreamInfo().manifestInfo.DVRWindowSize);
+ postponeTimePeriod = (liveDelay - segmentAvailabilityTimePeriod) * 1000;
+ }
+
+ if (postponeTimePeriod > 0) {
+ addDVRMetric();
+ postponeUpdate(postponeTimePeriod);
+ err = new _streamingVoError2['default'](SEGMENTS_UPDATE_FAILED_ERROR_CODE, 'Segments update failed', null);
+ eventBus.trigger(_coreEventsEvents2['default'].DATA_UPDATE_COMPLETED, { sender: this, data: data, currentRepresentation: currentRepresentation, error: err });
+
+ return;
+ }
+
+ if (manifestUpdateInfo) {
+ for (var i = 0; i < manifestUpdateInfo.trackInfo.length; i++) {
+ repInfo = manifestUpdateInfo.trackInfo[i];
+ if (repInfo.index === r.index && repInfo.mediaType === streamProcessor.getType()) {
+ alreadyAdded = true;
+ break;
+ }
+ }
+
+ if (!alreadyAdded) {
+ metricsModel.addManifestUpdateRepresentationInfo(manifestUpdateInfo, r.id, r.index, r.adaptation.period.index, streamProcessor.getType(), r.presentationTimeOffset, r.startNumber, r.segmentInfoType);
+ }
+ }
+
+ if (isAllRepresentationsUpdated()) {
+ updating = false;
+ abrController.setPlaybackQuality(streamProcessor.getType(), streamProcessor.getStreamInfo(), getQualityForRepresentation(currentRepresentation));
+ metricsModel.updateManifestUpdateInfo(manifestUpdateInfo, { latency: currentRepresentation.segmentAvailabilityRange.end - playbackController.getTime() });
+
+ repSwitch = dashMetrics.getCurrentRepresentationSwitch(metrics);
+
+ if (!repSwitch) {
+ addRepresentationSwitch();
+ }
+
+ eventBus.trigger(_coreEventsEvents2['default'].DATA_UPDATE_COMPLETED, { sender: this, data: data, currentRepresentation: currentRepresentation });
+ }
+ }
+
+ function onWallclockTimeUpdated(e) {
+ if (e.isDynamic) {
+ updateAvailabilityWindow(e.isDynamic);
+ }
+ }
+
+ function onLiveEdgeSearchCompleted(e) {
+ if (e.error) return;
+
+ updateAvailabilityWindow(true);
+ indexHandler.updateRepresentation(currentRepresentation, false);
+
+ // we need to update checkTime after we have found the live edge because its initial value
+ // does not take into account clientServerTimeShift
+ var manifest = manifestModel.getValue();
+ var period = currentRepresentation.adaptation.period;
+ var streamInfo = streamController.getActiveStreamInfo();
+
+ if (streamInfo.isLast) {
+ period.mpd.checkTime = dashManifestModel.getCheckTime(manifest, period);
+ period.duration = dashManifestModel.getEndTimeForLastPeriod(manifestModel.getValue(), period) - period.start;
+ streamInfo.duration = period.duration;
+ }
+ }
+
+ function onBufferLevelUpdated(e) {
+ if (e.sender.getStreamProcessor() !== streamProcessor) return;
+ addDVRMetric();
+ }
+
+ function onQualityChanged(e) {
+ if (e.mediaType !== streamProcessor.getType() || streamProcessor.getStreamInfo().id !== e.streamInfo.id) return;
+
+ if (e.oldQuality !== e.newQuality) {
+ currentRepresentation = getRepresentationForQuality(e.newQuality);
+ domStorage.setSavedBitrateSettings(e.mediaType, currentRepresentation.bandwidth);
+ addRepresentationSwitch();
+ }
+ }
+
+ instance = {
+ initialize: initialize,
+ setConfig: setConfig,
+ getData: getData,
+ getDataIndex: getDataIndex,
+ isUpdating: isUpdating,
+ updateData: updateData,
+ getStreamProcessor: getStreamProcessor,
+ getCurrentRepresentation: getCurrentRepresentation,
+ getRepresentationForQuality: getRepresentationForQuality,
+ reset: reset
+ };
+
+ setup();
+ return instance;
+}
+
+RepresentationController.__dashjs_factory_name = 'RepresentationController';
+exports['default'] = _coreFactoryMaker2['default'].getClassFactory(RepresentationController);
+module.exports = exports['default'];
+
+},{"10":10,"100":100,"101":101,"102":102,"13":13,"149":149,"162":162,"17":17,"22":22,"37":37,"60":60,"68":68,"71":71,"9":9}],22:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _voRepresentation = _dereq_(45);
+
+var _voRepresentation2 = _interopRequireDefault(_voRepresentation);
+
+var _voAdaptationSet = _dereq_(39);
+
+var _voAdaptationSet2 = _interopRequireDefault(_voAdaptationSet);
+
+var _voPeriod = _dereq_(44);
+
+var _voPeriod2 = _interopRequireDefault(_voPeriod);
+
+var _voMpd = _dereq_(43);
+
+var _voMpd2 = _interopRequireDefault(_voMpd);
+
+var _voUTCTiming = _dereq_(47);
+
+var _voUTCTiming2 = _interopRequireDefault(_voUTCTiming);
+
+var _utilsTimelineConverter = _dereq_(37);
+
+var _utilsTimelineConverter2 = _interopRequireDefault(_utilsTimelineConverter);
+
+var _streamingControllersMediaController = _dereq_(66);
+
+var _streamingControllersMediaController2 = _interopRequireDefault(_streamingControllersMediaController);
+
+var _DashAdapter = _dereq_(15);
+
+var _DashAdapter2 = _interopRequireDefault(_DashAdapter);
+
+var _voEvent = _dereq_(41);
+
+var _voEvent2 = _interopRequireDefault(_voEvent);
+
+var _voBaseURL = _dereq_(40);
+
+var _voBaseURL2 = _interopRequireDefault(_voBaseURL);
+
+var _voEventStream = _dereq_(42);
+
+var _voEventStream2 = _interopRequireDefault(_voEventStream);
+
+var _streamingUtilsURLUtils = _dereq_(158);
+
+var _streamingUtilsURLUtils2 = _interopRequireDefault(_streamingUtilsURLUtils);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+function DashManifestModel() {
+
+ var instance = undefined;
+ var context = this.context;
+ var timelineConverter = (0, _utilsTimelineConverter2['default'])(context).getInstance(); //TODO Need to pass this in not bake in
+ var mediaController = (0, _streamingControllersMediaController2['default'])(context).getInstance();
+ var adaptor = (0, _DashAdapter2['default'])(context).getInstance();
+
+ var urlUtils = (0, _streamingUtilsURLUtils2['default'])(context).getInstance();
+
+ function getIsTypeOf(adaptation, type) {
+
+ var i, len, representation;
+ var result = false;
+ var found = false;
+
+ var col = adaptation.ContentComponent_asArray;
+ var mimeTypeRegEx = type !== 'text' ? new RegExp(type) : new RegExp('(vtt|ttml)');
+
+ if (adaptation.Representation_asArray.length > 0 && adaptation.Representation_asArray[0].hasOwnProperty('codecs')) {
+ var codecs = adaptation.Representation_asArray[0].codecs;
+ if (codecs === 'stpp' || codecs === 'wvtt') {
+ return type === 'fragmentedText';
+ }
+ }
+
+ if (col) {
+ if (col.length > 1) {
+ return type === 'muxed';
+ } else if (col[0] && col[0].contentType === type) {
+ result = true;
+ found = true;
+ }
+ }
+
+ if (adaptation.hasOwnProperty('mimeType')) {
+ result = mimeTypeRegEx.test(adaptation.mimeType);
+ found = true;
+ }
+
+ // couldn't find on adaptationset, so check a representation
+ if (!found) {
+ i = 0;
+ len = adaptation.Representation_asArray.length;
+ while (!found && i < len) {
+ representation = adaptation.Representation_asArray[i];
+
+ if (representation.hasOwnProperty('mimeType')) {
+ result = mimeTypeRegEx.test(representation.mimeType);
+ found = true;
+ }
+
+ i++;
+ }
+ }
+
+ return result;
+ }
+
+ function getIsAudio(adaptation) {
+ return getIsTypeOf(adaptation, 'audio');
+ }
+
+ function getIsVideo(adaptation) {
+ return getIsTypeOf(adaptation, 'video');
+ }
+
+ function getIsFragmentedText(adaptation) {
+ return getIsTypeOf(adaptation, 'fragmentedText');
+ }
+
+ function getIsText(adaptation) {
+ return getIsTypeOf(adaptation, 'text');
+ }
+
+ function getIsMuxed(adaptation) {
+ return getIsTypeOf(adaptation, 'muxed');
+ }
+
+ function getIsTextTrack(type) {
+ return type === 'text/vtt' || type === 'application/ttml+xml';
+ }
+
+ function getLanguageForAdaptation(adaptation) {
+ var lang = '';
+
+ if (adaptation.hasOwnProperty('lang')) {
+ //Filter out any other characters not allowed according to RFC5646
+ lang = adaptation.lang.replace(/[^A-Za-z0-9-]/g, '');
+ }
+
+ return lang;
+ }
+
+ function getViewpointForAdaptation(adaptation) {
+ return adaptation.hasOwnProperty('Viewpoint') ? adaptation.Viewpoint : null;
+ }
+
+ function getRolesForAdaptation(adaptation) {
+ return adaptation.hasOwnProperty('Role_asArray') ? adaptation.Role_asArray : [];
+ }
+
+ function getAccessibilityForAdaptation(adaptation) {
+ return adaptation.hasOwnProperty('Accessibility_asArray') ? adaptation.Accessibility_asArray : [];
+ }
+
+ function getAudioChannelConfigurationForAdaptation(adaptation) {
+ return adaptation.hasOwnProperty('AudioChannelConfiguration_asArray') ? adaptation.AudioChannelConfiguration_asArray : [];
+ }
+
+ function getIsMain(adaptation) {
+ return getRolesForAdaptation(adaptation).filter(function (role) {
+ return role.value === 'main';
+ })[0];
+ }
+
+ function getRepresentationSortFunction() {
+ return function (a, b) {
+ return a.bandwidth - b.bandwidth;
+ };
+ }
+
+ function processAdaptation(adaptation) {
+ if (adaptation.Representation_asArray !== undefined && adaptation.Representation_asArray !== null) {
+ adaptation.Representation_asArray.sort(getRepresentationSortFunction());
+ }
+
+ return adaptation;
+ }
+
+ function getAdaptationForId(id, manifest, periodIndex) {
+
+ var adaptations = manifest.Period_asArray[periodIndex].AdaptationSet_asArray;
+ var i, len;
+
+ for (i = 0, len = adaptations.length; i < len; i++) {
+ if (adaptations[i].hasOwnProperty('id') && adaptations[i].id === id) {
+ return adaptations[i];
+ }
+ }
+
+ return null;
+ }
+
+ function getAdaptationForIndex(index, manifest, periodIndex) {
+ var adaptations = manifest.Period_asArray[periodIndex].AdaptationSet_asArray;
+ return adaptations[index];
+ }
+
+ function getIndexForAdaptation(adaptation, manifest, periodIndex) {
+
+ var adaptations = manifest.Period_asArray[periodIndex].AdaptationSet_asArray;
+ var i, len;
+
+ for (i = 0, len = adaptations.length; i < len; i++) {
+ if (adaptations[i] === adaptation) {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ function getAdaptationsForType(manifest, periodIndex, type) {
+
+ var adaptationSet = manifest.Period_asArray[periodIndex].AdaptationSet_asArray;
+ var i, len;
+ var adaptations = [];
+
+ for (i = 0, len = adaptationSet.length; i < len; i++) {
+ if (getIsTypeOf(adaptationSet[i], type)) {
+ adaptations.push(processAdaptation(adaptationSet[i]));
+ }
+ }
+
+ return adaptations;
+ }
+
+ function getAdaptationForType(manifest, periodIndex, type, streamInfo) {
+
+ var adaptations = getAdaptationsForType(manifest, periodIndex, type);
+
+ if (!adaptations || adaptations.length === 0) return null;
+
+ if (adaptations.length > 1 && streamInfo) {
+ var currentTrack = mediaController.getCurrentTrackFor(type, streamInfo);
+ var allMediaInfoForType = adaptor.getAllMediaInfoForType(manifest, streamInfo, type);
+ for (var i = 0, ln = adaptations.length; i < ln; i++) {
+ if (currentTrack && mediaController.isTracksEqual(currentTrack, allMediaInfoForType[i])) {
+ return adaptations[i];
+ }
+ if (getIsMain(adaptations[i])) {
+ return adaptations[i];
+ }
+ }
+ }
+
+ return adaptations[0];
+ }
+
+ function getCodec(adaptation) {
+ var representation = adaptation.Representation_asArray[0];
+ return representation.mimeType + ';codecs="' + representation.codecs + '"';
+ }
+
+ function getMimeType(adaptation) {
+ return adaptation.Representation_asArray[0].mimeType;
+ }
+
+ function getKID(adaptation) {
+ if (!adaptation || !adaptation.hasOwnProperty('cenc:default_KID')) {
+ return null;
+ }
+ return adaptation['cenc:default_KID'];
+ }
+
+ function getContentProtectionData(adaptation) {
+ if (!adaptation || !adaptation.hasOwnProperty('ContentProtection_asArray') || adaptation.ContentProtection_asArray.length === 0) {
+ return null;
+ }
+ return adaptation.ContentProtection_asArray;
+ }
+
+ function getIsDynamic(manifest) {
+ var isDynamic = false;
+ if (manifest.hasOwnProperty('type')) {
+ isDynamic = manifest.type === 'dynamic';
+ }
+ return isDynamic;
+ }
+
+ function getIsDVR(manifest) {
+ var isDynamic = getIsDynamic(manifest);
+ var containsDVR, isDVR;
+
+ containsDVR = !isNaN(manifest.timeShiftBufferDepth);
+ isDVR = isDynamic && containsDVR;
+
+ return isDVR;
+ }
+
+ function hasProfile(manifest, profile) {
+ var has = false;
+
+ if (manifest.profiles && manifest.profiles.length > 0) {
+ has = manifest.profiles.indexOf(profile) !== -1;
+ }
+
+ return has;
+ }
+
+ function getIsOnDemand(manifest) {
+ return hasProfile(manifest, 'urn:mpeg:dash:profile:isoff-on-demand:2011');
+ }
+
+ function getIsDVB(manifest) {
+ return hasProfile(manifest, 'urn:dvb:dash:profile:dvb-dash:2014');
+ }
+
+ function getDuration(manifest) {
+ var mpdDuration;
+ //@mediaPresentationDuration specifies the duration of the entire Media Presentation.
+ //If the attribute is not present, the duration of the Media Presentation is unknown.
+ if (manifest.hasOwnProperty('mediaPresentationDuration')) {
+ mpdDuration = manifest.mediaPresentationDuration;
+ } else {
+ mpdDuration = Number.MAX_VALUE;
+ }
+
+ return mpdDuration;
+ }
+
+ function getBandwidth(representation) {
+ return representation.bandwidth;
+ }
+
+ function getRefreshDelay(manifest) {
+ var delay = NaN;
+ var minDelay = 2;
+
+ if (manifest.hasOwnProperty('minimumUpdatePeriod')) {
+ delay = Math.max(parseFloat(manifest.minimumUpdatePeriod), minDelay);
+ }
+
+ return delay;
+ }
+
+ function getRepresentationCount(adaptation) {
+ return adaptation.Representation_asArray.length;
+ }
+
+ function getBitrateListForAdaptation(adaptation) {
+ if (!adaptation || !adaptation.Representation_asArray || !adaptation.Representation_asArray.length) return null;
+
+ var a = processAdaptation(adaptation);
+ var reps = a.Representation_asArray;
+ var ln = reps.length;
+ var bitrateList = [];
+
+ for (var i = 0; i < ln; i++) {
+ bitrateList.push({
+ bandwidth: reps[i].bandwidth,
+ width: reps[i].width || 0,
+ height: reps[i].height || 0
+ });
+ }
+
+ return bitrateList;
+ }
+
+ function getRepresentationFor(index, adaptation) {
+ return adaptation.Representation_asArray[index];
+ }
+
+ function getRepresentationsForAdaptation(manifest, adaptation) {
+ var a = processAdaptation(manifest.Period_asArray[adaptation.period.index].AdaptationSet_asArray[adaptation.index]);
+ var representations = [];
+ var representation, initialization, segmentInfo, r, s;
+
+ for (var i = 0; i < a.Representation_asArray.length; i++) {
+ r = a.Representation_asArray[i];
+ representation = new _voRepresentation2['default']();
+ representation.index = i;
+ representation.adaptation = adaptation;
+
+ if (r.hasOwnProperty('id')) {
+ representation.id = r.id;
+ }
+
+ if (r.hasOwnProperty('bandwidth')) {
+ representation.bandwidth = r.bandwidth;
+ }
+ if (r.hasOwnProperty('maxPlayoutRate')) {
+ representation.maxPlayoutRate = r.maxPlayoutRate;
+ }
+ if (r.hasOwnProperty('SegmentBase')) {
+ segmentInfo = r.SegmentBase;
+ representation.segmentInfoType = 'SegmentBase';
+ } else if (r.hasOwnProperty('SegmentList')) {
+ segmentInfo = r.SegmentList;
+
+ if (segmentInfo.hasOwnProperty('SegmentTimeline')) {
+ representation.segmentInfoType = 'SegmentTimeline';
+ s = segmentInfo.SegmentTimeline.S_asArray[segmentInfo.SegmentTimeline.S_asArray.length - 1];
+ if (!s.hasOwnProperty('r') || s.r >= 0) {
+ representation.useCalculatedLiveEdgeTime = true;
+ }
+ } else {
+ representation.segmentInfoType = 'SegmentList';
+ representation.useCalculatedLiveEdgeTime = true;
+ }
+ } else if (r.hasOwnProperty('SegmentTemplate')) {
+ segmentInfo = r.SegmentTemplate;
+
+ if (segmentInfo.hasOwnProperty('SegmentTimeline')) {
+ representation.segmentInfoType = 'SegmentTimeline';
+ s = segmentInfo.SegmentTimeline.S_asArray[segmentInfo.SegmentTimeline.S_asArray.length - 1];
+ if (!s.hasOwnProperty('r') || s.r >= 0) {
+ representation.useCalculatedLiveEdgeTime = true;
+ }
+ } else {
+ representation.segmentInfoType = 'SegmentTemplate';
+ }
+
+ if (segmentInfo.hasOwnProperty('initialization')) {
+ representation.initialization = segmentInfo.initialization.split('$Bandwidth$').join(r.bandwidth).split('$RepresentationID$').join(r.id);
+ }
+ } else {
+ segmentInfo = r.BaseURL;
+ representation.segmentInfoType = 'BaseURL';
+ }
+
+ if (segmentInfo.hasOwnProperty('Initialization')) {
+ initialization = segmentInfo.Initialization;
+ if (initialization.hasOwnProperty('sourceURL')) {
+ representation.initialization = initialization.sourceURL;
+ } else if (initialization.hasOwnProperty('range')) {
+ representation.range = initialization.range;
+ }
+ } else if (r.hasOwnProperty('mimeType') && getIsTextTrack(r.mimeType)) {
+ representation.range = 0;
+ }
+
+ if (segmentInfo.hasOwnProperty('timescale')) {
+ representation.timescale = segmentInfo.timescale;
+ }
+ if (segmentInfo.hasOwnProperty('duration')) {
+ // TODO according to the spec @maxSegmentDuration specifies the maximum duration of any Segment in any Representation in the Media Presentation
+ // It is also said that for a SegmentTimeline any @d value shall not exceed the value of MPD@maxSegmentDuration, but nothing is said about
+ // SegmentTemplate @duration attribute. We need to find out if @maxSegmentDuration should be used instead of calculated duration if the the duration
+ // exceeds @maxSegmentDuration
+ //representation.segmentDuration = Math.min(segmentInfo.duration / representation.timescale, adaptation.period.mpd.maxSegmentDuration);
+ representation.segmentDuration = segmentInfo.duration / representation.timescale;
+ }
+ if (segmentInfo.hasOwnProperty('startNumber')) {
+ representation.startNumber = segmentInfo.startNumber;
+ }
+ if (segmentInfo.hasOwnProperty('indexRange')) {
+ representation.indexRange = segmentInfo.indexRange;
+ }
+ if (segmentInfo.hasOwnProperty('presentationTimeOffset')) {
+ representation.presentationTimeOffset = segmentInfo.presentationTimeOffset / representation.timescale;
+ }
+
+ representation.MSETimeOffset = timelineConverter.calcMSETimeOffset(representation);
+
+ representation.path = [adaptation.period.index, adaptation.index, i];
+
+ representations.push(representation);
+ }
+
+ return representations;
+ }
+
+ function getAdaptationsForPeriod(manifest, period) {
+ var p = manifest.Period_asArray[period.index];
+ var adaptations = [];
+ var adaptationSet, a;
+
+ for (var i = 0; i < p.AdaptationSet_asArray.length; i++) {
+ a = p.AdaptationSet_asArray[i];
+ adaptationSet = new _voAdaptationSet2['default']();
+
+ if (a.hasOwnProperty('id')) {
+ adaptationSet.id = a.id;
+ }
+
+ adaptationSet.index = i;
+ adaptationSet.period = period;
+
+ if (getIsMuxed(a)) {
+ adaptationSet.type = 'muxed';
+ } else if (getIsAudio(a)) {
+ adaptationSet.type = 'audio';
+ } else if (getIsVideo(a)) {
+ adaptationSet.type = 'video';
+ } else if (getIsFragmentedText(a)) {
+ adaptationSet.type = 'fragmentedText';
+ } else {
+ adaptationSet.type = 'text';
+ }
+
+ adaptations.push(adaptationSet);
+ }
+
+ return adaptations;
+ }
+
+ function getRegularPeriods(manifest, mpd) {
+ var isDynamic = getIsDynamic(manifest);
+ var periods = [];
+ var p1 = null;
+ var p = null;
+ var vo1 = null;
+ var vo = null;
+ var len, i;
+
+ for (i = 0, len = manifest.Period_asArray.length; i < len; i++) {
+ p = manifest.Period_asArray[i];
+
+ // If the attribute @start is present in the Period, then the
+ // Period is a regular Period and the PeriodStart is equal
+ // to the value of this attribute.
+ if (p.hasOwnProperty('start')) {
+ vo = new _voPeriod2['default']();
+ vo.start = p.start;
+ }
+ // If the @start attribute is absent, but the previous Period
+ // element contains a @duration attribute then then this new
+ // Period is also a regular Period. The start time of the new
+ // Period PeriodStart is the sum of the start time of the previous
+ // Period PeriodStart and the value of the attribute @duration
+ // of the previous Period.
+ else if (p1 !== null && p.hasOwnProperty('duration') && vo1 !== null) {
+ vo = new _voPeriod2['default']();
+ vo.start = vo1.start + vo1.duration;
+ vo.duration = p.duration;
+ }
+ // If (i) @start attribute is absent, and (ii) the Period element
+ // is the first in the MPD, and (iii) the MPD@type is 'static',
+ // then the PeriodStart time shall be set to zero.
+ else if (i === 0 && !isDynamic) {
+ vo = new _voPeriod2['default']();
+ vo.start = 0;
+ }
+
+ // The Period extends until the PeriodStart of the next Period.
+ // The difference between the PeriodStart time of a Period and
+ // the PeriodStart time of the following Period.
+ if (vo1 !== null && isNaN(vo1.duration)) {
+ vo1.duration = vo.start - vo1.start;
+ }
+
+ if (vo !== null) {
+ vo.id = getPeriodId(p);
+ }
+
+ if (vo !== null && p.hasOwnProperty('duration')) {
+ vo.duration = p.duration;
+ }
+
+ if (vo !== null) {
+ vo.index = i;
+ vo.mpd = mpd;
+ periods.push(vo);
+ p1 = p;
+ vo1 = vo;
+ }
+
+ p = null;
+ vo = null;
+ }
+
+ if (periods.length === 0) {
+ return periods;
+ }
+
+ // The last Period extends until the end of the Media Presentation.
+ // The difference between the PeriodStart time of the last Period
+ // and the mpd duration
+ if (vo1 !== null && isNaN(vo1.duration)) {
+ vo1.duration = getEndTimeForLastPeriod(manifest, vo1) - vo1.start;
+ }
+
+ return periods;
+ }
+
+ function getPeriodId(p) {
+ if (!p) {
+ throw new Error('Period cannot be null or undefined');
+ }
+
+ var id = _voPeriod2['default'].DEFAULT_ID;
+
+ if (p.hasOwnProperty('id') && p.id !== '__proto__') {
+ id = p.id;
+ }
+
+ return id;
+ }
+
+ function getMpd(manifest) {
+ var mpd = new _voMpd2['default']();
+
+ mpd.manifest = manifest;
+
+ if (manifest.hasOwnProperty('availabilityStartTime')) {
+ mpd.availabilityStartTime = new Date(manifest.availabilityStartTime.getTime());
+ } else {
+ mpd.availabilityStartTime = new Date(manifest.loadedTime.getTime());
+ }
+
+ if (manifest.hasOwnProperty('availabilityEndTime')) {
+ mpd.availabilityEndTime = new Date(manifest.availabilityEndTime.getTime());
+ }
+
+ if (manifest.hasOwnProperty('suggestedPresentationDelay')) {
+ mpd.suggestedPresentationDelay = manifest.suggestedPresentationDelay;
+ }
+
+ if (manifest.hasOwnProperty('timeShiftBufferDepth')) {
+ mpd.timeShiftBufferDepth = manifest.timeShiftBufferDepth;
+ }
+
+ if (manifest.hasOwnProperty('maxSegmentDuration')) {
+ mpd.maxSegmentDuration = manifest.maxSegmentDuration;
+ }
+
+ return mpd;
+ }
+
+ function getFetchTime(manifest, period) {
+ // FetchTime is defined as the time at which the server processes the request for the MPD from the client.
+ // TODO The client typically should not use the time at which it actually successfully received the MPD, but should
+ // take into account delay due to MPD delivery and processing. The fetch is considered successful fetching
+ // either if the client obtains an updated MPD or the client verifies that the MPD has not been updated since the previous fetching.
+
+ return timelineConverter.calcPresentationTimeFromWallTime(manifest.loadedTime, period);
+ }
+
+ function getCheckTime(manifest, period) {
+ var checkTime = NaN;
+ var fetchTime;
+
+ // If the MPD@minimumUpdatePeriod attribute in the client is provided, then the check time is defined as the
+ // sum of the fetch time of this operating MPD and the value of this attribute,
+ // i.e. CheckTime = FetchTime + MPD@minimumUpdatePeriod.
+ if (manifest.hasOwnProperty('minimumUpdatePeriod')) {
+ fetchTime = getFetchTime(manifest, period);
+ checkTime = fetchTime + manifest.minimumUpdatePeriod;
+ }
+ // TODO If the MPD@minimumUpdatePeriod attribute in the client is not provided, external means are used to
+ // determine CheckTime, such as a priori knowledge, or HTTP cache headers, etc.
+
+ return checkTime;
+ }
+
+ function getEndTimeForLastPeriod(manifest, period) {
+ var periodEnd;
+ var checkTime = getCheckTime(manifest, period);
+
+ // if the MPD@mediaPresentationDuration attribute is present, then PeriodEndTime is defined as the end time of the Media Presentation.
+ // if the MPD@mediaPresentationDuration attribute is not present, then PeriodEndTime is defined as FetchTime + MPD@minimumUpdatePeriod
+
+ if (manifest.mediaPresentationDuration) {
+ periodEnd = manifest.mediaPresentationDuration;
+ } else if (!isNaN(checkTime)) {
+ // in this case the Period End Time should match CheckTime
+ periodEnd = checkTime;
+ } else {
+ throw new Error('Must have @mediaPresentationDuration or @minimumUpdatePeriod on MPD or an explicit @duration on the last period.');
+ }
+
+ return periodEnd;
+ }
+
+ function getEventsForPeriod(manifest, period) {
+
+ var periodArray = manifest.Period_asArray;
+ var eventStreams = periodArray[period.index].EventStream_asArray;
+ var events = [];
+
+ if (eventStreams) {
+ for (var i = 0; i < eventStreams.length; i++) {
+ var eventStream = new _voEventStream2['default']();
+ eventStream.period = period;
+ eventStream.timescale = 1;
+
+ if (eventStreams[i].hasOwnProperty('schemeIdUri')) {
+ eventStream.schemeIdUri = eventStreams[i].schemeIdUri;
+ } else {
+ throw new Error('Invalid EventStream. SchemeIdUri has to be set');
+ }
+ if (eventStreams[i].hasOwnProperty('timescale')) {
+ eventStream.timescale = eventStreams[i].timescale;
+ }
+ if (eventStreams[i].hasOwnProperty('value')) {
+ eventStream.value = eventStreams[i].value;
+ }
+ for (var j = 0; j < eventStreams[i].Event_asArray.length; j++) {
+ var event = new _voEvent2['default']();
+ event.presentationTime = 0;
+ event.eventStream = eventStream;
+
+ if (eventStreams[i].Event_asArray[j].hasOwnProperty('presentationTime')) {
+ event.presentationTime = eventStreams[i].Event_asArray[j].presentationTime;
+ }
+ if (eventStreams[i].Event_asArray[j].hasOwnProperty('duration')) {
+ event.duration = eventStreams[i].Event_asArray[j].duration;
+ }
+ if (eventStreams[i].Event_asArray[j].hasOwnProperty('id')) {
+ event.id = eventStreams[i].Event_asArray[j].id;
+ }
+ events.push(event);
+ }
+ }
+ }
+
+ return events;
+ }
+
+ function getEventStreams(inbandStreams, representation) {
+ var eventStreams = [];
+
+ if (!inbandStreams) return eventStreams;
+
+ for (var i = 0; i < inbandStreams.length; i++) {
+ var eventStream = new _voEventStream2['default']();
+ eventStream.timescale = 1;
+ eventStream.representation = representation;
+
+ if (inbandStreams[i].hasOwnProperty('schemeIdUri')) {
+ eventStream.schemeIdUri = inbandStreams[i].schemeIdUri;
+ } else {
+ throw new Error('Invalid EventStream. SchemeIdUri has to be set');
+ }
+ if (inbandStreams[i].hasOwnProperty('timescale')) {
+ eventStream.timescale = inbandStreams[i].timescale;
+ }
+ if (inbandStreams[i].hasOwnProperty('value')) {
+ eventStream.value = inbandStreams[i].value;
+ }
+ eventStreams.push(eventStream);
+ }
+
+ return eventStreams;
+ }
+
+ function getEventStreamForAdaptationSet(manifest, adaptation) {
+ var inbandStreams = manifest.Period_asArray[adaptation.period.index].AdaptationSet_asArray[adaptation.index].InbandEventStream_asArray;
+
+ return getEventStreams(inbandStreams, null);
+ }
+
+ function getEventStreamForRepresentation(manifest, representation) {
+ var inbandStreams = manifest.Period_asArray[representation.adaptation.period.index].AdaptationSet_asArray[representation.adaptation.index].Representation_asArray[representation.index].InbandEventStream_asArray;
+
+ return getEventStreams(inbandStreams, representation);
+ }
+
+ function getUTCTimingSources(manifest) {
+
+ var isDynamic = getIsDynamic(manifest);
+ var hasAST = manifest.hasOwnProperty('availabilityStartTime');
+ var utcTimingsArray = manifest.UTCTiming_asArray;
+ var utcTimingEntries = [];
+
+ // do not bother synchronizing the clock unless MPD is live,
+ // or it is static and has availabilityStartTime attribute
+ if (isDynamic || hasAST) {
+ if (utcTimingsArray) {
+ // the order is important here - 23009-1 states that the order
+ // in the manifest "indicates relative preference, first having
+ // the highest, and the last the lowest priority".
+ utcTimingsArray.forEach(function (utcTiming) {
+ var entry = new _voUTCTiming2['default']();
+
+ if (utcTiming.hasOwnProperty('schemeIdUri')) {
+ entry.schemeIdUri = utcTiming.schemeIdUri;
+ } else {
+ // entries of type DescriptorType with no schemeIdUri
+ // are meaningless. let's just ignore this entry and
+ // move on.
+ return;
+ }
+
+ // this is (incorrectly) interpreted as a number - schema
+ // defines it as a string
+ if (utcTiming.hasOwnProperty('value')) {
+ entry.value = utcTiming.value.toString();
+ } else {
+ // without a value, there's not a lot we can do with
+ // this entry. let's just ignore this one and move on
+ return;
+ }
+
+ // we're not interested in the optional id or any other
+ // attributes which might be attached to the entry
+
+ utcTimingEntries.push(entry);
+ });
+ }
+ }
+
+ return utcTimingEntries;
+ }
+
+ function getBaseURLsFromElement(node) {
+ var baseUrls = [];
+ // if node.BaseURL_asArray and node.baseUri are undefined entries
+ // will be [undefined] which entries.some will just skip
+ var entries = node.BaseURL_asArray || [node.baseUri];
+ var earlyReturn = false;
+
+ entries.some(function (entry) {
+ if (entry) {
+ var baseUrl = new _voBaseURL2['default']();
+ var text = entry.__text || entry;
+
+ if (urlUtils.isRelative(text)) {
+ // it doesn't really make sense to have relative and
+ // absolute URLs at the same level, or multiple
+ // relative URLs at the same level, so assume we are
+ // done from this level of the MPD
+ earlyReturn = true;
+
+ // deal with the specific case where the MPD@BaseURL
+ // is specified and is relative. when no MPD@BaseURL
+ // entries exist, that case is handled by the
+ // [node.baseUri] in the entries definition.
+ if (node.baseUri) {
+ text = node.baseUri + text;
+ }
+ }
+
+ baseUrl.url = text;
+
+ // serviceLocation is optional, but we need it in order
+ // to blacklist correctly. if it's not available, use
+ // anything unique since there's no relationship to any
+ // other BaseURL and, in theory, the url should be
+ // unique so use this instead.
+ if (entry.hasOwnProperty('serviceLocation') && entry.serviceLocation.length) {
+ baseUrl.serviceLocation = entry.serviceLocation;
+ } else {
+ baseUrl.serviceLocation = text;
+ }
+
+ if (entry.hasOwnProperty('dvb:priority')) {
+ baseUrl.dvb_priority = entry['dvb:priority'];
+ }
+
+ if (entry.hasOwnProperty('dvb:weight')) {
+ baseUrl.dvb_weight = entry['dvb:weight'];
+ }
+
+ /* NOTE: byteRange, availabilityTimeOffset,
+ * availabilityTimeComplete currently unused
+ */
+
+ baseUrls.push(baseUrl);
+
+ return earlyReturn;
+ }
+ });
+
+ return baseUrls;
+ }
+
+ function getLocation(manifest) {
+ if (manifest.hasOwnProperty('Location')) {
+ // for now, do not support multiple Locations -
+ // just set Location to the first Location.
+ manifest.Location = manifest.Location_asArray[0];
+ }
+
+ // may well be undefined
+ return manifest.Location;
+ }
+
+ instance = {
+ getIsTypeOf: getIsTypeOf,
+ getIsAudio: getIsAudio,
+ getIsVideo: getIsVideo,
+ getIsText: getIsText,
+ getIsMuxed: getIsMuxed,
+ getIsTextTrack: getIsTextTrack,
+ getIsFragmentedText: getIsFragmentedText,
+ getIsMain: getIsMain,
+ getLanguageForAdaptation: getLanguageForAdaptation,
+ getViewpointForAdaptation: getViewpointForAdaptation,
+ getRolesForAdaptation: getRolesForAdaptation,
+ getAccessibilityForAdaptation: getAccessibilityForAdaptation,
+ getAudioChannelConfigurationForAdaptation: getAudioChannelConfigurationForAdaptation,
+ processAdaptation: processAdaptation,
+ getAdaptationForIndex: getAdaptationForIndex,
+ getIndexForAdaptation: getIndexForAdaptation,
+ getAdaptationForId: getAdaptationForId,
+ getAdaptationsForType: getAdaptationsForType,
+ getAdaptationForType: getAdaptationForType,
+ getCodec: getCodec,
+ getMimeType: getMimeType,
+ getKID: getKID,
+ getContentProtectionData: getContentProtectionData,
+ getIsDynamic: getIsDynamic,
+ getIsDVR: getIsDVR,
+ getIsOnDemand: getIsOnDemand,
+ getIsDVB: getIsDVB,
+ getDuration: getDuration,
+ getBandwidth: getBandwidth,
+ getRefreshDelay: getRefreshDelay,
+ getRepresentationCount: getRepresentationCount,
+ getBitrateListForAdaptation: getBitrateListForAdaptation,
+ getRepresentationFor: getRepresentationFor,
+ getRepresentationsForAdaptation: getRepresentationsForAdaptation,
+ getAdaptationsForPeriod: getAdaptationsForPeriod,
+ getRegularPeriods: getRegularPeriods,
+ getPeriodId: getPeriodId,
+ getMpd: getMpd,
+ getFetchTime: getFetchTime,
+ getCheckTime: getCheckTime,
+ getEndTimeForLastPeriod: getEndTimeForLastPeriod,
+ getEventsForPeriod: getEventsForPeriod,
+ getEventStreams: getEventStreams,
+ getEventStreamForAdaptationSet: getEventStreamForAdaptationSet,
+ getEventStreamForRepresentation: getEventStreamForRepresentation,
+ getUTCTimingSources: getUTCTimingSources,
+ getBaseURLsFromElement: getBaseURLsFromElement,
+ getRepresentationSortFunction: getRepresentationSortFunction,
+ getLocation: getLocation
+ };
+
+ return instance;
+}
+
+DashManifestModel.__dashjs_factory_name = 'DashManifestModel';
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(DashManifestModel);
+module.exports = exports['default'];
+
+},{"10":10,"15":15,"158":158,"37":37,"39":39,"40":40,"41":41,"42":42,"43":43,"44":44,"45":45,"47":47,"66":66}],23:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _streamingUtilsErrorHandler = _dereq_(151);
+
+var _streamingUtilsErrorHandler2 = _interopRequireDefault(_streamingUtilsErrorHandler);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _coreDebug = _dereq_(8);
+
+var _coreDebug2 = _interopRequireDefault(_coreDebug);
+
+var _externalsObjectiron = _dereq_(3);
+
+var _externalsObjectiron2 = _interopRequireDefault(_externalsObjectiron);
+
+var _externalsXml2json = _dereq_(4);
+
+var _externalsXml2json2 = _interopRequireDefault(_externalsXml2json);
+
+var _matchersDurationMatcher = _dereq_(30);
+
+var _matchersDurationMatcher2 = _interopRequireDefault(_matchersDurationMatcher);
+
+var _matchersDateTimeMatcher = _dereq_(29);
+
+var _matchersDateTimeMatcher2 = _interopRequireDefault(_matchersDateTimeMatcher);
+
+var _matchersNumericMatcher = _dereq_(31);
+
+var _matchersNumericMatcher2 = _interopRequireDefault(_matchersNumericMatcher);
+
+var _mapsRepresentationBaseValuesMap = _dereq_(26);
+
+var _mapsRepresentationBaseValuesMap2 = _interopRequireDefault(_mapsRepresentationBaseValuesMap);
+
+var _mapsSegmentValuesMap = _dereq_(27);
+
+var _mapsSegmentValuesMap2 = _interopRequireDefault(_mapsSegmentValuesMap);
+
+function DashParser() /*config*/{
+
+ var context = this.context;
+ var log = (0, _coreDebug2['default'])(context).getInstance().log;
+ var errorHandler = (0, _streamingUtilsErrorHandler2['default'])(context).getInstance();
+
+ var instance = undefined,
+ matchers = undefined,
+ converter = undefined,
+ objectIron = undefined;
+
+ function setup() {
+ matchers = [new _matchersDurationMatcher2['default'](), new _matchersDateTimeMatcher2['default'](), new _matchersNumericMatcher2['default']()];
+
+ converter = new _externalsXml2json2['default'](matchers, '', true);
+
+ objectIron = new _externalsObjectiron2['default']([new _mapsRepresentationBaseValuesMap2['default'](), new _mapsSegmentValuesMap2['default']()]);
+ }
+
+ function parse(data, xlinkController) {
+ var manifest;
+
+ try {
+ var startTime = window.performance.now();
+
+ manifest = converter.xml_str2json(data);
+
+ if (!manifest) {
+ throw new Error('parser error');
+ }
+
+ var jsonTime = window.performance.now();
+
+ objectIron.run(manifest);
+
+ var ironedTime = window.performance.now();
+
+ xlinkController.setMatchers(matchers);
+ xlinkController.setIron(objectIron);
+
+ log('Parsing complete: ( xml2json: ' + (jsonTime - startTime).toPrecision(3) + 'ms, objectiron: ' + (ironedTime - jsonTime).toPrecision(3) + 'ms, total: ' + ((ironedTime - startTime) / 1000).toPrecision(3) + 's)');
+ } catch (err) {
+ errorHandler.manifestError('parsing the manifest failed', 'parse', data, err);
+ return null;
+ }
+
+ return manifest;
+ }
+
+ instance = {
+ parse: parse
+ };
+
+ setup();
+
+ return instance;
+}
+
+DashParser.__dashjs_factory_name = 'DashParser';
+exports['default'] = _coreFactoryMaker2['default'].getClassFactory(DashParser);
+module.exports = exports['default'];
+
+},{"10":10,"151":151,"26":26,"27":27,"29":29,"3":3,"30":30,"31":31,"4":4,"8":8}],24:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @classdesc a property belonging to a MapNode
+ */
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var CommonProperty = (function () {
+ function CommonProperty(name, merge) {
+ _classCallCheck(this, CommonProperty);
+
+ var getDefaultMergeForName = function getDefaultMergeForName(n) {
+ return n && n.length && n.charAt(0) === n.charAt(0).toUpperCase();
+ };
+
+ this._name = name;
+ this._merge = merge !== undefined ? merge : getDefaultMergeForName(name);
+ }
+
+ _createClass(CommonProperty, [{
+ key: "name",
+ get: function get() {
+ return this._name;
+ }
+ }, {
+ key: "merge",
+ get: function get() {
+ return this._merge;
+ }
+ }]);
+
+ return CommonProperty;
+})();
+
+exports["default"] = CommonProperty;
+module.exports = exports["default"];
+
+},{}],25:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @classdesc a node at some level in a ValueMap
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+
+var _CommonProperty = _dereq_(24);
+
+var _CommonProperty2 = _interopRequireDefault(_CommonProperty);
+
+var MapNode = (function () {
+ function MapNode(name, properties, children, isRoot, isArray) {
+ var _this = this;
+
+ _classCallCheck(this, MapNode);
+
+ this._name = name || '';
+ this._properties = [];
+ this._children = children || [];
+ this._isRoot = isRoot || false;
+ this._isArray = isArray || true;
+
+ if (Array.isArray(properties)) {
+ properties.forEach(function (p) {
+ _this._properties.push(new _CommonProperty2['default'](p));
+ });
+ }
+ }
+
+ _createClass(MapNode, [{
+ key: 'name',
+ get: function get() {
+ return this._name;
+ }
+ }, {
+ key: 'isRoot',
+ get: function get() {
+ return this._isRoot;
+ }
+ }, {
+ key: 'isArray',
+ get: function get() {
+ return this._isArray;
+ }
+ }, {
+ key: 'children',
+ get: function get() {
+ return this._children;
+ }
+ }, {
+ key: 'properties',
+ get: function get() {
+ return this._properties;
+ }
+ }]);
+
+ return MapNode;
+})();
+
+exports['default'] = MapNode;
+module.exports = exports['default'];
+
+},{"24":24}],26:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @classdesc a RepresentationBaseValuesMap type for input to objectiron
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+var _MapNode2 = _dereq_(25);
+
+var _MapNode3 = _interopRequireDefault(_MapNode2);
+
+var RepresentationBaseValuesMap = (function (_MapNode) {
+ _inherits(RepresentationBaseValuesMap, _MapNode);
+
+ function RepresentationBaseValuesMap() {
+ _classCallCheck(this, RepresentationBaseValuesMap);
+
+ var commonProperties = ['profiles', 'width', 'height', 'sar', 'frameRate', 'audioSamplingRate', 'mimeType', 'segmentProfiles', 'codecs', 'maximumSAPPeriod', 'startWithSAP', 'maxPlayoutRate', 'codingDependency', 'scanType', 'FramePacking', 'AudioChannelConfiguration', 'ContentProtection', 'EssentialProperty', 'SupplementalProperty', 'InbandEventStream'];
+
+ return _get(Object.getPrototypeOf(RepresentationBaseValuesMap.prototype), 'constructor', this).call(this, 'AdaptationSet', commonProperties, [new _MapNode3['default']('Representation', commonProperties, [new _MapNode3['default']('SubRepresentation', commonProperties)])]);
+ }
+
+ return RepresentationBaseValuesMap;
+})(_MapNode3['default']);
+
+exports['default'] = RepresentationBaseValuesMap;
+module.exports = exports['default'];
+
+},{"25":25}],27:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @classdesc a SegmentValuesMap type for input to objectiron
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+var _MapNode2 = _dereq_(25);
+
+var _MapNode3 = _interopRequireDefault(_MapNode2);
+
+var SegmentValuesMap = (function (_MapNode) {
+ _inherits(SegmentValuesMap, _MapNode);
+
+ function SegmentValuesMap() {
+ _classCallCheck(this, SegmentValuesMap);
+
+ var commonProperties = ['SegmentBase', 'SegmentTemplate', 'SegmentList'];
+
+ return _get(Object.getPrototypeOf(SegmentValuesMap.prototype), 'constructor', this).call(this, 'Period', commonProperties, [new _MapNode3['default']('AdaptationSet', commonProperties, [new _MapNode3['default']('Representation', commonProperties)])]);
+ }
+
+ return SegmentValuesMap;
+})(_MapNode3['default']);
+
+exports['default'] = SegmentValuesMap;
+module.exports = exports['default'];
+
+},{"25":25}],28:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @classdesc a base type for matching and converting types in manifest to
+ * something more useful
+ */
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var BaseMatcher = (function () {
+ function BaseMatcher(test, converter) {
+ _classCallCheck(this, BaseMatcher);
+
+ this._test = test;
+ this._converter = converter;
+ }
+
+ _createClass(BaseMatcher, [{
+ key: "test",
+ get: function get() {
+ return this._test;
+ }
+ }, {
+ key: "converter",
+ get: function get() {
+ return this._converter;
+ }
+ }]);
+
+ return BaseMatcher;
+})();
+
+exports["default"] = BaseMatcher;
+module.exports = exports["default"];
+
+},{}],29:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @classdesc matches and converts xs:datetime to Date
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+var _BaseMatcher2 = _dereq_(28);
+
+var _BaseMatcher3 = _interopRequireDefault(_BaseMatcher2);
+
+var SECONDS_IN_MIN = 60;
+var MINUTES_IN_HOUR = 60;
+var MILLISECONDS_IN_SECONDS = 1000;
+
+var datetimeRegex = /^([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2})(?::([0-9]*)(\.[0-9]*)?)?(?:([+-])([0-9]{2})(?::?)([0-9]{2}))?/;
+
+var DateTimeMatcher = (function (_BaseMatcher) {
+ _inherits(DateTimeMatcher, _BaseMatcher);
+
+ function DateTimeMatcher() {
+ _classCallCheck(this, DateTimeMatcher);
+
+ _get(Object.getPrototypeOf(DateTimeMatcher.prototype), 'constructor', this).call(this, function (attr) {
+ return datetimeRegex.test(attr.value);
+ }, function (str) {
+ var match = datetimeRegex.exec(str);
+ var utcDate = undefined;
+
+ // If the string does not contain a timezone offset different browsers can interpret it either
+ // as UTC or as a local time so we have to parse the string manually to normalize the given date value for
+ // all browsers
+ utcDate = Date.UTC(parseInt(match[1], 10), parseInt(match[2], 10) - 1, // months start from zero
+ parseInt(match[3], 10), parseInt(match[4], 10), parseInt(match[5], 10), match[6] && parseInt(match[6], 10) || 0, match[7] && parseFloat(match[7]) * MILLISECONDS_IN_SECONDS || 0);
+
+ // If the date has timezone offset take it into account as well
+ if (match[9] && match[10]) {
+ var timezoneOffset = parseInt(match[9], 10) * MINUTES_IN_HOUR + parseInt(match[10], 10);
+ utcDate += (match[8] === '+' ? -1 : +1) * timezoneOffset * SECONDS_IN_MIN * MILLISECONDS_IN_SECONDS;
+ }
+
+ return new Date(utcDate);
+ });
+ }
+
+ return DateTimeMatcher;
+})(_BaseMatcher3['default']);
+
+exports['default'] = DateTimeMatcher;
+module.exports = exports['default'];
+
+},{"28":28}],30:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @classdesc matches and converts xs:duration to seconds
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+var _BaseMatcher2 = _dereq_(28);
+
+var _BaseMatcher3 = _interopRequireDefault(_BaseMatcher2);
+
+var durationRegex = /^([-])?P(([\d.]*)Y)?(([\d.]*)M)?(([\d.]*)D)?T?(([\d.]*)H)?(([\d.]*)M)?(([\d.]*)S)?/;
+
+var SECONDS_IN_YEAR = 365 * 24 * 60 * 60;
+var SECONDS_IN_MONTH = 30 * 24 * 60 * 60;
+var SECONDS_IN_DAY = 24 * 60 * 60;
+var SECONDS_IN_HOUR = 60 * 60;
+var SECONDS_IN_MIN = 60;
+
+var DurationMatcher = (function (_BaseMatcher) {
+ _inherits(DurationMatcher, _BaseMatcher);
+
+ function DurationMatcher() {
+ _classCallCheck(this, DurationMatcher);
+
+ _get(Object.getPrototypeOf(DurationMatcher.prototype), 'constructor', this).call(this, function (attr) {
+ var attributeList = ['minBufferTime', 'mediaPresentationDuration', 'minimumUpdatePeriod', 'timeShiftBufferDepth', 'maxSegmentDuration', 'maxSubsegmentDuration', 'suggestedPresentationDelay', 'start', 'starttime', 'duration'];
+ var len = attributeList.length;
+
+ for (var i = 0; i < len; i++) {
+ if (attr.nodeName === attributeList[i]) {
+ return durationRegex.test(attr.value);
+ }
+ }
+
+ return false;
+ }, function (str) {
+ //str = "P10Y10M10DT10H10M10.1S";
+ var match = durationRegex.exec(str);
+ var result = parseFloat(match[2] || 0) * SECONDS_IN_YEAR + parseFloat(match[4] || 0) * SECONDS_IN_MONTH + parseFloat(match[6] || 0) * SECONDS_IN_DAY + parseFloat(match[8] || 0) * SECONDS_IN_HOUR + parseFloat(match[10] || 0) * SECONDS_IN_MIN + parseFloat(match[12] || 0);
+
+ if (match[1] !== undefined) {
+ result = -result;
+ }
+
+ return result;
+ });
+ }
+
+ return DurationMatcher;
+})(_BaseMatcher3['default']);
+
+exports['default'] = DurationMatcher;
+module.exports = exports['default'];
+
+},{"28":28}],31:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @classdesc Matches and converts xs:numeric to float
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+var _BaseMatcher2 = _dereq_(28);
+
+var _BaseMatcher3 = _interopRequireDefault(_BaseMatcher2);
+
+var numericRegex = /^[-+]?[0-9]+[.]?[0-9]*([eE][-+]?[0-9]+)?$/;
+
+var NumericMatcher = (function (_BaseMatcher) {
+ _inherits(NumericMatcher, _BaseMatcher);
+
+ function NumericMatcher() {
+ _classCallCheck(this, NumericMatcher);
+
+ _get(Object.getPrototypeOf(NumericMatcher.prototype), 'constructor', this).call(this, function (attr) {
+ return numericRegex.test(attr.value);
+ }, function (str) {
+ return parseFloat(str);
+ });
+ }
+
+ return NumericMatcher;
+})(_BaseMatcher3['default']);
+
+exports['default'] = NumericMatcher;
+module.exports = exports['default'];
+
+},{"28":28}],32:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+function FragmentedTextBoxParser() {
+
+ var instance = undefined,
+ boxParser = undefined;
+
+ function setConfig(config) {
+ if (!config) return;
+
+ if (config.boxParser) {
+ boxParser = config.boxParser;
+ }
+ }
+
+ function getSamplesInfo(ab) {
+ var isoFile = boxParser.parse(ab);
+ var tfhdBox = isoFile.getBox('tfhd');
+ var tfdtBox = isoFile.getBox('tfdt');
+ var trunBox = isoFile.getBox('trun');
+ var moofBox = isoFile.getBox('moof');
+ var mfhdBox = isoFile.getBox('mfhd');
+
+ var sampleDuration, sampleCompositionTimeOffset, sampleCount, sampleSize, sampleDts, sampleList, sample, i, dataOffset, sequenceNumber, totalDuration;
+
+ sequenceNumber = mfhdBox.sequence_number;
+ sampleCount = trunBox.sample_count;
+ sampleDts = tfdtBox.baseMediaDecodeTime;
+ dataOffset = (tfhdBox.base_data_offset || 0) + (trunBox.data_offset || 0);
+
+ sampleList = [];
+ for (i = 0; i < sampleCount; i++) {
+ sample = trunBox.samples[i];
+ sampleDuration = sample.sample_duration !== undefined ? sample.sample_duration : tfhdBox.default_sample_duration;
+ sampleSize = sample.sample_size !== undefined ? sample.sample_size : tfhdBox.default_sample_size;
+ sampleCompositionTimeOffset = sample.sample_composition_time_offset !== undefined ? sample.sample_composition_time_offset : 0;
+
+ sampleList.push({ 'dts': sampleDts,
+ 'cts': sampleDts + sampleCompositionTimeOffset,
+ 'duration': sampleDuration,
+ 'offset': moofBox.offset + dataOffset,
+ 'size': sampleSize });
+ dataOffset += sampleSize;
+ sampleDts += sampleDuration;
+ }
+ totalDuration = sampleDts - tfdtBox.baseMediaDecodeTime;
+ return { sampleList: sampleList, sequenceNumber: sequenceNumber, totalDuration: totalDuration };
+ }
+
+ function getMediaTimescaleFromMoov(ab) {
+ var isoFile = boxParser.parse(ab);
+ var mdhdBox = isoFile.getBox('mdhd');
+
+ return mdhdBox ? mdhdBox.timescale : NaN;
+ }
+
+ instance = {
+ getSamplesInfo: getSamplesInfo,
+ getMediaTimescaleFromMoov: getMediaTimescaleFromMoov,
+ setConfig: setConfig
+ };
+
+ return instance;
+}
+
+FragmentedTextBoxParser.__dashjs_factory_name = 'FragmentedTextBoxParser';
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(FragmentedTextBoxParser);
+module.exports = exports['default'];
+
+},{"10":10}],33:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _SegmentsUtils = _dereq_(35);
+
+function ListSegmentsGetter(config, isDynamic) {
+
+ var timelineConverter = config.timelineConverter;
+
+ var instance = undefined;
+
+ function getSegmentsFromList(representation, requestedTime, index, availabilityUpperLimit) {
+ var list = representation.adaptation.period.mpd.manifest.Period_asArray[representation.adaptation.period.index].AdaptationSet_asArray[representation.adaptation.index].Representation_asArray[representation.index].SegmentList;
+ var len = list.SegmentURL_asArray.length;
+
+ var segments = [];
+
+ var periodSegIdx, seg, s, range, startIdx, endIdx, start;
+
+ start = representation.startNumber;
+
+ range = (0, _SegmentsUtils.decideSegmentListRangeForTemplate)(timelineConverter, isDynamic, representation, requestedTime, index, availabilityUpperLimit);
+ startIdx = Math.max(range.start, 0);
+ endIdx = Math.min(range.end, list.SegmentURL_asArray.length - 1);
+
+ for (periodSegIdx = startIdx; periodSegIdx <= endIdx; periodSegIdx++) {
+ s = list.SegmentURL_asArray[periodSegIdx];
+
+ seg = (0, _SegmentsUtils.getIndexBasedSegment)(timelineConverter, isDynamic, representation, periodSegIdx);
+ seg.replacementTime = (start + periodSegIdx - 1) * representation.segmentDuration;
+ seg.media = s.media ? s.media : '';
+ seg.mediaRange = s.mediaRange;
+ seg.index = s.index;
+ seg.indexRange = s.indexRange;
+
+ segments.push(seg);
+ seg = null;
+ }
+
+ representation.availableSegmentsNumber = len;
+
+ return segments;
+ }
+
+ instance = {
+ getSegments: getSegmentsFromList
+ };
+
+ return instance;
+}
+
+ListSegmentsGetter.__dashjs_factory_name = 'ListSegmentsGetter';
+var factory = _coreFactoryMaker2['default'].getClassFactory(ListSegmentsGetter);
+exports['default'] = factory;
+module.exports = exports['default'];
+
+},{"10":10,"35":35}],34:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _TimelineSegmentsGetter = _dereq_(38);
+
+var _TimelineSegmentsGetter2 = _interopRequireDefault(_TimelineSegmentsGetter);
+
+var _TemplateSegmentsGetter = _dereq_(36);
+
+var _TemplateSegmentsGetter2 = _interopRequireDefault(_TemplateSegmentsGetter);
+
+var _ListSegmentsGetter = _dereq_(33);
+
+var _ListSegmentsGetter2 = _interopRequireDefault(_ListSegmentsGetter);
+
+function SegmentsGetter(config, isDynamic) {
+
+ var context = this.context;
+
+ var instance = undefined,
+ timelineSegmentsGetter = undefined,
+ templateSegmentsGetter = undefined,
+ listSegmentsGetter = undefined;
+
+ function setup() {
+ timelineSegmentsGetter = (0, _TimelineSegmentsGetter2['default'])(context).create(config, isDynamic);
+ templateSegmentsGetter = (0, _TemplateSegmentsGetter2['default'])(context).create(config, isDynamic);
+ listSegmentsGetter = (0, _ListSegmentsGetter2['default'])(context).create(config, isDynamic);
+ }
+
+ function getSegments(representation, requestedTime, index, onSegmentListUpdatedCallback, availabilityUpperLimit) {
+ var segments;
+ var type = representation.segmentInfoType;
+
+ // Already figure out the segments.
+ if (type === 'SegmentBase' || type === 'BaseURL' || !isSegmentListUpdateRequired(representation, index)) {
+ segments = representation.segments;
+ } else {
+ if (type === 'SegmentTimeline') {
+ segments = timelineSegmentsGetter.getSegments(representation, requestedTime, index, availabilityUpperLimit);
+ } else if (type === 'SegmentTemplate') {
+ segments = templateSegmentsGetter.getSegments(representation, requestedTime, index, availabilityUpperLimit);
+ } else if (type === 'SegmentList') {
+ segments = listSegmentsGetter.getSegments(representation, requestedTime, index, availabilityUpperLimit);
+ }
+
+ if (onSegmentListUpdatedCallback) {
+ onSegmentListUpdatedCallback(representation, segments);
+ }
+ }
+
+ return segments;
+ }
+
+ function isSegmentListUpdateRequired(representation, index) {
+ var segments = representation.segments;
+ var updateRequired = false;
+
+ var upperIdx, lowerIdx;
+
+ if (!segments || segments.length === 0) {
+ updateRequired = true;
+ } else {
+ lowerIdx = segments[0].availabilityIdx;
+ upperIdx = segments[segments.length - 1].availabilityIdx;
+ updateRequired = index < lowerIdx || index > upperIdx;
+ }
+
+ return updateRequired;
+ }
+
+ instance = {
+ getSegments: getSegments
+ };
+
+ setup();
+
+ return instance;
+}
+
+SegmentsGetter.__dashjs_factory_name = 'SegmentsGetter';
+var factory = _coreFactoryMaker2['default'].getClassFactory(SegmentsGetter);
+exports['default'] = factory;
+module.exports = exports['default'];
+
+},{"10":10,"33":33,"36":36,"38":38}],35:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+exports.replaceTokenForTemplate = replaceTokenForTemplate;
+exports.getIndexBasedSegment = getIndexBasedSegment;
+exports.getTimeBasedSegment = getTimeBasedSegment;
+exports.getSegmentByIndex = getSegmentByIndex;
+exports.decideSegmentListRangeForTimeline = decideSegmentListRangeForTimeline;
+exports.decideSegmentListRangeForTemplate = decideSegmentListRangeForTemplate;
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _voSegment = _dereq_(46);
+
+var _voSegment2 = _interopRequireDefault(_voSegment);
+
+function zeroPadToLength(numStr, minStrLength) {
+ while (numStr.length < minStrLength) {
+ numStr = '0' + numStr;
+ }
+ return numStr;
+}
+
+function getNumberForSegment(segment, segmentIndex) {
+ return segment.representation.startNumber + segmentIndex;
+}
+
+function replaceTokenForTemplate(url, token, value) {
+ var formatTag = '%0';
+
+ var startPos, endPos, formatTagPos, specifier, width, paddedValue;
+
+ var tokenLen = token.length;
+ var formatTagLen = formatTag.length;
+
+ // keep looping round until all instances of <token> have been
+ // replaced. once that has happened, startPos below will be -1
+ // and the completed url will be returned.
+ while (true) {
+
+ // check if there is a valid $<token>...$ identifier
+ // if not, return the url as is.
+ startPos = url.indexOf('$' + token);
+ if (startPos < 0) {
+ return url;
+ }
+
+ // the next '$' must be the end of the identifier
+ // if there isn't one, return the url as is.
+ endPos = url.indexOf('$', startPos + tokenLen);
+ if (endPos < 0) {
+ return url;
+ }
+
+ // now see if there is an additional format tag suffixed to
+ // the identifier within the enclosing '$' characters
+ formatTagPos = url.indexOf(formatTag, startPos + tokenLen);
+ if (formatTagPos > startPos && formatTagPos < endPos) {
+
+ specifier = url.charAt(endPos - 1);
+ width = parseInt(url.substring(formatTagPos + formatTagLen, endPos - 1), 10);
+
+ // support the minimum specifiers required by IEEE 1003.1
+ // (d, i , o, u, x, and X) for completeness
+ switch (specifier) {
+ // treat all int types as uint,
+ // hence deliberate fallthrough
+ case 'd':
+ case 'i':
+ case 'u':
+ paddedValue = zeroPadToLength(value.toString(), width);
+ break;
+ case 'x':
+ paddedValue = zeroPadToLength(value.toString(16), width);
+ break;
+ case 'X':
+ paddedValue = zeroPadToLength(value.toString(16), width).toUpperCase();
+ break;
+ case 'o':
+ paddedValue = zeroPadToLength(value.toString(8), width);
+ break;
+ default:
+ //TODO: commented out logging to supress jshint warning -- `log` is undefined here
+ //log('Unsupported/invalid IEEE 1003.1 format identifier string in URL');
+ return url;
+ }
+ } else {
+ paddedValue = value;
+ }
+
+ url = url.substring(0, startPos) + paddedValue + url.substring(endPos + 1);
+ }
+}
+
+function getIndexBasedSegment(timelineConverter, isDynamic, representation, index) {
+ var seg, duration, presentationStartTime, presentationEndTime;
+
+ duration = representation.segmentDuration;
+
+ /*
+ * From spec - If neither @duration attribute nor SegmentTimeline element is present, then the Representation
+ * shall contain exactly one Media Segment. The MPD start time is 0 and the MPD duration is obtained
+ * in the same way as for the last Media Segment in the Representation.
+ */
+ if (isNaN(duration)) {
+ duration = representation.adaptation.period.duration;
+ }
+
+ presentationStartTime = representation.adaptation.period.start + index * duration;
+ presentationEndTime = presentationStartTime + duration;
+
+ seg = new _voSegment2['default']();
+
+ seg.representation = representation;
+ seg.duration = duration;
+ seg.presentationStartTime = presentationStartTime;
+
+ seg.mediaStartTime = timelineConverter.calcMediaTimeFromPresentationTime(seg.presentationStartTime, representation);
+
+ seg.availabilityStartTime = timelineConverter.calcAvailabilityStartTimeFromPresentationTime(seg.presentationStartTime, representation.adaptation.period.mpd, isDynamic);
+ seg.availabilityEndTime = timelineConverter.calcAvailabilityEndTimeFromPresentationTime(presentationEndTime, representation.adaptation.period.mpd, isDynamic);
+
+ // at this wall clock time, the video element currentTime should be seg.presentationStartTime
+ seg.wallStartTime = timelineConverter.calcWallTimeForSegment(seg, isDynamic);
+
+ seg.replacementNumber = getNumberForSegment(seg, index);
+ seg.availabilityIdx = index;
+
+ return seg;
+}
+
+function getTimeBasedSegment(timelineConverter, isDynamic, representation, time, duration, fTimescale, url, range, index) {
+ var scaledTime = time / fTimescale;
+ var scaledDuration = Math.min(duration / fTimescale, representation.adaptation.period.mpd.maxSegmentDuration);
+
+ var presentationStartTime, presentationEndTime, seg;
+
+ presentationStartTime = timelineConverter.calcPresentationTimeFromMediaTime(scaledTime, representation);
+ presentationEndTime = presentationStartTime + scaledDuration;
+
+ seg = new _voSegment2['default']();
+
+ seg.representation = representation;
+ seg.duration = scaledDuration;
+ seg.mediaStartTime = scaledTime;
+
+ seg.presentationStartTime = presentationStartTime;
+
+ // For SegmentTimeline every segment is available at loadedTime
+ seg.availabilityStartTime = representation.adaptation.period.mpd.manifest.loadedTime;
+ seg.availabilityEndTime = timelineConverter.calcAvailabilityEndTimeFromPresentationTime(presentationEndTime, representation.adaptation.period.mpd, isDynamic);
+
+ // at this wall clock time, the video element currentTime should be seg.presentationStartTime
+ seg.wallStartTime = timelineConverter.calcWallTimeForSegment(seg, isDynamic);
+
+ seg.replacementTime = time;
+
+ seg.replacementNumber = getNumberForSegment(seg, index);
+
+ url = replaceTokenForTemplate(url, 'Number', seg.replacementNumber);
+ url = replaceTokenForTemplate(url, 'Time', seg.replacementTime);
+ seg.media = url;
+ seg.mediaRange = range;
+ seg.availabilityIdx = index;
+
+ return seg;
+}
+
+function getSegmentByIndex(index, representation) {
+ if (!representation || !representation.segments) return null;
+
+ var ln = representation.segments.length;
+ var seg, i;
+
+ if (index < ln) {
+ seg = representation.segments[index];
+ if (seg && seg.availabilityIdx === index) {
+ return seg;
+ }
+ }
+
+ for (i = 0; i < ln; i++) {
+ seg = representation.segments[i];
+
+ if (seg && seg.availabilityIdx === index) {
+ return seg;
+ }
+ }
+
+ return null;
+}
+
+function decideSegmentListRangeForTimeline(timelineConverter, isDynamic, requestedTime, index, givenAvailabilityUpperLimit) {
+ var availabilityLowerLimit = 2;
+ var availabilityUpperLimit = givenAvailabilityUpperLimit || 10;
+ var firstIdx = 0;
+ var lastIdx = Number.POSITIVE_INFINITY;
+
+ var start, end, range;
+
+ if (isDynamic && !timelineConverter.isTimeSyncCompleted()) {
+ range = { start: firstIdx, end: lastIdx };
+ return range;
+ }
+
+ if (!isDynamic && requestedTime || index < 0) return null;
+
+ // segment list should not be out of the availability window range
+ start = Math.max(index - availabilityLowerLimit, firstIdx);
+ end = Math.min(index + availabilityUpperLimit, lastIdx);
+
+ range = { start: start, end: end };
+
+ return range;
+}
+
+function decideSegmentListRangeForTemplate(timelineConverter, isDynamic, representation, requestedTime, index, givenAvailabilityUpperLimit) {
+ var duration = representation.segmentDuration;
+ var minBufferTime = representation.adaptation.period.mpd.manifest.minBufferTime;
+ var availabilityWindow = representation.segmentAvailabilityRange;
+ var periodRelativeRange = {
+ start: timelineConverter.calcPeriodRelativeTimeFromMpdRelativeTime(representation, availabilityWindow.start),
+ end: timelineConverter.calcPeriodRelativeTimeFromMpdRelativeTime(representation, availabilityWindow.end)
+ };
+ var currentSegmentList = representation.segments;
+ var availabilityLowerLimit = 2 * duration;
+ var availabilityUpperLimit = givenAvailabilityUpperLimit || Math.max(2 * minBufferTime, 10 * duration);
+
+ var originAvailabilityTime = NaN;
+ var originSegment = null;
+
+ var start, end, range;
+
+ periodRelativeRange.start = Math.max(periodRelativeRange.start, 0);
+
+ if (isDynamic && !timelineConverter.isTimeSyncCompleted()) {
+ start = Math.floor(periodRelativeRange.start / duration);
+ end = Math.floor(periodRelativeRange.end / duration);
+ range = { start: start, end: end };
+ return range;
+ }
+
+ // if segments exist we should try to find the latest buffered time, which is the presentation time of the
+ // segment for the current index
+ if (currentSegmentList && currentSegmentList.length > 0) {
+ originSegment = getSegmentByIndex(index, representation);
+ if (originSegment) {
+ originAvailabilityTime = timelineConverter.calcPeriodRelativeTimeFromMpdRelativeTime(representation, originSegment.presentationStartTime);
+ } else {
+ originAvailabilityTime = index > 0 ? index * duration : timelineConverter.calcPeriodRelativeTimeFromMpdRelativeTime(representation, requestedTime);
+ }
+ } else {
+ // If no segments exist, but index > 0, it means that we switch to the other representation, so
+ // we should proceed from this time.
+ // Otherwise we should start from the beginning for static mpds or from the end (live edge) for dynamic mpds
+ originAvailabilityTime = index > 0 ? index * duration : isDynamic ? periodRelativeRange.end : periodRelativeRange.start;
+ }
+
+ // segment list should not be out of the availability window range
+ start = Math.floor(Math.max(originAvailabilityTime - availabilityLowerLimit, periodRelativeRange.start) / duration);
+ end = Math.floor(Math.min(start + availabilityUpperLimit / duration, periodRelativeRange.end / duration));
+
+ range = { start: start, end: end };
+
+ return range;
+}
+
+},{"46":46}],36:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _SegmentsUtils = _dereq_(35);
+
+function TemplateSegmentsGetter(config, isDynamic) {
+
+ var timelineConverter = config.timelineConverter;
+
+ var instance = undefined;
+
+ function getSegmentsFromTemplate(representation, requestedTime, index, availabilityUpperLimit) {
+ var template = representation.adaptation.period.mpd.manifest.Period_asArray[representation.adaptation.period.index].AdaptationSet_asArray[representation.adaptation.index].Representation_asArray[representation.index].SegmentTemplate;
+ var duration = representation.segmentDuration;
+ var availabilityWindow = representation.segmentAvailabilityRange;
+
+ var segments = [];
+ var url = null;
+ var seg = null;
+
+ var segmentRange, periodSegIdx, startIdx, endIdx, start;
+
+ start = representation.startNumber;
+
+ if (isNaN(duration) && !isDynamic) {
+ segmentRange = { start: start, end: start };
+ } else {
+ segmentRange = (0, _SegmentsUtils.decideSegmentListRangeForTemplate)(timelineConverter, isDynamic, representation, requestedTime, index, availabilityUpperLimit);
+ }
+
+ startIdx = segmentRange.start;
+ endIdx = segmentRange.end;
+
+ for (periodSegIdx = startIdx; periodSegIdx <= endIdx; periodSegIdx++) {
+
+ seg = (0, _SegmentsUtils.getIndexBasedSegment)(timelineConverter, isDynamic, representation, periodSegIdx);
+ seg.replacementTime = (start + periodSegIdx - 1) * representation.segmentDuration;
+ url = template.media;
+ url = (0, _SegmentsUtils.replaceTokenForTemplate)(url, 'Number', seg.replacementNumber);
+ url = (0, _SegmentsUtils.replaceTokenForTemplate)(url, 'Time', seg.replacementTime);
+ seg.media = url;
+
+ segments.push(seg);
+ seg = null;
+ }
+
+ if (isNaN(duration)) {
+ representation.availableSegmentsNumber = 1;
+ } else {
+ representation.availableSegmentsNumber = Math.ceil((availabilityWindow.end - availabilityWindow.start) / duration);
+ }
+
+ return segments;
+ }
+
+ instance = {
+ getSegments: getSegmentsFromTemplate
+ };
+
+ return instance;
+}
+
+TemplateSegmentsGetter.__dashjs_factory_name = 'TemplateSegmentsGetter';
+var factory = _coreFactoryMaker2['default'].getClassFactory(TemplateSegmentsGetter);
+exports['default'] = factory;
+module.exports = exports['default'];
+
+},{"10":10,"35":35}],37:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreEventBus = _dereq_(9);
+
+var _coreEventBus2 = _interopRequireDefault(_coreEventBus);
+
+var _coreEventsEvents = _dereq_(13);
+
+var _coreEventsEvents2 = _interopRequireDefault(_coreEventsEvents);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+function TimelineConverter() {
+
+ var context = this.context;
+ var eventBus = (0, _coreEventBus2['default'])(context).getInstance();
+
+ var instance = undefined,
+ clientServerTimeShift = undefined,
+ isClientServerTimeSyncCompleted = undefined,
+ expectedLiveEdge = undefined;
+
+ function initialize() {
+
+ clientServerTimeShift = 0;
+ isClientServerTimeSyncCompleted = false;
+ expectedLiveEdge = NaN;
+
+ eventBus.on(_coreEventsEvents2['default'].LIVE_EDGE_SEARCH_COMPLETED, onLiveEdgeSearchCompleted, this);
+ eventBus.on(_coreEventsEvents2['default'].TIME_SYNCHRONIZATION_COMPLETED, onTimeSyncComplete, this);
+ }
+
+ function isTimeSyncCompleted() {
+ return isClientServerTimeSyncCompleted;
+ }
+
+ function setTimeSyncCompleted(value) {
+ isClientServerTimeSyncCompleted = value;
+ }
+
+ function getClientTimeOffset() {
+ return clientServerTimeShift;
+ }
+
+ function getExpectedLiveEdge() {
+ return expectedLiveEdge;
+ }
+
+ function setExpectedLiveEdge(value) {
+ expectedLiveEdge = value;
+ }
+
+ function calcAvailabilityTimeFromPresentationTime(presentationTime, mpd, isDynamic, calculateEnd) {
+ var availabilityTime = NaN;
+
+ if (calculateEnd) {
+ //@timeShiftBufferDepth specifies the duration of the time shifting buffer that is guaranteed
+ // to be available for a Media Presentation with type 'dynamic'.
+ // When not present, the value is infinite.
+ if (isDynamic && mpd.timeShiftBufferDepth != Number.POSITIVE_INFINITY) {
+ availabilityTime = new Date(mpd.availabilityStartTime.getTime() + (presentationTime + mpd.timeShiftBufferDepth) * 1000);
+ } else {
+ availabilityTime = mpd.availabilityEndTime;
+ }
+ } else {
+ if (isDynamic) {
+ availabilityTime = new Date(mpd.availabilityStartTime.getTime() + (presentationTime - clientServerTimeShift) * 1000);
+ } else {
+ // in static mpd, all segments are available at the same time
+ availabilityTime = mpd.availabilityStartTime;
+ }
+ }
+
+ return availabilityTime;
+ }
+
+ function calcAvailabilityStartTimeFromPresentationTime(presentationTime, mpd, isDynamic) {
+ return calcAvailabilityTimeFromPresentationTime.call(this, presentationTime, mpd, isDynamic);
+ }
+
+ function calcAvailabilityEndTimeFromPresentationTime(presentationTime, mpd, isDynamic) {
+ return calcAvailabilityTimeFromPresentationTime.call(this, presentationTime, mpd, isDynamic, true);
+ }
+
+ function calcPresentationTimeFromWallTime(wallTime, period) {
+ return (wallTime.getTime() - period.mpd.availabilityStartTime.getTime() + clientServerTimeShift * 1000) / 1000;
+ }
+
+ function calcPresentationTimeFromMediaTime(mediaTime, representation) {
+ var periodStart = representation.adaptation.period.start;
+ var presentationOffset = representation.presentationTimeOffset;
+
+ return mediaTime + (periodStart - presentationOffset);
+ }
+
+ function calcMediaTimeFromPresentationTime(presentationTime, representation) {
+ var periodStart = representation.adaptation.period.start;
+ var presentationOffset = representation.presentationTimeOffset;
+
+ return presentationTime - periodStart + presentationOffset;
+ }
+
+ function calcWallTimeForSegment(segment, isDynamic) {
+ var suggestedPresentationDelay, displayStartTime, wallTime;
+
+ if (isDynamic) {
+ suggestedPresentationDelay = segment.representation.adaptation.period.mpd.suggestedPresentationDelay;
+ displayStartTime = segment.presentationStartTime + suggestedPresentationDelay;
+ wallTime = new Date(segment.availabilityStartTime.getTime() + displayStartTime * 1000);
+ }
+
+ return wallTime;
+ }
+
+ function calcSegmentAvailabilityRange(representation, isDynamic) {
+ var start = representation.adaptation.period.start;
+ var end = start + representation.adaptation.period.duration;
+ var range = { start: start, end: end };
+ var d = representation.segmentDuration || (representation.segments && representation.segments.length ? representation.segments[representation.segments.length - 1].duration : 0);
+
+ var checkTime, now;
+
+ if (!isDynamic) return range;
+
+ if (!isClientServerTimeSyncCompleted && representation.segmentAvailabilityRange) {
+ return representation.segmentAvailabilityRange;
+ }
+
+ checkTime = representation.adaptation.period.mpd.checkTime;
+ now = calcPresentationTimeFromWallTime(new Date(), representation.adaptation.period);
+ //the Media Segment list is further restricted by the CheckTime together with the MPD attribute
+ // MPD@timeShiftBufferDepth such that only Media Segments for which the sum of the start time of the
+ // Media Segment and the Period start time falls in the interval [NOW- MPD@timeShiftBufferDepth - @duration, min(CheckTime, NOW)] are included.
+ start = Math.max(now - representation.adaptation.period.mpd.timeShiftBufferDepth, representation.adaptation.period.start);
+ var timeAnchor = isNaN(checkTime) ? now : Math.min(checkTime, now);
+ var periodEnd = representation.adaptation.period.start + representation.adaptation.period.duration;
+ end = (timeAnchor >= periodEnd && timeAnchor - d < periodEnd ? periodEnd : timeAnchor) - d;
+ //end = (isNaN(checkTime) ? now : Math.min(checkTime, now)) - d;
+ range = { start: start, end: end };
+
+ return range;
+ }
+
+ function calcPeriodRelativeTimeFromMpdRelativeTime(representation, mpdRelativeTime) {
+ var periodStartTime = representation.adaptation.period.start;
+ return mpdRelativeTime - periodStartTime;
+ }
+
+ function calcMpdRelativeTimeFromPeriodRelativeTime(representation, periodRelativeTime) {
+ var periodStartTime = representation.adaptation.period.start;
+
+ return periodRelativeTime + periodStartTime;
+ }
+
+ function onLiveEdgeSearchCompleted(e) {
+ if (isClientServerTimeSyncCompleted || e.error) return;
+
+ // the difference between expected and actual live edge time is supposed to be a difference between client
+ // and server time as well
+ clientServerTimeShift += e.liveEdge - (expectedLiveEdge + e.searchTime);
+ isClientServerTimeSyncCompleted = true;
+ }
+
+ function onTimeSyncComplete(e) {
+ if (isClientServerTimeSyncCompleted || e.error) {
+ return;
+ }
+
+ clientServerTimeShift = e.offset / 1000;
+
+ isClientServerTimeSyncCompleted = true;
+ }
+
+ function calcMSETimeOffset(representation) {
+ // The MSEOffset is offset from AST for media. It is Period@start - presentationTimeOffset
+ var presentationOffset = representation.presentationTimeOffset;
+ var periodStart = representation.adaptation.period.start;
+ return periodStart - presentationOffset;
+ }
+
+ function reset() {
+ eventBus.off(_coreEventsEvents2['default'].LIVE_EDGE_SEARCH_COMPLETED, onLiveEdgeSearchCompleted, this);
+ eventBus.off(_coreEventsEvents2['default'].TIME_SYNCHRONIZATION_COMPLETED, onTimeSyncComplete, this);
+ clientServerTimeShift = 0;
+ isClientServerTimeSyncCompleted = false;
+ expectedLiveEdge = NaN;
+ }
+
+ instance = {
+ initialize: initialize,
+ isTimeSyncCompleted: isTimeSyncCompleted,
+ setTimeSyncCompleted: setTimeSyncCompleted,
+ getClientTimeOffset: getClientTimeOffset,
+ getExpectedLiveEdge: getExpectedLiveEdge,
+ setExpectedLiveEdge: setExpectedLiveEdge,
+ calcAvailabilityStartTimeFromPresentationTime: calcAvailabilityStartTimeFromPresentationTime,
+ calcAvailabilityEndTimeFromPresentationTime: calcAvailabilityEndTimeFromPresentationTime,
+ calcPresentationTimeFromWallTime: calcPresentationTimeFromWallTime,
+ calcPresentationTimeFromMediaTime: calcPresentationTimeFromMediaTime,
+ calcPeriodRelativeTimeFromMpdRelativeTime: calcPeriodRelativeTimeFromMpdRelativeTime,
+ calcMpdRelativeTimeFromPeriodRelativeTime: calcMpdRelativeTimeFromPeriodRelativeTime,
+ calcMediaTimeFromPresentationTime: calcMediaTimeFromPresentationTime,
+ calcSegmentAvailabilityRange: calcSegmentAvailabilityRange,
+ calcWallTimeForSegment: calcWallTimeForSegment,
+ calcMSETimeOffset: calcMSETimeOffset,
+ reset: reset
+ };
+
+ return instance;
+}
+
+TimelineConverter.__dashjs_factory_name = 'TimelineConverter';
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(TimelineConverter);
+module.exports = exports['default'];
+
+},{"10":10,"13":13,"9":9}],38:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _SegmentsUtils = _dereq_(35);
+
+function TimelineSegmentsGetter(config, isDynamic) {
+
+ var timelineConverter = config.timelineConverter;
+
+ var instance = undefined;
+
+ function getSegmentsFromTimeline(representation, requestedTime, index, availabilityUpperLimit) {
+ var base = representation.adaptation.period.mpd.manifest.Period_asArray[representation.adaptation.period.index].AdaptationSet_asArray[representation.adaptation.index].Representation_asArray[representation.index].SegmentTemplate || representation.adaptation.period.mpd.manifest.Period_asArray[representation.adaptation.period.index].AdaptationSet_asArray[representation.adaptation.index].Representation_asArray[representation.index].SegmentList;
+ var timeline = base.SegmentTimeline;
+ var list = base.SegmentURL_asArray;
+ var isAvailableSegmentNumberCalculated = representation.availableSegmentsNumber > 0;
+
+ var maxSegmentsAhead = 10;
+ var time = 0;
+ var scaledTime = 0;
+ var availabilityIdx = -1;
+ var segments = [];
+ var isStartSegmentForRequestedTimeFound = false;
+
+ var fragments, frag, i, len, j, repeat, repeatEndTime, nextFrag, calculatedRange, hasEnoughSegments, requiredMediaTime, startIdx, endIdx, fTimescale;
+
+ var createSegment = function createSegment(s, i) {
+ var media = base.media;
+ var mediaRange = s.mediaRange;
+
+ if (list) {
+ media = list[i].media || '';
+ mediaRange = list[i].mediaRange;
+ }
+
+ return (0, _SegmentsUtils.getTimeBasedSegment)(timelineConverter, isDynamic, representation, time, s.d, fTimescale, media, mediaRange, availabilityIdx);
+ };
+
+ fTimescale = representation.timescale;
+
+ fragments = timeline.S_asArray;
+
+ calculatedRange = (0, _SegmentsUtils.decideSegmentListRangeForTimeline)(timelineConverter, isDynamic, requestedTime, index, availabilityUpperLimit);
+
+ // if calculatedRange exists we should generate segments that belong to this range.
+ // Otherwise generate maxSegmentsAhead segments ahead of the requested time
+ if (calculatedRange) {
+ startIdx = calculatedRange.start;
+ endIdx = calculatedRange.end;
+ } else {
+ requiredMediaTime = timelineConverter.calcMediaTimeFromPresentationTime(requestedTime || 0, representation);
+ }
+
+ for (i = 0, len = fragments.length; i < len; i++) {
+ frag = fragments[i];
+ repeat = 0;
+ if (frag.hasOwnProperty('r')) {
+ repeat = frag.r;
+ }
+
+ //For a repeated S element, t belongs only to the first segment
+ if (frag.hasOwnProperty('t')) {
+ time = frag.t;
+ scaledTime = time / fTimescale;
+ }
+
+ //This is a special case: "A negative value of the @r attribute of the S element indicates that the duration indicated in @d attribute repeats until the start of the next S element, the end of the Period or until the
+ // next MPD update."
+ if (repeat < 0) {
+ nextFrag = fragments[i + 1];
+
+ if (nextFrag && nextFrag.hasOwnProperty('t')) {
+ repeatEndTime = nextFrag.t / fTimescale;
+ } else {
+ var availabilityEnd = representation.segmentAvailabilityRange ? representation.segmentAvailabilityRange.end : timelineConverter.calcSegmentAvailabilityRange(representation, isDynamic).end;
+ repeatEndTime = timelineConverter.calcMediaTimeFromPresentationTime(availabilityEnd, representation);
+ representation.segmentDuration = frag.d / fTimescale;
+ }
+
+ repeat = Math.ceil((repeatEndTime - scaledTime) / (frag.d / fTimescale)) - 1;
+ }
+
+ // if we have enough segments in the list, but we have not calculated the total number of the segments yet we
+ // should continue the loop and calc the number. Once it is calculated, we can break the loop.
+ if (hasEnoughSegments) {
+ if (isAvailableSegmentNumberCalculated) break;
+ availabilityIdx += repeat + 1;
+ continue;
+ }
+
+ for (j = 0; j <= repeat; j++) {
+ availabilityIdx++;
+
+ if (calculatedRange) {
+ if (availabilityIdx > endIdx) {
+ hasEnoughSegments = true;
+ if (isAvailableSegmentNumberCalculated) break;
+ continue;
+ }
+
+ if (availabilityIdx >= startIdx) {
+ segments.push(createSegment(frag, availabilityIdx));
+ }
+ } else {
+ if (segments.length > maxSegmentsAhead) {
+ hasEnoughSegments = true;
+ if (isAvailableSegmentNumberCalculated) break;
+ continue;
+ }
+
+ // In some cases when requiredMediaTime = actual end time of the last segment
+ // it is possible that this time a bit exceeds the declared end time of the last segment.
+ // in this case we still need to include the last segment in the segment list. to do this we
+ // use a correction factor = 1.5. This number is used because the largest possible deviation is
+ // is 50% of segment duration.
+ if (isStartSegmentForRequestedTimeFound) {
+ segments.push(createSegment(frag, availabilityIdx));
+ } else if (scaledTime >= requiredMediaTime - frag.d / fTimescale * 1.5) {
+ isStartSegmentForRequestedTimeFound = true;
+ segments.push(createSegment(frag, availabilityIdx));
+ }
+ }
+
+ time += frag.d;
+ scaledTime = time / fTimescale;
+ }
+ }
+
+ if (!isAvailableSegmentNumberCalculated) {
+ representation.availableSegmentsNumber = availabilityIdx + 1;
+ }
+
+ return segments;
+ }
+
+ instance = {
+ getSegments: getSegmentsFromTimeline
+ };
+
+ return instance;
+}
+
+TimelineSegmentsGetter.__dashjs_factory_name = 'TimelineSegmentsGetter';
+var factory = _coreFactoryMaker2['default'].getClassFactory(TimelineSegmentsGetter);
+exports['default'] = factory;
+module.exports = exports['default'];
+
+},{"10":10,"35":35}],39:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @class
+ * @ignore
+ */
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var AdaptationSet = function AdaptationSet() {
+ _classCallCheck(this, AdaptationSet);
+
+ this.period = null;
+ this.index = -1;
+ this.type = null;
+};
+
+exports["default"] = AdaptationSet;
+module.exports = exports["default"];
+
+},{}],40:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @class
+ * @ignore
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+
+var DEFAULT_DVB_PRIORITY = 1;
+var DEFAULT_DVB_WEIGHT = 1;
+
+var BaseURL = function BaseURL(url, serviceLocation, priority, weight) {
+ _classCallCheck(this, BaseURL);
+
+ this.url = url || '';
+ this.serviceLocation = serviceLocation || url || '';
+
+ // DVB extensions
+ this.dvb_priority = priority || DEFAULT_DVB_PRIORITY;
+ this.dvb_weight = weight || DEFAULT_DVB_WEIGHT;
+
+ /* currently unused:
+ * byteRange,
+ * availabilityTimeOffset,
+ * availabilityTimeComplete
+ */
+};
+
+BaseURL.DEFAULT_DVB_PRIORITY = DEFAULT_DVB_PRIORITY;
+BaseURL.DEFAULT_DVB_WEIGHT = DEFAULT_DVB_WEIGHT;
+
+exports['default'] = BaseURL;
+module.exports = exports['default'];
+
+},{}],41:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @class
+ * @ignore
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+
+var Event = function Event() {
+ _classCallCheck(this, Event);
+
+ this.duration = NaN;
+ this.presentationTime = NaN;
+ this.id = NaN;
+ this.messageData = '';
+ this.eventStream = null;
+ this.presentationTimeDelta = NaN; // Specific EMSG Box parameter
+};
+
+exports['default'] = Event;
+module.exports = exports['default'];
+
+},{}],42:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @class
+ * @ignore
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+
+var EventStream = function EventStream() {
+ _classCallCheck(this, EventStream);
+
+ this.adaptionSet = null;
+ this.representation = null;
+ this.period = null;
+ this.timescale = 1;
+ this.value = '';
+ this.schemeIdUri = '';
+};
+
+exports['default'] = EventStream;
+module.exports = exports['default'];
+
+},{}],43:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @class
+ * @ignore
+ */
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var Mpd = function Mpd() {
+ _classCallCheck(this, Mpd);
+
+ this.manifest = null;
+ this.suggestedPresentationDelay = 0;
+ this.availabilityStartTime = null;
+ this.availabilityEndTime = Number.POSITIVE_INFINITY;
+ this.timeShiftBufferDepth = Number.POSITIVE_INFINITY;
+ this.maxSegmentDuration = Number.POSITIVE_INFINITY;
+ this.checkTime = NaN;
+ this.clientServerTimeShift = 0;
+ this.isClientServerTimeSyncCompleted = false;
+};
+
+exports["default"] = Mpd;
+module.exports = exports["default"];
+
+},{}],44:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @class
+ * @ignore
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+
+var Period = function Period() {
+ _classCallCheck(this, Period);
+
+ this.id = null;
+ this.index = -1;
+ this.duration = NaN;
+ this.start = NaN;
+ this.mpd = null;
+};
+
+Period.DEFAULT_ID = 'defaultId';
+
+exports['default'] = Period;
+module.exports = exports['default'];
+
+},{}],45:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @class
+ * @ignore
+ */
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var Representation = function Representation() {
+ _classCallCheck(this, Representation);
+
+ this.id = null;
+ this.index = -1;
+ this.adaptation = null;
+ this.segmentInfoType = null;
+ this.initialization = null;
+ this.segmentDuration = NaN;
+ this.timescale = 1;
+ this.startNumber = 1;
+ this.indexRange = null;
+ this.range = null;
+ this.presentationTimeOffset = 0;
+ // Set the source buffer timeOffset to this
+ this.MSETimeOffset = NaN;
+ this.segmentAvailabilityRange = null;
+ this.availableSegmentsNumber = 0;
+ this.bandwidth = NaN;
+ this.maxPlayoutRate = NaN;
+};
+
+exports["default"] = Representation;
+module.exports = exports["default"];
+
+},{}],46:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @class
+ * @ignore
+ */
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var Segment = function Segment() {
+ _classCallCheck(this, Segment);
+
+ this.indexRange = null;
+ this.index = null;
+ this.mediaRange = null;
+ this.media = null;
+ this.duration = NaN;
+ // this is the time that should be inserted into the media url
+ this.replacementTime = null;
+ // this is the number that should be inserted into the media url
+ this.replacementNumber = NaN;
+ // This is supposed to match the time encoded in the media Segment
+ this.mediaStartTime = NaN;
+ // When the source buffer timeOffset is set to MSETimeOffset this is the
+ // time that will match the seekTarget and video.currentTime
+ this.presentationStartTime = NaN;
+ // Do not schedule this segment until
+ this.availabilityStartTime = NaN;
+ // Ignore and discard this segment after
+ this.availabilityEndTime = NaN;
+ // The index of the segment inside the availability window
+ this.availabilityIdx = NaN;
+ // For dynamic mpd's, this is the wall clock time that the video
+ // element currentTime should be presentationStartTime
+ this.wallStartTime = NaN;
+ this.representation = null;
+};
+
+exports["default"] = Segment;
+module.exports = exports["default"];
+
+},{}],47:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @class
+ * @ignore
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+
+var UTCTiming = function UTCTiming() {
+ _classCallCheck(this, UTCTiming);
+
+ // UTCTiming is a DescriptorType and doesn't have any additional fields
+ this.schemeIdUri = '';
+ this.value = '';
+};
+
+exports['default'] = UTCTiming;
+module.exports = exports['default'];
+
+},{}],48:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _XHRLoader = _dereq_(58);
+
+var _XHRLoader2 = _interopRequireDefault(_XHRLoader);
+
+var _voHeadRequest = _dereq_(164);
+
+var _voHeadRequest2 = _interopRequireDefault(_voHeadRequest);
+
+var _voError = _dereq_(162);
+
+var _voError2 = _interopRequireDefault(_voError);
+
+var _coreEventBus = _dereq_(9);
+
+var _coreEventBus2 = _interopRequireDefault(_coreEventBus);
+
+var _coreEventsEvents = _dereq_(13);
+
+var _coreEventsEvents2 = _interopRequireDefault(_coreEventsEvents);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var FRAGMENT_LOADER_ERROR_LOADING_FAILURE = 1;
+var FRAGMENT_LOADER_ERROR_NULL_REQUEST = 2;
+var FRAGMENT_LOADER_MESSAGE_NULL_REQUEST = 'request is null';
+
+function FragmentLoader(config) {
+
+ var context = this.context;
+ var eventBus = (0, _coreEventBus2['default'])(context).getInstance();
+
+ var instance = undefined,
+ xhrLoader = undefined;
+
+ function setup() {
+ xhrLoader = (0, _XHRLoader2['default'])(context).create({
+ errHandler: config.errHandler,
+ metricsModel: config.metricsModel,
+ requestModifier: config.requestModifier
+ });
+ }
+
+ function checkForExistence(request) {
+ var report = function report(success) {
+ eventBus.trigger(_coreEventsEvents2['default'].CHECK_FOR_EXISTENCE_COMPLETED, {
+ request: request,
+ exists: success
+ });
+ };
+
+ if (request) {
+ var headRequest = new _voHeadRequest2['default'](request.url);
+
+ xhrLoader.load({
+ request: headRequest,
+ success: function success() {
+ report(true);
+ },
+ error: function error() {
+ report(false);
+ }
+ });
+ } else {
+ report(false);
+ }
+ }
+
+ function load(request) {
+ var report = function report(data, error) {
+ eventBus.trigger(_coreEventsEvents2['default'].LOADING_COMPLETED, {
+ request: request,
+ response: data || null,
+ error: error || null,
+ sender: instance
+ });
+ };
+
+ if (request) {
+ xhrLoader.load({
+ request: request,
+ progress: function progress() {
+ eventBus.trigger(_coreEventsEvents2['default'].LOADING_PROGRESS, {
+ request: request
+ });
+ },
+ success: function success(data) {
+ report(data);
+ },
+ error: function error(xhr, statusText, errorText) {
+ report(undefined, new _voError2['default'](FRAGMENT_LOADER_ERROR_LOADING_FAILURE, errorText, statusText));
+ }
+ });
+ } else {
+ report(undefined, new _voError2['default'](FRAGMENT_LOADER_ERROR_NULL_REQUEST, FRAGMENT_LOADER_MESSAGE_NULL_REQUEST));
+ }
+ }
+
+ function abort() {
+ if (xhrLoader) {
+ xhrLoader.abort();
+ }
+ }
+
+ function reset() {
+ if (xhrLoader) {
+ xhrLoader.abort();
+ xhrLoader = null;
+ }
+ }
+
+ instance = {
+ checkForExistence: checkForExistence,
+ load: load,
+ abort: abort,
+ reset: reset
+ };
+
+ setup();
+
+ return instance;
+}
+
+FragmentLoader.__dashjs_factory_name = 'FragmentLoader';
+
+var factory = _coreFactoryMaker2['default'].getClassFactory(FragmentLoader);
+factory.FRAGMENT_LOADER_ERROR_LOADING_FAILURE = FRAGMENT_LOADER_ERROR_LOADING_FAILURE;
+factory.FRAGMENT_LOADER_ERROR_NULL_REQUEST = FRAGMENT_LOADER_ERROR_NULL_REQUEST;
+exports['default'] = factory;
+module.exports = exports['default'];
+
+},{"10":10,"13":13,"162":162,"164":164,"58":58,"9":9}],49:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _controllersXlinkController = _dereq_(74);
+
+var _controllersXlinkController2 = _interopRequireDefault(_controllersXlinkController);
+
+var _XHRLoader = _dereq_(58);
+
+var _XHRLoader2 = _interopRequireDefault(_XHRLoader);
+
+var _utilsURLUtils = _dereq_(158);
+
+var _utilsURLUtils2 = _interopRequireDefault(_utilsURLUtils);
+
+var _voTextRequest = _dereq_(170);
+
+var _voTextRequest2 = _interopRequireDefault(_voTextRequest);
+
+var _voError = _dereq_(162);
+
+var _voError2 = _interopRequireDefault(_voError);
+
+var _voMetricsHTTPRequest = _dereq_(179);
+
+var _coreEventBus = _dereq_(9);
+
+var _coreEventBus2 = _interopRequireDefault(_coreEventBus);
+
+var _coreEventsEvents = _dereq_(13);
+
+var _coreEventsEvents2 = _interopRequireDefault(_coreEventsEvents);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var MANIFEST_LOADER_ERROR_PARSING_FAILURE = 1;
+var MANIFEST_LOADER_ERROR_LOADING_FAILURE = 2;
+var MANIFEST_LOADER_MESSAGE_PARSING_FAILURE = 'parsing failed';
+
+function ManifestLoader(config) {
+
+ var context = this.context;
+ var eventBus = (0, _coreEventBus2['default'])(context).getInstance();
+ var urlUtils = (0, _utilsURLUtils2['default'])(context).getInstance();
+ var parser = config.parser;
+
+ var instance = undefined,
+ xhrLoader = undefined,
+ xlinkController = undefined;
+
+ function setup() {
+ eventBus.on(_coreEventsEvents2['default'].XLINK_READY, onXlinkReady, instance);
+
+ xhrLoader = (0, _XHRLoader2['default'])(context).create({
+ errHandler: config.errHandler,
+ metricsModel: config.metricsModel,
+ requestModifier: config.requestModifier
+ });
+
+ xlinkController = (0, _controllersXlinkController2['default'])(context).create({
+ errHandler: config.errHandler,
+ metricsModel: config.metricsModel,
+ requestModifier: config.requestModifier
+ });
+ }
+
+ function onXlinkReady(event) {
+ eventBus.trigger(_coreEventsEvents2['default'].INTERNAL_MANIFEST_LOADED, {
+ manifest: event.manifest
+ });
+ }
+
+ function load(url) {
+ var request = new _voTextRequest2['default'](url, _voMetricsHTTPRequest.HTTPRequest.MPD_TYPE);
+
+ xhrLoader.load({
+ request: request,
+ success: function success(data, textStatus, xhr) {
+ var actualUrl;
+ var baseUri;
+
+ // Handle redirects for the MPD - as per RFC3986 Section 5.1.3
+ // also handily resolves relative MPD URLs to absolute
+ if (xhr.responseURL && xhr.responseURL !== url) {
+ baseUri = urlUtils.parseBaseUrl(xhr.responseURL);
+ actualUrl = xhr.responseURL;
+ } else {
+ // usually this case will be caught and resolved by
+ // xhr.responseURL above but it is not available for IE11
+ // baseUri must be absolute for BaseURL resolution later
+ if (urlUtils.isRelative(url)) {
+ url = urlUtils.parseBaseUrl(window.location.href) + url;
+ }
+
+ baseUri = urlUtils.parseBaseUrl(url);
+ }
+
+ var manifest = parser.parse(data, xlinkController);
+
+ if (manifest) {
+ manifest.url = actualUrl || url;
+
+ // URL from which the MPD was originally retrieved (MPD updates will not change this value)
+ if (!manifest.originalUrl) {
+ manifest.originalUrl = manifest.url;
+ }
+
+ manifest.baseUri = baseUri;
+ manifest.loadedTime = new Date();
+ xlinkController.resolveManifestOnLoad(manifest);
+ } else {
+ eventBus.trigger(_coreEventsEvents2['default'].INTERNAL_MANIFEST_LOADED, {
+ manifest: null,
+ error: new _voError2['default'](MANIFEST_LOADER_ERROR_PARSING_FAILURE, MANIFEST_LOADER_MESSAGE_PARSING_FAILURE)
+ });
+ }
+ },
+ error: function error(xhr, statusText, errorText) {
+ eventBus.trigger(_coreEventsEvents2['default'].INTERNAL_MANIFEST_LOADED, {
+ manifest: null,
+ error: new _voError2['default'](MANIFEST_LOADER_ERROR_LOADING_FAILURE, 'Failed loading manifest: ' + url + ', ' + errorText)
+ });
+ }
+ });
+ }
+
+ function reset() {
+ eventBus.off(_coreEventsEvents2['default'].XLINK_READY, onXlinkReady, instance);
+
+ if (xlinkController) {
+ xlinkController.reset();
+ xlinkController = null;
+ }
+
+ if (xhrLoader) {
+ xhrLoader.abort();
+ xhrLoader = null;
+ }
+ }
+
+ instance = {
+ load: load,
+ reset: reset
+ };
+
+ setup();
+
+ return instance;
+}
+
+ManifestLoader.__dashjs_factory_name = 'ManifestLoader';
+
+var factory = _coreFactoryMaker2['default'].getClassFactory(ManifestLoader);
+factory.MANIFEST_LOADER_ERROR_PARSING_FAILURE = MANIFEST_LOADER_ERROR_PARSING_FAILURE;
+factory.MANIFEST_LOADER_ERROR_LOADING_FAILURE = MANIFEST_LOADER_ERROR_LOADING_FAILURE;
+exports['default'] = factory;
+module.exports = exports['default'];
+
+},{"10":10,"13":13,"158":158,"162":162,"170":170,"179":179,"58":58,"74":74,"9":9}],50:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreEventBus = _dereq_(9);
+
+var _coreEventBus2 = _interopRequireDefault(_coreEventBus);
+
+var _coreEventsEvents = _dereq_(13);
+
+var _coreEventsEvents2 = _interopRequireDefault(_coreEventsEvents);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _coreDebug = _dereq_(8);
+
+var _coreDebug2 = _interopRequireDefault(_coreDebug);
+
+function ManifestUpdater() {
+
+ var context = this.context;
+ var log = (0, _coreDebug2['default'])(context).getInstance().log;
+ var eventBus = (0, _coreEventBus2['default'])(context).getInstance();
+
+ var instance = undefined,
+ refreshDelay = undefined,
+ refreshTimer = undefined,
+ isStopped = undefined,
+ isUpdating = undefined,
+ manifestLoader = undefined,
+ manifestModel = undefined,
+ dashManifestModel = undefined;
+
+ function setConfig(config) {
+ if (!config) return;
+
+ if (config.manifestModel) {
+ manifestModel = config.manifestModel;
+ }
+ if (config.dashManifestModel) {
+ dashManifestModel = config.dashManifestModel;
+ }
+ }
+
+ function initialize(loader) {
+ manifestLoader = loader;
+ refreshDelay = NaN;
+ refreshTimer = null;
+ isUpdating = false;
+ isStopped = true;
+
+ eventBus.on(_coreEventsEvents2['default'].STREAMS_COMPOSED, onStreamsComposed, this);
+ eventBus.on(_coreEventsEvents2['default'].PLAYBACK_STARTED, onPlaybackStarted, this);
+ eventBus.on(_coreEventsEvents2['default'].PLAYBACK_PAUSED, onPlaybackPaused, this);
+ eventBus.on(_coreEventsEvents2['default'].INTERNAL_MANIFEST_LOADED, onManifestLoaded, this);
+ }
+
+ function setManifest(manifest) {
+ update(manifest);
+ }
+
+ function getManifestLoader() {
+ return manifestLoader;
+ }
+
+ function reset() {
+ eventBus.off(_coreEventsEvents2['default'].PLAYBACK_STARTED, onPlaybackStarted, this);
+ eventBus.off(_coreEventsEvents2['default'].PLAYBACK_PAUSED, onPlaybackPaused, this);
+ eventBus.off(_coreEventsEvents2['default'].STREAMS_COMPOSED, onStreamsComposed, this);
+ eventBus.off(_coreEventsEvents2['default'].INTERNAL_MANIFEST_LOADED, onManifestLoaded, this);
+
+ isStopped = true;
+ isUpdating = false;
+ clear();
+ refreshDelay = NaN;
+ }
+
+ function clear() {
+ if (refreshTimer !== null) {
+ clearInterval(refreshTimer);
+ refreshTimer = null;
+ }
+ }
+
+ function startManifestRefreshTimer() {
+ clear();
+ if (!isNaN(refreshDelay)) {
+ log('Refresh manifest in ' + refreshDelay + ' seconds.');
+ refreshTimer = setTimeout(onRefreshTimer, Math.min(refreshDelay * 1000, Math.pow(2, 31) - 1), this);
+ }
+ }
+
+ function update(manifest) {
+ var delay, timeSinceLastUpdate;
+
+ var date = new Date();
+
+ manifestModel.setValue(manifest);
+ log('Manifest has been refreshed at ' + date + '[' + date.getTime() / 1000 + '] ');
+
+ delay = dashManifestModel.getRefreshDelay(manifest);
+ timeSinceLastUpdate = (new Date().getTime() - manifest.loadedTime.getTime()) / 1000;
+ refreshDelay = Math.max(delay - timeSinceLastUpdate, 0);
+
+ eventBus.trigger(_coreEventsEvents2['default'].MANIFEST_UPDATED, { manifest: manifest });
+
+ if (!isStopped) {
+ startManifestRefreshTimer();
+ }
+ }
+
+ function onRefreshTimer() {
+ var manifest, url;
+
+ if (isStopped || isUpdating) return;
+
+ isUpdating = true;
+ manifest = manifestModel.getValue();
+ url = manifest.url;
+
+ var location = dashManifestModel.getLocation(manifest);
+ if (location) {
+ url = location;
+ }
+
+ //log("Refresh manifest @ " + url);
+
+ manifestLoader.load(url);
+ }
+
+ function onManifestLoaded(e) {
+ if (!e.error) {
+ update(e.manifest);
+ }
+ }
+
+ function onPlaybackStarted() /*e*/{
+ isStopped = false;
+ startManifestRefreshTimer();
+ }
+
+ function onPlaybackPaused() /*e*/{
+ isStopped = true;
+ clear();
+ }
+
+ function onStreamsComposed() /*e*/{
+ // When streams are ready we can consider manifest update completed. Resolve the update promise.
+ isUpdating = false;
+ }
+
+ instance = {
+ initialize: initialize,
+ setManifest: setManifest,
+ getManifestLoader: getManifestLoader,
+ setConfig: setConfig,
+ reset: reset
+ };
+
+ return instance;
+}
+ManifestUpdater.__dashjs_factory_name = 'ManifestUpdater';
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(ManifestUpdater);
+module.exports = exports['default'];
+
+},{"10":10,"13":13,"8":8,"9":9}],51:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _dashVoUTCTiming = _dereq_(47);
+
+var _dashVoUTCTiming2 = _interopRequireDefault(_dashVoUTCTiming);
+
+var _controllersPlaybackController = _dereq_(68);
+
+var _controllersPlaybackController2 = _interopRequireDefault(_controllersPlaybackController);
+
+var _controllersStreamController = _dereq_(71);
+
+var _controllersStreamController2 = _interopRequireDefault(_controllersStreamController);
+
+var _controllersMediaController = _dereq_(66);
+
+var _controllersMediaController2 = _interopRequireDefault(_controllersMediaController);
+
+var _ManifestLoader = _dereq_(49);
+
+var _ManifestLoader2 = _interopRequireDefault(_ManifestLoader);
+
+var _utilsLiveEdgeFinder = _dereq_(154);
+
+var _utilsLiveEdgeFinder2 = _interopRequireDefault(_utilsLiveEdgeFinder);
+
+var _utilsErrorHandler = _dereq_(151);
+
+var _utilsErrorHandler2 = _interopRequireDefault(_utilsErrorHandler);
+
+var _utilsCapabilities = _dereq_(147);
+
+var _utilsCapabilities2 = _interopRequireDefault(_utilsCapabilities);
+
+var _TextTracks = _dereq_(57);
+
+var _TextTracks2 = _interopRequireDefault(_TextTracks);
+
+var _controllersSourceBufferController = _dereq_(70);
+
+var _controllersSourceBufferController2 = _interopRequireDefault(_controllersSourceBufferController);
+
+var _utilsRequestModifier = _dereq_(156);
+
+var _utilsRequestModifier2 = _interopRequireDefault(_utilsRequestModifier);
+
+var _TextSourceBuffer = _dereq_(56);
+
+var _TextSourceBuffer2 = _interopRequireDefault(_TextSourceBuffer);
+
+var _modelsURIQueryAndFragmentModel = _dereq_(103);
+
+var _modelsURIQueryAndFragmentModel2 = _interopRequireDefault(_modelsURIQueryAndFragmentModel);
+
+var _modelsManifestModel = _dereq_(100);
+
+var _modelsManifestModel2 = _interopRequireDefault(_modelsManifestModel);
+
+var _modelsMediaPlayerModel = _dereq_(101);
+
+var _modelsMediaPlayerModel2 = _interopRequireDefault(_modelsMediaPlayerModel);
+
+var _modelsMetricsModel = _dereq_(102);
+
+var _modelsMetricsModel2 = _interopRequireDefault(_modelsMetricsModel);
+
+var _controllersAbrController = _dereq_(60);
+
+var _controllersAbrController2 = _interopRequireDefault(_controllersAbrController);
+
+var _controllersTimeSyncController = _dereq_(73);
+
+var _controllersTimeSyncController2 = _interopRequireDefault(_controllersTimeSyncController);
+
+var _rulesAbrABRRulesCollection = _dereq_(131);
+
+var _rulesAbrABRRulesCollection2 = _interopRequireDefault(_rulesAbrABRRulesCollection);
+
+var _modelsVideoModel = _dereq_(104);
+
+var _modelsVideoModel2 = _interopRequireDefault(_modelsVideoModel);
+
+var _rulesRulesController = _dereq_(129);
+
+var _rulesRulesController2 = _interopRequireDefault(_rulesRulesController);
+
+var _rulesSynchronizationSynchronizationRulesCollection = _dereq_(144);
+
+var _rulesSynchronizationSynchronizationRulesCollection2 = _interopRequireDefault(_rulesSynchronizationSynchronizationRulesCollection);
+
+var _controllersMediaSourceController = _dereq_(67);
+
+var _controllersMediaSourceController2 = _interopRequireDefault(_controllersMediaSourceController);
+
+var _controllersBaseURLController = _dereq_(61);
+
+var _controllersBaseURLController2 = _interopRequireDefault(_controllersBaseURLController);
+
+var _coreDebug = _dereq_(8);
+
+var _coreDebug2 = _interopRequireDefault(_coreDebug);
+
+var _coreEventBus = _dereq_(9);
+
+var _coreEventBus2 = _interopRequireDefault(_coreEventBus);
+
+var _coreEventsEvents = _dereq_(13);
+
+var _coreEventsEvents2 = _interopRequireDefault(_coreEventsEvents);
+
+var _MediaPlayerEvents = _dereq_(52);
+
+var _MediaPlayerEvents2 = _interopRequireDefault(_MediaPlayerEvents);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _coreVersion = _dereq_(11);
+
+//Dash
+
+var _dashDashAdapter = _dereq_(15);
+
+var _dashDashAdapter2 = _interopRequireDefault(_dashDashAdapter);
+
+var _dashParserDashParser = _dereq_(23);
+
+var _dashParserDashParser2 = _interopRequireDefault(_dashParserDashParser);
+
+var _dashModelsDashManifestModel = _dereq_(22);
+
+var _dashModelsDashManifestModel2 = _interopRequireDefault(_dashModelsDashManifestModel);
+
+var _dashDashMetrics = _dereq_(17);
+
+var _dashDashMetrics2 = _interopRequireDefault(_dashDashMetrics);
+
+var _dashUtilsTimelineConverter = _dereq_(37);
+
+var _dashUtilsTimelineConverter2 = _interopRequireDefault(_dashUtilsTimelineConverter);
+
+/**
+ * @module MediaPlayer
+ * @description The MediaPlayer is the primary dash.js Module and a Facade to build your player around.
+ * It will allow you access to all the important dash.js properties/methods via the public API and all the
+ * events to build a robust DASH media player.
+ */
+function MediaPlayer() {
+
+ var PLAYBACK_NOT_INITIALIZED_ERROR = 'You must first call play() to init playback before calling this method';
+ var ELEMENT_NOT_ATTACHED_ERROR = 'You must first call attachView() to set the video element before calling this method';
+ var SOURCE_NOT_ATTACHED_ERROR = 'You must first call attachSource() with a valid source before calling this method';
+ var MEDIA_PLAYER_NOT_INITIALIZED_ERROR = 'MediaPlayer not initialized!';
+
+ var context = this.context;
+ var eventBus = (0, _coreEventBus2['default'])(context).getInstance();
+ var debug = (0, _coreDebug2['default'])(context).getInstance();
+ var log = debug.log;
+
+ var instance = undefined,
+ source = undefined,
+ protectionData = undefined,
+ mediaPlayerInitialized = undefined,
+ playbackInitialized = undefined,
+ autoPlay = undefined,
+ abrController = undefined,
+ mediaController = undefined,
+ protectionController = undefined,
+ metricsReportingController = undefined,
+ adapter = undefined,
+ metricsModel = undefined,
+ mediaPlayerModel = undefined,
+ errHandler = undefined,
+ capabilities = undefined,
+ streamController = undefined,
+ rulesController = undefined,
+ playbackController = undefined,
+ dashMetrics = undefined,
+ dashManifestModel = undefined,
+ videoModel = undefined,
+ textSourceBuffer = undefined;
+
+ function setup() {
+ mediaPlayerInitialized = false;
+ playbackInitialized = false;
+ autoPlay = true;
+ protectionController = null;
+ protectionData = null;
+ adapter = null;
+ _coreEventsEvents2['default'].extend(_MediaPlayerEvents2['default']);
+ mediaPlayerModel = (0, _modelsMediaPlayerModel2['default'])(context).getInstance();
+ }
+
+ /**
+ * Upon creating the MediaPlayer you must call initialize before you call anything else.
+ * There is one exception to this rule. It is crucial to call {@link module:MediaPlayer#extend extend()}
+ * with all your extensions prior to calling initialize.
+ *
+ * ALL arguments are optional and there are individual methods to set each argument later on.
+ * The args in this method are just for convenience and should only be used for a simple player setup.
+ *
+ * @param {HTML5MediaElement=} view - Optional arg to set the video element. {@link module:MediaPlayer#attachView attachView()}
+ * @param {string=} source - Optional arg to set the media source. {@link module:MediaPlayer#attachSource attachSource()}
+ * @param {boolean=} AutoPlay - Optional arg to set auto play. {@link module:MediaPlayer#setAutoPlay setAutoPlay()}
+ * @see {@link module:MediaPlayer#attachView attachView()}
+ * @see {@link module:MediaPlayer#attachSource attachSource()}
+ * @see {@link module:MediaPlayer#setAutoPlay setAutoPlay()}
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function initialize(view, source, AutoPlay) {
+
+ capabilities = (0, _utilsCapabilities2['default'])(context).getInstance();
+ errHandler = (0, _utilsErrorHandler2['default'])(context).getInstance();
+
+ if (!capabilities.supportsMediaSource()) {
+ errHandler.capabilityError('mediasource');
+ return;
+ }
+
+ if (mediaPlayerInitialized) return;
+ mediaPlayerInitialized = true;
+
+ abrController = (0, _controllersAbrController2['default'])(context).getInstance();
+
+ playbackController = (0, _controllersPlaybackController2['default'])(context).getInstance();
+ mediaController = (0, _controllersMediaController2['default'])(context).getInstance();
+ mediaController.initialize();
+ dashManifestModel = (0, _dashModelsDashManifestModel2['default'])(context).getInstance();
+ dashMetrics = (0, _dashDashMetrics2['default'])(context).getInstance();
+ metricsModel = (0, _modelsMetricsModel2['default'])(context).getInstance();
+ metricsModel.setConfig({ adapter: createAdaptor() });
+
+ restoreDefaultUTCTimingSources();
+ setAutoPlay(AutoPlay !== undefined ? AutoPlay : true);
+
+ if (view) {
+ attachView(view);
+ }
+
+ if (source) {
+ attachSource(source);
+ }
+
+ log('[dash.js ' + getVersion() + '] ' + 'MediaPlayer has been initialized');
+ }
+
+ /**
+ * The ready state of the MediaPlayer based on both the video element and MPD source being defined.
+ *
+ * @returns {boolean} The current ready state of the MediaPlayer
+ * @see {@link module:MediaPlayer#attachView attachView()}
+ * @see {@link module:MediaPlayer#attachSource attachSource()}
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function isReady() {
+ return !!videoModel && !!source;
+ }
+
+ /**
+ * The play method initiates playback of the media defined by the {@link module:MediaPlayer#attachSource attachSource()} method.
+ * This method will call play on the native Video Element.
+ *
+ * @see {@link module:MediaPlayer#attachSource attachSource()}
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function play() {
+ if (!playbackInitialized) {
+ throw PLAYBACK_NOT_INITIALIZED_ERROR;
+ }
+ if (!autoPlay || isPaused() && playbackInitialized) {
+ playbackController.play();
+ }
+ }
+
+ /**
+ * This method will call pause on the native Video Element.
+ *
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function pause() {
+ if (!playbackInitialized) {
+ throw PLAYBACK_NOT_INITIALIZED_ERROR;
+ }
+ playbackController.pause();
+ }
+
+ /**
+ * Returns a Boolean that indicates whether the Video Element is paused.
+ * @return {boolean}
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function isPaused() {
+ if (!playbackInitialized) {
+ throw PLAYBACK_NOT_INITIALIZED_ERROR;
+ }
+ return playbackController.isPaused();
+ }
+
+ /**
+ * Returns a Boolean that indicates whether the media is in the process of seeking to a new position.
+ * @return {boolean}
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function isSeeking() {
+ if (!playbackInitialized) {
+ throw PLAYBACK_NOT_INITIALIZED_ERROR;
+ }
+ return playbackController.isSeeking();
+ }
+
+ /**
+ * Use this method to set the native Video Element's muted state. Takes a Boolean that determines whether audio is muted. true if the audio is muted and false otherwise.
+ * @param {boolean} value
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function setMute(value) {
+ if (!videoModel) {
+ throw ELEMENT_NOT_ATTACHED_ERROR;
+ }
+ getVideoElement().muted = value;
+ }
+
+ /**
+ * A Boolean that determines whether audio is muted.
+ * @returns {boolean}
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function isMuted() {
+ if (!videoModel) {
+ throw ELEMENT_NOT_ATTACHED_ERROR;
+ }
+ return getVideoElement().muted;
+ }
+
+ /**
+ * A double indicating the audio volume, from 0.0 (silent) to 1.0 (loudest).
+ * @param {number} value
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function setVolume(value) {
+ if (!videoModel) {
+ throw ELEMENT_NOT_ATTACHED_ERROR;
+ }
+ getVideoElement().volume = value;
+ }
+
+ /**
+ * Returns the current audio volume, from 0.0 (silent) to 1.0 (loudest).
+ * @returns {number}
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function getVolume() {
+ if (!videoModel) {
+ throw ELEMENT_NOT_ATTACHED_ERROR;
+ }
+ return getVideoElement().volume;
+ }
+
+ /**
+ * The length of the buffer for a given media type, in seconds. Valid media
+ * types are "video", "audio" and "fragmentedText". If no type is passed
+ * in, then the minimum of video, audio and fragmentedText buffer length is
+ * returned. NaN is returned if an invalid type is requested, the
+ * presentation does not contain that type, or if no arguments are passed
+ * and the presentation does not include any adaption sets of valid media
+ * type.
+ *
+ * @param {string} type - the media type of the buffer
+ * @returns {number} The length of the buffer for the given media type, in
+ * seconds, or NaN
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function getBufferLength(type) {
+ var types = ['video', 'audio', 'fragmentedText'];
+ if (!type) {
+ return types.map(function (t) {
+ return getTracksFor(t).length > 0 ? getDashMetrics().getCurrentBufferLevel(getMetricsFor(t)) : Number.MAX_VALUE;
+ }).reduce(function (p, c) {
+ return Math.min(p, c);
+ });
+ } else {
+ if (types.indexOf(type) !== -1) {
+ var buffer = getDashMetrics().getCurrentBufferLevel(getMetricsFor(type));
+ return buffer ? buffer : NaN;
+ } else {
+ log('Warning - getBufferLength requested for invalid type');
+ return NaN;
+ }
+ }
+ }
+
+ /**
+ * The timeShiftBufferLength (DVR Window), in seconds.
+ *
+ * @returns {number} The window of allowable play time behind the live point of a live stream.
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function getDVRWindowSize() {
+ var metric = getDVRInfoMetric();
+ if (!metric) {
+ return 0;
+ }
+ return metric.manifestInfo.DVRWindowSize;
+ }
+
+ /**
+ * This method should only be used with a live stream that has a valid timeShiftBufferLength (DVR Window).
+ * NOTE - If you do not need the raw offset value (i.e. media analytics, tracking, etc) consider using the {@link module:MediaPlayer#seek seek()} method
+ * which will calculate this value for you and set the video element's currentTime property all in one simple call.
+ *
+ * @param {number} value - A relative time, in seconds, based on the return value of the {@link module:MediaPlayer#duration duration()} method is expected.
+ * @returns {number} A value that is relative the available range within the timeShiftBufferLength (DVR Window).
+ * @see {@link module:MediaPlayer#seek seek()}
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function getDVRSeekOffset(value) {
+ var metric = getDVRInfoMetric();
+
+ if (!metric) {
+ return 0;
+ }
+
+ var val = metric.range.start + value;
+
+ if (val > metric.range.end) {
+ val = metric.range.end;
+ }
+
+ return val;
+ }
+
+ /**
+ * Sets the currentTime property of the attached video element. If it is a live stream with a
+ * timeShiftBufferLength, then the DVR window offset will be automatically calculated.
+ *
+ * @param {number} value - A relative time, in seconds, based on the return value of the {@link module:MediaPlayer#duration duration()} method is expected
+ * @see {@link module:MediaPlayer#getDVRSeekOffset getDVRSeekOffset()}
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function seek(value) {
+ if (!playbackInitialized) {
+ throw PLAYBACK_NOT_INITIALIZED_ERROR;
+ }
+ var s = playbackController.getIsDynamic() ? getDVRSeekOffset(value) : value;
+ playbackController.seek(s);
+ }
+
+ /**
+ * Current time of the playhead, in seconds.
+ *
+ * If called with no arguments then the returned time value is time elapsed since the start point of the first stream, or if it is a live stream, then the time will be based on the return value of the {@link module:MediaPlayer#duration duration()} method.
+ * However if a stream ID is supplied then time is relative to the start of that stream, or is null if there is no such stream id in the manifest.
+ *
+ * @param {string} streamId - The ID of a stream that the returned playhead time must be relative to the start of. If undefined, then playhead time is relative to the first stream.
+ * @returns {number} The current playhead time of the media, or null.
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function time(streamId) {
+ if (!playbackInitialized) {
+ throw PLAYBACK_NOT_INITIALIZED_ERROR;
+ }
+ var t = getVideoElement().currentTime;
+
+ if (streamId !== undefined) {
+ t = streamController.getTimeRelativeToStreamId(t, streamId);
+ } else if (playbackController.getIsDynamic()) {
+ var metric = getDVRInfoMetric();
+ t = metric === null ? 0 : duration() - (metric.range.end - metric.time);
+ }
+
+ return t;
+ }
+
+ /**
+ * Duration of the media's playback, in seconds.
+ *
+ * @returns {number} The current duration of the media.
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function duration() {
+ if (!playbackInitialized) {
+ throw PLAYBACK_NOT_INITIALIZED_ERROR;
+ }
+ var d = getVideoElement().duration;
+
+ if (playbackController.getIsDynamic()) {
+
+ var metric = getDVRInfoMetric();
+ var range;
+
+ if (!metric) {
+ return 0;
+ }
+
+ range = metric.range.end - metric.range.start;
+ d = range < metric.manifestInfo.DVRWindowSize ? range : metric.manifestInfo.DVRWindowSize;
+ }
+ return d;
+ }
+
+ /**
+ * Use this method to get the current playhead time as an absolute value, the time in seconds since midnight UTC, Jan 1 1970.
+ * Note - this property only has meaning for live streams. If called before play() has begun, it will return a value of NaN.
+ *
+ * @returns {number} The current playhead time as UTC timestamp.
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function timeAsUTC() {
+ if (!playbackInitialized) {
+ throw PLAYBACK_NOT_INITIALIZED_ERROR;
+ }
+ if (time() < 0) {
+ return NaN;
+ }
+ return getAsUTC(time());
+ }
+
+ /**
+ * Use this method to get the current duration as an absolute value, the time in seconds since midnight UTC, Jan 1 1970.
+ * Note - this property only has meaning for live streams.
+ *
+ * @returns {number} The current duration as UTC timestamp.
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function durationAsUTC() {
+ if (!playbackInitialized) {
+ throw PLAYBACK_NOT_INITIALIZED_ERROR;
+ }
+ return getAsUTC(duration());
+ }
+
+ /**
+ * A utility methods which converts UTC timestamp value into a valid time and date string.
+ *
+ * @param {number} time - UTC timestamp to be converted into date and time.
+ * @param {string} locales - a region identifier (i.e. en_US).
+ * @param {boolean} hour12 - 12 vs 24 hour. Set to true for 12 hour time formatting.
+ * @returns {string} A formatted time and date string.
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function formatUTC(time, locales, hour12) {
+ var dt = new Date(time * 1000);
+ var d = dt.toLocaleDateString(locales);
+ var t = dt.toLocaleTimeString(locales, { hour12: hour12 });
+ return t + ' ' + d;
+ }
+
+ /**
+ * A utility method which converts seconds into TimeCode (i.e. 300 --> 05:00).
+ *
+ * @param {number} value - A number in seconds to be converted into a formatted time code.
+ * @returns {string} A formatted time code string.
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function convertToTimeCode(value) {
+ value = Math.max(value, 0);
+
+ var h = Math.floor(value / 3600);
+ var m = Math.floor(value % 3600 / 60);
+ var s = Math.floor(value % 3600 % 60);
+ return (h === 0 ? '' : h < 10 ? '0' + h.toString() + ':' : h.toString() + ':') + (m < 10 ? '0' + m.toString() : m.toString()) + ':' + (s < 10 ? '0' + s.toString() : s.toString());
+ }
+
+ /**
+ * This method should be used to extend or replace internal dash.js objects.
+ * There are two ways to extend dash.js (determined by the override argument):
+ * <ol>
+ * <li>If you set override to true any public method or property in your custom object will
+ * override the dash.js parent object's property(ies) and will be used instead but the
+ * dash.js parent module will still be created.</li>
+ *
+ * <li>If you set override to false your object will completely replace the dash.js object.
+ * (Note: This is how it was in 1.x of Dash.js with Dijon).</li>
+ * </ol>
+ * <b>When you extend you get access to this.context, this.factory and this.parent to operate with in your custom object.</b>
+ * <ul>
+ * <li><b>this.context</b> - can be used to pass context for singleton access.</li>
+ * <li><b>this.factory</b> - can be used to call factory.getSingletonInstance().</li>
+ * <li><b>this.parent</b> - is the reference of the parent object to call other public methods. (this.parent is excluded if you extend with override set to false or option 2)</li>
+ * </ul>
+ * <b>You must call extend before you call initialize</b>
+ * @see {@link module:MediaPlayer#initialize initialize()}
+ * @param {string} parentNameString - name of parent module
+ * @param {Object} childInstance - overriding object
+ * @param {boolean} override - replace only some methods (true) or the whole object (false)
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function extend(parentNameString, childInstance, override) {
+ _coreFactoryMaker2['default'].extend(parentNameString, childInstance, override, context);
+ }
+
+ /**
+ * Use the on method to listen for public events found in MediaPlayer.events. {@link MediaPlayerEvents}
+ *
+ * @param {string} type - {@link MediaPlayerEvents}
+ * @param {Function} listener - callback method when the event fires.
+ * @param {Object} scope - context of the listener so it can be removed properly.
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function on(type, listener, scope) {
+ eventBus.on(type, listener, scope);
+ }
+
+ /**
+ * Use the off method to remove listeners for public events found in MediaPlayer.events. {@link MediaPlayerEvents}
+ *
+ * @param {string} type - {@link MediaPlayerEvents}
+ * @param {Function} listener - callback method when the event fires.
+ * @param {Object} scope - context of the listener so it can be removed properly.
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function off(type, listener, scope) {
+ eventBus.off(type, listener, scope);
+ }
+
+ /**
+ * Current version of Dash.js
+ * @returns {string} the current dash.js version string.
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function getVersion() {
+ return (0, _coreVersion.getVersionString)();
+ }
+
+ /**
+ * Use this method to access the dash.js logging class.
+ *
+ * @returns {Debug}
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function getDebug() {
+ return debug;
+ }
+
+ /**
+ * @deprecated Since version 2.1.0. <b>Instead use:</b>
+ * <ul>
+ * <li>{@link module:MediaPlayer#getVideoElement getVideoElement()}</li>
+ * <li>{@link module:MediaPlayer#getSource getSource()}</li>
+ * <li>{@link module:MediaPlayer#getVideoContainer getVideoContainer()}</li>
+ * <li>{@link module:MediaPlayer#getTTMLRenderingDiv getTTMLRenderingDiv()}</li>
+ * </ul>
+ *
+ * @returns {VideoModel}
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function getVideoModel() {
+ if (!videoModel) {
+ throw ELEMENT_NOT_ATTACHED_ERROR;
+ }
+ return videoModel;
+ }
+
+ /**
+ * <p>Changing this value will lower or increase live stream latency. The detected segment duration will be multiplied by this value
+ * to define a time in seconds to delay a live stream from the live edge.</p>
+ * <p>Lowering this value will lower latency but may decrease the player's ability to build a stable buffer.</p>
+ *
+ * @param {number} value - Represents how many segment durations to delay the live stream.
+ * @default 4
+ * @memberof module:MediaPlayer
+ * @see {@link module:MediaPlayer#useSuggestedPresentationDelay useSuggestedPresentationDelay()}
+ * @instance
+ */
+ function setLiveDelayFragmentCount(value) {
+ mediaPlayerModel.setLiveDelayFragmentCount(value);
+ }
+
+ /**
+ * <p>Equivalent in seconds of setLiveDelayFragmentCount</p>
+ * <p>Lowering this value will lower latency but may decrease the player's ability to build a stable buffer.</p>
+ * <p>This value should be less than the manifest duration by a couple of segment durations to avoid playback issues</p>
+ * <p>If set, this parameter will take precedence over setLiveDelayFragmentCount and manifest info</p>
+ *
+ * @param {number} value - Represents how many seconds to delay the live stream.
+ * @default undefined
+ * @memberof module:MediaPlayer
+ * @see {@link module:MediaPlayer#useSuggestedPresentationDelay useSuggestedPresentationDelay()}
+ * @instance
+ */
+ function setLiveDelay(value) {
+ mediaPlayerModel.setLiveDelay(value);
+ }
+
+ /**
+ * <p>Set to true if you would like to override the default live delay and honor the SuggestedPresentationDelay attribute in by the manifest.</p>
+ * @param {boolean} value
+ * @default false
+ * @memberof module:MediaPlayer
+ * @see {@link module:MediaPlayer#setLiveDelayFragmentCount setLiveDelayFragmentCount()}
+ * @instance
+ */
+ function useSuggestedPresentationDelay(value) {
+ mediaPlayerModel.setUseSuggestedPresentationDelay(value);
+ }
+
+ /**
+ * Set to false if you would like to disable the last known bit rate from being stored during playback and used
+ * to set the initial bit rate for subsequent playback within the expiration window.
+ *
+ * The default expiration is one hour, defined in milliseconds. If expired, the default initial bit rate (closest to 1000 kbps) will be used
+ * for that session and a new bit rate will be stored during that session.
+ *
+ * @param {boolean} enable - Will toggle if feature is enabled. True to enable, False to disable.
+ * @param {number=} ttl - (Optional) A value defined in milliseconds representing how long to cache the bit rate for. Time to live.
+ * @default enable = True, ttl = 360000 (1 hour)
+ * @memberof module:MediaPlayer
+ * @instance
+ *
+ */
+ function enableLastBitrateCaching(enable, ttl) {
+ mediaPlayerModel.setLastBitrateCachingInfo(enable, ttl);
+ }
+
+ /**
+ * Set to false if you would like to disable the last known lang for audio (or camera angle for video) from being stored during playback and used
+ * to set the initial settings for subsequent playback within the expiration window.
+ *
+ * The default expiration is one hour, defined in milliseconds. If expired, the default settings will be used
+ * for that session and a new settings will be stored during that session.
+ *
+ * @param {boolean} enable - Will toggle if feature is enabled. True to enable, False to disable.
+ * @param {number=} [ttl] - (Optional) A value defined in milliseconds representing how long to cache the settings for. Time to live.
+ * @default enable = True, ttl = 360000 (1 hour)
+ * @memberof module:MediaPlayer
+ * @instance
+ *
+ */
+ function enableLastMediaSettingsCaching(enable, ttl) {
+ mediaPlayerModel.setLastMediaSettingsCachingInfo(enable, ttl);
+ }
+
+ /**
+ * When switching multi-bitrate content (auto or manual mode) this property specifies the maximum bitrate allowed.
+ * If you set this property to a value lower than that currently playing, the switching engine will switch down to
+ * satisfy this requirement. If you set it to a value that is lower than the lowest bitrate, it will still play
+ * that lowest bitrate.
+ *
+ * You can set or remove this bitrate cap at anytime before or during playback. To clear this setting you must use the API
+ * and set the value param to NaN.
+ *
+ * This feature is typically used to reserve higher bitrates for playback only when the player is in large or full-screen format.
+ *
+ * @param {string} type - 'video' or 'audio' are the type options.
+ * @param {number} value - Value in kbps representing the maximum bitrate allowed.
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function setMaxAllowedBitrateFor(type, value) {
+ abrController.setMaxAllowedBitrateFor(type, value);
+ }
+
+ /**
+ * @param {string} type - 'video' or 'audio' are the type options.
+ * @memberof module:MediaPlayer
+ * @see {@link module:MediaPlayer#setMaxAllowedBitrateFor setMaxAllowedBitrateFor()}
+ * @instance
+ */
+ function getMaxAllowedBitrateFor(type) {
+ return abrController.getMaxAllowedBitrateFor(type);
+ }
+
+ /**
+ * When switching multi-bitrate content (auto or manual mode) this property specifies the maximum representation allowed,
+ * as a proportion of the size of the representation set.
+ *
+ * You can set or remove this cap at anytime before or during playback. To clear this setting you must use the API
+ * and set the value param to NaN.
+ *
+ * If both this and maxAllowedBitrate are defined, maxAllowedBitrate is evaluated first, then maxAllowedRepresentation,
+ * i.e. the lowest value from executing these rules is used.
+ *
+ * This feature is typically used to reserve higher representations for playback only when connected over a fast connection.
+ *
+ * @param {string} type - 'video' or 'audio' are the type options.
+ * @param {number} value - number between 0 and 1, where 1 is allow all representations, and 0 is allow only the lowest.
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function setMaxAllowedRepresentationRatioFor(type, value) {
+ abrController.setMaxAllowedRepresentationRatioFor(type, value);
+ }
+
+ /**
+ * @param {string} type - 'video' or 'audio' are the type options.
+ * @returns {number} The current representation ratio cap.
+ * @memberof module:MediaPlayer
+ * @see {@link MediaPlayer#setMaxAllowedRepresentationRatioFor setMaxAllowedRepresentationRatioFor()}
+ * @instance
+ */
+ function getMaxAllowedRepresentationRatioFor(type) {
+ return abrController.getMaxAllowedRepresentationRatioFor(type);
+ }
+
+ /**
+ * <p>Set to false to prevent stream from auto-playing when the view is attached.</p>
+ *
+ * @param {boolean} value
+ * @default true
+ * @memberof module:MediaPlayer
+ * @see {@link module:MediaPlayer#attachView attachView()}
+ * @instance
+ *
+ */
+ function setAutoPlay(value) {
+ autoPlay = value;
+ }
+
+ /**
+ * @returns {boolean} The current autoPlay state.
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function getAutoPlay() {
+ return autoPlay;
+ }
+
+ /**
+ * Set to true if you would like dash.js to keep downloading fragments in the background
+ * when the video element is paused.
+ *
+ * @default true
+ * @param {boolean} value
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function setScheduleWhilePaused(value) {
+ mediaPlayerModel.setScheduleWhilePaused(value);
+ }
+
+ /**
+ * Returns a boolean of the current state of ScheduleWhilePaused.
+ * @returns {boolean}
+ * @see {@link module:MediaPlayer#setScheduleWhilePaused setScheduleWhilePaused()}
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function getScheduleWhilePaused() {
+ return mediaPlayerModel.getScheduleWhilePaused();
+ }
+
+ /**
+ * Returns the DashMetrics.js Module. You use this Module to get access to all the public metrics
+ * stored in dash.js
+ *
+ * @see {@link module:DashMetrics}
+ * @returns {Object}
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function getDashMetrics() {
+ return dashMetrics;
+ }
+
+ /**
+ *
+ * @param {string} type
+ * @returns {Object}
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function getMetricsFor(type) {
+ return metricsModel.getReadOnlyMetricsFor(type);
+ }
+
+ /**
+ * @param {string} type
+ * @returns {Object}
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function getQualityFor(type) {
+ if (!playbackInitialized) {
+ throw PLAYBACK_NOT_INITIALIZED_ERROR;
+ }
+ return abrController.getQualityFor(type, streamController.getActiveStreamInfo());
+ }
+
+ /**
+ * Sets the current quality for media type instead of letting the ABR Heuristics automatically selecting it..
+ *
+ * @param {string} type
+ * @param {number} value
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function setQualityFor(type, value) {
+ if (!playbackInitialized) {
+ throw PLAYBACK_NOT_INITIALIZED_ERROR;
+ }
+ abrController.setPlaybackQuality(type, streamController.getActiveStreamInfo(), value);
+ }
+
+ /**
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function getLimitBitrateByPortal() {
+ return abrController.getLimitBitrateByPortal();
+ }
+
+ /**
+ * Sets whether to limit the representation used based on the size of the playback area
+ *
+ * @param {boolean} value
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function setLimitBitrateByPortal(value) {
+ abrController.setLimitBitrateByPortal(value);
+ }
+
+ /**
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function getUsePixelRatioInLimitBitrateByPortal() {
+ return abrController.getUsePixelRatioInLimitBitrateByPortal();
+ }
+
+ /**
+ * Sets whether to take into account the device's pixel ratio when defining the portal dimensions.
+ * Useful on, for example, retina displays.
+ *
+ * @param {boolean} value
+ * @memberof module:MediaPlayer
+ * @instance
+ * @default {boolean} false
+ */
+ function setUsePixelRatioInLimitBitrateByPortal(value) {
+ abrController.setUsePixelRatioInLimitBitrateByPortal(value);
+ }
+
+ /**
+ * Use this method to change the current text track for both external time text files and fragmented text tracks. There is no need to
+ * set the track mode on the video object to switch a track when using this method.
+ *
+ * @param {number} idx - Index of track based on the order of the order the tracks are added Use -1 to disable all tracks. (turn captions off). Use module:MediaPlayer#dashjs.MediaPlayer.events.TEXT_TRACK_ADDED.
+ * @see {@link module:MediaPlayer#dashjs.MediaPlayer.events.TEXT_TRACK_ADDED}
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function setTextTrack(idx) {
+ if (!playbackInitialized) {
+ throw PLAYBACK_NOT_INITIALIZED_ERROR;
+ }
+ //For external time text file, the only action needed to change a track is marking the track mode to showing.
+ // Fragmented text tracks need the additional step of calling textSourceBuffer.setTextTrack();
+ if (textSourceBuffer === undefined) {
+ textSourceBuffer = (0, _TextSourceBuffer2['default'])(context).getInstance();
+ }
+
+ var tracks = getVideoElement().textTracks;
+ var ln = tracks.length;
+
+ for (var i = 0; i < ln; i++) {
+ var track = tracks[i];
+ var mode = idx === i ? 'showing' : 'hidden';
+
+ if (track.mode !== mode) {
+ //checking that mode is not already set by 3rd Party player frameworks that set mode to prevent event retrigger.
+ track.mode = mode;
+ }
+ }
+
+ textSourceBuffer.setTextTrack();
+ }
+
+ /**
+ * @param {string} type
+ * @returns {Array}
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function getBitrateInfoListFor(type) {
+ if (!playbackInitialized) {
+ throw PLAYBACK_NOT_INITIALIZED_ERROR;
+ }
+ var stream = getActiveStream();
+ return stream ? stream.getBitrateListFor(type) : [];
+ }
+
+ /**
+ * Use this method to explicitly set the starting bitrate for audio | video
+ *
+ * @param {string} type
+ * @param {number} value - A value of the initial bitrate, kbps
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function setInitialBitrateFor(type, value) {
+ abrController.setInitialBitrateFor(type, value);
+ }
+
+ /**
+ * @param {string} type
+ * @returns {number} A value of the initial bitrate, kbps
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function getInitialBitrateFor(type) {
+ if (!playbackInitialized) {
+ throw PLAYBACK_NOT_INITIALIZED_ERROR; //abrController.getInitialBitrateFor is overloaded with ratioDict logic that needs manifest force it to not be callable pre play.
+ }
+ return abrController.getInitialBitrateFor(type);
+ }
+
+ /**
+ * @param {string} type
+ * @param {number} value - A value of the initial Representation Ratio
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function setInitialRepresentationRatioFor(type, value) {
+ abrController.setInitialRepresentationRatioFor(type, value);
+ }
+
+ /**
+ * @param {string} type
+ * @returns {number} A value of the initial Representation Ratio
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function getInitialRepresentationRatioFor(type) {
+ return abrController.getInitialRepresentationRatioFor(type);
+ }
+
+ /**
+ * This method returns the list of all available streams from a given manifest
+ * @param {Object} manifest
+ * @returns {Array} list of {@link StreamInfo}
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function getStreamsFromManifest(manifest) {
+ if (!playbackInitialized) {
+ throw PLAYBACK_NOT_INITIALIZED_ERROR;
+ }
+ return adapter.getStreamsInfo(manifest);
+ }
+
+ /**
+ * This method returns the list of all available tracks for a given media type
+ * @param {string} type
+ * @returns {Array} list of {@link MediaInfo}
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function getTracksFor(type) {
+ if (!playbackInitialized) {
+ throw PLAYBACK_NOT_INITIALIZED_ERROR;
+ }
+ var streamInfo = streamController.getActiveStreamInfo();
+ if (!streamInfo) return [];
+ return mediaController.getTracksFor(type, streamInfo);
+ }
+
+ /**
+ * This method returns the list of all available tracks for a given media type and streamInfo from a given manifest
+ * @param {string} type
+ * @param {Object} manifest
+ * @param {Object} streamInfo
+ * @returns {Array} list of {@link MediaInfo}
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function getTracksForTypeFromManifest(type, manifest, streamInfo) {
+ if (!playbackInitialized) {
+ throw PLAYBACK_NOT_INITIALIZED_ERROR;
+ }
+
+ streamInfo = streamInfo || adapter.getStreamsInfo(manifest)[0];
+
+ return streamInfo ? adapter.getAllMediaInfoForType(manifest, streamInfo, type) : [];
+ }
+
+ /**
+ * @param {string} type
+ * @returns {Object|null} {@link MediaInfo}
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function getCurrentTrackFor(type) {
+ if (!playbackInitialized) {
+ throw PLAYBACK_NOT_INITIALIZED_ERROR;
+ }
+ var streamInfo = streamController.getActiveStreamInfo();
+
+ if (!streamInfo) return null;
+
+ return mediaController.getCurrentTrackFor(type, streamInfo);
+ }
+
+ /**
+ * This method allows to set media settings that will be used to pick the initial track. Format of the settings
+ * is following:
+ * {lang: langValue,
+ * viewpoint: viewpointValue,
+ * audioChannelConfiguration: audioChannelConfigurationValue,
+ * accessibility: accessibilityValue,
+ * role: roleValue}
+ *
+ *
+ * @param {string} type
+ * @param {Object} value
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function setInitialMediaSettingsFor(type, value) {
+ mediaController.setInitialSettings(type, value);
+ }
+
+ /**
+ * This method returns media settings that is used to pick the initial track. Format of the settings
+ * is following:
+ * {lang: langValue,
+ * viewpoint: viewpointValue,
+ * audioChannelConfiguration: audioChannelConfigurationValue,
+ * accessibility: accessibilityValue,
+ * role: roleValue}
+ * @param {string} type
+ * @returns {Object}
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function getInitialMediaSettingsFor(type) {
+ return mediaController.getInitialSettings(type);
+ }
+
+ /**
+ * @param {MediaInfo} track - instance of {@link MediaInfo}
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function setCurrentTrack(track) {
+ if (!playbackInitialized) {
+ throw PLAYBACK_NOT_INITIALIZED_ERROR;
+ }
+ mediaController.setTrack(track);
+ }
+
+ /**
+ * This method returns the current track switch mode.
+ *
+ * @param {string} type
+ * @returns {string} mode
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function getTrackSwitchModeFor(type) {
+ return mediaController.getSwitchMode(type);
+ }
+
+ /**
+ * This method sets the current track switch mode. Available options are:
+ *
+ * MediaController.TRACK_SWITCH_MODE_NEVER_REPLACE
+ * (used to forbid clearing the buffered data (prior to current playback position) after track switch. Default for video)
+ *
+ * MediaController.TRACK_SWITCH_MODE_ALWAYS_REPLACE
+ * (used to clear the buffered data (prior to current playback position) after track switch. Default for audio)
+ *
+ * @param {string} type
+ * @param {string} mode
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function setTrackSwitchModeFor(type, mode) {
+ mediaController.setSwitchMode(type, mode);
+ }
+
+ /**
+ * This method sets the selection mode for the initial track. This mode defines how the initial track will be selected
+ * if no initial media settings are set. If initial media settings are set this parameter will be ignored. Available options are:
+ *
+ * MediaController.TRACK_SELECTION_MODE_HIGHEST_BITRATE
+ * this mode makes the player select the track with a highest bitrate. This mode is a default mode.
+ *
+ * MediaController.TRACK_SELECTION_MODE_WIDEST_RANGE
+ * this mode makes the player select the track with a widest range of bitrates
+ *
+ * @param {string} mode
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function setSelectionModeForInitialTrack(mode) {
+ mediaController.setSelectionModeForInitialTrack(mode);
+ }
+
+ /**
+ * This method returns the track selection mode.
+ *
+ * @returns {string} mode
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function getSelectionModeForInitialTrack() {
+ return mediaController.getSelectionModeForInitialTrack();
+ }
+
+ /**
+ * @deprecated since version 2.0 Instead use {@link module:MediaPlayer#getAutoSwitchQualityFor getAutoSwitchQualityFor()}.
+ * @returns {boolean} Current state of adaptive bitrate switching
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function getAutoSwitchQuality() {
+ return abrController.getAutoSwitchBitrateFor('video') || abrController.getAutoSwitchBitrateFor('audio');
+ }
+
+ /**
+ * Set to false to switch off adaptive bitrate switching.
+ *
+ * @deprecated since version 2.0 Instead use {@link module:MediaPlayer#setAutoSwitchQualityFor setAutoSwitchQualityFor()}.
+ * @param {boolean} value
+ * @default {boolean} true
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function setAutoSwitchQuality(value) {
+ abrController.setAutoSwitchBitrateFor('video', value);
+ abrController.setAutoSwitchBitrateFor('audio', value);
+ }
+
+ /**
+ * @param {string} type - 'audio' | 'video'
+ * @returns {boolean} Current state of adaptive bitrate switching
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function getAutoSwitchQualityFor(type) {
+ return abrController.getAutoSwitchBitrateFor(type);
+ }
+
+ /**
+ * Set to false to switch off adaptive bitrate switching.
+ *
+ * @param {string} type - 'audio' | 'video'
+ * @param {boolean} value
+ * @default {boolean} true
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function setAutoSwitchQualityFor(type, value) {
+ abrController.setAutoSwitchBitrateFor(type, value);
+ }
+
+ /**
+ * When enabled, after an ABR up-switch in quality, instead of requesting and appending the next fragment
+ * at the end of the current buffer range it is requested and appended closer to the current time
+ * When enabled, The maximum time to render a higher quality is current time + (1.5 * fragment duration).
+ *
+ * Note, WHen ABR down-switch is detected, we appended the lower quality at the end of the buffer range to preserve the
+ * higher quality media for as long as possible.
+ *
+ * If enabled, it should be noted there are a few cases when the client will not replace inside buffer range but rather
+ * just append at the end. 1. When the buffer level is less than one fragment duration 2. The client
+ * is in an Abandonment State due to recent fragment abandonment event.
+ *
+ * Known issues:
+ * 1. In IE11 with auto switching off, if a user switches to a quality they can not downloaded in time the
+ * fragment may be appended in the same range as the playhead or even in past, in IE11 it may cause a stutter
+ * or stall in playback.
+ *
+ *
+ * @param {boolean} value
+ * @default {boolean} false
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function setFastSwitchEnabled(value) {
+ //TODO we need to look at track switches for adaptation sets. If always replace it works much like this but clears buffer. Maybe too many ways to do same thing.
+ mediaPlayerModel.setFastSwitchEnabled(value);
+ }
+
+ /**
+ * @return {boolean} Returns true if FastSwitch ABR is enabled.
+ */
+ function getFastSwitchEnabled() {
+ return mediaPlayerModel.getFastSwitchEnabled();
+ }
+
+ /**
+ * Enabling buffer-occupancy ABR will switch to the *experimental* implementation of BOLA,
+ * replacing the throughput-based ABR rule set (ThroughputRule, BufferOccupancyRule,
+ * InsufficientBufferRule and AbandonRequestsRule) with the buffer-occupancy-based
+ * BOLA rule set (BolaRule, BolaAbandonRule).
+ *
+ * @see {@link http://arxiv.org/abs/1601.06748 BOLA WhitePaper.}
+ * @see {@link https://github.com/Dash-Industry-Forum/dash.js/wiki/BOLA-status More details about the implementation status.}
+ * @param {boolean} value
+ * @default false
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function enableBufferOccupancyABR(value) {
+ mediaPlayerModel.setBufferOccupancyABREnabled(value);
+ }
+
+ /**
+ * Allows application to retrieve a manifest. Manifest loading is asynchro
+ * nous and
+ * requires the app-provided callback function
+ *
+ * @param {string} url - url the manifest url
+ * @param {function} callback - A Callback function provided when retrieving manifests
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function retrieveManifest(url, callback) {
+ var manifestLoader = createManifestLoader();
+ var self = this;
+
+ var handler = function handler(e) {
+ if (!e.error) {
+ callback(e.manifest);
+ } else {
+ callback(null, e.error);
+ }
+ eventBus.off(_coreEventsEvents2['default'].INTERNAL_MANIFEST_LOADED, handler, self);
+ manifestLoader.reset();
+ };
+
+ eventBus.on(_coreEventsEvents2['default'].INTERNAL_MANIFEST_LOADED, handler, self);
+
+ var uriQueryFragModel = (0, _modelsURIQueryAndFragmentModel2['default'])(context).getInstance();
+ uriQueryFragModel.initialize();
+ manifestLoader.load(uriQueryFragModel.parseURI(url));
+ }
+
+ /**
+ * <p>Allows you to set a scheme and server source for UTC live edge detection for dynamic streams.
+ * If UTCTiming is defined in the manifest, it will take precedence over any time source manually added.</p>
+ * <p>If you have exposed the Date header, use the method {@link module:MediaPlayer#clearDefaultUTCTimingSources clearDefaultUTCTimingSources()}.
+ * This will allow the date header on the manifest to be used instead of a time server</p>
+ * @param {string} schemeIdUri - <ul>
+ * <li>urn:mpeg:dash:utc:http-head:2014</li>
+ * <li>urn:mpeg:dash:utc:http-xsdate:2014</li>
+ * <li>urn:mpeg:dash:utc:http-iso:2014</li>
+ * <li>urn:mpeg:dash:utc:direct:2014</li>
+ * </ul>
+ * <p>Some specs referencing early ISO23009-1 drafts incorrectly use
+ * 2012 in the URI, rather than 2014. support these for now.</p>
+ * <ul>
+ * <li>urn:mpeg:dash:utc:http-head:2012</li>
+ * <li>urn:mpeg:dash:utc:http-xsdate:2012</li>
+ * <li>urn:mpeg:dash:utc:http-iso:2012</li>
+ * <li>urn:mpeg:dash:utc:direct:2012</li>
+ * </ul>
+ * @param {string} value - Path to a time source.
+ * @default
+ * <ul>
+ * <li>schemeIdUri:urn:mpeg:dash:utc:http-xsdate:2014</li>
+ * <li>value:http://time.akamai.com</li>
+ * </ul>
+ * @memberof module:MediaPlayer
+ * @see {@link module:MediaPlayer#removeUTCTimingSource removeUTCTimingSource()}
+ * @instance
+ */
+ function addUTCTimingSource(schemeIdUri, value) {
+ removeUTCTimingSource(schemeIdUri, value); //check if it already exists and remove if so.
+ var vo = new _dashVoUTCTiming2['default']();
+ vo.schemeIdUri = schemeIdUri;
+ vo.value = value;
+ mediaPlayerModel.getUTCTimingSources().push(vo);
+ }
+
+ /**
+ * <p>Allows you to remove a UTC time source. Both schemeIdUri and value need to match the Dash.vo.UTCTiming properties in order for the
+ * entry to be removed from the array</p>
+ * @param {string} schemeIdUri - see {@link module:MediaPlayer#addUTCTimingSource addUTCTimingSource()}
+ * @param {string} value - see {@link module:MediaPlayer#addUTCTimingSource addUTCTimingSource()}
+ * @memberof module:MediaPlayer
+ * @see {@link module:MediaPlayer#clearDefaultUTCTimingSources clearDefaultUTCTimingSources()}
+ * @instance
+ */
+ function removeUTCTimingSource(schemeIdUri, value) {
+ var UTCTimingSources = mediaPlayerModel.getUTCTimingSources();
+ UTCTimingSources.forEach(function (obj, idx) {
+ if (obj.schemeIdUri === schemeIdUri && obj.value === value) {
+ UTCTimingSources.splice(idx, 1);
+ }
+ });
+ }
+
+ /**
+ * <p>Allows you to clear the stored array of time sources.</p>
+ * <p>Example use: If you have exposed the Date header, calling this method
+ * will allow the date header on the manifest to be used instead of the time server.</p>
+ * <p>Example use: Calling this method, assuming there is not an exposed date header on the manifest, will default back
+ * to using a binary search to discover the live edge</p>
+ *
+ * @memberof module:MediaPlayer
+ * @see {@link module:MediaPlayer#restoreDefaultUTCTimingSources restoreDefaultUTCTimingSources()}
+ * @instance
+ */
+ function clearDefaultUTCTimingSources() {
+ mediaPlayerModel.setUTCTimingSources([]);
+ }
+
+ /**
+ * <p>Allows you to restore the default time sources after calling {@link module:MediaPlayer#clearDefaultUTCTimingSources clearDefaultUTCTimingSources()}</p>
+ *
+ * @default
+ * <ul>
+ * <li>schemeIdUri:urn:mpeg:dash:utc:http-xsdate:2014</li>
+ * <li>value:http://time.akamai.com</li>
+ * </ul>
+ *
+ * @memberof module:MediaPlayer
+ * @see {@link module:MediaPlayer#addUTCTimingSource addUTCTimingSource()}
+ * @instance
+ */
+ function restoreDefaultUTCTimingSources() {
+ addUTCTimingSource(_modelsMediaPlayerModel2['default'].DEFAULT_UTC_TIMING_SOURCE.scheme, _modelsMediaPlayerModel2['default'].DEFAULT_UTC_TIMING_SOURCE.value);
+ }
+
+ /**
+ * <p>Allows you to enable the use of the Date Header, if exposed with CORS, as a timing source for live edge detection. The
+ * use of the date header will happen only after the other timing source that take precedence fail or are omitted as described.
+ * {@link module:MediaPlayer#clearDefaultUTCTimingSources clearDefaultUTCTimingSources()} </p>
+ *
+ * @param {boolean} value - true to enable
+ * @default {boolean} True
+ * @memberof module:MediaPlayer
+ * @see {@link module:MediaPlayer#addUTCTimingSource addUTCTimingSource()}
+ * @instance
+ */
+ function enableManifestDateHeaderTimeSource(value) {
+ mediaPlayerModel.setUseManifestDateHeaderTimeSource(value);
+ }
+
+ /**
+ * This value influences the buffer pruning logic.
+ * Allows you to modify the buffer that is kept in source buffer in seconds.
+ * 0|-----------bufferToPrune-----------|-----bufferToKeep-----|currentTime|
+ *
+ * @default 30 seconds
+ * @param {int} value
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function setBufferToKeep(value) {
+ mediaPlayerModel.setBufferToKeep(value);
+ }
+
+ /**
+ * This value influences the buffer pruning logic.
+ * Allows you to modify the interval of pruning buffer in seconds.
+ *
+ * @default 30 seconds
+ * @param {int} value
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function setBufferPruningInterval(value) {
+ mediaPlayerModel.setBufferPruningInterval(value);
+ }
+
+ /**
+ * The time that the internal buffer target will be set to post startup/seeks (NOT top quality).
+ *
+ * When the time is set higher than the default you will have to wait longer
+ * to see automatic bitrate switches but will have a larger buffer which
+ * will increase stability.
+ *
+ * @default 12 seconds.
+ * @param {int} value
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function setStableBufferTime(value) {
+ mediaPlayerModel.setStableBufferTime(value);
+ }
+
+ /**
+ * The time that the internal buffer target will be set to once playing the top quality.
+ * If there are multiple bitrates in your adaptation, and the media is playing at the highest
+ * bitrate, then we try to build a larger buffer at the top quality to increase stability
+ * and to maintain media quality.
+ *
+ * @default 30 seconds.
+ * @param {int} value
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function setBufferTimeAtTopQuality(value) {
+ mediaPlayerModel.setBufferTimeAtTopQuality(value);
+ }
+
+ /**
+ * The time that the internal buffer target will be set to once playing the top quality for long form content.
+ *
+ * @default 60 seconds.
+ * @see {@link module:MediaPlayer#setLongFormContentDurationThreshold setLongFormContentDurationThreshold()}
+ * @see {@link module:MediaPlayer#setBufferTimeAtTopQuality setBufferTimeAtTopQuality()}
+ * @param {int} value
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function setBufferTimeAtTopQualityLongForm(value) {
+ mediaPlayerModel.setBufferTimeAtTopQualityLongForm(value);
+ }
+
+ /**
+ * The threshold which defines if the media is considered long form content.
+ * This will directly affect the buffer targets when playing back at the top quality.
+ *
+ * @see {@link module:MediaPlayer#setBufferTimeAtTopQualityLongForm setBufferTimeAtTopQualityLongForm()}
+ * @default 600 seconds (10 minutes).
+ * @param {number} value
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function setLongFormContentDurationThreshold(value) {
+ mediaPlayerModel.setLongFormContentDurationThreshold(value);
+ }
+
+ /**
+ * A threshold, in seconds, of when dashjs abr becomes less conservative since we have a
+ * larger "rich" buffer.
+ * The BufferOccupancyRule.js rule will override the ThroughputRule's decision when the
+ * buffer level surpasses this value and while it remains greater than this value.
+ *
+ * @default 20 seconds
+ * @param {number} value
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function setRichBufferThreshold(value) {
+ mediaPlayerModel.setRichBufferThreshold(value);
+ }
+
+ /**
+ * A percentage between 0.0 and 1 to reduce the measured throughput calculations.
+ * The default is 0.9. The lower the value the more conservative and restricted the
+ * measured throughput calculations will be. please use carefully. This will directly
+ * affect the ABR logic in dash.js
+ *
+ * @param {number} value
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function setBandwidthSafetyFactor(value) {
+ mediaPlayerModel.setBandwidthSafetyFactor(value);
+ }
+
+ /**
+ * Returns the number of the current BandwidthSafetyFactor
+ *
+ * @return {number} value
+ * @see {@link module:MediaPlayer#setBandwidthSafetyFactor setBandwidthSafetyFactor()}
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function getBandwidthSafetyFactor() {
+ return mediaPlayerModel.getBandwidthSafetyFactor();
+ }
+
+ /**
+ * A timeout value in seconds, which during the ABRController will block switch-up events.
+ * This will only take effect after an abandoned fragment event occurs.
+ *
+ * @default 10 seconds
+ * @param {int} value
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function setAbandonLoadTimeout(value) {
+ mediaPlayerModel.setAbandonLoadTimeout(value);
+ }
+
+ /**
+ * Total number of retry attempts that will occur on a fragment load before it fails.
+ * Increase this value to a maximum in order to achieve an automatic playback resume
+ * in case of completely lost internet connection.
+ *
+ * @default 3
+ * @param {int} value
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function setFragmentLoaderRetryAttempts(value) {
+ mediaPlayerModel.setFragmentRetryAttempts(value);
+ }
+
+ /**
+ * Time in milliseconds of which to reload a failed fragment load attempt.
+ *
+ * @default 1000 milliseconds
+ * @param {int} value
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function setFragmentLoaderRetryInterval(value) {
+ mediaPlayerModel.setFragmentRetryInterval(value);
+ }
+
+ /**
+ * Sets whether withCredentials on XHR requests is true or false
+ *
+ * @default false
+ * @param {boolean} value
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function setXHRWithCredentials(value) {
+ mediaPlayerModel.setXHRWithCredentials(value);
+ }
+
+ /**
+ * Detects if Protection is included and returns an instance of ProtectionController.js
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function getProtectionController() {
+ return detectProtection();
+ }
+
+ /**
+ * Will override dash.js protection controller.
+ * @param {ProtectionController} value - valid protection controller instance.
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function attachProtectionController(value) {
+ protectionController = value;
+ }
+
+ /**
+ * @param {ProtectionData} value - object containing
+ * property names corresponding to key system name strings and associated
+ * values being instances of.
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function setProtectionData(value) {
+ protectionData = value;
+ }
+
+ /**
+ * This method serves to control captions z-index value. If 'true' is passed, the captions will have the highest z-index and be
+ * displayed on top of other html elements. Default value is 'false' (z-index is not set).
+ * @param {boolean} value
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function displayCaptionsOnTop(value) {
+ var textTracks = (0, _TextTracks2['default'])(context).getInstance();
+ textTracks.setConfig({ videoModel: videoModel });
+ textTracks.initialize();
+ textTracks.displayCConTop(value);
+ }
+
+ /**
+ * Returns instance of Video Container that was attached by calling attachVideoContainer()
+ * @returns {Object}
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function getVideoContainer() {
+ return videoModel ? videoModel.getVideoContainer() : null;
+ }
+
+ /**
+ * Use this method to attach an HTML5 element that wraps the video element.
+ *
+ * @param {HTMLElement} container - The HTML5 element containing the video element.
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function attachVideoContainer(container) {
+ if (!videoModel) {
+ throw ELEMENT_NOT_ATTACHED_ERROR;
+ }
+ videoModel.setVideoContainer(container);
+ }
+
+ /**
+ * Returns instance of Video Element that was attached by calling attachView()
+ * @returns {Object}
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function getVideoElement() {
+ if (!videoModel) {
+ throw ELEMENT_NOT_ATTACHED_ERROR;
+ }
+ return videoModel.getElement();
+ }
+
+ /**
+ * Use this method to attach an HTML5 VideoElement for dash.js to operate upon.
+ *
+ * @param {Object} element - An HTMLMediaElement that has already been defined in the DOM (or equivalent stub).
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function attachView(element) {
+ if (!mediaPlayerInitialized) {
+ throw MEDIA_PLAYER_NOT_INITIALIZED_ERROR;
+ }
+ videoModel = null;
+ if (element) {
+ videoModel = (0, _modelsVideoModel2['default'])(context).getInstance();
+ videoModel.initialize();
+ videoModel.setElement(element);
+ detectProtection();
+ detectMetricsReporting();
+ }
+ resetAndInitializePlayback();
+ }
+
+ /**
+ * Returns instance of Div that was attached by calling attachTTMLRenderingDiv()
+ * @returns {Object}
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function getTTMLRenderingDiv() {
+ return videoModel ? videoModel.getTTMLRenderingDiv() : null;
+ }
+
+ /**
+ * Use this method to attach an HTML5 div for dash.js to render rich TTML subtitles.
+ *
+ * @param {HTMLDivElement} div - An unstyled div placed after the video element. It will be styled to match the video size and overlay z-order.
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function attachTTMLRenderingDiv(div) {
+ if (!videoModel) {
+ throw ELEMENT_NOT_ATTACHED_ERROR;
+ }
+ videoModel.setTTMLRenderingDiv(div);
+ }
+
+ /**
+ * Returns the source string or manifest that was attached by calling attachSource()
+ * @returns {string | manifest}
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function getSource() {
+ if (!source) {
+ throw SOURCE_NOT_ATTACHED_ERROR;
+ }
+ return source;
+ }
+
+ /**
+ * Use this method to set a source URL to a valid MPD manifest file OR
+ * a previously downloaded and parsed manifest object. Optionally, can
+ * also provide protection information
+ *
+ * @param {string|Object} urlOrManifest - A URL to a valid MPD manifest file, or a
+ * parsed manifest object.
+ *
+ *
+ * @throws "MediaPlayer not initialized!"
+ *
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function attachSource(urlOrManifest) {
+ if (!mediaPlayerInitialized) {
+ throw MEDIA_PLAYER_NOT_INITIALIZED_ERROR;
+ }
+
+ if (typeof urlOrManifest === 'string') {
+ var uriQueryFragModel = (0, _modelsURIQueryAndFragmentModel2['default'])(context).getInstance();
+ uriQueryFragModel.initialize();
+ source = uriQueryFragModel.parseURI(urlOrManifest);
+ } else {
+ source = urlOrManifest;
+ }
+
+ resetAndInitializePlayback();
+ }
+
+ /**
+ * Sets the MPD source and the video element to null. You can also reset the MediaPlayer by
+ * calling attachSource with a new source file.
+ *
+ * @memberof module:MediaPlayer
+ * @instance
+ */
+ function reset() {
+ attachSource(null);
+ attachView(null);
+ protectionData = null;
+ protectionController = null;
+ }
+
+ //***********************************
+ // PRIVATE METHODS
+ //***********************************
+
+ function resetAndInitializePlayback() {
+ if (playbackInitialized) {
+ playbackInitialized = false;
+ adapter.reset();
+ streamController.reset();
+ playbackController.reset();
+ abrController.reset();
+ rulesController.reset();
+ mediaController.reset();
+ streamController = null;
+ metricsReportingController = null;
+ if (isReady()) {
+ initializePlayback();
+ }
+ } else if (isReady()) {
+ initializePlayback();
+ }
+ }
+
+ function createControllers() {
+
+ var synchronizationRulesCollection = (0, _rulesSynchronizationSynchronizationRulesCollection2['default'])(context).getInstance();
+ synchronizationRulesCollection.initialize();
+
+ var abrRulesCollection = (0, _rulesAbrABRRulesCollection2['default'])(context).getInstance();
+ abrRulesCollection.initialize();
+
+ //let scheduleRulesCollection = ScheduleRulesCollection(context).getInstance();
+ //scheduleRulesCollection.initialize();
+
+ var sourceBufferController = (0, _controllersSourceBufferController2['default'])(context).getInstance();
+ sourceBufferController.setConfig({ dashManifestModel: dashManifestModel });
+
+ mediaController.initialize();
+ mediaController.setConfig({
+ errHandler: errHandler
+ });
+
+ rulesController = (0, _rulesRulesController2['default'])(context).getInstance();
+ rulesController.initialize();
+ rulesController.setConfig({
+ abrRulesCollection: abrRulesCollection,
+ synchronizationRulesCollection: synchronizationRulesCollection
+ });
+
+ streamController = (0, _controllersStreamController2['default'])(context).getInstance();
+ streamController.setConfig({
+ capabilities: capabilities,
+ manifestLoader: createManifestLoader(),
+ manifestModel: (0, _modelsManifestModel2['default'])(context).getInstance(),
+ dashManifestModel: dashManifestModel,
+ protectionController: protectionController,
+ adapter: adapter,
+ metricsModel: metricsModel,
+ dashMetrics: dashMetrics,
+ liveEdgeFinder: (0, _utilsLiveEdgeFinder2['default'])(context).getInstance(),
+ mediaSourceController: (0, _controllersMediaSourceController2['default'])(context).getInstance(),
+ timeSyncController: (0, _controllersTimeSyncController2['default'])(context).getInstance(),
+ baseURLController: (0, _controllersBaseURLController2['default'])(context).getInstance(),
+ errHandler: errHandler,
+ timelineConverter: (0, _dashUtilsTimelineConverter2['default'])(context).getInstance()
+ });
+ streamController.initialize(autoPlay, protectionData);
+
+ abrController.setConfig({
+ abrRulesCollection: abrRulesCollection,
+ rulesController: rulesController,
+ streamController: streamController
+ });
+ }
+
+ function createManifestLoader() {
+ return (0, _ManifestLoader2['default'])(context).create({
+ errHandler: errHandler,
+ parser: createManifestParser(),
+ metricsModel: metricsModel,
+ requestModifier: (0, _utilsRequestModifier2['default'])(context).getInstance()
+ });
+ }
+
+ function createManifestParser() {
+ //TODO-Refactor Need to be able to switch this create out so will need API to set which parser to use?
+ return (0, _dashParserDashParser2['default'])(context).create();
+ }
+
+ function createAdaptor() {
+ //TODO-Refactor Need to be able to switch this create out so will need API to set which adapter to use? Handler is created is inside streamProcessor so need to figure that out as well
+ adapter = (0, _dashDashAdapter2['default'])(context).getInstance();
+ adapter.initialize();
+ adapter.setConfig({ dashManifestModel: dashManifestModel });
+ return adapter;
+ }
+
+ function detectProtection() {
+ if (protectionController) {
+ return protectionController;
+ }
+ // do not require Protection as dependencies as this is optional and intended to be loaded separately
+ var Protection = dashjs.Protection; /* jshint ignore:line */
+ if (typeof Protection === 'function') {
+ //TODO need a better way to register/detect plugin components
+ var protection = Protection(context).create();
+ _coreEventsEvents2['default'].extend(Protection.events);
+ _MediaPlayerEvents2['default'].extend(Protection.events, { publicOnly: true });
+ protectionController = protection.createProtectionSystem({
+ log: log,
+ videoModel: videoModel,
+ capabilities: capabilities,
+ eventBus: eventBus,
+ adapter: adapter
+ });
+ return protectionController;
+ }
+
+ return null;
+ }
+
+ function detectMetricsReporting() {
+ if (metricsReportingController) {
+ return metricsReportingController;
+ }
+ // do not require MetricsReporting as dependencies as this is optional and intended to be loaded separately
+ var MetricsReporting = dashjs.MetricsReporting; /* jshint ignore:line */
+ if (typeof MetricsReporting === 'function') {
+ //TODO need a better way to register/detect plugin components
+ var metricsReporting = MetricsReporting(context).create();
+
+ metricsReportingController = metricsReporting.createMetricsReporting({
+ log: log,
+ eventBus: eventBus,
+ mediaElement: getVideoElement(),
+ dashManifestModel: dashManifestModel,
+ metricsModel: metricsModel
+ });
+
+ return metricsReportingController;
+ }
+
+ return null;
+ }
+
+ function getDVRInfoMetric() {
+ var metric = metricsModel.getReadOnlyMetricsFor('video') || metricsModel.getReadOnlyMetricsFor('audio');
+ return dashMetrics.getCurrentDVRInfo(metric);
+ }
+
+ function getAsUTC(valToConvert) {
+ var metric = getDVRInfoMetric();
+ var availableFrom, utcValue;
+
+ if (!metric) {
+ return 0;
+ }
+ availableFrom = metric.manifestInfo.availableFrom.getTime() / 1000;
+ utcValue = valToConvert + (availableFrom + metric.range.start);
+ return utcValue;
+ }
+
+ function getActiveStream() {
+ if (!playbackInitialized) {
+ throw PLAYBACK_NOT_INITIALIZED_ERROR;
+ }
+ var streamInfo = streamController.getActiveStreamInfo();
+ return streamInfo ? streamController.getStreamById(streamInfo.id) : null;
+ }
+
+ function initializePlayback() {
+ if (!playbackInitialized) {
+ playbackInitialized = true;
+ log('Playback Initialized');
+ createControllers();
+ if (typeof source === 'string') {
+ streamController.load(source);
+ } else {
+ streamController.loadWithManifest(source);
+ }
+ }
+ }
+
+ instance = {
+ initialize: initialize,
+ on: on,
+ off: off,
+ extend: extend,
+ attachView: attachView,
+ attachSource: attachSource,
+ isReady: isReady,
+ play: play,
+ isPaused: isPaused,
+ pause: pause,
+ isSeeking: isSeeking,
+ seek: seek,
+ setMute: setMute,
+ isMuted: isMuted,
+ setVolume: setVolume,
+ getVolume: getVolume,
+ time: time,
+ duration: duration,
+ timeAsUTC: timeAsUTC,
+ durationAsUTC: durationAsUTC,
+ getActiveStream: getActiveStream,
+ getDVRWindowSize: getDVRWindowSize,
+ getDVRSeekOffset: getDVRSeekOffset,
+ convertToTimeCode: convertToTimeCode,
+ formatUTC: formatUTC,
+ getVersion: getVersion,
+ getDebug: getDebug,
+ getBufferLength: getBufferLength,
+ getVideoModel: getVideoModel,
+ getVideoContainer: getVideoContainer,
+ getTTMLRenderingDiv: getTTMLRenderingDiv,
+ getVideoElement: getVideoElement,
+ getSource: getSource,
+ setLiveDelayFragmentCount: setLiveDelayFragmentCount,
+ setLiveDelay: setLiveDelay,
+ useSuggestedPresentationDelay: useSuggestedPresentationDelay,
+ enableLastBitrateCaching: enableLastBitrateCaching,
+ enableLastMediaSettingsCaching: enableLastMediaSettingsCaching,
+ setMaxAllowedBitrateFor: setMaxAllowedBitrateFor,
+ getMaxAllowedBitrateFor: getMaxAllowedBitrateFor,
+ setMaxAllowedRepresentationRatioFor: setMaxAllowedRepresentationRatioFor,
+ getMaxAllowedRepresentationRatioFor: getMaxAllowedRepresentationRatioFor,
+ setAutoPlay: setAutoPlay,
+ getAutoPlay: getAutoPlay,
+ setScheduleWhilePaused: setScheduleWhilePaused,
+ getScheduleWhilePaused: getScheduleWhilePaused,
+ getDashMetrics: getDashMetrics,
+ getMetricsFor: getMetricsFor,
+ getQualityFor: getQualityFor,
+ setQualityFor: setQualityFor,
+ getLimitBitrateByPortal: getLimitBitrateByPortal,
+ setLimitBitrateByPortal: setLimitBitrateByPortal,
+ getUsePixelRatioInLimitBitrateByPortal: getUsePixelRatioInLimitBitrateByPortal,
+ setUsePixelRatioInLimitBitrateByPortal: setUsePixelRatioInLimitBitrateByPortal,
+ setTextTrack: setTextTrack,
+ getBitrateInfoListFor: getBitrateInfoListFor,
+ setInitialBitrateFor: setInitialBitrateFor,
+ getInitialBitrateFor: getInitialBitrateFor,
+ setInitialRepresentationRatioFor: setInitialRepresentationRatioFor,
+ getInitialRepresentationRatioFor: getInitialRepresentationRatioFor,
+ getStreamsFromManifest: getStreamsFromManifest,
+ getTracksFor: getTracksFor,
+ getTracksForTypeFromManifest: getTracksForTypeFromManifest,
+ getCurrentTrackFor: getCurrentTrackFor,
+ setInitialMediaSettingsFor: setInitialMediaSettingsFor,
+ getInitialMediaSettingsFor: getInitialMediaSettingsFor,
+ setCurrentTrack: setCurrentTrack,
+ getTrackSwitchModeFor: getTrackSwitchModeFor,
+ setTrackSwitchModeFor: setTrackSwitchModeFor,
+ setSelectionModeForInitialTrack: setSelectionModeForInitialTrack,
+ getSelectionModeForInitialTrack: getSelectionModeForInitialTrack,
+ getAutoSwitchQuality: getAutoSwitchQuality,
+ setAutoSwitchQuality: setAutoSwitchQuality,
+ setFastSwitchEnabled: setFastSwitchEnabled,
+ getFastSwitchEnabled: getFastSwitchEnabled,
+ getAutoSwitchQualityFor: getAutoSwitchQualityFor,
+ setAutoSwitchQualityFor: setAutoSwitchQualityFor,
+ enableBufferOccupancyABR: enableBufferOccupancyABR,
+ setBandwidthSafetyFactor: setBandwidthSafetyFactor,
+ getBandwidthSafetyFactor: getBandwidthSafetyFactor,
+ setAbandonLoadTimeout: setAbandonLoadTimeout,
+ retrieveManifest: retrieveManifest,
+ addUTCTimingSource: addUTCTimingSource,
+ removeUTCTimingSource: removeUTCTimingSource,
+ clearDefaultUTCTimingSources: clearDefaultUTCTimingSources,
+ restoreDefaultUTCTimingSources: restoreDefaultUTCTimingSources,
+ setBufferToKeep: setBufferToKeep,
+ setBufferPruningInterval: setBufferPruningInterval,
+ setStableBufferTime: setStableBufferTime,
+ setBufferTimeAtTopQuality: setBufferTimeAtTopQuality,
+ setFragmentLoaderRetryAttempts: setFragmentLoaderRetryAttempts,
+ setFragmentLoaderRetryInterval: setFragmentLoaderRetryInterval,
+ setXHRWithCredentials: setXHRWithCredentials,
+ setBufferTimeAtTopQualityLongForm: setBufferTimeAtTopQualityLongForm,
+ setLongFormContentDurationThreshold: setLongFormContentDurationThreshold,
+ setRichBufferThreshold: setRichBufferThreshold,
+ getProtectionController: getProtectionController,
+ attachProtectionController: attachProtectionController,
+ setProtectionData: setProtectionData,
+ enableManifestDateHeaderTimeSource: enableManifestDateHeaderTimeSource,
+ displayCaptionsOnTop: displayCaptionsOnTop,
+ attachVideoContainer: attachVideoContainer,
+ attachTTMLRenderingDiv: attachTTMLRenderingDiv,
+ reset: reset
+ };
+
+ setup();
+
+ return instance;
+}
+
+MediaPlayer.__dashjs_factory_name = 'MediaPlayer';
+var factory = _coreFactoryMaker2['default'].getClassFactory(MediaPlayer);
+factory.events = _MediaPlayerEvents2['default'];
+exports['default'] = factory;
+module.exports = exports['default'];
+
+},{"10":10,"100":100,"101":101,"102":102,"103":103,"104":104,"11":11,"129":129,"13":13,"131":131,"144":144,"147":147,"15":15,"151":151,"154":154,"156":156,"17":17,"22":22,"23":23,"37":37,"47":47,"49":49,"52":52,"56":56,"57":57,"60":60,"61":61,"66":66,"67":67,"68":68,"70":70,"71":71,"73":73,"8":8,"9":9}],52:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+var _coreEventsEventsBase = _dereq_(14);
+
+var _coreEventsEventsBase2 = _interopRequireDefault(_coreEventsEventsBase);
+
+/**
+ * @class
+ *
+ */
+
+var MediaPlayerEvents = (function (_EventsBase) {
+ _inherits(MediaPlayerEvents, _EventsBase);
+
+ /**
+ * @description Public facing external events to be used when developing a player that implements dash.js.
+ */
+
+ function MediaPlayerEvents() {
+ _classCallCheck(this, MediaPlayerEvents);
+
+ _get(Object.getPrototypeOf(MediaPlayerEvents.prototype), 'constructor', this).call(this);
+ /**
+ * Triggered when the video element's buffer state changes to stalled.
+ * Check mediaType in payload to determine type (Video, Audio, FragmentedText).
+ * @event MediaPlayerEvents#BUFFER_EMPTY
+ */
+ this.BUFFER_EMPTY = 'bufferstalled';
+ /**
+ * Triggered when the video element's buffer state changes to loaded.
+ * Check mediaType in payload to determine type (Video, Audio, FragmentedText).
+ * @event MediaPlayerEvents#BUFFER_LOADED
+ */
+ this.BUFFER_LOADED = 'bufferloaded';
+
+ /**
+ * Triggered when the video element's buffer state changes, either stalled or loaded. Check payload for state.
+ * @event MediaPlayerEvents#BUFFER_LEVEL_STATE_CHANGED
+ */
+ this.BUFFER_LEVEL_STATE_CHANGED = 'bufferStateChanged';
+
+ /**
+ * Triggered when
+ * @event MediaPlayerEvents#ERROR
+ */
+ this.ERROR = 'error';
+ /**
+ * Triggered when {@link module:Debug} log method is called.
+ * @event MediaPlayerEvents#LOG
+ */
+ this.LOG = 'log';
+ //TODO refactor with internal event
+ /**
+ * Triggered when the manifest load is complete
+ * @event MediaPlayerEvents#MANIFEST_LOADED
+ */
+ this.MANIFEST_LOADED = 'manifestloaded';
+ /**
+ * Triggered anytime there is a change to the overall metrics.
+ * @event MediaPlayerEvents#METRICS_CHANGED
+ */
+ this.METRICS_CHANGED = 'metricschanged';
+ /**
+ * Triggered when an individual metric is added, updated or cleared.
+ * @event MediaPlayerEvents#METRIC_CHANGED
+ */
+ this.METRIC_CHANGED = 'metricchanged';
+ /**
+ * Triggered every time a new metric is added.
+ * @event MediaPlayerEvents#METRIC_ADDED
+ */
+ this.METRIC_ADDED = 'metricadded';
+ /**
+ * Triggered every time a metric is updated.
+ * @event MediaPlayerEvents#METRIC_UPDATED
+ */
+ this.METRIC_UPDATED = 'metricupdated';
+ /**
+ * Triggered at the stream end of a period.
+ * @event MediaPlayerEvents#PERIOD_SWITCH_COMPLETED
+ */
+ this.PERIOD_SWITCH_COMPLETED = 'streamswitchcompleted';
+ /**
+ * Triggered when a new period starts.
+ * @event MediaPlayerEvents#PERIOD_SWITCH_STARTED
+ */
+ this.PERIOD_SWITCH_STARTED = 'streamswitchstarted';
+
+ /**
+ * Triggered when an ABR up /down switch is initialed; either by user in manual mode or auto mode via ABR rules.
+ * @event MediaPlayerEvents#QUALITY_CHANGE_REQUESTED
+ */
+ this.QUALITY_CHANGE_REQUESTED = 'qualityChangeRequested';
+
+ /**
+ * Triggered when the new ABR quality is being rendered on-screen.
+ * @event MediaPlayerEvents#QUALITY_CHANGE_RENDERED
+ */
+ this.QUALITY_CHANGE_RENDERED = 'qualityChangeRendered';
+
+ /**
+ * Triggered when the stream is setup and ready.
+ * @event MediaPlayerEvents#STREAM_INITIALIZED
+ */
+ this.STREAM_INITIALIZED = 'streaminitialized';
+ /**
+ * Triggered once all text tracks detected in the MPD are added to the video element.
+ * @event MediaPlayerEvents#TEXT_TRACKS_ADDED
+ */
+ this.TEXT_TRACKS_ADDED = 'alltexttracksadded';
+ /**
+ * Triggered when a text track is added to the video element's TextTrackList
+ * @event MediaPlayerEvents#TEXT_TRACK_ADDED
+ */
+ this.TEXT_TRACK_ADDED = 'texttrackadded';
+
+ /**
+ * Sent when enough data is available that the media can be played,
+ * at least for a couple of frames. This corresponds to the
+ * HAVE_ENOUGH_DATA readyState.
+ * @event MediaPlayerEvents#CAN_PLAY
+ */
+ this.CAN_PLAY = 'canPlay';
+
+ /**
+ * Sent when playback completes.
+ * @event MediaPlayerEvents#PLAYBACK_ENDED
+ */
+ this.PLAYBACK_ENDED = 'playbackEnded';
+
+ /**
+ * Sent when an error occurs. The element's error
+ * attribute contains more information.
+ * @event MediaPlayerEvents#PLAYBACK_ERROR
+ */
+ this.PLAYBACK_ERROR = 'playbackError';
+ /**
+ * Sent when playback is not allowed (for example if user gesture is needed).
+ * @event MediaPlayerEvents#PLAYBACK_NOT_ALLOWED
+ */
+ this.PLAYBACK_NOT_ALLOWED = 'playbackNotAllowed';
+ /**
+ * The media's metadata has finished loading; all attributes now
+ * contain as much useful information as they're going to.
+ * @event MediaPlayerEvents#PLAYBACK_METADATA_LOADED
+ */
+ this.PLAYBACK_METADATA_LOADED = 'playbackMetaDataLoaded';
+ /**
+ * Sent when playback is paused.
+ * @event MediaPlayerEvents#PLAYBACK_PAUSED
+ */
+ this.PLAYBACK_PAUSED = 'playbackPaused';
+ /**
+ * Sent when the media begins to play (either for the first time, after having been paused,
+ * or after ending and then restarting).
+ *
+ * @event MediaPlayerEvents#PLAYBACK_PLAYING
+ */
+ this.PLAYBACK_PLAYING = 'playbackPlaying';
+ /**
+ * Sent periodically to inform interested parties of progress downloading
+ * the media. Information about the current amount of the media that has
+ * been downloaded is available in the media element's buffered attribute.
+ * @event MediaPlayerEvents#PLAYBACK_PROGRESS
+ */
+ this.PLAYBACK_PROGRESS = 'playbackProgress';
+ /**
+ * Sent when the playback speed changes.
+ * @event MediaPlayerEvents#PLAYBACK_RATE_CHANGED
+ */
+ this.PLAYBACK_RATE_CHANGED = 'playbackRateChanged';
+ /**
+ * Sent when a seek operation completes.
+ * @event MediaPlayerEvents#PLAYBACK_SEEKED
+ */
+ this.PLAYBACK_SEEKED = 'playbackSeeked';
+ /**
+ * Sent when a seek operation begins.
+ * @event MediaPlayerEvents#PLAYBACK_SEEKING
+ */
+ this.PLAYBACK_SEEKING = 'playbackSeeking';
+ /**
+ * Sent when playback of the media starts after having been paused;
+ * that is, when playback is resumed after a prior pause event.
+ *
+ * @event MediaPlayerEvents#PLAYBACK_STARTED
+ */
+ this.PLAYBACK_STARTED = 'playbackStarted';
+ /**
+ * The time indicated by the element's currentTime attribute has changed.
+ * @event MediaPlayerEvents#PLAYBACK_TIME_UPDATED
+ */
+ this.PLAYBACK_TIME_UPDATED = 'playbackTimeUpdated';
+ }
+
+ return MediaPlayerEvents;
+})(_coreEventsEventsBase2['default']);
+
+var mediaPlayerEvents = new MediaPlayerEvents();
+exports['default'] = mediaPlayerEvents;
+module.exports = exports['default'];
+
+},{"14":14}],53:[function(_dereq_,module,exports){
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _MediaPlayer = _dereq_(51);
+
+var _MediaPlayer2 = _interopRequireDefault(_MediaPlayer);
+
+function MediaPlayerFactory() {
+
+ /**
+ * mime-type identifier for any source content to be accepted as a dash manifest by the create() method.
+ * @type {string}
+ */
+ var SUPPORTED_MIME_TYPE = 'application/dash+xml';
+
+ /**
+ * A new MediaPlayer is instantiated for the supplied videoElement and optional source and context. If no context is provided,
+ * a default DashContext is used. If no source is provided, the videoElement is interrogated to extract the first source whose
+ * type is application/dash+xml.
+ * The autoplay property of the videoElement is preserved. Any preload attribute is ignored. This method should be called after the page onLoad event is dispatched.
+ * @param {HTMLMediaElement} video
+ * @param {HTMLSourceElement} source
+ * @param {Object} context
+ * @returns {MediaPlayer|null}
+ */
+ function create(video, source, context) {
+ if (!video || video.nodeName !== 'VIDEO') return null;
+
+ if (video._dashjs_player) return video._dashjs_player;
+
+ var player;
+ var videoID = video.id || video.name || 'video element';
+
+ source = source || [].slice.call(video.querySelectorAll('source')).filter(function (s) {
+ return s.type == SUPPORTED_MIME_TYPE;
+ })[0];
+ if (!source && video.src) {
+ source = document.createElement('source');
+ source.src = video.src;
+ } else if (!source && !video.src) {
+ return null;
+ }
+
+ context = context || {};
+ player = (0, _MediaPlayer2['default'])(context).create();
+ player.initialize(video, source.src, video.autoplay);
+ player.getDebug().log('Converted ' + videoID + ' to dash.js player and added content: ' + source.src);
+
+ // Store a reference to the player on the video element so it can be gotten at for debugging and so we know its
+ // already been setup.
+ video._dashjs_player = player;
+
+ return player;
+ }
+
+ /**
+ * Searches the provided scope for all instances of the indicated selector. If no scope is provided, document is used. If no selector is
+ * specified, [data-dashjs-player] is used. The declarative setup also looks for source elements with the type attribute set to 'application/dash+xml'.
+ * It then looks for those video elements which have a source element defined with a type matching 'application/dash+xml'.
+ * A new MediaPlayer is instantiated for each matching video element and the appropriate source is assigned.
+ * The autoplay property of the video element is preserved. Any preload attribute is ignored. This method should be called after the page onLoad event is dispatched.
+ * Returns an array holding all the MediaPlayer instances that were added by this method.
+ * @param {string} selector - CSS selector
+ * @param {Object} scope
+ * @returns {Array} an array of MediaPlayer objects
+ */
+ function createAll(selector, scope) {
+ var aPlayers = [];
+ selector = selector || '[data-dashjs-player]';
+ scope = scope || document;
+ var videos = scope.querySelectorAll(selector);
+ for (var i = 0; i < videos.length; i++) {
+ var player = create(videos[i], null);
+ aPlayers.push(player);
+ }
+
+ var sources = scope.querySelectorAll('source[type="' + SUPPORTED_MIME_TYPE + '"]');
+ for (var i = 0; i < sources.length; i++) {
+ var video = findVideo(sources[i]);
+ var player = create(video, null);
+ aPlayers.push(player);
+ }
+
+ return aPlayers;
+ }
+
+ function findVideo(_x) {
+ var _again = true;
+
+ _function: while (_again) {
+ var el = _x;
+ _again = false;
+
+ if (el.nodeName.toLowerCase() === 'video') {
+ return el;
+ } else {
+ _x = el.parentNode;
+ _again = true;
+ continue _function;
+ }
+ }
+ }
+
+ return {
+ create: create,
+ createAll: createAll
+ };
+}
+
+var instance = MediaPlayerFactory();
+
+function loadHandler() {
+ window.removeEventListener('load', loadHandler);
+ instance.createAll();
+}
+
+var avoidAutoCreate = window && window.dashjs && window.dashjs.skipAutoCreate;
+
+if (!avoidAutoCreate && window && window.addEventListener) {
+ if (window.document.readyState === 'complete') {
+ instance.createAll();
+ } else {
+ window.addEventListener('load', loadHandler);
+ }
+}
+
+exports['default'] = instance;
+module.exports = exports['default'];
+
+},{"51":51}],54:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _utilsLiveEdgeFinder = _dereq_(154);
+
+var _utilsLiveEdgeFinder2 = _interopRequireDefault(_utilsLiveEdgeFinder);
+
+var _StreamProcessor = _dereq_(55);
+
+var _StreamProcessor2 = _interopRequireDefault(_StreamProcessor);
+
+var _controllersMediaController = _dereq_(66);
+
+var _controllersMediaController2 = _interopRequireDefault(_controllersMediaController);
+
+var _controllersEventController = _dereq_(64);
+
+var _controllersEventController2 = _interopRequireDefault(_controllersEventController);
+
+var _controllersFragmentController = _dereq_(65);
+
+var _controllersFragmentController2 = _interopRequireDefault(_controllersFragmentController);
+
+var _controllersAbrController = _dereq_(60);
+
+var _controllersAbrController2 = _interopRequireDefault(_controllersAbrController);
+
+var _modelsVideoModel = _dereq_(104);
+
+var _modelsVideoModel2 = _interopRequireDefault(_modelsVideoModel);
+
+var _modelsMetricsModel = _dereq_(102);
+
+var _modelsMetricsModel2 = _interopRequireDefault(_modelsMetricsModel);
+
+var _controllersPlaybackController = _dereq_(68);
+
+var _controllersPlaybackController2 = _interopRequireDefault(_controllersPlaybackController);
+
+var _dashDashHandler = _dereq_(16);
+
+var _dashDashHandler2 = _interopRequireDefault(_dashDashHandler);
+
+var _dashSegmentBaseLoader = _dereq_(18);
+
+var _dashSegmentBaseLoader2 = _interopRequireDefault(_dashSegmentBaseLoader);
+
+var _dashWebmSegmentBaseLoader = _dereq_(19);
+
+var _dashWebmSegmentBaseLoader2 = _interopRequireDefault(_dashWebmSegmentBaseLoader);
+
+var _dashDashMetrics = _dereq_(17);
+
+var _dashDashMetrics2 = _interopRequireDefault(_dashDashMetrics);
+
+var _coreEventBus = _dereq_(9);
+
+var _coreEventBus2 = _interopRequireDefault(_coreEventBus);
+
+var _coreEventsEvents = _dereq_(13);
+
+var _coreEventsEvents2 = _interopRequireDefault(_coreEventsEvents);
+
+var _coreDebug = _dereq_(8);
+
+var _coreDebug2 = _interopRequireDefault(_coreDebug);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _TextSourceBuffer = _dereq_(56);
+
+var _TextSourceBuffer2 = _interopRequireDefault(_TextSourceBuffer);
+
+function Stream(config) {
+
+ var DATA_UPDATE_FAILED_ERROR_CODE = 1;
+
+ var context = this.context;
+ var log = (0, _coreDebug2['default'])(context).getInstance().log;
+ var eventBus = (0, _coreEventBus2['default'])(context).getInstance();
+
+ var manifestModel = config.manifestModel;
+ var manifestUpdater = config.manifestUpdater;
+ var adapter = config.adapter;
+ var capabilities = config.capabilities;
+ var errHandler = config.errHandler;
+ var timelineConverter = config.timelineConverter;
+ var baseURLController = config.baseURLController;
+
+ var instance = undefined,
+ streamProcessors = undefined,
+ isStreamActivated = undefined,
+ isMediaInitialized = undefined,
+ streamInfo = undefined,
+ updateError = undefined,
+ isUpdating = undefined,
+ initialized = undefined,
+ protectionController = undefined,
+ liveEdgeFinder = undefined,
+ playbackController = undefined,
+ mediaController = undefined,
+ fragmentController = undefined,
+ eventController = undefined,
+ abrController = undefined,
+ textSourceBuffer = undefined;
+
+ function setup() {
+ streamProcessors = [];
+ isStreamActivated = false;
+ isMediaInitialized = false;
+ streamInfo = null;
+ updateError = {};
+ isUpdating = false;
+ initialized = false;
+
+ liveEdgeFinder = (0, _utilsLiveEdgeFinder2['default'])(context).getInstance();
+ playbackController = (0, _controllersPlaybackController2['default'])(context).getInstance();
+ abrController = (0, _controllersAbrController2['default'])(context).getInstance();
+ mediaController = (0, _controllersMediaController2['default'])(context).getInstance();
+ fragmentController = (0, _controllersFragmentController2['default'])(context).create();
+ textSourceBuffer = (0, _TextSourceBuffer2['default'])(context).getInstance();
+
+ eventBus.on(_coreEventsEvents2['default'].BUFFERING_COMPLETED, onBufferingCompleted, instance);
+ eventBus.on(_coreEventsEvents2['default'].DATA_UPDATE_COMPLETED, onDataUpdateCompleted, instance);
+ }
+
+ function initialize(StreamInfo, ProtectionController) {
+ streamInfo = StreamInfo;
+ protectionController = ProtectionController;
+ if (protectionController) {
+ eventBus.on(_coreEventsEvents2['default'].KEY_ERROR, onProtectionError, instance);
+ eventBus.on(_coreEventsEvents2['default'].SERVER_CERTIFICATE_UPDATED, onProtectionError, instance);
+ eventBus.on(_coreEventsEvents2['default'].LICENSE_REQUEST_COMPLETE, onProtectionError, instance);
+ eventBus.on(_coreEventsEvents2['default'].KEY_SYSTEM_SELECTED, onProtectionError, instance);
+ eventBus.on(_coreEventsEvents2['default'].KEY_SESSION_CREATED, onProtectionError, instance);
+ }
+ }
+
+ /**
+ * Activates Stream by re-initializing some of its components
+ * @param {MediaSource} mediaSource
+ * @memberof Stream#
+ */
+ function activate(mediaSource) {
+ if (!isStreamActivated) {
+ eventBus.on(_coreEventsEvents2['default'].CURRENT_TRACK_CHANGED, onCurrentTrackChanged, instance);
+ initializeMedia(mediaSource);
+ } else {
+ createBuffers();
+ }
+ }
+
+ /**
+ * Partially resets some of the Stream elements
+ * @memberof Stream#
+ */
+ function deactivate() {
+ var ln = streamProcessors.length;
+ for (var i = 0; i < ln; i++) {
+ streamProcessors[i].reset();
+ }
+ streamProcessors = [];
+ isStreamActivated = false;
+ isMediaInitialized = false;
+ clearEventController();
+ eventBus.off(_coreEventsEvents2['default'].CURRENT_TRACK_CHANGED, onCurrentTrackChanged, instance);
+ }
+
+ function reset() {
+
+ if (playbackController) {
+ playbackController.pause();
+ playbackController = null;
+ }
+
+ if (fragmentController) {
+ fragmentController.reset();
+ fragmentController = null;
+ }
+
+ liveEdgeFinder.abortSearch();
+ deactivate();
+
+ mediaController = null;
+ abrController = null;
+ manifestUpdater = null;
+ manifestModel = null;
+ adapter = null;
+ capabilities = null;
+ log = null;
+ errHandler = null;
+ isUpdating = false;
+ initialized = false;
+ updateError = {};
+
+ eventBus.off(_coreEventsEvents2['default'].DATA_UPDATE_COMPLETED, onDataUpdateCompleted, instance);
+ eventBus.off(_coreEventsEvents2['default'].BUFFERING_COMPLETED, onBufferingCompleted, instance);
+ eventBus.off(_coreEventsEvents2['default'].KEY_ERROR, onProtectionError, instance);
+ eventBus.off(_coreEventsEvents2['default'].SERVER_CERTIFICATE_UPDATED, onProtectionError, instance);
+ eventBus.off(_coreEventsEvents2['default'].LICENSE_REQUEST_COMPLETE, onProtectionError, instance);
+ eventBus.off(_coreEventsEvents2['default'].KEY_SYSTEM_SELECTED, onProtectionError, instance);
+ eventBus.off(_coreEventsEvents2['default'].KEY_SESSION_CREATED, onProtectionError, instance);
+ }
+
+ function getDuration() {
+ return streamInfo.duration;
+ }
+
+ function getStartTime() {
+ return streamInfo.start;
+ }
+
+ function getStreamIndex() {
+ return streamInfo.index;
+ }
+
+ function getId() {
+ return streamInfo.id;
+ }
+
+ function getStreamInfo() {
+ return streamInfo;
+ }
+
+ function hasMedia(type) {
+ return getMediaInfo(type) !== null;
+ }
+
+ /**
+ * @param {string} type
+ * @returns {Array}
+ * @memberof Stream#
+ */
+ function getBitrateListFor(type) {
+ var mediaInfo = getMediaInfo(type);
+ return abrController.getBitrateList(mediaInfo);
+ }
+
+ function startEventController() {
+ if (eventController) {
+ eventController.start();
+ }
+ }
+
+ function clearEventController() {
+ if (eventController) {
+ eventController.clear();
+ }
+ }
+
+ function isActivated() {
+ return isStreamActivated;
+ }
+
+ function isInitialized() {
+ return initialized;
+ }
+
+ function onProtectionError(event) {
+ if (event.error) {
+ errHandler.mediaKeySessionError(event.error);
+ log(event.error);
+ reset();
+ }
+ }
+
+ function getMimeTypeOrType(mediaInfo) {
+ return mediaInfo.type === 'text' ? mediaInfo.mimeType : mediaInfo.type;
+ }
+
+ function isMediaSupported(mediaInfo, mediaSource, manifest) {
+ var type = mediaInfo.type;
+ var codec, msg;
+
+ if (type === 'muxed' && mediaInfo) {
+ msg = 'Multiplexed representations are intentionally not supported, as they are not compliant with the DASH-AVC/264 guidelines';
+ log(msg);
+ errHandler.manifestError(msg, 'multiplexedrep', manifestModel.getValue());
+ return false;
+ }
+
+ if (type === 'text' || type === 'fragmentedText' || type === 'embeddedText') return true;
+
+ codec = mediaInfo.codec;
+ log(type + ' codec: ' + codec);
+
+ if (!!mediaInfo.contentProtection && !capabilities.supportsEncryptedMedia()) {
+ errHandler.capabilityError('encryptedmedia');
+ } else if (!capabilities.supportsCodec((0, _modelsVideoModel2['default'])(context).getInstance().getElement(), codec)) {
+ msg = type + 'Codec (' + codec + ') is not supported.';
+ errHandler.manifestError(msg, 'codec', manifest);
+ log(msg);
+ return false;
+ }
+
+ return true;
+ }
+
+ function onCurrentTrackChanged(e) {
+ if (e.newMediaInfo.streamInfo.id !== streamInfo.id) return;
+
+ var processor = getProcessorForMediaInfo(e.oldMediaInfo);
+ if (!processor) return;
+
+ var currentTime = playbackController.getTime();
+ var buffer = processor.getBuffer();
+ var mediaInfo = e.newMediaInfo;
+ var manifest = manifestModel.getValue();
+ var idx = streamProcessors.indexOf(processor);
+ var mediaSource = processor.getMediaSource();
+
+ if (mediaInfo.type !== 'fragmentedText') {
+ processor.reset(true);
+ createStreamProcessor(mediaInfo, manifest, mediaSource, { buffer: buffer, replaceIdx: idx, currentTime: currentTime });
+ playbackController.seek(playbackController.getTime());
+ } else {
+ processor.updateMediaInfo(manifest, mediaInfo);
+ }
+ }
+
+ function isWebM(mimeType) {
+ var type = mimeType.split('/')[1];
+
+ return 'webm' === type.toLowerCase();
+ }
+
+ function createIndexHandler(mediaInfo) {
+
+ var segmentBaseLoader = isWebM(mediaInfo.mimeType) ? (0, _dashWebmSegmentBaseLoader2['default'])(context).getInstance() : (0, _dashSegmentBaseLoader2['default'])(context).getInstance();
+ segmentBaseLoader.setConfig({
+ baseURLController: baseURLController,
+ metricsModel: (0, _modelsMetricsModel2['default'])(context).getInstance()
+ });
+ segmentBaseLoader.initialize();
+
+ var handler = (0, _dashDashHandler2['default'])(context).create({
+ segmentBaseLoader: segmentBaseLoader,
+ timelineConverter: timelineConverter,
+ dashMetrics: (0, _dashDashMetrics2['default'])(context).getInstance(),
+ metricsModel: (0, _modelsMetricsModel2['default'])(context).getInstance(),
+ baseURLController: baseURLController
+ });
+
+ return handler;
+ }
+
+ function createStreamProcessor(mediaInfo, manifest, mediaSource, optionalSettings) {
+ var streamProcessor = (0, _StreamProcessor2['default'])(context).create({
+ indexHandler: createIndexHandler(mediaInfo),
+ timelineConverter: timelineConverter,
+ adapter: adapter,
+ manifestModel: manifestModel
+ });
+
+ var allMediaForType = adapter.getAllMediaInfoForType(manifest, streamInfo, mediaInfo.type);
+ streamProcessor.initialize(getMimeTypeOrType(mediaInfo), fragmentController, mediaSource, instance, eventController);
+ abrController.updateTopQualityIndex(mediaInfo);
+
+ if (optionalSettings) {
+ streamProcessor.setBuffer(optionalSettings.buffer);
+ streamProcessor.getIndexHandler().setCurrentTime(optionalSettings.currentTime);
+ streamProcessors[optionalSettings.replaceIdx] = streamProcessor;
+ } else {
+ streamProcessors.push(streamProcessor);
+ }
+
+ if (mediaInfo.type === 'text' || mediaInfo.type === 'fragmentedText') {
+ var idx;
+ for (var i = 0; i < allMediaForType.length; i++) {
+ if (allMediaForType[i].index === mediaInfo.index) {
+ idx = i;
+ }
+ streamProcessor.updateMediaInfo(manifest, allMediaForType[i]); //creates text tracks for all adaptations in one stream processor
+ }
+ if (mediaInfo.type === 'fragmentedText') {
+ streamProcessor.updateMediaInfo(manifest, allMediaForType[idx]); //sets the initial media info
+ }
+ } else {
+ streamProcessor.updateMediaInfo(manifest, mediaInfo);
+ }
+
+ return streamProcessor;
+ }
+
+ function initializeMediaForType(type, mediaSource) {
+ var manifest = manifestModel.getValue();
+ var allMediaForType = adapter.getAllMediaInfoForType(manifest, streamInfo, type);
+
+ var mediaInfo = null;
+ var initialMediaInfo;
+
+ if (!allMediaForType || allMediaForType.length === 0) {
+ log('No ' + type + ' data.');
+ return;
+ }
+
+ for (var i = 0, ln = allMediaForType.length; i < ln; i++) {
+ mediaInfo = allMediaForType[i];
+
+ if (type === 'embeddedText') {
+ textSourceBuffer.addEmbeddedTrack(mediaInfo);
+ } else {
+ if (!isMediaSupported(mediaInfo, mediaSource, manifest)) continue;
+
+ if (mediaController.isMultiTrackSupportedByType(mediaInfo.type)) {
+ mediaController.addTrack(mediaInfo, streamInfo);
+ }
+ }
+ }
+
+ if (type === 'embeddedText' || mediaController.getTracksFor(type, streamInfo).length === 0) {
+ return;
+ }
+
+ mediaController.checkInitialMediaSettingsForType(type, streamInfo);
+ initialMediaInfo = mediaController.getCurrentTrackFor(type, streamInfo);
+
+ // TODO : How to tell index handler live/duration?
+ // TODO : Pass to controller and then pass to each method on handler?
+
+ createStreamProcessor(initialMediaInfo, manifest, mediaSource);
+ }
+
+ function initializeMedia(mediaSource) {
+ var manifest = manifestModel.getValue();
+ var events;
+
+ eventController = (0, _controllersEventController2['default'])(context).getInstance();
+ eventController.initialize();
+ eventController.setConfig({
+ manifestModel: manifestModel,
+ manifestUpdater: manifestUpdater
+ });
+ events = adapter.getEventsFor(manifest, streamInfo);
+ eventController.addInlineEvents(events);
+
+ isUpdating = true;
+ initializeMediaForType('video', mediaSource);
+ initializeMediaForType('audio', mediaSource);
+ initializeMediaForType('text', mediaSource);
+ initializeMediaForType('fragmentedText', mediaSource);
+ initializeMediaForType('embeddedText', mediaSource);
+ initializeMediaForType('muxed', mediaSource);
+
+ createBuffers();
+
+ //TODO. Consider initialization of TextSourceBuffer here if embeddedText, but no sideloadedText.
+
+ isMediaInitialized = true;
+ isUpdating = false;
+
+ if (streamProcessors.length === 0) {
+ var msg = 'No streams to play.';
+ errHandler.manifestError(msg, 'nostreams', manifest);
+ log(msg);
+ } else {
+ liveEdgeFinder.initialize(timelineConverter, streamProcessors[0]);
+ //log("Playback initialized!");
+ checkIfInitializationCompleted();
+ }
+ }
+
+ function checkIfInitializationCompleted() {
+ var ln = streamProcessors.length;
+ var hasError = !!updateError.audio || !!updateError.video;
+ var error = hasError ? new Error(DATA_UPDATE_FAILED_ERROR_CODE, 'Data update failed', null) : null;
+ var i = 0;
+
+ for (i; i < ln; i++) {
+ if (streamProcessors[i].isUpdating() || isUpdating) return;
+ }
+
+ initialized = true;
+ isStreamActivated = true;
+ if (!isMediaInitialized) return;
+ if (protectionController) {
+ protectionController.initialize(manifestModel.getValue(), getMediaInfo('audio'), getMediaInfo('video'));
+ }
+ eventBus.trigger(_coreEventsEvents2['default'].STREAM_INITIALIZED, { streamInfo: streamInfo, error: error });
+ }
+
+ function getMediaInfo(type) {
+ var ln = streamProcessors.length;
+ var mediaCtrl = null;
+
+ for (var i = 0; i < ln; i++) {
+ mediaCtrl = streamProcessors[i];
+
+ if (mediaCtrl.getType() === type) return mediaCtrl.getMediaInfo();
+ }
+
+ return null;
+ }
+
+ function createBuffers() {
+ for (var i = 0, ln = streamProcessors.length; i < ln; i++) {
+ streamProcessors[i].createBuffer();
+ }
+ }
+
+ function onBufferingCompleted(e) {
+ if (e.streamInfo !== streamInfo) return;
+
+ var processors = getProcessors();
+ var ln = processors.length;
+ var i = 0;
+
+ // if there is at least one buffer controller that has not completed buffering yet do nothing
+ for (i; i < ln; i++) {
+ if (!processors[i].isBufferingCompleted()) return;
+ }
+
+ eventBus.trigger(_coreEventsEvents2['default'].STREAM_BUFFERING_COMPLETED, { streamInfo: streamInfo });
+ }
+
+ function onDataUpdateCompleted(e) {
+ var sp = e.sender.getStreamProcessor();
+
+ if (sp.getStreamInfo() !== streamInfo) return;
+
+ updateError[sp.getType()] = e.error;
+ checkIfInitializationCompleted();
+ }
+
+ function getProcessorForMediaInfo(mediaInfo) {
+ if (!mediaInfo) return false;
+
+ var processors = getProcessors();
+
+ return processors.filter(function (processor) {
+ return processor.getType() === mediaInfo.type;
+ })[0];
+ }
+
+ function getProcessors() {
+ var ln = streamProcessors.length;
+ var arr = [];
+ var i = 0;
+
+ var type, controller;
+
+ for (i; i < ln; i++) {
+ controller = streamProcessors[i];
+ type = controller.getType();
+
+ if (type === 'audio' || type === 'video' || type === 'fragmentedText') {
+ arr.push(controller);
+ }
+ }
+
+ return arr;
+ }
+
+ function updateData(updatedStreamInfo) {
+
+ log('Manifest updated... updating data system wide.');
+
+ var manifest = manifestModel.getValue();
+
+ isStreamActivated = false;
+ isUpdating = true;
+ initialized = false;
+ streamInfo = updatedStreamInfo;
+
+ if (eventController) {
+ var events = adapter.getEventsFor(manifest, streamInfo);
+ eventController.addInlineEvents(events);
+ }
+
+ for (var i = 0, ln = streamProcessors.length; i < ln; i++) {
+ var streamProcessor = streamProcessors[i];
+ var mediaInfo = adapter.getMediaInfoForType(manifest, streamInfo, streamProcessor.getType());
+ abrController.updateTopQualityIndex(mediaInfo);
+ streamProcessor.updateMediaInfo(manifest, mediaInfo);
+ }
+
+ isUpdating = false;
+ checkIfInitializationCompleted();
+ }
+
+ instance = {
+ initialize: initialize,
+ activate: activate,
+ deactivate: deactivate,
+ getDuration: getDuration,
+ getStartTime: getStartTime,
+ getStreamIndex: getStreamIndex,
+ getId: getId,
+ getStreamInfo: getStreamInfo,
+ hasMedia: hasMedia,
+ getBitrateListFor: getBitrateListFor,
+ startEventController: startEventController,
+ isActivated: isActivated,
+ isInitialized: isInitialized,
+ updateData: updateData,
+ reset: reset,
+ getProcessors: getProcessors
+ };
+
+ setup();
+ return instance;
+}
+
+Stream.__dashjs_factory_name = 'Stream';
+exports['default'] = _coreFactoryMaker2['default'].getClassFactory(Stream);
+module.exports = exports['default'];
+
+},{"10":10,"102":102,"104":104,"13":13,"154":154,"16":16,"17":17,"18":18,"19":19,"55":55,"56":56,"60":60,"64":64,"65":65,"66":66,"68":68,"8":8,"9":9}],55:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _controllersAbrController = _dereq_(60);
+
+var _controllersAbrController2 = _interopRequireDefault(_controllersAbrController);
+
+var _controllersBufferController = _dereq_(63);
+
+var _controllersBufferController2 = _interopRequireDefault(_controllersBufferController);
+
+var _controllersStreamController = _dereq_(71);
+
+var _controllersStreamController2 = _interopRequireDefault(_controllersStreamController);
+
+var _controllersMediaController = _dereq_(66);
+
+var _controllersMediaController2 = _interopRequireDefault(_controllersMediaController);
+
+var _controllersTextController = _dereq_(72);
+
+var _controllersTextController2 = _interopRequireDefault(_controllersTextController);
+
+var _controllersScheduleController = _dereq_(69);
+
+var _controllersScheduleController2 = _interopRequireDefault(_controllersScheduleController);
+
+var _rulesRulesController = _dereq_(129);
+
+var _rulesRulesController2 = _interopRequireDefault(_rulesRulesController);
+
+var _modelsMediaPlayerModel = _dereq_(101);
+
+var _modelsMediaPlayerModel2 = _interopRequireDefault(_modelsMediaPlayerModel);
+
+var _modelsMetricsModel = _dereq_(102);
+
+var _modelsMetricsModel2 = _interopRequireDefault(_modelsMetricsModel);
+
+var _FragmentLoader = _dereq_(48);
+
+var _FragmentLoader2 = _interopRequireDefault(_FragmentLoader);
+
+var _utilsRequestModifier = _dereq_(156);
+
+var _utilsRequestModifier2 = _interopRequireDefault(_utilsRequestModifier);
+
+var _controllersSourceBufferController = _dereq_(70);
+
+var _controllersSourceBufferController2 = _interopRequireDefault(_controllersSourceBufferController);
+
+var _TextSourceBuffer = _dereq_(56);
+
+var _TextSourceBuffer2 = _interopRequireDefault(_TextSourceBuffer);
+
+var _dashModelsDashManifestModel = _dereq_(22);
+
+var _dashModelsDashManifestModel2 = _interopRequireDefault(_dashModelsDashManifestModel);
+
+var _dashDashMetrics = _dereq_(17);
+
+var _dashDashMetrics2 = _interopRequireDefault(_dashDashMetrics);
+
+var _dashControllersRepresentationController = _dereq_(21);
+
+var _dashControllersRepresentationController2 = _interopRequireDefault(_dashControllersRepresentationController);
+
+var _utilsErrorHandler = _dereq_(151);
+
+var _utilsErrorHandler2 = _interopRequireDefault(_utilsErrorHandler);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+function StreamProcessor(config) {
+
+ var context = this.context;
+
+ var indexHandler = config.indexHandler;
+ var timelineConverter = config.timelineConverter;
+ var adapter = config.adapter;
+ var manifestModel = config.manifestModel;
+
+ var instance = undefined,
+ dynamic = undefined,
+ mediaInfo = undefined,
+ type = undefined,
+ mediaInfoArr = undefined,
+ stream = undefined,
+ eventController = undefined,
+ abrController = undefined,
+ bufferController = undefined,
+ scheduleController = undefined,
+ representationController = undefined,
+ fragmentController = undefined,
+ fragmentLoader = undefined,
+ fragmentModel = undefined;
+
+ function setup() {
+ mediaInfoArr = [];
+ }
+
+ function initialize(Type, FragmentController, mediaSource, Stream, EventController) {
+
+ type = Type;
+ stream = Stream;
+ eventController = EventController;
+ fragmentController = FragmentController;
+ dynamic = stream.getStreamInfo().manifestInfo.isDynamic;
+
+ indexHandler.initialize(this);
+
+ abrController = (0, _controllersAbrController2['default'])(context).getInstance();
+ abrController.initialize(type, this);
+
+ bufferController = createBufferControllerForType(Type);
+ scheduleController = (0, _controllersScheduleController2['default'])(context).create({
+ metricsModel: (0, _modelsMetricsModel2['default'])(context).getInstance(),
+ manifestModel: manifestModel,
+ adapter: adapter,
+ dashMetrics: (0, _dashDashMetrics2['default'])(context).getInstance(),
+ dashManifestModel: (0, _dashModelsDashManifestModel2['default'])(context).getInstance(),
+ timelineConverter: timelineConverter,
+ rulesController: (0, _rulesRulesController2['default'])(context).getInstance(),
+ mediaPlayerModel: (0, _modelsMediaPlayerModel2['default'])(context).getInstance()
+ });
+
+ bufferController.initialize(type, mediaSource, this);
+ scheduleController.initialize(type, this);
+
+ fragmentLoader = (0, _FragmentLoader2['default'])(context).create({
+ metricsModel: (0, _modelsMetricsModel2['default'])(context).getInstance(),
+ errHandler: (0, _utilsErrorHandler2['default'])(context).getInstance(),
+ requestModifier: (0, _utilsRequestModifier2['default'])(context).getInstance()
+ });
+
+ fragmentModel = scheduleController.getFragmentModel();
+ fragmentModel.setLoader(fragmentLoader);
+
+ representationController = (0, _dashControllersRepresentationController2['default'])(context).create();
+ representationController.initialize(this);
+ }
+
+ function reset(errored) {
+
+ indexHandler.reset();
+
+ if (bufferController) {
+ bufferController.reset(errored);
+ bufferController = null;
+ }
+
+ if (scheduleController) {
+ scheduleController.reset();
+ scheduleController = null;
+ }
+
+ if (representationController) {
+ representationController.reset();
+ representationController = null;
+ }
+
+ fragmentController = null;
+ fragmentLoader = null;
+
+ eventController = null;
+ stream = null;
+ dynamic = null;
+ mediaInfo = null;
+ mediaInfoArr = [];
+ type = null;
+ }
+
+ function isUpdating() {
+ return representationController.isUpdating();
+ }
+
+ function getType() {
+ return type;
+ }
+
+ function getABRController() {
+ return abrController;
+ }
+
+ function getRepresentationController() {
+ return representationController;
+ }
+
+ function getFragmentLoader() {
+ return fragmentLoader;
+ }
+
+ function getIndexHandler() {
+ return indexHandler;
+ }
+
+ function getFragmentController() {
+ return fragmentController;
+ }
+
+ function getBuffer() {
+ return bufferController.getBuffer();
+ }
+
+ function setBuffer(buffer) {
+ bufferController.setBuffer(buffer);
+ }
+
+ function getBufferController() {
+ return bufferController;
+ }
+
+ function getFragmentModel() {
+ return fragmentModel;
+ }
+
+ function getStreamInfo() {
+ return stream.getStreamInfo();
+ }
+
+ function updateMediaInfo(manifest, newMediaInfo) {
+ if (newMediaInfo !== mediaInfo && (!newMediaInfo || !mediaInfo || newMediaInfo.type === mediaInfo.type)) {
+ mediaInfo = newMediaInfo;
+ }
+ if (mediaInfoArr.indexOf(newMediaInfo) === -1) {
+ mediaInfoArr.push(newMediaInfo);
+ }
+ adapter.updateData(manifest, this);
+ }
+
+ function getMediaInfoArr() {
+ return mediaInfoArr;
+ }
+
+ function getMediaInfo() {
+ return mediaInfo;
+ }
+
+ function getMediaSource() {
+ return bufferController.getMediaSource();
+ }
+
+ function getScheduleController() {
+ return scheduleController;
+ }
+
+ function getEventController() {
+ return eventController;
+ }
+
+ function start() {
+ scheduleController.start();
+ }
+
+ function stop() {
+ scheduleController.stop();
+ }
+
+ function getCurrentRepresentationInfo() {
+ return adapter.getCurrentRepresentationInfo(manifestModel.getValue(), representationController);
+ }
+
+ function getRepresentationInfoForQuality(quality) {
+ return adapter.getRepresentationInfoForQuality(manifestModel.getValue(), representationController, quality);
+ }
+
+ function isBufferingCompleted() {
+ return bufferController.getIsBufferingCompleted();
+ }
+
+ function createBuffer() {
+ return bufferController.getBuffer() || bufferController.createBuffer(mediaInfo);
+ }
+
+ function isDynamic() {
+ return dynamic;
+ }
+
+ function createBufferControllerForType(type) {
+ var controller = null;
+
+ if (type === 'video' || type === 'audio' || type === 'fragmentedText') {
+ controller = (0, _controllersBufferController2['default'])(context).create({
+ metricsModel: (0, _modelsMetricsModel2['default'])(context).getInstance(),
+ manifestModel: manifestModel,
+ sourceBufferController: (0, _controllersSourceBufferController2['default'])(context).getInstance(),
+ errHandler: (0, _utilsErrorHandler2['default'])(context).getInstance(),
+ streamController: (0, _controllersStreamController2['default'])(context).getInstance(),
+ mediaController: (0, _controllersMediaController2['default'])(context).getInstance(),
+ adapter: adapter,
+ textSourceBuffer: (0, _TextSourceBuffer2['default'])(context).getInstance()
+ });
+ } else {
+ controller = (0, _controllersTextController2['default'])(context).create({
+ errHandler: (0, _utilsErrorHandler2['default'])(context).getInstance(),
+ sourceBufferController: (0, _controllersSourceBufferController2['default'])(context).getInstance()
+ });
+ }
+
+ return controller;
+ }
+
+ instance = {
+ initialize: initialize,
+ isUpdating: isUpdating,
+ getType: getType,
+ getBufferController: getBufferController,
+ getABRController: getABRController,
+ getFragmentLoader: getFragmentLoader,
+ getFragmentModel: getFragmentModel,
+ getScheduleController: getScheduleController,
+ getEventController: getEventController,
+ getFragmentController: getFragmentController,
+ getRepresentationController: getRepresentationController,
+ getIndexHandler: getIndexHandler,
+ getCurrentRepresentationInfo: getCurrentRepresentationInfo,
+ getRepresentationInfoForQuality: getRepresentationInfoForQuality,
+ isBufferingCompleted: isBufferingCompleted,
+ createBuffer: createBuffer,
+ getStreamInfo: getStreamInfo,
+ updateMediaInfo: updateMediaInfo,
+ getMediaInfoArr: getMediaInfoArr,
+ getMediaInfo: getMediaInfo,
+ getMediaSource: getMediaSource,
+ getBuffer: getBuffer,
+ setBuffer: setBuffer,
+ start: start,
+ stop: stop,
+ isDynamic: isDynamic,
+ reset: reset
+ };
+
+ setup();
+ return instance;
+}
+StreamProcessor.__dashjs_factory_name = 'StreamProcessor';
+exports['default'] = _coreFactoryMaker2['default'].getClassFactory(StreamProcessor);
+module.exports = exports['default'];
+
+},{"10":10,"101":101,"102":102,"129":129,"151":151,"156":156,"17":17,"21":21,"22":22,"48":48,"56":56,"60":60,"63":63,"66":66,"69":69,"70":70,"71":71,"72":72}],56:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _voTextTrackInfo = _dereq_(171);
+
+var _voTextTrackInfo2 = _interopRequireDefault(_voTextTrackInfo);
+
+var _dashUtilsFragmentedTextBoxParser = _dereq_(32);
+
+var _dashUtilsFragmentedTextBoxParser2 = _interopRequireDefault(_dashUtilsFragmentedTextBoxParser);
+
+var _utilsBoxParser = _dereq_(146);
+
+var _utilsBoxParser2 = _interopRequireDefault(_utilsBoxParser);
+
+var _utilsCustomTimeRanges = _dereq_(148);
+
+var _utilsCustomTimeRanges2 = _interopRequireDefault(_utilsCustomTimeRanges);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _coreDebug = _dereq_(8);
+
+var _coreDebug2 = _interopRequireDefault(_coreDebug);
+
+var _modelsVideoModel = _dereq_(104);
+
+var _modelsVideoModel2 = _interopRequireDefault(_modelsVideoModel);
+
+var _TextTracks = _dereq_(57);
+
+var _TextTracks2 = _interopRequireDefault(_TextTracks);
+
+var _codemIsoboxer = _dereq_(6);
+
+var _codemIsoboxer2 = _interopRequireDefault(_codemIsoboxer);
+
+var _externalsCea608Parser = _dereq_(2);
+
+var _externalsCea608Parser2 = _interopRequireDefault(_externalsCea608Parser);
+
+function TextSourceBuffer() {
+
+ var context = this.context;
+ var log = (0, _coreDebug2['default'])(context).getInstance().log;
+ var embeddedInitialized = false;
+ var captionId = 0;
+
+ var instance = undefined,
+ boxParser = undefined,
+ errHandler = undefined,
+ adapter = undefined,
+ dashManifestModel = undefined,
+ mediaController = undefined,
+ allTracksAreDisabled = undefined,
+ parser = undefined,
+ VTTParser = undefined,
+ TTMLParser = undefined,
+ fragmentedTextBoxParser = undefined,
+ mediaInfos = undefined,
+ textTracks = undefined,
+ isFragmented = undefined,
+ fragmentModel = undefined,
+ initializationSegmentReceived = undefined,
+ timescale = undefined,
+ fragmentedTracks = undefined,
+ videoModel = undefined,
+ streamController = undefined,
+ firstSubtitleStart = undefined,
+ currFragmentedTrackIdx = undefined,
+ embeddedTracks = undefined,
+ embeddedInitializationSegmentReceived = undefined,
+ embeddedTimescale = undefined,
+ embeddedLastSequenceNumber = undefined,
+ embeddedSequenceNumbers = undefined,
+ embeddedCea608FieldParsers = undefined;
+
+ function initialize(type, bufferController) {
+ allTracksAreDisabled = false;
+ parser = null;
+ fragmentModel = null;
+ initializationSegmentReceived = false;
+ timescale = NaN;
+ fragmentedTracks = [];
+ firstSubtitleStart = null;
+
+ if (!embeddedInitialized) {
+ initEmbedded();
+ }
+
+ var streamProcessor = bufferController.getStreamProcessor();
+
+ mediaInfos = streamProcessor.getMediaInfoArr();
+ textTracks.setConfig({ videoModel: videoModel });
+ textTracks.initialize();
+ isFragmented = !dashManifestModel.getIsTextTrack(type);
+ boxParser = (0, _utilsBoxParser2['default'])(context).getInstance();
+ fragmentedTextBoxParser = (0, _dashUtilsFragmentedTextBoxParser2['default'])(context).getInstance();
+ fragmentedTextBoxParser.setConfig({ boxParser: boxParser });
+
+ if (isFragmented) {
+ fragmentModel = streamProcessor.getFragmentModel();
+ this.buffered = (0, _utilsCustomTimeRanges2['default'])(context).create();
+ fragmentedTracks = mediaController.getTracksFor('fragmentedText', streamController.getActiveStreamInfo());
+ var currFragTrack = mediaController.getCurrentTrackFor('fragmentedText', streamController.getActiveStreamInfo());
+ for (var i = 0; i < fragmentedTracks.length; i++) {
+ if (fragmentedTracks[i] === currFragTrack) {
+ currFragmentedTrackIdx = i;
+ break;
+ }
+ }
+ }
+ }
+
+ function initEmbedded() {
+ embeddedTracks = [];
+ mediaInfos = [];
+ videoModel = (0, _modelsVideoModel2['default'])(context).getInstance();
+ textTracks = (0, _TextTracks2['default'])(context).getInstance();
+ textTracks.setConfig({ videoModel: videoModel });
+ textTracks.initialize();
+ boxParser = (0, _utilsBoxParser2['default'])(context).getInstance();
+ fragmentedTextBoxParser = (0, _dashUtilsFragmentedTextBoxParser2['default'])(context).getInstance();
+ fragmentedTextBoxParser.setConfig({ boxParser: boxParser });
+ isFragmented = false;
+ currFragmentedTrackIdx = null;
+ embeddedInitializationSegmentReceived = false;
+ embeddedTimescale = 0;
+ embeddedCea608FieldParsers = [];
+ embeddedSequenceNumbers = [];
+ embeddedLastSequenceNumber = null;
+ embeddedInitialized = true;
+ }
+
+ function append(bytes, chunk) {
+ var result, sampleList, i, samplesInfo, ccContent;
+ var mediaInfo = chunk.mediaInfo;
+ var mediaType = mediaInfo.type;
+ var mimeType = mediaInfo.mimeType;
+ var codecType = mediaInfo.codec || mimeType;
+ if (!codecType) {
+ log('No text type defined');
+ return;
+ }
+
+ function createTextTrackFromMediaInfo(captionData, mediaInfo) {
+ var textTrackInfo = new _voTextTrackInfo2['default']();
+ var trackKindMap = { subtitle: 'subtitles', caption: 'captions' }; //Dash Spec has no "s" on end of KIND but HTML needs plural.
+ var getKind = function getKind() {
+ var kind = mediaInfo.roles.length > 0 ? trackKindMap[mediaInfo.roles[0]] : trackKindMap.caption;
+ kind = kind === trackKindMap.caption || kind === trackKindMap.subtitle ? kind : trackKindMap.caption;
+ return kind;
+ };
+
+ var checkTTML = function checkTTML() {
+ var ttml = false;
+ if (mediaInfo.codec && mediaInfo.codec.search('stpp') >= 0) {
+ ttml = true;
+ }
+ if (mediaInfo.mimeType && mediaInfo.mimeType.search('ttml') >= 0) {
+ ttml = true;
+ }
+ return ttml;
+ };
+
+ textTrackInfo.captionData = captionData;
+ textTrackInfo.lang = mediaInfo.lang;
+ textTrackInfo.label = mediaInfo.id; // AdaptationSet id (an unsigned int)
+ textTrackInfo.index = mediaInfo.index; // AdaptationSet index in manifest
+ textTrackInfo.isTTML = checkTTML();
+ textTrackInfo.video = videoModel.getElement();
+ textTrackInfo.defaultTrack = getIsDefault(mediaInfo);
+ textTrackInfo.isFragmented = isFragmented;
+ textTrackInfo.isEmbedded = mediaInfo.isEmbedded ? true : false;
+ textTrackInfo.kind = getKind();
+ var totalNrTracks = (mediaInfos ? mediaInfos.length : 0) + embeddedTracks.length;
+ textTracks.addTextTrack(textTrackInfo, totalNrTracks);
+ }
+
+ if (mediaType === 'fragmentedText') {
+ if (!initializationSegmentReceived) {
+ initializationSegmentReceived = true;
+ for (i = 0; i < mediaInfos.length; i++) {
+ createTextTrackFromMediaInfo(null, mediaInfos[i]);
+ }
+ timescale = fragmentedTextBoxParser.getMediaTimescaleFromMoov(bytes);
+ } else {
+ samplesInfo = fragmentedTextBoxParser.getSamplesInfo(bytes);
+ sampleList = samplesInfo.sampleList;
+ if (!firstSubtitleStart && sampleList.length > 0) {
+ firstSubtitleStart = sampleList[0].cts - chunk.start * timescale;
+ }
+ if (codecType.search('stpp') >= 0) {
+ parser = parser !== null ? parser : getParser(codecType);
+ for (i = 0; i < sampleList.length; i++) {
+ var _sample = sampleList[i];
+ var sampleStart = _sample.cts;
+ var sampleRelStart = sampleStart - firstSubtitleStart;
+ this.buffered.add(sampleRelStart / timescale, (sampleRelStart + _sample.duration) / timescale);
+ var dataView = new DataView(bytes, _sample.offset, _sample.size);
+ ccContent = _codemIsoboxer2['default'].Utils.dataViewToString(dataView, 'utf-8');
+ try {
+ result = parser.parse(ccContent, sampleStart / timescale, (sampleStart + _sample.duration) / timescale);
+ textTracks.addCaptions(currFragmentedTrackIdx, firstSubtitleStart / timescale, result);
+ } catch (e) {
+ log('TTML parser error: ' + e.message);
+ }
+ }
+ } else {
+ // WebVTT case
+ var captionArray = [];
+ for (i = 0; i < sampleList.length; i++) {
+ var sample = sampleList[i];
+ sample.cts -= firstSubtitleStart;
+ this.buffered.add(sample.cts / timescale, (sample.cts + sample.duration) / timescale);
+ var sampleData = bytes.slice(sample.offset, sample.offset + sample.size);
+ // There are boxes inside the sampleData, so we need a ISOBoxer to get at it.
+ var sampleBoxes = _codemIsoboxer2['default'].parseBuffer(sampleData);
+
+ for (var j = 0; j < sampleBoxes.boxes.length; j++) {
+ var box1 = sampleBoxes.boxes[j];
+ log('VTT box1: ' + box1.type);
+ if (box1.type === 'vtte') {
+ continue; //Empty box
+ }
+ if (box1.type === 'vttc') {
+ log('VTT vttc boxes.length = ' + box1.boxes.length);
+ for (var k = 0; k < box1.boxes.length; k++) {
+ var box2 = box1.boxes[k];
+ log('VTT box2: ' + box2.type);
+ if (box2.type === 'payl') {
+ var cue_text = box2.cue_text;
+ log('VTT cue_text = ' + cue_text);
+ var start_time = sample.cts / timescale;
+ var end_time = (sample.cts + sample.duration) / timescale;
+ captionArray.push({
+ start: start_time,
+ end: end_time,
+ data: cue_text,
+ styles: {}
+ });
+ log('VTT ' + start_time + '-' + end_time + ' : ' + cue_text);
+ }
+ }
+ }
+ }
+ }
+ if (captionArray.length > 0) {
+ textTracks.addCaptions(currFragmentedTrackIdx, 0, captionArray);
+ }
+ }
+ }
+ } else if (mediaType === 'text') {
+ var dataView = new DataView(bytes, 0, bytes.byteLength);
+ ccContent = _codemIsoboxer2['default'].Utils.dataViewToString(dataView, 'utf-8');
+
+ try {
+ result = getParser(codecType).parse(ccContent);
+ createTextTrackFromMediaInfo(result, mediaInfo);
+ } catch (e) {
+ errHandler.timedTextError(e, 'parse', ccContent);
+ }
+ } else if (mediaType === 'video') {
+ //embedded text
+ if (chunk.segmentType === 'InitializationSegment') {
+ if (embeddedTimescale === 0) {
+ embeddedTimescale = fragmentedTextBoxParser.getMediaTimescaleFromMoov(bytes);
+ for (i = 0; i < embeddedTracks.length; i++) {
+ createTextTrackFromMediaInfo(null, embeddedTracks[i]);
+ }
+ }
+ } else {
+ // MediaSegment
+ if (embeddedTimescale === 0) {
+ log('CEA-608: No timescale for embeddedTextTrack yet');
+ return;
+ }
+ var makeCueAdderForIndex = function makeCueAdderForIndex(self, trackIndex) {
+ function newCue(startTime, endTime, captionScreen) {
+ var captionsArray = null;
+ if (videoModel.getTTMLRenderingDiv()) {
+ captionsArray = createHTMLCaptionsFromScreen(videoModel.getElement(), startTime, endTime, captionScreen);
+ } else {
+ var text = captionScreen.getDisplayText();
+ //log("CEA text: " + startTime + "-" + endTime + " '" + text + "'");
+ captionsArray = [{ start: startTime, end: endTime, data: text, styles: {} }];
+ }
+ if (captionsArray) {
+ textTracks.addCaptions(trackIndex, 0, captionsArray);
+ }
+ }
+ return newCue;
+ };
+
+ samplesInfo = fragmentedTextBoxParser.getSamplesInfo(bytes);
+ var sequenceNumber = samplesInfo.sequenceNumber;
+
+ if (!embeddedCea608FieldParsers[0] && !embeddedCea608FieldParsers[1]) {
+ // Time to setup the CEA-608 parsing
+ var field = undefined,
+ handler = undefined,
+ trackIdx = undefined;
+ for (i = 0; i < embeddedTracks.length; i++) {
+ if (embeddedTracks[i].id === 'CC1') {
+ field = 0;
+ trackIdx = textTracks.getTrackIdxForId('CC1');
+ } else if (embeddedTracks[i].id === 'CC3') {
+ field = 1;
+ trackIdx = textTracks.getTrackIdxForId('CC3');
+ }
+ if (trackIdx === -1) {
+ log('CEA-608: data before track is ready.');
+ return;
+ }
+ handler = makeCueAdderForIndex(this, trackIdx);
+ embeddedCea608FieldParsers[i] = new _externalsCea608Parser2['default'].Cea608Parser(i, { 'newCue': handler }, null);
+ }
+ }
+
+ if (embeddedTimescale && embeddedSequenceNumbers.indexOf(sequenceNumber) == -1) {
+ if (embeddedLastSequenceNumber !== null && sequenceNumber !== embeddedLastSequenceNumber + 1) {
+ for (i = 0; i < embeddedCea608FieldParsers.length; i++) {
+ if (embeddedCea608FieldParsers[i]) {
+ embeddedCea608FieldParsers[i].reset();
+ }
+ }
+ }
+ var allCcData = extractCea608Data(bytes);
+
+ for (var fieldNr = 0; fieldNr < embeddedCea608FieldParsers.length; fieldNr++) {
+ var ccData = allCcData.fields[fieldNr];
+ var fieldParser = embeddedCea608FieldParsers[fieldNr];
+ if (fieldParser) {
+ /*if (ccData.length > 0 ) {
+ log("CEA-608 adding Data to field " + fieldNr + " " + ccData.length + "bytes");
+ }*/
+ for (i = 0; i < ccData.length; i++) {
+ fieldParser.addData(ccData[i][0] / embeddedTimescale, ccData[i][1]);
+ }
+ if (allCcData.endTime) {
+ fieldParser.cueSplitAtTime(allCcData.endTime / embeddedTimescale);
+ }
+ }
+ }
+ embeddedLastSequenceNumber = sequenceNumber;
+ embeddedSequenceNumbers.push(sequenceNumber);
+ }
+ }
+ }
+ }
+ /**
+ * Extract CEA-608 data from a buffer of data.
+ * @param {ArrayBuffer} data
+ * @returns {Object|null} ccData corresponding to one segment.
+ */
+ function extractCea608Data(data) {
+
+ /* Insert [time, data] pairs in order into array. */
+ var insertInOrder = function insertInOrder(arr, time, data) {
+ var len = arr.length;
+ if (len > 0) {
+ if (time >= arr[len - 1][0]) {
+ arr.push([time, data]);
+ } else {
+ for (var pos = len - 1; pos >= 0; pos--) {
+ if (time < arr[pos][0]) {
+ arr.splice(pos, 0, [time, data]);
+ break;
+ }
+ }
+ }
+ } else {
+ arr.push([time, data]);
+ }
+ };
+
+ var isoFile = boxParser.parse(data);
+ var moof = isoFile.getBox('moof');
+ var tfdt = isoFile.getBox('tfdt');
+ //var tfhd = isoFile.getBox('tfhd'); //Can have a base_data_offset and other default values
+ //log("tfhd: " + tfhd);
+ //var saio = isoFile.getBox('saio'); // Offset possibly
+ //var saiz = isoFile.getBox('saiz'); // Possible sizes
+ var truns = isoFile.getBoxes('trun'); //
+ var trun = null;
+
+ if (truns.length === 0) {
+ return null;
+ }
+ trun = truns[0];
+ if (truns.length > 1) {
+ log('Warning: Too many truns');
+ }
+ var baseOffset = moof.offset + trun.data_offset;
+ //Doublecheck that trun.offset == moof.size + 8
+ var sampleCount = trun.sample_count;
+ var startPos = baseOffset;
+ var baseSampleTime = tfdt.baseMediaDecodeTime;
+ var raw = new DataView(data);
+ var allCcData = { 'startTime': null, 'endTime': null, fields: [[], []] };
+ var accDuration = 0;
+ for (var i = 0; i < sampleCount; i++) {
+ var sample = trun.samples[i];
+ var sampleTime = baseSampleTime + accDuration + sample.sample_composition_time_offset;
+ var cea608Ranges = _externalsCea608Parser2['default'].findCea608Nalus(raw, startPos, sample.sample_size);
+ for (var j = 0; j < cea608Ranges.length; j++) {
+ var ccData = _externalsCea608Parser2['default'].extractCea608DataFromRange(raw, cea608Ranges[j]);
+ for (var k = 0; k < 2; k++) {
+ if (ccData[k].length > 0) {
+ insertInOrder(allCcData.fields[k], sampleTime, ccData[k]);
+ }
+ }
+ }
+
+ accDuration += sample.sample_duration;
+ startPos += sample.sample_size;
+ }
+ var endSampleTime = baseSampleTime + accDuration;
+ allCcData.startTime = baseSampleTime;
+ allCcData.endTime = endSampleTime;
+ return allCcData;
+ }
+
+ /* HTML Rendering functions */
+ function checkIndent(chars) {
+ var line = '';
+
+ for (var c = 0; c < chars.length; ++c) {
+ var uc = chars[c];
+ line += uc.uchar;
+ }
+
+ var l = line.length;
+ var ll = line.replace(/^\s+/, '').length;
+ return l - ll;
+ }
+
+ function getRegionProperties(region) {
+ return 'left: ' + region.x * 3.125 + '%; top: ' + region.y1 * 6.66 + '%; width: ' + (100 - region.x * 3.125) + '%; height: ' + Math.max(region.y2 - 1 - region.y1, 1) * 6.66 + '%; align-items: flex-start; overflow: visible; -webkit-writing-mode: horizontal-tb;';
+ }
+
+ function createRGB(color) {
+ if (color == 'red') {
+ return 'rgb(255, 0, 0)';
+ } else if (color == 'green') {
+ return 'rgb(0, 255, 0)';
+ } else if (color == 'blue') {
+ return 'rgb(0, 0, 255)';
+ } else if (color == 'cyan') {
+ return 'rgb(0, 255, 255)';
+ } else if (color == 'magenta') {
+ return 'rgb(255, 0, 255)';
+ } else if (color == 'yellow') {
+ return 'rgb(255, 255, 0)';
+ } else if (color == 'white') {
+ return 'rgb(255, 255, 255)';
+ } else if (color == 'black') {
+ return 'rgb(0, 0, 0)';
+ }
+ return color;
+ }
+
+ function getStyle(videoElement, style) {
+ var fontSize = videoElement.videoHeight / 15.0;
+ if (style) {
+ return 'font-size: ' + fontSize + 'px; font-family: Menlo, Consolas, \'Cutive Mono\', monospace; color: ' + (style.foreground ? createRGB(style.foreground) : 'rgb(255, 255, 255)') + '; font-style: ' + (style.italics ? 'italic' : 'normal') + '; text-decoration: ' + (style.underline ? 'underline' : 'none') + '; white-space: pre; background-color: ' + (style.background ? createRGB(style.background) : 'transparent') + ';';
+ } else {
+ return 'font-size: ' + fontSize + 'px; font-family: Menlo, Consolas, \'Cutive Mono\', monospace; justify-content: flex-start; text-align: left; color: rgb(255, 255, 255); font-style: normal; white-space: pre; line-height: normal; font-weight: normal; text-decoration: none; width: 100%; display: flex;';
+ }
+ }
+
+ function ltrim(s) {
+ var trimmed = s.replace(/^\s+/g, '');
+ return trimmed;
+ }
+ function rtrim(s) {
+ var trimmed = s.replace(/\s+$/g, '');
+ return trimmed;
+ }
+
+ function createHTMLCaptionsFromScreen(videoElement, startTime, endTime, captionScreen) {
+
+ var currRegion = null;
+ var existingRegion = null;
+ var lastRowHasText = false;
+ var lastRowIndentL = -1;
+ var currP = { start: startTime, end: endTime, spans: [] };
+ var currentStyle = 'style_cea608_white_black';
+ var seenRegions = {};
+ var styleStates = {};
+ var regions = [];
+ var r = undefined,
+ s = undefined;
+
+ for (r = 0; r < 15; ++r) {
+ var row = captionScreen.rows[r];
+ var line = '';
+ var prevPenState = null;
+
+ if (false === row.isEmpty()) {
+ /* Row is not empty */
+
+ /* Get indentation of this row */
+ var rowIndent = checkIndent(row.chars);
+
+ /* Create a new region is there is none */
+ if (currRegion === null) {
+ currRegion = { x: rowIndent, y1: r, y2: r + 1, p: [] };
+ }
+
+ /* Check if indentation has changed and we had text of last row */
+ if (rowIndent !== lastRowIndentL && lastRowHasText) {
+ currRegion.p.push(currP);
+ currP = { start: startTime, end: endTime, spans: [] };
+ currRegion.y2 = r;
+ currRegion.name = 'region_' + currRegion.x + '_' + currRegion.y1 + '_' + currRegion.y2;
+ if (false === seenRegions.hasOwnProperty(currRegion.name)) {
+ regions.push(currRegion);
+ seenRegions[currRegion.name] = currRegion;
+ } else {
+ existingRegion = seenRegions[currRegion.name];
+ existingRegion.p.contat(currRegion.p);
+ }
+
+ currRegion = { x: rowIndent, y1: r, y2: r + 1, p: [] };
+ }
+
+ for (var c = 0; c < row.chars.length; ++c) {
+ var uc = row.chars[c];
+ var currPenState = uc.penState;
+ if (prevPenState === null || !currPenState.equals(prevPenState)) {
+ if (line.trim().length > 0) {
+ currP.spans.push({ name: currentStyle, line: line, row: r });
+ line = '';
+ }
+
+ var currPenStateString = 'style_cea608_' + currPenState.foreground + '_' + currPenState.background;
+ if (currPenState.underline) {
+ currPenStateString += '_underline';
+ }
+ if (currPenState.italics) {
+ currPenStateString += '_italics';
+ }
+
+ if (!styleStates.hasOwnProperty(currPenStateString)) {
+ styleStates[currPenStateString] = JSON.parse(JSON.stringify(currPenState));
+ }
+
+ prevPenState = currPenState;
+
+ currentStyle = currPenStateString;
+ }
+
+ line += uc.uchar;
+ }
+
+ if (line.trim().length > 0) {
+ currP.spans.push({ name: currentStyle, line: line, row: r });
+ }
+
+ lastRowHasText = true;
+ lastRowIndentL = rowIndent;
+ } else {
+ /* Row is empty */
+ lastRowHasText = false;
+ lastRowIndentL = -1;
+
+ if (currRegion) {
+ currRegion.p.push(currP);
+ currP = { start: startTime, end: endTime, spans: [] };
+ currRegion.y2 = r;
+ currRegion.name = 'region_' + currRegion.x + '_' + currRegion.y1 + '_' + currRegion.y2;
+ if (false === seenRegions.hasOwnProperty(currRegion.name)) {
+ regions.push(currRegion);
+ seenRegions[currRegion.name] = currRegion;
+ } else {
+ existingRegion = seenRegions[currRegion.name];
+ existingRegion.p.contat(currRegion.p);
+ }
+
+ currRegion = null;
+ }
+ }
+ }
+
+ if (currRegion) {
+ currRegion.p.push(currP);
+ currRegion.y2 = r + 1;
+ currRegion.name = 'region_' + currRegion.x + '_' + currRegion.y1 + '_' + currRegion.y2;
+ if (false === seenRegions.hasOwnProperty(currRegion.name)) {
+ regions.push(currRegion);
+ seenRegions[currRegion.name] = currRegion;
+ } else {
+ existingRegion = seenRegions[currRegion.name];
+ existingRegion.p.contat(currRegion.p);
+ }
+
+ currRegion = null;
+ }
+
+ //log(styleStates);
+ //log(regions);
+
+ var captionsArray = [];
+
+ /* Loop thru regions */
+ for (r = 0; r < regions.length; ++r) {
+ var region = regions[r];
+
+ var cueID = 'sub_cea608_' + captionId++;
+ var finalDiv = document.createElement('div');
+ finalDiv.id = cueID;
+ var cueRegionProperties = getRegionProperties(region);
+ finalDiv.style.cssText = 'position: absolute; margin: 0; display: flex; box-sizing: border-box; pointer-events: none;' + cueRegionProperties;
+
+ var bodyDiv = document.createElement('div');
+ bodyDiv.className = 'paragraph bodyStyle';
+ bodyDiv.style.cssText = getStyle(videoElement);
+
+ var cueUniWrapper = document.createElement('div');
+ cueUniWrapper.className = 'cueUniWrapper';
+ cueUniWrapper.style.cssText = 'unicode-bidi: normal; direction: ltr;';
+
+ for (var p = 0; p < region.p.length; ++p) {
+ var ptag = region.p[p];
+ var lastSpanRow = 0;
+ for (s = 0; s < ptag.spans.length; ++s) {
+ var span = ptag.spans[s];
+ if (span.line.length > 0) {
+ if (s !== 0 && lastSpanRow != span.row) {
+ var brElement = document.createElement('br');
+ brElement.className = 'lineBreak';
+ cueUniWrapper.appendChild(brElement);
+ }
+ var sameRow = false;
+ if (lastSpanRow === span.row) {
+ sameRow = true;
+ }
+ lastSpanRow = span.row;
+ var spanStyle = styleStates[span.name];
+ var spanElement = document.createElement('span');
+ spanElement.className = 'spanPadding ' + span.name + ' customSpanColor';
+ spanElement.style.cssText = getStyle(videoElement, spanStyle);
+ if (s !== 0 && sameRow) {
+ if (s === ptag.spans.length - 1) {
+ spanElement.textContent = rtrim(span.line);
+ } else {
+ spanElement.textContent = span.line;
+ }
+ } else {
+ if (s === 0) {
+ if (ptag.spans.length > 1) {
+ /* Check if next text is on same row */
+ if (span.row === ptag.spans[1].row) {
+ /* Next element on same row, trim start */
+ spanElement.textContent = ltrim(span.line);
+ } else {
+ /* Different rows, trim */
+ spanElement.textContent = span.line.trim();
+ }
+ } else {
+ spanElement.textContent = span.line.trim();
+ }
+ } else {
+ spanElement.textContent = span.line.trim();
+ }
+ }
+ cueUniWrapper.appendChild(spanElement);
+ }
+ }
+ }
+
+ bodyDiv.appendChild(cueUniWrapper);
+
+ finalDiv.appendChild(bodyDiv);
+
+ var fontSize = { 'bodyStyle': 90 };
+ for (s in styleStates) {
+ if (styleStates.hasOwnProperty(s)) {
+ fontSize[s] = 90;
+ }
+ }
+
+ captionsArray.push({ type: 'html',
+ start: startTime,
+ end: endTime,
+ cueHTMLElement: finalDiv,
+ cueID: cueID,
+ cellResolution: [32, 15],
+ isFromCEA608: true,
+ regions: regions,
+ regionID: region.name,
+ videoHeight: videoElement.videoHeight,
+ videoWidth: videoElement.videoWidth,
+ fontSize: fontSize || {
+ defaultFontSize: '100'
+ },
+ lineHeight: {},
+ linePadding: {}
+ });
+ }
+ return captionsArray;
+ }
+
+ function abort() {
+ textTracks.deleteAllTextTracks();
+ allTracksAreDisabled = false;
+ parser = null;
+ fragmentedTextBoxParser = null;
+ mediaInfos = null;
+ textTracks = null;
+ isFragmented = false;
+ fragmentModel = null;
+ initializationSegmentReceived = false;
+ timescale = NaN;
+ fragmentedTracks = [];
+ videoModel = null;
+ streamController = null;
+ embeddedInitialized = false;
+ embeddedTracks = null;
+ }
+
+ function addEmbeddedTrack(mediaInfo) {
+ if (!embeddedInitialized) {
+ initEmbedded();
+ }
+ if (mediaInfo.id === 'CC1' || mediaInfo.id === 'CC3') {
+ embeddedTracks.push(mediaInfo);
+ } else {
+ log('Warning: Embedded track ' + mediaInfo.id + ' not supported!');
+ }
+ }
+
+ function resetEmbedded() {
+ embeddedInitialized = false;
+ embeddedTracks = [];
+ embeddedCea608FieldParsers = [null, null];
+ embeddedSequenceNumbers = [];
+ embeddedLastSequenceNumber = null;
+ }
+
+ function getAllTracksAreDisabled() {
+ return allTracksAreDisabled;
+ }
+
+ function setConfig(config) {
+ if (!config) return;
+
+ if (config.errHandler) {
+ errHandler = config.errHandler;
+ }
+ if (config.adapter) {
+ adapter = config.adapter;
+ }
+ if (config.dashManifestModel) {
+ dashManifestModel = config.dashManifestModel;
+ }
+ if (config.mediaController) {
+ mediaController = config.mediaController;
+ }
+ if (config.videoModel) {
+ videoModel = config.videoModel;
+ }
+ if (config.streamController) {
+ streamController = config.streamController;
+ }
+ if (config.textTracks) {
+ textTracks = config.textTracks;
+ }
+ if (config.VTTParser) {
+ VTTParser = config.VTTParser;
+ }
+ if (config.TTMLParser) {
+ TTMLParser = config.TTMLParser;
+ }
+ }
+
+ function setTextTrack() {
+
+ var el = videoModel.getElement();
+ var tracks = el.textTracks;
+ var ln = tracks.length;
+ var nrNonEmbeddedTracks = ln - embeddedTracks.length;
+ var oldTrackIdx = textTracks.getCurrentTrackIdx();
+
+ for (var i = 0; i < ln; i++) {
+ var track = tracks[i];
+ allTracksAreDisabled = track.mode !== 'showing';
+ if (track.mode === 'showing') {
+ if (oldTrackIdx !== i) {
+ // do not reset track if already the current track. This happens when all captions get turned off via UI and then turned on again and with videojs.
+ textTracks.setCurrentTrackIdx(i);
+ textTracks.addCaptions(i, 0, null); // Make sure that previously queued captions are added as cues
+ if (isFragmented && i < nrNonEmbeddedTracks) {
+ var currentFragTrack = mediaController.getCurrentTrackFor('fragmentedText', streamController.getActiveStreamInfo());
+ var newFragTrack = fragmentedTracks[i];
+ if (newFragTrack !== currentFragTrack) {
+ fragmentModel.abortRequests();
+ textTracks.deleteTrackCues(currentFragTrack);
+ mediaController.setTrack(newFragTrack);
+ currFragmentedTrackIdx = i;
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ if (allTracksAreDisabled) {
+ textTracks.setCurrentTrackIdx(-1);
+ }
+ }
+
+ function getIsDefault(mediaInfo) {
+ //TODO How to tag default. currently same order as listed in manifest.
+ // Is there a way to mark a text adaptation set as the default one? DASHIF meeting talk about using role which is being used for track KIND
+ // Eg subtitles etc. You can have multiple role tags per adaptation Not defined in the spec yet.
+ var isDefault = false;
+ if (embeddedTracks.length > 1) {
+ isDefault = mediaInfo.id && mediaInfo.id === 'CC1'; // CC1 if both CC1 and CC3 exist
+ } else if (embeddedTracks.length === 1) {
+ if (mediaInfo.id && mediaInfo.id.substring(0, 2) === 'CC') {
+ // Either CC1 or CC3
+ isDefault = true;
+ }
+ } else {
+ isDefault = mediaInfo.index === mediaInfos[0].index;
+ }
+ return isDefault;
+ }
+
+ function getParser(codecType) {
+ var parser;
+ if (codecType.search('vtt') >= 0) {
+ parser = VTTParser;
+ } else if (codecType.search('ttml') >= 0 || codecType.search('stpp') >= 0) {
+ parser = TTMLParser;
+ parser.setConfig({ videoModel: videoModel });
+ }
+ return parser;
+ }
+
+ instance = {
+ initialize: initialize,
+ append: append,
+ abort: abort,
+ getAllTracksAreDisabled: getAllTracksAreDisabled,
+ setTextTrack: setTextTrack,
+ setConfig: setConfig,
+ addEmbeddedTrack: addEmbeddedTrack,
+ resetEmbedded: resetEmbedded
+ };
+
+ return instance;
+}
+
+TextSourceBuffer.__dashjs_factory_name = 'TextSourceBuffer';
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(TextSourceBuffer);
+module.exports = exports['default'];
+
+},{"10":10,"104":104,"146":146,"148":148,"171":171,"2":2,"32":32,"57":57,"6":6,"8":8}],57:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreEventBus = _dereq_(9);
+
+var _coreEventBus2 = _interopRequireDefault(_coreEventBus);
+
+var _coreEventsEvents = _dereq_(13);
+
+var _coreEventsEvents2 = _interopRequireDefault(_coreEventsEvents);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _coreDebug = _dereq_(8);
+
+var _coreDebug2 = _interopRequireDefault(_coreDebug);
+
+function TextTracks() {
+
+ var context = this.context;
+ var eventBus = (0, _coreEventBus2['default'])(context).getInstance();
+ var log = (0, _coreDebug2['default'])(context).getInstance().log;
+
+ var instance = undefined,
+ Cue = undefined,
+ videoModel = undefined,
+ video = undefined,
+ textTrackQueue = undefined,
+ trackElementArr = undefined,
+ currentTrackIdx = undefined,
+ actualVideoLeft = undefined,
+ actualVideoTop = undefined,
+ actualVideoWidth = undefined,
+ actualVideoHeight = undefined,
+ captionContainer = undefined,
+ videoSizeCheckInterval = undefined,
+ isChrome = undefined,
+ fullscreenAttribute = undefined,
+ displayCCOnTop = undefined,
+ topZIndex = undefined;
+
+ function initialize() {
+ Cue = window.VTTCue || window.TextTrackCue;
+ textTrackQueue = [];
+ trackElementArr = [];
+ currentTrackIdx = -1;
+ actualVideoLeft = 0;
+ actualVideoTop = 0;
+ actualVideoWidth = 0;
+ actualVideoHeight = 0;
+ captionContainer = null;
+ videoSizeCheckInterval = null;
+ displayCCOnTop = false;
+ topZIndex = 2147483647;
+
+ //TODO Check if IE has resolved issues: Then revert to not using the addTextTrack API for all browsers.
+ // https://connect.microsoft.com/IE/feedbackdetail/view/1660701/text-tracks-do-not-fire-change-addtrack-or-removetrack-events
+ // https://connect.microsoft.com/IE/feedback/details/1573380/htmltrackelement-track-addcue-throws-invalidstateerror-when-adding-new-cue
+ // Same issue with Firefox.
+ //isIE11orEdge = !!navigator.userAgent.match(/Trident.*rv[ :]*11\./) || navigator.userAgent.match(/Edge/);
+ //isFirefox = !!navigator.userAgent.match(/Firefox/);
+ isChrome = !!navigator.userAgent.match(/Chrome/) && !navigator.userAgent.match(/Edge/);
+ if (document.fullscreenElement !== undefined) {
+ fullscreenAttribute = 'fullscreenElement'; // Standard and Edge
+ } else if (document.webkitIsFullScreen !== undefined) {
+ fullscreenAttribute = 'webkitIsFullScreen'; // Chrome and Safari (and Edge)
+ } else if (document.msFullscreenElement) {
+ // IE11
+ fullscreenAttribute = 'msFullscreenElement';
+ } else if (document.mozFullScreen) {
+ // Firefox
+ fullscreenAttribute = 'mozFullScreen';
+ }
+ }
+
+ function createTrackForUserAgent(i) {
+ var kind = textTrackQueue[i].kind;
+ var label = textTrackQueue[i].label !== undefined ? textTrackQueue[i].label : textTrackQueue[i].lang;
+ var lang = textTrackQueue[i].lang;
+ var track = isChrome ? document.createElement('track') : video.addTextTrack(kind, label, lang);
+
+ if (isChrome) {
+ track.kind = kind;
+ track.label = label;
+ track.srclang = lang;
+ }
+
+ return track;
+ }
+
+ function displayCConTop(value) {
+ displayCCOnTop = value;
+ if (!captionContainer || document[fullscreenAttribute]) return;
+ captionContainer.style.zIndex = value ? topZIndex : null;
+ }
+
+ function addTextTrack(textTrackInfoVO, totalTextTracks) {
+
+ if (textTrackQueue.length === totalTextTracks) {
+ log('Trying to add too many tracks.');
+ return;
+ }
+
+ textTrackQueue.push(textTrackInfoVO);
+ if (video === undefined) {
+ video = textTrackInfoVO.video;
+ }
+
+ if (textTrackQueue.length === totalTextTracks) {
+ textTrackQueue.sort(function (a, b) {
+ //Sort in same order as in manifest
+ return a.index - b.index;
+ });
+ captionContainer = videoModel.getTTMLRenderingDiv();
+ var defaultIndex = -1;
+ for (var i = 0; i < textTrackQueue.length; i++) {
+ var track = createTrackForUserAgent.call(this, i);
+ trackElementArr.push(track); //used to remove tracks from video element when added manually
+
+ if (textTrackQueue[i].defaultTrack) {
+ // track.default is an object property identifier that is a reserved word
+ // The following jshint directive is used to suppressed the warning "Expected an identifier and instead saw 'default' (a reserved word)"
+ /*jshint -W024 */
+ track['default'] = true;
+ defaultIndex = i;
+ }
+ if (isChrome) {
+ video.appendChild(track);
+ }
+ var textTrack = video.textTracks[i];
+ textTrack.nonAddedCues = [];
+ if (captionContainer && (textTrackQueue[i].isTTML || textTrackQueue[i].isEmbedded)) {
+ textTrack.renderingType = 'html';
+ } else {
+ textTrack.renderingType = 'default';
+ }
+ this.addCaptions(i, 0, textTrackQueue[i].captionData);
+ eventBus.trigger(_coreEventsEvents2['default'].TEXT_TRACK_ADDED);
+ }
+ setCurrentTrackIdx.call(this, defaultIndex);
+ if (defaultIndex >= 0) {
+ video.textTracks[defaultIndex].mode = 'showing';
+ this.addCaptions(defaultIndex, 0, null);
+ }
+ eventBus.trigger(_coreEventsEvents2['default'].TEXT_TRACKS_ADDED, { index: currentTrackIdx, tracks: textTrackQueue }); //send default idx.
+ }
+ }
+
+ function getVideoVisibleVideoSize(viewWidth, viewHeight, videoWidth, videoHeight, aspectRatio, use80Percent) {
+ var viewAspectRatio = viewWidth / viewHeight;
+ var videoAspectRatio = videoWidth / videoHeight;
+
+ var videoPictureWidth = 0;
+ var videoPictureHeight = 0;
+
+ if (viewAspectRatio > videoAspectRatio) {
+ videoPictureHeight = viewHeight;
+ videoPictureWidth = videoPictureHeight / videoHeight * videoWidth;
+ } else {
+ videoPictureWidth = viewWidth;
+ videoPictureHeight = videoPictureWidth / videoWidth * videoHeight;
+ }
+
+ var videoPictureXAspect = 0;
+ var videoPictureYAspect = 0;
+ var videoPictureWidthAspect = 0;
+ var videoPictureHeightAspect = 0;
+ var videoPictureAspect = videoPictureWidth / videoPictureHeight;
+
+ if (videoPictureAspect > aspectRatio) {
+ videoPictureHeightAspect = videoPictureHeight;
+ videoPictureWidthAspect = videoPictureHeight / (1 / aspectRatio);
+ videoPictureXAspect = (viewWidth - videoPictureWidthAspect) / 2;
+ videoPictureYAspect = 0;
+ } else {
+ videoPictureWidthAspect = videoPictureWidth;
+ videoPictureHeightAspect = videoPictureWidth / aspectRatio;
+ videoPictureXAspect = 0;
+ videoPictureYAspect = (viewHeight - videoPictureHeightAspect) / 2;
+ }
+
+ if (use80Percent) {
+ return { x: videoPictureXAspect + videoPictureWidthAspect * 0.1,
+ y: videoPictureYAspect + videoPictureHeightAspect * 0.1,
+ w: videoPictureWidthAspect * 0.8,
+ h: videoPictureHeightAspect * 0.8 }; /* Maximal picture size in videos aspect ratio */
+ } else {
+ return { x: videoPictureXAspect,
+ y: videoPictureYAspect,
+ w: videoPictureWidthAspect,
+ h: videoPictureHeightAspect }; /* Maximal picture size in videos aspect ratio */
+ }
+ }
+
+ function checkVideoSize() {
+ var track = this.getCurrentTextTrack();
+ if (track && track.renderingType === 'html') {
+ var aspectRatio = video.clientWidth / video.clientHeight;
+ var use80Percent = false;
+ if (track.isFromCEA608) {
+ // If this is CEA608 then use predefined aspect ratio
+ aspectRatio = 3.5 / 3.0;
+ use80Percent = true;
+ }
+
+ var realVideoSize = getVideoVisibleVideoSize.call(this, video.clientWidth, video.clientHeight, video.videoWidth, video.videoHeight, aspectRatio, use80Percent);
+
+ var newVideoWidth = realVideoSize.w;
+ var newVideoHeight = realVideoSize.h;
+
+ if (newVideoWidth != actualVideoWidth || newVideoHeight != actualVideoHeight) {
+ actualVideoLeft = realVideoSize.x;
+ actualVideoTop = realVideoSize.y;
+ actualVideoWidth = newVideoWidth;
+ actualVideoHeight = newVideoHeight;
+ captionContainer.style.left = actualVideoLeft + 'px';
+ captionContainer.style.top = actualVideoTop + 'px';
+ captionContainer.style.width = actualVideoWidth + 'px';
+ captionContainer.style.height = actualVideoHeight + 'px';
+
+ // Video view has changed size, so resize any active cues
+ for (var i = 0; track.activeCues && i < track.activeCues.length; ++i) {
+ var cue = track.activeCues[i];
+ cue.scaleCue(cue);
+ }
+
+ if (fullscreenAttribute && document[fullscreenAttribute] || displayCCOnTop) {
+ captionContainer.style.zIndex = topZIndex;
+ } else {
+ captionContainer.style.zIndex = null;
+ }
+ }
+ }
+ }
+
+ function convertToPixels(percentage, pixelMeasure) {
+ var percentString = Math.round(0.01 * percentage * pixelMeasure).toString() + 'px';
+ return percentString;
+ }
+
+ function scaleImageCue(activeCue) {
+ var videoWidth = actualVideoWidth;
+ var videoHeight = actualVideoHeight;
+
+ if (videoWidth * videoHeight === 0) {
+ return; //At least one of the measures is still zero
+ }
+
+ if (activeCue.layout) {
+ var layout = activeCue.layout;
+ var left = convertToPixels(layout.left, videoWidth);
+ var _top = convertToPixels(layout.top, videoHeight);
+ var width = convertToPixels(layout.width, videoWidth);
+ var height = convertToPixels(layout.height, videoHeight);
+ captionContainer.style.left = left;
+ captionContainer.style.top = _top;
+ captionContainer.style.width = width;
+ captionContainer.style.height = height;
+ var image = captionContainer.firstChild;
+ if (image && image.style) {
+ image.style.left = '0px';
+ image.style.top = '0px';
+ image.style.width = width;
+ image.style.height = height;
+ }
+ }
+ }
+
+ function scaleCue(activeCue) {
+ var videoWidth = actualVideoWidth;
+ var videoHeight = actualVideoHeight;
+ var key, replaceValue, elements;
+
+ var cellUnit = [videoWidth / activeCue.cellResolution[0], videoHeight / activeCue.cellResolution[1]];
+
+ if (activeCue.linePadding) {
+ for (key in activeCue.linePadding) {
+ if (activeCue.linePadding.hasOwnProperty(key)) {
+ var valueLinePadding = activeCue.linePadding[key];
+ replaceValue = (valueLinePadding * cellUnit[0]).toString();
+ // Compute the CellResolution unit in order to process properties using sizing (fontSize, linePadding, etc).
+ var elementsSpan = document.getElementsByClassName('spanPadding');
+ for (var i = 0; i < elementsSpan.length; i++) {
+ elementsSpan[i].style.cssText = elementsSpan[i].style.cssText.replace(/(padding-left\s*:\s*)[\d.,]+(?=\s*px)/gi, '$1' + replaceValue);
+ elementsSpan[i].style.cssText = elementsSpan[i].style.cssText.replace(/(padding-right\s*:\s*)[\d.,]+(?=\s*px)/gi, '$1' + replaceValue);
+ }
+ }
+ }
+ }
+
+ if (activeCue.fontSize) {
+ for (key in activeCue.fontSize) {
+ if (activeCue.fontSize.hasOwnProperty(key)) {
+ var valueFontSize = activeCue.fontSize[key] / 100;
+ replaceValue = (valueFontSize * cellUnit[1]).toString();
+
+ if (key !== 'defaultFontSize') {
+ elements = document.getElementsByClassName(key);
+ } else {
+ elements = document.getElementsByClassName('paragraph');
+ }
+
+ for (var j = 0; j < elements.length; j++) {
+ elements[j].style.cssText = elements[j].style.cssText.replace(/(font-size\s*:\s*)[\d.,]+(?=\s*px)/gi, '$1' + replaceValue);
+ }
+ }
+ }
+ }
+
+ if (activeCue.lineHeight) {
+ for (key in activeCue.lineHeight) {
+ if (activeCue.lineHeight.hasOwnProperty(key)) {
+ var valueLineHeight = activeCue.lineHeight[key] / 100;
+ replaceValue = (valueLineHeight * cellUnit[1]).toString();
+ elements = document.getElementsByClassName(key);
+ for (var k = 0; k < elements.length; k++) {
+ elements[k].style.cssText = elements[k].style.cssText.replace(/(line-height\s*:\s*)[\d.,]+(?=\s*px)/gi, '$1' + replaceValue);
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ * Add captions to track, store for later adding, or add captions added before
+ */
+ function addCaptions(trackIdx, timeOffset, captionData) {
+ var track = trackIdx >= 0 ? video.textTracks[trackIdx] : null;
+ var self = this;
+
+ if (!track) return;
+ if (track.mode !== 'showing') {
+ if (captionData && captionData.length > 0) {
+ track.nonAddedCues = track.nonAddedCues.concat(captionData);
+ }
+ return;
+ }
+
+ if (!captionData) {
+ captionData = track.nonAddedCues;
+ track.nonAddedCues = [];
+ }
+
+ if (!captionData || captionData.length === 0) {
+ return;
+ }
+
+ for (var item in captionData) {
+ var cue;
+ var currentItem = captionData[item];
+
+ track.cellResolution = currentItem.cellResolution;
+ track.isFromCEA608 = currentItem.isFromCEA608;
+
+ if (!videoSizeCheckInterval && (currentItem.type === 'html' || currentItem.type === 'image')) {
+ videoSizeCheckInterval = setInterval(checkVideoSize.bind(this), 500);
+ }
+
+ //image subtitle extracted from TTML
+ if (currentItem.type === 'image') {
+ cue = new Cue(currentItem.start - timeOffset, currentItem.end - timeOffset, '');
+ cue.image = currentItem.data;
+ cue.id = currentItem.id;
+ cue.size = 0; //discard the native display for this subtitles
+ cue.type = 'image'; // active image overlay
+ cue.layout = currentItem.layout;
+ cue.scaleCue = scaleImageCue.bind(self);
+ cue.onenter = function () {
+ if (!captionContainer) {
+ // Does not support image captions without a container
+ return;
+ }
+ if (track.mode === 'showing') {
+ var img = new Image();
+ img.id = 'ttmlImage_' + this.id;
+ img.src = this.image;
+ //img.className = 'cue-image';
+ img.style.cssText = 'z-index: 2147483648; pointer-events: none; display: block; visibility: visible !important; position: relative !important;';
+ captionContainer.appendChild(img);
+ scaleImageCue.call(self, this);
+ }
+ };
+
+ cue.onexit = function () {
+ if (!captionContainer) {
+ return;
+ }
+ var imgs = captionContainer.childNodes;
+ for (var i = 0; i < imgs.length; i++) {
+ if (imgs[i].id === 'ttmlImage_' + this.id) {
+ captionContainer.removeChild(imgs[i]);
+ }
+ }
+ };
+ } else if (currentItem.type === 'html') {
+ cue = new Cue(currentItem.start - timeOffset, currentItem.end - timeOffset, '');
+ cue.cueHTMLElement = currentItem.cueHTMLElement;
+ cue.regions = currentItem.regions;
+ cue.regionID = currentItem.regionID;
+ cue.cueID = currentItem.cueID;
+ cue.videoWidth = currentItem.videoWidth;
+ cue.videoHeight = currentItem.videoHeight;
+ cue.cellResolution = currentItem.cellResolution;
+ cue.fontSize = currentItem.fontSize;
+ cue.lineHeight = currentItem.lineHeight;
+ cue.linePadding = currentItem.linePadding;
+ cue.scaleCue = scaleCue.bind(self);
+ captionContainer.style.left = actualVideoLeft + 'px';
+ captionContainer.style.top = actualVideoTop + 'px';
+ captionContainer.style.width = actualVideoWidth + 'px';
+ captionContainer.style.height = actualVideoHeight + 'px';
+
+ cue.onenter = function () {
+ if (track.mode === 'showing') {
+ log('Cue ' + this.startTime + '-' + this.endTime + ' : ' + this.cueHTMLElement.id + ' : ' + this.cueHTMLElement.innerText);
+ captionContainer.appendChild(this.cueHTMLElement);
+ scaleCue.call(self, this);
+ }
+ };
+
+ cue.onexit = function () {
+ var divs = captionContainer.childNodes;
+ for (var i = 0; i < divs.length; ++i) {
+ if (divs[i].id === this.cueID) {
+ captionContainer.removeChild(divs[i]);
+ }
+ }
+ };
+ } else {
+ cue = new Cue(currentItem.start - timeOffset, currentItem.end - timeOffset, currentItem.data);
+ if (currentItem.styles) {
+ if (currentItem.styles.align !== undefined && cue.hasOwnProperty('align')) {
+ cue.align = currentItem.styles.align;
+ }
+ if (currentItem.styles.line !== undefined && cue.hasOwnProperty('line')) {
+ cue.line = currentItem.styles.line;
+ }
+ if (currentItem.styles.position !== undefined && cue.hasOwnProperty('position')) {
+ cue.position = currentItem.styles.position;
+ }
+ if (currentItem.styles.size !== undefined && cue.hasOwnProperty('size')) {
+ cue.size = currentItem.styles.size;
+ }
+ }
+ }
+
+ track.addCue(cue);
+ }
+ }
+
+ function getCurrentTextTrack() {
+ return currentTrackIdx >= 0 ? video.textTracks[currentTrackIdx] : null;
+ }
+
+ function getCurrentTrackIdx() {
+ return currentTrackIdx;
+ }
+
+ function getTrackIdxForId(trackId) {
+ var idx = -1;
+ for (var i = 0; i < video.textTracks.length; i++) {
+ if (video.textTracks[i].label === trackId) {
+ idx = i;
+ break;
+ }
+ }
+ return idx;
+ }
+
+ function setCurrentTrackIdx(idx) {
+ currentTrackIdx = idx;
+ clearCaptionContainer.call(this);
+ if (idx >= 0) {
+ var track = video.textTracks[idx];
+ if (track.renderingType === 'html') {
+ setNativeCueStyle.call(this);
+ } else {
+ removeNativeCueStyle.call(this);
+ }
+ } else {
+ removeNativeCueStyle.call(this);
+ }
+ }
+
+ function getTextTrack(idx) {
+ return video.textTracks[idx];
+ }
+
+ function deleteTrackCues(track) {
+ if (track.cues) {
+ var cues = track.cues;
+ var lastIdx = cues.length - 1;
+
+ for (var r = lastIdx; r >= 0; r--) {
+ track.removeCue(cues[r]);
+ }
+
+ track.mode = 'disabled';
+ }
+ }
+
+ function deleteAllTextTracks() {
+ var ln = trackElementArr.length;
+ for (var i = 0; i < ln; i++) {
+ if (isChrome) {
+ video.removeChild(trackElementArr[i]);
+ } else {
+ var track = getTextTrack.call(this, i);
+ track.nonAddedCues = [];
+ deleteTrackCues.call(this, track);
+ }
+ }
+ trackElementArr = [];
+ textTrackQueue = [];
+ if (videoSizeCheckInterval) {
+ clearInterval(videoSizeCheckInterval);
+ videoSizeCheckInterval = null;
+ }
+ clearCaptionContainer.call(this);
+ }
+
+ function deleteTextTrack(idx) {
+ video.removeChild(trackElementArr[idx]);
+ trackElementArr.splice(idx, 1);
+ }
+
+ /* Set native cue style to transparent background to avoid it being displayed. */
+ function setNativeCueStyle() {
+ if (!isChrome) return;
+ var styleElement = document.getElementById('native-cue-style');
+ if (styleElement) return; //Already set
+
+ styleElement = document.createElement('style');
+ styleElement.id = 'native-cue-style';
+ document.head.appendChild(styleElement);
+ var stylesheet = styleElement.sheet;
+ if (video.id) {
+ stylesheet.insertRule('#' + video.id + '::cue {background: transparent}', 0);
+ } else if (video.classList.length !== 0) {
+ stylesheet.insertRule('.' + video.className + '::cue {background: transparent}', 0);
+ } else {
+ stylesheet.insertRule('video::cue {background: transparent}', 0);
+ }
+ }
+
+ /* Remove the extra cue style with transparent background for native cues. */
+ function removeNativeCueStyle() {
+ if (!isChrome) return;
+ var styleElement = document.getElementById('native-cue-style');
+ if (styleElement) {
+ document.head.removeChild(styleElement);
+ }
+ }
+
+ function clearCaptionContainer() {
+ if (captionContainer) {
+ while (captionContainer.firstChild) {
+ captionContainer.removeChild(captionContainer.firstChild);
+ }
+ }
+ }
+
+ function setConfig(config) {
+ if (!config) return;
+
+ if (config.videoModel) {
+ videoModel = config.videoModel;
+ }
+ }
+
+ instance = {
+ initialize: initialize,
+ displayCConTop: displayCConTop,
+ addTextTrack: addTextTrack,
+ addCaptions: addCaptions,
+ getTextTrack: getTextTrack,
+ getCurrentTextTrack: getCurrentTextTrack,
+ getCurrentTrackIdx: getCurrentTrackIdx,
+ setCurrentTrackIdx: setCurrentTrackIdx,
+ getTrackIdxForId: getTrackIdxForId,
+ deleteTrackCues: deleteTrackCues,
+ deleteAllTextTracks: deleteAllTextTracks,
+ deleteTextTrack: deleteTextTrack,
+ setConfig: setConfig
+ };
+
+ return instance;
+}
+
+TextTracks.__dashjs_factory_name = 'TextTracks';
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(TextTracks);
+module.exports = exports['default'];
+
+},{"10":10,"13":13,"8":8,"9":9}],58:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
+
+var _voMetricsHTTPRequest = _dereq_(179);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _modelsMediaPlayerModel = _dereq_(101);
+
+var _modelsMediaPlayerModel2 = _interopRequireDefault(_modelsMediaPlayerModel);
+
+var _utilsErrorHandlerJs = _dereq_(151);
+
+var _utilsErrorHandlerJs2 = _interopRequireDefault(_utilsErrorHandlerJs);
+
+/**
+ * @module XHRLoader
+ * @description Manages download of resources via HTTP.
+ * @param {Object} cfg - dependancies from parent
+ */
+function XHRLoader(cfg) {
+ var context = this.context;
+
+ //const log = Debug(context).getInstance().log;
+ var mediaPlayerModel = (0, _modelsMediaPlayerModel2['default'])(context).getInstance();
+
+ var errHandler = cfg.errHandler;
+ var metricsModel = cfg.metricsModel;
+ var requestModifier = cfg.requestModifier;
+
+ var instance = undefined;
+ var xhrs = undefined;
+ var delayedXhrs = undefined;
+ var retryTimers = undefined;
+ var downloadErrorToRequestTypeMap = undefined;
+
+ function setup() {
+ var _downloadErrorToRequestTypeMap;
+
+ xhrs = [];
+ delayedXhrs = [];
+ retryTimers = [];
+
+ downloadErrorToRequestTypeMap = (_downloadErrorToRequestTypeMap = {}, _defineProperty(_downloadErrorToRequestTypeMap, _voMetricsHTTPRequest.HTTPRequest.MPD_TYPE, _utilsErrorHandlerJs2['default'].DOWNLOAD_ERROR_ID_MANIFEST), _defineProperty(_downloadErrorToRequestTypeMap, _voMetricsHTTPRequest.HTTPRequest.XLINK_EXPANSION_TYPE, _utilsErrorHandlerJs2['default'].DOWNLOAD_ERROR_ID_XLINK), _defineProperty(_downloadErrorToRequestTypeMap, _voMetricsHTTPRequest.HTTPRequest.INIT_SEGMENT_TYPE, _utilsErrorHandlerJs2['default'].DOWNLOAD_ERROR_ID_INITIALIZATION), _defineProperty(_downloadErrorToRequestTypeMap, _voMetricsHTTPRequest.HTTPRequest.MEDIA_SEGMENT_TYPE, _utilsErrorHandlerJs2['default'].DOWNLOAD_ERROR_ID_CONTENT), _defineProperty(_downloadErrorToRequestTypeMap, _voMetricsHTTPRequest.HTTPRequest.INDEX_SEGMENT_TYPE, _utilsErrorHandlerJs2['default'].DOWNLOAD_ERROR_ID_CONTENT), _defineProperty(_downloadErrorToRequestTypeMap, _voMetricsHTTPRequest.HTTPRequest.BITSTREAM_SWITCHING_SEGMENT_TYPE, _utilsErrorHandlerJs2['default'].DOWNLOAD_ERROR_ID_CONTENT), _defineProperty(_downloadErrorToRequestTypeMap, _voMetricsHTTPRequest.HTTPRequest.OTHER_TYPE, _utilsErrorHandlerJs2['default'].DOWNLOAD_ERROR_ID_CONTENT), _downloadErrorToRequestTypeMap);
+ }
+
+ function internalLoad(config, remainingAttempts) {
+
+ var request = config.request;
+ var xhr = new XMLHttpRequest();
+ var traces = [];
+ var firstProgress = true;
+ var needFailureReport = true;
+ var requestStartTime = new Date();
+ var lastTraceTime = requestStartTime;
+ var lastTraceReceivedCount = 0;
+
+ var handleLoaded = function handleLoaded(success) {
+ needFailureReport = false;
+
+ request.requestStartDate = requestStartTime;
+ request.requestEndDate = new Date();
+ request.firstByteDate = request.firstByteDate || requestStartTime;
+
+ if (!request.checkExistenceOnly) {
+ metricsModel.addHttpRequest(request.mediaType, null, request.type, request.url, xhr.responseURL || null, request.serviceLocation || null, request.range || null, request.requestStartDate, request.firstByteDate, request.requestEndDate, xhr.status, request.duration, xhr.getAllResponseHeaders(), success ? traces : null);
+ }
+ };
+
+ var onloadend = function onloadend() {
+ if (xhrs.indexOf(xhr) === -1) {
+ return;
+ } else {
+ xhrs.splice(xhrs.indexOf(xhr), 1);
+ }
+
+ if (needFailureReport) {
+ handleLoaded(false);
+
+ if (remainingAttempts > 0) {
+ remainingAttempts--;
+ retryTimers.push(setTimeout(function () {
+ internalLoad(config, remainingAttempts);
+ }, mediaPlayerModel.getRetryIntervalForType(request.type)));
+ } else {
+ errHandler.downloadError(downloadErrorToRequestTypeMap[request.type], request.url, request);
+
+ if (config.error) {
+ config.error(request, 'error', xhr.statusText);
+ }
+
+ if (config.complete) {
+ config.complete(request, xhr.statusText);
+ }
+ }
+ }
+ };
+
+ var progress = function progress(event) {
+ var currentTime = new Date();
+
+ if (firstProgress) {
+ firstProgress = false;
+ if (!event.lengthComputable || event.lengthComputable && event.total !== event.loaded) {
+ request.firstByteDate = currentTime;
+ }
+ }
+
+ if (event.lengthComputable) {
+ request.bytesLoaded = event.loaded;
+ request.bytesTotal = event.total;
+ }
+
+ traces.push({
+ s: lastTraceTime,
+ d: currentTime.getTime() - lastTraceTime.getTime(),
+ b: [event.loaded ? event.loaded - lastTraceReceivedCount : 0]
+ });
+
+ lastTraceTime = currentTime;
+ lastTraceReceivedCount = event.loaded;
+
+ if (config.progress) {
+ config.progress();
+ }
+ };
+
+ var onload = function onload() {
+ if (xhr.status >= 200 && xhr.status <= 299) {
+ handleLoaded(true);
+
+ if (config.success) {
+ config.success(xhr.response, xhr.statusText, xhr);
+ }
+
+ if (config.complete) {
+ config.complete(request, xhr.statusText);
+ }
+ }
+ };
+
+ try {
+ var modifiedUrl = requestModifier.modifyRequestURL(request.url);
+ var verb = request.checkExistenceOnly ? 'HEAD' : 'GET';
+
+ xhr.open(verb, modifiedUrl, true);
+
+ if (request.responseType) {
+ xhr.responseType = request.responseType;
+ }
+
+ if (request.range) {
+ xhr.setRequestHeader('Range', 'bytes=' + request.range);
+ }
+
+ if (!request.requestStartDate) {
+ request.requestStartDate = requestStartTime;
+ }
+
+ xhr = requestModifier.modifyRequestHeader(xhr);
+
+ xhr.withCredentials = mediaPlayerModel.getXHRWithCredentials();
+
+ xhr.onload = onload;
+ xhr.onloadend = onloadend;
+ xhr.onerror = onloadend;
+ xhr.onprogress = progress;
+
+ // Adds the ability to delay single fragment loading time to control buffer.
+ var now = new Date().getTime();
+ if (isNaN(request.delayLoadingTime) || now >= request.delayLoadingTime) {
+ // no delay - just send xhr
+
+ xhrs.push(xhr);
+ xhr.send();
+ } else {
+ (function () {
+ // delay
+ var delayedXhr = { xhr: xhr };
+ delayedXhrs.push(delayedXhr);
+ delayedXhr.delayTimeout = setTimeout(function () {
+ if (delayedXhrs.indexOf(delayedXhr) === -1) {
+ return;
+ } else {
+ delayedXhrs.splice(delayedXhrs.indexOf(delayedXhr), 1);
+ }
+ try {
+ xhrs.push(delayedXhr.xhr);
+ delayedXhr.xhr.send();
+ } catch (e) {
+ delayedXhr.xhr.onerror();
+ }
+ }, request.delayLoadingTime - now);
+ })();
+ }
+ } catch (e) {
+ xhr.onerror();
+ }
+ }
+
+ /**
+ * Initiates a download of the resource described by config.request
+ * @param {Object} config - contains request (FragmentRequest or derived type), and callbacks
+ * @memberof module:XHRLoader
+ * @instance
+ */
+ function load(config) {
+ if (config.request) {
+ internalLoad(config, mediaPlayerModel.getRetryAttemptsForType(config.request.type));
+ }
+ }
+
+ /**
+ * Aborts any inflight downloads
+ * @memberof module:XHRLoader
+ * @instance
+ */
+ function abort() {
+ retryTimers.forEach(function (t) {
+ return clearTimeout(t);
+ });
+ retryTimers = [];
+
+ delayedXhrs.forEach(function (x) {
+ return clearTimeout(x.delayTimeout);
+ });
+ delayedXhrs = [];
+
+ xhrs.forEach(function (x) {
+ // abort will trigger onloadend which we don't want
+ // when deliberately aborting inflight requests -
+ // set them to undefined so they are not called
+ x.onloadend = x.onerror = x.onprogress = undefined;
+ x.abort();
+ });
+ xhrs = [];
+ }
+
+ instance = {
+ load: load,
+ abort: abort
+ };
+
+ setup();
+
+ return instance;
+}
+
+XHRLoader.__dashjs_factory_name = 'XHRLoader';
+
+var factory = _coreFactoryMaker2['default'].getClassFactory(XHRLoader);
+exports['default'] = factory;
+module.exports = exports['default'];
+
+},{"10":10,"101":101,"151":151,"179":179}],59:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _voError = _dereq_(162);
+
+var _voError2 = _interopRequireDefault(_voError);
+
+var _XHRLoader = _dereq_(58);
+
+var _XHRLoader2 = _interopRequireDefault(_XHRLoader);
+
+var _voMetricsHTTPRequest = _dereq_(179);
+
+var _voTextRequest = _dereq_(170);
+
+var _voTextRequest2 = _interopRequireDefault(_voTextRequest);
+
+var _coreEventBus = _dereq_(9);
+
+var _coreEventBus2 = _interopRequireDefault(_coreEventBus);
+
+var _coreEventsEvents = _dereq_(13);
+
+var _coreEventsEvents2 = _interopRequireDefault(_coreEventsEvents);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var XLINK_LOADER_ERROR_LOADING_FAILURE = 1;
+
+function XlinkLoader(config) {
+
+ var RESOLVE_TO_ZERO = 'urn:mpeg:dash:resolve-to-zero:2013';
+
+ var context = this.context;
+ var eventBus = (0, _coreEventBus2['default'])(context).getInstance();
+
+ var xhrLoader = (0, _XHRLoader2['default'])(context).create({
+ errHandler: config.errHandler,
+ metricsModel: config.metricsModel,
+ requestModifier: config.requestModifier
+ });
+
+ var instance = undefined;
+
+ function load(url, element, resolveObject) {
+ var report = function report(content, resolveToZero) {
+ element.resolved = true;
+ element.resolvedContent = content ? content : null;
+
+ eventBus.trigger(_coreEventsEvents2['default'].XLINK_ELEMENT_LOADED, {
+ element: element,
+ resolveObject: resolveObject,
+ error: content || resolveToZero ? null : new _voError2['default'](XLINK_LOADER_ERROR_LOADING_FAILURE, 'Failed loading Xlink element: ' + url)
+ });
+ };
+
+ if (url === RESOLVE_TO_ZERO) {
+ report(null, true);
+ } else {
+ var request = new _voTextRequest2['default'](url, _voMetricsHTTPRequest.HTTPRequest.XLINK_TYPE);
+
+ xhrLoader.load({
+ request: request,
+ success: function success(data) {
+ report(data);
+ },
+ error: function error() {
+ report(null);
+ }
+ });
+ }
+ }
+
+ function reset() {
+ if (xhrLoader) {
+ xhrLoader.abort();
+ xhrLoader = null;
+ }
+ }
+
+ instance = {
+ load: load,
+ reset: reset
+ };
+
+ return instance;
+}
+
+XlinkLoader.__dashjs_factory_name = 'XlinkLoader';
+
+var factory = _coreFactoryMaker2['default'].getClassFactory(XlinkLoader);
+factory.XLINK_LOADER_ERROR_LOADING_FAILURE = XLINK_LOADER_ERROR_LOADING_FAILURE;
+exports['default'] = factory;
+module.exports = exports['default'];
+
+},{"10":10,"13":13,"162":162,"170":170,"179":179,"58":58,"9":9}],60:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _rulesSwitchRequest = _dereq_(130);
+
+var _rulesSwitchRequest2 = _interopRequireDefault(_rulesSwitchRequest);
+
+var _voBitrateInfo = _dereq_(160);
+
+var _voBitrateInfo2 = _interopRequireDefault(_voBitrateInfo);
+
+var _utilsDOMStorage = _dereq_(149);
+
+var _utilsDOMStorage2 = _interopRequireDefault(_utilsDOMStorage);
+
+var _rulesAbrABRRulesCollection = _dereq_(131);
+
+var _rulesAbrABRRulesCollection2 = _interopRequireDefault(_rulesAbrABRRulesCollection);
+
+var _modelsMediaPlayerModel = _dereq_(101);
+
+var _modelsMediaPlayerModel2 = _interopRequireDefault(_modelsMediaPlayerModel);
+
+var _modelsFragmentModel = _dereq_(99);
+
+var _modelsFragmentModel2 = _interopRequireDefault(_modelsFragmentModel);
+
+var _coreEventBus = _dereq_(9);
+
+var _coreEventBus2 = _interopRequireDefault(_coreEventBus);
+
+var _coreEventsEvents = _dereq_(13);
+
+var _coreEventsEvents2 = _interopRequireDefault(_coreEventsEvents);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _modelsManifestModel = _dereq_(100);
+
+var _modelsManifestModel2 = _interopRequireDefault(_modelsManifestModel);
+
+var _dashModelsDashManifestModel = _dereq_(22);
+
+var _dashModelsDashManifestModel2 = _interopRequireDefault(_dashModelsDashManifestModel);
+
+var _modelsVideoModel = _dereq_(104);
+
+var _modelsVideoModel2 = _interopRequireDefault(_modelsVideoModel);
+
+var ABANDON_LOAD = 'abandonload';
+var ALLOW_LOAD = 'allowload';
+var DEFAULT_VIDEO_BITRATE = 1000;
+var DEFAULT_AUDIO_BITRATE = 100;
+var QUALITY_DEFAULT = 0;
+
+function AbrController() {
+
+ var context = this.context;
+ var eventBus = (0, _coreEventBus2['default'])(context).getInstance();
+
+ var instance = undefined,
+ abrRulesCollection = undefined,
+ rulesController = undefined,
+ streamController = undefined,
+ autoSwitchBitrate = undefined,
+ topQualities = undefined,
+ qualityDict = undefined,
+ confidenceDict = undefined,
+ bitrateDict = undefined,
+ ratioDict = undefined,
+ averageThroughputDict = undefined,
+ streamProcessorDict = undefined,
+ abandonmentStateDict = undefined,
+ abandonmentTimeout = undefined,
+ limitBitrateByPortal = undefined,
+ usePixelRatioInLimitBitrateByPortal = undefined,
+ manifestModel = undefined,
+ dashManifestModel = undefined,
+ videoModel = undefined,
+ mediaPlayerModel = undefined,
+ domStorage = undefined;
+
+ function setup() {
+ autoSwitchBitrate = { video: true, audio: true };
+ topQualities = {};
+ qualityDict = {};
+ confidenceDict = {};
+ bitrateDict = {};
+ ratioDict = {};
+ averageThroughputDict = {};
+ abandonmentStateDict = {};
+ streamProcessorDict = {};
+ limitBitrateByPortal = false;
+ usePixelRatioInLimitBitrateByPortal = false;
+ domStorage = (0, _utilsDOMStorage2['default'])(context).getInstance();
+ mediaPlayerModel = (0, _modelsMediaPlayerModel2['default'])(context).getInstance();
+ manifestModel = (0, _modelsManifestModel2['default'])(context).getInstance();
+ dashManifestModel = (0, _dashModelsDashManifestModel2['default'])(context).getInstance();
+ videoModel = (0, _modelsVideoModel2['default'])(context).getInstance();
+ }
+
+ function initialize(type, streamProcessor) {
+ streamProcessorDict[type] = streamProcessor;
+ abandonmentStateDict[type] = abandonmentStateDict[type] || {};
+ abandonmentStateDict[type].state = ALLOW_LOAD;
+ eventBus.on(_coreEventsEvents2['default'].LOADING_PROGRESS, onFragmentLoadProgress, this);
+ }
+
+ function setConfig(config) {
+ if (!config) return;
+
+ if (config.abrRulesCollection) {
+ abrRulesCollection = config.abrRulesCollection;
+ }
+ if (config.rulesController) {
+ rulesController = config.rulesController;
+ }
+ if (config.streamController) {
+ streamController = config.streamController;
+ }
+ }
+
+ function getTopQualityIndexFor(type, id) {
+ var idx;
+ topQualities[id] = topQualities[id] || {};
+
+ if (!topQualities[id].hasOwnProperty(type)) {
+ topQualities[id][type] = 0;
+ }
+
+ idx = checkMaxBitrate(topQualities[id][type], type);
+ idx = checkMaxRepresentationRatio(idx, type, topQualities[id][type]);
+ idx = checkPortalSize(idx, type);
+ return idx;
+ }
+
+ /**
+ * @param {string} type
+ * @returns {number} A value of the initial bitrate, kbps
+ * @memberof AbrController#
+ */
+ function getInitialBitrateFor(type) {
+
+ var savedBitrate = domStorage.getSavedBitrateSettings(type);
+
+ if (!bitrateDict.hasOwnProperty(type)) {
+ if (ratioDict.hasOwnProperty(type)) {
+ var manifest = manifestModel.getValue();
+ var representation = dashManifestModel.getAdaptationForType(manifest, 0, type).Representation;
+
+ if (Array.isArray(representation)) {
+ var repIdx = Math.max(Math.round(representation.length * ratioDict[type]) - 1, 0);
+ bitrateDict[type] = representation[repIdx].bandwidth;
+ } else {
+ bitrateDict[type] = 0;
+ }
+ } else if (!isNaN(savedBitrate)) {
+ bitrateDict[type] = savedBitrate;
+ } else {
+ bitrateDict[type] = type === 'video' ? DEFAULT_VIDEO_BITRATE : DEFAULT_AUDIO_BITRATE;
+ }
+ }
+
+ return bitrateDict[type];
+ }
+
+ /**
+ * @param {string} type
+ * @param {number} value A value of the initial bitrate, kbps
+ * @memberof AbrController#
+ */
+ function setInitialBitrateFor(type, value) {
+ bitrateDict[type] = value;
+ }
+
+ function getInitialRepresentationRatioFor(type) {
+ if (!ratioDict.hasOwnProperty(type)) {
+ return null;
+ }
+
+ return ratioDict[type];
+ }
+
+ function setInitialRepresentationRatioFor(type, value) {
+ ratioDict[type] = value;
+ }
+
+ function getMaxAllowedBitrateFor(type) {
+ if (bitrateDict.hasOwnProperty('max') && bitrateDict.max.hasOwnProperty(type)) {
+ return bitrateDict.max[type];
+ }
+ return NaN;
+ }
+
+ //TODO change bitrateDict structure to hold one object for video and audio with initial and max values internal.
+ // This means you need to update all the logic around initial bitrate DOMStorage, RebController etc...
+ function setMaxAllowedBitrateFor(type, value) {
+ bitrateDict.max = bitrateDict.max || {};
+ bitrateDict.max[type] = value;
+ }
+
+ function getMaxAllowedRepresentationRatioFor(type) {
+ if (ratioDict.hasOwnProperty('max') && ratioDict.max.hasOwnProperty(type)) {
+ return ratioDict.max[type];
+ }
+ return 1;
+ }
+
+ function setMaxAllowedRepresentationRatioFor(type, value) {
+ ratioDict.max = ratioDict.max || {};
+ ratioDict.max[type] = value;
+ }
+
+ function getAutoSwitchBitrateFor(type) {
+ return autoSwitchBitrate[type];
+ }
+
+ function setAutoSwitchBitrateFor(type, value) {
+ autoSwitchBitrate[type] = value;
+ }
+
+ function getLimitBitrateByPortal() {
+ return limitBitrateByPortal;
+ }
+
+ function setLimitBitrateByPortal(value) {
+ limitBitrateByPortal = value;
+ }
+
+ function getUsePixelRatioInLimitBitrateByPortal() {
+ return usePixelRatioInLimitBitrateByPortal;
+ }
+
+ function setUsePixelRatioInLimitBitrateByPortal(value) {
+ usePixelRatioInLimitBitrateByPortal = value;
+ }
+
+ function getPlaybackQuality(streamProcessor, completedCallback) {
+
+ var type = streamProcessor.getType();
+ var streamInfo = streamProcessor.getStreamInfo();
+ var streamId = streamInfo.id;
+
+ var callback = function callback(res) {
+
+ var topQualityIdx = getTopQualityIndexFor(type, streamId);
+
+ var newQuality = res.value;
+ if (newQuality < 0) {
+ newQuality = 0;
+ }
+ if (newQuality > topQualityIdx) {
+ newQuality = topQualityIdx;
+ }
+
+ var oldQuality = getQualityFor(type, streamInfo);
+ if (newQuality !== oldQuality && (abandonmentStateDict[type].state === ALLOW_LOAD || newQuality > oldQuality)) {
+ setConfidenceFor(type, streamId, res.confidence);
+ changeQuality(type, streamInfo, oldQuality, newQuality, res.reason);
+ }
+ if (completedCallback) {
+ completedCallback();
+ }
+ };
+
+ //log("ABR enabled? (" + autoSwitchBitrate + ")");
+ if (!getAutoSwitchBitrateFor(type)) {
+ if (completedCallback) {
+ completedCallback();
+ }
+ } else {
+ var rules = abrRulesCollection.getRules(_rulesAbrABRRulesCollection2['default'].QUALITY_SWITCH_RULES);
+ rulesController.applyRules(rules, streamProcessor, callback, getQualityFor(type, streamInfo), function (currentValue, newValue) {
+ currentValue = currentValue === _rulesSwitchRequest2['default'].NO_CHANGE ? 0 : currentValue;
+ return Math.max(currentValue, newValue);
+ });
+ }
+ }
+
+ function setPlaybackQuality(type, streamInfo, newQuality, reason) {
+ var id = streamInfo.id;
+ var oldQuality = getQualityFor(type, streamInfo);
+ var isInt = newQuality !== null && !isNaN(newQuality) && newQuality % 1 === 0;
+
+ if (!isInt) throw new Error('argument is not an integer');
+
+ if (newQuality !== oldQuality && newQuality >= 0 && newQuality <= getTopQualityIndexFor(type, id)) {
+ changeQuality(type, streamInfo, oldQuality, newQuality, reason);
+ }
+ }
+
+ function changeQuality(type, streamInfo, oldQuality, newQuality, reason) {
+ setQualityFor(type, streamInfo.id, newQuality);
+ eventBus.trigger(_coreEventsEvents2['default'].QUALITY_CHANGE_REQUESTED, { mediaType: type, streamInfo: streamInfo, oldQuality: oldQuality, newQuality: newQuality, reason: reason });
+ }
+
+ function setAbandonmentStateFor(type, state) {
+ abandonmentStateDict[type].state = state;
+ }
+
+ function getAbandonmentStateFor(type) {
+ return abandonmentStateDict[type].state;
+ }
+
+ /**
+ * @param {MediaInfo} mediaInfo
+ * @param {number} bitrate A bitrate value, kbps
+ * @returns {number} A quality index <= for the given bitrate
+ * @memberof AbrController#
+ */
+ function getQualityForBitrate(mediaInfo, bitrate) {
+
+ var bitrateList = getBitrateList(mediaInfo);
+
+ if (!bitrateList || bitrateList.length === 0) {
+ return QUALITY_DEFAULT;
+ }
+
+ for (var i = bitrateList.length - 1; i >= 0; i--) {
+ var bitrateInfo = bitrateList[i];
+ if (bitrate * 1000 >= bitrateInfo.bitrate) {
+ return i;
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * @param {MediaInfo} mediaInfo
+ * @returns {Array|null} A list of {@link BitrateInfo} objects
+ * @memberof AbrController#
+ */
+ function getBitrateList(mediaInfo) {
+ if (!mediaInfo || !mediaInfo.bitrateList) return null;
+
+ var bitrateList = mediaInfo.bitrateList;
+ var type = mediaInfo.type;
+
+ var infoList = [];
+ var bitrateInfo;
+
+ for (var i = 0, ln = bitrateList.length; i < ln; i++) {
+ bitrateInfo = new _voBitrateInfo2['default']();
+ bitrateInfo.mediaType = type;
+ bitrateInfo.qualityIndex = i;
+ bitrateInfo.bitrate = bitrateList[i].bandwidth;
+ bitrateInfo.width = bitrateList[i].width;
+ bitrateInfo.height = bitrateList[i].height;
+ infoList.push(bitrateInfo);
+ }
+
+ return infoList;
+ }
+
+ function setAverageThroughput(type, value) {
+ averageThroughputDict[type] = value;
+ }
+
+ function getAverageThroughput(type) {
+ return averageThroughputDict[type];
+ }
+
+ function updateTopQualityIndex(mediaInfo) {
+ var type = mediaInfo.type;
+ var streamId = mediaInfo.streamInfo.id;
+ var max = mediaInfo.representationCount - 1;
+
+ setTopQualityIndex(type, streamId, max);
+
+ return max;
+ }
+
+ function isPlayingAtTopQuality(streamInfo) {
+ var isAtTop;
+ var streamId = streamInfo.id;
+ var audioQuality = getQualityFor('audio', streamInfo);
+ var videoQuality = getQualityFor('video', streamInfo);
+
+ isAtTop = audioQuality === getTopQualityIndexFor('audio', streamId) && videoQuality === getTopQualityIndexFor('video', streamId);
+
+ return isAtTop;
+ }
+
+ function reset() {
+ eventBus.off(_coreEventsEvents2['default'].LOADING_PROGRESS, onFragmentLoadProgress, this);
+ clearTimeout(abandonmentTimeout);
+ abandonmentTimeout = null;
+ setup();
+ }
+
+ function getQualityFor(type, streamInfo) {
+ var id = streamInfo.id;
+ var quality;
+
+ qualityDict[id] = qualityDict[id] || {};
+
+ if (!qualityDict[id].hasOwnProperty(type)) {
+ qualityDict[id][type] = QUALITY_DEFAULT;
+ }
+
+ quality = qualityDict[id][type];
+ return quality;
+ }
+
+ function setQualityFor(type, id, value) {
+ qualityDict[id] = qualityDict[id] || {};
+ qualityDict[id][type] = value;
+ }
+
+ function getConfidenceFor(type, id) {
+ var confidence;
+
+ confidenceDict[id] = confidenceDict[id] || {};
+
+ if (!confidenceDict[id].hasOwnProperty(type)) {
+ confidenceDict[id][type] = 0;
+ }
+
+ confidence = confidenceDict[id][type];
+
+ return confidence;
+ }
+
+ function setConfidenceFor(type, id, value) {
+ confidenceDict[id] = confidenceDict[id] || {};
+ confidenceDict[id][type] = value;
+ }
+
+ function setTopQualityIndex(type, id, value) {
+ topQualities[id] = topQualities[id] || {};
+ topQualities[id][type] = value;
+ }
+
+ function checkMaxBitrate(idx, type) {
+ var maxBitrate = getMaxAllowedBitrateFor(type);
+ if (isNaN(maxBitrate) || !streamProcessorDict[type]) {
+ return idx;
+ }
+ var maxIdx = getQualityForBitrate(streamProcessorDict[type].getMediaInfo(), maxBitrate);
+ return Math.min(idx, maxIdx);
+ }
+
+ function checkMaxRepresentationRatio(idx, type, maxIdx) {
+ var maxRepresentationRatio = getMaxAllowedRepresentationRatioFor(type);
+ if (isNaN(maxRepresentationRatio) || maxRepresentationRatio >= 1 || maxRepresentationRatio < 0) {
+ return idx;
+ }
+ return Math.min(idx, Math.round(maxIdx * maxRepresentationRatio));
+ }
+
+ function checkPortalSize(idx, type) {
+ if (type !== 'video' || !limitBitrateByPortal || !streamProcessorDict[type]) {
+ return idx;
+ }
+
+ var hasPixelRatio = usePixelRatioInLimitBitrateByPortal && window.hasOwnProperty('devicePixelRatio');
+ var pixelRatio = hasPixelRatio ? window.devicePixelRatio : 1;
+ var element = videoModel.getElement();
+ var elementWidth = element.clientWidth * pixelRatio;
+ var elementHeight = element.clientHeight * pixelRatio;
+ var manifest = manifestModel.getValue();
+ var representation = dashManifestModel.getAdaptationForType(manifest, 0, type).Representation;
+ var newIdx = idx;
+
+ if (elementWidth > 0 && elementHeight > 0) {
+ while (newIdx > 0 && representation[newIdx] && elementWidth < representation[newIdx].width && elementWidth - representation[newIdx - 1].width < representation[newIdx].width - elementWidth) {
+ newIdx = newIdx - 1;
+ }
+
+ if (representation.length - 2 >= newIdx && representation[newIdx].width === representation[newIdx + 1].width) {
+ newIdx = Math.min(idx, newIdx + 1);
+ }
+ }
+
+ return newIdx;
+ }
+
+ function onFragmentLoadProgress(e) {
+ var type = e.request.mediaType;
+ if (getAutoSwitchBitrateFor(type)) {
+ var _ret = (function () {
+
+ var rules = abrRulesCollection.getRules(_rulesAbrABRRulesCollection2['default'].ABANDON_FRAGMENT_RULES);
+ var scheduleController = streamProcessorDict[type].getScheduleController();
+ if (!scheduleController) return {
+ v: undefined
+ }; // There may be a fragment load in progress when we switch periods and recreated some controllers.
+
+ var callback = function callback(switchRequest) {
+ if (switchRequest.confidence === _rulesSwitchRequest2['default'].STRONG && switchRequest.value < getQualityFor(type, streamController.getActiveStreamInfo())) {
+
+ var fragmentModel = scheduleController.getFragmentModel();
+ var request = fragmentModel.getRequests({ state: _modelsFragmentModel2['default'].FRAGMENT_MODEL_LOADING, index: e.request.index })[0];
+ if (request) {
+ //TODO Check if we should abort or if better to finish download. check bytesLoaded/Total
+ fragmentModel.abortRequests();
+ setAbandonmentStateFor(type, ABANDON_LOAD);
+ setPlaybackQuality(type, streamController.getActiveStreamInfo(), switchRequest.value, switchRequest.reason);
+ eventBus.trigger(_coreEventsEvents2['default'].FRAGMENT_LOADING_ABANDONED, { streamProcessor: streamProcessorDict[type], request: request, mediaType: type });
+
+ clearTimeout(abandonmentTimeout);
+ abandonmentTimeout = setTimeout(function () {
+ setAbandonmentStateFor(type, ALLOW_LOAD);
+ abandonmentTimeout = null;
+ }, mediaPlayerModel.getAbandonLoadTimeout());
+ }
+ }
+ };
+
+ rulesController.applyRules(rules, streamProcessorDict[type], callback, e, function (currentValue, newValue) {
+ return newValue;
+ });
+ })();
+
+ if (typeof _ret === 'object') return _ret.v;
+ }
+ }
+
+ instance = {
+ isPlayingAtTopQuality: isPlayingAtTopQuality,
+ updateTopQualityIndex: updateTopQualityIndex,
+ getAverageThroughput: getAverageThroughput,
+ getBitrateList: getBitrateList,
+ getQualityForBitrate: getQualityForBitrate,
+ getMaxAllowedBitrateFor: getMaxAllowedBitrateFor,
+ setMaxAllowedBitrateFor: setMaxAllowedBitrateFor,
+ getMaxAllowedRepresentationRatioFor: getMaxAllowedRepresentationRatioFor,
+ setMaxAllowedRepresentationRatioFor: setMaxAllowedRepresentationRatioFor,
+ getInitialBitrateFor: getInitialBitrateFor,
+ setInitialBitrateFor: setInitialBitrateFor,
+ getInitialRepresentationRatioFor: getInitialRepresentationRatioFor,
+ setInitialRepresentationRatioFor: setInitialRepresentationRatioFor,
+ setAutoSwitchBitrateFor: setAutoSwitchBitrateFor,
+ getAutoSwitchBitrateFor: getAutoSwitchBitrateFor,
+ setLimitBitrateByPortal: setLimitBitrateByPortal,
+ getLimitBitrateByPortal: getLimitBitrateByPortal,
+ getUsePixelRatioInLimitBitrateByPortal: getUsePixelRatioInLimitBitrateByPortal,
+ setUsePixelRatioInLimitBitrateByPortal: setUsePixelRatioInLimitBitrateByPortal,
+ getConfidenceFor: getConfidenceFor,
+ getQualityFor: getQualityFor,
+ getAbandonmentStateFor: getAbandonmentStateFor,
+ setAbandonmentStateFor: setAbandonmentStateFor,
+ setPlaybackQuality: setPlaybackQuality,
+ getPlaybackQuality: getPlaybackQuality,
+ setAverageThroughput: setAverageThroughput,
+ getTopQualityIndexFor: getTopQualityIndexFor,
+ initialize: initialize,
+ setConfig: setConfig,
+ reset: reset
+ };
+
+ setup();
+
+ return instance;
+}
+
+AbrController.__dashjs_factory_name = 'AbrController';
+var factory = _coreFactoryMaker2['default'].getSingletonFactory(AbrController);
+factory.ABANDON_LOAD = ABANDON_LOAD;
+factory.QUALITY_DEFAULT = QUALITY_DEFAULT;
+exports['default'] = factory;
+module.exports = exports['default'];
+
+},{"10":10,"100":100,"101":101,"104":104,"13":13,"130":130,"131":131,"149":149,"160":160,"22":22,"9":9,"99":99}],61:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _modelsBaseURLTreeModel = _dereq_(98);
+
+var _modelsBaseURLTreeModel2 = _interopRequireDefault(_modelsBaseURLTreeModel);
+
+var _utilsBaseURLSelector = _dereq_(145);
+
+var _utilsBaseURLSelector2 = _interopRequireDefault(_utilsBaseURLSelector);
+
+var _utilsURLUtils = _dereq_(158);
+
+var _utilsURLUtils2 = _interopRequireDefault(_utilsURLUtils);
+
+var _dashVoBaseURL = _dereq_(40);
+
+var _dashVoBaseURL2 = _interopRequireDefault(_dashVoBaseURL);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _coreEventBus = _dereq_(9);
+
+var _coreEventBus2 = _interopRequireDefault(_coreEventBus);
+
+var _coreEventsEvents = _dereq_(13);
+
+var _coreEventsEvents2 = _interopRequireDefault(_coreEventsEvents);
+
+function BaseURLController() {
+
+ var instance = undefined;
+
+ var context = this.context;
+ var eventBus = (0, _coreEventBus2['default'])(context).getInstance();
+ var urlUtils = (0, _utilsURLUtils2['default'])(context).getInstance();
+
+ var baseURLTreeModel = undefined,
+ baseURLSelector = undefined;
+
+ function onBlackListChanged(e) {
+ baseURLTreeModel.invalidateSelectedIndexes(e.entry);
+ }
+
+ function setup() {
+ baseURLTreeModel = (0, _modelsBaseURLTreeModel2['default'])(context).create();
+ baseURLSelector = (0, _utilsBaseURLSelector2['default'])(context).create();
+
+ eventBus.on(_coreEventsEvents2['default'].SERVICE_LOCATION_BLACKLIST_CHANGED, onBlackListChanged, instance);
+ }
+
+ function update(manifest) {
+ baseURLTreeModel.update(manifest);
+ baseURLSelector.chooseSelectorFromManifest(manifest);
+ }
+
+ function resolve(path) {
+ var baseUrls = baseURLTreeModel.getForPath(path);
+
+ var baseUrl = baseUrls.reduce(function (p, c) {
+ var b = baseURLSelector.select(c);
+
+ if (b) {
+ if (!urlUtils.isRelative(b.url)) {
+ if (urlUtils.isPathAbsolute(b.url)) {
+ p.url = urlUtils.parseOrigin(p.url) + b.url;
+ } else {
+ p.url = b.url;
+ p.serviceLocation = b.serviceLocation;
+ }
+ } else {
+ p.url += b.url;
+ }
+ }
+
+ return p;
+ }, new _dashVoBaseURL2['default']());
+
+ if (!urlUtils.isRelative(baseUrl.url)) {
+ return baseUrl;
+ }
+ }
+
+ function reset() {
+ baseURLTreeModel.reset();
+ baseURLSelector.reset();
+ }
+
+ function initialize(data) {
+ update(data);
+ }
+
+ instance = {
+ reset: reset,
+ initialize: initialize,
+ resolve: resolve
+ };
+
+ setup();
+
+ return instance;
+}
+
+BaseURLController.__dashjs_factory_name = 'BaseURLController';
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(BaseURLController);
+module.exports = exports['default'];
+
+},{"10":10,"13":13,"145":145,"158":158,"40":40,"9":9,"98":98}],62:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _coreEventBus = _dereq_(9);
+
+var _coreEventBus2 = _interopRequireDefault(_coreEventBus);
+
+function BlackListController(config) {
+
+ var blacklist = [];
+
+ var eventBus = (0, _coreEventBus2['default'])(this.context).getInstance();
+ var updateEventName = config.updateEventName;
+ var loadFailedEventName = config.loadFailedEventName;
+
+ function contains(query) {
+ if (!blacklist.length || !query || !query.length) {
+ return false;
+ }
+
+ return blacklist.indexOf(query) !== -1;
+ }
+
+ function add(entry) {
+ if (blacklist.indexOf(entry) !== -1) {
+ return;
+ }
+
+ blacklist.push(entry);
+
+ eventBus.trigger(updateEventName, {
+ entry: entry
+ });
+ }
+
+ function onLoadFailed(e) {
+ if (e.error) {
+ add(e.request.serviceLocation);
+ }
+ }
+
+ function setup() {
+ if (loadFailedEventName) {
+ eventBus.on(loadFailedEventName, onLoadFailed, this);
+ }
+ }
+
+ function reset() {
+ blacklist = [];
+ }
+
+ setup();
+
+ return {
+ add: add,
+ contains: contains,
+ reset: reset
+ };
+}
+
+BlackListController.__dashjs_factory_name = 'BlackListController';
+exports['default'] = _coreFactoryMaker2['default'].getClassFactory(BlackListController);
+module.exports = exports['default'];
+
+},{"10":10,"9":9}],63:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _modelsFragmentModel = _dereq_(99);
+
+var _modelsFragmentModel2 = _interopRequireDefault(_modelsFragmentModel);
+
+var _modelsMediaPlayerModel = _dereq_(101);
+
+var _modelsMediaPlayerModel2 = _interopRequireDefault(_modelsMediaPlayerModel);
+
+var _SourceBufferController = _dereq_(70);
+
+var _SourceBufferController2 = _interopRequireDefault(_SourceBufferController);
+
+var _AbrController = _dereq_(60);
+
+var _AbrController2 = _interopRequireDefault(_AbrController);
+
+var _PlaybackController = _dereq_(68);
+
+var _PlaybackController2 = _interopRequireDefault(_PlaybackController);
+
+var _MediaController = _dereq_(66);
+
+var _MediaController2 = _interopRequireDefault(_MediaController);
+
+var _coreEventBus = _dereq_(9);
+
+var _coreEventBus2 = _interopRequireDefault(_coreEventBus);
+
+var _coreEventsEvents = _dereq_(13);
+
+var _coreEventsEvents2 = _interopRequireDefault(_coreEventsEvents);
+
+var _utilsBoxParser = _dereq_(146);
+
+var _utilsBoxParser2 = _interopRequireDefault(_utilsBoxParser);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _coreDebug = _dereq_(8);
+
+var _coreDebug2 = _interopRequireDefault(_coreDebug);
+
+var _utilsInitCache = _dereq_(152);
+
+var _utilsInitCache2 = _interopRequireDefault(_utilsInitCache);
+
+var BUFFER_LOADED = 'bufferLoaded';
+var BUFFER_EMPTY = 'bufferStalled';
+var STALL_THRESHOLD = 0.5;
+
+function BufferController(config) {
+
+ var context = this.context;
+ var log = (0, _coreDebug2['default'])(context).getInstance().log;
+ var eventBus = (0, _coreEventBus2['default'])(context).getInstance();
+ var metricsModel = config.metricsModel;
+ var manifestModel = config.manifestModel;
+ var sourceBufferController = config.sourceBufferController;
+ var errHandler = config.errHandler;
+ var streamController = config.streamController;
+ var mediaController = config.mediaController;
+ var adapter = config.adapter;
+ var textSourceBuffer = config.textSourceBuffer;
+
+ var instance = undefined,
+ requiredQuality = undefined,
+ isBufferingCompleted = undefined,
+ bufferLevel = undefined,
+ criticalBufferLevel = undefined,
+ mediaSource = undefined,
+ maxAppendedIndex = undefined,
+ lastIndex = undefined,
+ type = undefined,
+ buffer = undefined,
+ bufferState = undefined,
+ appendedBytesInfo = undefined,
+ wallclockTicked = undefined,
+ appendingMediaChunk = undefined,
+ isAppendingInProgress = undefined,
+ isPruningInProgress = undefined,
+ inbandEventFound = undefined,
+ playbackController = undefined,
+ streamProcessor = undefined,
+ abrController = undefined,
+ scheduleController = undefined,
+ mediaPlayerModel = undefined,
+ initCache = undefined;
+
+ function setup() {
+ requiredQuality = _AbrController2['default'].QUALITY_DEFAULT;
+ isBufferingCompleted = false;
+ bufferLevel = 0;
+ criticalBufferLevel = Number.POSITIVE_INFINITY;
+ maxAppendedIndex = 0;
+ lastIndex = 0;
+ buffer = null;
+ bufferState = BUFFER_EMPTY;
+ wallclockTicked = 0;
+ appendingMediaChunk = false;
+ isAppendingInProgress = false;
+ isPruningInProgress = false;
+ inbandEventFound = false;
+ }
+
+ function initialize(Type, Source, StreamProcessor) {
+ type = Type;
+ setMediaSource(Source);
+ streamProcessor = StreamProcessor;
+ mediaPlayerModel = (0, _modelsMediaPlayerModel2['default'])(context).getInstance();
+ playbackController = (0, _PlaybackController2['default'])(context).getInstance();
+ abrController = (0, _AbrController2['default'])(context).getInstance();
+ initCache = (0, _utilsInitCache2['default'])(context).getInstance();
+ scheduleController = streamProcessor.getScheduleController();
+ requiredQuality = abrController.getQualityFor(type, streamProcessor.getStreamInfo());
+
+ eventBus.on(_coreEventsEvents2['default'].DATA_UPDATE_COMPLETED, onDataUpdateCompleted, this);
+ eventBus.on(_coreEventsEvents2['default'].INIT_FRAGMENT_LOADED, onInitFragmentLoaded, this);
+ eventBus.on(_coreEventsEvents2['default'].MEDIA_FRAGMENT_LOADED, onMediaFragmentLoaded, this);
+ eventBus.on(_coreEventsEvents2['default'].QUALITY_CHANGE_REQUESTED, onQualityChanged, this);
+ eventBus.on(_coreEventsEvents2['default'].STREAM_COMPLETED, onStreamCompleted, this);
+ eventBus.on(_coreEventsEvents2['default'].PLAYBACK_PROGRESS, onPlaybackProgression, this);
+ eventBus.on(_coreEventsEvents2['default'].PLAYBACK_TIME_UPDATED, onPlaybackProgression, this);
+ eventBus.on(_coreEventsEvents2['default'].PLAYBACK_RATE_CHANGED, onPlaybackRateChanged, this);
+ eventBus.on(_coreEventsEvents2['default'].PLAYBACK_SEEKING, onPlaybackSeeking, this);
+ eventBus.on(_coreEventsEvents2['default'].WALLCLOCK_TIME_UPDATED, onWallclockTimeUpdated, this);
+ eventBus.on(_coreEventsEvents2['default'].CURRENT_TRACK_CHANGED, onCurrentTrackChanged, this, _coreEventBus2['default'].EVENT_PRIORITY_HIGH);
+ eventBus.on(_coreEventsEvents2['default'].SOURCEBUFFER_APPEND_COMPLETED, onAppended, this);
+ eventBus.on(_coreEventsEvents2['default'].SOURCEBUFFER_REMOVE_COMPLETED, onRemoved, this);
+ }
+
+ function createBuffer(mediaInfo) {
+ if (!mediaInfo || !mediaSource || !streamProcessor) return null;
+
+ var sourceBuffer = null;
+
+ try {
+ sourceBuffer = sourceBufferController.createSourceBuffer(mediaSource, mediaInfo);
+
+ if (sourceBuffer && sourceBuffer.hasOwnProperty('initialize')) {
+ sourceBuffer.initialize(type, this);
+ }
+ } catch (e) {
+ errHandler.mediaSourceError('Error creating ' + type + ' source buffer.');
+ }
+ setBuffer(sourceBuffer);
+ updateBufferTimestampOffset(streamProcessor.getRepresentationInfoForQuality(requiredQuality).MSETimeOffset);
+ return sourceBuffer;
+ }
+
+ function isActive() {
+ return streamProcessor.getStreamInfo().id === streamController.getActiveStreamInfo().id;
+ }
+
+ function onInitFragmentLoaded(e) {
+ if (e.fragmentModel !== streamProcessor.getFragmentModel()) return;
+ log('Init fragment finished loading saving to', type + '\'s init cache');
+ initCache.save(e.chunk);
+ appendToBuffer(e.chunk);
+ }
+
+ function switchInitData(streamId, quality) {
+ var chunk = initCache.extract(streamId, type, quality);
+ if (chunk) {
+ appendToBuffer(chunk);
+ } else {
+ eventBus.trigger(_coreEventsEvents2['default'].INIT_REQUESTED, { sender: instance });
+ }
+ }
+
+ function onMediaFragmentLoaded(e) {
+ if (e.fragmentModel !== streamProcessor.getFragmentModel()) return;
+
+ var chunk = e.chunk;
+ var bytes = chunk.bytes;
+ var quality = chunk.quality;
+ var currentRepresentation = streamProcessor.getRepresentationInfoForQuality(quality);
+ var manifest = manifestModel.getValue();
+ var eventStreamMedia = adapter.getEventsFor(manifest, currentRepresentation.mediaInfo, streamProcessor);
+ var eventStreamTrack = adapter.getEventsFor(manifest, currentRepresentation, streamProcessor);
+
+ if (eventStreamMedia.length > 0 || eventStreamTrack.length > 0) {
+ var request = streamProcessor.getFragmentModel().getRequests({
+ state: _modelsFragmentModel2['default'].FRAGMENT_MODEL_EXECUTED,
+ quality: quality,
+ index: chunk.index
+ })[0];
+ var events = handleInbandEvents(bytes, request, eventStreamMedia, eventStreamTrack);
+ streamProcessor.getEventController().addInbandEvents(events);
+ }
+
+ chunk.bytes = deleteInbandEvents(bytes);
+ appendToBuffer(chunk);
+ }
+
+ function appendToBuffer(chunk) {
+ isAppendingInProgress = true;
+ appendedBytesInfo = chunk;
+ sourceBufferController.append(buffer, chunk);
+
+ if (chunk.mediaInfo.type === 'video') {
+ if (chunk.mediaInfo.embeddedCaptions) {
+ textSourceBuffer.append(chunk.bytes, chunk);
+ }
+ }
+ }
+
+ function onAppended(e) {
+ if (buffer !== e.buffer) return;
+
+ if (e.error || !hasEnoughSpaceToAppend()) {
+ if (e.error.code === _SourceBufferController2['default'].QUOTA_EXCEEDED_ERROR_CODE) {
+ criticalBufferLevel = sourceBufferController.getTotalBufferedTime(buffer) * 0.8;
+ }
+ if (e.error.code === _SourceBufferController2['default'].QUOTA_EXCEEDED_ERROR_CODE || !hasEnoughSpaceToAppend()) {
+ eventBus.trigger(_coreEventsEvents2['default'].QUOTA_EXCEEDED, { sender: instance, criticalBufferLevel: criticalBufferLevel }); //Tells ScheduleController to stop scheduling.
+ clearBuffer(getClearRange()); // Then we clear the buffer and onCleared event will tell ScheduleController to start scheduling again.
+ }
+ return;
+ }
+
+ if (!isNaN(appendedBytesInfo.index)) {
+ maxAppendedIndex = Math.max(appendedBytesInfo.index, maxAppendedIndex);
+ checkIfBufferingCompleted();
+ }
+
+ var ranges = sourceBufferController.getAllRanges(buffer);
+ if (ranges && ranges.length > 0) {
+ for (var i = 0, len = ranges.length; i < len; i++) {
+ log('Buffered Range for type:', type, ':', ranges.start(i), ' - ', ranges.end(i));
+ }
+ }
+
+ onPlaybackProgression();
+ isAppendingInProgress = false;
+ eventBus.trigger(_coreEventsEvents2['default'].BYTES_APPENDED, {
+ sender: instance,
+ quality: appendedBytesInfo.quality,
+ startTime: appendedBytesInfo.start,
+ index: appendedBytesInfo.index,
+ bufferedRanges: ranges
+ });
+ }
+
+ function onQualityChanged(e) {
+ if (requiredQuality === e.newQuality || type !== e.mediaType || streamProcessor.getStreamInfo().id !== e.streamInfo.id) return;
+
+ updateBufferTimestampOffset(streamProcessor.getRepresentationInfoForQuality(e.newQuality).MSETimeOffset);
+ requiredQuality = e.newQuality;
+ }
+
+ //**********************************************************************
+ // START Buffer Level, State & Sufficiency Handling.
+ //**********************************************************************
+ function onPlaybackSeeking() {
+ lastIndex = 0;
+ isBufferingCompleted = false;
+ onPlaybackProgression();
+ }
+
+ function onPlaybackProgression() {
+ updateBufferLevel();
+ addBufferMetrics();
+ }
+
+ function updateBufferLevel() {
+ bufferLevel = sourceBufferController.getBufferLength(buffer, playbackController.getTime());
+ eventBus.trigger(_coreEventsEvents2['default'].BUFFER_LEVEL_UPDATED, { sender: instance, bufferLevel: bufferLevel });
+ checkIfSufficientBuffer();
+ }
+
+ function addBufferMetrics() {
+ if (!isActive()) return;
+ metricsModel.addBufferState(type, bufferState, scheduleController.getBufferTarget());
+ metricsModel.addBufferLevel(type, new Date(), bufferLevel * 1000);
+ }
+
+ function checkIfBufferingCompleted() {
+ var isLastIdxAppended = maxAppendedIndex === lastIndex - 1;
+ if (isLastIdxAppended && !isBufferingCompleted) {
+ isBufferingCompleted = true;
+ eventBus.trigger(_coreEventsEvents2['default'].BUFFERING_COMPLETED, { sender: instance, streamInfo: streamProcessor.getStreamInfo() });
+ }
+ }
+
+ function checkIfSufficientBuffer() {
+ if (bufferLevel < STALL_THRESHOLD && !isBufferingCompleted) {
+ notifyBufferStateChanged(BUFFER_EMPTY);
+ } else {
+ notifyBufferStateChanged(BUFFER_LOADED);
+ }
+ }
+
+ function notifyBufferStateChanged(state) {
+ if (bufferState === state || type === 'fragmentedText' && textSourceBuffer.getAllTracksAreDisabled()) return;
+ bufferState = state;
+ addBufferMetrics();
+ eventBus.trigger(_coreEventsEvents2['default'].BUFFER_LEVEL_STATE_CHANGED, { sender: instance, state: state, mediaType: type, streamInfo: streamProcessor.getStreamInfo() });
+ eventBus.trigger(state === BUFFER_LOADED ? _coreEventsEvents2['default'].BUFFER_LOADED : _coreEventsEvents2['default'].BUFFER_EMPTY, { mediaType: type });
+ log(state === BUFFER_LOADED ? 'Got enough buffer to start.' : 'Waiting for more buffer before starting playback.');
+ }
+
+ function handleInbandEvents(data, request, mediaInbandEvents, trackInbandEvents) {
+
+ var fragmentStartTime = Math.max(isNaN(request.startTime) ? 0 : request.startTime, 0);
+ var eventStreams = [];
+ var events = [];
+
+ inbandEventFound = false; //TODO Discuss why this is hear!
+ /* Extract the possible schemeIdUri : If a DASH client detects an event message box with a scheme that is not defined in MPD, the client is expected to ignore it */
+ var inbandEvents = mediaInbandEvents.concat(trackInbandEvents);
+ for (var i = 0, ln = inbandEvents.length; i < ln; i++) {
+ eventStreams[inbandEvents[i].schemeIdUri] = inbandEvents[i];
+ }
+
+ var isoFile = (0, _utilsBoxParser2['default'])(context).getInstance().parse(data);
+ var eventBoxes = isoFile.getBoxes('emsg');
+
+ for (var i = 0, ln = eventBoxes.length; i < ln; i++) {
+ var _event = adapter.getEvent(eventBoxes[i], eventStreams, fragmentStartTime);
+
+ if (_event) {
+ events.push(_event);
+ }
+ }
+
+ return events;
+ }
+
+ function deleteInbandEvents(data) {
+
+ if (!inbandEventFound) {
+ //TODO Discuss why this is here. inbandEventFound is never set to true!!
+ return data;
+ }
+
+ var length = data.length;
+ var expTwo = Math.pow(256, 2);
+ var expThree = Math.pow(256, 3);
+ var modData = new Uint8Array(data.length);
+
+ var i = 0;
+ var j = 0;
+
+ while (i < length) {
+
+ var identifier = String.fromCharCode(data[i + 4], data[i + 5], data[i + 6], data[i + 7]);
+ var size = data[i] * expThree + data[i + 1] * expTwo + data[i + 2] * 256 + data[i + 3] * 1;
+
+ if (identifier != 'emsg') {
+ for (var l = i; l < i + size; l++) {
+ modData[j] = data[l];
+ j++;
+ }
+ }
+ i += size;
+ }
+
+ return modData.subarray(0, j);
+ }
+
+ function hasEnoughSpaceToAppend() {
+ var totalBufferedTime = sourceBufferController.getTotalBufferedTime(buffer);
+ return totalBufferedTime < criticalBufferLevel;
+ }
+
+ /* prune buffer on our own in background to avoid browsers pruning buffer silently */
+ function pruneBuffer() {
+ if (type === 'fragmentedText') return;
+ var start = buffer.buffered.length ? buffer.buffered.start(0) : 0;
+ var bufferToPrune = playbackController.getTime() - start - mediaPlayerModel.getBufferToKeep();
+ if (bufferToPrune > 0) {
+ log('pruning buffer: ' + bufferToPrune + ' seconds.');
+ isPruningInProgress = true;
+ sourceBufferController.remove(buffer, 0, Math.round(start + bufferToPrune), mediaSource);
+ }
+ }
+
+ function getClearRange() {
+
+ if (!buffer) return null;
+
+ // we need to remove data that is more than one fragment before the video currentTime
+ var currentTime = playbackController.getTime();
+ var req = streamProcessor.getFragmentModel().getRequests({ state: _modelsFragmentModel2['default'].FRAGMENT_MODEL_EXECUTED, time: currentTime })[0];
+ var range = sourceBufferController.getBufferRange(buffer, currentTime);
+
+ var removeEnd = req && !isNaN(req.startTime) ? req.startTime : Math.floor(currentTime);
+ if (range === null && buffer.buffered.length > 0) {
+ removeEnd = buffer.buffered.end(buffer.buffered.length - 1);
+ }
+
+ return { start: buffer.buffered.start(0), end: removeEnd };
+ }
+
+ function clearBuffer(range) {
+ if (!range || !buffer) return;
+ sourceBufferController.remove(buffer, range.start, range.end, mediaSource);
+ }
+
+ function onRemoved(e) {
+ if (buffer !== e.buffer) return;
+
+ if (isPruningInProgress) {
+ isPruningInProgress = false;
+ }
+
+ updateBufferLevel();
+ eventBus.trigger(_coreEventsEvents2['default'].BUFFER_CLEARED, { sender: instance, from: e.from, to: e.to, hasEnoughSpaceToAppend: hasEnoughSpaceToAppend() });
+ //TODO - REMEMBER removed a timerout hack calling clearBuffer after manifestInfo.minBufferTime * 1000 if !hasEnoughSpaceToAppend() Aug 04 2016
+ }
+
+ function updateBufferTimestampOffset(MSETimeOffset) {
+ // Each track can have its own @presentationTimeOffset, so we should set the offset
+ // if it has changed after switching the quality or updating an mpd
+ if (buffer && buffer.timestampOffset !== MSETimeOffset && !isNaN(MSETimeOffset)) {
+ buffer.timestampOffset = MSETimeOffset;
+ }
+ }
+
+ function onDataUpdateCompleted(e) {
+ if (e.sender.getStreamProcessor() !== streamProcessor || e.error) return;
+ updateBufferTimestampOffset(e.currentRepresentation.MSETimeOffset);
+ }
+
+ function onStreamCompleted(e) {
+ if (e.fragmentModel !== streamProcessor.getFragmentModel()) return;
+ lastIndex = e.request.index;
+ checkIfBufferingCompleted();
+ }
+
+ function onCurrentTrackChanged(e) {
+ if (!buffer || e.newMediaInfo.type !== type || e.newMediaInfo.streamInfo.id !== streamProcessor.getStreamInfo().id) return;
+ if (mediaController.getSwitchMode(type) === _MediaController2['default'].TRACK_SWITCH_MODE_ALWAYS_REPLACE) {
+ clearBuffer(getClearRange());
+ }
+ }
+
+ function onWallclockTimeUpdated() {
+ wallclockTicked++;
+ var secondsElapsed = wallclockTicked * (mediaPlayerModel.getWallclockTimeUpdateInterval() / 1000);
+ if (secondsElapsed >= mediaPlayerModel.getBufferPruningInterval() && !isAppendingInProgress) {
+ wallclockTicked = 0;
+ pruneBuffer();
+ }
+ }
+
+ function onPlaybackRateChanged() {
+ checkIfSufficientBuffer();
+ }
+
+ function getType() {
+ return type;
+ }
+
+ function getStreamProcessor() {
+ return streamProcessor;
+ }
+
+ function setStreamProcessor(value) {
+ streamProcessor = value;
+ }
+
+ function getBuffer() {
+ return buffer;
+ }
+
+ function setBuffer(value) {
+ buffer = value;
+ }
+
+ function getBufferLevel() {
+ return bufferLevel;
+ }
+
+ function getCriticalBufferLevel() {
+ return criticalBufferLevel;
+ }
+
+ function setMediaSource(value) {
+ mediaSource = value;
+ }
+
+ function getMediaSource() {
+ return mediaSource;
+ }
+
+ function getIsBufferingCompleted() {
+ return isBufferingCompleted;
+ }
+
+ function reset(errored) {
+
+ eventBus.off(_coreEventsEvents2['default'].DATA_UPDATE_COMPLETED, onDataUpdateCompleted, this);
+ eventBus.off(_coreEventsEvents2['default'].QUALITY_CHANGE_REQUESTED, onQualityChanged, this);
+ eventBus.off(_coreEventsEvents2['default'].INIT_FRAGMENT_LOADED, onInitFragmentLoaded, this);
+ eventBus.off(_coreEventsEvents2['default'].MEDIA_FRAGMENT_LOADED, onMediaFragmentLoaded, this);
+ eventBus.off(_coreEventsEvents2['default'].STREAM_COMPLETED, onStreamCompleted, this);
+ eventBus.off(_coreEventsEvents2['default'].CURRENT_TRACK_CHANGED, onCurrentTrackChanged, this);
+ eventBus.off(_coreEventsEvents2['default'].PLAYBACK_PROGRESS, onPlaybackProgression, this);
+ eventBus.off(_coreEventsEvents2['default'].PLAYBACK_TIME_UPDATED, onPlaybackProgression, this);
+ eventBus.off(_coreEventsEvents2['default'].PLAYBACK_RATE_CHANGED, onPlaybackRateChanged, this);
+ eventBus.off(_coreEventsEvents2['default'].PLAYBACK_SEEKING, onPlaybackSeeking, this);
+ eventBus.off(_coreEventsEvents2['default'].WALLCLOCK_TIME_UPDATED, onWallclockTimeUpdated, this);
+ eventBus.off(_coreEventsEvents2['default'].SOURCEBUFFER_APPEND_COMPLETED, onAppended, this);
+ eventBus.off(_coreEventsEvents2['default'].SOURCEBUFFER_REMOVE_COMPLETED, onRemoved, this);
+
+ criticalBufferLevel = Number.POSITIVE_INFINITY;
+ bufferState = BUFFER_EMPTY;
+ requiredQuality = _AbrController2['default'].QUALITY_DEFAULT;
+ lastIndex = 0;
+ maxAppendedIndex = 0;
+ appendedBytesInfo = null;
+ appendingMediaChunk = false;
+ isBufferingCompleted = false;
+ isAppendingInProgress = false;
+ isPruningInProgress = false;
+ playbackController = null;
+ streamProcessor = null;
+ abrController = null;
+ scheduleController = null;
+
+ if (!errored) {
+ sourceBufferController.abort(mediaSource, buffer);
+ sourceBufferController.removeSourceBuffer(mediaSource, buffer);
+ }
+
+ buffer = null;
+ }
+
+ instance = {
+ initialize: initialize,
+ createBuffer: createBuffer,
+ getType: getType,
+ getStreamProcessor: getStreamProcessor,
+ setStreamProcessor: setStreamProcessor,
+ getBuffer: getBuffer,
+ setBuffer: setBuffer,
+ getBufferLevel: getBufferLevel,
+ getCriticalBufferLevel: getCriticalBufferLevel,
+ setMediaSource: setMediaSource,
+ getMediaSource: getMediaSource,
+ getIsBufferingCompleted: getIsBufferingCompleted,
+ switchInitData: switchInitData,
+ reset: reset
+ };
+
+ setup();
+ return instance;
+}
+
+BufferController.__dashjs_factory_name = 'BufferController';
+var factory = _coreFactoryMaker2['default'].getClassFactory(BufferController);
+factory.BUFFER_LOADED = BUFFER_LOADED;
+factory.BUFFER_EMPTY = BUFFER_EMPTY;
+exports['default'] = factory;
+module.exports = exports['default'];
+
+},{"10":10,"101":101,"13":13,"146":146,"152":152,"60":60,"66":66,"68":68,"70":70,"8":8,"9":9,"99":99}],64:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _controllersPlaybackController = _dereq_(68);
+
+var _controllersPlaybackController2 = _interopRequireDefault(_controllersPlaybackController);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _coreDebug = _dereq_(8);
+
+var _coreDebug2 = _interopRequireDefault(_coreDebug);
+
+var _coreEventBus = _dereq_(9);
+
+var _coreEventBus2 = _interopRequireDefault(_coreEventBus);
+
+function EventController() {
+
+ var MPD_RELOAD_SCHEME = 'urn:mpeg:dash:event:2012';
+ var MPD_RELOAD_VALUE = 1;
+
+ var context = this.context;
+ var log = (0, _coreDebug2['default'])(context).getInstance().log;
+ var eventBus = (0, _coreEventBus2['default'])(context).getInstance();
+
+ var instance = undefined,
+ inlineEvents = undefined,
+ // Holds all Inline Events not triggered yet
+ inbandEvents = undefined,
+ // Holds all Inband Events not triggered yet
+ activeEvents = undefined,
+ // Holds all Events currently running
+ eventInterval = undefined,
+ // variable holding the setInterval
+ refreshDelay = undefined,
+ // refreshTime for the setInterval
+ presentationTimeThreshold = undefined,
+ manifestModel = undefined,
+ manifestUpdater = undefined,
+ playbackController = undefined,
+ isStarted = undefined;
+
+ function initialize() {
+ isStarted = false;
+ inlineEvents = {};
+ inbandEvents = {};
+ activeEvents = {};
+ eventInterval = null;
+ refreshDelay = 100;
+ presentationTimeThreshold = refreshDelay / 1000;
+ playbackController = (0, _controllersPlaybackController2['default'])(context).getInstance();
+ }
+
+ function clear() {
+ if (eventInterval !== null && isStarted) {
+ clearInterval(eventInterval);
+ eventInterval = null;
+ isStarted = false;
+ }
+ }
+
+ function start() {
+ log('Start Event Controller');
+ if (!isStarted && !isNaN(refreshDelay)) {
+ isStarted = true;
+ eventInterval = setInterval(onEventTimer, refreshDelay);
+ }
+ }
+
+ /**
+ * Add events to the eventList. Events that are not in the mpd anymore but not triggered yet will still be deleted
+ * @param {Array.<Object>} values
+ */
+ function addInlineEvents(values) {
+ inlineEvents = {};
+
+ if (values) {
+ for (var i = 0; i < values.length; i++) {
+ var event = values[i];
+ inlineEvents[event.id] = event;
+ log('Add inline event with id ' + event.id);
+ }
+ }
+ log('Added ' + values.length + ' inline events');
+ }
+
+ /**
+ * i.e. processing of any one event message box with the same id is sufficient
+ * @param {Array.<Object>} values
+ */
+ function addInbandEvents(values) {
+ for (var i = 0; i < values.length; i++) {
+ var event = values[i];
+ if (!(event.id in inbandEvents)) {
+ inbandEvents[event.id] = event;
+ log('Add inband event with id ' + event.id);
+ } else {
+ log('Repeated event with id ' + event.id);
+ }
+ }
+ }
+
+ /**
+ * Remove events which are over from the list
+ */
+ function removeEvents() {
+ if (activeEvents) {
+ var currentVideoTime = playbackController.getTime();
+ var eventIds = Object.keys(activeEvents);
+
+ for (var i = 0; i < eventIds.length; i++) {
+ var eventId = eventIds[i];
+ var curr = activeEvents[eventId];
+ if (curr !== null && (curr.duration + curr.presentationTime) / curr.eventStream.timescale < currentVideoTime) {
+ log('Remove Event ' + eventId + ' at time ' + currentVideoTime);
+ curr = null;
+ delete activeEvents[eventId];
+ }
+ }
+ }
+ }
+
+ /**
+ * Iterate through the eventList and trigger/remove the events
+ */
+ function onEventTimer() {
+ triggerEvents(inbandEvents);
+ triggerEvents(inlineEvents);
+ removeEvents();
+ }
+
+ function refreshManifest() {
+ var manifest = manifestModel.getValue();
+ var url = manifest.url;
+
+ if (manifest.hasOwnProperty('Location')) {
+ url = manifest.Location;
+ }
+ log('Refresh manifest @ ' + url);
+ manifestUpdater.getManifestLoader().load(url);
+ }
+
+ function triggerEvents(events) {
+ var currentVideoTime = playbackController.getTime();
+ var presentationTime;
+
+ /* == Trigger events that are ready == */
+ if (events) {
+ var eventIds = Object.keys(events);
+ for (var i = 0; i < eventIds.length; i++) {
+ var eventId = eventIds[i];
+ var curr = events[eventId];
+
+ if (curr !== undefined) {
+ presentationTime = curr.presentationTime / curr.eventStream.timescale;
+ if (presentationTime === 0 || presentationTime <= currentVideoTime && presentationTime + presentationTimeThreshold > currentVideoTime) {
+ log('Start Event ' + eventId + ' at ' + currentVideoTime);
+ if (curr.duration > 0) {
+ activeEvents[eventId] = curr;
+ }
+ if (curr.eventStream.schemeIdUri == MPD_RELOAD_SCHEME && curr.eventStream.value == MPD_RELOAD_VALUE) {
+ refreshManifest();
+ } else {
+ eventBus.trigger(curr.eventStream.schemeIdUri, { event: curr });
+ }
+ delete events[eventId];
+ }
+ }
+ }
+ }
+ }
+
+ function setConfig(config) {
+ if (!config) return;
+
+ if (config.manifestModel) {
+ manifestModel = config.manifestModel;
+ }
+
+ if (config.manifestUpdater) {
+ manifestUpdater = config.manifestUpdater;
+ }
+ }
+
+ function reset() {
+ clear();
+ inlineEvents = null;
+ inbandEvents = null;
+ activeEvents = null;
+ playbackController = null;
+ }
+
+ instance = {
+ initialize: initialize,
+ addInlineEvents: addInlineEvents,
+ addInbandEvents: addInbandEvents,
+ clear: clear,
+ start: start,
+ setConfig: setConfig,
+ reset: reset
+ };
+
+ return instance;
+}
+
+EventController.__dashjs_factory_name = 'EventController';
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(EventController);
+module.exports = exports['default'];
+
+},{"10":10,"68":68,"8":8,"9":9}],65:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _voMetricsHTTPRequest = _dereq_(179);
+
+var _voDataChunk = _dereq_(161);
+
+var _voDataChunk2 = _interopRequireDefault(_voDataChunk);
+
+var _modelsFragmentModel = _dereq_(99);
+
+var _modelsFragmentModel2 = _interopRequireDefault(_modelsFragmentModel);
+
+var _modelsMetricsModel = _dereq_(102);
+
+var _modelsMetricsModel2 = _interopRequireDefault(_modelsMetricsModel);
+
+var _coreEventBus = _dereq_(9);
+
+var _coreEventBus2 = _interopRequireDefault(_coreEventBus);
+
+var _coreEventsEvents = _dereq_(13);
+
+var _coreEventsEvents2 = _interopRequireDefault(_coreEventsEvents);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _coreDebug = _dereq_(8);
+
+var _coreDebug2 = _interopRequireDefault(_coreDebug);
+
+function FragmentController() /*config*/{
+
+ var context = this.context;
+ var log = (0, _coreDebug2['default'])(context).getInstance().log;
+ var eventBus = (0, _coreEventBus2['default'])(context).getInstance();
+
+ var instance = undefined,
+ fragmentModels = undefined;
+
+ function setup() {
+ fragmentModels = {};
+ eventBus.on(_coreEventsEvents2['default'].FRAGMENT_LOADING_COMPLETED, onFragmentLoadingCompleted, instance);
+ }
+
+ function process(bytes) {
+ var result = null;
+ if (bytes !== null && bytes !== undefined && bytes.byteLength > 0) {
+ result = new Uint8Array(bytes);
+ }
+ return result;
+ }
+
+ function getModel(type) {
+ var model = fragmentModels[type];
+ if (!model) {
+ model = (0, _modelsFragmentModel2['default'])(context).create({ metricsModel: (0, _modelsMetricsModel2['default'])(context).getInstance() });
+ fragmentModels[type] = model;
+ }
+
+ return model;
+ }
+
+ function isInitializationRequest(request) {
+ return request && request.type && request.type === _voMetricsHTTPRequest.HTTPRequest.INIT_SEGMENT_TYPE;
+ }
+
+ function reset() {
+ eventBus.off(_coreEventsEvents2['default'].FRAGMENT_LOADING_COMPLETED, onFragmentLoadingCompleted, this);
+ for (var model in fragmentModels) {
+ fragmentModels[model].reset();
+ }
+ fragmentModels = {};
+ }
+
+ function createDataChunk(bytes, request, streamId) {
+ var chunk = new _voDataChunk2['default']();
+
+ chunk.streamId = streamId;
+ chunk.mediaInfo = request.mediaInfo;
+ chunk.segmentType = request.type;
+ chunk.start = request.startTime;
+ chunk.duration = request.duration;
+ chunk.end = chunk.start + chunk.duration;
+ chunk.bytes = bytes;
+ chunk.index = request.index;
+ chunk.quality = request.quality;
+
+ return chunk;
+ }
+
+ function onFragmentLoadingCompleted(e) {
+ if (fragmentModels[e.request.mediaType] !== e.sender) return;
+
+ var scheduleController = e.sender.getScheduleController();
+ var request = e.request;
+ var bytes = e.response;
+ var isInit = isInitializationRequest(request);
+ var streamId = scheduleController.getStreamProcessor().getStreamInfo().id;
+
+ if (!bytes) {
+ log('No ' + request.mediaType + ' bytes to push.');
+ return;
+ }
+
+ var chunk = createDataChunk(bytes, request, streamId);
+ eventBus.trigger(isInit ? _coreEventsEvents2['default'].INIT_FRAGMENT_LOADED : _coreEventsEvents2['default'].MEDIA_FRAGMENT_LOADED, { chunk: chunk, fragmentModel: e.sender });
+ }
+
+ instance = {
+ process: process,
+ getModel: getModel,
+ isInitializationRequest: isInitializationRequest,
+ reset: reset
+ };
+
+ setup();
+
+ return instance;
+}
+
+FragmentController.__dashjs_factory_name = 'FragmentController';
+exports['default'] = _coreFactoryMaker2['default'].getClassFactory(FragmentController);
+module.exports = exports['default'];
+
+},{"10":10,"102":102,"13":13,"161":161,"179":179,"8":8,"9":9,"99":99}],66:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreEventsEvents = _dereq_(13);
+
+var _coreEventsEvents2 = _interopRequireDefault(_coreEventsEvents);
+
+var _coreEventBus = _dereq_(9);
+
+var _coreEventBus2 = _interopRequireDefault(_coreEventBus);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _coreDebug = _dereq_(8);
+
+var _coreDebug2 = _interopRequireDefault(_coreDebug);
+
+var _TextSourceBuffer = _dereq_(56);
+
+var _TextSourceBuffer2 = _interopRequireDefault(_TextSourceBuffer);
+
+var _utilsDOMStorage = _dereq_(149);
+
+var _utilsDOMStorage2 = _interopRequireDefault(_utilsDOMStorage);
+
+var TRACK_SWITCH_MODE_NEVER_REPLACE = 'neverReplace';
+var TRACK_SWITCH_MODE_ALWAYS_REPLACE = 'alwaysReplace';
+var TRACK_SELECTION_MODE_HIGHEST_BITRATE = 'highestBitrate';
+var TRACK_SELECTION_MODE_WIDEST_RANGE = 'widestRange';
+var DEFAULT_INIT_TRACK_SELECTION_MODE = TRACK_SELECTION_MODE_HIGHEST_BITRATE;
+
+function MediaController() {
+
+ var context = this.context;
+ var log = (0, _coreDebug2['default'])(context).getInstance().log;
+ var eventBus = (0, _coreEventBus2['default'])(context).getInstance();
+ var textSourceBuffer = (0, _TextSourceBuffer2['default'])(context).getInstance();
+ var domStorage = (0, _utilsDOMStorage2['default'])(context).getInstance();
+
+ var instance = undefined,
+ tracks = undefined,
+ initialSettings = undefined,
+ selectionMode = undefined,
+ switchMode = undefined,
+ errHandler = undefined;
+
+ var validTrackSwitchModes = [TRACK_SWITCH_MODE_ALWAYS_REPLACE, TRACK_SWITCH_MODE_NEVER_REPLACE];
+
+ var validTrackSelectionModes = [TRACK_SELECTION_MODE_HIGHEST_BITRATE, TRACK_SELECTION_MODE_WIDEST_RANGE];
+
+ function initialize() {
+ tracks = {};
+ resetInitialSettings();
+ resetSwitchMode();
+ }
+
+ /**
+ * @param {string} type
+ * @param {StreamInfo} streamInfo
+ * @memberof MediaController#
+ */
+ function checkInitialMediaSettingsForType(type, streamInfo) {
+ var settings = getInitialSettings(type);
+ var tracksForType = getTracksFor(type, streamInfo);
+ var tracks = [];
+
+ if (type === 'fragmentedText') {
+ // Choose the first track
+ setTrack(tracksForType[0]);
+ return;
+ }
+
+ if (!settings) {
+ settings = domStorage.getSavedMediaSettings(type);
+ setInitialSettings(type, settings);
+ }
+
+ if (!tracksForType || tracksForType.length === 0) return;
+
+ if (settings) {
+ tracksForType.forEach(function (track) {
+ if (matchSettings(settings, track)) {
+ tracks.push(track);
+ }
+ });
+ }
+
+ if (tracks.length === 0) {
+ setTrack(selectInitialTrack(tracksForType));
+ } else {
+ if (tracks.length > 1) {
+ setTrack(selectInitialTrack(tracks));
+ } else {
+ setTrack(tracks[0]);
+ }
+ }
+ }
+
+ /**
+ * @param {MediaInfo} track
+ * @returns {boolean}
+ * @memberof MediaController#
+ */
+ function addTrack(track) {
+ var mediaType = track ? track.type : null;
+ var streamId = track ? track.streamInfo.id : null;
+ var initSettings = getInitialSettings(mediaType);
+
+ if (!track || !isMultiTrackSupportedByType(mediaType)) return false;
+
+ tracks[streamId] = tracks[streamId] || createTrackInfo();
+
+ if (tracks[streamId][mediaType].list.indexOf(track) >= 0) return false;
+
+ tracks[streamId][mediaType].list.push(track);
+
+ if (initSettings && matchSettings(initSettings, track) && !getCurrentTrackFor(mediaType, track.streamInfo)) {
+ setTrack(track);
+ }
+
+ return true;
+ }
+
+ /**
+ * @param {string} type
+ * @param {StreamInfo} streamInfo
+ * @returns {Array}
+ * @memberof MediaController#
+ */
+ function getTracksFor(type, streamInfo) {
+ if (!type || !streamInfo) return [];
+
+ var id = streamInfo.id;
+
+ if (!tracks[id] || !tracks[id][type]) return [];
+
+ return tracks[id][type].list;
+ }
+
+ /**
+ * @param {string} type
+ * @param {StreamInfo} streamInfo
+ * @returns {Object|null}
+ * @memberof MediaController#
+ */
+ function getCurrentTrackFor(type, streamInfo) {
+ if (!type || !streamInfo || streamInfo && !tracks[streamInfo.id]) return null;
+ return tracks[streamInfo.id][type].current;
+ }
+
+ /**
+ * @param {MediaInfo} track
+ * @returns {boolean}
+ * @memberof MediaController#
+ */
+ function isCurrentTrack(track) {
+ var type = track.type;
+ var id = track.streamInfo.id;
+
+ return tracks[id] && tracks[id][type] && isTracksEqual(tracks[id][type].current, track);
+ }
+
+ /**
+ * @param {MediaInfo} track
+ * @memberof MediaController#
+ */
+ function setTrack(track) {
+ if (!track) return;
+
+ var type = track.type;
+ var streamInfo = track.streamInfo;
+ var id = streamInfo.id;
+ var current = getCurrentTrackFor(type, streamInfo);
+
+ if (!tracks[id] || !tracks[id][type] || current && isTracksEqual(track, current)) return;
+
+ tracks[id][type].current = track;
+
+ if (current) {
+ eventBus.trigger(_coreEventsEvents2['default'].CURRENT_TRACK_CHANGED, { oldMediaInfo: current, newMediaInfo: track, switchMode: switchMode[type] });
+ }
+
+ var settings = extractSettings(track);
+
+ if (!settings || !tracks[id][type].storeLastSettings) return;
+
+ if (settings.roles) {
+ settings.role = settings.roles[0];
+ delete settings.roles;
+ }
+
+ if (settings.accessibility) {
+ settings.accessibility = settings.accessibility[0];
+ }
+
+ if (settings.audioChannelConfiguration) {
+ settings.audioChannelConfiguration = settings.audioChannelConfiguration[0];
+ }
+
+ domStorage.setSavedMediaSettings(type, settings);
+ }
+
+ /**
+ * @param {string} type
+ * @param {Object} value
+ * @memberof MediaController#
+ */
+ function setInitialSettings(type, value) {
+ if (!type || !value) return;
+
+ initialSettings[type] = value;
+ }
+
+ /**
+ * @param {string} type
+ * @returns {Object|null}
+ * @memberof MediaController#
+ */
+ function getInitialSettings(type) {
+ if (!type) return null;
+
+ return initialSettings[type];
+ }
+
+ /**
+ * @param {string} type
+ * @param {string} mode
+ * @memberof MediaController#
+ */
+ function setSwitchMode(type, mode) {
+ var isModeSupported = validTrackSwitchModes.indexOf(mode) !== -1;
+
+ if (!isModeSupported) {
+ log('track switch mode is not supported: ' + mode);
+ return;
+ }
+
+ switchMode[type] = mode;
+ }
+
+ /**
+ * @param {string} type
+ * @returns {string} mode
+ * @memberof MediaController#
+ */
+ function getSwitchMode(type) {
+ return switchMode[type];
+ }
+
+ /**
+ * @param {string} mode
+ * @memberof MediaController#
+ */
+ function setSelectionModeForInitialTrack(mode) {
+ var isModeSupported = validTrackSelectionModes.indexOf(mode) !== -1;
+
+ if (!isModeSupported) {
+ log('track selection mode is not supported: ' + mode);
+ return;
+ }
+ selectionMode = mode;
+ }
+
+ /**
+ * @returns {string} mode
+ * @memberof MediaController#
+ */
+ function getSelectionModeForInitialTrack() {
+ return selectionMode || DEFAULT_INIT_TRACK_SELECTION_MODE;
+ }
+
+ /**
+ * @param {string} type
+ * @returns {boolean}
+ * @memberof MediaController#
+ */
+ function isMultiTrackSupportedByType(type) {
+ return type === 'audio' || type === 'video' || type === 'text' || type === 'fragmentedText';
+ }
+
+ /**
+ * @param {MediaInfo} t1 - first track to compare
+ * @param {MediaInfo} t2 - second track to compare
+ * @returns {boolean}
+ * @memberof MediaController#
+ */
+ function isTracksEqual(t1, t2) {
+ var sameId = t1.id === t2.id;
+ var sameViewpoint = t1.viewpoint === t2.viewpoint;
+ var sameLang = t1.lang === t2.lang;
+ var sameRoles = t1.roles.toString() === t2.roles.toString();
+ var sameAccessibility = t1.accessibility.toString() === t2.accessibility.toString();
+ var sameAudioChannelConfiguration = t1.audioChannelConfiguration.toString() === t2.audioChannelConfiguration.toString();
+
+ return sameId && sameViewpoint && sameLang && sameRoles && sameAccessibility && sameAudioChannelConfiguration;
+ }
+
+ function setConfig(config) {
+ if (!config) return;
+
+ if (config.errHandler) {
+ errHandler = config.errHandler;
+ }
+ }
+
+ /**
+ * @memberof MediaController#
+ */
+ function reset() {
+ initialize();
+ textSourceBuffer.resetEmbedded();
+ }
+
+ function extractSettings(mediaInfo) {
+ var settings = {
+ lang: mediaInfo.lang,
+ viewpoint: mediaInfo.viewpoint,
+ roles: mediaInfo.roles,
+ accessibility: mediaInfo.accessibility,
+ audioChannelConfiguration: mediaInfo.audioChannelConfiguration
+ };
+ var notEmpty = settings.lang || settings.viewpoint || settings.role && settings.role.length > 0 || settings.accessibility && settings.accessibility.length > 0 || settings.audioChannelConfiguration && settings.audioChannelConfiguration.length > 0;
+
+ return notEmpty ? settings : null;
+ }
+
+ function matchSettings(settings, track) {
+ var matchLang = !settings.lang || settings.lang === track.lang;
+ var matchViewPoint = !settings.viewpoint || settings.viewpoint === track.viewpoint;
+ var matchRole = !settings.role || !!track.roles.filter(function (item) {
+ return item === settings.role;
+ })[0];
+ var matchAccessibility = !settings.accessibility || !!track.accessibility.filter(function (item) {
+ return item === settings.accessibility;
+ })[0];
+ var matchAudioChannelConfiguration = !settings.audioChannelConfiguration || !!track.audioChannelConfiguration.filter(function (item) {
+ return item === settings.audioChannelConfiguration;
+ })[0];
+
+ return matchLang && matchViewPoint && matchRole && matchAccessibility && matchAudioChannelConfiguration;
+ }
+
+ function resetSwitchMode() {
+ switchMode = {
+ audio: TRACK_SWITCH_MODE_ALWAYS_REPLACE,
+ video: TRACK_SWITCH_MODE_NEVER_REPLACE
+ };
+ }
+
+ function resetInitialSettings() {
+ initialSettings = {
+ audio: null,
+ video: null
+ };
+ }
+
+ function selectInitialTrack(tracks) {
+ var mode = getSelectionModeForInitialTrack();
+ var tmpArr = [];
+ var getTracksWithHighestBitrate = function getTracksWithHighestBitrate(trackArr) {
+ var max = 0;
+ var result = [];
+ var tmp;
+
+ trackArr.forEach(function (track) {
+ tmp = Math.max.apply(Math, track.bitrateList.map(function (obj) {
+ return obj.bandwidth;
+ }));
+
+ if (tmp > max) {
+ max = tmp;
+ result = [track];
+ } else if (tmp === max) {
+ result.push(track);
+ }
+ });
+
+ return result;
+ };
+ var getTracksWithWidestRange = function getTracksWithWidestRange(trackArr) {
+ var max = 0;
+ var result = [];
+ var tmp;
+
+ trackArr.forEach(function (track) {
+ tmp = track.representationCount;
+
+ if (tmp > max) {
+ max = tmp;
+ result = [track];
+ } else if (tmp === max) {
+ result.push(track);
+ }
+ });
+
+ return result;
+ };
+
+ switch (mode) {
+ case TRACK_SELECTION_MODE_HIGHEST_BITRATE:
+ tmpArr = getTracksWithHighestBitrate(tracks);
+
+ if (tmpArr.length > 1) {
+ tmpArr = getTracksWithWidestRange(tmpArr);
+ }
+ break;
+ case TRACK_SELECTION_MODE_WIDEST_RANGE:
+ tmpArr = getTracksWithWidestRange(tracks);
+
+ if (tmpArr.length > 1) {
+ tmpArr = getTracksWithHighestBitrate(tracks);
+ }
+ break;
+ default:
+ log('track selection mode is not supported: ' + mode);
+ break;
+ }
+
+ return tmpArr[0];
+ }
+
+ function createTrackInfo() {
+ return {
+ audio: {
+ list: [],
+ storeLastSettings: true,
+ current: null
+ },
+ video: {
+ list: [],
+ storeLastSettings: true,
+ current: null
+ },
+ text: {
+ list: [],
+ storeLastSettings: true,
+ current: null
+ },
+ fragmentedText: {
+ list: [],
+ storeLastSettings: true,
+ current: null
+ }
+ };
+ }
+
+ instance = {
+ initialize: initialize,
+ checkInitialMediaSettingsForType: checkInitialMediaSettingsForType,
+ addTrack: addTrack,
+ getTracksFor: getTracksFor,
+ getCurrentTrackFor: getCurrentTrackFor,
+ isCurrentTrack: isCurrentTrack,
+ setTrack: setTrack,
+ setInitialSettings: setInitialSettings,
+ getInitialSettings: getInitialSettings,
+ setSwitchMode: setSwitchMode,
+ getSwitchMode: getSwitchMode,
+ setSelectionModeForInitialTrack: setSelectionModeForInitialTrack,
+ getSelectionModeForInitialTrack: getSelectionModeForInitialTrack,
+ isMultiTrackSupportedByType: isMultiTrackSupportedByType,
+ isTracksEqual: isTracksEqual,
+ setConfig: setConfig,
+ reset: reset
+ };
+
+ return instance;
+}
+
+MediaController.__dashjs_factory_name = 'MediaController';
+var factory = _coreFactoryMaker2['default'].getSingletonFactory(MediaController);
+factory.TRACK_SWITCH_MODE_NEVER_REPLACE = TRACK_SWITCH_MODE_NEVER_REPLACE;
+factory.TRACK_SWITCH_MODE_ALWAYS_REPLACE = TRACK_SWITCH_MODE_ALWAYS_REPLACE;
+factory.TRACK_SELECTION_MODE_HIGHEST_BITRATE = TRACK_SELECTION_MODE_HIGHEST_BITRATE;
+factory.TRACK_SELECTION_MODE_WIDEST_RANGE = TRACK_SELECTION_MODE_WIDEST_RANGE;
+factory.DEFAULT_INIT_TRACK_SELECTION_MODE = DEFAULT_INIT_TRACK_SELECTION_MODE;
+exports['default'] = factory;
+module.exports = exports['default'];
+
+},{"10":10,"13":13,"149":149,"56":56,"8":8,"9":9}],67:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+function MediaSourceController() {
+
+ var instance = undefined;
+
+ function createMediaSource() {
+
+ var hasWebKit = ('WebKitMediaSource' in window);
+ var hasMediaSource = ('MediaSource' in window);
+
+ if (hasMediaSource) {
+ return new MediaSource();
+ } else if (hasWebKit) {
+ return new WebKitMediaSource();
+ }
+
+ return null;
+ }
+
+ function attachMediaSource(source, videoModel) {
+
+ var objectURL = window.URL.createObjectURL(source);
+
+ videoModel.setSource(objectURL);
+
+ return objectURL;
+ }
+
+ function detachMediaSource(videoModel) {
+ videoModel.setSource(null);
+ }
+
+ function setDuration(source, value) {
+
+ if (source.duration != value) source.duration = value;
+
+ return source.duration;
+ }
+
+ function signalEndOfStream(source) {
+
+ var buffers = source.sourceBuffers;
+ var ln = buffers.length;
+ var i = 0;
+
+ if (source.readyState !== 'open') return;
+
+ for (i; i < ln; i++) {
+ if (buffers[i].updating) return;
+ if (buffers[i].buffered.length === 0) return;
+ }
+
+ source.endOfStream();
+ }
+
+ instance = {
+ createMediaSource: createMediaSource,
+ attachMediaSource: attachMediaSource,
+ detachMediaSource: detachMediaSource,
+ setDuration: setDuration,
+ signalEndOfStream: signalEndOfStream
+ };
+
+ return instance;
+}
+
+MediaSourceController.__dashjs_factory_name = 'MediaSourceController';
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(MediaSourceController);
+module.exports = exports['default'];
+
+},{"10":10}],68:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _BufferController = _dereq_(63);
+
+var _BufferController2 = _interopRequireDefault(_BufferController);
+
+var _modelsURIQueryAndFragmentModel = _dereq_(103);
+
+var _modelsURIQueryAndFragmentModel2 = _interopRequireDefault(_modelsURIQueryAndFragmentModel);
+
+var _streamingModelsMediaPlayerModel = _dereq_(101);
+
+var _streamingModelsMediaPlayerModel2 = _interopRequireDefault(_streamingModelsMediaPlayerModel);
+
+var _coreEventBus = _dereq_(9);
+
+var _coreEventBus2 = _interopRequireDefault(_coreEventBus);
+
+var _coreEventsEvents = _dereq_(13);
+
+var _coreEventsEvents2 = _interopRequireDefault(_coreEventsEvents);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _coreDebug = _dereq_(8);
+
+var _coreDebug2 = _interopRequireDefault(_coreDebug);
+
+function PlaybackController() {
+
+ var context = this.context;
+ var log = (0, _coreDebug2['default'])(context).getInstance().log;
+ var eventBus = (0, _coreEventBus2['default'])(context).getInstance();
+
+ var instance = undefined,
+ element = undefined,
+ streamController = undefined,
+ timelineConverter = undefined,
+ metricsModel = undefined,
+ dashMetrics = undefined,
+ manifestModel = undefined,
+ dashManifestModel = undefined,
+ adapter = undefined,
+ videoModel = undefined,
+ currentTime = undefined,
+ liveStartTime = undefined,
+ wallclockTimeIntervalId = undefined,
+ commonEarliestTime = undefined,
+ streamInfo = undefined,
+ isDynamic = undefined,
+ mediaPlayerModel = undefined,
+ playOnceInitialized = undefined;
+
+ function setup() {
+ currentTime = 0;
+ liveStartTime = NaN;
+ wallclockTimeIntervalId = null;
+ isDynamic = null;
+ playOnceInitialized = false;
+ commonEarliestTime = {};
+ mediaPlayerModel = (0, _streamingModelsMediaPlayerModel2['default'])(context).getInstance();
+ }
+
+ function initialize(StreamInfo) {
+ streamInfo = StreamInfo;
+ element = videoModel.getElement();
+ addAllListeners();
+ isDynamic = streamInfo.manifestInfo.isDynamic;
+ liveStartTime = streamInfo.start;
+ eventBus.on(_coreEventsEvents2['default'].DATA_UPDATE_COMPLETED, onDataUpdateCompleted, this);
+ eventBus.on(_coreEventsEvents2['default'].LIVE_EDGE_SEARCH_COMPLETED, onLiveEdgeSearchCompleted, this);
+ eventBus.on(_coreEventsEvents2['default'].BYTES_APPENDED, onBytesAppended, this);
+ eventBus.on(_coreEventsEvents2['default'].BUFFER_LEVEL_STATE_CHANGED, onBufferLevelStateChanged, this);
+ eventBus.on(_coreEventsEvents2['default'].PERIOD_SWITCH_STARTED, onPeriodSwitchStarted, this);
+
+ if (playOnceInitialized) {
+ playOnceInitialized = false;
+ play();
+ }
+ }
+
+ function onPeriodSwitchStarted(e) {
+ if (e.fromStreamInfo && commonEarliestTime[e.fromStreamInfo.id]) {
+ delete commonEarliestTime[e.fromStreamInfo.id];
+ }
+ }
+
+ function getTimeToStreamEnd() {
+ return getStreamStartTime(true) + streamInfo.duration - getTime();
+ }
+
+ function isPlaybackStarted() {
+ return getTime() > 0;
+ }
+
+ function getStreamId() {
+ return streamInfo.id;
+ }
+
+ function getStreamDuration() {
+ return streamInfo.duration;
+ }
+
+ function play() {
+ if (element) {
+ element.autoplay = true;
+ var p = element.play();
+ if (p && typeof Promise !== 'undefined' && p instanceof Promise) {
+ p['catch'](function (e) {
+ if (e.name === 'NotAllowedError') {
+ eventBus.trigger(_coreEventsEvents2['default'].PLAYBACK_NOT_ALLOWED);
+ }
+ log('Caught pending play exception - continuing (' + e + ')');
+ });
+ }
+ } else {
+ playOnceInitialized = true;
+ }
+ }
+
+ function isPaused() {
+ if (!element) return;
+ return element.paused;
+ }
+
+ function pause() {
+ if (!element) return;
+ element.pause();
+ element.autoplay = false;
+ }
+
+ function isSeeking() {
+ if (!element) return;
+ return element.seeking;
+ }
+
+ function seek(time) {
+ if (!videoModel) return;
+ log('Requesting seek to time: ' + time);
+ videoModel.setCurrentTime(time);
+ }
+
+ function getTime() {
+ if (!element) return;
+ return element.currentTime;
+ }
+
+ function getPlaybackRate() {
+ if (!element) return;
+ return element.playbackRate;
+ }
+
+ function getPlayedRanges() {
+ if (!element) return;
+ return element.played;
+ }
+
+ function getEnded() {
+ if (!element) return;
+ return element.ended;
+ }
+
+ function getIsDynamic() {
+ return isDynamic;
+ }
+
+ function setLiveStartTime(value) {
+ liveStartTime = value;
+ }
+
+ function getLiveStartTime() {
+ return liveStartTime;
+ }
+
+ /**
+ * Computes the desirable delay for the live edge to avoid a risk of getting 404 when playing at the bleeding edge
+ * @param {number} fragmentDuration - seconds?
+ * @param {number} dvrWindowSize - seconds?
+ * @returns {number} object
+ * @memberof PlaybackController#
+ */
+ function computeLiveDelay(fragmentDuration, dvrWindowSize) {
+ var mpd = dashManifestModel.getMpd(manifestModel.getValue());
+
+ var delay = undefined;
+ var END_OF_PLAYLIST_PADDING = 10;
+
+ if (mediaPlayerModel.getUseSuggestedPresentationDelay() && mpd.hasOwnProperty('suggestedPresentationDelay')) {
+ delay = mpd.suggestedPresentationDelay;
+ } else if (mediaPlayerModel.getLiveDelay()) {
+ delay = mediaPlayerModel.getLiveDelay(); // If set by user, this value takes precedence
+ } else if (!isNaN(fragmentDuration)) {
+ delay = fragmentDuration * mediaPlayerModel.getLiveDelayFragmentCount();
+ } else {
+ delay = streamInfo.manifestInfo.minBufferTime * 2;
+ }
+
+ // cap target latency to:
+ // - dvrWindowSize / 2 for short playlists
+ // - dvrWindowSize - END_OF_PLAYLIST_PADDING for longer playlists
+ var targetDelayCapping = Math.max(dvrWindowSize - END_OF_PLAYLIST_PADDING, dvrWindowSize / 2);
+
+ return Math.min(delay, targetDelayCapping);
+ }
+
+ function reset() {
+ if (videoModel && element) {
+ eventBus.off(_coreEventsEvents2['default'].DATA_UPDATE_COMPLETED, onDataUpdateCompleted, this);
+ eventBus.off(_coreEventsEvents2['default'].BUFFER_LEVEL_STATE_CHANGED, onBufferLevelStateChanged, this);
+ eventBus.off(_coreEventsEvents2['default'].LIVE_EDGE_SEARCH_COMPLETED, onLiveEdgeSearchCompleted, this);
+ eventBus.off(_coreEventsEvents2['default'].BYTES_APPENDED, onBytesAppended, this);
+ stopUpdatingWallclockTime();
+ removeAllListeners();
+ }
+ videoModel = null;
+ streamInfo = null;
+ element = null;
+ isDynamic = null;
+ setup();
+ }
+
+ function setConfig(config) {
+ if (!config) return;
+
+ if (config.streamController) {
+ streamController = config.streamController;
+ }
+ if (config.timelineConverter) {
+ timelineConverter = config.timelineConverter;
+ }
+ if (config.metricsModel) {
+ metricsModel = config.metricsModel;
+ }
+ if (config.dashMetrics) {
+ dashMetrics = config.dashMetrics;
+ }
+ if (config.manifestModel) {
+ manifestModel = config.manifestModel;
+ }
+ if (config.dashManifestModel) {
+ dashManifestModel = config.dashManifestModel;
+ }
+ if (config.adapter) {
+ adapter = config.adapter;
+ }
+ if (config.videoModel) {
+ videoModel = config.videoModel;
+ }
+ }
+
+ /**
+ * @param {boolean} ignoreStartOffset - ignore URL fragment start offset if true
+ * @returns {number} object
+ * @memberof PlaybackController#
+ */
+ function getStreamStartTime(ignoreStartOffset) {
+ var presentationStartTime = undefined;
+ var fragData = (0, _modelsURIQueryAndFragmentModel2['default'])(context).getInstance().getURIFragmentData();
+ var fragS = parseInt(fragData.s, 10);
+ var fragT = parseInt(fragData.t, 10);
+ var startTimeOffset = NaN;
+
+ if (!ignoreStartOffset) {
+ startTimeOffset = !isNaN(fragS) ? fragS : fragT;
+ }
+
+ if (isDynamic) {
+ if (!isNaN(startTimeOffset) && startTimeOffset > 1262304000) {
+
+ presentationStartTime = startTimeOffset - streamInfo.manifestInfo.availableFrom.getTime() / 1000;
+
+ if (presentationStartTime > liveStartTime || presentationStartTime < liveStartTime - streamInfo.manifestInfo.DVRWindowSize) {
+ presentationStartTime = null;
+ }
+ }
+ presentationStartTime = presentationStartTime || liveStartTime;
+ } else {
+ if (!isNaN(startTimeOffset) && startTimeOffset < Math.max(streamInfo.manifestInfo.duration, streamInfo.duration) && startTimeOffset >= 0) {
+ presentationStartTime = startTimeOffset;
+ } else {
+ var earliestTime = commonEarliestTime[streamInfo.id]; //set by ready bufferStart after first onBytesAppended
+ if (earliestTime === undefined) {
+ earliestTime = streamController.getActiveStreamCommonEarliestTime(); //deal with calculated PST that is none 0 when streamInfo.start is 0
+ }
+ presentationStartTime = Math.max(earliestTime, streamInfo.start);
+ }
+ }
+
+ return presentationStartTime;
+ }
+
+ function getActualPresentationTime(currentTime) {
+ var metrics = metricsModel.getReadOnlyMetricsFor('video') || metricsModel.getReadOnlyMetricsFor('audio');
+ var DVRMetrics = dashMetrics.getCurrentDVRInfo(metrics);
+ var DVRWindow = DVRMetrics ? DVRMetrics.range : null;
+ var actualTime;
+
+ if (!DVRWindow) return NaN;
+
+ if (currentTime >= DVRWindow.start && currentTime <= DVRWindow.end) {
+ return currentTime;
+ }
+
+ actualTime = Math.max(DVRWindow.end - streamInfo.manifestInfo.minBufferTime * 2, DVRWindow.start);
+
+ return actualTime;
+ }
+
+ function startUpdatingWallclockTime() {
+ if (wallclockTimeIntervalId !== null) return;
+
+ var tick = function tick() {
+ onWallclockTime();
+ };
+
+ wallclockTimeIntervalId = setInterval(tick, mediaPlayerModel.getWallclockTimeUpdateInterval());
+ }
+
+ function stopUpdatingWallclockTime() {
+ clearInterval(wallclockTimeIntervalId);
+ wallclockTimeIntervalId = null;
+ }
+
+ function seekToStartTimeOffset() {
+ var initialSeekTime = getStreamStartTime(false);
+ if (initialSeekTime > 0) {
+ seek(initialSeekTime);
+ log('Starting playback at offset: ' + initialSeekTime);
+ }
+ }
+
+ function updateCurrentTime() {
+ if (isPaused() || !isDynamic || element.readyState === 0) return;
+ var currentTime = getTime();
+ var actualTime = getActualPresentationTime(currentTime);
+ var timeChanged = !isNaN(actualTime) && actualTime !== currentTime;
+ if (timeChanged) {
+ seek(actualTime);
+ }
+ }
+
+ function onDataUpdateCompleted(e) {
+ if (e.error) return;
+
+ var representationInfo = adapter.convertDataToTrack(manifestModel.getValue(), e.currentRepresentation);
+ var info = representationInfo.mediaInfo.streamInfo;
+
+ if (streamInfo.id !== info.id) return;
+ streamInfo = info;
+
+ updateCurrentTime();
+ }
+
+ function onLiveEdgeSearchCompleted(e) {
+ //This is here to catch the case when live edge search takes longer than playback metadata
+ if (e.error || element.readyState === 0) return;
+ seekToStartTimeOffset();
+ }
+
+ function onCanPlay() {
+ eventBus.trigger(_coreEventsEvents2['default'].CAN_PLAY);
+ }
+
+ function onPlaybackStart() {
+ log('Native video element event: play');
+ updateCurrentTime();
+ startUpdatingWallclockTime();
+ eventBus.trigger(_coreEventsEvents2['default'].PLAYBACK_STARTED, { startTime: getTime() });
+ }
+
+ function onPlaybackPlaying() {
+ log('Native video element event: playing');
+ eventBus.trigger(_coreEventsEvents2['default'].PLAYBACK_PLAYING, { playingTime: getTime() });
+ }
+
+ function onPlaybackPaused() {
+ log('Native video element event: pause');
+ eventBus.trigger(_coreEventsEvents2['default'].PLAYBACK_PAUSED, { ended: getEnded() });
+ }
+
+ function onPlaybackSeeking() {
+ var seekTime = getTime();
+ log('Seeking to: ' + seekTime);
+ startUpdatingWallclockTime();
+ eventBus.trigger(_coreEventsEvents2['default'].PLAYBACK_SEEKING, { seekTime: seekTime });
+ }
+
+ function onPlaybackSeeked() {
+ log('Native video element event: seeked');
+ eventBus.trigger(_coreEventsEvents2['default'].PLAYBACK_SEEKED);
+ }
+
+ function onPlaybackTimeUpdated() {
+ //log("Native video element event: timeupdate");
+ var time = getTime();
+ if (time === currentTime) return;
+ currentTime = time;
+ eventBus.trigger(_coreEventsEvents2['default'].PLAYBACK_TIME_UPDATED, { timeToEnd: getTimeToStreamEnd(), time: time });
+ }
+
+ function onPlaybackProgress() {
+ //log("Native video element event: progress");
+ eventBus.trigger(_coreEventsEvents2['default'].PLAYBACK_PROGRESS);
+ }
+
+ function onPlaybackRateChanged() {
+ var rate = getPlaybackRate();
+ log('Native video element event: ratechange: ', rate);
+ eventBus.trigger(_coreEventsEvents2['default'].PLAYBACK_RATE_CHANGED, { playbackRate: rate });
+ }
+
+ function onPlaybackMetaDataLoaded() {
+ log('Native video element event: loadedmetadata');
+ if (!isDynamic && streamInfo.isFirst || timelineConverter.isTimeSyncCompleted()) {
+ seekToStartTimeOffset();
+ }
+ eventBus.trigger(_coreEventsEvents2['default'].PLAYBACK_METADATA_LOADED);
+ startUpdatingWallclockTime();
+ }
+
+ function onPlaybackEnded() {
+ log('Native video element event: ended');
+ pause();
+ stopUpdatingWallclockTime();
+ eventBus.trigger(_coreEventsEvents2['default'].PLAYBACK_ENDED);
+ }
+
+ function onPlaybackError(event) {
+ var target = event.target || event.srcElement;
+ eventBus.trigger(_coreEventsEvents2['default'].PLAYBACK_ERROR, { error: target.error });
+ }
+
+ function onWallclockTime() {
+ eventBus.trigger(_coreEventsEvents2['default'].WALLCLOCK_TIME_UPDATED, { isDynamic: isDynamic, time: new Date() });
+ }
+
+ function onBytesAppended(e) {
+ var ranges = e.bufferedRanges;
+ if (!ranges || !ranges.length) return;
+ var bufferedStart = Math.max(ranges.start(0), streamInfo.start);
+ var earliestTime = commonEarliestTime[streamInfo.id] === undefined ? bufferedStart : Math.max(commonEarliestTime[streamInfo.id], bufferedStart);
+ if (earliestTime === commonEarliestTime[streamInfo.id]) return;
+ if (!isDynamic && getStreamStartTime(true) < earliestTime && getTime() < earliestTime) {
+ seek(earliestTime);
+ }
+ commonEarliestTime[streamInfo.id] = earliestTime;
+ }
+
+ function onBufferLevelStateChanged(e) {
+ // do not stall playback when get an event from Stream that is not active
+ if (e.streamInfo.id !== streamInfo.id) return;
+ videoModel.setStallState(e.mediaType, e.state === _BufferController2['default'].BUFFER_EMPTY);
+ }
+
+ function addAllListeners() {
+ element.addEventListener('canplay', onCanPlay);
+ element.addEventListener('play', onPlaybackStart);
+ element.addEventListener('playing', onPlaybackPlaying);
+ element.addEventListener('pause', onPlaybackPaused);
+ element.addEventListener('error', onPlaybackError);
+ element.addEventListener('seeking', onPlaybackSeeking);
+ element.addEventListener('seeked', onPlaybackSeeked);
+ element.addEventListener('timeupdate', onPlaybackTimeUpdated);
+ element.addEventListener('progress', onPlaybackProgress);
+ element.addEventListener('ratechange', onPlaybackRateChanged);
+ element.addEventListener('loadedmetadata', onPlaybackMetaDataLoaded);
+ element.addEventListener('ended', onPlaybackEnded);
+ }
+
+ function removeAllListeners() {
+ element.removeEventListener('canplay', onCanPlay);
+ element.removeEventListener('play', onPlaybackStart);
+ element.removeEventListener('playing', onPlaybackPlaying);
+ element.removeEventListener('pause', onPlaybackPaused);
+ element.removeEventListener('error', onPlaybackError);
+ element.removeEventListener('seeking', onPlaybackSeeking);
+ element.removeEventListener('seeked', onPlaybackSeeked);
+ element.removeEventListener('timeupdate', onPlaybackTimeUpdated);
+ element.removeEventListener('progress', onPlaybackProgress);
+ element.removeEventListener('ratechange', onPlaybackRateChanged);
+ element.removeEventListener('loadedmetadata', onPlaybackMetaDataLoaded);
+ element.removeEventListener('ended', onPlaybackEnded);
+ }
+
+ instance = {
+ initialize: initialize,
+ setConfig: setConfig,
+ getStreamStartTime: getStreamStartTime,
+ getTimeToStreamEnd: getTimeToStreamEnd,
+ isPlaybackStarted: isPlaybackStarted,
+ getStreamId: getStreamId,
+ getStreamDuration: getStreamDuration,
+ getTime: getTime,
+ getPlaybackRate: getPlaybackRate,
+ getPlayedRanges: getPlayedRanges,
+ getEnded: getEnded,
+ getIsDynamic: getIsDynamic,
+ setLiveStartTime: setLiveStartTime,
+ getLiveStartTime: getLiveStartTime,
+ computeLiveDelay: computeLiveDelay,
+ play: play,
+ isPaused: isPaused,
+ pause: pause,
+ isSeeking: isSeeking,
+ seek: seek,
+ reset: reset
+ };
+
+ setup();
+
+ return instance;
+}
+
+PlaybackController.__dashjs_factory_name = 'PlaybackController';
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(PlaybackController);
+module.exports = exports['default'];
+
+},{"10":10,"101":101,"103":103,"13":13,"63":63,"8":8,"9":9}],69:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _voMetricsPlayList = _dereq_(181);
+
+var _PlaybackController = _dereq_(68);
+
+var _PlaybackController2 = _interopRequireDefault(_PlaybackController);
+
+var _AbrController = _dereq_(60);
+
+var _AbrController2 = _interopRequireDefault(_AbrController);
+
+var _BufferController = _dereq_(63);
+
+var _BufferController2 = _interopRequireDefault(_BufferController);
+
+var _MediaController = _dereq_(66);
+
+var _MediaController2 = _interopRequireDefault(_MediaController);
+
+var _rulesSchedulingBufferLevelRule = _dereq_(140);
+
+var _rulesSchedulingBufferLevelRule2 = _interopRequireDefault(_rulesSchedulingBufferLevelRule);
+
+var _rulesSchedulingNextFragmentRequestRule = _dereq_(141);
+
+var _rulesSchedulingNextFragmentRequestRule2 = _interopRequireDefault(_rulesSchedulingNextFragmentRequestRule);
+
+var _TextSourceBuffer = _dereq_(56);
+
+var _TextSourceBuffer2 = _interopRequireDefault(_TextSourceBuffer);
+
+var _modelsMetricsModel = _dereq_(102);
+
+var _modelsMetricsModel2 = _interopRequireDefault(_modelsMetricsModel);
+
+var _modelsFragmentModel = _dereq_(99);
+
+var _modelsFragmentModel2 = _interopRequireDefault(_modelsFragmentModel);
+
+var _dashDashMetrics = _dereq_(17);
+
+var _dashDashMetrics2 = _interopRequireDefault(_dashDashMetrics);
+
+var _dashDashAdapter = _dereq_(15);
+
+var _dashDashAdapter2 = _interopRequireDefault(_dashDashAdapter);
+
+var _controllersSourceBufferController = _dereq_(70);
+
+var _controllersSourceBufferController2 = _interopRequireDefault(_controllersSourceBufferController);
+
+var _utilsLiveEdgeFinder = _dereq_(154);
+
+var _utilsLiveEdgeFinder2 = _interopRequireDefault(_utilsLiveEdgeFinder);
+
+var _coreEventBus = _dereq_(9);
+
+var _coreEventBus2 = _interopRequireDefault(_coreEventBus);
+
+var _coreEventsEvents = _dereq_(13);
+
+var _coreEventsEvents2 = _interopRequireDefault(_coreEventsEvents);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _controllersStreamController = _dereq_(71);
+
+var _controllersStreamController2 = _interopRequireDefault(_controllersStreamController);
+
+var _coreDebug = _dereq_(8);
+
+var _coreDebug2 = _interopRequireDefault(_coreDebug);
+
+function ScheduleController(config) {
+
+ var context = this.context;
+ var log = (0, _coreDebug2['default'])(context).getInstance().log;
+ var eventBus = (0, _coreEventBus2['default'])(context).getInstance();
+ var metricsModel = config.metricsModel;
+ var manifestModel = config.manifestModel;
+ var adapter = config.adapter;
+ var dashMetrics = config.dashMetrics;
+ var dashManifestModel = config.dashManifestModel;
+ var timelineConverter = config.timelineConverter;
+ var mediaPlayerModel = config.mediaPlayerModel;
+
+ var instance = undefined,
+ type = undefined,
+ ready = undefined,
+ fragmentModel = undefined,
+ isDynamic = undefined,
+ currentRepresentationInfo = undefined,
+ initialPlayback = undefined,
+ isStopped = undefined,
+ playListMetrics = undefined,
+ playListTraceMetrics = undefined,
+ playListTraceMetricsClosed = undefined,
+ isFragmentProcessingInProgress = undefined,
+ timeToLoadDelay = undefined,
+ scheduleTimeout = undefined,
+ seekTarget = undefined,
+ playbackController = undefined,
+ mediaController = undefined,
+ abrController = undefined,
+ streamProcessor = undefined,
+ streamController = undefined,
+ fragmentController = undefined,
+ liveEdgeFinder = undefined,
+ bufferController = undefined,
+ bufferLevelRule = undefined,
+ nextFragmentRequestRule = undefined,
+ scheduleWhilePaused = undefined,
+ lastQualityIndex = undefined,
+ lastInitQuality = undefined,
+ replaceRequestArray = undefined;
+
+ function setup() {
+ initialPlayback = true;
+ lastInitQuality = NaN;
+ lastQualityIndex = NaN;
+ replaceRequestArray = [];
+ isStopped = false;
+ playListMetrics = null;
+ playListTraceMetrics = null;
+ playListTraceMetricsClosed = true;
+ isFragmentProcessingInProgress = false;
+ timeToLoadDelay = 0;
+ seekTarget = NaN;
+ }
+
+ function initialize(Type, StreamProcessor) {
+ type = Type;
+ streamProcessor = StreamProcessor;
+ liveEdgeFinder = (0, _utilsLiveEdgeFinder2['default'])(context).getInstance();
+ playbackController = (0, _PlaybackController2['default'])(context).getInstance();
+ mediaController = (0, _MediaController2['default'])(context).getInstance();
+ abrController = (0, _AbrController2['default'])(context).getInstance();
+ streamController = (0, _controllersStreamController2['default'])(context).getInstance();
+ fragmentController = streamProcessor.getFragmentController();
+ bufferController = streamProcessor.getBufferController();
+ fragmentModel = fragmentController.getModel(type);
+ fragmentModel.setScheduleController(this);
+ isDynamic = streamProcessor.isDynamic();
+ scheduleWhilePaused = mediaPlayerModel.getScheduleWhilePaused();
+
+ bufferLevelRule = (0, _rulesSchedulingBufferLevelRule2['default'])(context).create({
+ dashMetrics: (0, _dashDashMetrics2['default'])(context).getInstance(),
+ metricsModel: (0, _modelsMetricsModel2['default'])(context).getInstance(),
+ textSourceBuffer: (0, _TextSourceBuffer2['default'])(context).getInstance()
+ });
+
+ nextFragmentRequestRule = (0, _rulesSchedulingNextFragmentRequestRule2['default'])(context).create({
+ adapter: (0, _dashDashAdapter2['default'])(context).getInstance(),
+ sourceBufferController: (0, _controllersSourceBufferController2['default'])(context).getInstance(),
+ textSourceBuffer: (0, _TextSourceBuffer2['default'])(context).getInstance()
+
+ });
+
+ if (dashManifestModel.getIsTextTrack(type)) {
+ eventBus.on(_coreEventsEvents2['default'].TIMED_TEXT_REQUESTED, onTimedTextRequested, this);
+ }
+
+ eventBus.on(_coreEventsEvents2['default'].LIVE_EDGE_SEARCH_COMPLETED, onLiveEdgeSearchCompleted, this);
+ eventBus.on(_coreEventsEvents2['default'].QUALITY_CHANGE_REQUESTED, onQualityChanged, this);
+ eventBus.on(_coreEventsEvents2['default'].DATA_UPDATE_STARTED, onDataUpdateStarted, this);
+ eventBus.on(_coreEventsEvents2['default'].DATA_UPDATE_COMPLETED, onDataUpdateCompleted, this);
+ eventBus.on(_coreEventsEvents2['default'].FRAGMENT_LOADING_COMPLETED, onFragmentLoadingCompleted, this);
+ eventBus.on(_coreEventsEvents2['default'].STREAM_COMPLETED, onStreamCompleted, this);
+ eventBus.on(_coreEventsEvents2['default'].STREAM_INITIALIZED, onStreamInitialized, this);
+ eventBus.on(_coreEventsEvents2['default'].BUFFER_LEVEL_STATE_CHANGED, onBufferLevelStateChanged, this);
+ eventBus.on(_coreEventsEvents2['default'].BUFFER_CLEARED, onBufferCleared, this);
+ eventBus.on(_coreEventsEvents2['default'].BYTES_APPENDED, onBytesAppended, this);
+ eventBus.on(_coreEventsEvents2['default'].INIT_REQUESTED, onInitRequested, this);
+ eventBus.on(_coreEventsEvents2['default'].QUOTA_EXCEEDED, onQuotaExceeded, this);
+ eventBus.on(_coreEventsEvents2['default'].BUFFER_LEVEL_STATE_CHANGED, onBufferLevelStateChanged, this);
+ eventBus.on(_coreEventsEvents2['default'].PLAYBACK_STARTED, onPlaybackStarted, this);
+ eventBus.on(_coreEventsEvents2['default'].PLAYBACK_SEEKING, onPlaybackSeeking, this);
+ eventBus.on(_coreEventsEvents2['default'].PLAYBACK_RATE_CHANGED, onPlaybackRateChanged, this);
+ eventBus.on(_coreEventsEvents2['default'].PLAYBACK_TIME_UPDATED, onPlaybackTimeUpdated, this);
+ eventBus.on(_coreEventsEvents2['default'].URL_RESOLUTION_FAILED, onURLResolutionFailed, this);
+ eventBus.on(_coreEventsEvents2['default'].FRAGMENT_LOADING_ABANDONED, onFragmentLoadingAbandoned, this);
+ }
+
+ function start() {
+ if (!ready) return;
+ addPlaylistTraceMetrics();
+ isStopped = false;
+
+ if (initialPlayback) {
+ getInitRequest(currentRepresentationInfo.quality);
+ } else {
+ //schedule will be first called after the init segment is appended. But in the case where we stop and start
+ //the ScheduleController E.g dateUpdate on manifest refresh for live streams. we need to start schedule again.
+ startScheduleTimer(0);
+ }
+
+ if (initialPlayback) {
+ initialPlayback = false;
+ }
+ log('Schedule controller starting for ' + type);
+ }
+
+ function stop() {
+ if (isStopped) return;
+ isStopped = true;
+ clearTimeout(scheduleTimeout);
+ log('Schedule controller stopping for ' + type);
+ }
+
+ function schedule() {
+
+ if (isStopped || isFragmentProcessingInProgress || !bufferController || playbackController.isPaused() && !scheduleWhilePaused) return;
+
+ validateExecutedFragmentRequest();
+
+ var isReplacement = replaceRequestArray.length > 0;
+ var readyToLoad = bufferLevelRule.execute(streamProcessor, type, streamController.isVideoTrackPresent());
+
+ if (readyToLoad || isReplacement) {
+ var getNextFragment = function getNextFragment() {
+ if (currentRepresentationInfo.quality !== lastInitQuality) {
+ lastInitQuality = currentRepresentationInfo.quality;
+ bufferController.switchInitData(streamProcessor.getStreamInfo().id, currentRepresentationInfo.quality);
+ } else {
+
+ var request = nextFragmentRequestRule.execute(streamProcessor, replaceRequestArray.shift());
+ if (request) {
+ fragmentModel.executeRequest(request);
+ } else {
+ //Use case - Playing at the bleeding live edge and frag is not available yet. Cycle back around.
+ isFragmentProcessingInProgress = false;
+ startScheduleTimer(250);
+ }
+ }
+ };
+
+ isFragmentProcessingInProgress = true;
+ if (isReplacement) {
+ getNextFragment();
+ } else {
+ abrController.getPlaybackQuality(streamProcessor, getNextFragment);
+ }
+ } else {
+ startScheduleTimer(500);
+ }
+ }
+
+ function validateExecutedFragmentRequest() {
+ //Validate that the fragment request executed and appended into the source buffer is as
+ // good of quality as the current quality and is the correct media track.
+ var safeBufferLevel = currentRepresentationInfo.fragmentDuration * 1.5;
+ var request = fragmentModel.getRequests({ state: _modelsFragmentModel2['default'].FRAGMENT_MODEL_EXECUTED, time: playbackController.getTime() + safeBufferLevel, threshold: 0 })[0];
+
+ if (request && replaceRequestArray.indexOf(request) === -1 && !dashManifestModel.getIsTextTrack(type)) {
+ if (!mediaController.isCurrentTrack(request.mediaInfo) || mediaPlayerModel.getFastSwitchEnabled() && request.quality < currentRepresentationInfo.quality && bufferController.getBufferLevel() >= safeBufferLevel && abrController.getAbandonmentStateFor(type) !== _AbrController2['default'].ABANDON_LOAD) {
+ replaceRequest(request);
+ log('Reloading outdated fragment at index: ', request.index);
+ } else if (request.quality > currentRepresentationInfo.quality) {
+ //The buffer has better quality it in then what we would request so set append point to end of buffer!!
+ setSeekTarget(playbackController.getTime() + bufferController.getBufferLevel());
+ }
+ }
+ }
+
+ function startScheduleTimer(value) {
+ clearTimeout(scheduleTimeout);
+ scheduleTimeout = setTimeout(schedule, value);
+ }
+
+ function onInitRequested(e) {
+ if (e.sender.getStreamProcessor() !== streamProcessor) return;
+ getInitRequest(currentRepresentationInfo.quality);
+ }
+
+ function getInitRequest(quality) {
+ lastInitQuality = quality;
+
+ var request = adapter.getInitRequest(streamProcessor, quality);
+ if (request) {
+ isFragmentProcessingInProgress = true;
+ fragmentModel.executeRequest(request);
+ }
+ }
+
+ function replaceRequest(request) {
+ replaceRequestArray.push(request);
+ }
+
+ function onQualityChanged(e) {
+ if (type !== e.mediaType || streamProcessor.getStreamInfo().id !== e.streamInfo.id) return;
+
+ currentRepresentationInfo = streamProcessor.getRepresentationInfoForQuality(e.newQuality);
+
+ if (currentRepresentationInfo === null || currentRepresentationInfo === undefined) {
+ throw new Error('Unexpected error! - currentRepresentationInfo is null or undefined');
+ }
+
+ clearPlayListTraceMetrics(new Date(), _voMetricsPlayList.PlayListTrace.REPRESENTATION_SWITCH_STOP_REASON);
+ addPlaylistTraceMetrics();
+ }
+
+ function completeQualityChange(trigger) {
+ var item = fragmentModel.getRequests({ state: _modelsFragmentModel2['default'].FRAGMENT_MODEL_EXECUTED, time: playbackController.getTime(), threshold: 0 })[0];
+ if (item && playbackController.getTime() >= item.startTime) {
+ if (item.quality !== lastQualityIndex && trigger) {
+ eventBus.trigger(_coreEventsEvents2['default'].QUALITY_CHANGE_RENDERED, { mediaType: type, oldQuality: lastQualityIndex, newQuality: item.quality });
+ }
+ lastQualityIndex = item.quality;
+ }
+ }
+
+ function onDataUpdateCompleted(e) {
+ if (e.error || e.sender.getStreamProcessor() !== streamProcessor) return;
+ currentRepresentationInfo = adapter.convertDataToTrack(manifestModel.getValue(), e.currentRepresentation);
+ }
+
+ function onStreamInitialized(e) {
+ if (e.error || streamProcessor.getStreamInfo().id !== e.streamInfo.id) return;
+ currentRepresentationInfo = streamProcessor.getCurrentRepresentationInfo();
+ if (!isDynamic || liveEdgeFinder.getLiveEdge() !== null) {
+ ready = true;
+ }
+ if (isStopped) {
+ start();
+ }
+ }
+
+ function onStreamCompleted(e) {
+ if (e.fragmentModel !== fragmentModel) return;
+ stop();
+ isFragmentProcessingInProgress = false;
+ log('Stream is complete');
+ }
+
+ function onFragmentLoadingCompleted(e) {
+ if (e.sender !== fragmentModel) return;
+
+ if (dashManifestModel.getIsTextTrack(type)) {
+ isFragmentProcessingInProgress = false;
+ }
+
+ if (e.error && e.serviceLocation && !isStopped) {
+ replaceRequest(e.request);
+ }
+ }
+
+ function onPlaybackTimeUpdated() {
+ completeQualityChange(true);
+ }
+
+ function onBytesAppended(e) {
+ if (e.sender.getStreamProcessor() !== streamProcessor) return;
+ isFragmentProcessingInProgress = false;
+ startScheduleTimer(0);
+ }
+
+ function onFragmentLoadingAbandoned(e) {
+ if (e.streamProcessor !== streamProcessor) return;
+ replaceRequest(e.request);
+ isFragmentProcessingInProgress = false;
+ startScheduleTimer(0);
+ }
+
+ function onDataUpdateStarted(e) {
+ if (e.sender.getStreamProcessor() !== streamProcessor) return;
+ stop();
+ }
+
+ function onBufferCleared(e) {
+ if (e.sender.getStreamProcessor() !== streamProcessor) return;
+ // after the data has been removed from the buffer we should remove the requests from the list of
+ // the executed requests for which playback time is inside the time interval that has been removed from the buffer
+ fragmentModel.removeExecutedRequestsBeforeTime(e.to);
+
+ if (e.hasEnoughSpaceToAppend && !bufferController.getIsBufferingCompleted() && isStopped) {
+ start();
+ }
+ }
+
+ function onBufferLevelStateChanged(e) {
+ if (e.sender.getStreamProcessor() === streamProcessor && e.state === _BufferController2['default'].BUFFER_EMPTY && !playbackController.isSeeking()) {
+ log('Buffer is empty! Stalling!');
+ clearPlayListTraceMetrics(new Date(), _voMetricsPlayList.PlayListTrace.REBUFFERING_REASON);
+ }
+ }
+
+ function onQuotaExceeded(e) {
+ if (e.sender.getStreamProcessor() !== streamProcessor) return;
+ stop();
+ }
+
+ function onURLResolutionFailed() {
+ fragmentModel.abortRequests();
+ stop();
+ }
+
+ function onTimedTextRequested(e) {
+ if (e.sender.getStreamProcessor() !== streamProcessor) return;
+ getInitRequest(e.index);
+ }
+
+ function onPlaybackStarted() {
+ if (isStopped) {
+ start();
+ }
+ }
+
+ function onPlaybackSeeking(e) {
+ seekTarget = e.seekTime;
+ setTimeToLoadDelay(0);
+
+ if (isStopped) {
+ start();
+ }
+
+ var manifestUpdateInfo = dashMetrics.getCurrentManifestUpdate(metricsModel.getMetricsFor('stream'));
+ var latency = currentRepresentationInfo.DVRWindow ? currentRepresentationInfo.DVRWindow.end - playbackController.getTime() : NaN;
+ metricsModel.updateManifestUpdateInfo(manifestUpdateInfo, { latency: latency });
+ }
+
+ function onPlaybackRateChanged(e) {
+ if (playListTraceMetrics) {
+ playListTraceMetrics.playbackspeed = e.playbackRate.toString();
+ }
+ }
+
+ function onLiveEdgeSearchCompleted(e) {
+ if (e.error) return;
+
+ var dvrWindowSize = currentRepresentationInfo.mediaInfo.streamInfo.manifestInfo.DVRWindowSize / 2;
+ var startTime = e.liveEdge - playbackController.computeLiveDelay(currentRepresentationInfo.fragmentDuration, dvrWindowSize);
+ var manifestUpdateInfo = dashMetrics.getCurrentManifestUpdate(metricsModel.getMetricsFor('stream'));
+ var currentLiveStart = playbackController.getLiveStartTime();
+ var request = adapter.getFragmentRequestForTime(streamProcessor, currentRepresentationInfo, startTime, { ignoreIsFinished: true });
+
+ seekTarget = currentLiveStart;
+ if (isNaN(currentLiveStart) || request.startTime > currentLiveStart) {
+ playbackController.setLiveStartTime(request.startTime);
+ seekTarget = request.startTime;
+ }
+
+ metricsModel.updateManifestUpdateInfo(manifestUpdateInfo, {
+ currentTime: seekTarget,
+ presentationStartTime: e.liveEdge,
+ latency: e.liveEdge - seekTarget,
+ clientTimeOffset: timelineConverter.getClientTimeOffset()
+ });
+
+ ready = true;
+ if (isStopped) {
+ start();
+ }
+ }
+
+ function getSeekTarget() {
+ return seekTarget;
+ }
+
+ function setSeekTarget(value) {
+ seekTarget = value;
+ }
+
+ function getFragmentModel() {
+ return fragmentModel;
+ }
+
+ function setTimeToLoadDelay(value) {
+ timeToLoadDelay = value;
+ }
+
+ function getTimeToLoadDelay() {
+ return timeToLoadDelay;
+ }
+
+ function getStreamProcessor() {
+ return streamProcessor;
+ }
+
+ function getBufferTarget() {
+ return bufferLevelRule.getBufferTarget(streamProcessor, type, streamController.isVideoTrackPresent());
+ }
+
+ function setPlayList(playList) {
+ playListMetrics = playList;
+ }
+
+ function finalisePlayList(time, reason) {
+ clearPlayListTraceMetrics(time, reason);
+ playListMetrics = null;
+ }
+
+ function clearPlayListTraceMetrics(endTime, stopreason) {
+ if (playListMetrics && playListTraceMetricsClosed === false) {
+ var startTime = playListTraceMetrics.start;
+ var duration = endTime.getTime() - startTime.getTime();
+ playListTraceMetrics.duration = duration;
+ playListTraceMetrics.stopreason = stopreason;
+ playListMetrics.trace.push(playListTraceMetrics);
+ playListTraceMetricsClosed = true;
+ }
+ }
+
+ function addPlaylistTraceMetrics() {
+ if (playListMetrics && playListTraceMetricsClosed === true && currentRepresentationInfo) {
+ playListTraceMetricsClosed = false;
+ playListTraceMetrics = new _voMetricsPlayList.PlayListTrace();
+ playListTraceMetrics.representationid = currentRepresentationInfo.id;
+ playListTraceMetrics.start = new Date();
+ playListTraceMetrics.mstart = playbackController.getTime() * 1000;
+ playListTraceMetrics.playbackspeed = playbackController.getPlaybackRate().toString();
+ }
+ }
+
+ function reset() {
+ eventBus.off(_coreEventsEvents2['default'].LIVE_EDGE_SEARCH_COMPLETED, onLiveEdgeSearchCompleted, this);
+ eventBus.off(_coreEventsEvents2['default'].DATA_UPDATE_STARTED, onDataUpdateStarted, this);
+ eventBus.off(_coreEventsEvents2['default'].DATA_UPDATE_COMPLETED, onDataUpdateCompleted, this);
+ eventBus.off(_coreEventsEvents2['default'].BUFFER_LEVEL_STATE_CHANGED, onBufferLevelStateChanged, this);
+ eventBus.off(_coreEventsEvents2['default'].QUALITY_CHANGE_REQUESTED, onQualityChanged, this);
+ eventBus.off(_coreEventsEvents2['default'].FRAGMENT_LOADING_COMPLETED, onFragmentLoadingCompleted, this);
+ eventBus.off(_coreEventsEvents2['default'].STREAM_COMPLETED, onStreamCompleted, this);
+ eventBus.off(_coreEventsEvents2['default'].STREAM_INITIALIZED, onStreamInitialized, this);
+ eventBus.off(_coreEventsEvents2['default'].QUOTA_EXCEEDED, onQuotaExceeded, this);
+ eventBus.off(_coreEventsEvents2['default'].BYTES_APPENDED, onBytesAppended, this);
+ eventBus.off(_coreEventsEvents2['default'].BUFFER_CLEARED, onBufferCleared, this);
+ eventBus.off(_coreEventsEvents2['default'].INIT_REQUESTED, onInitRequested, this);
+ eventBus.off(_coreEventsEvents2['default'].PLAYBACK_RATE_CHANGED, onPlaybackRateChanged, this);
+ eventBus.off(_coreEventsEvents2['default'].PLAYBACK_SEEKING, onPlaybackSeeking, this);
+ eventBus.off(_coreEventsEvents2['default'].PLAYBACK_STARTED, onPlaybackStarted, this);
+ eventBus.off(_coreEventsEvents2['default'].PLAYBACK_TIME_UPDATED, onPlaybackTimeUpdated, this);
+ eventBus.off(_coreEventsEvents2['default'].URL_RESOLUTION_FAILED, onURLResolutionFailed, this);
+ eventBus.off(_coreEventsEvents2['default'].FRAGMENT_LOADING_ABANDONED, onFragmentLoadingAbandoned, this);
+ if (dashManifestModel.getIsTextTrack(type)) {
+ eventBus.off(_coreEventsEvents2['default'].TIMED_TEXT_REQUESTED, onTimedTextRequested, this);
+ }
+
+ stop();
+ completeQualityChange(false);
+ isFragmentProcessingInProgress = false;
+ timeToLoadDelay = 0;
+ seekTarget = NaN;
+ playbackController = null;
+ playListMetrics = null;
+ }
+
+ instance = {
+ initialize: initialize,
+ getStreamProcessor: getStreamProcessor,
+ getSeekTarget: getSeekTarget,
+ setSeekTarget: setSeekTarget,
+ getFragmentModel: getFragmentModel,
+ setTimeToLoadDelay: setTimeToLoadDelay,
+ getTimeToLoadDelay: getTimeToLoadDelay,
+ replaceRequest: replaceRequest,
+ start: start,
+ stop: stop,
+ reset: reset,
+ setPlayList: setPlayList,
+ getBufferTarget: getBufferTarget,
+ finalisePlayList: finalisePlayList
+ };
+
+ setup();
+
+ return instance;
+}
+
+ScheduleController.__dashjs_factory_name = 'ScheduleController';
+exports['default'] = _coreFactoryMaker2['default'].getClassFactory(ScheduleController);
+module.exports = exports['default'];
+
+},{"10":10,"102":102,"13":13,"140":140,"141":141,"15":15,"154":154,"17":17,"181":181,"56":56,"60":60,"63":63,"66":66,"68":68,"70":70,"71":71,"8":8,"9":9,"99":99}],70:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _TextSourceBuffer = _dereq_(56);
+
+var _TextSourceBuffer2 = _interopRequireDefault(_TextSourceBuffer);
+
+var _MediaController = _dereq_(66);
+
+var _MediaController2 = _interopRequireDefault(_MediaController);
+
+var _dashDashAdapter = _dereq_(15);
+
+var _dashDashAdapter2 = _interopRequireDefault(_dashDashAdapter);
+
+var _utilsErrorHandler = _dereq_(151);
+
+var _utilsErrorHandler2 = _interopRequireDefault(_utilsErrorHandler);
+
+var _StreamController = _dereq_(71);
+
+var _StreamController2 = _interopRequireDefault(_StreamController);
+
+var _TextTracks = _dereq_(57);
+
+var _TextTracks2 = _interopRequireDefault(_TextTracks);
+
+var _utilsVTTParser = _dereq_(159);
+
+var _utilsVTTParser2 = _interopRequireDefault(_utilsVTTParser);
+
+var _utilsTTMLParser = _dereq_(157);
+
+var _utilsTTMLParser2 = _interopRequireDefault(_utilsTTMLParser);
+
+var _modelsVideoModel = _dereq_(104);
+
+var _modelsVideoModel2 = _interopRequireDefault(_modelsVideoModel);
+
+var _voError = _dereq_(162);
+
+var _voError2 = _interopRequireDefault(_voError);
+
+var _coreEventBus = _dereq_(9);
+
+var _coreEventBus2 = _interopRequireDefault(_coreEventBus);
+
+var _coreEventsEvents = _dereq_(13);
+
+var _coreEventsEvents2 = _interopRequireDefault(_coreEventsEvents);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var QUOTA_EXCEEDED_ERROR_CODE = 22;
+
+function SourceBufferController() {
+
+ var context = this.context;
+ var eventBus = (0, _coreEventBus2['default'])(context).getInstance();
+
+ var instance = undefined,
+ dashManifestModel = undefined;
+
+ function createSourceBuffer(mediaSource, mediaInfo) {
+
+ var codec = mediaInfo.codec;
+ var buffer = null;
+
+ try {
+ // Safari claims to support anything starting 'application/mp4'.
+ // it definitely doesn't understand 'application/mp4;codecs="stpp"'
+ // - currently no browser does, so check for it and use our own
+ // implementation. The same is true for codecs="wvtt".
+ if (codec.match(/application\/mp4;\s*codecs="(stpp|wvtt)"/i)) {
+ throw new _voError2['default']('not really supported');
+ }
+
+ buffer = mediaSource.addSourceBuffer(codec);
+ } catch (ex) {
+ if (mediaInfo.isText || codec.indexOf('codecs="stpp"') !== -1 || codec.indexOf('codecs="wvtt"') !== -1) {
+ buffer = (0, _TextSourceBuffer2['default'])(context).getInstance();
+ buffer.setConfig({
+ errHandler: (0, _utilsErrorHandler2['default'])(context).getInstance(),
+ adapter: (0, _dashDashAdapter2['default'])(context).getInstance(),
+ dashManifestModel: dashManifestModel,
+ mediaController: (0, _MediaController2['default'])(context).getInstance(),
+ videoModel: (0, _modelsVideoModel2['default'])(context).getInstance(),
+ streamController: (0, _StreamController2['default'])(context).getInstance(),
+ textTracks: (0, _TextTracks2['default'])(context).getInstance(),
+ VTTParser: (0, _utilsVTTParser2['default'])(context).getInstance(),
+ TTMLParser: (0, _utilsTTMLParser2['default'])(context).getInstance()
+
+ });
+ } else {
+ throw ex;
+ }
+ }
+
+ return buffer;
+ }
+
+ function removeSourceBuffer(mediaSource, buffer) {
+ try {
+ mediaSource.removeSourceBuffer(buffer);
+ } catch (ex) {}
+ }
+
+ function getBufferRange(buffer, time, tolerance) {
+ var ranges = null;
+ var start = 0;
+ var end = 0;
+ var firstStart = null;
+ var lastEnd = null;
+ var gap = 0;
+
+ var len, i;
+
+ var toler = tolerance || 0.15;
+
+ try {
+ ranges = buffer.buffered;
+ } catch (ex) {
+ return null;
+ }
+
+ if (ranges !== null && ranges !== undefined) {
+ for (i = 0, len = ranges.length; i < len; i++) {
+ start = ranges.start(i);
+ end = ranges.end(i);
+ if (firstStart === null) {
+ gap = Math.abs(start - time);
+ if (time >= start && time < end) {
+ // start the range
+ firstStart = start;
+ lastEnd = end;
+ } else if (gap <= toler) {
+ // start the range even though the buffer does not contain time 0
+ firstStart = start;
+ lastEnd = end;
+ }
+ } else {
+ gap = start - lastEnd;
+ if (gap <= toler) {
+ // the discontinuity is smaller than the tolerance, combine the ranges
+ lastEnd = end;
+ } else {
+ break;
+ }
+ }
+ }
+
+ if (firstStart !== null) {
+ return { start: firstStart, end: lastEnd };
+ }
+ }
+
+ return null;
+ }
+
+ function getAllRanges(buffer) {
+ var ranges = null;
+
+ try {
+ ranges = buffer.buffered;
+ return ranges;
+ } catch (ex) {
+ return null;
+ }
+ }
+
+ function getTotalBufferedTime(buffer) {
+ var ranges = getAllRanges(buffer);
+ var totalBufferedTime = 0;
+ var ln, i;
+
+ if (!ranges) return totalBufferedTime;
+
+ for (i = 0, ln = ranges.length; i < ln; i++) {
+ totalBufferedTime += ranges.end(i) - ranges.start(i);
+ }
+
+ return totalBufferedTime;
+ }
+
+ function getBufferLength(buffer, time, tolerance) {
+
+ var range, length;
+
+ range = getBufferRange(buffer, time, tolerance);
+
+ if (range === null) {
+ length = 0;
+ } else {
+ length = range.end - time;
+ }
+
+ return length;
+ }
+
+ function getRangeDifference(currentRanges, buffer) {
+ if (!buffer) return null;
+
+ //TODO we may need to look for a more elegant and robust method
+ // The logic below checks that is the difference between currentRanges and actual SourceBuffer ranges
+
+ var newRanges = getAllRanges(buffer);
+ var newStart, newEnd, equalStart, equalEnd, currentRange, nextCurrentRange, nextNewRange, hasRange, diff;
+
+ if (!newRanges) return null;
+
+ for (var i = 0, ln = newRanges.length; i < ln; i++) {
+ hasRange = currentRanges.length > i;
+ currentRange = hasRange ? { start: currentRanges.start(i), end: currentRanges.end(i) } : null;
+ newStart = newRanges.start(i);
+ newEnd = newRanges.end(i);
+
+ // if there is no range with the same index it means that a new range has been added. This range is
+ // the difference we are looking for
+ // Example
+ // current ranges
+ // 0|---range1---|4 8|--range2--|12
+ // new ranges
+ // 0|---range1---|4| 8|--range2--|12 16|--range3--|20
+
+ if (!currentRange) {
+ diff = { start: newStart, end: newEnd };
+ return diff;
+ }
+
+ equalStart = currentRange.start === newStart;
+ equalEnd = currentRange.end === newEnd;
+
+ // if ranges are equal do nothing here and go the next ranges
+ if (equalStart && equalEnd) continue;
+
+ // start or/and end of the range has been changed
+ if (equalStart) {
+ diff = { start: currentRange.end, end: newEnd };
+ } else if (equalEnd) {
+ diff = { start: newStart, end: currentRange.start };
+ } else {
+ // new range has been added before the current one
+ diff = { start: newStart, end: newEnd };
+ return diff;
+ }
+
+ // if there is next current range but no next new range (it it is not equal the next current range) it means
+ // that the ranges have been merged
+ // Example 1
+ // current ranges
+ // 0|---range1---|4 8|--range2--|12 16|---range3---|
+ // new ranges
+ // 0|-----------range1-----------|12 16|---range3--|
+ nextCurrentRange = currentRanges.length > i + 1 ? { start: currentRanges.start(i + 1), end: currentRanges.end(i + 1) } : null;
+ nextNewRange = i + 1 < ln ? { start: newRanges.start(i + 1), end: newRanges.end(i + 1) } : null;
+
+ if (nextCurrentRange && (!nextNewRange || nextNewRange.start !== nextCurrentRange.start || nextNewRange.end !== nextCurrentRange.end)) {
+ diff.end = nextCurrentRange.start;
+ }
+
+ return diff;
+ }
+
+ return null;
+ }
+
+ function append(buffer, chunk) {
+ var bytes = chunk.bytes;
+ var appendMethod = 'append' in buffer ? 'append' : 'appendBuffer' in buffer ? 'appendBuffer' : null;
+ // our user-defined sourcebuffer-like object has Object as its
+ // prototype whereas built-in SourceBuffers will have something
+ // more sensible. do not pass chunk to built-in append.
+ var acceptsChunk = Object.prototype.toString.call(buffer).slice(8, -1) === 'Object';
+
+ if (!appendMethod) return;
+
+ try {
+ waitForUpdateEnd(buffer, function () {
+ if (acceptsChunk) {
+ // chunk.start is used in calculations by TextSourceBuffer
+ buffer[appendMethod](bytes, chunk);
+ } else {
+ buffer[appendMethod](bytes);
+ }
+ // updating is in progress, we should wait for it to complete before signaling that this operation is done
+ waitForUpdateEnd(buffer, function () {
+ eventBus.trigger(_coreEventsEvents2['default'].SOURCEBUFFER_APPEND_COMPLETED, { buffer: buffer, bytes: bytes });
+ });
+ });
+ } catch (err) {
+ eventBus.trigger(_coreEventsEvents2['default'].SOURCEBUFFER_APPEND_COMPLETED, { buffer: buffer, bytes: bytes, error: new _voError2['default'](err.code, err.message, null) });
+ }
+ }
+
+ function remove(buffer, start, end, mediaSource) {
+
+ try {
+ // make sure that the given time range is correct. Otherwise we will get InvalidAccessError
+ waitForUpdateEnd(buffer, function () {
+ if (start >= 0 && end > start && mediaSource.readyState !== 'ended') {
+ buffer.remove(start, end);
+ }
+ // updating is in progress, we should wait for it to complete before signaling that this operation is done
+ waitForUpdateEnd(buffer, function () {
+ eventBus.trigger(_coreEventsEvents2['default'].SOURCEBUFFER_REMOVE_COMPLETED, { buffer: buffer, from: start, to: end });
+ });
+ });
+ } catch (err) {
+ eventBus.trigger(_coreEventsEvents2['default'].SOURCEBUFFER_REMOVE_COMPLETED, { buffer: buffer, from: start, to: end, error: new _voError2['default'](err.code, err.message, null) });
+ }
+ }
+
+ function abort(mediaSource, buffer) {
+ try {
+ if (mediaSource.readyState === 'open') {
+ buffer.abort();
+ } else if (buffer.setTextTrack && mediaSource.readyState === 'ended') {
+ buffer.abort(); //The cues need to be removed from the TextSourceBuffer via a call to abort()
+ }
+ } catch (ex) {}
+ }
+
+ function setConfig(config) {
+ if (!config) return;
+
+ if (config.dashManifestModel) {
+ dashManifestModel = config.dashManifestModel;
+ }
+ }
+
+ function waitForUpdateEnd(buffer, callback) {
+ var intervalId;
+ var CHECK_INTERVAL = 50;
+
+ var checkIsUpdateEnded = function checkIsUpdateEnded() {
+ // if updating is still in progress do nothing and wait for the next check again.
+ if (buffer.updating) return;
+ // updating is completed, now we can stop checking and resolve the promise
+ clearInterval(intervalId);
+ callback();
+ };
+
+ var updateEndHandler = function updateEndHandler() {
+ if (buffer.updating) return;
+
+ buffer.removeEventListener('updateend', updateEndHandler, false);
+ callback();
+ };
+
+ if (!buffer.updating) {
+ callback();
+ return;
+ }
+
+ // use updateend event if possible
+ if (typeof buffer.addEventListener === 'function') {
+ try {
+ buffer.addEventListener('updateend', updateEndHandler, false);
+ } catch (err) {
+ // use setInterval to periodically check if updating has been completed
+ intervalId = setInterval(checkIsUpdateEnded, CHECK_INTERVAL);
+ }
+ } else {
+ // use setInterval to periodically check if updating has been completed
+ intervalId = setInterval(checkIsUpdateEnded, CHECK_INTERVAL);
+ }
+ }
+
+ instance = {
+ append: append,
+ remove: remove,
+ abort: abort,
+ createSourceBuffer: createSourceBuffer,
+ removeSourceBuffer: removeSourceBuffer,
+ getBufferRange: getBufferRange,
+ getAllRanges: getAllRanges,
+ getTotalBufferedTime: getTotalBufferedTime,
+ getBufferLength: getBufferLength,
+ getRangeDifference: getRangeDifference,
+ setConfig: setConfig
+ };
+
+ return instance;
+}
+
+SourceBufferController.__dashjs_factory_name = 'SourceBufferController';
+var factory = _coreFactoryMaker2['default'].getSingletonFactory(SourceBufferController);
+factory.QUOTA_EXCEEDED_ERROR_CODE = QUOTA_EXCEEDED_ERROR_CODE;
+exports['default'] = factory;
+module.exports = exports['default'];
+
+},{"10":10,"104":104,"13":13,"15":15,"151":151,"157":157,"159":159,"162":162,"56":56,"57":57,"66":66,"71":71,"9":9}],71:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _PlaybackController = _dereq_(68);
+
+var _PlaybackController2 = _interopRequireDefault(_PlaybackController);
+
+var _Stream = _dereq_(54);
+
+var _Stream2 = _interopRequireDefault(_Stream);
+
+var _ManifestUpdater = _dereq_(50);
+
+var _ManifestUpdater2 = _interopRequireDefault(_ManifestUpdater);
+
+var _coreEventBus = _dereq_(9);
+
+var _coreEventBus2 = _interopRequireDefault(_coreEventBus);
+
+var _coreEventsEvents = _dereq_(13);
+
+var _coreEventsEvents2 = _interopRequireDefault(_coreEventsEvents);
+
+var _modelsURIQueryAndFragmentModel = _dereq_(103);
+
+var _modelsURIQueryAndFragmentModel2 = _interopRequireDefault(_modelsURIQueryAndFragmentModel);
+
+var _modelsVideoModel = _dereq_(104);
+
+var _modelsVideoModel2 = _interopRequireDefault(_modelsVideoModel);
+
+var _modelsMediaPlayerModel = _dereq_(101);
+
+var _modelsMediaPlayerModel2 = _interopRequireDefault(_modelsMediaPlayerModel);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _voMetricsPlayList = _dereq_(181);
+
+var _coreDebug = _dereq_(8);
+
+var _coreDebug2 = _interopRequireDefault(_coreDebug);
+
+var _utilsInitCache = _dereq_(152);
+
+var _utilsInitCache2 = _interopRequireDefault(_utilsInitCache);
+
+function StreamController() {
+
+ var STREAM_END_THRESHOLD = 1.0;
+
+ var context = this.context;
+ var log = (0, _coreDebug2['default'])(context).getInstance().log;
+ var eventBus = (0, _coreEventBus2['default'])(context).getInstance();
+
+ var instance = undefined,
+ capabilities = undefined,
+ manifestUpdater = undefined,
+ manifestLoader = undefined,
+ manifestModel = undefined,
+ dashManifestModel = undefined,
+ adapter = undefined,
+ metricsModel = undefined,
+ dashMetrics = undefined,
+ liveEdgeFinder = undefined,
+ mediaSourceController = undefined,
+ timeSyncController = undefined,
+ baseURLController = undefined,
+ initCache = undefined,
+ errHandler = undefined,
+ timelineConverter = undefined,
+ streams = undefined,
+ activeStream = undefined,
+ protectionController = undefined,
+ protectionData = undefined,
+ autoPlay = undefined,
+ isStreamSwitchingInProgress = undefined,
+ isUpdating = undefined,
+ hasMediaError = undefined,
+ hasInitialisationError = undefined,
+ mediaSource = undefined,
+ videoModel = undefined,
+ playbackController = undefined,
+ mediaPlayerModel = undefined,
+ isPaused = undefined,
+ initialPlayback = undefined,
+ playListMetrics = undefined,
+ videoTrackDetected = undefined;
+
+ function setup() {
+ protectionController = null;
+ streams = [];
+ mediaPlayerModel = (0, _modelsMediaPlayerModel2['default'])(context).getInstance();
+ autoPlay = true;
+ isStreamSwitchingInProgress = false;
+ isUpdating = false;
+ isPaused = false;
+ initialPlayback = true;
+ playListMetrics = null;
+ hasMediaError = false;
+ hasInitialisationError = false;
+ }
+
+ function initialize(autoPl, protData) {
+ autoPlay = autoPl;
+ protectionData = protData;
+ timelineConverter.initialize();
+ initCache = (0, _utilsInitCache2['default'])(context).getInstance();
+
+ manifestUpdater = (0, _ManifestUpdater2['default'])(context).getInstance();
+ manifestUpdater.setConfig({
+ log: log,
+ manifestModel: manifestModel,
+ dashManifestModel: dashManifestModel
+ });
+ manifestUpdater.initialize(manifestLoader);
+
+ videoModel = (0, _modelsVideoModel2['default'])(context).getInstance();
+ playbackController = (0, _PlaybackController2['default'])(context).getInstance();
+ playbackController.setConfig({
+ streamController: instance,
+ timelineConverter: timelineConverter,
+ metricsModel: metricsModel,
+ dashMetrics: dashMetrics,
+ manifestModel: manifestModel,
+ dashManifestModel: dashManifestModel,
+ adapter: adapter,
+ videoModel: videoModel
+ });
+
+ eventBus.on(_coreEventsEvents2['default'].TIME_SYNCHRONIZATION_COMPLETED, onTimeSyncCompleted, this);
+ eventBus.on(_coreEventsEvents2['default'].PLAYBACK_SEEKING, onPlaybackSeeking, this);
+ eventBus.on(_coreEventsEvents2['default'].PLAYBACK_TIME_UPDATED, onPlaybackTimeUpdated, this);
+ eventBus.on(_coreEventsEvents2['default'].PLAYBACK_ENDED, onEnded, this);
+ eventBus.on(_coreEventsEvents2['default'].PLAYBACK_ERROR, onPlaybackError, this);
+ eventBus.on(_coreEventsEvents2['default'].PLAYBACK_STARTED, onPlaybackStarted, this);
+ eventBus.on(_coreEventsEvents2['default'].PLAYBACK_PAUSED, onPlaybackPaused, this);
+ eventBus.on(_coreEventsEvents2['default'].MANIFEST_UPDATED, onManifestUpdated, this);
+ eventBus.on(_coreEventsEvents2['default'].STREAM_BUFFERING_COMPLETED, onStreamBufferingCompleted, this);
+ }
+
+ function flushPlaylistMetrics(reason, time) {
+ time = time || new Date();
+
+ if (playListMetrics) {
+ if (activeStream) {
+ activeStream.getProcessors().forEach(function (p) {
+ var ctrlr = p.getScheduleController();
+ if (ctrlr) {
+ ctrlr.finalisePlayList(time, reason);
+ }
+ });
+ }
+
+ metricsModel.addPlayList(playListMetrics);
+
+ playListMetrics = null;
+ }
+ }
+
+ function addPlaylistMetrics(startReason) {
+ playListMetrics = new _voMetricsPlayList.PlayList();
+ playListMetrics.start = new Date();
+ playListMetrics.mstart = playbackController.getTime() * 1000;
+ playListMetrics.starttype = startReason;
+
+ if (activeStream) {
+ activeStream.getProcessors().forEach(function (p) {
+ var ctrlr = p.getScheduleController();
+ if (ctrlr) {
+ ctrlr.setPlayList(playListMetrics);
+ }
+ });
+ }
+ }
+ /*
+ * StreamController aggregates all streams defined in the manifest file
+ * and implements corresponding logic to switch between them.
+ */
+ function fireSwitchEvent(eventType, fromStream, toStream) {
+ eventBus.trigger(eventType, { fromStreamInfo: fromStream ? fromStream.getStreamInfo() : null, toStreamInfo: toStream.getStreamInfo() });
+ }
+
+ function startAutoPlay() {
+ if (!activeStream.isActivated() || !initialPlayback) return;
+ // only first stream must be played automatically during playback initialization
+ if (activeStream.getStreamInfo().index === 0) {
+ activeStream.startEventController();
+ if (autoPlay) {
+ playbackController.play();
+ }
+ }
+ }
+
+ function onPlaybackError(e) {
+
+ if (!e.error) return;
+
+ var msg = '';
+
+ switch (e.error.code) {
+ case 1:
+ msg = 'MEDIA_ERR_ABORTED';
+ break;
+ case 2:
+ msg = 'MEDIA_ERR_NETWORK';
+ break;
+ case 3:
+ msg = 'MEDIA_ERR_DECODE';
+ break;
+ case 4:
+ msg = 'MEDIA_ERR_SRC_NOT_SUPPORTED';
+ break;
+ case 5:
+ msg = 'MEDIA_ERR_ENCRYPTED';
+ break;
+ default:
+ msg = 'UNKNOWN';
+ break;
+ }
+
+ hasMediaError = true;
+
+ if (e.error.msExtendedCode) {
+ msg += ' (0x' + (e.error.msExtendedCode >>> 0).toString(16).toUpperCase() + ')';
+ }
+
+ log('Video Element Error: ' + msg);
+ if (e.error) {
+ log(e.error);
+ }
+ errHandler.mediaSourceError(msg);
+ reset();
+ }
+
+ /*
+ * Called when current playback position is changed.
+ * Used to determine the time current stream is finished and we should switch to the next stream.
+ */
+ function onPlaybackTimeUpdated(e) {
+
+ if (isVideoTrackPresent()) {
+ var playbackQuality = videoModel.getPlaybackQuality();
+ if (playbackQuality) {
+ metricsModel.addDroppedFrames('video', playbackQuality);
+ }
+ }
+ // Sometimes after seeking timeUpdateHandler is called before seekingHandler and a new stream starts
+ // from beginning instead of from a chosen position. So we do nothing if the player is in the seeking state
+ if (playbackController.isSeeking()) return;
+ if (e.timeToEnd < STREAM_END_THRESHOLD) {
+ //This is only used for multiperiod content.
+ // The main call to signalEndOfStream is driven by BUFFERING_COMPLETED event
+ mediaSourceController.signalEndOfStream(mediaSource);
+ }
+ }
+
+ function onEnded() {
+ var nextStream = getNextStream();
+ if (nextStream) {
+ switchStream(activeStream, nextStream, NaN);
+ }
+ flushPlaylistMetrics(nextStream ? _voMetricsPlayList.PlayListTrace.END_OF_PERIOD_STOP_REASON : _voMetricsPlayList.PlayListTrace.END_OF_CONTENT_STOP_REASON);
+ }
+
+ function onPlaybackSeeking(e) {
+ var seekingStream = getStreamForTime(e.seekTime);
+
+ if (seekingStream && seekingStream !== activeStream) {
+ flushPlaylistMetrics(_voMetricsPlayList.PlayListTrace.END_OF_PERIOD_STOP_REASON);
+ switchStream(activeStream, seekingStream, e.seekTime);
+ } else {
+ flushPlaylistMetrics(_voMetricsPlayList.PlayListTrace.USER_REQUEST_STOP_REASON);
+ }
+
+ addPlaylistMetrics(_voMetricsPlayList.PlayList.SEEK_START_REASON);
+ }
+
+ function onPlaybackStarted() /*e*/{
+ if (initialPlayback) {
+ initialPlayback = false;
+ addPlaylistMetrics(_voMetricsPlayList.PlayList.INITIAL_PLAYOUT_START_REASON);
+ } else {
+ if (isPaused) {
+ isPaused = false;
+ addPlaylistMetrics(_voMetricsPlayList.PlayList.RESUME_FROM_PAUSE_START_REASON);
+ }
+ }
+ }
+
+ function onPlaybackPaused(e) {
+ if (!e.ended) {
+ isPaused = true;
+ flushPlaylistMetrics(_voMetricsPlayList.PlayListTrace.USER_REQUEST_STOP_REASON);
+ }
+ }
+
+ /*
+ * Handles the current stream buffering end moment to start the next stream buffering
+ * Removing MP logic from this for now, we removing the complexity of buffering into next period for now.
+ * this handler's logic caused Firefox and Safari to not period switch since the end event did not fire due to this.
+ */
+ function onStreamBufferingCompleted(e) {
+ if (mediaSource && e.streamInfo.isLast) {
+ mediaSourceController.signalEndOfStream(mediaSource);
+ }
+ }
+
+ function getNextStream() {
+ var start = activeStream.getStreamInfo().start;
+ var duration = activeStream.getStreamInfo().duration;
+
+ return streams.filter(function (stream) {
+ return stream.getStreamInfo().start === start + duration;
+ })[0];
+ }
+
+ function getStreamForTime(time) {
+ var duration = 0;
+ var stream = null;
+
+ var ln = streams.length;
+
+ if (ln > 0) {
+ duration += streams[0].getStartTime();
+ }
+
+ for (var i = 0; i < ln; i++) {
+ stream = streams[i];
+ duration += stream.getDuration();
+
+ if (time < duration) {
+ return stream;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns a playhead time, in seconds, converted to be relative
+ * to the start of an identified stream/period or null if no such stream
+ * @param {number} time
+ * @param {string} id
+ * @returns {number|null}
+ */
+ function getTimeRelativeToStreamId(time, id) {
+ var stream = null;
+ var baseStart = 0;
+ var streamStart = 0;
+ var streamDur = null;
+
+ var ln = streams.length;
+
+ for (var i = 0; i < ln; i++) {
+ stream = streams[i];
+ streamStart = stream.getStartTime();
+ streamDur = stream.getDuration();
+
+ // use start time, if not undefined or NaN or similar
+ if (Number.isFinite(streamStart)) {
+ baseStart = streamStart;
+ }
+
+ if (stream.getId() === id) {
+ return time - baseStart;
+ } else {
+ // use duration if not undefined or NaN or similar
+ if (Number.isFinite(streamDur)) {
+ baseStart += streamDur;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ function getActiveStreamCommonEarliestTime() {
+ var commonEarliestTime = [];
+ activeStream.getProcessors().forEach(function (p) {
+ commonEarliestTime.push(p.getIndexHandler().getEarliestTime());
+ });
+ return Math.min.apply(Math, commonEarliestTime);
+ }
+
+ function switchStream(from, to, seekTime) {
+
+ if (isStreamSwitchingInProgress || !from || !to || from === to) return;
+
+ isStreamSwitchingInProgress = true;
+ fireSwitchEvent(_coreEventsEvents2['default'].PERIOD_SWITCH_STARTED, from, to);
+
+ function onMediaSourceReady() {
+ if (!isNaN(seekTime)) {
+ playbackController.seek(seekTime); //we only need to call seek here, IndexHandlerTime was set from seeking event
+ } else {
+ (function () {
+ var startTime = playbackController.getStreamStartTime(true);
+ activeStream.getProcessors().forEach(function (p) {
+ adapter.setIndexHandlerTime(p, startTime);
+ });
+ playbackController.seek(startTime); //seek to period start time
+ })();
+ }
+ playbackController.play();
+ activeStream.startEventController();
+ isStreamSwitchingInProgress = false;
+ fireSwitchEvent(_coreEventsEvents2['default'].PERIOD_SWITCH_COMPLETED, from, to);
+ }
+
+ from.deactivate();
+ activeStream = to;
+ playbackController.initialize(activeStream.getStreamInfo());
+ videoTrackDetected = checkVideoPresence();
+ setupMediaSource(onMediaSourceReady);
+ }
+
+ function setupMediaSource(callback) {
+
+ var sourceUrl = undefined;
+
+ function onMediaSourceOpen() {
+ log('MediaSource is open!');
+
+ window.URL.revokeObjectURL(sourceUrl);
+ mediaSource.removeEventListener('sourceopen', onMediaSourceOpen);
+ mediaSource.removeEventListener('webkitsourceopen', onMediaSourceOpen);
+ setMediaDuration();
+ activeStream.activate(mediaSource);
+
+ if (callback) {
+ callback();
+ }
+ }
+
+ if (!mediaSource) {
+ mediaSource = mediaSourceController.createMediaSource();
+ } else {
+ mediaSourceController.detachMediaSource(videoModel);
+ }
+
+ mediaSource.addEventListener('sourceopen', onMediaSourceOpen, false);
+ mediaSource.addEventListener('webkitsourceopen', onMediaSourceOpen, false);
+ sourceUrl = mediaSourceController.attachMediaSource(mediaSource, videoModel);
+ log('MediaSource attached to element. Waiting on open...');
+ }
+
+ function setMediaDuration() {
+ var manifestDuration, mediaDuration;
+
+ manifestDuration = activeStream.getStreamInfo().manifestInfo.duration;
+ mediaDuration = mediaSourceController.setDuration(mediaSource, manifestDuration);
+ log('Duration successfully set to: ' + mediaDuration);
+ }
+
+ function composeStreams() {
+ var manifest = manifestModel.getValue();
+ var metrics = metricsModel.getMetricsFor('stream');
+ var manifestUpdateInfo = dashMetrics.getCurrentManifestUpdate(metrics);
+ var remainingStreams = [];
+ var streamInfo, pLen, sLen, pIdx, sIdx, streamsInfo, stream;
+
+ if (!manifest) return;
+
+ streamsInfo = adapter.getStreamsInfo(manifest);
+ if (protectionController) {
+ eventBus.trigger(_coreEventsEvents2['default'].PROTECTION_CREATED, { controller: protectionController, manifest: manifest });
+ protectionController.setMediaElement(videoModel.getElement());
+ if (protectionData) {
+ protectionController.setProtectionData(protectionData);
+ }
+ }
+
+ try {
+ if (streamsInfo.length === 0) {
+ throw new Error('There are no streams');
+ }
+
+ metricsModel.updateManifestUpdateInfo(manifestUpdateInfo, {
+ currentTime: playbackController.getTime(),
+ buffered: videoModel.getElement().buffered,
+ presentationStartTime: streamsInfo[0].start,
+ clientTimeOffset: timelineConverter.getClientTimeOffset()
+ });
+
+ isUpdating = true;
+
+ for (pIdx = 0, pLen = streamsInfo.length; pIdx < pLen; pIdx++) {
+ streamInfo = streamsInfo[pIdx];
+ for (sIdx = 0, sLen = streams.length; sIdx < sLen; sIdx++) {
+ // If the stream already exists we just need to update the values we got from the updated manifest
+ if (streams[sIdx].getId() === streamInfo.id) {
+ stream = streams[sIdx];
+ remainingStreams.push(stream);
+ stream.updateData(streamInfo);
+ }
+ }
+ // If the Stream object does not exist we probably loaded the manifest the first time or it was
+ // introduced in the updated manifest, so we need to create a new Stream and perform all the initialization operations
+ if (!stream) {
+
+ stream = (0, _Stream2['default'])(context).create({
+ manifestModel: manifestModel,
+ manifestUpdater: manifestUpdater,
+ adapter: adapter,
+ timelineConverter: timelineConverter,
+ capabilities: capabilities,
+ errHandler: errHandler,
+ baseURLController: baseURLController
+ });
+ stream.initialize(streamInfo, protectionController);
+
+ eventBus.on(_coreEventsEvents2['default'].STREAM_INITIALIZED, onStreamInitialized, this);
+ remainingStreams.push(stream);
+
+ if (activeStream) {
+ stream.updateData(streamInfo);
+ }
+ }
+ metricsModel.addManifestUpdateStreamInfo(manifestUpdateInfo, streamInfo.id, streamInfo.index, streamInfo.start, streamInfo.duration);
+ stream = null;
+ }
+
+ streams = remainingStreams;
+
+ // If the active stream has not been set up yet, let it be the first Stream in the list
+ if (!activeStream) {
+ activeStream = streams[0];
+ fireSwitchEvent(_coreEventsEvents2['default'].PERIOD_SWITCH_STARTED, null, activeStream);
+ playbackController.initialize(activeStream.getStreamInfo());
+ fireSwitchEvent(_coreEventsEvents2['default'].PERIOD_SWITCH_COMPLETED, null, activeStream);
+ }
+
+ if (!mediaSource) {
+ setupMediaSource();
+ }
+
+ isUpdating = false;
+ checkIfUpdateCompleted();
+ } catch (e) {
+ errHandler.manifestError(e.message, 'nostreamscomposed', manifest);
+ hasInitialisationError = true;
+ reset();
+ }
+ }
+
+ function checkIfUpdateCompleted() {
+ if (isUpdating) return;
+
+ var ln = streams.length;
+ var i = 0;
+
+ startAutoPlay();
+
+ for (i; i < ln; i++) {
+ if (!streams[i].isInitialized()) return;
+ }
+
+ eventBus.trigger(_coreEventsEvents2['default'].STREAMS_COMPOSED);
+ }
+
+ function onStreamInitialized() /*e*/{
+ checkIfUpdateCompleted();
+ }
+
+ function onTimeSyncCompleted() /*e*/{
+ composeStreams();
+ }
+
+ function onManifestUpdated(e) {
+ if (!e.error) {
+ //Since streams are not composed yet , need to manually look up useCalculatedLiveEdgeTime to detect if stream
+ //is SegmentTimeline to avoid using time source
+ var manifest = e.manifest;
+ var streamInfo = adapter.getStreamsInfo(manifest)[0];
+ var mediaInfo = adapter.getMediaInfoForType(manifest, streamInfo, 'video') || adapter.getMediaInfoForType(manifest, streamInfo, 'audio');
+
+ var adaptation, useCalculatedLiveEdgeTime;
+
+ if (mediaInfo) {
+ adaptation = adapter.getDataForMedia(mediaInfo);
+ useCalculatedLiveEdgeTime = dashManifestModel.getRepresentationsForAdaptation(manifest, adaptation)[0].useCalculatedLiveEdgeTime;
+
+ if (useCalculatedLiveEdgeTime) {
+ log('SegmentTimeline detected using calculated Live Edge Time');
+ mediaPlayerModel.setUseManifestDateHeaderTimeSource(false);
+ }
+ }
+
+ var manifestUTCTimingSources = dashManifestModel.getUTCTimingSources(e.manifest);
+ var allUTCTimingSources = !dashManifestModel.getIsDynamic(manifest) || useCalculatedLiveEdgeTime ? manifestUTCTimingSources : manifestUTCTimingSources.concat(mediaPlayerModel.getUTCTimingSources());
+ var isHTTPS = (0, _modelsURIQueryAndFragmentModel2['default'])(context).getInstance().isManifestHTTPS();
+
+ //If https is detected on manifest then lets apply that protocol to only the default time source(s). In the future we may find the need to apply this to more then just default so left code at this level instead of in MediaPlayer.
+ allUTCTimingSources.forEach(function (item) {
+ if (item.value.replace(/.*?:\/\//g, '') === _modelsMediaPlayerModel2['default'].DEFAULT_UTC_TIMING_SOURCE.value.replace(/.*?:\/\//g, '')) {
+ item.value = item.value.replace(isHTTPS ? new RegExp(/^(http:)?\/\//i) : new RegExp(/^(https:)?\/\//i), isHTTPS ? 'https://' : 'http://');
+ log('Matching default timing source protocol to manifest protocol: ', item.value);
+ }
+ });
+
+ baseURLController.initialize(manifest);
+
+ timeSyncController.setConfig({
+ metricsModel: metricsModel,
+ dashMetrics: dashMetrics
+ });
+ timeSyncController.initialize(allUTCTimingSources, mediaPlayerModel.getUseManifestDateHeaderTimeSource());
+ } else {
+ hasInitialisationError = true;
+ reset();
+ }
+ }
+
+ function isVideoTrackPresent() {
+ if (videoTrackDetected === undefined) {
+ videoTrackDetected = checkVideoPresence();
+ }
+ return videoTrackDetected;
+ }
+
+ function checkVideoPresence() {
+ var isVideoDetected = false;
+ activeStream.getProcessors().forEach(function (p) {
+ if (p.getMediaInfo().type === 'video') {
+ isVideoDetected = true;
+ }
+ });
+ return isVideoDetected;
+ }
+
+ function getAutoPlay() {
+ return autoPlay;
+ }
+
+ function getActiveStreamInfo() {
+ return activeStream ? activeStream.getStreamInfo() : null;
+ }
+
+ function isStreamActive(streamInfo) {
+ return activeStream.getId() === streamInfo.id;
+ }
+
+ function getStreamById(id) {
+ return streams.filter(function (item) {
+ return item.getId() === id;
+ })[0];
+ }
+
+ function load(url) {
+ manifestLoader.load(url);
+ }
+
+ function loadWithManifest(manifest) {
+ manifestUpdater.setManifest(manifest);
+ }
+
+ function setConfig(config) {
+ if (!config) return;
+
+ if (config.capabilities) {
+ capabilities = config.capabilities;
+ }
+ if (config.manifestLoader) {
+ manifestLoader = config.manifestLoader;
+ }
+ if (config.manifestModel) {
+ manifestModel = config.manifestModel;
+ }
+ if (config.dashManifestModel) {
+ dashManifestModel = config.dashManifestModel;
+ }
+ if (config.protectionController) {
+ protectionController = config.protectionController;
+ }
+ if (config.adapter) {
+ adapter = config.adapter;
+ }
+ if (config.metricsModel) {
+ metricsModel = config.metricsModel;
+ }
+ if (config.dashMetrics) {
+ dashMetrics = config.dashMetrics;
+ }
+ if (config.liveEdgeFinder) {
+ liveEdgeFinder = config.liveEdgeFinder;
+ }
+ if (config.mediaSourceController) {
+ mediaSourceController = config.mediaSourceController;
+ }
+ if (config.timeSyncController) {
+ timeSyncController = config.timeSyncController;
+ }
+ if (config.baseURLController) {
+ baseURLController = config.baseURLController;
+ }
+ if (config.errHandler) {
+ errHandler = config.errHandler;
+ }
+ if (config.timelineConverter) {
+ timelineConverter = config.timelineConverter;
+ }
+ }
+
+ function reset() {
+ timeSyncController.reset();
+
+ flushPlaylistMetrics(hasMediaError || hasInitialisationError ? _voMetricsPlayList.PlayListTrace.FAILURE_STOP_REASON : _voMetricsPlayList.PlayListTrace.USER_REQUEST_STOP_REASON);
+
+ for (var i = 0, ln = streams.length; i < ln; i++) {
+ var stream = streams[i];
+ eventBus.off(_coreEventsEvents2['default'].STREAM_INITIALIZED, onStreamInitialized, this);
+ stream.reset(hasMediaError);
+ }
+
+ streams = [];
+
+ eventBus.off(_coreEventsEvents2['default'].PLAYBACK_TIME_UPDATED, onPlaybackTimeUpdated, this);
+ eventBus.off(_coreEventsEvents2['default'].PLAYBACK_SEEKING, onPlaybackSeeking, this);
+ eventBus.off(_coreEventsEvents2['default'].PLAYBACK_ERROR, onPlaybackError, this);
+ eventBus.off(_coreEventsEvents2['default'].PLAYBACK_STARTED, onPlaybackStarted, this);
+ eventBus.off(_coreEventsEvents2['default'].PLAYBACK_PAUSED, onPlaybackPaused, this);
+ eventBus.off(_coreEventsEvents2['default'].PLAYBACK_ENDED, onEnded, this);
+ eventBus.off(_coreEventsEvents2['default'].MANIFEST_UPDATED, onManifestUpdated, this);
+ eventBus.off(_coreEventsEvents2['default'].STREAM_BUFFERING_COMPLETED, onStreamBufferingCompleted, this);
+
+ baseURLController.reset();
+ manifestUpdater.reset();
+ metricsModel.clearAllCurrentMetrics();
+ manifestModel.setValue(null);
+ manifestLoader.reset();
+ timelineConverter.reset();
+ liveEdgeFinder.reset();
+ adapter.reset();
+ initCache.reset();
+ isStreamSwitchingInProgress = false;
+ isUpdating = false;
+ activeStream = null;
+ hasMediaError = false;
+ hasInitialisationError = false;
+ videoTrackDetected = undefined;
+ initialPlayback = true;
+ isPaused = false;
+
+ if (mediaSource) {
+ mediaSourceController.detachMediaSource(videoModel);
+ mediaSource = null;
+ }
+ videoModel = null;
+ if (protectionController) {
+ protectionController.setMediaElement(null);
+ protectionController = null;
+ protectionData = null;
+ if (manifestModel.getValue()) {
+ eventBus.trigger(_coreEventsEvents2['default'].PROTECTION_DESTROYED, { data: manifestModel.getValue().url });
+ }
+ }
+
+ eventBus.trigger(_coreEventsEvents2['default'].STREAM_TEARDOWN_COMPLETE);
+ }
+
+ instance = {
+ initialize: initialize,
+ getAutoPlay: getAutoPlay,
+ getActiveStreamInfo: getActiveStreamInfo,
+ isStreamActive: isStreamActive,
+ isVideoTrackPresent: isVideoTrackPresent,
+ getStreamById: getStreamById,
+ getTimeRelativeToStreamId: getTimeRelativeToStreamId,
+ load: load,
+ loadWithManifest: loadWithManifest,
+ getActiveStreamCommonEarliestTime: getActiveStreamCommonEarliestTime,
+ setConfig: setConfig,
+ reset: reset
+ };
+
+ setup();
+
+ return instance;
+}
+
+StreamController.__dashjs_factory_name = 'StreamController';
+
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(StreamController);
+module.exports = exports['default'];
+
+},{"10":10,"101":101,"103":103,"104":104,"13":13,"152":152,"181":181,"50":50,"54":54,"68":68,"8":8,"9":9}],72:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreEventBus = _dereq_(9);
+
+var _coreEventBus2 = _interopRequireDefault(_coreEventBus);
+
+var _coreEventsEvents = _dereq_(13);
+
+var _coreEventsEvents2 = _interopRequireDefault(_coreEventsEvents);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+function TextController(config) {
+
+ var context = this.context;
+ var eventBus = (0, _coreEventBus2['default'])(context).getInstance();
+
+ var sourceBufferController = config.sourceBufferController;
+ var errHandler = config.errHandler;
+
+ var instance = undefined,
+ initialized = undefined,
+ mediaSource = undefined,
+ buffer = undefined,
+ type = undefined,
+ streamProcessor = undefined,
+ representationController = undefined;
+
+ function setup() {
+
+ initialized = false;
+ mediaSource = null;
+ buffer = null;
+ type = null;
+ streamProcessor = null;
+ representationController = null;
+
+ eventBus.on(_coreEventsEvents2['default'].DATA_UPDATE_COMPLETED, onDataUpdateCompleted, this);
+ eventBus.on(_coreEventsEvents2['default'].INIT_FRAGMENT_LOADED, onInitFragmentLoaded, this);
+ }
+
+ function initialize(Type, source, StreamProcessor) {
+ type = Type;
+ setMediaSource(source);
+ streamProcessor = StreamProcessor;
+ representationController = streamProcessor.getRepresentationController();
+ }
+
+ /**
+ * @param {MediaInfo }mediaInfo
+ * @returns {Object} SourceBuffer object
+ * @memberof BufferController#
+ */
+ function createBuffer(mediaInfo) {
+ try {
+ buffer = sourceBufferController.createSourceBuffer(mediaSource, mediaInfo);
+
+ if (!initialized) {
+ if (buffer.hasOwnProperty('initialize')) {
+ buffer.initialize(type, this);
+ }
+ initialized = true;
+ }
+ } catch (e) {
+ errHandler.mediaSourceError('Error creating ' + type + ' source buffer.');
+ }
+
+ return buffer;
+ }
+
+ function getBuffer() {
+ return buffer;
+ }
+
+ function setBuffer(value) {
+ buffer = value;
+ }
+
+ function setMediaSource(value) {
+ mediaSource = value;
+ }
+
+ function getStreamProcessor() {
+ return streamProcessor;
+ }
+
+ function reset(errored) {
+
+ eventBus.off(_coreEventsEvents2['default'].DATA_UPDATE_COMPLETED, onDataUpdateCompleted, this);
+ eventBus.off(_coreEventsEvents2['default'].INIT_FRAGMENT_LOADED, onInitFragmentLoaded, this);
+
+ if (!errored) {
+ sourceBufferController.abort(mediaSource, buffer);
+ sourceBufferController.removeSourceBuffer(mediaSource, buffer);
+ }
+ }
+
+ function onDataUpdateCompleted(e) {
+ if (e.sender.getStreamProcessor() !== streamProcessor) return;
+ eventBus.trigger(_coreEventsEvents2['default'].TIMED_TEXT_REQUESTED, { index: 0, sender: e.sender }); //TODO make index dynamic if referring to MP?
+ }
+
+ function onInitFragmentLoaded(e) {
+ if (e.fragmentModel !== streamProcessor.getFragmentModel() || !e.chunk.bytes) return;
+ sourceBufferController.append(buffer, e.chunk);
+ }
+
+ instance = {
+ initialize: initialize,
+ createBuffer: createBuffer,
+ getBuffer: getBuffer,
+ setBuffer: setBuffer,
+ getStreamProcessor: getStreamProcessor,
+ setMediaSource: setMediaSource,
+ reset: reset
+ };
+
+ setup();
+
+ return instance;
+}
+
+TextController.__dashjs_factory_name = 'TextController';
+exports['default'] = _coreFactoryMaker2['default'].getClassFactory(TextController);
+module.exports = exports['default'];
+
+},{"10":10,"13":13,"9":9}],73:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _voError = _dereq_(162);
+
+var _voError2 = _interopRequireDefault(_voError);
+
+var _coreEventBus = _dereq_(9);
+
+var _coreEventBus2 = _interopRequireDefault(_coreEventBus);
+
+var _coreEventsEvents = _dereq_(13);
+
+var _coreEventsEvents2 = _interopRequireDefault(_coreEventsEvents);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _coreDebug = _dereq_(8);
+
+var _coreDebug2 = _interopRequireDefault(_coreDebug);
+
+var TIME_SYNC_FAILED_ERROR_CODE = 1;
+var HTTP_TIMEOUT_MS = 5000;
+
+function TimeSyncController() {
+
+ var context = this.context;
+ var log = (0, _coreDebug2['default'])(context).getInstance().log;
+ var eventBus = (0, _coreEventBus2['default'])(context).getInstance();
+
+ var instance = undefined,
+ offsetToDeviceTimeMs = undefined,
+ isSynchronizing = undefined,
+ isInitialised = undefined,
+ useManifestDateHeaderTimeSource = undefined,
+ handlers = undefined,
+ metricsModel = undefined,
+ dashMetrics = undefined;
+
+ function initialize(timingSources, useManifestDateHeader) {
+ useManifestDateHeaderTimeSource = useManifestDateHeader;
+ offsetToDeviceTimeMs = 0;
+ isSynchronizing = false;
+ isInitialised = false;
+
+ // a list of known schemeIdUris and a method to call with @value
+ handlers = {
+ 'urn:mpeg:dash:utc:http-head:2014': httpHeadHandler,
+ 'urn:mpeg:dash:utc:http-xsdate:2014': httpHandler.bind(null, xsdatetimeDecoder),
+ 'urn:mpeg:dash:utc:http-iso:2014': httpHandler.bind(null, iso8601Decoder),
+ 'urn:mpeg:dash:utc:direct:2014': directHandler,
+
+ // some specs referencing early ISO23009-1 drafts incorrectly use
+ // 2012 in the URI, rather than 2014. support these for now.
+ 'urn:mpeg:dash:utc:http-head:2012': httpHeadHandler,
+ 'urn:mpeg:dash:utc:http-xsdate:2012': httpHandler.bind(null, xsdatetimeDecoder),
+ 'urn:mpeg:dash:utc:http-iso:2012': httpHandler.bind(null, iso8601Decoder),
+ 'urn:mpeg:dash:utc:direct:2012': directHandler,
+
+ // it isn't clear how the data returned would be formatted, and
+ // no public examples available so http-ntp not supported for now.
+ // presumably you would do an arraybuffer type xhr and decode the
+ // binary data returned but I would want to see a sample first.
+ 'urn:mpeg:dash:utc:http-ntp:2014': notSupportedHandler,
+
+ // not clear how this would be supported in javascript (in browser)
+ 'urn:mpeg:dash:utc:ntp:2014': notSupportedHandler,
+ 'urn:mpeg:dash:utc:sntp:2014': notSupportedHandler
+ };
+
+ if (!getIsSynchronizing()) {
+ attemptSync(timingSources);
+ setIsInitialised(true);
+ }
+ }
+
+ function setConfig(config) {
+ if (!config) return;
+
+ if (config.metricsModel) {
+ metricsModel = config.metricsModel;
+ }
+
+ if (config.dashMetrics) {
+ dashMetrics = config.dashMetrics;
+ }
+ }
+
+ function getOffsetToDeviceTimeMs() {
+ return getOffsetMs();
+ }
+
+ function setIsSynchronizing(value) {
+ isSynchronizing = value;
+ }
+
+ function getIsSynchronizing() {
+ return isSynchronizing;
+ }
+
+ function setIsInitialised(value) {
+ isInitialised = value;
+ }
+
+ function setOffsetMs(value) {
+ offsetToDeviceTimeMs = value;
+ }
+
+ function getOffsetMs() {
+ return offsetToDeviceTimeMs;
+ }
+
+ // takes xsdatetime and returns milliseconds since UNIX epoch
+ // may not be necessary as xsdatetime is very similar to ISO 8601
+ // which is natively understood by javascript Date parser
+ function alternateXsdatetimeDecoder(xsdatetimeStr) {
+ // taken from DashParser - should probably refactor both uses
+ var SECONDS_IN_MIN = 60;
+ var MINUTES_IN_HOUR = 60;
+ var MILLISECONDS_IN_SECONDS = 1000;
+ var datetimeRegex = /^([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2})(?::([0-9]*)(\.[0-9]*)?)?(?:([+\-])([0-9]{2})([0-9]{2}))?/;
+
+ var utcDate, timezoneOffset;
+
+ var match = datetimeRegex.exec(xsdatetimeStr);
+
+ // If the string does not contain a timezone offset different browsers can interpret it either
+ // as UTC or as a local time so we have to parse the string manually to normalize the given date value for
+ // all browsers
+ utcDate = Date.UTC(parseInt(match[1], 10), parseInt(match[2], 10) - 1, // months start from zero
+ parseInt(match[3], 10), parseInt(match[4], 10), parseInt(match[5], 10), match[6] && (parseInt(match[6], 10) || 0), match[7] && parseFloat(match[7]) * MILLISECONDS_IN_SECONDS || 0);
+ // If the date has timezone offset take it into account as well
+ if (match[9] && match[10]) {
+ timezoneOffset = parseInt(match[9], 10) * MINUTES_IN_HOUR + parseInt(match[10], 10);
+ utcDate += (match[8] === '+' ? -1 : +1) * timezoneOffset * SECONDS_IN_MIN * MILLISECONDS_IN_SECONDS;
+ }
+
+ return new Date(utcDate).getTime();
+ }
+
+ // try to use the built in parser, since xsdate is a constrained ISO8601
+ // which is supported natively by Date.parse. if that fails, try a
+ // regex-based version used elsewhere in this application.
+ function xsdatetimeDecoder(xsdatetimeStr) {
+ var parsedDate = Date.parse(xsdatetimeStr);
+
+ if (isNaN(parsedDate)) {
+ parsedDate = alternateXsdatetimeDecoder(xsdatetimeStr);
+ }
+
+ return parsedDate;
+ }
+
+ // takes ISO 8601 timestamp and returns milliseconds since UNIX epoch
+ function iso8601Decoder(isoStr) {
+ return Date.parse(isoStr);
+ }
+
+ // takes RFC 1123 timestamp (which is same as ISO8601) and returns
+ // milliseconds since UNIX epoch
+ function rfc1123Decoder(dateStr) {
+ return Date.parse(dateStr);
+ }
+
+ function notSupportedHandler(url, onSuccessCB, onFailureCB) {
+ onFailureCB();
+ }
+
+ function directHandler(xsdatetimeStr, onSuccessCB, onFailureCB) {
+ var time = xsdatetimeDecoder(xsdatetimeStr);
+
+ if (!isNaN(time)) {
+ onSuccessCB(time);
+ return;
+ }
+
+ onFailureCB();
+ }
+
+ function httpHandler(decoder, url, onSuccessCB, onFailureCB, isHeadRequest) {
+ var oncomplete, onload;
+ var complete = false;
+ var req = new XMLHttpRequest();
+
+ var verb = isHeadRequest ? 'HEAD' : 'GET';
+ var urls = url.match(/\S+/g);
+
+ // according to ISO 23009-1, url could be a white-space
+ // separated list of URLs. just handle one at a time.
+ url = urls.shift();
+
+ oncomplete = function () {
+ if (complete) {
+ return;
+ }
+
+ // we only want to pass through here once per xhr,
+ // regardless of whether the load was successful.
+ complete = true;
+
+ // if there are more urls to try, call self.
+ if (urls.length) {
+ httpHandler(decoder, urls.join(' '), onSuccessCB, onFailureCB, isHeadRequest);
+ } else {
+ onFailureCB();
+ }
+ };
+
+ onload = function () {
+ var time, result;
+
+ if (req.status === 200) {
+ time = isHeadRequest ? req.getResponseHeader('Date') : req.response;
+
+ result = decoder(time);
+
+ // decoder returns NaN if non-standard input
+ if (!isNaN(result)) {
+ onSuccessCB(result);
+ complete = true;
+ }
+ }
+ };
+
+ req.open(verb, url);
+ req.timeout = HTTP_TIMEOUT_MS || 0;
+ req.onload = onload;
+ req.onloadend = oncomplete;
+ req.send();
+ }
+
+ function httpHeadHandler(url, onSuccessCB, onFailureCB) {
+ httpHandler(rfc1123Decoder, url, onSuccessCB, onFailureCB, true);
+ }
+
+ function checkForDateHeader() {
+ var metrics = metricsModel.getReadOnlyMetricsFor('stream');
+ var dateHeaderValue = dashMetrics.getLatestMPDRequestHeaderValueByID(metrics, 'Date');
+ var dateHeaderTime = dateHeaderValue !== null ? new Date(dateHeaderValue).getTime() : Number.NaN;
+
+ if (!isNaN(dateHeaderTime)) {
+ setOffsetMs(dateHeaderTime - new Date().getTime());
+ completeTimeSyncSequence(false, dateHeaderTime / 1000, offsetToDeviceTimeMs);
+ } else {
+ completeTimeSyncSequence(true);
+ }
+ }
+
+ function completeTimeSyncSequence(failed, time, offset) {
+ setIsSynchronizing(false);
+ eventBus.trigger(_coreEventsEvents2['default'].TIME_SYNCHRONIZATION_COMPLETED, { time: time, offset: offset, error: failed ? new _voError2['default'](TIME_SYNC_FAILED_ERROR_CODE) : null });
+ }
+
+ function attemptSync(sources, sourceIndex) {
+
+ // if called with no sourceIndex, use zero (highest priority)
+ var index = sourceIndex || 0;
+
+ // the sources should be ordered in priority from the manifest.
+ // try each in turn, from the top, until either something
+ // sensible happens, or we run out of sources to try.
+ var source = sources[index];
+
+ // callback to emit event to listeners
+ var onComplete = function onComplete(time, offset) {
+ var failed = !time || !offset;
+ if (failed && useManifestDateHeaderTimeSource) {
+ //Before falling back to binary search , check if date header exists on MPD. if so, use for a time source.
+ checkForDateHeader();
+ } else {
+ completeTimeSyncSequence(failed, time, offset);
+ }
+ };
+
+ setIsSynchronizing(true);
+
+ if (source) {
+ // check if there is a handler for this @schemeIdUri
+ if (handlers.hasOwnProperty(source.schemeIdUri)) {
+ // if so, call it with its @value
+ handlers[source.schemeIdUri](source.value, function (serverTime) {
+ // the timing source returned something useful
+ var deviceTime = new Date().getTime();
+ var offset = serverTime - deviceTime;
+
+ setOffsetMs(offset);
+
+ log('Local time: ' + new Date(deviceTime));
+ log('Server time: ' + new Date(serverTime));
+ log('Difference (ms): ' + offset);
+
+ onComplete(serverTime, offset);
+ }, function () {
+ // the timing source was probably uncontactable
+ // or returned something we can't use - try again
+ // with the remaining sources
+ attemptSync(sources, index + 1);
+ });
+ } else {
+ // an unknown schemeIdUri must have been found
+ // try again with the remaining sources
+ attemptSync(sources, index + 1);
+ }
+ } else {
+ // no valid time source could be found, just use device time
+ setOffsetMs(0);
+ onComplete();
+ }
+ }
+
+ function reset() {
+ setIsInitialised(false);
+ setIsSynchronizing(false);
+ }
+
+ instance = {
+ initialize: initialize,
+ getOffsetToDeviceTimeMs: getOffsetToDeviceTimeMs,
+ setConfig: setConfig,
+ reset: reset
+ };
+
+ return instance;
+}
+
+TimeSyncController.__dashjs_factory_name = 'TimeSyncController';
+var factory = _coreFactoryMaker2['default'].getSingletonFactory(TimeSyncController);
+factory.TIME_SYNC_FAILED_ERROR_CODE = TIME_SYNC_FAILED_ERROR_CODE;
+factory.HTTP_TIMEOUT_MS = HTTP_TIMEOUT_MS;
+exports['default'] = factory;
+module.exports = exports['default'];
+
+},{"10":10,"13":13,"162":162,"8":8,"9":9}],74:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _XlinkLoader = _dereq_(59);
+
+var _XlinkLoader2 = _interopRequireDefault(_XlinkLoader);
+
+var _coreEventBus = _dereq_(9);
+
+var _coreEventBus2 = _interopRequireDefault(_coreEventBus);
+
+var _coreEventsEvents = _dereq_(13);
+
+var _coreEventsEvents2 = _interopRequireDefault(_coreEventsEvents);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _externalsXml2json = _dereq_(4);
+
+var _externalsXml2json2 = _interopRequireDefault(_externalsXml2json);
+
+var _utilsURLUtils = _dereq_(158);
+
+var _utilsURLUtils2 = _interopRequireDefault(_utilsURLUtils);
+
+var RESOLVE_TYPE_ONLOAD = 'onLoad';
+var RESOLVE_TYPE_ONACTUATE = 'onActuate';
+var ELEMENT_TYPE_PERIOD = 'Period';
+var ELEMENT_TYPE_ADAPTATIONSET = 'AdaptationSet';
+var ELEMENT_TYPE_EVENTSTREAM = 'EventStream';
+var RESOLVE_TO_ZERO = 'urn:mpeg:dash:resolve-to-zero:2013';
+
+function XlinkController(config) {
+
+ var context = this.context;
+ var eventBus = (0, _coreEventBus2['default'])(context).getInstance();
+ var urlUtils = (0, _utilsURLUtils2['default'])(context).getInstance();
+
+ var instance = undefined,
+ matchers = undefined,
+ iron = undefined,
+ manifest = undefined,
+ converter = undefined,
+ xlinkLoader = undefined;
+
+ function setup() {
+ eventBus.on(_coreEventsEvents2['default'].XLINK_ELEMENT_LOADED, onXlinkElementLoaded, instance);
+
+ xlinkLoader = (0, _XlinkLoader2['default'])(context).create({
+ errHandler: config.errHandler,
+ metricsModel: config.metricsModel,
+ requestModifier: config.requestModifier
+ });
+ }
+
+ function setMatchers(value) {
+ matchers = value;
+ }
+
+ function setIron(value) {
+ iron = value;
+ }
+
+ /**
+ * <p>Triggers the resolution of the xlink.onLoad attributes in the manifest file </p>
+ * @param {Object} mpd - the manifest
+ */
+ function resolveManifestOnLoad(mpd) {
+ var elements;
+ // First resolve all periods, so unnecessary requests inside onLoad Periods with Default content are avoided
+ converter = new _externalsXml2json2['default'](matchers, '', true);
+ manifest = mpd;
+ elements = getElementsToResolve(manifest.Period_asArray, manifest, ELEMENT_TYPE_PERIOD, RESOLVE_TYPE_ONLOAD);
+ resolve(elements, ELEMENT_TYPE_PERIOD, RESOLVE_TYPE_ONLOAD);
+ }
+
+ function reset() {
+ eventBus.off(_coreEventsEvents2['default'].XLINK_ELEMENT_LOADED, onXlinkElementLoaded, instance);
+
+ if (xlinkLoader) {
+ xlinkLoader.reset();
+ xlinkLoader = null;
+ }
+ }
+
+ function resolve(elements, type, resolveType) {
+ var resolveObject = {};
+ var element, url, i;
+
+ resolveObject.elements = elements;
+ resolveObject.type = type;
+ resolveObject.resolveType = resolveType;
+ // If nothing to resolve, directly call allElementsLoaded
+ if (resolveObject.elements.length === 0) {
+ onXlinkAllElementsLoaded(resolveObject);
+ }
+ for (i = 0; i < resolveObject.elements.length; i++) {
+ element = resolveObject.elements[i];
+ if (urlUtils.isHTTPURL(element.url)) {
+ url = element.url;
+ } else {
+ url = element.originalContent.BaseURL + element.url;
+ }
+ xlinkLoader.load(url, element, resolveObject);
+ }
+ }
+
+ function onXlinkElementLoaded(event) {
+ var element, resolveObject, index;
+
+ var openingTag = '<response>';
+ var closingTag = '</response>';
+ var mergedContent = '';
+
+ element = event.element;
+ resolveObject = event.resolveObject;
+ // if the element resolved into content parse the content
+ if (element.resolvedContent) {
+ // we add a parent elements so the converter is able to parse multiple elements of the same type which are not wrapped inside a container
+ index = element.resolvedContent.indexOf('>') + 1; //find the closing position of the xml tag
+ mergedContent = element.resolvedContent.substr(0, index) + openingTag + element.resolvedContent.substr(index) + closingTag;
+ element.resolvedContent = converter.xml_str2json(mergedContent);
+ }
+ if (isResolvingFinished(resolveObject)) {
+ onXlinkAllElementsLoaded(resolveObject);
+ }
+ }
+
+ // We got to wait till all elements of the current queue are resolved before merging back
+ function onXlinkAllElementsLoaded(resolveObject) {
+ var elements = [];
+ var i, obj;
+
+ mergeElementsBack(resolveObject);
+ if (resolveObject.resolveType === RESOLVE_TYPE_ONACTUATE) {
+ eventBus.trigger(_coreEventsEvents2['default'].XLINK_READY, { manifest: manifest });
+ }
+ if (resolveObject.resolveType === RESOLVE_TYPE_ONLOAD) {
+ switch (resolveObject.type) {
+ // Start resolving the other elements. We can do Adaptation Set and EventStream in parallel
+ case ELEMENT_TYPE_PERIOD:
+ for (i = 0; i < manifest[ELEMENT_TYPE_PERIOD + '_asArray'].length; i++) {
+ obj = manifest[ELEMENT_TYPE_PERIOD + '_asArray'][i];
+ if (obj.hasOwnProperty(ELEMENT_TYPE_ADAPTATIONSET + '_asArray')) {
+ elements = elements.concat(getElementsToResolve(obj[ELEMENT_TYPE_ADAPTATIONSET + '_asArray'], obj, ELEMENT_TYPE_ADAPTATIONSET, RESOLVE_TYPE_ONLOAD));
+ }
+ if (obj.hasOwnProperty(ELEMENT_TYPE_EVENTSTREAM + '_asArray')) {
+ elements = elements.concat(getElementsToResolve(obj[ELEMENT_TYPE_EVENTSTREAM + '_asArray'], obj, ELEMENT_TYPE_EVENTSTREAM, RESOLVE_TYPE_ONLOAD));
+ }
+ }
+ resolve(elements, ELEMENT_TYPE_ADAPTATIONSET, RESOLVE_TYPE_ONLOAD);
+ break;
+ case ELEMENT_TYPE_ADAPTATIONSET:
+ // TODO: Resolve SegmentList here
+ eventBus.trigger(_coreEventsEvents2['default'].XLINK_READY, { manifest: manifest });
+ break;
+ }
+ }
+ }
+
+ // Returns the elements with the specific resolve Type
+ function getElementsToResolve(elements, parentElement, type, resolveType) {
+ var toResolve = [];
+ var element, i, xlinkObject;
+ // first remove all the resolve-to-zero elements
+ for (i = elements.length - 1; i >= 0; i--) {
+ element = elements[i];
+ if (element.hasOwnProperty('xlink:href') && element['xlink:href'] === RESOLVE_TO_ZERO) {
+ elements.splice(i, 1);
+ }
+ }
+ // now get the elements with the right resolve type
+ for (i = 0; i < elements.length; i++) {
+ element = elements[i];
+ if (element.hasOwnProperty('xlink:href') && element.hasOwnProperty('xlink:actuate') && element['xlink:actuate'] === resolveType) {
+ xlinkObject = createXlinkObject(element['xlink:href'], parentElement, type, i, resolveType, element);
+ toResolve.push(xlinkObject);
+ }
+ }
+ return toResolve;
+ }
+
+ function mergeElementsBack(resolveObject) {
+ var resolvedElements = [];
+ var element, type, obj, i, j, k;
+ // Start merging back from the end because of index shifting. Note that the elements with the same parent have to be ordered by index ascending
+ for (i = resolveObject.elements.length - 1; i >= 0; i--) {
+ element = resolveObject.elements[i];
+ type = element.type + '_asArray';
+
+ // Element couldn't be resolved or is TODO Inappropriate target: Remove all Xlink attributes
+ if (!element.resolvedContent || isInappropriateTarget()) {
+ delete element.originalContent['xlink:actuate'];
+ delete element.originalContent['xlink:href'];
+ resolvedElements.push(element.originalContent);
+ }
+ // Element was successfully resolved
+ else if (element.resolvedContent) {
+ for (j = 0; j < element.resolvedContent[type].length; j++) {
+ //TODO Contains another Xlink attribute with xlink:actuate set to onload. Remove all xLink attributes
+ obj = element.resolvedContent[type][j];
+ resolvedElements.push(obj);
+ }
+ }
+ // Replace the old elements in the parent with the resolved ones
+ element.parentElement[type].splice(element.index, 1);
+ for (k = 0; k < resolvedElements.length; k++) {
+ element.parentElement[type].splice(element.index + k, 0, resolvedElements[k]);
+ }
+ resolvedElements = [];
+ }
+ if (resolveObject.elements.length > 0) {
+ iron.run(manifest);
+ }
+ }
+
+ function createXlinkObject(url, parentElement, type, index, resolveType, originalContent) {
+ return {
+ url: url,
+ parentElement: parentElement,
+ type: type,
+ index: index,
+ resolveType: resolveType,
+ originalContent: originalContent,
+ resolvedContent: null,
+ resolved: false
+ };
+ }
+
+ // Check if all pending requests are finished
+ function isResolvingFinished(elementsToResolve) {
+ var i, obj;
+ for (i = 0; i < elementsToResolve.elements.length; i++) {
+ obj = elementsToResolve.elements[i];
+ if (obj.resolved === false) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ // TODO : Do some syntax check here if the target is valid or not
+ function isInappropriateTarget() {
+ return false;
+ }
+
+ instance = {
+ resolveManifestOnLoad: resolveManifestOnLoad,
+ setMatchers: setMatchers,
+ setIron: setIron,
+ reset: reset
+ };
+
+ setup();
+ return instance;
+}
+
+XlinkController.__dashjs_factory_name = 'XlinkController';
+exports['default'] = _coreFactoryMaker2['default'].getClassFactory(XlinkController);
+module.exports = exports['default'];
+
+},{"10":10,"13":13,"158":158,"4":4,"59":59,"9":9}],75:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _utilsDVBErrorsTranslator = _dereq_(89);
+
+var _utilsDVBErrorsTranslator2 = _interopRequireDefault(_utilsDVBErrorsTranslator);
+
+var _MetricsReportingEvents = _dereq_(76);
+
+var _MetricsReportingEvents2 = _interopRequireDefault(_MetricsReportingEvents);
+
+var _controllersMetricsCollectionController = _dereq_(77);
+
+var _controllersMetricsCollectionController2 = _interopRequireDefault(_controllersMetricsCollectionController);
+
+var _metricsMetricsHandlerFactory = _dereq_(82);
+
+var _metricsMetricsHandlerFactory2 = _interopRequireDefault(_metricsMetricsHandlerFactory);
+
+var _reportingReportingFactory = _dereq_(87);
+
+var _reportingReportingFactory2 = _interopRequireDefault(_reportingReportingFactory);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+function MetricsReporting() {
+
+ var context = this.context;
+ var instance = undefined;
+
+ var dvbErrorsTranslator = undefined;
+
+ /**
+ * Create a MetricsCollectionController, and a DVBErrorsTranslator
+ * @param {Object} config - dependancies from owner
+ * @return {MetricsCollectionController} Metrics Collection Controller
+ */
+ function createMetricsReporting(config) {
+ dvbErrorsTranslator = (0, _utilsDVBErrorsTranslator2['default'])(context).getInstance({
+ eventBus: config.eventBus,
+ metricsModel: config.metricsModel
+ });
+
+ return (0, _controllersMetricsCollectionController2['default'])(context).create(config);
+ }
+
+ /**
+ * Get the ReportingFactory to allow new reporters to be registered
+ * @return {ReportingFactory} Reporting Factory
+ */
+ function getReportingFactory() {
+ return (0, _reportingReportingFactory2['default'])(context).getInstance();
+ }
+
+ /**
+ * Get the MetricsHandlerFactory to allow new handlers to be registered
+ * @return {MetricsHandlerFactory} Metrics Handler Factory
+ */
+ function getMetricsHandlerFactory() {
+ return (0, _metricsMetricsHandlerFactory2['default'])(context).getInstance();
+ }
+
+ instance = {
+ createMetricsReporting: createMetricsReporting,
+ getReportingFactory: getReportingFactory,
+ getMetricsHandlerFactory: getMetricsHandlerFactory
+ };
+
+ return instance;
+}
+
+MetricsReporting.__dashjs_factory_name = 'MetricsReporting';
+var factory = _coreFactoryMaker2['default'].getClassFactory(MetricsReporting);
+factory.events = _MetricsReportingEvents2['default'];
+exports['default'] = factory;
+module.exports = exports['default'];
+
+},{"10":10,"76":76,"77":77,"82":82,"87":87,"89":89}],76:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+var _coreEventsEventsBase = _dereq_(14);
+
+var _coreEventsEventsBase2 = _interopRequireDefault(_coreEventsEventsBase);
+
+var MetricsReportingEvents = (function (_EventsBase) {
+ _inherits(MetricsReportingEvents, _EventsBase);
+
+ function MetricsReportingEvents() {
+ _classCallCheck(this, MetricsReportingEvents);
+
+ _get(Object.getPrototypeOf(MetricsReportingEvents.prototype), 'constructor', this).call(this);
+
+ this.METRICS_INITIALISATION_COMPLETE = 'internal_metricsReportingInitialized';
+ this.BECAME_REPORTING_PLAYER = 'internal_becameReportingPlayer';
+ }
+
+ return MetricsReportingEvents;
+})(_coreEventsEventsBase2['default']);
+
+var metricsReportingEvents = new MetricsReportingEvents();
+exports['default'] = metricsReportingEvents;
+module.exports = exports['default'];
+
+},{"14":14}],77:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _MetricsController = _dereq_(78);
+
+var _MetricsController2 = _interopRequireDefault(_MetricsController);
+
+var _utilsManifestParsing = _dereq_(91);
+
+var _utilsManifestParsing2 = _interopRequireDefault(_utilsManifestParsing);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _MetricsReportingEvents = _dereq_(76);
+
+var _MetricsReportingEvents2 = _interopRequireDefault(_MetricsReportingEvents);
+
+var _coreEventsEvents = _dereq_(13);
+
+var _coreEventsEvents2 = _interopRequireDefault(_coreEventsEvents);
+
+function MetricsCollectionController(config) {
+
+ var metricsControllers = {};
+
+ var context = this.context;
+ var eventBus = config.eventBus;
+
+ function update(e) {
+ if (e.error) {
+ return;
+ }
+
+ // start by assuming all existing controllers need removing
+ var controllersToRemove = Object.keys(metricsControllers);
+
+ var metrics = (0, _utilsManifestParsing2['default'])(context).getInstance({
+ dashManifestModel: config.dashManifestModel
+ }).getMetrics(e.manifest);
+
+ metrics.forEach(function (m) {
+ var key = JSON.stringify(m);
+
+ if (!metricsControllers.hasOwnProperty(key)) {
+ try {
+ var controller = (0, _MetricsController2['default'])(context).create(config);
+ controller.initialize(m);
+ metricsControllers[key] = controller;
+ } catch (e) {
+ // fail quietly
+ }
+ } else {
+ // we still need this controller - delete from removal list
+ controllersToRemove.splice(key, 1);
+ }
+ });
+
+ // now remove the unwanted controllers
+ controllersToRemove.forEach(function (c) {
+ metricsControllers[c].reset();
+ delete metricsControllers[c];
+ });
+
+ eventBus.trigger(_MetricsReportingEvents2['default'].METRICS_INITIALISATION_COMPLETE);
+ }
+
+ function reset() {
+ Object.keys(metricsControllers).forEach(function (key) {
+ metricsControllers[key].reset();
+ });
+
+ metricsControllers = {};
+ }
+
+ function setup() {
+
+ eventBus.on(_coreEventsEvents2['default'].MANIFEST_UPDATED, update);
+ eventBus.on(_coreEventsEvents2['default'].STREAM_TEARDOWN_COMPLETE, reset);
+ }
+
+ setup();
+
+ // don't export any actual methods
+ return {};
+}
+
+MetricsCollectionController.__dashjs_factory_name = 'MetricsCollectionController';
+exports['default'] = _coreFactoryMaker2['default'].getClassFactory(MetricsCollectionController);
+module.exports = exports['default'];
+
+},{"10":10,"13":13,"76":76,"78":78,"91":91}],78:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _RangeController = _dereq_(80);
+
+var _RangeController2 = _interopRequireDefault(_RangeController);
+
+var _ReportingController = _dereq_(81);
+
+var _ReportingController2 = _interopRequireDefault(_ReportingController);
+
+var _MetricsHandlersController = _dereq_(79);
+
+var _MetricsHandlersController2 = _interopRequireDefault(_MetricsHandlersController);
+
+function MetricsController(config) {
+
+ var metricsHandlersController = undefined,
+ reportingController = undefined,
+ rangeController = undefined,
+ instance = undefined;
+
+ var context = this.context;
+
+ function initialize(metricsEntry) {
+ try {
+ rangeController = (0, _RangeController2['default'])(context).create({
+ mediaElement: config.mediaElement
+ });
+
+ rangeController.initialize(metricsEntry.Range);
+
+ reportingController = (0, _ReportingController2['default'])(context).create({
+ log: config.log
+ });
+
+ reportingController.initialize(metricsEntry.Reporting, rangeController);
+
+ metricsHandlersController = (0, _MetricsHandlersController2['default'])(context).create({
+ log: config.log,
+ eventBus: config.eventBus
+ });
+
+ metricsHandlersController.initialize(metricsEntry.metrics, reportingController);
+ } catch (e) {
+ reset();
+ throw e;
+ }
+ }
+
+ function reset() {
+ if (metricsHandlersController) {
+ metricsHandlersController.reset();
+ }
+
+ if (reportingController) {
+ reportingController.reset();
+ }
+
+ if (rangeController) {
+ rangeController.reset();
+ }
+ }
+
+ instance = {
+ initialize: initialize,
+ reset: reset
+ };
+
+ return instance;
+}
+
+MetricsController.__dashjs_factory_name = 'MetricsController';
+exports['default'] = _coreFactoryMaker2['default'].getClassFactory(MetricsController);
+module.exports = exports['default'];
+
+},{"10":10,"79":79,"80":80,"81":81}],79:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _metricsMetricsHandlerFactory = _dereq_(82);
+
+var _metricsMetricsHandlerFactory2 = _interopRequireDefault(_metricsMetricsHandlerFactory);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _MediaPlayerEvents = _dereq_(52);
+
+var _MediaPlayerEvents2 = _interopRequireDefault(_MediaPlayerEvents);
+
+function MetricsHandlersController(config) {
+ var handlers = [];
+
+ var instance = undefined;
+ var context = this.context;
+ var eventBus = config.eventBus;
+
+ var metricsHandlerFactory = (0, _metricsMetricsHandlerFactory2['default'])(context).getInstance({
+ log: config.log,
+ eventBus: config.eventBus
+ });
+
+ function handle(e) {
+ handlers.forEach(function (handler) {
+ handler.handleNewMetric(e.metric, e.value, e.mediaType);
+ });
+ }
+
+ function initialize(metrics, reportingController) {
+ metrics.split(',').forEach(function (m, midx, ms) {
+ var handler;
+
+ // there is a bug in ISO23009-1 where the metrics attribute
+ // is a comma-separated list but HttpList key can contain a
+ // comma enclosed by ().
+ if (m.indexOf('(') !== -1 && m.indexOf(')') === -1) {
+ var nextm = ms[midx + 1];
+
+ if (nextm && nextm.indexOf('(') === -1 && nextm.indexOf(')') !== -1) {
+ m += ',' + nextm;
+
+ // delete the next metric so forEach does not visit.
+ delete ms[midx + 1];
+ }
+ }
+
+ handler = metricsHandlerFactory.create(m, reportingController);
+
+ if (handler) {
+ handlers.push(handler);
+ }
+ });
+
+ eventBus.on(_MediaPlayerEvents2['default'].METRIC_ADDED, handle, instance);
+
+ eventBus.on(_MediaPlayerEvents2['default'].METRIC_UPDATED, handle, instance);
+ }
+
+ function reset() {
+ eventBus.off(_MediaPlayerEvents2['default'].METRIC_ADDED, handle, instance);
+
+ eventBus.off(_MediaPlayerEvents2['default'].METRIC_UPDATED, handle, instance);
+
+ handlers.forEach(function (handler) {
+ return handler.reset();
+ });
+
+ handlers = [];
+ }
+
+ instance = {
+ initialize: initialize,
+ reset: reset
+ };
+
+ return instance;
+}
+
+MetricsHandlersController.__dashjs_factory_name = 'MetricsHandlersController';
+exports['default'] = _coreFactoryMaker2['default'].getClassFactory(MetricsHandlersController);
+module.exports = exports['default'];
+
+},{"10":10,"52":52,"82":82}],80:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _utilsCustomTimeRanges = _dereq_(148);
+
+var _utilsCustomTimeRanges2 = _interopRequireDefault(_utilsCustomTimeRanges);
+
+function RangeController(config) {
+
+ var useWallClockTime = false;
+ var context = this.context;
+ var instance = undefined,
+ ranges = undefined;
+
+ var mediaElement = config.mediaElement;
+
+ function initialize(rs) {
+ if (rs && rs.length) {
+ rs.forEach(function (r) {
+ var start = r.starttime;
+ var end = start + r.duration;
+
+ ranges.add(start, end);
+ });
+
+ useWallClockTime = !!rs[0]._useWallClockTime;
+ }
+ }
+
+ function reset() {
+ ranges.clear();
+ }
+
+ function setup() {
+ ranges = (0, _utilsCustomTimeRanges2['default'])(context).create();
+ }
+
+ function isEnabled() {
+ var numRanges = ranges.length;
+ var time;
+
+ if (!numRanges) {
+ return true;
+ }
+
+ // When not present, DASH Metrics reporting is requested
+ // for the whole duration of the content.
+ time = useWallClockTime ? new Date().getTime() / 1000 : mediaElement.currentTime;
+
+ for (var i = 0; i < numRanges; i += 1) {
+ var start = ranges.start(i);
+ var end = ranges.end(i);
+
+ if (start <= time && time < end) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ instance = {
+ initialize: initialize,
+ reset: reset,
+ isEnabled: isEnabled
+ };
+
+ setup();
+
+ return instance;
+}
+
+RangeController.__dashjs_factory_name = 'RangeController';
+exports['default'] = _coreFactoryMaker2['default'].getClassFactory(RangeController);
+module.exports = exports['default'];
+
+},{"10":10,"148":148}],81:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _reportingReportingFactory = _dereq_(87);
+
+var _reportingReportingFactory2 = _interopRequireDefault(_reportingReportingFactory);
+
+function ReportingController(config) {
+
+ var reporters = [];
+ var instance = undefined;
+
+ var reportingFactory = (0, _reportingReportingFactory2['default'])(this.context).getInstance({
+ log: config.log
+ });
+
+ function initialize(reporting, rangeController) {
+ // "if multiple Reporting elements are present, it is expected that
+ // the client processes one of the recognized reporting schemes."
+ // to ignore this, and support multiple Reporting per Metric,
+ // simply change the 'some' below to 'forEach'
+ reporting.some(function (r) {
+ var reporter = reportingFactory.create(r, rangeController);
+
+ if (reporter) {
+ reporters.push(reporter);
+ return true;
+ }
+ });
+ }
+
+ function reset() {
+ reporters.forEach(function (r) {
+ return r.reset();
+ });
+ reporters = [];
+ }
+
+ function report(type, vos) {
+ reporters.forEach(function (r) {
+ return r.report(type, vos);
+ });
+ }
+
+ instance = {
+ initialize: initialize,
+ reset: reset,
+ report: report
+ };
+
+ return instance;
+}
+
+ReportingController.__dashjs_factory_name = 'ReportingController';
+exports['default'] = _coreFactoryMaker2['default'].getClassFactory(ReportingController);
+module.exports = exports['default'];
+
+},{"10":10,"87":87}],82:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _handlersBufferLevelHandler = _dereq_(83);
+
+var _handlersBufferLevelHandler2 = _interopRequireDefault(_handlersBufferLevelHandler);
+
+var _handlersDVBErrorsHandler = _dereq_(84);
+
+var _handlersDVBErrorsHandler2 = _interopRequireDefault(_handlersDVBErrorsHandler);
+
+var _handlersHttpListHandler = _dereq_(86);
+
+var _handlersHttpListHandler2 = _interopRequireDefault(_handlersHttpListHandler);
+
+var _handlersGenericMetricHandler = _dereq_(85);
+
+var _handlersGenericMetricHandler2 = _interopRequireDefault(_handlersGenericMetricHandler);
+
+function MetricsHandlerFactory(config) {
+
+ var instance = undefined;
+ var log = config.log;
+
+ // group 1: key, [group 3: n [, group 5: type]]
+ var keyRegex = /([a-zA-Z]*)(\(([0-9]*)(\,\s*([a-zA-Z]*))?\))?/;
+
+ var context = this.context;
+ var knownFactoryProducts = {
+ BufferLevel: _handlersBufferLevelHandler2['default'],
+ DVBErrors: _handlersDVBErrorsHandler2['default'],
+ HttpList: _handlersHttpListHandler2['default'],
+ PlayList: _handlersGenericMetricHandler2['default'],
+ RepSwitchList: _handlersGenericMetricHandler2['default'],
+ TcpList: _handlersGenericMetricHandler2['default']
+ };
+
+ function create(listType, reportingController) {
+ var matches = listType.match(keyRegex);
+ var handler;
+
+ if (!matches) {
+ return;
+ }
+
+ try {
+ handler = knownFactoryProducts[matches[1]](context).create({
+ eventBus: config.eventBus
+ });
+
+ handler.initialize(matches[1], reportingController, matches[3], matches[5]);
+ } catch (e) {
+ handler = null;
+
+ log('MetricsHandlerFactory: Could not create handler for type ' + matches[1] + ' with args ' + matches[3] + ', ' + matches[5] + ' (' + e.message + ')');
+ }
+
+ return handler;
+ }
+
+ function register(key, handler) {
+ knownFactoryProducts[key] = handler;
+ }
+
+ function unregister(key) {
+ delete knownFactoryProducts[key];
+ }
+
+ instance = {
+ create: create,
+ register: register,
+ unregister: unregister
+ };
+
+ return instance;
+}
+
+MetricsHandlerFactory.__dashjs_factory_name = 'MetricsHandlerFactory';
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(MetricsHandlerFactory);
+module.exports = exports['default'];
+
+},{"10":10,"83":83,"84":84,"85":85,"86":86}],83:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _utilsHandlerHelpers = _dereq_(90);
+
+var _utilsHandlerHelpers2 = _interopRequireDefault(_utilsHandlerHelpers);
+
+function BufferLevelHandler() {
+
+ var instance = undefined,
+ reportingController = undefined,
+ n = undefined,
+ name = undefined,
+ interval = undefined,
+ lastReportedTime = undefined;
+
+ var context = this.context;
+ var handlerHelpers = (0, _utilsHandlerHelpers2['default'])(context).getInstance();
+
+ var storedVOs = [];
+
+ function getLowestBufferLevelVO() {
+ try {
+ return Object.keys(storedVOs).map(function (key) {
+ return storedVOs[key];
+ }).reduce(function (a, b) {
+ return a.level < b.level ? a : b;
+ });
+ } catch (e) {
+ return;
+ }
+ }
+
+ function intervalCallback() {
+ var vo = getLowestBufferLevelVO();
+
+ if (vo) {
+ if (lastReportedTime !== vo.t) {
+ lastReportedTime = vo.t;
+ reportingController.report(name, vo);
+ }
+ }
+ }
+
+ function initialize(basename, rc, n_ms) {
+ if (rc) {
+ // this will throw if n is invalid, to be
+ // caught by the initialize caller.
+ n = handlerHelpers.validateN(n_ms);
+ reportingController = rc;
+ name = handlerHelpers.reconstructFullMetricName(basename, n_ms);
+ interval = setInterval(intervalCallback, n);
+ }
+ }
+
+ function reset() {
+ clearInterval(interval);
+ interval = null;
+ n = 0;
+ reportingController = null;
+ lastReportedTime = null;
+ }
+
+ function handleNewMetric(metric, vo, type) {
+ if (metric === 'BufferLevel') {
+ storedVOs[type] = vo;
+ }
+ }
+
+ instance = {
+ initialize: initialize,
+ reset: reset,
+ handleNewMetric: handleNewMetric
+ };
+
+ return instance;
+}
+
+BufferLevelHandler.__dashjs_factory_name = 'BufferLevelHandler';
+exports['default'] = _coreFactoryMaker2['default'].getClassFactory(BufferLevelHandler);
+module.exports = exports['default'];
+
+},{"10":10,"90":90}],84:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _MetricsReportingEvents = _dereq_(76);
+
+var _MetricsReportingEvents2 = _interopRequireDefault(_MetricsReportingEvents);
+
+function DVBErrorsHandler(config) {
+
+ var instance = undefined,
+ reportingController = undefined;
+
+ var eventBus = config.eventBus;
+
+ function onInitialisationComplete() {
+ // we only want to report this once per call to initialize
+ eventBus.off(_MetricsReportingEvents2['default'].METRICS_INITIALISATION_COMPLETE, onInitialisationComplete, this);
+
+ // Note: A Player becoming a reporting Player is itself
+ // something which is recorded by the DVBErrors metric.
+ eventBus.trigger(_MetricsReportingEvents2['default'].BECAME_REPORTING_PLAYER);
+ }
+
+ function initialize(unused, rc) {
+ if (rc) {
+ reportingController = rc;
+
+ eventBus.on(_MetricsReportingEvents2['default'].METRICS_INITIALISATION_COMPLETE, onInitialisationComplete, this);
+ }
+ }
+
+ function reset() {
+ reportingController = null;
+ }
+
+ function handleNewMetric(metric, vo) {
+ // simply pass metric straight through
+ if (metric === 'DVBErrors') {
+ if (reportingController) {
+ reportingController.report(metric, vo);
+ }
+ }
+ }
+
+ instance = {
+ initialize: initialize,
+ reset: reset,
+ handleNewMetric: handleNewMetric
+ };
+
+ return instance;
+}
+
+exports['default'] = _coreFactoryMaker2['default'].getClassFactory(DVBErrorsHandler);
+module.exports = exports['default'];
+
+},{"10":10,"76":76}],85:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+function GenericMetricHandler() {
+
+ var instance = undefined,
+ metricName = undefined,
+ reportingController = undefined;
+
+ function initialize(name, rc) {
+ metricName = name;
+ reportingController = rc;
+ }
+
+ function reset() {
+ reportingController = null;
+ metricName = undefined;
+ }
+
+ function handleNewMetric(metric, vo) {
+ // simply pass metric straight through
+ if (metric === metricName) {
+ if (reportingController) {
+ reportingController.report(metricName, vo);
+ }
+ }
+ }
+
+ instance = {
+ initialize: initialize,
+ reset: reset,
+ handleNewMetric: handleNewMetric
+ };
+
+ return instance;
+}
+
+GenericMetricHandler.__dashjs_factory_name = 'GenericMetricHandler';
+exports['default'] = _coreFactoryMaker2['default'].getClassFactory(GenericMetricHandler);
+module.exports = exports['default'];
+
+},{"10":10}],86:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _utilsHandlerHelpers = _dereq_(90);
+
+var _utilsHandlerHelpers2 = _interopRequireDefault(_utilsHandlerHelpers);
+
+function HttpListHandler() {
+
+ var instance = undefined,
+ reportingController = undefined,
+ n = undefined,
+ type = undefined,
+ name = undefined,
+ interval = undefined;
+
+ var storedVos = [];
+
+ var handlerHelpers = (0, _utilsHandlerHelpers2['default'])(this.context).getInstance();
+
+ function intervalCallback() {
+ var vos = storedVos;
+
+ if (vos.length) {
+ if (reportingController) {
+ reportingController.report(name, vos);
+ }
+ }
+
+ storedVos = [];
+ }
+
+ function initialize(basename, rc, n_ms, requestType) {
+ if (rc) {
+
+ // this will throw if n is invalid, to be
+ // caught by the initialize caller.
+ n = handlerHelpers.validateN(n_ms);
+
+ reportingController = rc;
+
+ if (requestType && requestType.length) {
+ type = requestType;
+ }
+
+ name = handlerHelpers.reconstructFullMetricName(basename, n_ms, requestType);
+
+ interval = setInterval(intervalCallback, n);
+ }
+ }
+
+ function reset() {
+ clearInterval(interval);
+ interval = null;
+ n = null;
+ type = null;
+ storedVos = [];
+ reportingController = null;
+ }
+
+ function handleNewMetric(metric, vo) {
+ if (metric === 'HttpList') {
+ if (!type || type === vo.type) {
+ storedVos.push(vo);
+ }
+ }
+ }
+
+ instance = {
+ initialize: initialize,
+ reset: reset,
+ handleNewMetric: handleNewMetric
+ };
+
+ return instance;
+}
+
+HttpListHandler.__dashjs_factory_name = 'HttpListHandler';
+exports['default'] = _coreFactoryMaker2['default'].getClassFactory(HttpListHandler);
+module.exports = exports['default'];
+
+},{"10":10,"90":90}],87:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _reportersDVBReporting = _dereq_(88);
+
+var _reportersDVBReporting2 = _interopRequireDefault(_reportersDVBReporting);
+
+function ReportingFactory(config) {
+
+ var knownReportingSchemeIdUris = {
+ 'urn:dvb:dash:reporting:2014': _reportersDVBReporting2['default']
+ };
+
+ var context = this.context;
+ var log = config.log;
+ var instance = undefined;
+
+ function create(entry, rangeController) {
+ var reporting;
+
+ try {
+ reporting = knownReportingSchemeIdUris[entry.schemeIdUri](context).create();
+
+ reporting.initialize(entry, rangeController);
+ } catch (e) {
+ reporting = null;
+
+ log('ReportingFactory: could not create Reporting with schemeIdUri ' + entry.schemeIdUri + ' (' + e.message + ')');
+ }
+
+ return reporting;
+ }
+
+ function register(schemeIdUri, moduleName) {
+ knownReportingSchemeIdUris[schemeIdUri] = moduleName;
+ }
+
+ function unregister(schemeIdUri) {
+ delete knownReportingSchemeIdUris[schemeIdUri];
+ }
+
+ instance = {
+ create: create,
+ register: register,
+ unregister: unregister
+ };
+
+ return instance;
+}
+
+ReportingFactory.__dashjs_factory_name = 'ReportingFactory';
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(ReportingFactory);
+module.exports = exports['default'];
+
+},{"10":10,"88":88}],88:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _utilsMetricSerialiser = _dereq_(92);
+
+var _utilsMetricSerialiser2 = _interopRequireDefault(_utilsMetricSerialiser);
+
+var _utilsRNG = _dereq_(93);
+
+var _utilsRNG2 = _interopRequireDefault(_utilsRNG);
+
+function DVBReporting() {
+ var instance = undefined;
+
+ var context = this.context;
+ var metricSerialiser = (0, _utilsMetricSerialiser2['default'])(context).getInstance();
+ var randomNumberGenerator = (0, _utilsRNG2['default'])(context).getInstance();
+
+ var USE_DRAFT_DVB_SPEC = true;
+ var isReportingPlayer = false;
+ var reportingPlayerStatusDecided = false;
+ var reportingUrl = null;
+ var rangeController = null;
+ var allowPendingRequestsToCompleteOnReset = true;
+ var pendingRequests = [];
+
+ function doGetRequest(url, successCB, failureCB) {
+ var req = new XMLHttpRequest();
+ var oncomplete = function oncomplete() {
+ var reqIndex = pendingRequests.indexOf(req);
+
+ if (reqIndex === -1) {
+ return;
+ } else {
+ pendingRequests.splice(reqIndex, 1);
+ }
+
+ if (req.status >= 200 && req.status < 300) {
+ if (successCB) {
+ successCB();
+ }
+ } else {
+ if (failureCB) {
+ failureCB();
+ }
+ }
+ };
+
+ pendingRequests.push(req);
+
+ try {
+ req.open('GET', url);
+ req.onloadend = oncomplete;
+ req.onerror = oncomplete;
+ req.send();
+ } catch (e) {
+ req.onerror();
+ }
+ }
+
+ function report(type, vos) {
+ if (!Array.isArray(vos)) {
+ vos = [vos];
+ }
+
+ // If the Player is not a reporting Player, then the Player shall
+ // not report any errors.
+ // ... In addition to any time restrictions specified by a Range
+ // element within the Metrics element.
+ if (isReportingPlayer && rangeController.isEnabled()) {
+
+ // This reporting mechanism operates by creating one HTTP GET
+ // request for every entry in the top level list of the metric.
+ vos.forEach(function (vo) {
+ var url = metricSerialiser.serialise(vo);
+
+ // this has been proposed for errata
+ if (USE_DRAFT_DVB_SPEC && type !== 'DVBErrors') {
+ url = 'metricname=' + type + '&' + url;
+ }
+
+ // Take the value of the @reportingUrl attribute, append a
+ // question mark ('?') character and then append the string
+ // created in the previous step.
+ url = reportingUrl + '?' + url;
+
+ // Make an HTTP GET request to the URL contained within the
+ // string created in the previous step.
+ doGetRequest(url, null, function () {
+ // If the Player is unable to make the report, for
+ // example because the @reportingUrl is invalid, the
+ // host cannot be reached, or an HTTP status code other
+ // than one in the 200 series is received, the Player
+ // shall cease being a reporting Player for the
+ // duration of the MPD.
+ isReportingPlayer = false;
+ });
+ });
+ }
+ }
+
+ function initialize(entry, rc) {
+ var probability;
+
+ rangeController = rc;
+
+ reportingUrl = entry['dvb:reportingUrl'];
+
+ // If a required attribute is missing, the Reporting descriptor may
+ // be ignored by the Player
+ if (!reportingUrl) {
+ throw new Error('required parameter missing (dvb:reportingUrl)');
+ }
+
+ // A Player's status, as a reporting Player or not, shall remain
+ // static for the duration of the MPD, regardless of MPD updates.
+ // (i.e. only calling reset (or failure) changes this state)
+ if (!reportingPlayerStatusDecided) {
+ // NOTE: DVB spec has a typo where it incorrectly references the
+ // priority attribute, which should be probability
+ probability = entry['dvb:probability'] || entry['dvb:priority'] || 0;
+ // If the @priority attribute is set to 1000, it shall be a reporting Player.
+ // If the @priority attribute is missing, the Player shall not be a reporting Player.
+ // For any other value of the @probability attribute, it shall decide at random whether to be a
+ // reporting Player, such that the probability of being one is @probability/1000.
+ if (probability && (probability === 1000 || probability / 1000 >= randomNumberGenerator.random())) {
+ isReportingPlayer = true;
+ }
+
+ reportingPlayerStatusDecided = true;
+ }
+ }
+
+ function reset() {
+ if (!allowPendingRequestsToCompleteOnReset) {
+ pendingRequests.forEach(function (req) {
+ return req.abort();
+ });
+ pendingRequests = [];
+ }
+
+ reportingPlayerStatusDecided = false;
+ isReportingPlayer = false;
+ reportingUrl = null;
+ rangeController = null;
+ }
+
+ instance = {
+ report: report,
+ initialize: initialize,
+ reset: reset
+ };
+
+ return instance;
+}
+
+DVBReporting.__dashjs_factory_name = 'DVBReporting';
+exports['default'] = _coreFactoryMaker2['default'].getClassFactory(DVBReporting);
+module.exports = exports['default'];
+
+},{"10":10,"92":92,"93":93}],89:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _voDVBErrors = _dereq_(94);
+
+var _voDVBErrors2 = _interopRequireDefault(_voDVBErrors);
+
+var _coreEventsEvents = _dereq_(13);
+
+var _coreEventsEvents2 = _interopRequireDefault(_coreEventsEvents);
+
+var _MediaPlayerEvents = _dereq_(52);
+
+var _MediaPlayerEvents2 = _interopRequireDefault(_MediaPlayerEvents);
+
+var _MetricsReportingEvents = _dereq_(76);
+
+var _MetricsReportingEvents2 = _interopRequireDefault(_MetricsReportingEvents);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+function DVBErrorsTranslator(config) {
+
+ var instance = undefined;
+ var eventBus = config.eventBus;
+ var metricModel = config.metricsModel;
+ var mpd = undefined;
+
+ function report(vo) {
+ var o = new _voDVBErrors2['default']();
+
+ if (!mpd) {
+ return;
+ }
+
+ for (var key in vo) {
+ if (vo.hasOwnProperty(key)) {
+ o[key] = vo[key];
+ }
+ }
+
+ if (!o.mpdurl) {
+ o.mpdurl = mpd.originalUrl || mpd.url;
+ }
+
+ if (!o.terror) {
+ o.terror = new Date();
+ }
+
+ metricModel.addDVBErrors(o);
+ }
+
+ function onManifestUpdate(e) {
+ if (e.error) {
+ return;
+ }
+
+ mpd = e.manifest;
+ }
+
+ function onServiceLocationChanged(e) {
+ report({
+ errorcode: _voDVBErrors2['default'].BASE_URL_CHANGED,
+ servicelocation: e.entry
+ });
+ }
+
+ function onBecameReporter() {
+ report({
+ errorcode: _voDVBErrors2['default'].BECAME_REPORTER
+ });
+ }
+
+ function handleHttpMetric(vo) {
+ if (vo.responsecode === 0 || // connection failure - unknown
+ vo.responsecode >= 400 || // HTTP error status code
+ vo.responsecode < 100 || // unknown status codes
+ vo.responsecode >= 600) {
+ // unknown status codes
+ report({
+ errorcode: vo.responsecode || _voDVBErrors2['default'].CONNECTION_ERROR,
+ url: vo.url,
+ terror: vo.tresponse,
+ servicelocation: vo._serviceLocation
+ });
+ }
+ }
+
+ function onMetricEvent(e) {
+ switch (e.metric) {
+ case 'HttpList':
+ handleHttpMetric(e.value);
+ break;
+ default:
+ break;
+ }
+ }
+
+ function onPlaybackError(e) {
+ var reason = e.error ? e.error.code : 0;
+ var errorcode;
+
+ switch (reason) {
+ case MediaError.MEDIA_ERR_NETWORK:
+ errorcode = _voDVBErrors2['default'].CONNECTION_ERROR;
+ break;
+ case MediaError.MEDIA_ERR_DECODE:
+ errorcode = _voDVBErrors2['default'].CORRUPT_MEDIA_OTHER;
+ break;
+ default:
+ return;
+ }
+
+ report({
+ errorcode: errorcode
+ });
+ }
+
+ function initialise() {
+ eventBus.on(_coreEventsEvents2['default'].MANIFEST_UPDATED, onManifestUpdate, instance);
+ eventBus.on(_coreEventsEvents2['default'].SERVICE_LOCATION_BLACKLIST_CHANGED, onServiceLocationChanged, instance);
+ eventBus.on(_MediaPlayerEvents2['default'].METRIC_ADDED, onMetricEvent, instance);
+ eventBus.on(_MediaPlayerEvents2['default'].METRIC_UPDATED, onMetricEvent, instance);
+ eventBus.on(_MediaPlayerEvents2['default'].PLAYBACK_ERROR, onPlaybackError, instance);
+ eventBus.on(_MetricsReportingEvents2['default'].BECAME_REPORTING_PLAYER, onBecameReporter, instance);
+ }
+
+ function reset() {
+ eventBus.off(_coreEventsEvents2['default'].MANIFEST_UPDATED, onManifestUpdate, instance);
+ eventBus.off(_coreEventsEvents2['default'].SERVICE_LOCATION_BLACKLIST_CHANGED, onServiceLocationChanged, instance);
+ eventBus.off(_MediaPlayerEvents2['default'].METRIC_ADDED, onMetricEvent, instance);
+ eventBus.off(_MediaPlayerEvents2['default'].METRIC_UPDATED, onMetricEvent, instance);
+ eventBus.off(_MediaPlayerEvents2['default'].PLAYBACK_ERROR, onPlaybackError, instance);
+ eventBus.off(_MetricsReportingEvents2['default'].BECAME_REPORTING_PLAYER, onBecameReporter, instance);
+ }
+
+ instance = {
+ initialise: initialise,
+ reset: reset
+ };
+
+ initialise();
+
+ return instance;
+}
+
+DVBErrorsTranslator.__dashjs_factory_name = 'DVBErrorsTranslator';
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(DVBErrorsTranslator);
+module.exports = exports['default'];
+
+},{"10":10,"13":13,"52":52,"76":76,"94":94}],90:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+function HandlerHelpers() {
+ return {
+ reconstructFullMetricName: function reconstructFullMetricName(key, n, type) {
+ var mn = key;
+
+ if (n) {
+ mn += '(' + n;
+
+ if (type && type.length) {
+ mn += ',' + type;
+ }
+
+ mn += ')';
+ }
+
+ return mn;
+ },
+
+ validateN: function validateN(n_ms) {
+ if (!n_ms) {
+ throw new Error('missing n');
+ }
+
+ if (isNaN(n_ms)) {
+ throw new Error('n is NaN');
+ }
+
+ // n is a positive integer is defined to refer to the metric
+ // in which the buffer level is recorded every n ms.
+ if (n_ms < 0) {
+ throw new Error('n must be positive');
+ }
+
+ return n_ms;
+ }
+ };
+}
+
+HandlerHelpers.__dashjs_factory_name = 'HandlerHelpers';
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(HandlerHelpers);
+module.exports = exports['default'];
+
+},{"10":10}],91:[function(_dereq_,module,exports){
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _voMetrics = _dereq_(95);
+
+var _voMetrics2 = _interopRequireDefault(_voMetrics);
+
+var _voRange = _dereq_(96);
+
+var _voRange2 = _interopRequireDefault(_voRange);
+
+var _voReporting = _dereq_(97);
+
+var _voReporting2 = _interopRequireDefault(_voReporting);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+function ManifestParsing(config) {
+ var instance = undefined;
+ var dashManifestModel = config.dashManifestModel;
+
+ function getMetricsRangeStartTime(manifest, dynamic, range) {
+ var mpd = dashManifestModel.getMpd(manifest);
+ var periods;
+ var presentationStartTime = 0;
+ var reportingStartTime;
+
+ if (dynamic) {
+ // For services with MPD@type='dynamic', the start time is
+ // indicated in wall clock time by adding the value of this
+ // attribute to the value of the MPD@availabilityStartTime
+ // attribute.
+ presentationStartTime = mpd.availabilityStartTime.getTime() / 1000;
+ } else {
+ // For services with MPD@type='static', the start time is indicated
+ // in Media Presentation time and is relative to the PeriodStart
+ // time of the first Period in this MPD.
+ periods = this.getRegularPeriods(manifest, mpd);
+
+ if (periods.length) {
+ presentationStartTime = periods[0].start;
+ }
+ }
+
+ // When not present, DASH Metrics collection is
+ // requested from the beginning of content
+ // consumption.
+ reportingStartTime = presentationStartTime;
+
+ if (range && range.hasOwnProperty('starttime')) {
+ reportingStartTime += range.starttime;
+ }
+
+ return reportingStartTime;
+ }
+
+ function getMetrics(manifest) {
+ var metrics = [];
+
+ if (manifest.Metrics_asArray) {
+ manifest.Metrics_asArray.forEach(function (metric) {
+ var metricEntry = new _voMetrics2['default']();
+ var isDynamic = dashManifestModel.getIsDynamic(manifest);
+
+ if (metric.hasOwnProperty('metrics')) {
+ metricEntry.metrics = metric.metrics;
+ } else {
+ //console.log("Invalid Metrics. metrics must be set. Ignoring.");
+ return;
+ }
+
+ if (metric.Range_asArray) {
+ metric.Range_asArray.forEach(function (range) {
+ var rangeEntry = new _voRange2['default']();
+
+ rangeEntry.starttime = getMetricsRangeStartTime(manifest, isDynamic, range);
+
+ if (range.hasOwnProperty('duration')) {
+ rangeEntry.duration = range.duration;
+ } else {
+ // if not present, the value is identical to the
+ // Media Presentation duration.
+ rangeEntry.duration = dashManifestModel.getDuration(manifest);
+ }
+
+ rangeEntry._useWallClockTime = isDynamic;
+
+ metricEntry.Range.push(rangeEntry);
+ });
+ }
+
+ if (metric.Reporting_asArray) {
+ metric.Reporting_asArray.forEach(function (reporting) {
+ var reportingEntry = new _voReporting2['default']();
+
+ if (reporting.hasOwnProperty('schemeIdUri')) {
+ reportingEntry.schemeIdUri = reporting.schemeIdUri;
+ } else {
+ // Invalid Reporting. schemeIdUri must be set. Ignore.
+ return;
+ }
+
+ for (var prop in reporting) {
+ if (reporting.hasOwnProperty(prop)) {
+ reportingEntry[prop] = reporting[prop];
+ }
+ }
+
+ metricEntry.Reporting.push(reportingEntry);
+ });
+ } else {
+ // Invalid Metrics. At least one reporting must be present. Ignore
+ return;
+ }
+
+ metrics.push(metricEntry);
+ });
+ }
+
+ return metrics;
+ }
+
+ instance = {
+ getMetrics: getMetrics
+ };
+
+ return instance;
+}
+
+ManifestParsing.__dashjs_factory_name = 'ManifestParsing';
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(ManifestParsing);
+module.exports = exports['default'];
+
+},{"10":10,"95":95,"96":96,"97":97}],92:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+function MetricSerialiser() {
+
+ // For each entry in the top level list within the metric (in the case
+ // of the DVBErrors metric each entry corresponds to an "error event"
+ // described in clause 10.8.4) the Player shall:
+ function serialise(metric) {
+ var pairs = [];
+ var obj = [];
+ var key, value;
+
+ // Take each (key, value) pair from the metric entry and create a
+ // string consisting of the name of the key, followed by an equals
+ // ('=') character, followed by the string representation of the
+ // value. The string representation of the value is created based
+ // on the type of the value following the instructions in Table 22.
+ for (key in metric) {
+ if (metric.hasOwnProperty(key) && key.indexOf('_') !== 0) {
+ value = metric[key];
+
+ // we want to ensure that keys still end up in the report
+ // even if there is no value
+ if (value === undefined || value === null) {
+ value = '';
+ }
+
+ // DVB A168 10.12.4 Table 22
+ if (Array.isArray(value)) {
+ // if trace or similar is null, do not include in output
+ if (!value.length) {
+ continue;
+ }
+
+ obj = [];
+
+ value.forEach(function (v) {
+ var isBuiltIn = Object.prototype.toString.call(v).slice(8, -1) !== 'Object';
+
+ obj.push(isBuiltIn ? v : serialise(v));
+ });
+
+ value = encodeURIComponent(obj.join(','));
+ } else if (typeof value === 'string') {
+ value = encodeURIComponent(value);
+ } else if (value instanceof Date) {
+ value = value.toISOString();
+ } else if (typeof value === 'number') {
+ value = Math.round(value);
+ }
+
+ pairs.push(key + '=' + value);
+ }
+ }
+
+ // Concatenate the strings created in the previous step with an
+ // ampersand ('&') character between each one.
+ return pairs.join('&');
+ }
+
+ return {
+ serialise: serialise
+ };
+}
+
+MetricSerialiser.__dashjs_factory_name = 'MetricSerialiser';
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(MetricSerialiser);
+module.exports = exports['default'];
+
+},{"10":10}],93:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+function RNG() {
+
+ // check whether secure random numbers are available. if not, revert to
+ // using Math.random
+ var crypto = window.crypto || window.msCrypto;
+
+ // could just as easily use any other array type by changing line below
+ var ArrayType = Uint32Array;
+ var MAX_VALUE = Math.pow(2, ArrayType.BYTES_PER_ELEMENT * 8) - 1;
+
+ // currently there is only one client for this code, and that only uses
+ // a single random number per initialisation. may want to increase this
+ // number if more consumers in the future
+ var NUM_RANDOM_NUMBERS = 10;
+
+ var randomNumbers = undefined,
+ index = undefined,
+ instance = undefined;
+
+ function initialise() {
+ if (crypto) {
+ if (!randomNumbers) {
+ randomNumbers = new ArrayType(NUM_RANDOM_NUMBERS);
+ }
+ crypto.getRandomValues(randomNumbers);
+ index = 0;
+ }
+ }
+
+ function rand(min, max) {
+ var r;
+
+ if (!min) {
+ min = 0;
+ }
+
+ if (!max) {
+ max = 1;
+ }
+
+ if (crypto) {
+ if (index === randomNumbers.length) {
+ initialise();
+ }
+
+ r = randomNumbers[index] / MAX_VALUE;
+ index += 1;
+ } else {
+ r = Math.random();
+ }
+
+ return r * (max - min) + min;
+ }
+
+ instance = {
+ random: rand
+ };
+
+ initialise();
+
+ return instance;
+}
+
+RNG.__dashjs_factory_name = 'RNG';
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(RNG);
+module.exports = exports['default'];
+
+},{"10":10}],94:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @class
+ * @ignore
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+
+var DVBErrors = function DVBErrors() {
+ _classCallCheck(this, DVBErrors);
+
+ this.mpdurl = null;
+ // String - Absolute URL from which the MPD was originally
+ // retrieved (MPD updates will not change this value).
+
+ this.errorcode = null;
+ // String - The value of errorcode depends upon the type
+ // of error being reported. For an error listed in the
+ // ErrorType column below the value is as described in the
+ // Value column.
+ //
+ // ErrorType Value
+ // --------- -----
+ // HTTP error status code HTTP status code
+ // Unknown HTTP status code HTTP status code
+ // SSL connection failed "SSL" followed by SSL alert value
+ // DNS resolution failed "C00"
+ // Host unreachable "C01"
+ // Connection refused "C02"
+ // Connection error – Not otherwise specified "C03"
+ // Corrupt media – ISO BMFF container cannot be parsed "M00"
+ // Corrupt media – Not otherwise specified "M01"
+ // Changing Base URL in use due to errors "F00"
+ // Becoming an error reporting Player "S00"
+
+ this.terror = null;
+ // Real-Time - Date and time at which error occurred in UTC,
+ // formatted as a combined date and time according to ISO 8601.
+
+ this.url = null;
+ // String - Absolute URL from which data was being requested
+ // when this error occurred. If the error report is in relation
+ // to corrupt media or changing BaseURL, this may be a null
+ // string if the URL from which the media was obtained or
+ // which led to the change of BaseURL is no longer known.
+
+ this.ipaddress = null;
+ // String - IP Address which the host name in "url" resolved to.
+ // If the error report is in relation to corrupt media or
+ // changing BaseURL, this may be a null string if the URL
+ // from which the media was obtained or which led to the
+ // change of BaseURL is no longer known.
+
+ this.servicelocation = null;
+ // String - The value of the serviceLocation field in the
+ // BaseURL being used. In the event of this report indicating
+ // a change of BaseURL this is the value from the BaseURL
+ // being moved from.
+};
+
+DVBErrors.SSL_CONNECTION_FAILED_PREFIX = 'SSL';
+DVBErrors.DNS_RESOLUTION_FAILED = 'C00';
+DVBErrors.HOST_UNREACHABLE = 'C01';
+DVBErrors.CONNECTION_REFUSED = 'C02';
+DVBErrors.CONNECTION_ERROR = 'C03';
+DVBErrors.CORRUPT_MEDIA_ISOBMFF = 'M00';
+DVBErrors.CORRUPT_MEDIA_OTHER = 'M01';
+DVBErrors.BASE_URL_CHANGED = 'F00';
+DVBErrors.BECAME_REPORTER = 'S00';
+
+exports['default'] = DVBErrors;
+module.exports = exports['default'];
+
+},{}],95:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @class
+ * @ignore
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+
+var Metrics = function Metrics() {
+ _classCallCheck(this, Metrics);
+
+ this.metrics = '';
+ this.Range = [];
+ this.Reporting = [];
+};
+
+exports['default'] = Metrics;
+module.exports = exports['default'];
+
+},{}],96:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @class
+ * @ignore
+ */
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var Range = function Range() {
+ _classCallCheck(this, Range);
+
+ // as defined in ISO23009-1
+ this.starttime = 0;
+ this.duration = Infinity;
+
+ // for internal use
+ this._useWallClockTime = false;
+};
+
+exports["default"] = Range;
+module.exports = exports["default"];
+
+},{}],97:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @class
+ * @ignore
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+
+var Reporting = function Reporting() {
+ _classCallCheck(this, Reporting);
+
+ // Reporting is a DescriptorType and doesn't have any additional fields
+ this.schemeIdUri = '';
+ this.value = '';
+};
+
+exports['default'] = Reporting;
+module.exports = exports['default'];
+
+},{}],98:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+
+var _dashModelsDashManifestModel = _dereq_(22);
+
+var _dashModelsDashManifestModel2 = _interopRequireDefault(_dashModelsDashManifestModel);
+
+var _utilsObjectUtils = _dereq_(155);
+
+var _utilsObjectUtils2 = _interopRequireDefault(_utilsObjectUtils);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var DEFAULT_INDEX = NaN;
+
+var Node = function Node(_baseUrls, _selectedIdx) {
+ _classCallCheck(this, Node);
+
+ this.data = {
+ baseUrls: _baseUrls || null,
+ selectedIdx: _selectedIdx || DEFAULT_INDEX
+ };
+ this.children = [];
+};
+
+function BaseURLTreeModel() {
+
+ var instance = undefined;
+ var root = undefined;
+
+ var context = this.context;
+ var dashManifestModel = (0, _dashModelsDashManifestModel2['default'])(context).getInstance();
+ var objectUtils = (0, _utilsObjectUtils2['default'])(context).getInstance();
+
+ function setup() {
+ root = new Node();
+ }
+
+ function updateChildData(node, index, element) {
+ var baseUrls = dashManifestModel.getBaseURLsFromElement(element);
+
+ if (!node[index]) {
+ node[index] = new Node(baseUrls);
+ } else {
+ if (!objectUtils.areSimpleEquivalent(baseUrls, node[index].data.baseUrls)) {
+ node[index].data.baseUrls = baseUrls;
+ node[index].data.selectedIdx = DEFAULT_INDEX;
+ }
+ }
+ }
+
+ function getBaseURLCollectionsFromManifest(manifest) {
+ var baseUrls = dashManifestModel.getBaseURLsFromElement(manifest);
+
+ if (!objectUtils.areSimpleEquivalent(baseUrls, root.data.baseUrls)) {
+ root.data.baseUrls = baseUrls;
+ root.data.selectedIdx = DEFAULT_INDEX;
+ }
+
+ if (manifest.Period_asArray) {
+ manifest.Period_asArray.forEach(function (p, pi) {
+ updateChildData(root.children, pi, p);
+
+ if (p.AdaptationSet_asArray) {
+ p.AdaptationSet_asArray.forEach(function (a, ai) {
+ updateChildData(root.children[pi].children, ai, a);
+
+ if (a.Representation_asArray) {
+ a.Representation_asArray.sort(dashManifestModel.getRepresentationSortFunction()).forEach(function (r, ri) {
+ updateChildData(root.children[pi].children[ai].children, ri, r);
+ });
+ }
+ });
+ }
+ });
+ }
+ }
+
+ function walk(callback, node) {
+ var target = node || root;
+
+ callback(target.data);
+
+ if (target.children) {
+ target.children.forEach(function (child) {
+ return walk(callback, child);
+ });
+ }
+ }
+
+ function invalidateSelectedIndexes(serviceLocation) {
+ walk(function (data) {
+ if (!isNaN(data.selectedIdx)) {
+ if (serviceLocation === data.baseUrls[data.selectedIdx].serviceLocation) {
+ data.selectedIdx = DEFAULT_INDEX;
+ }
+ }
+ });
+ }
+
+ function update(manifest) {
+ getBaseURLCollectionsFromManifest(manifest);
+ }
+
+ function reset() {
+ root = new Node();
+ }
+
+ function getForPath(path) {
+ var target = root;
+ var nodes = [target.data];
+
+ path.forEach(function (p) {
+ target = target.children[p];
+
+ if (target) {
+ nodes.push(target.data);
+ }
+ });
+
+ return nodes.filter(function (n) {
+ return n.baseUrls.length;
+ });
+ }
+
+ instance = {
+ reset: reset,
+ update: update,
+ getForPath: getForPath,
+ invalidateSelectedIndexes: invalidateSelectedIndexes
+ };
+
+ setup();
+
+ return instance;
+}
+
+BaseURLTreeModel.__dashjs_factory_name = 'BaseURLTreeModel';
+exports['default'] = _coreFactoryMaker2['default'].getClassFactory(BaseURLTreeModel);
+module.exports = exports['default'];
+
+},{"10":10,"155":155,"22":22}],99:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreEventBus = _dereq_(9);
+
+var _coreEventBus2 = _interopRequireDefault(_coreEventBus);
+
+var _coreEventsEvents = _dereq_(13);
+
+var _coreEventsEvents2 = _interopRequireDefault(_coreEventsEvents);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _voFragmentRequest = _dereq_(163);
+
+var _voFragmentRequest2 = _interopRequireDefault(_voFragmentRequest);
+
+var _coreDebug = _dereq_(8);
+
+var _coreDebug2 = _interopRequireDefault(_coreDebug);
+
+var FRAGMENT_MODEL_LOADING = 'loading';
+var FRAGMENT_MODEL_EXECUTED = 'executed';
+var FRAGMENT_MODEL_CANCELED = 'canceled';
+var FRAGMENT_MODEL_FAILED = 'failed';
+
+function FragmentModel(config) {
+
+ var context = this.context;
+ var log = (0, _coreDebug2['default'])(context).getInstance().log;
+ var eventBus = (0, _coreEventBus2['default'])(context).getInstance();
+ var metricsModel = config.metricsModel;
+
+ var instance = undefined,
+ scheduleController = undefined,
+ executedRequests = undefined,
+ loadingRequests = undefined,
+ fragmentLoader = undefined;
+
+ function setup() {
+ scheduleController = null;
+ fragmentLoader = null;
+ executedRequests = [];
+ loadingRequests = [];
+ eventBus.on(_coreEventsEvents2['default'].LOADING_COMPLETED, onLoadingCompleted, instance);
+ }
+
+ function setLoader(value) {
+ fragmentLoader = value;
+ }
+
+ function setScheduleController(value) {
+ scheduleController = value;
+ }
+
+ function getScheduleController() {
+ return scheduleController;
+ }
+
+ function isFragmentLoaded(request) {
+ var isEqualComplete = function isEqualComplete(req1, req2) {
+ return req1.action === _voFragmentRequest2['default'].ACTION_COMPLETE && req1.action === req2.action;
+ };
+
+ var isEqualMedia = function isEqualMedia(req1, req2) {
+ return !isNaN(req1.index) && req1.startTime === req2.startTime && req1.adaptationIndex === req2.adaptationIndex;
+ };
+
+ var isEqualInit = function isEqualInit(req1, req2) {
+ return isNaN(req1.index) && isNaN(req2.index) && req1.quality === req2.quality;
+ };
+
+ var check = function check(requests) {
+ var isLoaded = false;
+ requests.some(function (req) {
+ if (isEqualMedia(request, req) || isEqualInit(request, req) || isEqualComplete(request, req)) {
+ isLoaded = true;
+ return isLoaded;
+ }
+ });
+ return isLoaded;
+ };
+
+ return check(executedRequests);
+ }
+
+ /**
+ *
+ * Gets an array of {@link FragmentRequest} objects
+ *
+ * @param {Object} filter The object with properties by which the method filters the requests to be returned.
+ * the only mandatory property is state, which must be a value from
+ * other properties should match the properties of {@link FragmentRequest}. E.g.:
+ * getRequests({state: FragmentModel.FRAGMENT_MODEL_EXECUTED, quality: 0}) - returns
+ * all the requests from executedRequests array where requests.quality = filter.quality
+ *
+ * @returns {Array}
+ * @memberof FragmentModel#
+ */
+ function getRequests(filter) {
+
+ var states = filter.state instanceof Array ? filter.state : [filter.state];
+
+ var filteredRequests = [];
+ states.forEach(function (state) {
+ var requests = getRequestsForState(state);
+ filteredRequests = filteredRequests.concat(filterRequests(requests, filter));
+ });
+
+ return filteredRequests;
+ }
+
+ function removeExecutedRequestsBeforeTime(time) {
+ executedRequests = executedRequests.filter(function (req) {
+ return isNaN(req.startTime) || req.startTime >= time;
+ });
+ }
+
+ function abortRequests() {
+ fragmentLoader.abort();
+ loadingRequests = [];
+ }
+
+ function executeRequest(request) {
+
+ switch (request.action) {
+ case _voFragmentRequest2['default'].ACTION_COMPLETE:
+ executedRequests.push(request);
+ addSchedulingInfoMetrics(request, FRAGMENT_MODEL_EXECUTED);
+ eventBus.trigger(_coreEventsEvents2['default'].STREAM_COMPLETED, { request: request, fragmentModel: this });
+ break;
+ case _voFragmentRequest2['default'].ACTION_DOWNLOAD:
+ addSchedulingInfoMetrics(request, FRAGMENT_MODEL_LOADING);
+ loadingRequests.push(request);
+ loadCurrentFragment(request);
+ break;
+ default:
+ log('Unknown request action.');
+ }
+ }
+
+ function loadCurrentFragment(request) {
+ eventBus.trigger(_coreEventsEvents2['default'].FRAGMENT_LOADING_STARTED, { sender: instance, request: request });
+ fragmentLoader.load(request);
+ }
+
+ function getRequestForTime(arr, time, threshold) {
+ // loop through the executed requests and pick the one for which the playback interval matches the given time
+ var lastIdx = arr.length - 1;
+ for (var i = lastIdx; i >= 0; i--) {
+ var req = arr[i];
+ var start = req.startTime;
+ var end = start + req.duration;
+ threshold = threshold !== undefined ? threshold : req.duration / 2;
+ if (!isNaN(start) && !isNaN(end) && time + threshold >= start && time - threshold < end || isNaN(start) && isNaN(time)) {
+ return req;
+ }
+ }
+ return null;
+ }
+
+ function filterRequests(arr, filter) {
+ // for time use a specific filtration function
+ if (filter.hasOwnProperty('time')) {
+ return [getRequestForTime(arr, filter.time, filter.threshold)];
+ }
+
+ return arr.filter(function (request) {
+ for (var prop in filter) {
+ if (prop === 'state') continue;
+ if (filter.hasOwnProperty(prop) && request[prop] != filter[prop]) return false;
+ }
+
+ return true;
+ });
+ }
+
+ function getRequestsForState(state) {
+
+ var requests = undefined;
+ switch (state) {
+ case FRAGMENT_MODEL_LOADING:
+ requests = loadingRequests;
+ break;
+ case FRAGMENT_MODEL_EXECUTED:
+ requests = executedRequests;
+ break;
+ default:
+ requests = [];
+ }
+ return requests;
+ }
+
+ function addSchedulingInfoMetrics(request, state) {
+
+ metricsModel.addSchedulingInfo(request.mediaType, new Date(), request.type, request.startTime, request.availabilityStartTime, request.duration, request.quality, request.range, state);
+
+ metricsModel.addRequestsQueue(request.mediaType, loadingRequests, executedRequests);
+ }
+
+ function onLoadingCompleted(e) {
+ if (e.sender !== fragmentLoader) return;
+
+ loadingRequests.splice(loadingRequests.indexOf(e.request), 1);
+
+ if (e.response && !e.error) {
+ executedRequests.push(e.request);
+ }
+
+ addSchedulingInfoMetrics(e.request, e.error ? FRAGMENT_MODEL_FAILED : FRAGMENT_MODEL_EXECUTED);
+
+ eventBus.trigger(_coreEventsEvents2['default'].FRAGMENT_LOADING_COMPLETED, {
+ request: e.request,
+ response: e.response,
+ error: e.error,
+ sender: this
+ });
+ }
+
+ function reset() {
+ eventBus.off(_coreEventsEvents2['default'].LOADING_COMPLETED, onLoadingCompleted, this);
+
+ if (fragmentLoader) {
+ fragmentLoader.reset();
+ fragmentLoader = null;
+ }
+
+ executedRequests = [];
+ loadingRequests = [];
+ }
+
+ instance = {
+ setLoader: setLoader,
+ setScheduleController: setScheduleController,
+ getScheduleController: getScheduleController,
+ getRequests: getRequests,
+ isFragmentLoaded: isFragmentLoaded,
+ removeExecutedRequestsBeforeTime: removeExecutedRequestsBeforeTime,
+ abortRequests: abortRequests,
+ executeRequest: executeRequest,
+ reset: reset
+ };
+
+ setup();
+ return instance;
+}
+
+FragmentModel.__dashjs_factory_name = 'FragmentModel';
+var factory = _coreFactoryMaker2['default'].getClassFactory(FragmentModel);
+factory.FRAGMENT_MODEL_LOADING = FRAGMENT_MODEL_LOADING;
+factory.FRAGMENT_MODEL_EXECUTED = FRAGMENT_MODEL_EXECUTED;
+factory.FRAGMENT_MODEL_CANCELED = FRAGMENT_MODEL_CANCELED;
+factory.FRAGMENT_MODEL_FAILED = FRAGMENT_MODEL_FAILED;
+exports['default'] = factory;
+module.exports = exports['default'];
+
+},{"10":10,"13":13,"163":163,"8":8,"9":9}],100:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreEventBus = _dereq_(9);
+
+var _coreEventBus2 = _interopRequireDefault(_coreEventBus);
+
+var _coreEventsEvents = _dereq_(13);
+
+var _coreEventsEvents2 = _interopRequireDefault(_coreEventsEvents);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+function ManifestModel() {
+
+ var context = this.context;
+ var eventBus = (0, _coreEventBus2['default'])(context).getInstance();
+
+ var instance = undefined,
+ manifest = undefined;
+
+ function getValue() {
+ return manifest;
+ }
+
+ function setValue(value) {
+ manifest = value;
+ if (value) {
+ eventBus.trigger(_coreEventsEvents2['default'].MANIFEST_LOADED, { data: value });
+ }
+ }
+
+ instance = {
+ getValue: getValue,
+ setValue: setValue
+ };
+
+ return instance;
+}
+
+ManifestModel.__dashjs_factory_name = 'ManifestModel';
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(ManifestModel);
+module.exports = exports['default'];
+
+},{"10":10,"13":13,"9":9}],101:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _voMetricsHTTPRequest = _dereq_(179);
+
+var DEFAULT_UTC_TIMING_SOURCE = { scheme: 'urn:mpeg:dash:utc:http-xsdate:2014', value: 'http://time.akamai.com/?iso' };
+var LIVE_DELAY_FRAGMENT_COUNT = 4;
+
+var DEFAULT_LOCAL_STORAGE_BITRATE_EXPIRATION = 360000;
+var DEFAULT_LOCAL_STORAGE_MEDIA_SETTINGS_EXPIRATION = 360000;
+
+var BANDWIDTH_SAFETY_FACTOR = 0.9;
+var ABANDON_LOAD_TIMEOUT = 10000;
+
+var BUFFER_TO_KEEP = 30;
+var BUFFER_PRUNING_INTERVAL = 30;
+var DEFAULT_MIN_BUFFER_TIME = 12;
+var DEFAULT_MIN_BUFFER_TIME_FAST_SWITCH = 20;
+var BUFFER_TIME_AT_TOP_QUALITY = 30;
+var BUFFER_TIME_AT_TOP_QUALITY_LONG_FORM = 60;
+var LONG_FORM_CONTENT_DURATION_THRESHOLD = 600;
+var RICH_BUFFER_THRESHOLD = 20;
+
+var FRAGMENT_RETRY_ATTEMPTS = 3;
+var FRAGMENT_RETRY_INTERVAL = 1000;
+
+var MANIFEST_RETRY_ATTEMPTS = 3;
+var MANIFEST_RETRY_INTERVAL = 500;
+
+var XLINK_RETRY_ATTEMPTS = 1;
+var XLINK_RETRY_INTERVAL = 500;
+
+//This value influences the startup time for live (in ms).
+var WALLCLOCK_TIME_UPDATE_INTERVAL = 50;
+
+var DEFAULT_XHR_WITH_CREDENTIALS = false;
+
+function MediaPlayerModel() {
+
+ var instance = undefined,
+ useManifestDateHeaderTimeSource = undefined,
+ useSuggestedPresentationDelay = undefined,
+ UTCTimingSources = undefined,
+ liveDelayFragmentCount = undefined,
+ liveDelay = undefined,
+ scheduleWhilePaused = undefined,
+ bufferToKeep = undefined,
+ bufferPruningInterval = undefined,
+ lastBitrateCachingInfo = undefined,
+ lastMediaSettingsCachingInfo = undefined,
+ stableBufferTime = undefined,
+ bufferTimeAtTopQuality = undefined,
+ bufferTimeAtTopQualityLongForm = undefined,
+ longFormContentDurationThreshold = undefined,
+ richBufferThreshold = undefined,
+ bandwidthSafetyFactor = undefined,
+ abandonLoadTimeout = undefined,
+ retryAttempts = undefined,
+ retryIntervals = undefined,
+ wallclockTimeUpdateInterval = undefined,
+ bufferOccupancyABREnabled = undefined,
+ xhrWithCredentials = undefined,
+ fastSwitchEnabled = undefined;
+
+ function setup() {
+ var _retryAttempts, _retryIntervals;
+
+ UTCTimingSources = [];
+ useSuggestedPresentationDelay = false;
+ useManifestDateHeaderTimeSource = true;
+ scheduleWhilePaused = true;
+ bufferOccupancyABREnabled = false;
+ fastSwitchEnabled = false;
+ lastBitrateCachingInfo = { enabled: true, ttl: DEFAULT_LOCAL_STORAGE_BITRATE_EXPIRATION };
+ lastMediaSettingsCachingInfo = { enabled: true, ttl: DEFAULT_LOCAL_STORAGE_MEDIA_SETTINGS_EXPIRATION };
+ liveDelayFragmentCount = LIVE_DELAY_FRAGMENT_COUNT;
+ liveDelay = undefined; // Explicitly state that default is undefined
+ bufferToKeep = BUFFER_TO_KEEP;
+ bufferPruningInterval = BUFFER_PRUNING_INTERVAL;
+ stableBufferTime = NaN;
+ bufferTimeAtTopQuality = BUFFER_TIME_AT_TOP_QUALITY;
+ bufferTimeAtTopQualityLongForm = BUFFER_TIME_AT_TOP_QUALITY_LONG_FORM;
+ longFormContentDurationThreshold = LONG_FORM_CONTENT_DURATION_THRESHOLD;
+ richBufferThreshold = RICH_BUFFER_THRESHOLD;
+ bandwidthSafetyFactor = BANDWIDTH_SAFETY_FACTOR;
+ abandonLoadTimeout = ABANDON_LOAD_TIMEOUT;
+ wallclockTimeUpdateInterval = WALLCLOCK_TIME_UPDATE_INTERVAL;
+ xhrWithCredentials = DEFAULT_XHR_WITH_CREDENTIALS;
+
+ retryAttempts = (_retryAttempts = {}, _defineProperty(_retryAttempts, _voMetricsHTTPRequest.HTTPRequest.MPD_TYPE, MANIFEST_RETRY_ATTEMPTS), _defineProperty(_retryAttempts, _voMetricsHTTPRequest.HTTPRequest.XLINK_EXPANSION_TYPE, XLINK_RETRY_ATTEMPTS), _defineProperty(_retryAttempts, _voMetricsHTTPRequest.HTTPRequest.MEDIA_SEGMENT_TYPE, FRAGMENT_RETRY_ATTEMPTS), _defineProperty(_retryAttempts, _voMetricsHTTPRequest.HTTPRequest.INIT_SEGMENT_TYPE, FRAGMENT_RETRY_ATTEMPTS), _defineProperty(_retryAttempts, _voMetricsHTTPRequest.HTTPRequest.BITSTREAM_SWITCHING_SEGMENT_TYPE, FRAGMENT_RETRY_ATTEMPTS), _defineProperty(_retryAttempts, _voMetricsHTTPRequest.HTTPRequest.INDEX_SEGMENT_TYPE, FRAGMENT_RETRY_ATTEMPTS), _defineProperty(_retryAttempts, _voMetricsHTTPRequest.HTTPRequest.OTHER_TYPE, FRAGMENT_RETRY_ATTEMPTS), _retryAttempts);
+
+ retryIntervals = (_retryIntervals = {}, _defineProperty(_retryIntervals, _voMetricsHTTPRequest.HTTPRequest.MPD_TYPE, MANIFEST_RETRY_INTERVAL), _defineProperty(_retryIntervals, _voMetricsHTTPRequest.HTTPRequest.XLINK_EXPANSION_TYPE, XLINK_RETRY_INTERVAL), _defineProperty(_retryIntervals, _voMetricsHTTPRequest.HTTPRequest.MEDIA_SEGMENT_TYPE, FRAGMENT_RETRY_INTERVAL), _defineProperty(_retryIntervals, _voMetricsHTTPRequest.HTTPRequest.INIT_SEGMENT_TYPE, FRAGMENT_RETRY_INTERVAL), _defineProperty(_retryIntervals, _voMetricsHTTPRequest.HTTPRequest.BITSTREAM_SWITCHING_SEGMENT_TYPE, FRAGMENT_RETRY_INTERVAL), _defineProperty(_retryIntervals, _voMetricsHTTPRequest.HTTPRequest.INDEX_SEGMENT_TYPE, FRAGMENT_RETRY_INTERVAL), _defineProperty(_retryIntervals, _voMetricsHTTPRequest.HTTPRequest.OTHER_TYPE, FRAGMENT_RETRY_INTERVAL), _retryIntervals);
+ }
+
+ //TODO Should we use Object.define to have setters/getters? makes more readable code on other side.
+ function setBufferOccupancyABREnabled(value) {
+ bufferOccupancyABREnabled = value;
+ }
+
+ function getBufferOccupancyABREnabled() {
+ return bufferOccupancyABREnabled;
+ }
+
+ function setBandwidthSafetyFactor(value) {
+ bandwidthSafetyFactor = value;
+ }
+
+ function getBandwidthSafetyFactor() {
+ return bandwidthSafetyFactor;
+ }
+
+ function setAbandonLoadTimeout(value) {
+ abandonLoadTimeout = value;
+ }
+
+ function getAbandonLoadTimeout() {
+ return abandonLoadTimeout;
+ }
+
+ function setStableBufferTime(value) {
+ stableBufferTime = value;
+ }
+
+ function getStableBufferTime() {
+ return !isNaN(stableBufferTime) ? stableBufferTime : fastSwitchEnabled ? DEFAULT_MIN_BUFFER_TIME_FAST_SWITCH : DEFAULT_MIN_BUFFER_TIME;
+ }
+
+ function setBufferTimeAtTopQuality(value) {
+ bufferTimeAtTopQuality = value;
+ }
+
+ function getBufferTimeAtTopQuality() {
+ return bufferTimeAtTopQuality;
+ }
+
+ function setBufferTimeAtTopQualityLongForm(value) {
+ bufferTimeAtTopQualityLongForm = value;
+ }
+
+ function getBufferTimeAtTopQualityLongForm() {
+ return bufferTimeAtTopQualityLongForm;
+ }
+
+ function setLongFormContentDurationThreshold(value) {
+ longFormContentDurationThreshold = value;
+ }
+
+ function getLongFormContentDurationThreshold() {
+ return longFormContentDurationThreshold;
+ }
+
+ function setRichBufferThreshold(value) {
+ richBufferThreshold = value;
+ }
+
+ function getRichBufferThreshold() {
+ return richBufferThreshold;
+ }
+
+ function setBufferToKeep(value) {
+ bufferToKeep = value;
+ }
+
+ function getBufferToKeep() {
+ return bufferToKeep;
+ }
+
+ function setLastBitrateCachingInfo(enable, ttl) {
+ lastBitrateCachingInfo.enabled = enable;
+ if (ttl !== undefined && !isNaN(ttl) && typeof ttl === 'number') {
+ lastBitrateCachingInfo.ttl = ttl;
+ }
+ }
+
+ function getLastBitrateCachingInfo() {
+ return lastBitrateCachingInfo;
+ }
+
+ function setLastMediaSettingsCachingInfo(enable, ttl) {
+ lastMediaSettingsCachingInfo.enabled = enable;
+ if (ttl !== undefined && !isNaN(ttl) && typeof ttl === 'number') {
+ lastMediaSettingsCachingInfo.ttl = ttl;
+ }
+ }
+
+ function getLastMediaSettingsCachingInfo() {
+ return lastMediaSettingsCachingInfo;
+ }
+
+ function setBufferPruningInterval(value) {
+ bufferPruningInterval = value;
+ }
+
+ function getBufferPruningInterval() {
+ return bufferPruningInterval;
+ }
+
+ function setFragmentRetryAttempts(value) {
+ retryAttempts[_voMetricsHTTPRequest.HTTPRequest.MEDIA_SEGMENT_TYPE] = value;
+ }
+
+ function setRetryAttemptsForType(type, value) {
+ retryAttempts[type] = value;
+ }
+
+ function getFragmentRetryAttempts() {
+ return retryAttempts[_voMetricsHTTPRequest.HTTPRequest.MEDIA_SEGMENT_TYPE];
+ }
+
+ function getRetryAttemptsForType(type) {
+ return retryAttempts[type];
+ }
+
+ function setFragmentRetryInterval(value) {
+ retryIntervals[_voMetricsHTTPRequest.HTTPRequest.MEDIA_SEGMENT_TYPE] = value;
+ }
+
+ function setRetryIntervalForType(type, value) {
+ retryIntervals[type] = value;
+ }
+
+ function getFragmentRetryInterval() {
+ return retryIntervals[_voMetricsHTTPRequest.HTTPRequest.MEDIA_SEGMENT_TYPE];
+ }
+
+ function getRetryIntervalForType(type) {
+ return retryIntervals[type];
+ }
+
+ function setWallclockTimeUpdateInterval(value) {
+ wallclockTimeUpdateInterval = value;
+ }
+
+ function getWallclockTimeUpdateInterval() {
+ return wallclockTimeUpdateInterval;
+ }
+
+ function setScheduleWhilePaused(value) {
+ scheduleWhilePaused = value;
+ }
+
+ function getScheduleWhilePaused() {
+ return scheduleWhilePaused;
+ }
+
+ function setLiveDelayFragmentCount(value) {
+ liveDelayFragmentCount = value;
+ }
+
+ function setLiveDelay(value) {
+ liveDelay = value;
+ }
+
+ function getLiveDelayFragmentCount() {
+ return liveDelayFragmentCount;
+ }
+
+ function getLiveDelay() {
+ return liveDelay;
+ }
+
+ function setUseManifestDateHeaderTimeSource(value) {
+ useManifestDateHeaderTimeSource = value;
+ }
+
+ function getUseManifestDateHeaderTimeSource() {
+ return useManifestDateHeaderTimeSource;
+ }
+
+ function setUseSuggestedPresentationDelay(value) {
+ useSuggestedPresentationDelay = value;
+ }
+
+ function getUseSuggestedPresentationDelay() {
+ return useSuggestedPresentationDelay;
+ }
+
+ function setUTCTimingSources(value) {
+ UTCTimingSources = value;
+ }
+
+ function getUTCTimingSources() {
+ return UTCTimingSources;
+ }
+
+ function setXHRWithCredentials(value) {
+ xhrWithCredentials = !!value;
+ }
+
+ function getXHRWithCredentials() {
+ return xhrWithCredentials;
+ }
+
+ function getFastSwitchEnabled() {
+ return fastSwitchEnabled;
+ }
+
+ function setFastSwitchEnabled(value) {
+ fastSwitchEnabled = value;
+ }
+
+ function reset() {
+ //TODO need to figure out what props to persist across sessions and which to reset if any.
+ //setup();
+ }
+
+ instance = {
+ setBufferOccupancyABREnabled: setBufferOccupancyABREnabled,
+ getBufferOccupancyABREnabled: getBufferOccupancyABREnabled,
+ setBandwidthSafetyFactor: setBandwidthSafetyFactor,
+ getBandwidthSafetyFactor: getBandwidthSafetyFactor,
+ setAbandonLoadTimeout: setAbandonLoadTimeout,
+ getAbandonLoadTimeout: getAbandonLoadTimeout,
+ setLastBitrateCachingInfo: setLastBitrateCachingInfo,
+ getLastBitrateCachingInfo: getLastBitrateCachingInfo,
+ setLastMediaSettingsCachingInfo: setLastMediaSettingsCachingInfo,
+ getLastMediaSettingsCachingInfo: getLastMediaSettingsCachingInfo,
+ setStableBufferTime: setStableBufferTime,
+ getStableBufferTime: getStableBufferTime,
+ setBufferTimeAtTopQuality: setBufferTimeAtTopQuality,
+ getBufferTimeAtTopQuality: getBufferTimeAtTopQuality,
+ setBufferTimeAtTopQualityLongForm: setBufferTimeAtTopQualityLongForm,
+ getBufferTimeAtTopQualityLongForm: getBufferTimeAtTopQualityLongForm,
+ setLongFormContentDurationThreshold: setLongFormContentDurationThreshold,
+ getLongFormContentDurationThreshold: getLongFormContentDurationThreshold,
+ setRichBufferThreshold: setRichBufferThreshold,
+ getRichBufferThreshold: getRichBufferThreshold,
+ setBufferToKeep: setBufferToKeep,
+ getBufferToKeep: getBufferToKeep,
+ setBufferPruningInterval: setBufferPruningInterval,
+ getBufferPruningInterval: getBufferPruningInterval,
+ setFragmentRetryAttempts: setFragmentRetryAttempts,
+ getFragmentRetryAttempts: getFragmentRetryAttempts,
+ setRetryAttemptsForType: setRetryAttemptsForType,
+ getRetryAttemptsForType: getRetryAttemptsForType,
+ setFragmentRetryInterval: setFragmentRetryInterval,
+ getFragmentRetryInterval: getFragmentRetryInterval,
+ setRetryIntervalForType: setRetryIntervalForType,
+ getRetryIntervalForType: getRetryIntervalForType,
+ setWallclockTimeUpdateInterval: setWallclockTimeUpdateInterval,
+ getWallclockTimeUpdateInterval: getWallclockTimeUpdateInterval,
+ setScheduleWhilePaused: setScheduleWhilePaused,
+ getScheduleWhilePaused: getScheduleWhilePaused,
+ getUseSuggestedPresentationDelay: getUseSuggestedPresentationDelay,
+ setUseSuggestedPresentationDelay: setUseSuggestedPresentationDelay,
+ setLiveDelayFragmentCount: setLiveDelayFragmentCount,
+ getLiveDelayFragmentCount: getLiveDelayFragmentCount,
+ getLiveDelay: getLiveDelay,
+ setLiveDelay: setLiveDelay,
+ setUseManifestDateHeaderTimeSource: setUseManifestDateHeaderTimeSource,
+ getUseManifestDateHeaderTimeSource: getUseManifestDateHeaderTimeSource,
+ setUTCTimingSources: setUTCTimingSources,
+ getUTCTimingSources: getUTCTimingSources,
+ setXHRWithCredentials: setXHRWithCredentials,
+ getXHRWithCredentials: getXHRWithCredentials,
+ setFastSwitchEnabled: setFastSwitchEnabled,
+ getFastSwitchEnabled: getFastSwitchEnabled,
+ reset: reset
+ };
+
+ setup();
+
+ return instance;
+}
+
+//TODO see if you can move this and not export and just getter to get default value.
+MediaPlayerModel.__dashjs_factory_name = 'MediaPlayerModel';
+var factory = _coreFactoryMaker2['default'].getSingletonFactory(MediaPlayerModel);
+factory.DEFAULT_UTC_TIMING_SOURCE = DEFAULT_UTC_TIMING_SOURCE;
+exports['default'] = factory;
+module.exports = exports['default'];
+
+},{"10":10,"179":179}],102:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _voMetricsList = _dereq_(168);
+
+var _voMetricsList2 = _interopRequireDefault(_voMetricsList);
+
+var _voMetricsTCPConnection = _dereq_(185);
+
+var _voMetricsTCPConnection2 = _interopRequireDefault(_voMetricsTCPConnection);
+
+var _voMetricsHTTPRequest = _dereq_(179);
+
+var _voMetricsRepresentationSwitch = _dereq_(182);
+
+var _voMetricsRepresentationSwitch2 = _interopRequireDefault(_voMetricsRepresentationSwitch);
+
+var _voMetricsBufferLevel = _dereq_(175);
+
+var _voMetricsBufferLevel2 = _interopRequireDefault(_voMetricsBufferLevel);
+
+var _voMetricsBufferState = _dereq_(176);
+
+var _voMetricsBufferState2 = _interopRequireDefault(_voMetricsBufferState);
+
+var _voMetricsDVRInfo = _dereq_(177);
+
+var _voMetricsDVRInfo2 = _interopRequireDefault(_voMetricsDVRInfo);
+
+var _voMetricsDroppedFrames = _dereq_(178);
+
+var _voMetricsDroppedFrames2 = _interopRequireDefault(_voMetricsDroppedFrames);
+
+var _voMetricsManifestUpdate = _dereq_(180);
+
+var _voMetricsSchedulingInfo = _dereq_(184);
+
+var _voMetricsSchedulingInfo2 = _interopRequireDefault(_voMetricsSchedulingInfo);
+
+var _coreEventBus = _dereq_(9);
+
+var _coreEventBus2 = _interopRequireDefault(_coreEventBus);
+
+var _voMetricsRequestsQueue = _dereq_(183);
+
+var _voMetricsRequestsQueue2 = _interopRequireDefault(_voMetricsRequestsQueue);
+
+var _coreEventsEvents = _dereq_(13);
+
+var _coreEventsEvents2 = _interopRequireDefault(_coreEventsEvents);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _voMetricsBolaState = _dereq_(174);
+
+var _voMetricsBolaState2 = _interopRequireDefault(_voMetricsBolaState);
+
+function MetricsModel() {
+
+ var context = this.context;
+ var eventBus = (0, _coreEventBus2['default'])(context).getInstance();
+
+ var instance = undefined,
+ adapter = undefined,
+ streamMetrics = undefined;
+
+ function setup() {
+ streamMetrics = {};
+ }
+
+ function setConfig(config) {
+ if (!config) return;
+
+ if (config.adapter) {
+ adapter = config.adapter;
+ }
+ }
+
+ function metricsChanged() {
+ eventBus.trigger(_coreEventsEvents2['default'].METRICS_CHANGED);
+ }
+
+ function metricChanged(mediaType) {
+ eventBus.trigger(_coreEventsEvents2['default'].METRIC_CHANGED, { mediaType: mediaType });
+ metricsChanged();
+ }
+
+ function metricUpdated(mediaType, metricType, vo) {
+ eventBus.trigger(_coreEventsEvents2['default'].METRIC_UPDATED, { mediaType: mediaType, metric: metricType, value: vo });
+ metricChanged(mediaType);
+ }
+
+ function metricAdded(mediaType, metricType, vo) {
+ eventBus.trigger(_coreEventsEvents2['default'].METRIC_ADDED, { mediaType: mediaType, metric: metricType, value: vo });
+ metricChanged(mediaType);
+ }
+
+ function clearCurrentMetricsForType(type) {
+ delete streamMetrics[type];
+ metricChanged(type);
+ }
+
+ function clearAllCurrentMetrics() {
+ streamMetrics = {};
+ metricsChanged();
+ }
+
+ function getReadOnlyMetricsFor(type) {
+ if (streamMetrics.hasOwnProperty(type)) {
+ return streamMetrics[type];
+ }
+
+ return null;
+ }
+
+ function getMetricsFor(type) {
+ var metrics;
+
+ if (streamMetrics.hasOwnProperty(type)) {
+ metrics = streamMetrics[type];
+ } else {
+ metrics = new _voMetricsList2['default']();
+ streamMetrics[type] = metrics;
+ }
+
+ return metrics;
+ }
+
+ function addTcpConnection(mediaType, tcpid, dest, topen, tclose, tconnect) {
+ var vo = new _voMetricsTCPConnection2['default']();
+
+ vo.tcpid = tcpid;
+ vo.dest = dest;
+ vo.topen = topen;
+ vo.tclose = tclose;
+ vo.tconnect = tconnect;
+
+ getMetricsFor(mediaType).TcpList.push(vo);
+
+ metricAdded(mediaType, adapter.metricsList.TCP_CONNECTION, vo);
+ return vo;
+ }
+
+ function appendHttpTrace(httpRequest, s, d, b) {
+ var vo = new _voMetricsHTTPRequest.HTTPRequestTrace();
+
+ vo.s = s;
+ vo.d = d;
+ vo.b = b;
+
+ httpRequest.trace.push(vo);
+
+ if (!httpRequest.interval) {
+ httpRequest.interval = 0;
+ }
+
+ httpRequest.interval += d;
+
+ return vo;
+ }
+
+ function addHttpRequest(mediaType, tcpid, type, url, actualurl, serviceLocation, range, trequest, tresponse, tfinish, responsecode, mediaduration, responseHeaders, traces) {
+ var vo = new _voMetricsHTTPRequest.HTTPRequest();
+
+ // ISO 23009-1 D.4.3 NOTE 2:
+ // All entries for a given object will have the same URL and range
+ // and so can easily be correlated. If there were redirects or
+ // failures there will be one entry for each redirect/failure.
+ // The redirect-to URL or alternative url (where multiple have been
+ // provided in the MPD) will appear as the actualurl of the next
+ // entry with the same url value.
+ if (actualurl && actualurl !== url) {
+
+ // given the above, add an entry for the original request
+ addHttpRequest(mediaType, null, type, url, null, null, range, trequest, null, // unknown
+ null, // unknown
+ null, // unknown, probably a 302
+ mediaduration, null, null);
+
+ vo.actualurl = actualurl;
+ }
+
+ vo.tcpid = tcpid;
+ vo.type = type;
+ vo.url = url;
+ vo.range = range;
+ vo.trequest = trequest;
+ vo.tresponse = tresponse;
+ vo.responsecode = responsecode;
+
+ vo._tfinish = tfinish;
+ vo._stream = mediaType;
+ vo._mediaduration = mediaduration;
+ vo._responseHeaders = responseHeaders;
+ vo._serviceLocation = serviceLocation;
+
+ if (traces) {
+ traces.forEach(function (trace) {
+ appendHttpTrace(vo, trace.s, trace.d, trace.b);
+ });
+ } else {
+ // The interval and trace shall be absent for redirect and failure records.
+ delete vo.interval;
+ delete vo.trace;
+ }
+
+ getMetricsFor(mediaType).HttpList.push(vo);
+
+ metricAdded(mediaType, adapter.metricsList.HTTP_REQUEST, vo);
+ return vo;
+ }
+
+ function addRepresentationSwitch(mediaType, t, mt, to, lto) {
+ var vo = new _voMetricsRepresentationSwitch2['default']();
+
+ vo.t = t;
+ vo.mt = mt;
+ vo.to = to;
+
+ if (lto) {
+ vo.lto = lto;
+ } else {
+ delete vo.lto;
+ }
+
+ getMetricsFor(mediaType).RepSwitchList.push(vo);
+
+ metricAdded(mediaType, adapter.metricsList.TRACK_SWITCH, vo);
+ return vo;
+ }
+
+ function addBufferLevel(mediaType, t, level) {
+ var vo = new _voMetricsBufferLevel2['default']();
+ vo.t = t;
+ vo.level = level;
+ getMetricsFor(mediaType).BufferLevel.push(vo);
+
+ metricAdded(mediaType, adapter.metricsList.BUFFER_LEVEL, vo);
+ return vo;
+ }
+
+ function addBufferState(mediaType, state, target) {
+ var vo = new _voMetricsBufferState2['default']();
+ vo.target = target;
+ vo.state = state;
+ getMetricsFor(mediaType).BufferState.push(vo);
+
+ metricAdded(mediaType, adapter.metricsList.BUFFER_STATE, vo);
+ return vo;
+ }
+
+ function addDVRInfo(mediaType, currentTime, mpd, range) {
+ var vo = new _voMetricsDVRInfo2['default']();
+
+ vo.time = currentTime;
+ vo.range = range;
+ vo.manifestInfo = mpd;
+
+ getMetricsFor(mediaType).DVRInfo.push(vo);
+ metricAdded(mediaType, adapter.metricsList.DVR_INFO, vo);
+
+ return vo;
+ }
+
+ function addDroppedFrames(mediaType, quality) {
+ var vo = new _voMetricsDroppedFrames2['default']();
+ var list = getMetricsFor(mediaType).DroppedFrames;
+
+ vo.time = quality.creationTime;
+ vo.droppedFrames = quality.droppedVideoFrames;
+
+ if (list.length > 0 && list[list.length - 1] == vo) {
+ return list[list.length - 1];
+ }
+
+ list.push(vo);
+
+ metricAdded(mediaType, adapter.metricsList.DROPPED_FRAMES, vo);
+ return vo;
+ }
+
+ function addSchedulingInfo(mediaType, t, type, startTime, availabilityStartTime, duration, quality, range, state) {
+ var vo = new _voMetricsSchedulingInfo2['default']();
+
+ vo.mediaType = mediaType;
+ vo.t = t;
+
+ vo.type = type;
+ vo.startTime = startTime;
+ vo.availabilityStartTime = availabilityStartTime;
+ vo.duration = duration;
+ vo.quality = quality;
+ vo.range = range;
+
+ vo.state = state;
+
+ getMetricsFor(mediaType).SchedulingInfo.push(vo);
+
+ metricAdded(mediaType, adapter.metricsList.SCHEDULING_INFO, vo);
+ return vo;
+ }
+
+ function addRequestsQueue(mediaType, loadingRequests, executedRequests) {
+ var vo = new _voMetricsRequestsQueue2['default']();
+ vo.loadingRequests = loadingRequests;
+ vo.executedRequests = executedRequests;
+
+ getMetricsFor(mediaType).RequestsQueue = vo;
+ metricAdded(mediaType, adapter.metricsList.REQUESTS_QUEUE, vo);
+ }
+
+ function addManifestUpdate(mediaType, type, requestTime, fetchTime, availabilityStartTime, presentationStartTime, clientTimeOffset, currentTime, buffered, latency) {
+ var vo = new _voMetricsManifestUpdate.ManifestUpdate();
+ var metrics = getMetricsFor('stream');
+
+ vo.mediaType = mediaType;
+ vo.type = type;
+ vo.requestTime = requestTime; // when this manifest update was requested
+ vo.fetchTime = fetchTime; // when this manifest update was received
+ vo.availabilityStartTime = availabilityStartTime;
+ vo.presentationStartTime = presentationStartTime; // the seek point (liveEdge for dynamic, Stream[0].startTime for static)
+ vo.clientTimeOffset = clientTimeOffset; // the calculated difference between the server and client wall clock time
+ vo.currentTime = currentTime; // actual element.currentTime
+ vo.buffered = buffered; // actual element.ranges
+ vo.latency = latency; // (static is fixed value of zero. dynamic should be ((Now-@availabilityStartTime) - currentTime)
+
+ metrics.ManifestUpdate.push(vo);
+ metricAdded(mediaType, adapter.metricsList.MANIFEST_UPDATE, vo);
+
+ return vo;
+ }
+
+ function updateManifestUpdateInfo(manifestUpdate, updatedFields) {
+ if (manifestUpdate) {
+ for (var field in updatedFields) {
+ manifestUpdate[field] = updatedFields[field];
+ }
+
+ metricUpdated(manifestUpdate.mediaType, adapter.metricsList.MANIFEST_UPDATE, manifestUpdate);
+ }
+ }
+
+ function addManifestUpdateStreamInfo(manifestUpdate, id, index, start, duration) {
+ if (manifestUpdate) {
+ var vo = new _voMetricsManifestUpdate.ManifestUpdateStreamInfo();
+
+ vo.id = id;
+ vo.index = index;
+ vo.start = start;
+ vo.duration = duration;
+
+ manifestUpdate.streamInfo.push(vo);
+ metricUpdated(manifestUpdate.mediaType, adapter.metricsList.MANIFEST_UPDATE_STREAM_INFO, manifestUpdate);
+
+ return vo;
+ }
+ return null;
+ }
+
+ function addManifestUpdateRepresentationInfo(manifestUpdate, id, index, streamIndex, mediaType, presentationTimeOffset, startNumber, fragmentInfoType) {
+ if (manifestUpdate) {
+ var vo = new _voMetricsManifestUpdate.ManifestUpdateTrackInfo();
+
+ vo.id = id;
+ vo.index = index;
+ vo.streamIndex = streamIndex;
+ vo.mediaType = mediaType;
+ vo.startNumber = startNumber;
+ vo.fragmentInfoType = fragmentInfoType;
+ vo.presentationTimeOffset = presentationTimeOffset;
+
+ manifestUpdate.trackInfo.push(vo);
+ metricUpdated(manifestUpdate.mediaType, adapter.metricsList.MANIFEST_UPDATE_TRACK_INFO, manifestUpdate);
+
+ return vo;
+ }
+ return null;
+ }
+
+ function addPlayList(vo) {
+ var type = 'stream';
+
+ if (vo.trace && Array.isArray(vo.trace)) {
+ vo.trace.forEach(function (trace) {
+ if (trace.hasOwnProperty('subreplevel') && !trace.subreplevel) {
+ delete trace.subreplevel;
+ }
+ });
+ } else {
+ delete vo.trace;
+ }
+
+ getMetricsFor(type).PlayList.push(vo);
+
+ metricAdded(type, adapter.metricsList.PLAY_LIST, vo);
+ return vo;
+ }
+
+ function addDVBErrors(vo) {
+ var type = 'stream';
+
+ getMetricsFor(type).DVBErrors.push(vo);
+
+ metricAdded(type, adapter.metricsList.DVB_ERRORS, vo);
+
+ return vo;
+ }
+
+ function updateBolaState(mediaType, _s) {
+ var vo = new _voMetricsBolaState2['default']();
+ vo._s = _s;
+ getMetricsFor(mediaType).BolaState = [vo];
+
+ metricAdded(mediaType, 'BolaState', vo);
+ return vo;
+ }
+
+ instance = {
+ metricsChanged: metricsChanged,
+ metricChanged: metricChanged,
+ metricUpdated: metricUpdated,
+ metricAdded: metricAdded,
+ clearCurrentMetricsForType: clearCurrentMetricsForType,
+ clearAllCurrentMetrics: clearAllCurrentMetrics,
+ getReadOnlyMetricsFor: getReadOnlyMetricsFor,
+ getMetricsFor: getMetricsFor,
+ addTcpConnection: addTcpConnection,
+ addHttpRequest: addHttpRequest,
+ addRepresentationSwitch: addRepresentationSwitch,
+ addBufferLevel: addBufferLevel,
+ addBufferState: addBufferState,
+ addDVRInfo: addDVRInfo,
+ addDroppedFrames: addDroppedFrames,
+ addSchedulingInfo: addSchedulingInfo,
+ addRequestsQueue: addRequestsQueue,
+ addManifestUpdate: addManifestUpdate,
+ updateManifestUpdateInfo: updateManifestUpdateInfo,
+ addManifestUpdateStreamInfo: addManifestUpdateStreamInfo,
+ addManifestUpdateRepresentationInfo: addManifestUpdateRepresentationInfo,
+ addPlayList: addPlayList,
+ addDVBErrors: addDVBErrors,
+ updateBolaState: updateBolaState,
+ setConfig: setConfig
+ };
+
+ setup();
+ return instance;
+}
+
+MetricsModel.__dashjs_factory_name = 'MetricsModel';
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(MetricsModel);
+module.exports = exports['default'];
+
+},{"10":10,"13":13,"168":168,"174":174,"175":175,"176":176,"177":177,"178":178,"179":179,"180":180,"182":182,"183":183,"184":184,"185":185,"9":9}],103:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _voURIFragmentData = _dereq_(173);
+
+var _voURIFragmentData2 = _interopRequireDefault(_voURIFragmentData);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+function URIQueryAndFragmentModel() {
+
+ var instance = undefined,
+ URIFragmentDataVO = undefined,
+ URIQueryData = undefined,
+ isHTTPS = undefined;
+
+ function initialize() {
+ URIFragmentDataVO = new _voURIFragmentData2['default']();
+ URIQueryData = [];
+ isHTTPS = false;
+ }
+
+ function getURIFragmentData() {
+ return URIFragmentDataVO;
+ }
+
+ function getURIQueryData() {
+ return URIQueryData;
+ }
+
+ function isManifestHTTPS() {
+ return isHTTPS;
+ }
+
+ function parseURI(uri) {
+ if (!uri) return null;
+
+ var URIFragmentData = [];
+ var mappedArr;
+
+ var testQuery = new RegExp(/[?]/);
+ var testFragment = new RegExp(/[#]/);
+ var testHTTPS = new RegExp(/^(https:)?\/\//i);
+ var isQuery = testQuery.test(uri);
+ var isFragment = testFragment.test(uri);
+
+ isHTTPS = testHTTPS.test(uri);
+
+ function reduceArray(previousValue, currentValue, index, array) {
+ var arr = array[0].split(/[=]/);
+ array.push({ key: arr[0], value: arr[1] });
+ array.shift();
+ return array;
+ }
+
+ function mapArray(currentValue, index, array) {
+ if (index > 0) {
+ if (isQuery && URIQueryData.length === 0) {
+ URIQueryData = array[index].split(/[&]/);
+ } else if (isFragment) {
+ URIFragmentData = array[index].split(/[&]/);
+ }
+ }
+
+ return array;
+ }
+
+ mappedArr = uri.split(/[?#]/).map(mapArray);
+
+ if (URIQueryData.length > 0) {
+ URIQueryData = URIQueryData.reduce(reduceArray, null);
+ }
+
+ if (URIFragmentData.length > 0) {
+ URIFragmentData = URIFragmentData.reduce(reduceArray, null);
+ URIFragmentData.forEach(function (object) {
+ URIFragmentDataVO[object.key] = object.value;
+ });
+ }
+
+ return uri;
+ }
+
+ instance = {
+ initialize: initialize,
+ parseURI: parseURI,
+ getURIFragmentData: getURIFragmentData,
+ getURIQueryData: getURIQueryData,
+ isManifestHTTPS: isManifestHTTPS
+ };
+
+ return instance;
+}
+
+URIQueryAndFragmentModel.__dashjs_factory_name = 'URIQueryAndFragmentModel';
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(URIQueryAndFragmentModel);
+module.exports = exports['default'];
+
+},{"10":10,"173":173}],104:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+function VideoModel() {
+
+ var instance = undefined,
+ element = undefined,
+ TTMLRenderingDiv = undefined,
+ videoContainer = undefined,
+ stalledStreams = undefined,
+ previousPlaybackRate = undefined;
+
+ function initialize() {
+ stalledStreams = [];
+ }
+
+ function setPlaybackRate(value) {
+ if (!element || element.readyState < 2) return;
+ element.playbackRate = value;
+ }
+
+ //TODO Move the DVR window calculations from MediaPlayer to Here.
+ function setCurrentTime(currentTime) {
+ //_currentTime = currentTime;
+
+ // We don't set the same currentTime because it can cause firing unexpected Pause event in IE11
+ // providing playbackRate property equals to zero.
+ if (element.currentTime == currentTime) return;
+
+ // TODO Despite the fact that MediaSource 'open' event has been fired IE11 cannot set videoElement.currentTime
+ // immediately (it throws InvalidStateError). It seems that this is related to videoElement.readyState property
+ // Initially it is 0, but soon after 'open' event it goes to 1 and setting currentTime is allowed. Chrome allows to
+ // set currentTime even if readyState = 0.
+ // setTimeout is used to workaround InvalidStateError in IE11
+ try {
+ element.currentTime = currentTime;
+ } catch (e) {
+ if (element.readyState === 0 && e.code === e.INVALID_STATE_ERR) {
+ setTimeout(function () {
+ element.currentTime = currentTime;
+ }, 400);
+ }
+ }
+ }
+
+ function getElement() {
+ return element;
+ }
+
+ function setElement(value) {
+ element = value;
+ // Workaround to force Firefox to fire the canplay event.
+ element.preload = 'auto';
+ }
+
+ function setSource(source) {
+ if (source) {
+ element.src = source;
+ } else {
+ element.removeAttribute('src');
+ element.load();
+ }
+ }
+
+ function getSource() {
+ return element.src;
+ }
+
+ function getVideoContainer() {
+ return videoContainer;
+ }
+
+ function setVideoContainer(value) {
+ videoContainer = value;
+ }
+
+ function getTTMLRenderingDiv() {
+ return TTMLRenderingDiv;
+ }
+
+ function setTTMLRenderingDiv(div) {
+ TTMLRenderingDiv = div;
+ // The styling will allow the captions to match the video window size and position.
+ TTMLRenderingDiv.style.position = 'absolute';
+ TTMLRenderingDiv.style.display = 'flex';
+ TTMLRenderingDiv.style.overflow = 'hidden';
+ TTMLRenderingDiv.style.pointerEvents = 'none';
+ TTMLRenderingDiv.style.top = 0;
+ TTMLRenderingDiv.style.left = 0;
+ }
+
+ function setStallState(type, state) {
+ stallStream(type, state);
+ }
+
+ function isStalled() {
+ return stalledStreams.length > 0;
+ }
+
+ function addStalledStream(type) {
+
+ var event = undefined;
+
+ if (type === null || element.seeking || stalledStreams.indexOf(type) !== -1) {
+ return;
+ }
+
+ stalledStreams.push(type);
+ if (stalledStreams.length === 1) {
+ // Halt playback until nothing is stalled.
+ event = document.createEvent('Event');
+ event.initEvent('waiting', true, false);
+ previousPlaybackRate = element.playbackRate;
+ setPlaybackRate(0);
+ element.dispatchEvent(event);
+ }
+ }
+
+ function removeStalledStream(type) {
+ var index = stalledStreams.indexOf(type);
+ var event = undefined;
+
+ if (type === null) {
+ return;
+ }
+ if (index !== -1) {
+ stalledStreams.splice(index, 1);
+ }
+ // If nothing is stalled resume playback.
+ if (isStalled() === false && element.playbackRate === 0) {
+ event = document.createEvent('Event');
+ event.initEvent('playing', true, false);
+ setPlaybackRate(previousPlaybackRate || 1);
+ element.dispatchEvent(event);
+ }
+ }
+
+ function stallStream(type, isStalled) {
+ if (isStalled) {
+ addStalledStream(type);
+ } else {
+ removeStalledStream(type);
+ }
+ }
+
+ function getPlaybackQuality() {
+ var hasWebKit = ('webkitDroppedFrameCount' in element);
+ var hasQuality = ('getVideoPlaybackQuality' in element);
+ var result = null;
+
+ if (hasQuality) {
+ result = element.getVideoPlaybackQuality();
+ } else if (hasWebKit) {
+ result = { droppedVideoFrames: element.webkitDroppedFrameCount, creationTime: new Date() };
+ }
+
+ return result;
+ }
+
+ instance = {
+ initialize: initialize,
+ setCurrentTime: setCurrentTime,
+ setStallState: setStallState,
+ getElement: getElement,
+ setElement: setElement,
+ setSource: setSource,
+ getSource: getSource,
+ getVideoContainer: getVideoContainer,
+ setVideoContainer: setVideoContainer,
+ getTTMLRenderingDiv: getTTMLRenderingDiv,
+ setTTMLRenderingDiv: setTTMLRenderingDiv,
+ getPlaybackQuality: getPlaybackQuality
+ };
+
+ return instance;
+}
+
+VideoModel.__dashjs_factory_name = 'VideoModel';
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(VideoModel);
+module.exports = exports['default'];
+
+},{"10":10}],105:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+
+var _externalsBase64 = _dereq_(1);
+
+var _externalsBase642 = _interopRequireDefault(_externalsBase64);
+
+var CommonEncryption = (function () {
+ function CommonEncryption() {
+ _classCallCheck(this, CommonEncryption);
+ }
+
+ _createClass(CommonEncryption, null, [{
+ key: 'findCencContentProtection',
+
+ /**
+ * Find and return the ContentProtection element in the given array
+ * that indicates support for MPEG Common Encryption
+ *
+ * @param {Array} cpArray array of content protection elements
+ * @returns {Object|null} the Common Encryption content protection element or
+ * null if one was not found
+ */
+ value: function findCencContentProtection(cpArray) {
+ var retVal = null;
+ for (var i = 0; i < cpArray.length; ++i) {
+ var cp = cpArray[i];
+ if (cp.schemeIdUri.toLowerCase() === 'urn:mpeg:dash:mp4protection:2011' && cp.value.toLowerCase() === 'cenc') retVal = cp;
+ }
+ return retVal;
+ }
+
+ /**
+ * Returns just the data portion of a single PSSH
+ *
+ * @param {ArrayBuffer} pssh - the PSSH
+ * @return {ArrayBuffer} data portion of the PSSH
+ */
+ }, {
+ key: 'getPSSHData',
+ value: function getPSSHData(pssh) {
+ var offset = 8; // Box size and type fields
+ var view = new DataView(pssh);
+
+ // Read version
+ var version = view.getUint8(offset);
+
+ offset += 20; // Version (1), flags (3), system ID (16)
+
+ if (version > 0) {
+ offset += 4 + 16 * view.getUint32(offset); // Key ID count (4) and All key IDs (16*count)
+ }
+
+ offset += 4; // Data size
+ return pssh.slice(offset);
+ }
+
+ /**
+ * Returns the PSSH associated with the given key system from the concatenated
+ * list of PSSH boxes in the given initData
+ *
+ * @param {KeySystem} keySystem the desired
+ * key system
+ * @param {ArrayBuffer} initData 'cenc' initialization data. Concatenated list of PSSH.
+ * @returns {ArrayBuffer|null} The PSSH box data corresponding to the given key system, null if not found
+ * or null if a valid association could not be found.
+ */
+ }, {
+ key: 'getPSSHForKeySystem',
+ value: function getPSSHForKeySystem(keySystem, initData) {
+ var psshList = CommonEncryption.parsePSSHList(initData);
+ if (psshList.hasOwnProperty(keySystem.uuid.toLowerCase())) {
+ return psshList[keySystem.uuid.toLowerCase()];
+ }
+ return null;
+ }
+
+ /**
+ * Parse a standard common encryption PSSH which contains a simple
+ * base64-encoding of the init data
+ *
+ * @param {Object} cpData the ContentProtection element
+ * @returns {ArrayBuffer|null} the init data or null if not found
+ */
+ }, {
+ key: 'parseInitDataFromContentProtection',
+ value: function parseInitDataFromContentProtection(cpData) {
+ if ('pssh' in cpData) {
+ return _externalsBase642['default'].decodeArray(cpData.pssh.__text).buffer;
+ }
+ return null;
+ }
+
+ /**
+ * Parses list of PSSH boxes into keysystem-specific PSSH data
+ *
+ * @param {ArrayBuffer} data - the concatenated list of PSSH boxes as provided by
+ * CDM as initialization data when CommonEncryption content is detected
+ * @returns {Object|Array} an object that has a property named according to each of
+ * the detected key system UUIDs (e.g. 00000000-0000-0000-0000-0000000000)
+ * and a ArrayBuffer (the entire PSSH box) as the property value
+ */
+ }, {
+ key: 'parsePSSHList',
+ value: function parsePSSHList(data) {
+
+ if (data === null) return [];
+
+ var dv = new DataView(data);
+ var done = false;
+ var pssh = {};
+
+ // TODO: Need to check every data read for end of buffer
+ var byteCursor = 0;
+ while (!done) {
+
+ var size, nextBox, version, systemID, psshDataSize;
+ var boxStart = byteCursor;
+
+ if (byteCursor >= dv.buffer.byteLength) break;
+
+ /* Box size */
+ size = dv.getUint32(byteCursor);
+ nextBox = byteCursor + size;
+ byteCursor += 4;
+
+ /* Verify PSSH */
+ if (dv.getUint32(byteCursor) !== 0x70737368) {
+ byteCursor = nextBox;
+ continue;
+ }
+ byteCursor += 4;
+
+ /* Version must be 0 or 1 */
+ version = dv.getUint8(byteCursor);
+ if (version !== 0 && version !== 1) {
+ byteCursor = nextBox;
+ continue;
+ }
+ byteCursor++;
+
+ byteCursor += 3; /* skip flags */
+
+ // 16-byte UUID/SystemID
+ systemID = '';
+ var i, val;
+ for (i = 0; i < 4; i++) {
+ val = dv.getUint8(byteCursor + i).toString(16);
+ systemID += val.length === 1 ? '0' + val : val;
+ }
+ byteCursor += 4;
+ systemID += '-';
+ for (i = 0; i < 2; i++) {
+ val = dv.getUint8(byteCursor + i).toString(16);
+ systemID += val.length === 1 ? '0' + val : val;
+ }
+ byteCursor += 2;
+ systemID += '-';
+ for (i = 0; i < 2; i++) {
+ val = dv.getUint8(byteCursor + i).toString(16);
+ systemID += val.length === 1 ? '0' + val : val;
+ }
+ byteCursor += 2;
+ systemID += '-';
+ for (i = 0; i < 2; i++) {
+ val = dv.getUint8(byteCursor + i).toString(16);
+ systemID += val.length === 1 ? '0' + val : val;
+ }
+ byteCursor += 2;
+ systemID += '-';
+ for (i = 0; i < 6; i++) {
+ val = dv.getUint8(byteCursor + i).toString(16);
+ systemID += val.length === 1 ? '0' + val : val;
+ }
+ byteCursor += 6;
+
+ systemID = systemID.toLowerCase();
+
+ /* PSSH Data Size */
+ psshDataSize = dv.getUint32(byteCursor);
+ byteCursor += 4;
+
+ /* PSSH Data */
+ pssh[systemID] = dv.buffer.slice(boxStart, nextBox);
+ byteCursor = nextBox;
+ }
+
+ return pssh;
+ }
+ }]);
+
+ return CommonEncryption;
+})();
+
+exports['default'] = CommonEncryption;
+module.exports = exports['default'];
+
+},{"1":1}],106:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _controllersProtectionController = _dereq_(108);
+
+var _controllersProtectionController2 = _interopRequireDefault(_controllersProtectionController);
+
+var _controllersProtectionKeyController = _dereq_(109);
+
+var _controllersProtectionKeyController2 = _interopRequireDefault(_controllersProtectionKeyController);
+
+var _ProtectionEvents = _dereq_(107);
+
+var _ProtectionEvents2 = _interopRequireDefault(_ProtectionEvents);
+
+var _modelsProtectionModel_21Jan2015 = _dereq_(114);
+
+var _modelsProtectionModel_21Jan20152 = _interopRequireDefault(_modelsProtectionModel_21Jan2015);
+
+var _modelsProtectionModel_3Feb2014 = _dereq_(115);
+
+var _modelsProtectionModel_3Feb20142 = _interopRequireDefault(_modelsProtectionModel_3Feb2014);
+
+var _modelsProtectionModel_01b = _dereq_(113);
+
+var _modelsProtectionModel_01b2 = _interopRequireDefault(_modelsProtectionModel_01b);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var APIS_ProtectionModel_01b = [
+// Un-prefixed as per spec
+{
+ // Video Element
+ generateKeyRequest: 'generateKeyRequest',
+ addKey: 'addKey',
+ cancelKeyRequest: 'cancelKeyRequest',
+
+ // Events
+ needkey: 'needkey',
+ keyerror: 'keyerror',
+ keyadded: 'keyadded',
+ keymessage: 'keymessage'
+},
+// Webkit-prefixed (early Chrome versions and Chrome with EME disabled in chrome://flags)
+{
+ // Video Element
+ generateKeyRequest: 'webkitGenerateKeyRequest',
+ addKey: 'webkitAddKey',
+ cancelKeyRequest: 'webkitCancelKeyRequest',
+
+ // Events
+ needkey: 'webkitneedkey',
+ keyerror: 'webkitkeyerror',
+ keyadded: 'webkitkeyadded',
+ keymessage: 'webkitkeymessage'
+}];
+
+var APIS_ProtectionModel_3Feb2014 = [
+// Un-prefixed as per spec
+// Chrome 38-39 (and some earlier versions) with chrome://flags -- Enable Encrypted Media Extensions
+{
+ // Video Element
+ setMediaKeys: 'setMediaKeys',
+ // MediaKeys
+ MediaKeys: 'MediaKeys',
+ // MediaKeySession
+ release: 'close',
+
+ // Events
+ needkey: 'needkey',
+ error: 'keyerror',
+ message: 'keymessage',
+ ready: 'keyadded',
+ close: 'keyclose'
+},
+// MS-prefixed (IE11, Windows 8.1)
+{
+ // Video Element
+ setMediaKeys: 'msSetMediaKeys',
+ // MediaKeys
+ MediaKeys: 'MSMediaKeys',
+ // MediaKeySession
+ release: 'close',
+ // Events
+ needkey: 'msneedkey',
+ error: 'mskeyerror',
+ message: 'mskeymessage',
+ ready: 'mskeyadded',
+ close: 'mskeyclose'
+}];
+
+function Protection() {
+
+ var instance = undefined;
+ var context = this.context;
+
+ /**
+ * Create a ProtectionController and associated ProtectionModel for use with
+ * a single piece of content.
+ *
+ * @param {Object} config
+ * @return {ProtectionController} protection controller
+ *
+ */
+ function createProtectionSystem(config) {
+
+ var controller = null;
+
+ var protectionKeyController = (0, _controllersProtectionKeyController2['default'])(context).getInstance();
+ protectionKeyController.setConfig({ log: config.log });
+ protectionKeyController.initialize();
+
+ var protectionModel = getProtectionModel(config);
+
+ if (!controller && protectionModel) {
+ //TODO add ability to set external controller if still needed at all?
+ controller = (0, _controllersProtectionController2['default'])(context).create({
+ protectionModel: protectionModel,
+ protectionKeyController: protectionKeyController,
+ adapter: config.adapter,
+ eventBus: config.eventBus,
+ log: config.log
+ });
+ config.capabilities.setEncryptedMediaSupported(true);
+ }
+ return controller;
+ }
+
+ function getProtectionModel(config) {
+
+ var log = config.log;
+ var eventBus = config.eventBus;
+ var videoElement = config.videoModel.getElement();
+
+ if (videoElement.onencrypted !== undefined && videoElement.mediaKeys !== undefined && navigator.requestMediaKeySystemAccess !== undefined && typeof navigator.requestMediaKeySystemAccess === 'function') {
+
+ log('EME detected on this user agent! (ProtectionModel_21Jan2015)');
+ return (0, _modelsProtectionModel_21Jan20152['default'])(context).create({ log: log, eventBus: eventBus });
+ } else if (getAPI(videoElement, APIS_ProtectionModel_3Feb2014)) {
+
+ log('EME detected on this user agent! (ProtectionModel_3Feb2014)');
+ return (0, _modelsProtectionModel_3Feb20142['default'])(context).create({ log: log, eventBus: eventBus, api: getAPI(videoElement, APIS_ProtectionModel_3Feb2014) });
+ } else if (getAPI(videoElement, APIS_ProtectionModel_01b)) {
+
+ log('EME detected on this user agent! (ProtectionModel_01b)');
+ return (0, _modelsProtectionModel_01b2['default'])(context).create({ log: log, eventBus: eventBus, api: getAPI(videoElement, APIS_ProtectionModel_01b) });
+ } else {
+
+ log('No supported version of EME detected on this user agent! - Attempts to play encrypted content will fail!');
+ return null;
+ }
+ }
+
+ function getAPI(videoElement, apis) {
+
+ for (var i = 0; i < apis.length; i++) {
+ var api = apis[i];
+ // detect if api is supported by browser
+ // check only first function in api -> should be fine
+ if (typeof videoElement[api[Object.keys(api)[0]]] !== 'function') {
+ continue;
+ }
+
+ return api;
+ }
+
+ return null;
+ }
+
+ instance = {
+ createProtectionSystem: createProtectionSystem
+ };
+
+ return instance;
+}
+
+Protection.__dashjs_factory_name = 'Protection';
+var factory = _coreFactoryMaker2['default'].getClassFactory(Protection);
+factory.events = _ProtectionEvents2['default'];
+exports['default'] = factory;
+module.exports = exports['default'];
+
+},{"10":10,"107":107,"108":108,"109":109,"113":113,"114":114,"115":115}],107:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+var _coreEventsEventsBase = _dereq_(14);
+
+var _coreEventsEventsBase2 = _interopRequireDefault(_coreEventsEventsBase);
+
+/**
+ * @class
+ *
+ */
+
+var ProtectionEvents = (function (_EventsBase) {
+ _inherits(ProtectionEvents, _EventsBase);
+
+ /**
+ * @description Public facing external events to be used when including protection package.
+ * All public events will be aggregated into the MediaPlayerEvents Class and can be accessed
+ * via MediaPlayer.events
+ */
+
+ function ProtectionEvents() {
+ _classCallCheck(this, ProtectionEvents);
+
+ _get(Object.getPrototypeOf(ProtectionEvents.prototype), 'constructor', this).call(this);
+
+ /**
+ * Event ID for events delivered when the protection set receives
+ * a key message from the CDM
+ *
+ * @ignore
+ */
+ this.INTERNAL_KEY_MESSAGE = 'internalKeyMessage';
+
+ /**
+ * Event ID for events delivered when a key system selection procedure
+ * completes
+ * @ignore
+ */
+ this.INTERNAL_KEY_SYSTEM_SELECTED = 'internalKeySystemSelected';
+
+ /**
+ * Event ID for events delivered when a new key has been added
+ *
+ * @constant
+ * @deprecated The latest versions of the EME specification no longer
+ * use this event. {@MediaPlayer.models.protectionModel.eventList.KEY_STATUSES_CHANGED}
+ * is preferred.
+ * @event ProtectionEvents#KEY_ADDED
+ */
+ this.KEY_ADDED = 'public_keyAdded';
+ /**
+ * Event ID for events delivered when an error is encountered by the CDM
+ * while processing a license server response message
+ * @event ProtectionEvents#KEY_ERROR
+ */
+ this.KEY_ERROR = 'public_keyError';
+
+ /**
+ * Event ID for events delivered when the protection set receives
+ * a key message from the CDM
+ * @event ProtectionEvents#KEY_MESSAGE
+ */
+ this.KEY_MESSAGE = 'public_keyMessage';
+
+ /**
+ * Event ID for events delivered when a key session close
+ * process has completed
+ * @event ProtectionEvents#KEY_SESSION_CLOSED
+ */
+ this.KEY_SESSION_CLOSED = 'public_keySessionClosed';
+
+ /**
+ * Event ID for events delivered when a new key sessions creation
+ * process has completed
+ * @event ProtectionEvents#KEY_SESSION_CREATED
+ */
+ this.KEY_SESSION_CREATED = 'public_keySessionCreated';
+
+ /**
+ * Event ID for events delivered when a key session removal
+ * process has completed
+ * @event ProtectionEvents#KEY_SESSION_REMOVED
+ */
+ this.KEY_SESSION_REMOVED = 'public_keySessionRemoved';
+
+ /**
+ * Event ID for events delivered when the status of one or more
+ * decryption keys has changed
+ * @event ProtectionEvents#KEY_STATUSES_CHANGED
+ */
+ this.KEY_STATUSES_CHANGED = 'public_keyStatusesChanged';
+
+ /**
+ * Event ID for events delivered when a key system access procedure
+ * has completed
+ * @ignore
+ */
+ this.KEY_SYSTEM_ACCESS_COMPLETE = 'keySystemAccessComplete';
+
+ /**
+ * Event ID for events delivered when a key system selection procedure
+ * completes
+ * @event ProtectionEvents#KEY_SYSTEM_SELECTED
+ */
+ this.KEY_SYSTEM_SELECTED = 'public_keySystemSelected';
+
+ /**
+ * Event ID for events delivered when a license request procedure
+ * has completed
+ * @event ProtectionEvents#LICENSE_REQUEST_COMPLETE
+ */
+ this.LICENSE_REQUEST_COMPLETE = 'public_licenseRequestComplete';
+
+ /**
+ * Event ID for needkey/encrypted events
+ * @ignore
+ */
+ this.NEED_KEY = 'needkey';
+
+ /**
+ * Event ID for events delivered when the Protection system is detected and created.
+ * @event ProtectionEvents#PROTECTION_CREATED
+ */
+ this.PROTECTION_CREATED = 'public_protectioncreated';
+
+ /**
+ * Event ID for events delivered when the Protection system is destroyed.
+ * @event ProtectionEvents#PROTECTION_DESTROYED
+ */
+ this.PROTECTION_DESTROYED = 'public_protectiondestroyed';
+
+ /**
+ * Event ID for events delivered when a new server certificate has
+ * been delivered to the CDM
+ * @ignore
+ */
+ this.SERVER_CERTIFICATE_UPDATED = 'serverCertificateUpdated';
+
+ /**
+ * Event ID for events delivered when the process of shutting down
+ * a protection set has completed
+ * @ignore
+ */
+ this.TEARDOWN_COMPLETE = 'protectionTeardownComplete';
+
+ /**
+ * Event ID for events delivered when a HTMLMediaElement has been
+ * associated with the protection set
+ * @ignore
+ */
+ this.VIDEO_ELEMENT_SELECTED = 'videoElementSelected';
+ }
+
+ return ProtectionEvents;
+})(_coreEventsEventsBase2['default']);
+
+var protectionEvents = new ProtectionEvents();
+exports['default'] = protectionEvents;
+module.exports = exports['default'];
+
+},{"14":14}],108:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _CommonEncryption = _dereq_(105);
+
+var _CommonEncryption2 = _interopRequireDefault(_CommonEncryption);
+
+var _coreEventsEvents = _dereq_(13);
+
+var _coreEventsEvents2 = _interopRequireDefault(_coreEventsEvents);
+
+var _voMediaCapability = _dereq_(126);
+
+var _voMediaCapability2 = _interopRequireDefault(_voMediaCapability);
+
+var _voKeySystemConfiguration = _dereq_(125);
+
+var _voKeySystemConfiguration2 = _interopRequireDefault(_voKeySystemConfiguration);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _Protection = _dereq_(106);
+
+var _Protection2 = _interopRequireDefault(_Protection);
+
+/**
+ * @module ProtectionController
+ * @description Provides access to media protection information and functionality. Each
+ * ProtectionController manages a single {@link MediaPlayer.models.ProtectionModel}
+ * which encapsulates a set of protection information (EME APIs, selected key system,
+ * key sessions). The APIs of ProtectionController mostly align with the latest EME
+ * APIs. Key system selection is mostly automated when combined with app-overrideable
+ * functionality provided in {@link ProtectionKeyController}.
+ * @todo ProtectionController does almost all of its tasks automatically after init() is
+ * called. Applications might want more control over this process and want to go through
+ * each step manually (key system selection, session creation, session maintenance).
+ * @param {Object} config
+ */
+
+function ProtectionController(config) {
+
+ var protectionKeyController = config.protectionKeyController;
+ var protectionModel = config.protectionModel;
+ var adapter = config.adapter;
+ var eventBus = config.eventBus;
+ var log = config.log;
+
+ var instance = undefined,
+ keySystems = undefined,
+ pendingNeedKeyData = undefined,
+ audioInfo = undefined,
+ videoInfo = undefined,
+ protDataSet = undefined,
+ initialized = undefined,
+ sessionType = undefined,
+ robustnessLevel = undefined,
+ keySystem = undefined;
+
+ function setup() {
+ keySystems = protectionKeyController.getKeySystems();
+ pendingNeedKeyData = [];
+ initialized = false;
+ sessionType = 'temporary';
+ robustnessLevel = '';
+
+ _coreEventsEvents2['default'].extend(_Protection2['default'].events);
+ }
+
+ /**
+ * Initialize this protection system with a given manifest and optional audio
+ * and video stream information.
+ *
+ * @param {Object} manifest the json version of the manifest XML document for the
+ * desired content. Applications can download their manifest using
+ * {@link module:MediaPlayer#retrieveManifest}
+ * @param {StreamInfo} [aInfo] audio stream information
+ * @param {StreamInfo} [vInfo] video stream information
+ * @memberof module:ProtectionController
+ * @instance
+ * @todo This API will change when we have better support for allowing applications
+ * to select different adaptation sets for playback. Right now it is clunky for
+ * applications to create {@link StreamInfo} with the right information,
+ */
+ function initialize(manifest, aInfo, vInfo) {
+
+ // TODO: We really need to do much more here... We need to be smarter about knowing
+ // which adaptation sets for which we have initialized, including the default key ID
+ // value from the ContentProtection elements so we know whether or not we still need to
+ // select key systems and acquire keys.
+ if (!initialized) {
+
+ var streamInfo;
+
+ if (!aInfo && !vInfo) {
+ // Look for ContentProtection elements. InitData can be provided by either the
+ // dash264drm:Pssh ContentProtection format or a DRM-specific format.
+ streamInfo = adapter.getStreamsInfo(manifest)[0]; // TODO: Single period only for now. See TODO above
+ }
+
+ audioInfo = aInfo || (streamInfo ? adapter.getMediaInfoForType(manifest, streamInfo, 'audio') : null);
+ videoInfo = vInfo || (streamInfo ? adapter.getMediaInfoForType(manifest, streamInfo, 'video') : null);
+
+ var mediaInfo = videoInfo ? videoInfo : audioInfo; // We could have audio or video only
+
+ // ContentProtection elements are specified at the AdaptationSet level, so the CP for audio
+ // and video will be the same. Just use one valid MediaInfo object
+ var supportedKS = protectionKeyController.getSupportedKeySystemsFromContentProtection(mediaInfo.contentProtection);
+ if (supportedKS && supportedKS.length > 0) {
+ selectKeySystem(supportedKS, true);
+ }
+
+ initialized = true;
+ }
+ }
+
+ /**
+ * Create a new key session associated with the given initialization data from
+ * the MPD or from the PSSH box in the media
+ *
+ * @param {ArrayBuffer} initData the initialization data
+ * @memberof module:ProtectionController
+ * @instance
+ * @fires ProtectionController#KeySessionCreated
+ * @todo In older versions of the EME spec, there was a one-to-one relationship between
+ * initialization data and key sessions. That is no longer true in the latest APIs. This
+ * API will need to modified (and a new "generateRequest(keySession, initData)" API created)
+ * to come up to speed with the latest EME standard
+ */
+ function createKeySession(initData) {
+ var initDataForKS = _CommonEncryption2['default'].getPSSHForKeySystem(keySystem, initData);
+ if (initDataForKS) {
+
+ // Check for duplicate initData
+ var currentInitData = protectionModel.getAllInitData();
+ for (var i = 0; i < currentInitData.length; i++) {
+ if (protectionKeyController.initDataEquals(initDataForKS, currentInitData[i])) {
+ log('DRM: Ignoring initData because we have already seen it!');
+ return;
+ }
+ }
+ try {
+ protectionModel.createKeySession(initDataForKS, sessionType);
+ } catch (error) {
+ eventBus.trigger(_coreEventsEvents2['default'].KEY_SESSION_CREATED, { data: null, error: 'Error creating key session! ' + error.message });
+ }
+ } else {
+ eventBus.trigger(_coreEventsEvents2['default'].KEY_SESSION_CREATED, { data: null, error: 'Selected key system is ' + keySystem.systemString + '. needkey/encrypted event contains no initData corresponding to that key system!' });
+ }
+ }
+
+ /**
+ * Loads a key session with the given session ID from persistent storage. This
+ * essentially creates a new key session
+ *
+ * @param {string} sessionID
+ * @memberof module:ProtectionController
+ * @instance
+ * @fires ProtectionController#KeySessionCreated
+ */
+ function loadKeySession(sessionID) {
+ protectionModel.loadKeySession(sessionID);
+ }
+
+ /**
+ * Removes the given key session from persistent storage and closes the session
+ * as if {@link ProtectionController#closeKeySession}
+ * was called
+ *
+ * @param {SessionToken} sessionToken the session
+ * token
+ * @memberof module:ProtectionController
+ * @instance
+ * @fires ProtectionController#KeySessionRemoved
+ * @fires ProtectionController#KeySessionClosed
+ */
+ function removeKeySession(sessionToken) {
+ protectionModel.removeKeySession(sessionToken);
+ }
+
+ /**
+ * Closes the key session and releases all associated decryption keys. These
+ * keys will no longer be available for decrypting media
+ *
+ * @param {SessionToken} sessionToken the session
+ * token
+ * @memberof module:ProtectionController
+ * @instance
+ * @fires ProtectionController#KeySessionClosed
+ */
+ function closeKeySession(sessionToken) {
+ protectionModel.closeKeySession(sessionToken);
+ }
+
+ /**
+ * Sets a server certificate for use by the CDM when signing key messages
+ * intended for a particular license server. This will fire
+ * an error event if a key system has not yet been selected.
+ *
+ * @param {ArrayBuffer} serverCertificate a CDM-specific license server
+ * certificate
+ * @memberof module:ProtectionController
+ * @instance
+ * @fires ProtectionController#ServerCertificateUpdated
+ */
+ function setServerCertificate(serverCertificate) {
+ protectionModel.setServerCertificate(serverCertificate);
+ }
+
+ /**
+ * Associate this protection system with the given HTMLMediaElement. This
+ * causes the system to register for needkey/encrypted events from the given
+ * element and provides a destination for setting of MediaKeys
+ *
+ * @param {HTMLMediaElement} element the media element to which the protection
+ * system should be associated
+ * @memberof module:ProtectionController
+ * @instance
+ */
+ function setMediaElement(element) {
+ if (element) {
+ protectionModel.setMediaElement(element);
+ eventBus.on(_coreEventsEvents2['default'].NEED_KEY, onNeedKey, this);
+ eventBus.on(_coreEventsEvents2['default'].INTERNAL_KEY_MESSAGE, onKeyMessage, this);
+ } else if (element === null) {
+ protectionModel.setMediaElement(element);
+ eventBus.off(_coreEventsEvents2['default'].NEED_KEY, onNeedKey, this);
+ eventBus.off(_coreEventsEvents2['default'].INTERNAL_KEY_MESSAGE, onKeyMessage, this);
+ }
+ }
+
+ /**
+ * Sets the session type to use when creating key sessions. Either "temporary" or
+ * "persistent-license". Default is "temporary".
+ *
+ * @param {string} value the session type
+ * @memberof module:ProtectionController
+ * @instance
+ */
+ function setSessionType(value) {
+ sessionType = value;
+ }
+
+ /**
+ * Sets the robustness level for video and audio capabilities. Optional to remove Chrome warnings.
+ * Possible values are SW_SECURE_CRYPTO, SW_SECURE_DECODE, HW_SECURE_CRYPTO, HW_SECURE_CRYPTO, HW_SECURE_DECODE, HW_SECURE_ALL.
+ *
+ * @param {string} level the robustness level
+ * @memberof module:ProtectionController
+ * @instance
+ */
+ function setRobustnessLevel(level) {
+ robustnessLevel = level;
+ }
+
+ /**
+ * Attach KeySystem-specific data to use for license acquisition with EME
+ *
+ * @param {Object} data an object containing property names corresponding to
+ * key system name strings (e.g. "org.w3.clearkey") and associated values
+ * being instances of {@link ProtectionData}
+ * @memberof module:ProtectionController
+ * @instance
+ */
+ function setProtectionData(data) {
+ protDataSet = data;
+ }
+
+ /**
+ * Destroys all protection data associated with this protection set. This includes
+ * deleting all key sessions. In the case of persistent key sessions, the sessions
+ * will simply be unloaded and not deleted. Additionally, if this protection set is
+ * associated with a HTMLMediaElement, it will be detached from that element.
+ *
+ * @memberof module:ProtectionController
+ * @instance
+ */
+ function reset() {
+ setMediaElement(null);
+
+ keySystem = undefined; //TODO-Refactor look at why undefined is needed for this. refactor
+
+ if (protectionModel) {
+ protectionModel.reset();
+ protectionModel = null;
+ }
+ }
+
+ ///////////////
+ // Private
+ ///////////////
+
+ function getProtData(keySystem) {
+ var protData = null;
+ var keySystemString = keySystem.systemString;
+
+ if (protDataSet) {
+ protData = keySystemString in protDataSet ? protDataSet[keySystemString] : null;
+ }
+ return protData;
+ }
+
+ function selectKeySystem(supportedKS, fromManifest) {
+
+ var self = this;
+
+ // Build our request object for requestKeySystemAccess
+ var audioCapabilities = [];
+ var videoCapabilities = [];
+
+ if (videoInfo) {
+ videoCapabilities.push(new _voMediaCapability2['default'](videoInfo.codec, robustnessLevel));
+ }
+ if (audioInfo) {
+ audioCapabilities.push(new _voMediaCapability2['default'](audioInfo.codec, robustnessLevel));
+ }
+ var ksConfig = new _voKeySystemConfiguration2['default'](audioCapabilities, videoCapabilities, 'optional', sessionType === 'temporary' ? 'optional' : 'required', [sessionType]);
+ var requestedKeySystems = [];
+
+ var ksIdx;
+ if (keySystem) {
+ // We have a key system
+ for (ksIdx = 0; ksIdx < supportedKS.length; ksIdx++) {
+ if (keySystem === supportedKS[ksIdx].ks) {
+ var _ret = (function () {
+
+ requestedKeySystems.push({ ks: supportedKS[ksIdx].ks, configs: [ksConfig] });
+
+ // Ensure that we would be granted key system access using the key
+ // system and codec information
+ var onKeySystemAccessComplete = function onKeySystemAccessComplete(event) {
+ eventBus.off(_coreEventsEvents2['default'].KEY_SYSTEM_ACCESS_COMPLETE, onKeySystemAccessComplete, self);
+ if (event.error) {
+ if (!fromManifest) {
+ eventBus.trigger(_coreEventsEvents2['default'].KEY_SYSTEM_SELECTED, { error: 'DRM: KeySystem Access Denied! -- ' + event.error });
+ }
+ } else {
+ log('DRM: KeySystem Access Granted');
+ eventBus.trigger(_coreEventsEvents2['default'].KEY_SYSTEM_SELECTED, { data: event.data });
+ createKeySession(supportedKS[ksIdx].initData);
+ }
+ };
+ eventBus.on(_coreEventsEvents2['default'].KEY_SYSTEM_ACCESS_COMPLETE, onKeySystemAccessComplete, self);
+ protectionModel.requestKeySystemAccess(requestedKeySystems);
+ return 'break';
+ })();
+
+ if (_ret === 'break') break;
+ }
+ }
+ } else if (keySystem === undefined) {
+ // First time through, so we need to select a key system
+ keySystem = null;
+ pendingNeedKeyData.push(supportedKS);
+
+ // Add all key systems to our request list since we have yet to select a key system
+ for (var i = 0; i < supportedKS.length; i++) {
+ requestedKeySystems.push({ ks: supportedKS[i].ks, configs: [ksConfig] });
+ }
+
+ var keySystemAccess;
+ var onKeySystemAccessComplete = function onKeySystemAccessComplete(event) {
+ eventBus.off(_coreEventsEvents2['default'].KEY_SYSTEM_ACCESS_COMPLETE, onKeySystemAccessComplete, self);
+ if (event.error) {
+ keySystem = undefined;
+ eventBus.off(_coreEventsEvents2['default'].INTERNAL_KEY_SYSTEM_SELECTED, onKeySystemSelected, self);
+
+ if (!fromManifest) {
+ eventBus.trigger(_coreEventsEvents2['default'].KEY_SYSTEM_SELECTED, { data: null, error: 'DRM: KeySystem Access Denied! -- ' + event.error });
+ }
+ } else {
+ keySystemAccess = event.data;
+ log('DRM: KeySystem Access Granted (' + keySystemAccess.keySystem.systemString + ')! Selecting key system...');
+ protectionModel.selectKeySystem(keySystemAccess);
+ }
+ };
+ var onKeySystemSelected = function onKeySystemSelected(event) {
+ eventBus.off(_coreEventsEvents2['default'].INTERNAL_KEY_SYSTEM_SELECTED, onKeySystemSelected, self);
+ eventBus.off(_coreEventsEvents2['default'].KEY_SYSTEM_ACCESS_COMPLETE, onKeySystemAccessComplete, self);
+ if (!event.error) {
+ keySystem = protectionModel.getKeySystem();
+ eventBus.trigger(_coreEventsEvents2['default'].KEY_SYSTEM_SELECTED, { data: keySystemAccess });
+ for (var i = 0; i < pendingNeedKeyData.length; i++) {
+ for (ksIdx = 0; ksIdx < pendingNeedKeyData[i].length; ksIdx++) {
+ if (keySystem === pendingNeedKeyData[i][ksIdx].ks) {
+ createKeySession(pendingNeedKeyData[i][ksIdx].initData);
+ break;
+ }
+ }
+ }
+ } else {
+ keySystem = undefined;
+ if (!fromManifest) {
+ eventBus.trigger(_coreEventsEvents2['default'].KEY_SYSTEM_SELECTED, { data: null, error: 'DRM: Error selecting key system! -- ' + event.error });
+ }
+ }
+ };
+ eventBus.on(_coreEventsEvents2['default'].INTERNAL_KEY_SYSTEM_SELECTED, onKeySystemSelected, self);
+ eventBus.on(_coreEventsEvents2['default'].KEY_SYSTEM_ACCESS_COMPLETE, onKeySystemAccessComplete, self);
+ protectionModel.requestKeySystemAccess(requestedKeySystems);
+ } else {
+ // We are in the process of selecting a key system, so just save the data
+ pendingNeedKeyData.push(supportedKS);
+ }
+ }
+
+ function sendLicenseRequestCompleteEvent(data, error) {
+ eventBus.trigger(_coreEventsEvents2['default'].LICENSE_REQUEST_COMPLETE, { data: data, error: error });
+ }
+
+ function onKeyMessage(e) {
+ log('DRM: onKeyMessage');
+ if (e.error) {
+ log(e.error);
+ return;
+ }
+
+ // Dispatch event to applications indicating we received a key message
+ var keyMessage = e.data;
+ eventBus.trigger(_coreEventsEvents2['default'].KEY_MESSAGE, { data: keyMessage });
+ var messageType = keyMessage.messageType ? keyMessage.messageType : 'license-request';
+ var message = keyMessage.message;
+ var sessionToken = keyMessage.sessionToken;
+ var protData = getProtData(keySystem);
+ var keySystemString = keySystem.systemString;
+ var licenseServerData = protectionKeyController.getLicenseServer(keySystem, protData, messageType);
+ var eventData = { sessionToken: sessionToken, messageType: messageType };
+
+ // Message not destined for license server
+ if (!licenseServerData) {
+ log('DRM: License server request not required for this message (type = ' + e.data.messageType + '). Session ID = ' + sessionToken.getSessionID());
+ sendLicenseRequestCompleteEvent(eventData);
+ return;
+ }
+
+ // Perform any special handling for ClearKey
+ if (protectionKeyController.isClearKey(keySystem)) {
+ var clearkeys = protectionKeyController.processClearKeyLicenseRequest(protData, message);
+ if (clearkeys) {
+ log('DRM: ClearKey license request handled by application!');
+ sendLicenseRequestCompleteEvent(eventData);
+ protectionModel.updateKeySession(sessionToken, clearkeys);
+ return;
+ }
+ }
+
+ // All remaining key system scenarios require a request to a remote license server
+ var xhr = new XMLHttpRequest();
+
+ // Determine license server URL
+ var url = null;
+ if (protData) {
+ if (protData.serverURL) {
+ var serverURL = protData.serverURL;
+ if (typeof serverURL === 'string' && serverURL !== '') {
+ url = serverURL;
+ } else if (typeof serverURL === 'object' && serverURL.hasOwnProperty(messageType)) {
+ url = serverURL[messageType];
+ }
+ } else if (protData.laURL && protData.laURL !== '') {
+ // TODO: Deprecated!
+ url = protData.laURL;
+ }
+ } else {
+ url = keySystem.getLicenseServerURLFromInitData(_CommonEncryption2['default'].getPSSHData(sessionToken.initData));
+ if (!url) {
+ url = e.data.laURL;
+ }
+ }
+ // Possibly update or override the URL based on the message
+ url = licenseServerData.getServerURLFromMessage(url, message, messageType);
+
+ // Ensure valid license server URL
+ if (!url) {
+ sendLicenseRequestCompleteEvent(eventData, 'DRM: No license server URL specified!');
+ return;
+ }
+
+ xhr.open(licenseServerData.getHTTPMethod(messageType), url, true);
+ xhr.responseType = licenseServerData.getResponseType(keySystemString, messageType);
+ xhr.onload = function () {
+ if (this.status == 200) {
+ sendLicenseRequestCompleteEvent(eventData);
+ protectionModel.updateKeySession(sessionToken, licenseServerData.getLicenseMessage(this.response, keySystemString, messageType));
+ } else {
+ sendLicenseRequestCompleteEvent(eventData, 'DRM: ' + keySystemString + ' update, XHR status is "' + this.statusText + '" (' + this.status + '), expected to be 200. readyState is ' + this.readyState + '. Response is ' + (this.response ? licenseServerData.getErrorResponse(this.response, keySystemString, messageType) : 'NONE'));
+ }
+ };
+ xhr.onabort = function () {
+ sendLicenseRequestCompleteEvent(eventData, 'DRM: ' + keySystemString + ' update, XHR aborted. status is "' + this.statusText + '" (' + this.status + '), readyState is ' + this.readyState);
+ };
+ xhr.onerror = function () {
+ sendLicenseRequestCompleteEvent(eventData, 'DRM: ' + keySystemString + ' update, XHR error. status is "' + this.statusText + '" (' + this.status + '), readyState is ' + this.readyState);
+ };
+
+ // Set optional XMLHttpRequest headers from protection data and message
+ var updateHeaders = function updateHeaders(headers) {
+ var key;
+ if (headers) {
+ for (key in headers) {
+ if ('authorization' === key.toLowerCase()) {
+ xhr.withCredentials = true;
+ }
+ xhr.setRequestHeader(key, headers[key]);
+ }
+ }
+ };
+ if (protData) {
+ updateHeaders(protData.httpRequestHeaders);
+ }
+ updateHeaders(keySystem.getRequestHeadersFromMessage(message));
+
+ // Set withCredentials property from protData
+ if (protData && protData.withCredentials) {
+ xhr.withCredentials = true;
+ }
+
+ xhr.send(keySystem.getLicenseRequestFromMessage(message));
+ }
+
+ function onNeedKey(event) {
+ log('DRM: onNeedKey');
+ // Ignore non-cenc initData
+ if (event.key.initDataType !== 'cenc') {
+ log('DRM: Only \'cenc\' initData is supported! Ignoring initData of type: ' + event.key.initDataType);
+ return;
+ }
+
+ // Some browsers return initData as Uint8Array (IE), some as ArrayBuffer (Chrome).
+ // Convert to ArrayBuffer
+ var abInitData = event.key.initData;
+ if (ArrayBuffer.isView(abInitData)) {
+ abInitData = abInitData.buffer;
+ }
+
+ log('DRM: initData:', String.fromCharCode.apply(null, new Uint8Array(abInitData)));
+
+ var supportedKS = protectionKeyController.getSupportedKeySystems(abInitData, protDataSet);
+ if (supportedKS.length === 0) {
+ log('DRM: Received needkey event with initData, but we don\'t support any of the key systems!');
+ return;
+ }
+
+ selectKeySystem(supportedKS, false);
+ }
+
+ instance = {
+ initialize: initialize,
+ createKeySession: createKeySession,
+ loadKeySession: loadKeySession,
+ removeKeySession: removeKeySession,
+ closeKeySession: closeKeySession,
+ setServerCertificate: setServerCertificate,
+ setMediaElement: setMediaElement,
+ setSessionType: setSessionType,
+ setRobustnessLevel: setRobustnessLevel,
+ setProtectionData: setProtectionData,
+ reset: reset
+ };
+
+ setup();
+ return instance;
+}
+
+ProtectionController.__dashjs_factory_name = 'ProtectionController';
+exports['default'] = _coreFactoryMaker2['default'].getClassFactory(ProtectionController);
+module.exports = exports['default'];
+
+},{"10":10,"105":105,"106":106,"125":125,"126":126,"13":13}],109:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _CommonEncryption = _dereq_(105);
+
+var _CommonEncryption2 = _interopRequireDefault(_CommonEncryption);
+
+var _drmKeySystemClearKey = _dereq_(110);
+
+var _drmKeySystemClearKey2 = _interopRequireDefault(_drmKeySystemClearKey);
+
+var _drmKeySystemWidevine = _dereq_(112);
+
+var _drmKeySystemWidevine2 = _interopRequireDefault(_drmKeySystemWidevine);
+
+var _drmKeySystemPlayReady = _dereq_(111);
+
+var _drmKeySystemPlayReady2 = _interopRequireDefault(_drmKeySystemPlayReady);
+
+var _serversDRMToday = _dereq_(117);
+
+var _serversDRMToday2 = _interopRequireDefault(_serversDRMToday);
+
+var _serversPlayReady = _dereq_(118);
+
+var _serversPlayReady2 = _interopRequireDefault(_serversPlayReady);
+
+var _serversWidevine = _dereq_(119);
+
+var _serversWidevine2 = _interopRequireDefault(_serversWidevine);
+
+var _serversClearKey = _dereq_(116);
+
+var _serversClearKey2 = _interopRequireDefault(_serversClearKey);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+/**
+ * @module ProtectionKeyController
+ * @description Media protection key system functionality that can be modified/overridden by applications
+ */
+function ProtectionKeyController() {
+
+ var context = this.context;
+
+ var instance = undefined,
+ log = undefined,
+ keySystems = undefined,
+ clearkeyKeySystem = undefined;
+
+ function setConfig(config) {
+ if (!config) return;
+
+ if (config.log) {
+ log = config.log;
+ }
+ }
+
+ function initialize() {
+ keySystems = [];
+
+ var keySystem;
+
+ // PlayReady
+ keySystem = (0, _drmKeySystemPlayReady2['default'])(context).getInstance();
+ keySystems.push(keySystem);
+
+ // Widevine
+ keySystem = (0, _drmKeySystemWidevine2['default'])(context).getInstance();
+ keySystems.push(keySystem);
+
+ // ClearKey
+ keySystem = (0, _drmKeySystemClearKey2['default'])(context).getInstance();
+ keySystems.push(keySystem);
+ clearkeyKeySystem = keySystem;
+ }
+
+ /**
+ * Returns a prioritized list of key systems supported
+ * by this player (not necessarily those supported by the
+ * user agent)
+ *
+ * @returns {Array.<KeySystem>} a prioritized
+ * list of key systems
+ * @memberof module:ProtectionKeyController
+ * @instance
+ */
+ function getKeySystems() {
+ return keySystems;
+ }
+
+ /**
+ * Returns the key system associated with the given key system string
+ * name (i.e. 'org.w3.clearkey')
+ *
+ * @param {string} systemString the system string
+ * @returns {KeySystem|null} the key system
+ * or null if no supported key system is associated with the given key
+ * system string
+ * @memberof module:ProtectionKeyController
+ * @instance
+ */
+ function getKeySystemBySystemString(systemString) {
+ for (var i = 0; i < keySystems.length; i++) {
+ if (keySystems[i].systemString === systemString) {
+ return keySystems[i];
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Determines whether the given key system is ClearKey. This is
+ * necessary because the EME spec defines ClearKey and its method
+ * for providing keys to the key session; and this method has changed
+ * between the various API versions. Our EME-specific ProtectionModels
+ * must know if the system is ClearKey so that it can format the keys
+ * according to the particular spec version.
+ *
+ * @param {Object} keySystem the key
+ * @returns {boolean} true if this is the ClearKey key system, false
+ * otherwise
+ * @memberof module:ProtectionKeyController
+ * @instance
+ */
+ function isClearKey(keySystem) {
+ return keySystem === clearkeyKeySystem;
+ }
+
+ /**
+ * Check equality of initData array buffers.
+ *
+ * @param {ArrayBuffer} initData1 - first initData
+ * @param {ArrayBuffer} initData2 - second initData
+ * @returns {boolean} true if the initData arrays are equal in size and
+ * contents, false otherwise
+ * @memberof module:ProtectionKeyController
+ * @instance
+ */
+ function initDataEquals(initData1, initData2) {
+ if (initData1.byteLength === initData2.byteLength) {
+ var data1 = new Uint8Array(initData1);
+ var data2 = new Uint8Array(initData2);
+
+ for (var j = 0; j < data1.length; j++) {
+ if (data1[j] !== data2[j]) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns a set of supported key systems and CENC initialization data
+ * from the given array of ContentProtection elements. Only
+ * key systems that are supported by this player will be returned.
+ * Key systems are returned in priority order (highest first).
+ *
+ * @param {Array.<Object>} cps - array of content protection elements parsed
+ * from the manifest
+ * @returns {Array.<Object>} array of objects indicating which supported key
+ * systems were found. Empty array is returned if no
+ * supported key systems were found
+ * @memberof module:ProtectionKeyController
+ * @instance
+ */
+ function getSupportedKeySystemsFromContentProtection(cps) {
+ var cp, ks, ksIdx, cpIdx;
+ var supportedKS = [];
+
+ if (cps) {
+ for (ksIdx = 0; ksIdx < keySystems.length; ++ksIdx) {
+ ks = keySystems[ksIdx];
+ for (cpIdx = 0; cpIdx < cps.length; ++cpIdx) {
+ cp = cps[cpIdx];
+ if (cp.schemeIdUri.toLowerCase() === ks.schemeIdURI) {
+
+ // Look for DRM-specific ContentProtection
+ var initData = ks.getInitData(cp);
+ if (!!initData) {
+ supportedKS.push({
+ ks: keySystems[ksIdx],
+ initData: initData
+ });
+ }
+ }
+ }
+ }
+ }
+ return supportedKS;
+ }
+
+ /**
+ * Returns key systems supported by this player for the given PSSH
+ * initializationData. Only key systems supported by this player
+ * that have protection data present will be returned. Key systems are returned in priority order
+ * (highest priority first)
+ *
+ * @param {ArrayBuffer} initData Concatenated PSSH data for all DRMs
+ * supported by the content
+ * @param {ProtectionData} protDataSet user specified protection data - license server url etc
+ * supported by the content
+ * @returns {Array.<Object>} array of objects indicating which supported key
+ * systems were found. Empty array is returned if no
+ * supported key systems were found
+ * @memberof module:ProtectionKeyController
+ * @instance
+ */
+ function getSupportedKeySystems(initData, protDataSet) {
+ var ksIdx;
+ var supportedKS = [];
+ var pssh = _CommonEncryption2['default'].parsePSSHList(initData);
+
+ for (ksIdx = 0; ksIdx < keySystems.length; ++ksIdx) {
+ var keySystemString = keySystems[ksIdx].systemString;
+ var shouldNotFilterOutKeySystem = protDataSet ? keySystemString in protDataSet : true;
+
+ if (keySystems[ksIdx].uuid in pssh && shouldNotFilterOutKeySystem) {
+ supportedKS.push({
+ ks: keySystems[ksIdx],
+ initData: pssh[keySystems[ksIdx].uuid]
+ });
+ }
+ }
+ return supportedKS;
+ }
+
+ /**
+ * Returns the license server implementation data that should be used for this request.
+ *
+ * @param {KeySystem} keySystem the key system
+ * associated with this license request
+ * @param {ProtectionData} protData protection data to use for the
+ * request
+ * @param {string} [messageType="license-request"] the message type associated with this
+ * request. Supported message types can be found
+ * {@link https://w3c.github.io/encrypted-media/#idl-def-MediaKeyMessageType|here}.
+ * @returns {LicenseServer|null} the license server
+ * implementation that should be used for this request or null if the player should not
+ * pass messages of the given type to a license server
+ * @memberof module:ProtectionKeyController
+ * @instance
+ *
+ */
+ function getLicenseServer(keySystem, protData, messageType) {
+
+ // Our default server implementations do not do anything with "license-release" or
+ // "individualization-request" messages, so we just send a success event
+ if (messageType === 'license-release' || messageType === 'individualization-request') {
+ return null;
+ }
+
+ var licenseServerData = null;
+ if (protData && protData.hasOwnProperty('drmtoday')) {
+ licenseServerData = (0, _serversDRMToday2['default'])(context).getInstance();
+ } else if (keySystem.systemString === 'com.widevine.alpha') {
+ licenseServerData = (0, _serversWidevine2['default'])(context).getInstance();
+ } else if (keySystem.systemString === 'com.microsoft.playready') {
+ licenseServerData = (0, _serversPlayReady2['default'])(context).getInstance();
+ } else if (keySystem.systemString === 'org.w3.clearkey') {
+ licenseServerData = (0, _serversClearKey2['default'])(context).getInstance();
+ }
+
+ return licenseServerData;
+ }
+
+ /**
+ * Allows application-specific retrieval of ClearKey keys.
+ *
+ * @param {ProtectionData} protData protection data to use for the
+ * request
+ * @param {ArrayBuffer} message the key message from the CDM
+ * @return {ClearKeyKeySet|null} the clear keys associated with
+ * the request or null if no keys can be returned by this function
+ * @memberof module:ProtectionKeyController
+ * @instance
+ */
+ function processClearKeyLicenseRequest(protData, message) {
+ try {
+ return clearkeyKeySystem.getClearKeysFromProtectionData(protData, message);
+ } catch (error) {
+ log('Failed to retrieve clearkeys from ProtectionData');
+ return null;
+ }
+ }
+
+ instance = {
+ initialize: initialize,
+ isClearKey: isClearKey,
+ initDataEquals: initDataEquals,
+ getKeySystems: getKeySystems,
+ getKeySystemBySystemString: getKeySystemBySystemString,
+ getSupportedKeySystemsFromContentProtection: getSupportedKeySystemsFromContentProtection,
+ getSupportedKeySystems: getSupportedKeySystems,
+ getLicenseServer: getLicenseServer,
+ processClearKeyLicenseRequest: processClearKeyLicenseRequest,
+ setConfig: setConfig
+ };
+
+ return instance;
+}
+
+ProtectionKeyController.__dashjs_factory_name = 'ProtectionKeyController';
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(ProtectionKeyController);
+module.exports = exports['default'];
+
+},{"10":10,"105":105,"110":110,"111":111,"112":112,"116":116,"117":117,"118":118,"119":119}],110:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _voKeyPair = _dereq_(123);
+
+var _voKeyPair2 = _interopRequireDefault(_voKeyPair);
+
+var _voClearKeyKeySet = _dereq_(120);
+
+var _voClearKeyKeySet2 = _interopRequireDefault(_voClearKeyKeySet);
+
+var _CommonEncryption = _dereq_(105);
+
+var _CommonEncryption2 = _interopRequireDefault(_CommonEncryption);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var uuid = '1077efec-c0b2-4d02-ace3-3c1e52e2fb4b';
+var systemString = 'org.w3.clearkey';
+var schemeIdURI = 'urn:uuid:' + uuid;
+
+function KeySystemClearKey() {
+
+ var instance = undefined;
+ /**
+ * Returns desired clearkeys (as specified in the CDM message) from protection data
+ *
+ * @param {ProtectionData} protectionData the protection data
+ * @param {ArrayBuffer} message the ClearKey CDM message
+ * @returns {ClearKeyKeySet} the key set or null if none found
+ * @throws {Error} if a keyID specified in the CDM message was not found in the
+ * protection data
+ * @memberof KeySystemClearKey
+ */
+ function getClearKeysFromProtectionData(protectionData, message) {
+ var clearkeySet = null;
+ if (protectionData) {
+ // ClearKey is the only system that does not require a license server URL, so we
+ // handle it here when keys are specified in protection data
+ var jsonMsg = JSON.parse(String.fromCharCode.apply(null, new Uint8Array(message)));
+ var keyPairs = [];
+ for (var i = 0; i < jsonMsg.kids.length; i++) {
+ var clearkeyID = jsonMsg.kids[i];
+ var clearkey = protectionData.clearkeys.hasOwnProperty(clearkeyID) ? protectionData.clearkeys[clearkeyID] : null;
+ if (!clearkey) {
+ throw new Error('DRM: ClearKey keyID (' + clearkeyID + ') is not known!');
+ }
+ // KeyIDs from CDM are not base64 padded. Keys may or may not be padded
+ keyPairs.push(new _voKeyPair2['default'](clearkeyID, clearkey));
+ }
+ clearkeySet = new _voClearKeyKeySet2['default'](keyPairs);
+ }
+ return clearkeySet;
+ }
+
+ function getInitData(cp) {
+ return _CommonEncryption2['default'].parseInitDataFromContentProtection(cp);
+ }
+
+ function getRequestHeadersFromMessage() /*message*/{
+ return null;
+ }
+
+ function getLicenseRequestFromMessage(message) {
+ return new Uint8Array(message);
+ }
+
+ function getLicenseServerURLFromInitData() /*initData*/{
+ return null;
+ }
+
+ instance = {
+ uuid: uuid,
+ schemeIdURI: schemeIdURI,
+ systemString: systemString,
+ getInitData: getInitData,
+ getRequestHeadersFromMessage: getRequestHeadersFromMessage,
+ getLicenseRequestFromMessage: getLicenseRequestFromMessage,
+ getLicenseServerURLFromInitData: getLicenseServerURLFromInitData,
+ getClearKeysFromProtectionData: getClearKeysFromProtectionData
+ };
+
+ return instance;
+}
+
+KeySystemClearKey.__dashjs_factory_name = 'KeySystemClearKey';
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(KeySystemClearKey);
+module.exports = exports['default'];
+
+},{"10":10,"105":105,"120":120,"123":123}],111:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * Microsoft PlayReady DRM
+ *
+ * @class
+ * @implements KeySystem
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _CommonEncryption = _dereq_(105);
+
+var _CommonEncryption2 = _interopRequireDefault(_CommonEncryption);
+
+var _voError = _dereq_(162);
+
+var _voError2 = _interopRequireDefault(_voError);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _externalsBase64 = _dereq_(1);
+
+var _externalsBase642 = _interopRequireDefault(_externalsBase64);
+
+var uuid = '9a04f079-9840-4286-ab92-e65be0885f95';
+var systemString = 'com.microsoft.playready';
+var schemeIdURI = 'urn:uuid:' + uuid;
+
+function KeySystemPlayReady() {
+
+ var instance = undefined;
+ var messageFormat = 'utf16';
+
+ function getRequestHeadersFromMessage(message) {
+ var msg, xmlDoc;
+ var headers = {};
+ var parser = new DOMParser();
+ var dataview = messageFormat === 'utf16' ? new Uint16Array(message) : new Uint8Array(message);
+
+ msg = String.fromCharCode.apply(null, dataview);
+ xmlDoc = parser.parseFromString(msg, 'application/xml');
+
+ var headerNameList = xmlDoc.getElementsByTagName('name');
+ var headerValueList = xmlDoc.getElementsByTagName('value');
+ for (var i = 0; i < headerNameList.length; i++) {
+ headers[headerNameList[i].childNodes[0].nodeValue] = headerValueList[i].childNodes[0].nodeValue;
+ }
+ // some versions of the PlayReady CDM return 'Content' instead of 'Content-Type'.
+ // this is NOT w3c conform and license servers may reject the request!
+ // -> rename it to proper w3c definition!
+ if (headers.hasOwnProperty('Content')) {
+ headers['Content-Type'] = headers.Content;
+ delete headers.Content;
+ }
+ return headers;
+ }
+
+ function getLicenseRequestFromMessage(message) {
+ var msg, xmlDoc;
+ var licenseRequest = null;
+ var parser = new DOMParser();
+ var dataview = messageFormat === 'utf16' ? new Uint16Array(message) : new Uint8Array(message);
+
+ msg = String.fromCharCode.apply(null, dataview);
+ xmlDoc = parser.parseFromString(msg, 'application/xml');
+
+ if (xmlDoc.getElementsByTagName('Challenge')[0]) {
+ var Challenge = xmlDoc.getElementsByTagName('Challenge')[0].childNodes[0].nodeValue;
+ if (Challenge) {
+ licenseRequest = _externalsBase642['default'].decode(Challenge);
+ }
+ }
+ return licenseRequest;
+ }
+
+ function getLicenseServerURLFromInitData(initData) {
+ if (initData) {
+ var data = new DataView(initData);
+ var numRecords = data.getUint16(4, true);
+ var offset = 6;
+ var parser = new DOMParser();
+
+ for (var i = 0; i < numRecords; i++) {
+ // Parse the PlayReady Record header
+ var recordType = data.getUint16(offset, true);
+ offset += 2;
+ var recordLength = data.getUint16(offset, true);
+ offset += 2;
+ if (recordType !== 0x0001) {
+ offset += recordLength;
+ continue;
+ }
+
+ var recordData = initData.slice(offset, offset + recordLength);
+ var record = String.fromCharCode.apply(null, new Uint16Array(recordData));
+ var xmlDoc = parser.parseFromString(record, 'application/xml');
+
+ // First try <LA_URL>
+ if (xmlDoc.getElementsByTagName('LA_URL')[0]) {
+ var laurl = xmlDoc.getElementsByTagName('LA_URL')[0].childNodes[0].nodeValue;
+ if (laurl) {
+ return laurl;
+ }
+ }
+
+ // Optionally, try <LUI_URL>
+ if (xmlDoc.getElementsByTagName('LUI_URL')[0]) {
+ var luiurl = xmlDoc.getElementsByTagName('LUI_URL')[0].childNodes[0].nodeValue;
+ if (luiurl) {
+ return luiurl;
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ function getInitData(cpData) {
+ // * desc@ getInitData
+ // * generate PSSH data from PROHeader defined in MPD file
+ // * PSSH format:
+ // * size (4)
+ // * box type(PSSH) (8)
+ // * Protection SystemID (16)
+ // * protection system data size (4) - length of decoded PROHeader
+ // * decoded PROHeader data from MPD file
+ var PSSHBoxType = new Uint8Array([0x70, 0x73, 0x73, 0x68, 0x00, 0x00, 0x00, 0x00]); //'PSSH' 8 bytes
+ var playreadySystemID = new Uint8Array([0x9a, 0x04, 0xf0, 0x79, 0x98, 0x40, 0x42, 0x86, 0xab, 0x92, 0xe6, 0x5b, 0xe0, 0x88, 0x5f, 0x95]);
+
+ var byteCursor = 0;
+ var uint8arraydecodedPROHeader = null;
+
+ var PROSize, PSSHSize, PSSHBoxBuffer, PSSHBox, PSSHData;
+
+ // Handle common encryption PSSH
+ if ('pssh' in cpData) {
+ return _CommonEncryption2['default'].parseInitDataFromContentProtection(cpData);
+ }
+ // Handle native MS PlayReady ContentProtection elements
+ if ('pro' in cpData) {
+ uint8arraydecodedPROHeader = _externalsBase642['default'].decodeArray(cpData.pro.__text);
+ } else if ('prheader' in cpData) {
+ uint8arraydecodedPROHeader = _externalsBase642['default'].decodeArray(cpData.prheader.__text);
+ } else {
+ return null;
+ }
+
+ PROSize = uint8arraydecodedPROHeader.length;
+ PSSHSize = 0x4 + PSSHBoxType.length + playreadySystemID.length + 0x4 + PROSize;
+
+ PSSHBoxBuffer = new ArrayBuffer(PSSHSize);
+
+ PSSHBox = new Uint8Array(PSSHBoxBuffer);
+ PSSHData = new DataView(PSSHBoxBuffer);
+
+ PSSHData.setUint32(byteCursor, PSSHSize);
+ byteCursor += 0x4;
+
+ PSSHBox.set(PSSHBoxType, byteCursor);
+ byteCursor += PSSHBoxType.length;
+
+ PSSHBox.set(playreadySystemID, byteCursor);
+ byteCursor += playreadySystemID.length;
+
+ PSSHData.setUint32(byteCursor, PROSize);
+ byteCursor += 0x4;
+
+ PSSHBox.set(uint8arraydecodedPROHeader, byteCursor);
+ byteCursor += PROSize;
+
+ return PSSHBox.buffer;
+ }
+
+ /**
+ * It seems that some PlayReady implementations return their XML-based CDM
+ * messages using UTF16, while others return them as UTF8. Use this function
+ * to modify the message format to expect when parsing CDM messages.
+ *
+ * @param {string} format the expected message format. Either "utf8" or "utf16".
+ * @throws {Error} Specified message format is not one of "utf8" or "utf16"
+ */
+ function setPlayReadyMessageFormat(format) {
+ if (format !== 'utf8' && format !== 'utf16') {
+ throw new _voError2['default']('Illegal PlayReady message format! -- ' + format);
+ }
+ messageFormat = format;
+ }
+
+ instance = {
+ uuid: uuid,
+ schemeIdURI: schemeIdURI,
+ systemString: systemString,
+ getInitData: getInitData,
+ getRequestHeadersFromMessage: getRequestHeadersFromMessage,
+ getLicenseRequestFromMessage: getLicenseRequestFromMessage,
+ getLicenseServerURLFromInitData: getLicenseServerURLFromInitData,
+ setPlayReadyMessageFormat: setPlayReadyMessageFormat
+ };
+
+ return instance;
+}
+
+KeySystemPlayReady.__dashjs_factory_name = 'KeySystemPlayReady';
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(KeySystemPlayReady);
+module.exports = exports['default'];
+
+},{"1":1,"10":10,"105":105,"162":162}],112:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * Google Widevine DRM
+ *
+ * @class
+ * @implements MediaPlayer.dependencies.protection.KeySystem
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _CommonEncryption = _dereq_(105);
+
+var _CommonEncryption2 = _interopRequireDefault(_CommonEncryption);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var uuid = 'edef8ba9-79d6-4ace-a3c8-27dcd51d21ed';
+var systemString = 'com.widevine.alpha';
+var schemeIdURI = 'urn:uuid:' + uuid;
+
+function KeySystemWidevine() {
+
+ var instance = undefined;
+
+ function getInitData(cp) {
+ return _CommonEncryption2['default'].parseInitDataFromContentProtection(cp);
+ }
+
+ function getRequestHeadersFromMessage() /*message*/{
+ return null;
+ }
+
+ function getLicenseRequestFromMessage(message) {
+ return new Uint8Array(message);
+ }
+
+ function getLicenseServerURLFromInitData() /*initData*/{
+ return null;
+ }
+
+ instance = {
+ uuid: uuid,
+ schemeIdURI: schemeIdURI,
+ systemString: systemString,
+ getInitData: getInitData,
+ getRequestHeadersFromMessage: getRequestHeadersFromMessage,
+ getLicenseRequestFromMessage: getLicenseRequestFromMessage,
+ getLicenseServerURLFromInitData: getLicenseServerURLFromInitData
+ };
+
+ return instance;
+}
+
+KeySystemWidevine.__dashjs_factory_name = 'KeySystemWidevine';
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(KeySystemWidevine);
+module.exports = exports['default'];
+
+},{"10":10,"105":105}],113:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * Initial implementation of EME
+ *
+ * Implemented by Google Chrome prior to v36
+ *
+ * @implements ProtectionModel
+ * @class
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _controllersProtectionKeyController = _dereq_(109);
+
+var _controllersProtectionKeyController2 = _interopRequireDefault(_controllersProtectionKeyController);
+
+var _voNeedKey = _dereq_(127);
+
+var _voNeedKey2 = _interopRequireDefault(_voNeedKey);
+
+var _voKeyError = _dereq_(121);
+
+var _voKeyError2 = _interopRequireDefault(_voKeyError);
+
+var _voKeyMessage = _dereq_(122);
+
+var _voKeyMessage2 = _interopRequireDefault(_voKeyMessage);
+
+var _voKeySystemConfiguration = _dereq_(125);
+
+var _voKeySystemConfiguration2 = _interopRequireDefault(_voKeySystemConfiguration);
+
+var _voKeySystemAccess = _dereq_(124);
+
+var _voKeySystemAccess2 = _interopRequireDefault(_voKeySystemAccess);
+
+var _coreEventsEvents = _dereq_(13);
+
+var _coreEventsEvents2 = _interopRequireDefault(_coreEventsEvents);
+
+var _utilsErrorHandler = _dereq_(151);
+
+var _utilsErrorHandler2 = _interopRequireDefault(_utilsErrorHandler);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+function ProtectionModel_01b(config) {
+
+ var context = this.context;
+ var eventBus = config.eventBus; //Need to pass in here so we can use same instance since this is optional module
+ var log = config.log;
+ var api = config.api;
+
+ var instance = undefined,
+ videoElement = undefined,
+ keySystem = undefined,
+ protectionKeyController = undefined,
+ errHandler = undefined,
+
+ // With this version of the EME APIs, sessionIDs are not assigned to
+ // sessions until the first key message is received. We are assuming
+ // that in the case of multiple sessions, key messages will be received
+ // in the order that generateKeyRequest() is called.
+ // Holding spot for newly-created sessions until we determine whether or
+ // not the CDM supports sessionIDs
+ pendingSessions = undefined,
+
+ // List of sessions that have been initialized. Only the first position will
+ // be used in the case that the CDM does not support sessionIDs
+ sessions = undefined,
+
+ // Not all CDMs support the notion of sessionIDs. Without sessionIDs
+ // there is no way for us to differentiate between sessions, therefore
+ // we must only allow a single session. Once we receive the first key
+ // message we can set this flag to determine if more sessions are allowed
+ moreSessionsAllowed = undefined,
+
+ // This is our main event handler for all desired HTMLMediaElement events
+ // related to EME. These events are translated into our API-independent
+ // versions of the same events
+ eventHandler = undefined;
+
+ function setup() {
+ videoElement = null;
+ keySystem = null;
+ pendingSessions = [];
+ sessions = [];
+ protectionKeyController = (0, _controllersProtectionKeyController2['default'])(context).getInstance();
+ errHandler = (0, _utilsErrorHandler2['default'])(context).getInstance();
+ eventHandler = createEventHandler();
+ }
+
+ function reset() {
+ if (videoElement) {
+ removeEventListeners();
+ }
+ for (var i = 0; i < sessions.length; i++) {
+ closeKeySession(sessions[i]);
+ }
+ eventBus.trigger(_coreEventsEvents2['default'].TEARDOWN_COMPLETE);
+ }
+
+ function getKeySystem() {
+ return keySystem;
+ }
+
+ function getAllInitData() {
+ var retVal = [];
+ for (var i = 0; i < pendingSessions.length; i++) {
+ retVal.push(pendingSessions[i].initData);
+ }
+ for (var i = 0; i < sessions.length; i++) {
+ retVal.push(sessions[i].initData);
+ }
+ return retVal;
+ }
+
+ function requestKeySystemAccess(ksConfigurations) {
+ var ve = videoElement;
+ if (!ve) {
+ // Must have a video element to do this capability tests
+ ve = document.createElement('video');
+ }
+
+ // Try key systems in order, first one with supported key system configuration
+ // is used
+ var found = false;
+ for (var ksIdx = 0; ksIdx < ksConfigurations.length; ksIdx++) {
+ var systemString = ksConfigurations[ksIdx].ks.systemString;
+ var configs = ksConfigurations[ksIdx].configs;
+ var supportedAudio = null;
+ var supportedVideo = null;
+
+ // Try key system configs in order, first one with supported audio/video
+ // is used
+ for (var configIdx = 0; configIdx < configs.length; configIdx++) {
+ //var audios = configs[configIdx].audioCapabilities;
+ var videos = configs[configIdx].videoCapabilities;
+ // Look for supported video container/codecs
+ if (videos && videos.length !== 0) {
+ supportedVideo = []; // Indicates that we have a requested video config
+ for (var videoIdx = 0; videoIdx < videos.length; videoIdx++) {
+ if (ve.canPlayType(videos[videoIdx].contentType, systemString) !== '') {
+ supportedVideo.push(videos[videoIdx]);
+ }
+ }
+ }
+
+ // No supported audio or video in this configuration OR we have
+ // requested audio or video configuration that is not supported
+ if (!supportedAudio && !supportedVideo || supportedAudio && supportedAudio.length === 0 || supportedVideo && supportedVideo.length === 0) {
+ continue;
+ }
+
+ // This configuration is supported
+ found = true;
+ var ksConfig = new _voKeySystemConfiguration2['default'](supportedAudio, supportedVideo);
+ var ks = protectionKeyController.getKeySystemBySystemString(systemString);
+ eventBus.trigger(_coreEventsEvents2['default'].KEY_SYSTEM_ACCESS_COMPLETE, { data: new _voKeySystemAccess2['default'](ks, ksConfig) });
+ break;
+ }
+ }
+ if (!found) {
+ eventBus.trigger(_coreEventsEvents2['default'].KEY_SYSTEM_ACCESS_COMPLETE, { error: 'Key system access denied! -- No valid audio/video content configurations detected!' });
+ }
+ }
+
+ function selectKeySystem(keySystemAccess) {
+ keySystem = keySystemAccess.keySystem;
+ eventBus.trigger(_coreEventsEvents2['default'].INTERNAL_KEY_SYSTEM_SELECTED);
+ }
+
+ function setMediaElement(mediaElement) {
+ if (videoElement === mediaElement) {
+ return;
+ }
+
+ // Replacing the previous element
+ if (videoElement) {
+ removeEventListeners();
+ }
+
+ videoElement = mediaElement;
+
+ // Only if we are not detaching from the existing element
+ if (videoElement) {
+ videoElement.addEventListener(api.keyerror, eventHandler);
+ videoElement.addEventListener(api.needkey, eventHandler);
+ videoElement.addEventListener(api.keymessage, eventHandler);
+ videoElement.addEventListener(api.keyadded, eventHandler);
+ eventBus.trigger(_coreEventsEvents2['default'].VIDEO_ELEMENT_SELECTED);
+ }
+ }
+
+ function createKeySession(initData /*, keySystemType */) {
+
+ if (!keySystem) {
+ throw new Error('Can not create sessions until you have selected a key system');
+ }
+
+ // Determine if creating a new session is allowed
+ if (moreSessionsAllowed || sessions.length === 0) {
+
+ var newSession = { // Implements SessionToken
+ sessionID: null,
+ initData: initData,
+ getSessionID: function getSessionID() {
+ return this.sessionID;
+ },
+
+ getExpirationTime: function getExpirationTime() {
+ return NaN;
+ },
+
+ getSessionType: function getSessionType() {
+ return 'temporary';
+ }
+ };
+ pendingSessions.push(newSession);
+
+ // Send our request to the CDM
+ videoElement[api.generateKeyRequest](keySystem.systemString, new Uint8Array(initData));
+
+ return newSession;
+ } else {
+ throw new Error('Multiple sessions not allowed!');
+ }
+ }
+
+ function updateKeySession(sessionToken, message) {
+ var sessionID = sessionToken.sessionID;
+ if (!protectionKeyController.isClearKey(keySystem)) {
+ // Send our request to the CDM
+ videoElement[api.addKey](keySystem.systemString, new Uint8Array(message), sessionToken.initData, sessionID);
+ } else {
+ // For clearkey, message is a ClearKeyKeySet
+ for (var i = 0; i < message.keyPairs.length; i++) {
+ videoElement[api.addKey](keySystem.systemString, message.keyPairs[i].key, message.keyPairs[i].keyID, sessionID);
+ }
+ }
+ }
+
+ function closeKeySession(sessionToken) {
+ // Send our request to the CDM
+ videoElement[api.cancelKeyRequest](keySystem.systemString, sessionToken.sessionID);
+ }
+
+ function setServerCertificate() /*serverCertificate*/{/* Not supported */}
+ function loadKeySession() /*sessionID*/{/* Not supported */}
+ function removeKeySession() /*sessionToken*/{/* Not supported */}
+
+ function createEventHandler() {
+ return {
+ handleEvent: function handleEvent(event) {
+ var sessionToken = null;
+ switch (event.type) {
+
+ case api.needkey:
+ var initData = ArrayBuffer.isView(event.initData) ? event.initData.buffer : event.initData;
+ eventBus.trigger(_coreEventsEvents2['default'].NEED_KEY, { key: new _voNeedKey2['default'](initData, 'cenc') });
+ break;
+
+ case api.keyerror:
+ sessionToken = findSessionByID(sessions, event.sessionId);
+ if (!sessionToken) {
+ sessionToken = findSessionByID(pendingSessions, event.sessionId);
+ }
+
+ if (sessionToken) {
+ var msg = '';
+ switch (event.errorCode.code) {
+ case 1:
+ msg += 'MEDIA_KEYERR_UNKNOWN - An unspecified error occurred. This value is used for errors that don\'t match any of the other codes.';
+ break;
+ case 2:
+ msg += 'MEDIA_KEYERR_CLIENT - The Key System could not be installed or updated.';
+ break;
+ case 3:
+ msg += 'MEDIA_KEYERR_SERVICE - The message passed into update indicated an error from the license service.';
+ break;
+ case 4:
+ msg += 'MEDIA_KEYERR_OUTPUT - There is no available output device with the required characteristics for the content protection system.';
+ break;
+ case 5:
+ msg += 'MEDIA_KEYERR_HARDWARECHANGE - A hardware configuration change caused a content protection error.';
+ break;
+ case 6:
+ msg += 'MEDIA_KEYERR_DOMAIN - An error occurred in a multi-device domain licensing configuration. The most common error is a failure to join the domain.';
+ break;
+ }
+ msg += ' System Code = ' + event.systemCode;
+ // TODO: Build error string based on key error
+ eventBus.trigger(_coreEventsEvents2['default'].KEY_ERROR, { data: new _voKeyError2['default'](sessionToken, msg) });
+ } else {
+ log('No session token found for key error');
+ }
+ break;
+
+ case api.keyadded:
+ sessionToken = findSessionByID(sessions, event.sessionId);
+ if (!sessionToken) {
+ sessionToken = findSessionByID(pendingSessions, event.sessionId);
+ }
+
+ if (sessionToken) {
+ log('DRM: Key added.');
+ eventBus.trigger(_coreEventsEvents2['default'].KEY_ADDED, { data: sessionToken }); //TODO not sure anything is using sessionToken? why there?
+ } else {
+ log('No session token found for key added');
+ }
+ break;
+
+ case api.keymessage:
+
+ // If this CDM does not support session IDs, we will be limited
+ // to a single session
+ moreSessionsAllowed = event.sessionId !== null && event.sessionId !== undefined;
+
+ // SessionIDs supported
+ if (moreSessionsAllowed) {
+
+ // Attempt to find an uninitialized token with this sessionID
+ sessionToken = findSessionByID(sessions, event.sessionId);
+ if (!sessionToken && pendingSessions.length > 0) {
+
+ // This is the first message for our latest session, so set the
+ // sessionID and add it to our list
+ sessionToken = pendingSessions.shift();
+ sessions.push(sessionToken);
+ sessionToken.sessionID = event.sessionId;
+ }
+ } else if (pendingSessions.length > 0) {
+ // SessionIDs not supported
+
+ sessionToken = pendingSessions.shift();
+ sessions.push(sessionToken);
+
+ if (pendingSessions.length !== 0) {
+ errHandler.mediaKeyMessageError('Multiple key sessions were creates with a user-agent that does not support sessionIDs!! Unpredictable behavior ahead!');
+ }
+ }
+
+ if (sessionToken) {
+ var message = ArrayBuffer.isView(event.message) ? event.message.buffer : event.message;
+
+ // For ClearKey, the spec mandates that you pass this message to the
+ // addKey method, so we always save it to the token since there is no
+ // way to tell which key system is in use
+ sessionToken.keyMessage = message;
+ eventBus.trigger(_coreEventsEvents2['default'].INTERNAL_KEY_MESSAGE, { data: new _voKeyMessage2['default'](sessionToken, message, event.defaultURL) });
+ } else {
+ log('No session token found for key message');
+ }
+ break;
+ }
+ }
+ };
+ }
+
+ /**
+ * Helper function to retrieve the stored session token based on a given
+ * sessionID value
+ *
+ * @param {Array} sessionArray - the array of sessions to search
+ * @param {*} sessionID - the sessionID to search for
+ * @returns {*} the session token with the given sessionID
+ */
+ function findSessionByID(sessionArray, sessionID) {
+
+ if (!sessionID || !sessionArray) {
+ return null;
+ } else {
+ var len = sessionArray.length;
+ for (var i = 0; i < len; i++) {
+ if (sessionArray[i].sessionID == sessionID) {
+ return sessionArray[i];
+ }
+ }
+ return null;
+ }
+ }
+
+ function removeEventListeners() {
+ videoElement.removeEventListener(api.keyerror, eventHandler);
+ videoElement.removeEventListener(api.needkey, eventHandler);
+ videoElement.removeEventListener(api.keymessage, eventHandler);
+ videoElement.removeEventListener(api.keyadded, eventHandler);
+ }
+
+ instance = {
+ getAllInitData: getAllInitData,
+ requestKeySystemAccess: requestKeySystemAccess,
+ getKeySystem: getKeySystem,
+ selectKeySystem: selectKeySystem,
+ setMediaElement: setMediaElement,
+ createKeySession: createKeySession,
+ updateKeySession: updateKeySession,
+ closeKeySession: closeKeySession,
+ setServerCertificate: setServerCertificate,
+ loadKeySession: loadKeySession,
+ removeKeySession: removeKeySession,
+ reset: reset
+ };
+
+ setup();
+
+ return instance;
+}
+
+ProtectionModel_01b.__dashjs_factory_name = 'ProtectionModel_01b';
+exports['default'] = _coreFactoryMaker2['default'].getClassFactory(ProtectionModel_01b);
+module.exports = exports['default'];
+
+},{"10":10,"109":109,"121":121,"122":122,"124":124,"125":125,"127":127,"13":13,"151":151}],114:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * Most recent EME implementation
+ *
+ * Implemented by Google Chrome v36+ (Windows, OSX, Linux)
+ *
+ * @implements ProtectionModel
+ * @class
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _controllersProtectionKeyController = _dereq_(109);
+
+var _controllersProtectionKeyController2 = _interopRequireDefault(_controllersProtectionKeyController);
+
+var _voNeedKey = _dereq_(127);
+
+var _voNeedKey2 = _interopRequireDefault(_voNeedKey);
+
+var _voKeyError = _dereq_(121);
+
+var _voKeyError2 = _interopRequireDefault(_voKeyError);
+
+var _voKeyMessage = _dereq_(122);
+
+var _voKeyMessage2 = _interopRequireDefault(_voKeyMessage);
+
+var _voKeySystemAccess = _dereq_(124);
+
+var _voKeySystemAccess2 = _interopRequireDefault(_voKeySystemAccess);
+
+var _coreEventsEvents = _dereq_(13);
+
+var _coreEventsEvents2 = _interopRequireDefault(_coreEventsEvents);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+function ProtectionModel_21Jan2015(config) {
+
+ var context = this.context;
+ var eventBus = config.eventBus; //Need to pass in here so we can use same instance since this is optional module
+ var log = config.log;
+
+ var instance, keySystem, videoElement, mediaKeys, sessions, eventHandler, protectionKeyController;
+
+ function setup() {
+ keySystem = null;
+ videoElement = null;
+ mediaKeys = null;
+ sessions = [];
+ protectionKeyController = (0, _controllersProtectionKeyController2['default'])(context).getInstance();
+ eventHandler = createEventHandler();
+ }
+
+ function reset() {
+ var numSessions = sessions.length;
+ var session;
+
+ if (numSessions !== 0) {
+ // Called when we are done closing a session. Success or fail
+ var done = function done(session) {
+ removeSession(session);
+ if (sessions.length === 0) {
+ if (videoElement) {
+ videoElement.removeEventListener('encrypted', eventHandler);
+ videoElement.setMediaKeys(null).then(function () {
+ eventBus.trigger(_coreEventsEvents2['default'].TEARDOWN_COMPLETE);
+ });
+ } else {
+ eventBus.trigger(_coreEventsEvents2['default'].TEARDOWN_COMPLETE);
+ }
+ }
+ };
+ for (var i = 0; i < numSessions; i++) {
+ session = sessions[i];
+ (function (s) {
+ // Override closed promise resolver
+ session.session.closed.then(function () {
+ done(s);
+ });
+ // Close the session and handle errors, otherwise promise
+ // resolver above will be called
+ closeKeySessionInternal(session)['catch'](function () {
+ done(s);
+ });
+ })(session);
+ }
+ } else {
+ eventBus.trigger(_coreEventsEvents2['default'].TEARDOWN_COMPLETE);
+ }
+ }
+
+ function getKeySystem() {
+ return keySystem;
+ }
+
+ function getAllInitData() {
+ var retVal = [];
+ for (var i = 0; i < sessions.length; i++) {
+ retVal.push(sessions[i].initData);
+ }
+ return retVal;
+ }
+
+ function requestKeySystemAccess(ksConfigurations) {
+ requestKeySystemAccessInternal(ksConfigurations, 0);
+ }
+
+ function selectKeySystem(keySystemAccess) {
+ keySystemAccess.mksa.createMediaKeys().then(function (mkeys) {
+ keySystem = keySystemAccess.keySystem;
+ mediaKeys = mkeys;
+ if (videoElement) {
+ videoElement.setMediaKeys(mediaKeys);
+ }
+ eventBus.trigger(_coreEventsEvents2['default'].INTERNAL_KEY_SYSTEM_SELECTED);
+ })['catch'](function () {
+ eventBus.trigger(_coreEventsEvents2['default'].INTERNAL_KEY_SYSTEM_SELECTED, { error: 'Error selecting keys system (' + keySystemAccess.keySystem.systemString + ')! Could not create MediaKeys -- TODO' });
+ });
+ }
+
+ function setMediaElement(mediaElement) {
+ if (videoElement === mediaElement) return;
+
+ // Replacing the previous element
+ if (videoElement) {
+ videoElement.removeEventListener('encrypted', eventHandler);
+ videoElement.setMediaKeys(null);
+ }
+
+ videoElement = mediaElement;
+
+ // Only if we are not detaching from the existing element
+ if (videoElement) {
+ videoElement.addEventListener('encrypted', eventHandler);
+ if (mediaKeys) {
+ videoElement.setMediaKeys(mediaKeys);
+ }
+ }
+ }
+
+ function setServerCertificate(serverCertificate) {
+ if (!keySystem || !mediaKeys) {
+ throw new Error('Can not set server certificate until you have selected a key system');
+ }
+ mediaKeys.setServerCertificate(serverCertificate).then(function () {
+ log('DRM: License server certificate successfully updated.');
+ eventBus.trigger(_coreEventsEvents2['default'].SERVER_CERTIFICATE_UPDATED);
+ })['catch'](function (error) {
+ eventBus.trigger(_coreEventsEvents2['default'].SERVER_CERTIFICATE_UPDATED, { error: 'Error updating server certificate -- ' + error.name });
+ });
+ }
+
+ function createKeySession(initData, sessionType) {
+
+ if (!keySystem || !mediaKeys) {
+ throw new Error('Can not create sessions until you have selected a key system');
+ }
+
+ var session = mediaKeys.createSession(sessionType);
+ var sessionToken = createSessionToken(session, initData, sessionType);
+
+ // Generate initial key request
+ session.generateRequest('cenc', initData).then(function () {
+ log('DRM: Session created. SessionID = ' + sessionToken.getSessionID());
+ eventBus.trigger(_coreEventsEvents2['default'].KEY_SESSION_CREATED, { data: sessionToken });
+ })['catch'](function (error) {
+ // TODO: Better error string
+ removeSession(sessionToken);
+ eventBus.trigger(_coreEventsEvents2['default'].KEY_SESSION_CREATED, { data: null, error: 'Error generating key request -- ' + error.name });
+ });
+ }
+
+ function updateKeySession(sessionToken, message) {
+
+ var session = sessionToken.session;
+
+ // Send our request to the key session
+ if (protectionKeyController.isClearKey(keySystem)) {
+ message = message.toJWK();
+ }
+ session.update(message)['catch'](function (error) {
+ eventBus.trigger(_coreEventsEvents2['default'].KEY_ERROR, { data: new _voKeyError2['default'](sessionToken, 'Error sending update() message! ' + error.name) });
+ });
+ }
+
+ function loadKeySession(sessionID) {
+ if (!keySystem || !mediaKeys) {
+ throw new Error('Can not load sessions until you have selected a key system');
+ }
+
+ var session = mediaKeys.createSession();
+
+ // Load persisted session data into our newly created session object
+ session.load(sessionID).then(function (success) {
+ if (success) {
+ var sessionToken = createSessionToken(session);
+ log('DRM: Session created. SessionID = ' + sessionToken.getSessionID());
+ eventBus.trigger(_coreEventsEvents2['default'].KEY_SESSION_CREATED, { data: sessionToken });
+ } else {
+ eventBus.trigger(_coreEventsEvents2['default'].KEY_SESSION_CREATED, { data: null, error: 'Could not load session! Invalid Session ID (' + sessionID + ')' });
+ }
+ })['catch'](function (error) {
+ eventBus.trigger(_coreEventsEvents2['default'].KEY_SESSION_CREATED, { data: null, error: 'Could not load session (' + sessionID + ')! ' + error.name });
+ });
+ }
+
+ function removeKeySession(sessionToken) {
+ var session = sessionToken.session;
+
+ session.remove().then(function () {
+ log('DRM: Session removed. SessionID = ' + sessionToken.getSessionID());
+ eventBus.trigger(_coreEventsEvents2['default'].KEY_SESSION_REMOVED, { data: sessionToken.getSessionID() });
+ }, function (error) {
+ eventBus.trigger(_coreEventsEvents2['default'].KEY_SESSION_REMOVED, { data: null, error: 'Error removing session (' + sessionToken.getSessionID() + '). ' + error.name });
+ });
+ }
+
+ function closeKeySession(sessionToken) {
+ // Send our request to the key session
+ closeKeySessionInternal(sessionToken)['catch'](function (error) {
+ removeSession(sessionToken);
+ eventBus.trigger(_coreEventsEvents2['default'].KEY_SESSION_CLOSED, { data: null, error: 'Error closing session (' + sessionToken.getSessionID() + ') ' + error.name });
+ });
+ }
+
+ function requestKeySystemAccessInternal(ksConfigurations, idx) {
+ (function (i) {
+ var keySystem = ksConfigurations[i].ks;
+ var configs = ksConfigurations[i].configs;
+ navigator.requestMediaKeySystemAccess(keySystem.systemString, configs).then(function (mediaKeySystemAccess) {
+
+ // Chrome 40 does not currently implement MediaKeySystemAccess.getConfiguration()
+ var configuration = typeof mediaKeySystemAccess.getConfiguration === 'function' ? mediaKeySystemAccess.getConfiguration() : null;
+ var keySystemAccess = new _voKeySystemAccess2['default'](keySystem, configuration);
+ keySystemAccess.mksa = mediaKeySystemAccess;
+ eventBus.trigger(_coreEventsEvents2['default'].KEY_SYSTEM_ACCESS_COMPLETE, { data: keySystemAccess });
+ })['catch'](function () {
+ if (++i < ksConfigurations.length) {
+ requestKeySystemAccessInternal(ksConfigurations, i);
+ } else {
+ eventBus.trigger(_coreEventsEvents2['default'].KEY_SYSTEM_ACCESS_COMPLETE, { error: 'Key system access denied!' });
+ }
+ });
+ })(idx);
+ }
+
+ function closeKeySessionInternal(sessionToken) {
+ var session = sessionToken.session;
+
+ // Remove event listeners
+ session.removeEventListener('keystatuseschange', sessionToken);
+ session.removeEventListener('message', sessionToken);
+
+ // Send our request to the key session
+ return session.close();
+ }
+
+ // This is our main event handler for all desired HTMLMediaElement events
+ // related to EME. These events are translated into our API-independent
+ // versions of the same events
+ function createEventHandler() {
+ return {
+ handleEvent: function handleEvent(event) {
+ switch (event.type) {
+
+ case 'encrypted':
+ if (event.initData) {
+ var initData = ArrayBuffer.isView(event.initData) ? event.initData.buffer : event.initData;
+ eventBus.trigger(_coreEventsEvents2['default'].NEED_KEY, { key: new _voNeedKey2['default'](initData, event.initDataType) });
+ }
+ break;
+ }
+ }
+ };
+ }
+
+ function removeSession(token) {
+ // Remove from our session list
+ for (var i = 0; i < sessions.length; i++) {
+ if (sessions[i] === token) {
+ sessions.splice(i, 1);
+ break;
+ }
+ }
+ }
+
+ // Function to create our session token objects which manage the EME
+ // MediaKeySession and session-specific event handler
+ function createSessionToken(session, initData, sessionType) {
+
+ var token = { // Implements SessionToken
+ session: session,
+ initData: initData,
+
+ // This is our main event handler for all desired MediaKeySession events
+ // These events are translated into our API-independent versions of the
+ // same events
+ handleEvent: function handleEvent(event) {
+ switch (event.type) {
+ case 'keystatuseschange':
+ eventBus.trigger(_coreEventsEvents2['default'].KEY_STATUSES_CHANGED, { data: this });
+ break;
+
+ case 'message':
+ var message = ArrayBuffer.isView(event.message) ? event.message.buffer : event.message;
+ eventBus.trigger(_coreEventsEvents2['default'].INTERNAL_KEY_MESSAGE, { data: new _voKeyMessage2['default'](this, message, undefined, event.messageType) });
+ break;
+ }
+ },
+
+ getSessionID: function getSessionID() {
+ return session.sessionId;
+ },
+
+ getExpirationTime: function getExpirationTime() {
+ return session.expiration;
+ },
+
+ getKeyStatuses: function getKeyStatuses() {
+ return session.keyStatuses;
+ },
+
+ getSessionType: function getSessionType() {
+ return sessionType;
+ }
+ };
+
+ // Add all event listeners
+ session.addEventListener('keystatuseschange', token);
+ session.addEventListener('message', token);
+
+ // Register callback for session closed Promise
+ session.closed.then(function () {
+ removeSession(token);
+ log('DRM: Session closed. SessionID = ' + token.getSessionID());
+ eventBus.trigger(_coreEventsEvents2['default'].KEY_SESSION_CLOSED, { data: token.getSessionID() });
+ });
+
+ // Add to our session list
+ sessions.push(token);
+
+ return token;
+ }
+
+ instance = {
+ getAllInitData: getAllInitData,
+ requestKeySystemAccess: requestKeySystemAccess,
+ getKeySystem: getKeySystem,
+ selectKeySystem: selectKeySystem,
+ setMediaElement: setMediaElement,
+ setServerCertificate: setServerCertificate,
+ createKeySession: createKeySession,
+ updateKeySession: updateKeySession,
+ loadKeySession: loadKeySession,
+ removeKeySession: removeKeySession,
+ closeKeySession: closeKeySession,
+ reset: reset
+ };
+
+ setup();
+
+ return instance;
+}
+
+ProtectionModel_21Jan2015.__dashjs_factory_name = 'ProtectionModel_21Jan2015';
+exports['default'] = _coreFactoryMaker2['default'].getClassFactory(ProtectionModel_21Jan2015);
+module.exports = exports['default'];
+
+},{"10":10,"109":109,"121":121,"122":122,"124":124,"127":127,"13":13}],115:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * Implementation of the EME APIs as of the 3 Feb 2014 state of the specification.
+ *
+ * Implemented by Internet Explorer 11 (Windows 8.1)
+ *
+ * @implements ProtectionModel
+ * @class
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _controllersProtectionKeyController = _dereq_(109);
+
+var _controllersProtectionKeyController2 = _interopRequireDefault(_controllersProtectionKeyController);
+
+var _voNeedKey = _dereq_(127);
+
+var _voNeedKey2 = _interopRequireDefault(_voNeedKey);
+
+var _voKeyError = _dereq_(121);
+
+var _voKeyError2 = _interopRequireDefault(_voKeyError);
+
+var _voKeyMessage = _dereq_(122);
+
+var _voKeyMessage2 = _interopRequireDefault(_voKeyMessage);
+
+var _voKeySystemConfiguration = _dereq_(125);
+
+var _voKeySystemConfiguration2 = _interopRequireDefault(_voKeySystemConfiguration);
+
+var _voKeySystemAccess = _dereq_(124);
+
+var _voKeySystemAccess2 = _interopRequireDefault(_voKeySystemAccess);
+
+var _coreEventsEvents = _dereq_(13);
+
+var _coreEventsEvents2 = _interopRequireDefault(_coreEventsEvents);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+function ProtectionModel_3Feb2014(config) {
+
+ var context = this.context;
+ var eventBus = config.eventBus; //Need to pass in here so we can use same instance since this is optional module
+ var log = config.log;
+ var api = config.api;
+
+ var instance = undefined,
+ videoElement = undefined,
+ keySystem = undefined,
+ mediaKeys = undefined,
+ keySystemAccess = undefined,
+ sessions = undefined,
+ eventHandler = undefined,
+ protectionKeyController = undefined;
+
+ function setup() {
+ videoElement = null;
+ keySystem = null;
+ mediaKeys = null;
+ keySystemAccess = null;
+ sessions = [];
+ protectionKeyController = (0, _controllersProtectionKeyController2['default'])(context).getInstance();
+ eventHandler = createEventHandler();
+ }
+
+ function reset() {
+ try {
+ for (var i = 0; i < sessions.length; i++) {
+ closeKeySession(sessions[i]);
+ }
+ if (videoElement) {
+ videoElement.removeEventListener(api.needkey, eventHandler);
+ }
+ eventBus.trigger(_coreEventsEvents2['default'].TEARDOWN_COMPLETE);
+ } catch (error) {
+ eventBus.trigger(_coreEventsEvents2['default'].TEARDOWN_COMPLETE, { error: 'Error tearing down key sessions and MediaKeys! -- ' + error.message });
+ }
+ }
+
+ function getKeySystem() {
+ return keySystem;
+ }
+
+ function getAllInitData() {
+ var retVal = [];
+ for (var i = 0; i < sessions.length; i++) {
+ retVal.push(sessions[i].initData);
+ }
+ return retVal;
+ }
+
+ function requestKeySystemAccess(ksConfigurations) {
+
+ // Try key systems in order, first one with supported key system configuration
+ // is used
+ var found = false;
+ for (var ksIdx = 0; ksIdx < ksConfigurations.length; ksIdx++) {
+ var systemString = ksConfigurations[ksIdx].ks.systemString;
+ var configs = ksConfigurations[ksIdx].configs;
+ var supportedAudio = null;
+ var supportedVideo = null;
+
+ // Try key system configs in order, first one with supported audio/video
+ // is used
+ for (var configIdx = 0; configIdx < configs.length; configIdx++) {
+ var audios = configs[configIdx].audioCapabilities;
+ var videos = configs[configIdx].videoCapabilities;
+
+ // Look for supported audio container/codecs
+ if (audios && audios.length !== 0) {
+ supportedAudio = []; // Indicates that we have a requested audio config
+ for (var audioIdx = 0; audioIdx < audios.length; audioIdx++) {
+ if (window[api.MediaKeys].isTypeSupported(systemString, audios[audioIdx].contentType)) {
+ supportedAudio.push(audios[audioIdx]);
+ }
+ }
+ }
+
+ // Look for supported video container/codecs
+ if (videos && videos.length !== 0) {
+ supportedVideo = []; // Indicates that we have a requested video config
+ for (var videoIdx = 0; videoIdx < videos.length; videoIdx++) {
+ if (window[api.MediaKeys].isTypeSupported(systemString, videos[videoIdx].contentType)) {
+ supportedVideo.push(videos[videoIdx]);
+ }
+ }
+ }
+
+ // No supported audio or video in this configuration OR we have
+ // requested audio or video configuration that is not supported
+ if (!supportedAudio && !supportedVideo || supportedAudio && supportedAudio.length === 0 || supportedVideo && supportedVideo.length === 0) {
+ continue;
+ }
+
+ // This configuration is supported
+ found = true;
+ var ksConfig = new _voKeySystemConfiguration2['default'](supportedAudio, supportedVideo);
+ var ks = protectionKeyController.getKeySystemBySystemString(systemString);
+ eventBus.trigger(_coreEventsEvents2['default'].KEY_SYSTEM_ACCESS_COMPLETE, { data: new _voKeySystemAccess2['default'](ks, ksConfig) });
+ break;
+ }
+ }
+ if (!found) {
+ eventBus.trigger(_coreEventsEvents2['default'].KEY_SYSTEM_ACCESS_COMPLETE, { error: 'Key system access denied! -- No valid audio/video content configurations detected!' });
+ }
+ }
+
+ function selectKeySystem(ksAccess) {
+ try {
+ mediaKeys = ksAccess.mediaKeys = new window[api.MediaKeys](ksAccess.keySystem.systemString);
+ keySystem = ksAccess.keySystem;
+ keySystemAccess = ksAccess;
+ if (videoElement) {
+ setMediaKeys();
+ }
+ eventBus.trigger(_coreEventsEvents2['default'].INTERNAL_KEY_SYSTEM_SELECTED);
+ } catch (error) {
+ eventBus.trigger(_coreEventsEvents2['default'].INTERNAL_KEY_SYSTEM_SELECTED, { error: 'Error selecting keys system (' + keySystem.systemString + ')! Could not create MediaKeys -- TODO' });
+ }
+ }
+
+ function setMediaElement(mediaElement) {
+ if (videoElement === mediaElement) return;
+
+ // Replacing the previous element
+ if (videoElement) {
+ videoElement.removeEventListener(api.needkey, eventHandler);
+ }
+
+ videoElement = mediaElement;
+
+ // Only if we are not detaching from the existing element
+ if (videoElement) {
+ videoElement.addEventListener(api.needkey, eventHandler);
+ if (mediaKeys) {
+ setMediaKeys();
+ }
+ }
+ }
+
+ function createKeySession(initData /*, keySystemType */) {
+
+ if (!keySystem || !mediaKeys || !keySystemAccess) {
+ throw new Error('Can not create sessions until you have selected a key system');
+ }
+
+ // Use the first video capability for the contentType.
+ // TODO: Not sure if there is a way to concatenate all capability data into a RFC6386-compatible format
+
+ // If player is trying to playback Audio only stream - don't error out.
+ var capabilities = null;
+
+ if (keySystemAccess.ksConfiguration.videoCapabilities !== null && keySystemAccess.ksConfiguration.videoCapabilities.length > 0) capabilities = keySystemAccess.ksConfiguration.videoCapabilities[0];
+
+ if (capabilities === null && keySystemAccess.ksConfiguration.audioCapabilities !== null && keySystemAccess.ksConfiguration.audioCapabilities.length > 0) capabilities = keySystemAccess.ksConfiguration.audioCapabilities[0];
+
+ if (capabilities === null) throw new Error('Can not create sessions for unknown content types.');
+
+ var contentType = capabilities.contentType;
+ var session = mediaKeys.createSession(contentType, new Uint8Array(initData));
+ var sessionToken = createSessionToken(session, initData);
+
+ // Add all event listeners
+ session.addEventListener(api.error, sessionToken);
+ session.addEventListener(api.message, sessionToken);
+ session.addEventListener(api.ready, sessionToken);
+ session.addEventListener(api.close, sessionToken);
+
+ // Add to our session list
+ sessions.push(sessionToken);
+ log('DRM: Session created. SessionID = ' + sessionToken.getSessionID());
+ eventBus.trigger(_coreEventsEvents2['default'].KEY_SESSION_CREATED, { data: sessionToken });
+ }
+
+ function updateKeySession(sessionToken, message) {
+
+ var session = sessionToken.session;
+
+ if (!protectionKeyController.isClearKey(keySystem)) {
+ // Send our request to the key session
+ session.update(new Uint8Array(message));
+ } else {
+ // For clearkey, message is a ClearKeyKeySet
+ session.update(new Uint8Array(message.toJWK()));
+ }
+ }
+
+ /**
+ * Close the given session and release all associated keys. Following
+ * this call, the sessionToken becomes invalid
+ *
+ * @param {Object} sessionToken - the session token
+ */
+ function closeKeySession(sessionToken) {
+
+ var session = sessionToken.session;
+
+ // Remove event listeners
+ session.removeEventListener(api.error, sessionToken);
+ session.removeEventListener(api.message, sessionToken);
+ session.removeEventListener(api.ready, sessionToken);
+ session.removeEventListener(api.close, sessionToken);
+
+ // Remove from our session list
+ for (var i = 0; i < sessions.length; i++) {
+ if (sessions[i] === sessionToken) {
+ sessions.splice(i, 1);
+ break;
+ }
+ }
+
+ // Send our request to the key session
+ session[api.release]();
+ }
+
+ function setServerCertificate() /*serverCertificate*/{/* Not supported */}
+ function loadKeySession() /*sessionID*/{/* Not supported */}
+ function removeKeySession() /*sessionToken*/{/* Not supported */}
+
+ function createEventHandler() {
+ return {
+ handleEvent: function handleEvent(event) {
+ switch (event.type) {
+
+ case api.needkey:
+ if (event.initData) {
+ var initData = ArrayBuffer.isView(event.initData) ? event.initData.buffer : event.initData;
+ eventBus.trigger(_coreEventsEvents2['default'].NEED_KEY, { key: new _voNeedKey2['default'](initData, 'cenc') });
+ }
+ break;
+ }
+ }
+ };
+ }
+
+ // IE11 does not let you set MediaKeys until it has entered a certain
+ // readyState, so we need this logic to ensure we don't set the keys
+ // too early
+ function setMediaKeys() {
+ var boundDoSetKeys = null;
+ var doSetKeys = function doSetKeys() {
+ videoElement.removeEventListener('loadedmetadata', boundDoSetKeys);
+ videoElement[api.setMediaKeys](mediaKeys);
+ eventBus.trigger(_coreEventsEvents2['default'].VIDEO_ELEMENT_SELECTED);
+ };
+ if (videoElement.readyState >= 1) {
+ doSetKeys();
+ } else {
+ boundDoSetKeys = doSetKeys.bind(this);
+ videoElement.addEventListener('loadedmetadata', boundDoSetKeys);
+ }
+ }
+
+ // Function to create our session token objects which manage the EME
+ // MediaKeySession and session-specific event handler
+ function createSessionToken(keySession, initData) {
+ return {
+ // Implements SessionToken
+ session: keySession,
+ initData: initData,
+
+ getSessionID: function getSessionID() {
+ return this.session.sessionId;
+ },
+
+ getExpirationTime: function getExpirationTime() {
+ return NaN;
+ },
+
+ getSessionType: function getSessionType() {
+ return 'temporary';
+ },
+ // This is our main event handler for all desired MediaKeySession events
+ // These events are translated into our API-independent versions of the
+ // same events
+ handleEvent: function handleEvent(event) {
+ switch (event.type) {
+
+ case api.error:
+ var errorStr = 'KeyError'; // TODO: Make better string from event
+ eventBus.trigger(_coreEventsEvents2['default'].KEY_ERROR, { data: new _voKeyError2['default'](this, errorStr) });
+ break;
+ case api.message:
+ var message = ArrayBuffer.isView(event.message) ? event.message.buffer : event.message;
+ eventBus.trigger(_coreEventsEvents2['default'].INTERNAL_KEY_MESSAGE, { data: new _voKeyMessage2['default'](this, message, event.destinationURL) });
+ break;
+ case api.ready:
+ log('DRM: Key added.');
+ eventBus.trigger(_coreEventsEvents2['default'].KEY_ADDED);
+ break;
+
+ case api.close:
+ log('DRM: Session closed. SessionID = ' + this.getSessionID());
+ eventBus.trigger(_coreEventsEvents2['default'].KEY_SESSION_CLOSED, { data: this.getSessionID() });
+ break;
+ }
+ }
+ };
+ }
+
+ instance = {
+ getAllInitData: getAllInitData,
+ requestKeySystemAccess: requestKeySystemAccess,
+ getKeySystem: getKeySystem,
+ selectKeySystem: selectKeySystem,
+ setMediaElement: setMediaElement,
+ createKeySession: createKeySession,
+ updateKeySession: updateKeySession,
+ closeKeySession: closeKeySession,
+ setServerCertificate: setServerCertificate,
+ loadKeySession: loadKeySession,
+ removeKeySession: removeKeySession,
+ reset: reset
+ };
+
+ setup();
+
+ return instance;
+}
+
+ProtectionModel_3Feb2014.__dashjs_factory_name = 'ProtectionModel_3Feb2014';
+exports['default'] = _coreFactoryMaker2['default'].getClassFactory(ProtectionModel_3Feb2014);
+module.exports = exports['default'];
+
+},{"10":10,"109":109,"121":121,"122":122,"124":124,"125":125,"127":127,"13":13}],116:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * CableLabs ClearKey license server implementation
+ *
+ * For testing purposes and evaluating potential uses for ClearKey, we have developed
+ * a dirt-simple API for requesting ClearKey licenses from a remote server.
+ *
+ * @implements LicenseServer
+ * @class
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _voKeyPair = _dereq_(123);
+
+var _voKeyPair2 = _interopRequireDefault(_voKeyPair);
+
+var _voClearKeyKeySet = _dereq_(120);
+
+var _voClearKeyKeySet2 = _interopRequireDefault(_voClearKeyKeySet);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+function ClearKey() {
+
+ var instance = undefined;
+
+ function getServerURLFromMessage(url, message /*, messageType*/) {
+ // Build ClearKey server query string
+ var jsonMsg = JSON.parse(String.fromCharCode.apply(null, new Uint8Array(message)));
+ url += '/?';
+ for (var i = 0; i < jsonMsg.kids.length; i++) {
+ url += jsonMsg.kids[i] + '&';
+ }
+ url = url.substring(0, url.length - 1);
+ return url;
+ }
+
+ function getHTTPMethod() /*messageType*/{
+ return 'GET';
+ }
+
+ function getResponseType() /*keySystemStr*/{
+ return 'json';
+ }
+
+ function getLicenseMessage(serverResponse /*, keySystemStr, messageType*/) {
+ if (!serverResponse.hasOwnProperty('keys')) {
+ return null;
+ }
+ var keyPairs = [];
+ for (var i = 0; i < serverResponse.keys.length; i++) {
+ var keypair = serverResponse.keys[i];
+ var keyid = keypair.kid.replace(/=/g, '');
+ var key = keypair.k.replace(/=/g, '');
+
+ keyPairs.push(new _voKeyPair2['default'](keyid, key));
+ }
+ return new _voClearKeyKeySet2['default'](keyPairs);
+ }
+
+ function getErrorResponse(serverResponse /*, keySystemStr, messageType*/) {
+ return String.fromCharCode.apply(null, new Uint8Array(serverResponse));
+ }
+
+ instance = {
+ getServerURLFromMessage: getServerURLFromMessage,
+ getHTTPMethod: getHTTPMethod,
+ getResponseType: getResponseType,
+ getLicenseMessage: getLicenseMessage,
+ getErrorResponse: getErrorResponse
+ };
+
+ return instance;
+}
+
+ClearKey.__dashjs_factory_name = 'ClearKey';
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(ClearKey);
+module.exports = exports['default'];
+
+},{"10":10,"120":120,"123":123}],117:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * CastLabs DRMToday License Server implementation
+ *
+ * @implements LicenseServer
+ * @class
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _externalsBase64 = _dereq_(1);
+
+var _externalsBase642 = _interopRequireDefault(_externalsBase64);
+
+function DRMToday() {
+
+ var keySystems = {
+ 'com.widevine.alpha': {
+ responseType: 'json',
+ getLicenseMessage: function getLicenseMessage(response) {
+ return _externalsBase642['default'].decodeArray(response.license);
+ },
+ getErrorResponse: function getErrorResponse(response) {
+ return response;
+ }
+ },
+ 'com.microsoft.playready': {
+ responseType: 'arraybuffer',
+ getLicenseMessage: function getLicenseMessage(response) {
+ return response;
+ },
+ getErrorResponse: function getErrorResponse(response) {
+ return String.fromCharCode.apply(null, new Uint8Array(response));
+ }
+ }
+ };
+
+ var instance = undefined;
+
+ function getServerURLFromMessage(url /*, message, messageType*/) {
+ return url;
+ }
+
+ function getHTTPMethod() /*messageType*/{
+ return 'POST';
+ }
+
+ function getResponseType(keySystemStr /*, messageType*/) {
+ return keySystems[keySystemStr].responseType;
+ }
+
+ function getLicenseMessage(serverResponse, keySystemStr /*, messageType*/) {
+ return keySystems[keySystemStr].getLicenseMessage(serverResponse);
+ }
+
+ function getErrorResponse(serverResponse, keySystemStr /*, messageType*/) {
+ return keySystems[keySystemStr].getErrorResponse(serverResponse);
+ }
+
+ instance = {
+ getServerURLFromMessage: getServerURLFromMessage,
+ getHTTPMethod: getHTTPMethod,
+ getResponseType: getResponseType,
+ getLicenseMessage: getLicenseMessage,
+ getErrorResponse: getErrorResponse
+ };
+
+ return instance;
+}
+
+DRMToday.__dashjs_factory_name = 'DRMToday';
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(DRMToday);
+module.exports = exports['default'];
+
+},{"1":1,"10":10}],118:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * Microsoft PlayReady Test License Server
+ *
+ * For testing content that uses the PlayReady test server at
+ *
+ * @implements LicenseServer
+ * @class
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+function PlayReady() {
+
+ var instance = undefined;
+
+ function getServerURLFromMessage(url /*, message, messageType*/) {
+ return url;
+ }
+
+ function getHTTPMethod() /*messageType*/{
+ return 'POST';
+ }
+
+ function getResponseType() /*keySystemStr, messageType*/{
+ return 'arraybuffer';
+ }
+
+ function getLicenseMessage(serverResponse /*, keySystemStr, messageType*/) {
+ return serverResponse;
+ }
+
+ function getErrorResponse(serverResponse /*, keySystemStr, messageType*/) {
+ return String.fromCharCode.apply(null, new Uint8Array(serverResponse));
+ }
+
+ instance = {
+ getServerURLFromMessage: getServerURLFromMessage,
+ getHTTPMethod: getHTTPMethod,
+ getResponseType: getResponseType,
+ getLicenseMessage: getLicenseMessage,
+ getErrorResponse: getErrorResponse
+ };
+
+ return instance;
+}
+
+PlayReady.__dashjs_factory_name = 'PlayReady';
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(PlayReady);
+module.exports = exports['default'];
+
+},{"10":10}],119:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+function Widevine() {
+
+ var instance = undefined;
+
+ function getServerURLFromMessage(url /*, message, messageType*/) {
+ return url;
+ }
+
+ function getHTTPMethod() /*messageType*/{
+ return 'POST';
+ }
+
+ function getResponseType() /*keySystemStr, messageType*/{
+ return 'arraybuffer';
+ }
+
+ function getLicenseMessage(serverResponse /*, keySystemStr, messageType*/) {
+ return serverResponse;
+ }
+
+ function getErrorResponse(serverResponse /*, keySystemStr, messageType*/) {
+ return String.fromCharCode.apply(null, new Uint8Array(serverResponse));
+ }
+
+ instance = {
+ getServerURLFromMessage: getServerURLFromMessage,
+ getHTTPMethod: getHTTPMethod,
+ getResponseType: getResponseType,
+ getLicenseMessage: getLicenseMessage,
+ getErrorResponse: getErrorResponse
+ };
+
+ return instance;
+}
+
+Widevine.__dashjs_factory_name = 'Widevine';
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(Widevine);
+module.exports = exports['default'];
+
+},{"10":10}],120:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @classdesc A collection of ClearKey encryption keys with an (optional) associated
+ * type
+ * @ignore
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+
+var ClearKeyKeySet = (function () {
+ /**
+ * @param {Array.<KeyPair>} keyPairs
+ * @param {string} type the type of keys in this set. One of either 'persistent'
+ * or 'temporary'. Can also be null or undefined.
+ * @class
+ * @ignore
+ */
+
+ function ClearKeyKeySet(keyPairs, type) {
+ _classCallCheck(this, ClearKeyKeySet);
+
+ if (type && type !== 'persistent' && type !== 'temporary') throw new Error('Invalid ClearKey key set type! Must be one of \'persistent\' or \'temporary\'');
+ this.keyPairs = keyPairs;
+ this.type = type;
+ }
+
+ /**
+ * Convert this key set to its JSON Web Key (JWK) representation
+ *
+ * @return {ArrayBuffer} JWK object UTF-8 encoded as ArrayBuffer
+ */
+
+ _createClass(ClearKeyKeySet, [{
+ key: 'toJWK',
+ value: function toJWK() {
+ var i;
+ var numKeys = this.keyPairs.length;
+ var jwk = { keys: [] };
+
+ for (i = 0; i < numKeys; i++) {
+ var key = {
+ kty: 'oct',
+ alg: 'A128KW',
+ kid: this.keyPairs[i].keyID,
+ k: this.keyPairs[i].key
+ };
+ jwk.keys.push(key);
+ }
+ if (this.type) {
+ jwk.type = this.type;
+ }
+ var jwkString = JSON.stringify(jwk);
+ var len = jwkString.length;
+
+ // Convert JSON string to ArrayBuffer
+ var buf = new ArrayBuffer(len);
+ var bView = new Uint8Array(buf);
+ for (i = 0; i < len; i++) bView[i] = jwkString.charCodeAt(i);
+ return buf;
+ }
+ }]);
+
+ return ClearKeyKeySet;
+})();
+
+exports['default'] = ClearKeyKeySet;
+module.exports = exports['default'];
+
+},{}],121:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @classdesc EME-independent KeyError
+ * @ignore
+ */
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var KeyError =
+/**
+ * @param {Object} sessionToken the key session to which this error is associated
+ * @param {string} errorString an informational error message
+ * @class
+ * @deprecated Newest versions of EME APIs will not use this error object
+ */
+function KeyError(sessionToken, errorString) {
+ _classCallCheck(this, KeyError);
+
+ this.sessionToken = sessionToken;
+ this.error = errorString;
+};
+
+exports["default"] = KeyError;
+module.exports = exports["default"];
+
+},{}],122:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @classdesc EME-independent KeyMessage
+ * @ignore
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+
+var KeyMessage =
+/**
+ * @param {SessionToken} sessionToken the session
+ * to which the key message is associated
+ * @param {ArrayBuffer} message the key message
+ * @param {string} defaultURL license acquisition URL provided by the CDM
+ * @param {string} messageType Supported message types can be found
+ * {@link https://w3c.github.io/encrypted-media/#idl-def-MediaKeyMessageType|here}.
+ * @class
+ */
+function KeyMessage(sessionToken, message, defaultURL, messageType) {
+ _classCallCheck(this, KeyMessage);
+
+ this.sessionToken = sessionToken;
+ this.message = message;
+ this.defaultURL = defaultURL;
+ this.messageType = messageType ? messageType : 'license-request';
+};
+
+exports['default'] = KeyMessage;
+module.exports = exports['default'];
+
+},{}],123:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @classdesc Represents a 128-bit keyID and 128-bit encryption key
+ * @ignore
+ */
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var KeyPair =
+/**
+ * @param {string} keyID 128-bit key ID, base64 encoded, with no padding
+ * @param {string} key 128-bit encryption key, base64 encoded, with no padding
+ * @class
+ * @ignore
+ */
+function KeyPair(keyID, key) {
+ _classCallCheck(this, KeyPair);
+
+ this.keyID = keyID;
+ this.key = key;
+};
+
+exports["default"] = KeyPair;
+module.exports = exports["default"];
+
+},{}],124:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @classdesc Creates a new key system access token. Represents a valid key system for
+ * given piece of content and key system requirements. Used to initialize license
+ * acquisition operations.
+ * @ignore
+ */
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var KeySystemAccess =
+/**
+ * @param {MediaPlayer.dependencies.protection.KeySystem} keySystem the key system
+ * @param {KeySystemConfiguration} ksConfiguration the
+ * subset of configurations passed to the key system access request that are supported
+ * by this user agent
+ * @class
+ * @ignore
+ */
+function KeySystemAccess(keySystem, ksConfiguration) {
+ _classCallCheck(this, KeySystemAccess);
+
+ this.keySystem = keySystem;
+ this.ksConfiguration = ksConfiguration;
+};
+
+exports["default"] = KeySystemAccess;
+module.exports = exports["default"];
+
+},{}],125:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @classdesc Represents a set of configurations that describe the capabilities desired for
+ * support by a given CDM
+ * @ignore
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+
+var KeySystemConfiguration =
+/**
+ * @param {Array.<MediaCapability>} audioCapabilities array of
+ * desired audio capabilities. Higher preference capabilities should be placed earlier
+ * in the array.
+ * @param {Array.<MediaCapability>} videoCapabilities array of
+ * desired video capabilities. Higher preference capabilities should be placed earlier
+ * in the array.
+ * @param {string} distinctiveIdentifier desired use of distinctive identifiers.
+ * One of "required", "optional", or "not-allowed"
+ * @param {string} persistentState desired support for persistent storage of
+ * key systems. One of "required", "optional", or "not-allowed"
+ * @param {Array.<string>} sessionTypes List of session types that must
+ * be supported by the key system
+ * @class
+ */
+function KeySystemConfiguration(audioCapabilities, videoCapabilities, distinctiveIdentifier, persistentState, sessionTypes) {
+ _classCallCheck(this, KeySystemConfiguration);
+
+ this.initDataTypes = ['cenc'];
+ this.audioCapabilities = audioCapabilities;
+ this.videoCapabilities = videoCapabilities;
+ this.distinctiveIdentifier = distinctiveIdentifier;
+ this.persistentState = persistentState;
+ this.sessionTypes = sessionTypes;
+};
+
+exports['default'] = KeySystemConfiguration;
+module.exports = exports['default'];
+
+},{}],126:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @classdesc A media capability
+ * @ignore
+ */
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var MediaCapability =
+/**
+ * @param {string} contentType MIME type and codecs (RFC6386)
+ * @param {string} robustness
+ * @class
+ * @ignore
+ */
+function MediaCapability(contentType, robustness) {
+ _classCallCheck(this, MediaCapability);
+
+ this.contentType = contentType;
+ this.robustness = robustness;
+};
+
+exports["default"] = MediaCapability;
+module.exports = exports["default"];
+
+},{}],127:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @classdesc NeedKey
+ * @ignore
+ */
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var NeedKey =
+/**
+ * @param {ArrayBuffer} initData the initialization data
+ * @param {string} initDataType initialization data type
+ * @class
+ */
+function NeedKey(initData, initDataType) {
+ _classCallCheck(this, NeedKey);
+
+ this.initData = initData;
+ this.initDataType = initDataType;
+};
+
+exports["default"] = NeedKey;
+module.exports = exports["default"];
+
+},{}],128:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+function RulesContext(config) {
+
+ var instance = undefined;
+ var representationInfo = config.streamProcessor.getCurrentRepresentationInfo();
+ var sp = config.streamProcessor;
+ var currentValue = config.currentValue;
+
+ function getStreamInfo() {
+ return representationInfo.mediaInfo.streamInfo;
+ }
+
+ function getMediaInfo() {
+ return representationInfo.mediaInfo;
+ }
+
+ function getTrackInfo() {
+ return representationInfo;
+ }
+
+ function getCurrentValue() {
+ return currentValue;
+ }
+
+ function getManifestInfo() {
+ return representationInfo.mediaInfo.streamInfo.manifestInfo;
+ }
+
+ function getStreamProcessor() {
+ return sp;
+ }
+
+ instance = {
+ getStreamInfo: getStreamInfo,
+ getMediaInfo: getMediaInfo,
+ getTrackInfo: getTrackInfo,
+ getCurrentValue: getCurrentValue,
+ getManifestInfo: getManifestInfo,
+ getStreamProcessor: getStreamProcessor
+ };
+
+ return instance;
+}
+
+RulesContext.__dashjs_factory_name = 'RulesContext';
+exports['default'] = _coreFactoryMaker2['default'].getClassFactory(RulesContext);
+module.exports = exports['default'];
+
+},{"10":10}],129:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _RulesContext = _dereq_(128);
+
+var _RulesContext2 = _interopRequireDefault(_RulesContext);
+
+var _SwitchRequest = _dereq_(130);
+
+var _SwitchRequest2 = _interopRequireDefault(_SwitchRequest);
+
+var _abrABRRulesCollection = _dereq_(131);
+
+var _abrABRRulesCollection2 = _interopRequireDefault(_abrABRRulesCollection);
+
+var _synchronizationSynchronizationRulesCollection = _dereq_(144);
+
+var _synchronizationSynchronizationRulesCollection2 = _interopRequireDefault(_synchronizationSynchronizationRulesCollection);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var ABR_RULE = 0;
+var SYNC_RULE = 1;
+
+function RulesController() {
+
+ var context = this.context;
+
+ var instance = undefined,
+ rules = undefined;
+
+ function initialize() {
+ rules = {};
+ }
+
+ function setConfig(config) {
+ if (!config) return;
+
+ if (config.abrRulesCollection) {
+ rules[ABR_RULE] = config.abrRulesCollection;
+ }
+
+ if (config.synchronizationRulesCollection) {
+ rules[SYNC_RULE] = config.synchronizationRulesCollection;
+ }
+ }
+
+ function applyRules(rulesArr, streamProcessor, callback, current, overrideFunc) {
+ var values = {};
+ var reasons = {};
+ var rule, i;
+
+ var rulesCount = rulesArr.length;
+ var ln = rulesCount;
+ var rulesContext = getRulesContext(streamProcessor, current);
+
+ var callbackFunc = function callbackFunc(result) {
+ var value, reason, confidence;
+
+ if (result.value !== _SwitchRequest2['default'].NO_CHANGE) {
+ var newValue = overrideFunc(values[result.priority], result.value);
+ if (newValue !== values[result.priority]) {
+ // change in value
+ values[result.priority] = newValue; // === result.value
+ reasons[result.priority] = result.reason;
+ }
+ }
+
+ if (--rulesCount) return;
+
+ if (values[_SwitchRequest2['default'].WEAK] !== _SwitchRequest2['default'].NO_CHANGE) {
+ confidence = _SwitchRequest2['default'].WEAK;
+ value = values[_SwitchRequest2['default'].WEAK];
+ reason = reasons[_SwitchRequest2['default'].WEAK];
+ }
+
+ if (values[_SwitchRequest2['default'].DEFAULT] !== _SwitchRequest2['default'].NO_CHANGE) {
+ confidence = _SwitchRequest2['default'].DEFAULT;
+ value = values[_SwitchRequest2['default'].DEFAULT];
+ reason = reasons[_SwitchRequest2['default'].DEFAULT];
+ }
+
+ if (values[_SwitchRequest2['default'].STRONG] !== _SwitchRequest2['default'].NO_CHANGE) {
+ confidence = _SwitchRequest2['default'].STRONG;
+ value = values[_SwitchRequest2['default'].STRONG];
+ reason = reasons[_SwitchRequest2['default'].STRONG];
+ }
+
+ if (confidence != _SwitchRequest2['default'].STRONG && confidence != _SwitchRequest2['default'].WEAK) {
+ confidence = _SwitchRequest2['default'].DEFAULT;
+ }
+
+ if (value !== undefined) {
+ callback({ value: value, confidence: confidence, reason: reason });
+ } else {
+ callback({ value: current, confidence: confidence, reason: { name: 'NO_CHANGE' } });
+ }
+ };
+
+ values[_SwitchRequest2['default'].STRONG] = _SwitchRequest2['default'].NO_CHANGE;
+ values[_SwitchRequest2['default'].WEAK] = _SwitchRequest2['default'].NO_CHANGE;
+ values[_SwitchRequest2['default'].DEFAULT] = _SwitchRequest2['default'].NO_CHANGE;
+
+ for (i = 0; i < ln; i++) {
+ rule = rulesArr[i];
+ rule.execute(rulesContext, callbackFunc);
+ }
+ }
+
+ function reset() {
+ var abrRules = rules[ABR_RULE];
+ var synchronizationRules = rules[SYNC_RULE];
+ var allRules = (abrRules.getRules(_abrABRRulesCollection2['default'].QUALITY_SWITCH_RULES) || []).concat(abrRules.getRules(_abrABRRulesCollection2['default'].ABANDON_FRAGMENT_RULES) || []).concat(synchronizationRules.getRules(_synchronizationSynchronizationRulesCollection2['default'].TIME_SYNCHRONIZED_RULES) || []).concat(synchronizationRules.getRules(_synchronizationSynchronizationRulesCollection2['default'].BEST_GUESS_RULES) || []);
+ var ln = allRules.length;
+
+ var rule, i;
+
+ for (i = 0; i < ln; i++) {
+ rule = allRules[i];
+
+ if (typeof rule.reset !== 'function') continue;
+
+ rule.reset();
+ }
+
+ rules = {};
+ }
+
+ function getRulesContext(streamProcessor, currentValue) {
+ return (0, _RulesContext2['default'])(context).create({ streamProcessor: streamProcessor, currentValue: currentValue });
+ }
+
+ instance = {
+ initialize: initialize,
+ setConfig: setConfig,
+ applyRules: applyRules,
+ reset: reset
+ };
+
+ return instance;
+}
+
+RulesController.__dashjs_factory_name = 'RulesController';
+var factory = _coreFactoryMaker2['default'].getSingletonFactory(RulesController);
+factory.ABR_RULE = ABR_RULE;
+factory.SYNC_RULE = SYNC_RULE;
+exports['default'] = factory;
+module.exports = exports['default'];
+
+},{"10":10,"128":128,"130":130,"131":131,"144":144}],130:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var NO_CHANGE = 999;
+var DEFAULT = 0.5;
+var STRONG = 1;
+var WEAK = 0;
+
+function SwitchRequest(v, p, r) {
+ //TODO refactor all the calls to this to use config to be like everything else.
+ var value = v === undefined ? NO_CHANGE : v;
+ var priority = p === undefined ? DEFAULT : p;
+ var reason = r === undefined ? null : r;
+
+ var instance = {
+ value: value,
+ priority: priority,
+ reason: reason
+ };
+
+ return instance;
+}
+
+SwitchRequest.__dashjs_factory_name = 'SwitchRequest';
+var factory = _coreFactoryMaker2['default'].getClassFactory(SwitchRequest);
+factory.NO_CHANGE = NO_CHANGE;
+factory.DEFAULT = DEFAULT;
+factory.STRONG = STRONG;
+factory.WEAK = WEAK;
+exports['default'] = factory;
+module.exports = exports['default'];
+
+},{"10":10}],131:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _ThroughputRule = _dereq_(137);
+
+var _ThroughputRule2 = _interopRequireDefault(_ThroughputRule);
+
+var _BufferOccupancyRule = _dereq_(135);
+
+var _BufferOccupancyRule2 = _interopRequireDefault(_BufferOccupancyRule);
+
+var _InsufficientBufferRule = _dereq_(136);
+
+var _InsufficientBufferRule2 = _interopRequireDefault(_InsufficientBufferRule);
+
+var _AbandonRequestsRule = _dereq_(132);
+
+var _AbandonRequestsRule2 = _interopRequireDefault(_AbandonRequestsRule);
+
+var _BolaRule = _dereq_(134);
+
+var _BolaRule2 = _interopRequireDefault(_BolaRule);
+
+var _BolaAbandonRule = _dereq_(133);
+
+var _BolaAbandonRule2 = _interopRequireDefault(_BolaAbandonRule);
+
+var _modelsMediaPlayerModel = _dereq_(101);
+
+var _modelsMediaPlayerModel2 = _interopRequireDefault(_modelsMediaPlayerModel);
+
+var _modelsMetricsModel = _dereq_(102);
+
+var _modelsMetricsModel2 = _interopRequireDefault(_modelsMetricsModel);
+
+var _dashDashMetrics = _dereq_(17);
+
+var _dashDashMetrics2 = _interopRequireDefault(_dashDashMetrics);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var QUALITY_SWITCH_RULES = 'qualitySwitchRules';
+var ABANDON_FRAGMENT_RULES = 'abandonFragmentRules';
+
+function ABRRulesCollection() {
+
+ var context = this.context;
+
+ var instance = undefined,
+ qualitySwitchRules = undefined,
+ abandonFragmentRules = undefined;
+
+ function initialize() {
+ qualitySwitchRules = [];
+ abandonFragmentRules = [];
+
+ var metricsModel = (0, _modelsMetricsModel2['default'])(context).getInstance();
+ var dashMetrics = (0, _dashDashMetrics2['default'])(context).getInstance();
+ var mediaPlayerModel = (0, _modelsMediaPlayerModel2['default'])(context).getInstance();
+
+ if (mediaPlayerModel.getBufferOccupancyABREnabled()) {
+ qualitySwitchRules.push((0, _BolaRule2['default'])(context).create({
+ metricsModel: metricsModel,
+ dashMetrics: (0, _dashDashMetrics2['default'])(context).getInstance()
+ }));
+ abandonFragmentRules.push((0, _BolaAbandonRule2['default'])(context).create({
+ metricsModel: metricsModel,
+ dashMetrics: (0, _dashDashMetrics2['default'])(context).getInstance()
+ }));
+ } else {
+ qualitySwitchRules.push((0, _ThroughputRule2['default'])(context).create({
+ metricsModel: metricsModel,
+ dashMetrics: dashMetrics
+ }));
+
+ qualitySwitchRules.push((0, _BufferOccupancyRule2['default'])(context).create({
+ metricsModel: metricsModel,
+ dashMetrics: dashMetrics
+ }));
+
+ qualitySwitchRules.push((0, _InsufficientBufferRule2['default'])(context).create({ metricsModel: metricsModel }));
+ abandonFragmentRules.push((0, _AbandonRequestsRule2['default'])(context).create());
+ }
+ }
+
+ function getRules(type) {
+ switch (type) {
+ case QUALITY_SWITCH_RULES:
+ return qualitySwitchRules;
+ case ABANDON_FRAGMENT_RULES:
+ return abandonFragmentRules;
+ default:
+ return null;
+ }
+ }
+
+ instance = {
+ initialize: initialize,
+ getRules: getRules
+ };
+
+ return instance;
+}
+
+ABRRulesCollection.__dashjs_factory_name = 'ABRRulesCollection';
+var factory = _coreFactoryMaker2['default'].getSingletonFactory(ABRRulesCollection);
+factory.QUALITY_SWITCH_RULES = QUALITY_SWITCH_RULES;
+factory.ABANDON_FRAGMENT_RULES = ABANDON_FRAGMENT_RULES;
+exports['default'] = factory;
+module.exports = exports['default'];
+
+},{"10":10,"101":101,"102":102,"132":132,"133":133,"134":134,"135":135,"136":136,"137":137,"17":17}],132:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _SwitchRequest = _dereq_(130);
+
+var _SwitchRequest2 = _interopRequireDefault(_SwitchRequest);
+
+var _modelsMediaPlayerModel = _dereq_(101);
+
+var _modelsMediaPlayerModel2 = _interopRequireDefault(_modelsMediaPlayerModel);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _coreDebug = _dereq_(8);
+
+var _coreDebug2 = _interopRequireDefault(_coreDebug);
+
+function AbandonRequestsRule() {
+
+ var ABANDON_MULTIPLIER = 1.8;
+ var GRACE_TIME_THRESHOLD = 500;
+ var MIN_LENGTH_TO_AVERAGE = 5;
+
+ var context = this.context;
+ var log = (0, _coreDebug2['default'])(context).getInstance().log;
+
+ var fragmentDict = undefined,
+ abandonDict = undefined,
+ throughputArray = undefined,
+ mediaPlayerModel = undefined;
+
+ function setup() {
+ fragmentDict = {};
+ abandonDict = {};
+ throughputArray = [];
+ mediaPlayerModel = (0, _modelsMediaPlayerModel2['default'])(context).getInstance();
+ }
+
+ function setFragmentRequestDict(type, id) {
+ fragmentDict[type] = fragmentDict[type] || {};
+ fragmentDict[type][id] = fragmentDict[type][id] || {};
+ }
+
+ function storeLastRequestThroughputByType(type, throughput) {
+ throughputArray[type] = throughputArray[type] || [];
+ throughputArray[type].push(throughput);
+ }
+
+ function execute(rulesContext, callback) {
+
+ var mediaInfo = rulesContext.getMediaInfo();
+ var mediaType = mediaInfo.type;
+ var req = rulesContext.getCurrentValue().request;
+ var switchRequest = (0, _SwitchRequest2['default'])(context).create(_SwitchRequest2['default'].NO_CHANGE, _SwitchRequest2['default'].WEAK, { name: AbandonRequestsRule.__dashjs_factory_name });
+
+ if (!isNaN(req.index)) {
+
+ setFragmentRequestDict(mediaType, req.index);
+
+ var fragmentInfo = fragmentDict[mediaType][req.index];
+ if (fragmentInfo === null || req.firstByteDate === null || abandonDict.hasOwnProperty(fragmentInfo.id)) {
+ callback(switchRequest);
+ return;
+ }
+
+ //setup some init info based on first progress event
+ if (fragmentInfo.firstByteTime === undefined) {
+ throughputArray[mediaType] = [];
+ fragmentInfo.firstByteTime = req.firstByteDate.getTime();
+ fragmentInfo.segmentDuration = req.duration;
+ fragmentInfo.bytesTotal = req.bytesTotal;
+ fragmentInfo.id = req.index;
+ }
+ fragmentInfo.bytesLoaded = req.bytesLoaded;
+ fragmentInfo.elapsedTime = new Date().getTime() - fragmentInfo.firstByteTime;
+
+ if (fragmentInfo.bytesLoaded > 0 && fragmentInfo.elapsedTime > 0) {
+ storeLastRequestThroughputByType(mediaType, Math.round(fragmentInfo.bytesLoaded * 8 / fragmentInfo.elapsedTime));
+ }
+
+ if (throughputArray[mediaType].length >= MIN_LENGTH_TO_AVERAGE && fragmentInfo.elapsedTime > GRACE_TIME_THRESHOLD && fragmentInfo.bytesLoaded < fragmentInfo.bytesTotal) {
+
+ var totalSampledValue = throughputArray[mediaType].reduce(function (a, b) {
+ return a + b;
+ }, 0);
+ fragmentInfo.measuredBandwidthInKbps = Math.round(totalSampledValue / throughputArray[mediaType].length);
+ fragmentInfo.estimatedTimeOfDownload = (fragmentInfo.bytesTotal * 8 / fragmentInfo.measuredBandwidthInKbps / 1000).toFixed(2);
+ //log("id:",fragmentInfo.id, "kbps:", fragmentInfo.measuredBandwidthInKbps, "etd:",fragmentInfo.estimatedTimeOfDownload, fragmentInfo.bytesLoaded);
+
+ if (fragmentInfo.estimatedTimeOfDownload < fragmentInfo.segmentDuration * ABANDON_MULTIPLIER || rulesContext.getTrackInfo().quality === 0) {
+
+ callback(switchRequest);
+ return;
+ } else if (!abandonDict.hasOwnProperty(fragmentInfo.id)) {
+
+ var abrController = rulesContext.getStreamProcessor().getABRController();
+ var bytesRemaining = fragmentInfo.bytesTotal - fragmentInfo.bytesLoaded;
+ var bitrateList = abrController.getBitrateList(mediaInfo);
+ var newQuality = abrController.getQualityForBitrate(mediaInfo, fragmentInfo.measuredBandwidthInKbps * mediaPlayerModel.getBandwidthSafetyFactor());
+ var estimateOtherBytesTotal = fragmentInfo.bytesTotal * bitrateList[newQuality].bitrate / bitrateList[abrController.getQualityFor(mediaType, mediaInfo.streamInfo)].bitrate;
+
+ if (bytesRemaining > estimateOtherBytesTotal) {
+
+ switchRequest.value = newQuality;
+ switchRequest.priority = _SwitchRequest2['default'].STRONG;
+ switchRequest.reason.throughput = fragmentInfo.measuredBandwidthInKbps;
+ abandonDict[fragmentInfo.id] = fragmentInfo;
+ log('AbandonRequestsRule ( ', mediaType, 'frag id', fragmentInfo.id, ') is asking to abandon and switch to quality to ', newQuality, ' measured bandwidth was', fragmentInfo.measuredBandwidthInKbps);
+ delete fragmentDict[mediaType][fragmentInfo.id];
+ }
+ }
+ } else if (fragmentInfo.bytesLoaded === fragmentInfo.bytesTotal) {
+ delete fragmentDict[mediaType][fragmentInfo.id];
+ }
+ }
+
+ callback(switchRequest);
+ }
+
+ function reset() {
+ setup();
+ }
+
+ var instance = {
+ execute: execute,
+ reset: reset
+ };
+
+ setup();
+
+ return instance;
+}
+
+AbandonRequestsRule.__dashjs_factory_name = 'AbandonRequestsRule';
+exports['default'] = _coreFactoryMaker2['default'].getClassFactory(AbandonRequestsRule);
+module.exports = exports['default'];
+
+},{"10":10,"101":101,"130":130,"8":8}],133:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2016, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _SwitchRequest = _dereq_(130);
+
+var _SwitchRequest2 = _interopRequireDefault(_SwitchRequest);
+
+var _modelsMediaPlayerModel = _dereq_(101);
+
+var _modelsMediaPlayerModel2 = _interopRequireDefault(_modelsMediaPlayerModel);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _coreDebug = _dereq_(8);
+
+var _coreDebug2 = _interopRequireDefault(_coreDebug);
+
+var _BolaRule = _dereq_(134);
+
+var _BolaRule2 = _interopRequireDefault(_BolaRule);
+
+function BolaAbandonRule(config) {
+
+ // do not abandon during the grace period
+ var GRACE_PERIOD_MS = 500;
+ var POOR_LATENCY_MS = 200;
+
+ var context = this.context;
+ var log = (0, _coreDebug2['default'])(context).getInstance().log;
+ var dashMetrics = config.dashMetrics;
+ var metricsModel = config.metricsModel;
+
+ var instance = undefined,
+ abandonDict = undefined,
+ mediaPlayerModel = undefined;
+
+ function setup() {
+ abandonDict = {};
+ mediaPlayerModel = (0, _modelsMediaPlayerModel2['default'])(context).getInstance();
+ }
+
+ function rememberAbandon(mediaType, index, quality) {
+ // if this is called, then canStillAbandon(mediaType, index, quality) should have returned true
+ abandonDict[mediaType] = { index: index, quality: quality };
+ }
+
+ function canAbandon(mediaType, index, quality) {
+ var a = abandonDict[mediaType];
+ if (!a) return true;
+ return index !== a.index || quality < a.quality;
+ }
+
+ function execute(rulesContext, callback) {
+ var mediaInfo = rulesContext.getMediaInfo();
+ var mediaType = mediaInfo.type;
+ var metrics = metricsModel.getReadOnlyMetricsFor(mediaType);
+ var progressEvent = rulesContext.getCurrentValue();
+ var request = progressEvent.request;
+ var switchRequest = (0, _SwitchRequest2['default'])(context).create(_SwitchRequest2['default'].NO_CHANGE, _SwitchRequest2['default'].WEAK, { name: BolaAbandonRule.__dashjs_factory_name });
+
+ if (metrics.BolaState.length === 0) {
+ // should not arrive here - we shouldn't be downloading a fragment before BOLA is initialized
+ log('WARNING: executing BolaAbandonRule before initializing BolaRule');
+ abandonDict[mediaType] = null;
+ callback(switchRequest);
+ return;
+ }
+
+ var bolaState = metrics.BolaState[0]._s;
+ // TODO: does changing bolaState conform to coding style, or should we clone?
+
+ var index = request.index;
+ var quality = request.quality;
+
+ if (isNaN(index) || quality === 0 || !canAbandon(mediaType, index, quality) || !request.firstByteDate) {
+ callback(switchRequest);
+ return;
+ }
+
+ var nowMs = Date.now();
+ var elapsedTimeMs = nowMs - request.firstByteDate.getTime();
+
+ var bytesLoaded = request.bytesLoaded;
+ var bytesTotal = request.bytesTotal;
+ var bytesRemaining = bytesTotal - bytesLoaded;
+ var durationS = request.duration;
+
+ var bufferLevel = dashMetrics.getCurrentBufferLevel(metrics) ? dashMetrics.getCurrentBufferLevel(metrics) : 0.0;
+ var effectiveBufferLevel = bufferLevel + bolaState.virtualBuffer;
+
+ var estimateThroughput = 8 * bytesLoaded / (0.001 * elapsedTimeMs); // throughput in bits per second
+ var estimateThroughputBSF = bolaState.bandwidthSafetyFactor * estimateThroughput;
+ var latencyS = 0.001 * (request.firstByteDate.getTime() - request.requestStartDate.getTime());
+ if (latencyS < 0.001 * POOR_LATENCY_MS) {
+ latencyS = 0.001 * POOR_LATENCY_MS;
+ }
+ var estimateTotalTimeS = latencyS + 8 * bytesTotal / estimateThroughputBSF;
+
+ var diagnosticMessage = '';
+ if (_BolaRule2['default'].BOLA_DEBUG) diagnosticMessage = 'index=' + index + ' quality=' + quality + ' bytesLoaded/bytesTotal=' + bytesLoaded + '/' + bytesTotal + ' bufferLevel=' + bufferLevel + ' timeSince1stByte=' + (elapsedTimeMs / 1000).toFixed(3) + ' estThroughput=' + (estimateThroughputBSF / 1000000).toFixed(3) + ' latency=' + latencyS.toFixed(3);
+
+ var estimateOtherBytesTotal = bytesTotal * bolaState.bitrates[0] / bolaState.bitrates[quality];
+ var estimateBytesRemainingAfterLatency = bytesRemaining - latencyS * estimateThroughputBSF / 8;
+ if (estimateBytesRemainingAfterLatency < 1) {
+ estimateBytesRemainingAfterLatency = 1;
+ }
+
+ if (elapsedTimeMs < GRACE_PERIOD_MS || bytesRemaining <= estimateOtherBytesTotal || bufferLevel > bolaState.bufferTarget || estimateBytesRemainingAfterLatency <= estimateOtherBytesTotal || estimateTotalTimeS <= durationS) {
+ // Do not abandon during first GRACE_PERIOD_MS.
+ // Do not abandon if we need to download less bytes than the size of the lowest quality fragment.
+ // Do not abandon if buffer level is above bufferTarget because the schedule controller will not download anything anyway.
+ // Do not abandon if after latencyS bytesRemaining is estimated to drop below size of lowest quality fragment.
+ // Do not abandon if fragment takes less than 1 fragment duration to download.
+ callback(switchRequest);
+ return;
+ }
+
+ // If we abandon, there will be latencyS time before we get first byte at lower quality.
+ // By that time, the no-abandon option would have downloaded some more, and the buffer level would have depleted some more.
+ // Introducing this latencyS cushion also helps avoid extra abandonment, especially with close bitrates.
+
+ var effectiveBufferAfterLatency = effectiveBufferLevel - latencyS;
+ if (effectiveBufferAfterLatency < 0) {
+ effectiveBufferAfterLatency = 0;
+ }
+
+ // if we end up abandoning, we should not consider starting a download that would require more bytes than the remaining bytes in currently downloading fragment
+ var maxDroppedQuality = 0;
+ while (maxDroppedQuality + 1 < quality && bytesTotal * bolaState.bitrates[maxDroppedQuality + 1] / bolaState.bitrates[quality] < estimateBytesRemainingAfterLatency) {
+
+ ++maxDroppedQuality;
+ }
+
+ var newQuality = quality;
+
+ if (bolaState.state === _BolaRule2['default'].BOLA_STATE_STARTUP) {
+ // We are not yet using the BOLA buffer rules - use different abandonment logic.
+
+ // if we are here then we failed the test that estimateTotalTimeS <= durationS, so we abandon
+
+ // search for quality that matches the throughput
+ newQuality = 0;
+ for (var i = 0; i <= maxDroppedQuality; ++i) {
+ estimateOtherBytesTotal = bytesTotal * bolaState.bitrates[i] / bolaState.bitrates[quality];
+ if (8 * estimateOtherBytesTotal / durationS > estimateThroughputBSF) {
+ // chunks at quality i or higher need a greater throughput
+ break;
+ }
+ newQuality = i;
+ }
+ } else {
+ // bolaState.state === BolaRule.BOLA_STATE_STEADY
+ // check if we should abandon using BOLA utility criteria
+
+ var score = (bolaState.Vp * (bolaState.utilities[quality] + bolaState.gp) - effectiveBufferAfterLatency) / estimateBytesRemainingAfterLatency;
+
+ for (var i = 0; i <= maxDroppedQuality; ++i) {
+ estimateOtherBytesTotal = bytesTotal * bolaState.bitrates[i] / bolaState.bitrates[quality];
+ var s = (bolaState.Vp * (bolaState.utilities[i] + bolaState.gp) - effectiveBufferAfterLatency) / estimateOtherBytesTotal;
+ if (s > score) {
+ newQuality = i;
+ score = s;
+ }
+ }
+ }
+
+ // Perform check for rebuffer avoidance - now use real buffer level as opposed to effective buffer level.
+ var safeByteSize = bolaState.rebufferSafetyFactor * estimateThroughput * (bufferLevel - latencyS) / 8;
+
+ if (newQuality === quality && estimateBytesRemainingAfterLatency > safeByteSize) {
+ newQuality = maxDroppedQuality;
+ }
+
+ if (newQuality === quality) {
+ // no change
+ callback(switchRequest);
+ return;
+ }
+
+ // newQuality < quality, we are abandoning
+ while (newQuality > 0) {
+ estimateOtherBytesTotal = bytesTotal * bolaState.bitrates[newQuality] / bolaState.bitrates[quality];
+ if (estimateOtherBytesTotal <= safeByteSize) {
+ break;
+ }
+ --newQuality;
+ }
+
+ bolaState.lastQuality = newQuality;
+ metricsModel.updateBolaState(mediaType, bolaState);
+
+ if (_BolaRule2['default'].BOLA_DEBUG) log('BolaDebug ' + mediaType + ' BolaAbandonRule abandon to ' + newQuality + ' - ' + diagnosticMessage);
+
+ rememberAbandon(mediaType, index, quality);
+ switchRequest.value = newQuality;
+ switchRequest.priority = _SwitchRequest2['default'].STRONG;
+ switchRequest.reason.state = bolaState.state;
+ switchRequest.reason.throughput = estimateThroughput;
+ switchRequest.reason.bufferLevel = bufferLevel;
+ // following entries used for tuning algorithm
+ switchRequest.reason.bytesLoaded = request.bytesLoaded;
+ switchRequest.reason.bytesTotal = request.bytesTotal;
+ switchRequest.reason.elapsedTimeMs = elapsedTimeMs;
+
+ callback(switchRequest);
+ }
+
+ function reset() {
+ abandonDict = {};
+ }
+
+ instance = {
+ execute: execute,
+ reset: reset
+ };
+
+ setup();
+
+ return instance;
+}
+
+BolaAbandonRule.__dashjs_factory_name = 'BolaAbandonRule';
+exports['default'] = _coreFactoryMaker2['default'].getClassFactory(BolaAbandonRule);
+module.exports = exports['default'];
+
+},{"10":10,"101":101,"130":130,"134":134,"8":8}],134:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2016, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// For a description of the BOLA adaptive bitrate (ABR) algorithm, see http://arxiv.org/abs/1601.06748
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _SwitchRequest = _dereq_(130);
+
+var _SwitchRequest2 = _interopRequireDefault(_SwitchRequest);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _modelsMediaPlayerModel = _dereq_(101);
+
+var _modelsMediaPlayerModel2 = _interopRequireDefault(_modelsMediaPlayerModel);
+
+var _controllersPlaybackController = _dereq_(68);
+
+var _controllersPlaybackController2 = _interopRequireDefault(_controllersPlaybackController);
+
+var _voMetricsHTTPRequest = _dereq_(179);
+
+var _dashDashAdapter = _dereq_(15);
+
+var _dashDashAdapter2 = _interopRequireDefault(_dashDashAdapter);
+
+var _coreEventBus = _dereq_(9);
+
+var _coreEventBus2 = _interopRequireDefault(_coreEventBus);
+
+var _coreEventsEvents = _dereq_(13);
+
+var _coreEventsEvents2 = _interopRequireDefault(_coreEventsEvents);
+
+var _coreDebug = _dereq_(8);
+
+var _coreDebug2 = _interopRequireDefault(_coreDebug);
+
+// BOLA_STATE_ONE_BITRATE : If there is only one bitrate (or initialization failed), always return NO_CHANGE.
+// BOLA_STATE_STARTUP : Set virtual buffer such that we download fragments at most recently measured throughput.
+// BOLA_STATE_STEADY : Buffer primed, we switch to steady operation.
+// TODO: add BOLA_STATE_SEEK and tune Bola behavior on seeking
+var BOLA_STATE_ONE_BITRATE = 0;
+var BOLA_STATE_STARTUP = 1;
+var BOLA_STATE_STEADY = 2;
+var BOLA_DEBUG = false; // TODO: remove
+
+var MINIMUM_BUFFER_S = 10; // BOLA should never add artificial delays if buffer is less than MINIMUM_BUFFER_S.
+var BUFFER_TARGET_S = 30; // If Schedule Controller does not allow buffer level to reach BUFFER_TARGET_S, this can be a virtual buffer level.
+var REBUFFER_SAFETY_FACTOR = 0.5; // Used when buffer level is dangerously low, might happen often in live streaming.
+
+function BolaRule(config) {
+
+ var AVERAGE_THROUGHPUT_SAMPLE_AMOUNT_LIVE = 2;
+ var AVERAGE_THROUGHPUT_SAMPLE_AMOUNT_VOD = 3;
+
+ var context = this.context;
+ var log = (0, _coreDebug2['default'])(context).getInstance().log;
+ var dashMetrics = config.dashMetrics;
+ var metricsModel = config.metricsModel;
+ var eventBus = (0, _coreEventBus2['default'])(context).getInstance();
+
+ var instance = undefined,
+ lastCallTimeDict = undefined,
+ eventMediaTypes = undefined,
+ mediaPlayerModel = undefined,
+ playbackController = undefined,
+ adapter = undefined;
+
+ function setup() {
+ lastCallTimeDict = {};
+ eventMediaTypes = [];
+ mediaPlayerModel = (0, _modelsMediaPlayerModel2['default'])(context).getInstance();
+ playbackController = (0, _controllersPlaybackController2['default'])(context).getInstance();
+ adapter = (0, _dashDashAdapter2['default'])(context).getInstance();
+ eventBus.on(_coreEventsEvents2['default'].BUFFER_EMPTY, onBufferEmpty, instance);
+ eventBus.on(_coreEventsEvents2['default'].PLAYBACK_SEEKING, onPlaybackSeeking, instance);
+ eventBus.on(_coreEventsEvents2['default'].PERIOD_SWITCH_STARTED, onPeriodSwitchStarted, instance);
+ }
+
+ function utilitiesFromBitrates(bitrates) {
+ return bitrates.map(function (b) {
+ return Math.log(b);
+ });
+ // no need to worry about offset, any offset will be compensated for by gp
+ }
+
+ // NOTE: in live streaming, the real buffer level can drop below minimumBufferS, but bola should not stick to lowest bitrate by using a virtual buffer level
+ function calculateParameters(minimumBufferS, bufferTargetS, bitrates, utilities) {
+ var highest_utility_index = NaN;
+ if (!utilities) {
+ utilities = utilitiesFromBitrates(bitrates);
+ highest_utility_index = utilities.length - 1;
+ } else {
+ highest_utility_index = 0;
+ utilities.forEach(function (u, i) {
+ if (u > utilities[highest_utility_index]) highest_utility_index = i;
+ });
+ }
+
+ if (highest_utility_index === 0) {
+ // if highest_utility_index === 0, then always use lowest bitrate
+ return null;
+ }
+
+ // TODO: Investigate if following can be better if utilities are not the default Math.log utilities.
+ // If using Math.log utilities, we can choose Vp and gp to always prefer bitrates[0] at minimumBufferS and bitrates[max] at bufferTargetS.
+ // (Vp * (utility + gp) - buffer_level) / bitrate has the maxima described when:
+ // Vp * (utilities[0] + gp - 1) = minimumBufferS and Vp * (utilities[max] + gp - 1) = bufferTargetS
+ // giving:
+ var gp = 1 - utilities[0] + (utilities[highest_utility_index] - utilities[0]) / (bufferTargetS / minimumBufferS - 1);
+ var Vp = minimumBufferS / (utilities[0] + gp - 1);
+
+ return { utilities: utilities, gp: gp, Vp: Vp };
+ }
+
+ function calculateInitialState(rulesContext) {
+ var initialState = {};
+
+ var mediaInfo = rulesContext.getMediaInfo();
+
+ var streamProcessor = rulesContext.getStreamProcessor();
+ var streamInfo = rulesContext.getStreamInfo();
+ var trackInfo = rulesContext.getTrackInfo();
+
+ var isDynamic = streamProcessor.isDynamic();
+ var duration = streamInfo.manifestInfo.duration;
+ var fragmentDuration = trackInfo.fragmentDuration;
+
+ var bitrates = mediaInfo.bitrateList.map(function (b) {
+ return b.bandwidth;
+ });
+ var params = calculateParameters(MINIMUM_BUFFER_S, BUFFER_TARGET_S, bitrates, null);
+ if (params === null) {
+ // The best soloution is to always use the lowest bitrate...
+ initialState.state = BOLA_STATE_ONE_BITRATE;
+ return initialState;
+ }
+
+ initialState.state = BOLA_STATE_STARTUP;
+
+ initialState.bitrates = bitrates;
+ initialState.utilities = params.utilities;
+ initialState.Vp = params.Vp;
+ initialState.gp = params.gp;
+
+ initialState.isDynamic = isDynamic;
+ initialState.movieDuration = duration;
+ initialState.fragmentDuration = fragmentDuration;
+ initialState.bandwidthSafetyFactor = mediaPlayerModel.getBandwidthSafetyFactor();
+ initialState.rebufferSafetyFactor = REBUFFER_SAFETY_FACTOR;
+ initialState.bufferTarget = mediaPlayerModel.getStableBufferTime();
+
+ initialState.lastQuality = 0;
+ initialState.virtualBuffer = 0;
+ initialState.throughputCount = isDynamic ? AVERAGE_THROUGHPUT_SAMPLE_AMOUNT_LIVE : AVERAGE_THROUGHPUT_SAMPLE_AMOUNT_VOD;
+
+ if (BOLA_DEBUG) {
+ var info = '';
+ for (var i = 0; i < bitrates.length; ++i) {
+ var u = params.utilities[i];
+ var b = bitrates[i];
+ var th = 0;
+ if (i > 0) {
+ var u1 = params.utilities[i - 1];
+ var b1 = bitrates[i - 1];
+ th = params.Vp * ((u1 * b - u * b1) / (b - b1) + params.gp);
+ }
+ var z = params.Vp * (u + params.gp);
+ info += '\n' + i + ':' + (0.000001 * bitrates[i]).toFixed(3) + 'Mbps ' + th.toFixed(3) + '/' + z.toFixed(3);
+ }
+ log('BolaDebug ' + mediaInfo.type + ' bitrates' + info);
+ }
+
+ return initialState;
+ }
+
+ function getQualityFromBufferLevel(bolaState, bufferLevel) {
+ var bitrateCount = bolaState.bitrates.length;
+ var quality = NaN;
+ var score = NaN;
+ for (var i = 0; i < bitrateCount; ++i) {
+ var s = (bolaState.Vp * (bolaState.utilities[i] + bolaState.gp) - bufferLevel) / bolaState.bitrates[i];
+ if (isNaN(score) || s >= score) {
+ score = s;
+ quality = i;
+ }
+ }
+ return quality;
+ }
+
+ function getLastHttpRequests(metrics, count) {
+ var allHttpRequests = dashMetrics.getHttpRequests(metrics);
+ var httpRequests = [];
+
+ for (var i = allHttpRequests.length - 1; i >= 0 && httpRequests.length < count; --i) {
+ var request = allHttpRequests[i];
+ if (request.type === _voMetricsHTTPRequest.HTTPRequest.MEDIA_SEGMENT_TYPE && request._tfinish && request.tresponse && request.trace) {
+ httpRequests.push(request);
+ }
+ }
+
+ return httpRequests;
+ }
+
+ function getRecentThroughput(metrics, count, mediaType) {
+ // TODO: mediaType only used for debugging, remove it
+ var lastRequests = getLastHttpRequests(metrics, count);
+ if (lastRequests.length === 0) {
+ return 0;
+ }
+
+ var totalInverse = 0;
+ var msg = '';
+ for (var i = 0; i < lastRequests.length; ++i) {
+ // The RTT delay results in a lower throughput. We can avoid this delay in the calculation, but we do not want to.
+ var downloadSeconds = 0.001 * (lastRequests[i]._tfinish.getTime() - lastRequests[i].trequest.getTime());
+ var downloadBits = 8 * lastRequests[i].trace.reduce(function (prev, cur) {
+ return prev + cur.b[0];
+ }, 0);
+ if (BOLA_DEBUG) msg += ' ' + (0.000001 * downloadBits).toFixed(3) + '/' + downloadSeconds.toFixed(3) + '=' + (0.000001 * downloadBits / downloadSeconds).toFixed(3) + 'Mbps';
+ totalInverse += downloadSeconds / downloadBits;
+ }
+
+ if (BOLA_DEBUG) log('BolaDebug ' + mediaType + ' BolaRule recent throughput = ' + (lastRequests.length / (1000000 * totalInverse)).toFixed(3) + 'Mbps:' + msg);
+
+ return lastRequests.length / totalInverse;
+ }
+
+ function getQualityFromThroughput(bolaState, throughput) {
+ // do not factor in bandwidthSafetyFactor here - it is factored at point of function invocation
+
+ var q = 0;
+
+ bolaState.bitrates.some(function (value, index) {
+ if (value > throughput) {
+ return true;
+ }
+ q = index;
+ return false;
+ });
+
+ return q;
+ }
+
+ function getDelayFromLastFragmentInSeconds(metrics, mediaType) {
+ var lastRequests = getLastHttpRequests(metrics, 1);
+ if (lastRequests.length === 0) {
+ return 0;
+ }
+ var lastRequest = lastRequests[0];
+ var nowMs = Date.now();
+ var lastRequestFinishMs = lastRequest._tfinish.getTime();
+
+ if (lastRequestFinishMs > nowMs) {
+ // this shouldn't happen, try to handle gracefully
+ lastRequestFinishMs = nowMs;
+ }
+
+ // return the time since the finish of the last request.
+ // The return will be added cumulatively to the virtual buffer, so we must be sure not to add the same delay twice.
+
+ var lctMs = lastCallTimeDict[mediaType];
+ lastCallTimeDict[mediaType] = nowMs;
+ var delayMs = 0;
+ if (lctMs && lctMs > lastRequestFinishMs) {
+ delayMs = nowMs - lctMs;
+ } else {
+ delayMs = nowMs - lastRequestFinishMs;
+ }
+
+ if (delayMs <= 0) return 0;
+ return 0.001 * delayMs;
+ }
+
+ function onBufferEmpty() {
+ if (BOLA_DEBUG) log('BolaDebug BUFFER_EMPTY');
+ // if we rebuffer, we don't want the virtual buffer to artificially raise BOLA quality
+ eventMediaTypes.forEach(function (mediaType) {
+ var metrics = metricsModel.getReadOnlyMetricsFor(mediaType);
+ if (metrics.BolaState.length !== 0) {
+ var bolaState = metrics.BolaState[0]._s;
+ if (bolaState.state === BOLA_STATE_STEADY) {
+ bolaState.virtualBuffer = 0;
+ metricsModel.updateBolaState(mediaType, bolaState);
+ }
+ }
+ });
+ }
+
+ function onPlaybackSeeking(e) {
+ if (BOLA_DEBUG) log('BolaDebug PLAYBACK_SEEKING ' + e.seekTime.toFixed(3));
+ // TODO: 1. Verify what happens if we seek mid-fragment.
+ // TODO: 2. If e.g. we have 10s fragments and seek, we might want to download the first fragment at a lower quality to restart playback quickly.
+ eventMediaTypes.forEach(function (mediaType) {
+ var metrics = metricsModel.getReadOnlyMetricsFor(mediaType);
+ if (metrics.BolaState.length !== 0) {
+ var bolaState = metrics.BolaState[0]._s;
+ if (bolaState.state !== BOLA_STATE_ONE_BITRATE) {
+ bolaState.state = BOLA_STATE_STARTUP;
+ }
+ metricsModel.updateBolaState(mediaType, bolaState);
+ }
+ });
+ }
+
+ function onPeriodSwitchStarted() {
+ // TODO
+ }
+
+ function execute(rulesContext, callback) {
+ var streamProcessor = rulesContext.getStreamProcessor();
+ streamProcessor.getScheduleController().setTimeToLoadDelay(0);
+
+ var switchRequest = (0, _SwitchRequest2['default'])(context).create(_SwitchRequest2['default'].NO_CHANGE, _SwitchRequest2['default'].WEAK, { name: BolaRule.__dashjs_factory_name });
+
+ var mediaInfo = rulesContext.getMediaInfo();
+ var mediaType = mediaInfo.type;
+ var metrics = metricsModel.getReadOnlyMetricsFor(mediaType);
+
+ if (metrics.BolaState.length === 0) {
+ // initialization
+
+ if (BOLA_DEBUG) log('BolaDebug ' + mediaType + '\nBolaDebug ' + mediaType + ' BolaRule for state=- fragmentStart=' + adapter.getIndexHandlerTime(rulesContext.getStreamProcessor()).toFixed(3));
+
+ var initState = calculateInitialState(rulesContext);
+ metricsModel.updateBolaState(mediaType, initState);
+
+ var q = 0;
+ if (initState.state !== BOLA_STATE_ONE_BITRATE) {
+ // initState.state === BOLA_STATE_STARTUP
+
+ eventMediaTypes.push(mediaType);
+
+ // Bola is not invoked by dash.js to determine the bitrate quality for the first fragment. We might estimate the throughput level here, but the metric related to the HTTP request for the first fragment is usually not available.
+ // TODO: at some point, we may want to consider a tweak that redownloads the first fragment at a higher quality
+
+ var initThroughput = getRecentThroughput(metrics, initState.throughputCount, mediaType);
+ if (initThroughput === 0) {
+ // We don't have information about any download yet - let someone else decide quality.
+ if (BOLA_DEBUG) log('BolaDebug ' + mediaType + ' BolaRule quality unchanged for INITIALIZE');
+ callback(switchRequest);
+ return;
+ }
+ q = getQualityFromThroughput(initState, initThroughput * initState.bandwidthSafetyFactor);
+ initState.lastQuality = q;
+ switchRequest.value = q;
+ switchRequest.priority = _SwitchRequest2['default'].DEFAULT;
+ switchRequest.reason.state = initState.state;
+ switchRequest.reason.throughput = initThroughput;
+ }
+
+ if (BOLA_DEBUG) log('BolaDebug ' + mediaType + ' BolaRule quality ' + q + ' for INITIALIZE');
+ callback(switchRequest);
+ return;
+ } // initialization
+
+ // metrics.BolaState.length > 0
+ var bolaState = metrics.BolaState[0]._s;
+ // TODO: does changing bolaState conform to coding style, or should we clone?
+
+ if (bolaState.state === BOLA_STATE_ONE_BITRATE) {
+ if (BOLA_DEBUG) log('BolaDebug ' + mediaType + ' BolaRule quality 0 for ONE_BITRATE');
+ callback(switchRequest);
+ return;
+ }
+
+ var bitrates = bolaState.bitrates;
+ var utilities = bolaState.utilities;
+
+ if (BOLA_DEBUG) log('BolaDebug ' + mediaType + '\nBolaDebug ' + mediaType + ' EXECUTE BolaRule for state=' + bolaState.state + ' fragmentStart=' + adapter.getIndexHandlerTime(rulesContext.getStreamProcessor()).toFixed(3));
+
+ var bufferLevel = dashMetrics.getCurrentBufferLevel(metrics) ? dashMetrics.getCurrentBufferLevel(metrics) : 0;
+ var recentThroughput = getRecentThroughput(metrics, bolaState.throughputCount, mediaType);
+
+ if (bufferLevel <= 0.1) {
+ // rebuffering occurred, reset virtual buffer
+ bolaState.virtualBuffer = 0;
+ }
+
+ // find out if there was delay because of lack of availability or because buffer level > bufferTarget
+ var timeSinceLastDownload = getDelayFromLastFragmentInSeconds(metrics, mediaType);
+ if (timeSinceLastDownload > 0) {
+ // TODO: maybe we should set some positive threshold here
+ bolaState.virtualBuffer += timeSinceLastDownload;
+ }
+ if (bolaState.virtualBuffer < 0) {
+ bolaState.virtualBuffer = 0;
+ }
+
+ var effectiveBufferLevel = bufferLevel + bolaState.virtualBuffer;
+ var bolaQuality = getQualityFromBufferLevel(bolaState, effectiveBufferLevel);
+
+ if (BOLA_DEBUG) log('BolaDebug ' + mediaType + ' BolaRule bufferLevel=' + bufferLevel.toFixed(3) + '(+' + bolaState.virtualBuffer.toFixed(3) + '=' + effectiveBufferLevel.toFixed(3) + ') recentThroughput=' + (0.000001 * recentThroughput).toFixed(3) + ' tentativeQuality=' + bolaQuality);
+
+ if (bolaState.state === BOLA_STATE_STARTUP) {
+ // in startup phase, use some throughput estimation
+
+ var q = getQualityFromThroughput(bolaState, recentThroughput * bolaState.bandwidthSafetyFactor);
+
+ if (bufferLevel > bolaState.fragmentDuration / REBUFFER_SAFETY_FACTOR) {
+ // only switch to steady state if we believe we have enough buffer to not trigger quality drop to a safeBitrate
+ bolaState.state = BOLA_STATE_STEADY;
+
+ var wantEffectiveBuffer = 0;
+ for (var i = 0; i < q; ++i) {
+ // We want minimum effective buffer (bufferLevel + virtualBuffer) that gives a higher score for q when compared with any other i < q.
+ // We want
+ // (Vp * (utilities[q] + gp) - bufferLevel) / bitrates[q]
+ // to be >= any score for i < q.
+ // We get score equality for q and i when:
+ var b = bolaState.Vp * (bolaState.gp + (bitrates[q] * utilities[i] - bitrates[i] * utilities[q]) / (bitrates[q] - bitrates[i]));
+ if (b > wantEffectiveBuffer) {
+ wantEffectiveBuffer = b;
+ }
+ }
+ if (wantEffectiveBuffer > bufferLevel) {
+ bolaState.virtualBuffer = wantEffectiveBuffer - bufferLevel;
+ }
+ }
+
+ if (BOLA_DEBUG) log('BolaDebug ' + mediaType + ' BolaRule quality ' + q + ' for STARTUP');
+ bolaState.lastQuality = q;
+ metricsModel.updateBolaState(mediaType, bolaState);
+ switchRequest.value = q;
+ switchRequest.priority = _SwitchRequest2['default'].DEFAULT;
+ switchRequest.reason.state = BOLA_STATE_STARTUP;
+ switchRequest.reason.throughput = recentThroughput;
+ callback(switchRequest);
+ return;
+ }
+
+ // steady state
+
+ // we want to avoid oscillations
+ // We implement the "BOLA-O" variant: when network bandwidth lies between two encoded bitrate levels, stick to the lowest level.
+ if (bolaQuality > bolaState.lastQuality) {
+ // do not multiply throughput by bandwidthSafetyFactor here: we are not using throughput estimation but capping bitrate to avoid oscillations
+ var q = getQualityFromThroughput(bolaState, recentThroughput);
+ if (bolaQuality > q) {
+ // only intervene if we are trying to *increase* quality to an *unsustainable* level
+
+ if (q < bolaState.lastQuality) {
+ // we are only avoid oscillations - do not drop below last quality
+ q = bolaState.lastQuality;
+ }
+ // We are dropping to an encoding bitrate which is a little less than the network bandwidth because bitrate levels are discrete. Quality q might lead to buffer inflation, so we deflate buffer to the level that q gives postive utility. This delay will be added below.
+ bolaQuality = q;
+ }
+ }
+
+ // Try to make sure that we can download a chunk without rebuffering. This is especially important for live streaming.
+ if (recentThroughput > 0) {
+ // We can only perform this check if we have a throughput estimate.
+ var safeBitrate = REBUFFER_SAFETY_FACTOR * recentThroughput * bufferLevel / bolaState.fragmentDuration;
+ while (bolaQuality > 0 && bitrates[bolaQuality] > safeBitrate) {
+ --bolaQuality;
+ }
+ }
+
+ // We do not want to overfill buffer with low quality chunks.
+ // Note that there will be no delay if buffer level is below MINIMUM_BUFFER_S, probably even with some margin higher than MINIMUM_BUFFER_S.
+ var delaySeconds = 0;
+ var wantBufferLevel = bolaState.Vp * (utilities[bolaQuality] + bolaState.gp);
+ delaySeconds = effectiveBufferLevel - wantBufferLevel;
+ if (delaySeconds > 0) {
+ // First reduce virtual buffer.
+ // Note that this "delay" is the main mechanism of depleting virtualBuffer - the real buffer is depleted by playback.
+ if (delaySeconds > bolaState.virtualBuffer) {
+ delaySeconds -= bolaState.virtualBuffer;
+ bolaState.virtualBuffer = 0;
+ } else {
+ bolaState.virtualBuffer -= delaySeconds;
+ delaySeconds = 0;
+ }
+ }
+ if (delaySeconds > 0) {
+ // After depleting all virtual buffer, set delay.
+ if (bolaQuality === bitrates.length - 1) {
+ // At top quality, allow schedule controller to decide how far to fill buffer.
+ delaySeconds = 0;
+ } else {
+ streamProcessor.getScheduleController().setTimeToLoadDelay(1000 * delaySeconds);
+ }
+ } else {
+ delaySeconds = 0;
+ }
+
+ bolaState.lastQuality = bolaQuality;
+ metricsModel.updateBolaState(mediaType, bolaState);
+
+ switchRequest.value = bolaQuality;
+ switchRequest.priority = _SwitchRequest2['default'].DEFAULT;
+ switchRequest.reason.state = bolaState.state;
+ switchRequest.reason.throughput = recentThroughput;
+ switchRequest.reason.bufferLevel = bufferLevel;
+
+ if (BOLA_DEBUG) log('BolaDebug ' + mediaType + ' BolaRule quality ' + bolaQuality + ' delay=' + delaySeconds.toFixed(3) + ' for STEADY');
+ callback(switchRequest);
+ }
+
+ function reset() {
+ eventBus.off(_coreEventsEvents2['default'].BUFFER_EMPTY, onBufferEmpty, instance);
+ eventBus.off(_coreEventsEvents2['default'].PLAYBACK_SEEKING, onPlaybackSeeking, instance);
+ eventBus.off(_coreEventsEvents2['default'].PERIOD_SWITCH_STARTED, onPeriodSwitchStarted, instance);
+ setup();
+ }
+
+ instance = {
+ execute: execute,
+ reset: reset
+ };
+
+ setup();
+ return instance;
+}
+
+BolaRule.__dashjs_factory_name = 'BolaRule';
+var factory = _coreFactoryMaker2['default'].getClassFactory(BolaRule);
+factory.BOLA_STATE_ONE_BITRATE = BOLA_STATE_ONE_BITRATE;
+factory.BOLA_STATE_STARTUP = BOLA_STATE_STARTUP;
+factory.BOLA_STATE_STEADY = BOLA_STATE_STEADY;
+factory.BOLA_DEBUG = BOLA_DEBUG; // TODO: remove
+exports['default'] = factory;
+module.exports = exports['default'];
+
+},{"10":10,"101":101,"13":13,"130":130,"15":15,"179":179,"68":68,"8":8,"9":9}],135:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _SwitchRequest = _dereq_(130);
+
+var _SwitchRequest2 = _interopRequireDefault(_SwitchRequest);
+
+var _modelsMediaPlayerModel = _dereq_(101);
+
+var _modelsMediaPlayerModel2 = _interopRequireDefault(_modelsMediaPlayerModel);
+
+var _controllersAbrController = _dereq_(60);
+
+var _controllersAbrController2 = _interopRequireDefault(_controllersAbrController);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _coreDebug = _dereq_(8);
+
+var _coreDebug2 = _interopRequireDefault(_coreDebug);
+
+function BufferOccupancyRule(config) {
+
+ var instance = undefined;
+ var context = this.context;
+ var log = (0, _coreDebug2['default'])(context).getInstance().log;
+
+ var metricsModel = config.metricsModel;
+ var dashMetrics = config.dashMetrics;
+
+ var lastSwitchTime = undefined,
+ mediaPlayerModel = undefined;
+
+ function setup() {
+ lastSwitchTime = 0;
+ mediaPlayerModel = (0, _modelsMediaPlayerModel2['default'])(context).getInstance();
+ }
+
+ function execute(rulesContext, callback) {
+ var now = new Date().getTime() / 1000;
+ var mediaInfo = rulesContext.getMediaInfo();
+ var representationInfo = rulesContext.getTrackInfo();
+ var mediaType = mediaInfo.type;
+ var waitToSwitchTime = !isNaN(representationInfo.fragmentDuration) ? representationInfo.fragmentDuration / 2 : 2;
+ var current = rulesContext.getCurrentValue();
+ var streamProcessor = rulesContext.getStreamProcessor();
+ var abrController = streamProcessor.getABRController();
+ var metrics = metricsModel.getReadOnlyMetricsFor(mediaType);
+ var lastBufferLevel = dashMetrics.getCurrentBufferLevel(metrics);
+ var lastBufferStateVO = metrics.BufferState.length > 0 ? metrics.BufferState[metrics.BufferState.length - 1] : null;
+ var isBufferRich = false;
+ var maxIndex = mediaInfo.representationCount - 1;
+ var switchRequest = (0, _SwitchRequest2['default'])(context).create(_SwitchRequest2['default'].NO_CHANGE, _SwitchRequest2['default'].WEAK, { name: BufferOccupancyRule.__dashjs_factory_name });
+
+ if (now - lastSwitchTime < waitToSwitchTime || abrController.getAbandonmentStateFor(mediaType) === _controllersAbrController2['default'].ABANDON_LOAD) {
+ callback(switchRequest);
+ return;
+ }
+
+ if (lastBufferStateVO !== null) {
+ // This will happen when another rule tries to switch from top to any other.
+ // If there is enough buffer why not try to stay at high level.
+ if (lastBufferLevel > lastBufferStateVO.target) {
+ isBufferRich = lastBufferLevel - lastBufferStateVO.target > mediaPlayerModel.getRichBufferThreshold();
+
+ if (isBufferRich && mediaInfo.representationCount > 1) {
+ switchRequest.value = maxIndex;
+ switchRequest.priority = _SwitchRequest2['default'].STRONG;
+ switchRequest.reason.bufferLevel = lastBufferLevel;
+ switchRequest.reason.bufferTarget = lastBufferStateVO.target;
+ }
+ }
+ }
+
+ if (switchRequest.value !== _SwitchRequest2['default'].NO_CHANGE && switchRequest.value !== current) {
+ log('BufferOccupancyRule requesting switch to index: ', switchRequest.value, 'type: ', mediaType, ' Priority: ', switchRequest.priority === _SwitchRequest2['default'].DEFAULT ? 'Default' : switchRequest.priority === _SwitchRequest2['default'].STRONG ? 'Strong' : 'Weak');
+ }
+
+ callback(switchRequest);
+ }
+
+ function reset() {
+ lastSwitchTime = 0;
+ }
+
+ instance = {
+ execute: execute,
+ reset: reset
+ };
+
+ setup();
+
+ return instance;
+}
+
+BufferOccupancyRule.__dashjs_factory_name = 'BufferOccupancyRule';
+exports['default'] = _coreFactoryMaker2['default'].getClassFactory(BufferOccupancyRule);
+module.exports = exports['default'];
+
+},{"10":10,"101":101,"130":130,"60":60,"8":8}],136:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _SwitchRequest = _dereq_(130);
+
+var _SwitchRequest2 = _interopRequireDefault(_SwitchRequest);
+
+var _controllersBufferController = _dereq_(63);
+
+var _controllersBufferController2 = _interopRequireDefault(_controllersBufferController);
+
+var _coreEventBus = _dereq_(9);
+
+var _coreEventBus2 = _interopRequireDefault(_coreEventBus);
+
+var _coreEventsEvents = _dereq_(13);
+
+var _coreEventsEvents2 = _interopRequireDefault(_coreEventsEvents);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _coreDebug = _dereq_(8);
+
+var _coreDebug2 = _interopRequireDefault(_coreDebug);
+
+function InsufficientBufferRule(config) {
+
+ var context = this.context;
+ var log = (0, _coreDebug2['default'])(context).getInstance().log;
+ var eventBus = (0, _coreEventBus2['default'])(context).getInstance();
+
+ var metricsModel = config.metricsModel;
+
+ var instance = undefined,
+ bufferStateDict = undefined,
+ lastSwitchTime = undefined,
+ waitToSwitchTime = undefined;
+
+ function setup() {
+ bufferStateDict = {};
+ lastSwitchTime = 0;
+ waitToSwitchTime = 1000;
+ eventBus.on(_coreEventsEvents2['default'].PLAYBACK_SEEKING, onPlaybackSeeking, instance);
+ }
+
+ function execute(rulesContext, callback) {
+ var now = new Date().getTime();
+ var mediaType = rulesContext.getMediaInfo().type;
+ var current = rulesContext.getCurrentValue();
+ var metrics = metricsModel.getReadOnlyMetricsFor(mediaType);
+ var lastBufferStateVO = metrics.BufferState.length > 0 ? metrics.BufferState[metrics.BufferState.length - 1] : null;
+ var switchRequest = (0, _SwitchRequest2['default'])(context).create(_SwitchRequest2['default'].NO_CHANGE, _SwitchRequest2['default'].WEAK, { name: InsufficientBufferRule.__dashjs_factory_name });
+
+ if (now - lastSwitchTime < waitToSwitchTime || lastBufferStateVO === null) {
+ callback(switchRequest);
+ return;
+ }
+
+ setBufferInfo(mediaType, lastBufferStateVO.state);
+ // After the sessions first buffer loaded event , if we ever have a buffer empty event we want to switch all the way down.
+ if (lastBufferStateVO.state === _controllersBufferController2['default'].BUFFER_EMPTY && bufferStateDict[mediaType].firstBufferLoadedEvent !== undefined) {
+ switchRequest.value = 0;
+ switchRequest.priority = _SwitchRequest2['default'].STRONG;
+ switchRequest.reason.bufferState = lastBufferStateVO.state;
+
+ switchRequest = (0, _SwitchRequest2['default'])(context).create(0, _SwitchRequest2['default'].STRONG);
+ }
+
+ if (switchRequest.value !== _SwitchRequest2['default'].NO_CHANGE && switchRequest.value !== current) {
+ log('InsufficientBufferRule requesting switch to index: ', switchRequest.value, 'type: ', mediaType, ' Priority: ', switchRequest.priority === _SwitchRequest2['default'].DEFAULT ? 'Default' : switchRequest.priority === _SwitchRequest2['default'].STRONG ? 'Strong' : 'Weak');
+ }
+
+ lastSwitchTime = now;
+ callback(switchRequest);
+ }
+
+ function setBufferInfo(type, state) {
+ bufferStateDict[type] = bufferStateDict[type] || {};
+ bufferStateDict[type].state = state;
+ if (state === _controllersBufferController2['default'].BUFFER_LOADED && !bufferStateDict[type].firstBufferLoadedEvent) {
+ bufferStateDict[type].firstBufferLoadedEvent = true;
+ }
+ }
+
+ function onPlaybackSeeking() {
+ bufferStateDict = {};
+ }
+
+ function reset() {
+ eventBus.off(_coreEventsEvents2['default'].PLAYBACK_SEEKING, onPlaybackSeeking, instance);
+ bufferStateDict = {};
+ lastSwitchTime = 0;
+ }
+
+ instance = {
+ execute: execute,
+ reset: reset
+ };
+
+ setup();
+
+ return instance;
+}
+
+InsufficientBufferRule.__dashjs_factory_name = 'InsufficientBufferRule';
+exports['default'] = _coreFactoryMaker2['default'].getClassFactory(InsufficientBufferRule);
+module.exports = exports['default'];
+
+},{"10":10,"13":13,"130":130,"63":63,"8":8,"9":9}],137:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _SwitchRequest = _dereq_(130);
+
+var _SwitchRequest2 = _interopRequireDefault(_SwitchRequest);
+
+var _controllersBufferController = _dereq_(63);
+
+var _controllersBufferController2 = _interopRequireDefault(_controllersBufferController);
+
+var _controllersAbrController = _dereq_(60);
+
+var _controllersAbrController2 = _interopRequireDefault(_controllersAbrController);
+
+var _modelsMediaPlayerModel = _dereq_(101);
+
+var _modelsMediaPlayerModel2 = _interopRequireDefault(_modelsMediaPlayerModel);
+
+var _voMetricsHTTPRequest = _dereq_(179);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _coreDebug = _dereq_(8);
+
+var _coreDebug2 = _interopRequireDefault(_coreDebug);
+
+function ThroughputRule(config) {
+
+ var MAX_MEASUREMENTS_TO_KEEP = 20;
+ var AVERAGE_THROUGHPUT_SAMPLE_AMOUNT_LIVE = 3;
+ var AVERAGE_THROUGHPUT_SAMPLE_AMOUNT_VOD = 4;
+ var CACHE_LOAD_THRESHOLD_VIDEO = 50;
+ var CACHE_LOAD_THRESHOLD_AUDIO = 5;
+ var THROUGHPUT_DECREASE_SCALE = 1.3;
+ var THROUGHPUT_INCREASE_SCALE = 1.3;
+
+ var context = this.context;
+ var log = (0, _coreDebug2['default'])(context).getInstance().log;
+ var dashMetrics = config.dashMetrics;
+ var metricsModel = config.metricsModel;
+
+ var throughputArray = undefined,
+ cacheLoadDict = undefined,
+ mediaPlayerModel = undefined;
+
+ function setup() {
+ throughputArray = [];
+ cacheLoadDict = { audio: { threshold: CACHE_LOAD_THRESHOLD_AUDIO, value: NaN }, video: { threshold: CACHE_LOAD_THRESHOLD_VIDEO, value: NaN } }; //threshold is in milliseconds
+ mediaPlayerModel = (0, _modelsMediaPlayerModel2['default'])(context).getInstance();
+ }
+
+ function storeLastRequestThroughputByType(type, throughput) {
+ throughputArray[type] = throughputArray[type] || [];
+ throughputArray[type].push(throughput);
+ }
+
+ function getSample(type, isDynamic) {
+ var size = Math.min(throughputArray[type].length, isDynamic ? AVERAGE_THROUGHPUT_SAMPLE_AMOUNT_LIVE : AVERAGE_THROUGHPUT_SAMPLE_AMOUNT_VOD);
+ var sampleArray = throughputArray[type].slice(size * -1, throughputArray[type].length);
+ if (sampleArray.length > 1) {
+ sampleArray.reduce(function (a, b) {
+ if (a * THROUGHPUT_INCREASE_SCALE <= b || a >= b * THROUGHPUT_DECREASE_SCALE) {
+ size++;
+ }
+ return b;
+ });
+ }
+ size = Math.min(throughputArray[type].length, size);
+ return throughputArray[type].slice(size * -1, throughputArray[type].length);
+ }
+
+ function getAverageThroughput(type, isDynamic) {
+ var sample = getSample(type, isDynamic);
+ var averageThroughput = 0;
+ if (sample.length > 0) {
+ var totalSampledValue = sample.reduce(function (a, b) {
+ return a + b;
+ }, 0);
+ averageThroughput = totalSampledValue / sample.length;
+ }
+ if (throughputArray[type].length >= MAX_MEASUREMENTS_TO_KEEP) {
+ throughputArray[type].shift();
+ }
+ return averageThroughput / 1000 * mediaPlayerModel.getBandwidthSafetyFactor();
+ }
+
+ function execute(rulesContext, callback) {
+
+ var mediaInfo = rulesContext.getMediaInfo();
+ var mediaType = mediaInfo.type;
+ var currentQuality = rulesContext.getCurrentValue();
+ var metrics = metricsModel.getReadOnlyMetricsFor(mediaType);
+ var streamProcessor = rulesContext.getStreamProcessor();
+ var abrController = streamProcessor.getABRController();
+ var isDynamic = streamProcessor.isDynamic();
+ var lastRequest = dashMetrics.getCurrentHttpRequest(metrics);
+ var bufferStateVO = metrics.BufferState.length > 0 ? metrics.BufferState[metrics.BufferState.length - 1] : null;
+ var switchRequest = (0, _SwitchRequest2['default'])(context).create(_SwitchRequest2['default'].NO_CHANGE, _SwitchRequest2['default'].WEAK, { name: ThroughputRule.__dashjs_factory_name });
+
+ if (!metrics || !lastRequest || lastRequest.type !== _voMetricsHTTPRequest.HTTPRequest.MEDIA_SEGMENT_TYPE || !bufferStateVO) {
+ callback(switchRequest);
+ return;
+ }
+
+ var downloadTimeInMilliseconds = undefined;
+
+ if (lastRequest.trace && lastRequest.trace.length) {
+
+ downloadTimeInMilliseconds = lastRequest._tfinish.getTime() - lastRequest.tresponse.getTime() + 1; //Make sure never 0 we divide by this value. Avoid infinity!
+
+ var bytes = lastRequest.trace.reduce(function (a, b) {
+ return a + b.b[0];
+ }, 0);
+ var lastRequestThroughput = Math.round(bytes * 8 / (downloadTimeInMilliseconds / 1000));
+
+ //Prevent cached fragment loads from skewing the average throughput value - allow first even if cached to set allowance for ABR rules..
+ if (downloadTimeInMilliseconds <= cacheLoadDict[mediaType].threshold) {
+ cacheLoadDict[mediaType].value = lastRequestThroughput / 1000;
+ } else {
+ cacheLoadDict[mediaType].value = NaN;
+ storeLastRequestThroughputByType(mediaType, lastRequestThroughput);
+ }
+ }
+
+ var throughput = Math.round(!isNaN(cacheLoadDict[mediaType].value) ? cacheLoadDict[mediaType].value : getAverageThroughput(mediaType, isDynamic));
+ abrController.setAverageThroughput(mediaType, throughput);
+
+ if (abrController.getAbandonmentStateFor(mediaType) !== _controllersAbrController2['default'].ABANDON_LOAD) {
+
+ if (bufferStateVO.state === _controllersBufferController2['default'].BUFFER_LOADED || isDynamic) {
+ var newQuality = abrController.getQualityForBitrate(mediaInfo, throughput);
+ streamProcessor.getScheduleController().setTimeToLoadDelay(0);
+ switchRequest.value = newQuality;
+ switchRequest.priority = _SwitchRequest2['default'].DEFAULT;
+ switchRequest.reason.throughput = throughput;
+ }
+
+ if (switchRequest.value !== _SwitchRequest2['default'].NO_CHANGE && switchRequest.value !== currentQuality) {
+ log('ThroughputRule requesting switch to index: ', switchRequest.value, 'type: ', mediaType, ' Priority: ', switchRequest.priority === _SwitchRequest2['default'].DEFAULT ? 'Default' : switchRequest.priority === _SwitchRequest2['default'].STRONG ? 'Strong' : 'Weak', 'Average throughput', Math.round(throughput), 'kbps');
+ }
+ }
+
+ callback(switchRequest);
+ }
+
+ function reset() {
+ setup();
+ }
+
+ var instance = {
+ execute: execute,
+ reset: reset
+ };
+
+ setup();
+ return instance;
+}
+
+ThroughputRule.__dashjs_factory_name = 'ThroughputRule';
+exports['default'] = _coreFactoryMaker2['default'].getClassFactory(ThroughputRule);
+module.exports = exports['default'];
+
+},{"10":10,"101":101,"130":130,"179":179,"60":60,"63":63,"8":8}],138:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+function BasicSelector(config) {
+
+ var instance = undefined;
+
+ var blacklistController = config.blacklistController;
+
+ function select(baseUrls) {
+ var index = 0;
+ var selectedBaseUrl;
+
+ if (baseUrls && baseUrls.some(function (baseUrl, idx) {
+ index = idx;
+
+ return !blacklistController.contains(baseUrl.serviceLocation);
+ })) {
+ selectedBaseUrl = baseUrls[index];
+ }
+
+ return selectedBaseUrl;
+ }
+
+ instance = {
+ select: select
+ };
+
+ return instance;
+}
+
+BasicSelector.__dashjs_factory_name = 'BasicSelector';
+exports['default'] = _coreFactoryMaker2['default'].getClassFactory(BasicSelector);
+module.exports = exports['default'];
+
+},{"10":10}],139:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+function DVBSelector(config) {
+
+ var instance = undefined;
+
+ var blacklistController = config.blacklistController;
+
+ function getNonBlacklistedBaseUrls(urls) {
+ var removedPriorities = [];
+
+ var samePrioritiesFilter = function samePrioritiesFilter(el) {
+ if (removedPriorities.length) {
+ if (el.dvb_priority && removedPriorities.indexOf(el.dvb_priority) !== -1) {
+ return false;
+ }
+ }
+
+ return true;
+ };
+
+ var serviceLocationFilter = function serviceLocationFilter(baseUrl) {
+ if (blacklistController.contains(baseUrl.serviceLocation)) {
+ // whenever a BaseURL is removed from the available list of
+ // BaseURLs, any other BaseURL with the same @priority
+ // value as the BaseURL being removed shall also be removed
+ if (baseUrl.dvb_priority) {
+ removedPriorities.push(baseUrl.dvb_priority);
+ }
+
+ // all URLs in the list which have a @serviceLocation
+ // attribute matching an entry in the blacklist shall be
+ // removed from the available list of BaseURLs
+ return false;
+ }
+
+ return true;
+ };
+
+ return urls.filter(serviceLocationFilter).filter(samePrioritiesFilter);
+ }
+
+ function selectByWeight(availableUrls) {
+ var prioritySorter = function prioritySorter(a, b) {
+ var diff = a.dvb_priority - b.dvb_priority;
+ return isNaN(diff) ? 0 : diff;
+ };
+
+ var topPriorityFilter = function topPriorityFilter(baseUrl, idx, arr) {
+ return !idx || arr[0].dvb_priority && baseUrl.dvb_priority && arr[0].dvb_priority === baseUrl.dvb_priority;
+ };
+
+ var totalWeight = 0;
+ var cumulWeights = [];
+ var idx = 0;
+ var rn;
+ var urls;
+
+ // It shall begin by taking the set of resolved BaseURLs present or inherited at the current
+ // position in the MPD, resolved and filtered as described in 10.8.2.1, that have the lowest
+ // @priority attribute value.
+ urls = availableUrls.sort(prioritySorter).filter(topPriorityFilter);
+
+ if (urls.length) {
+ if (urls.length > 1) {
+ // If there is more than one BaseURL with this lowest @priority attribute value then the Player
+ // shall select one of them at random such that the probability of each BaseURL being chosen
+ // is proportional to the value of its @weight attribute. The method described in RFC 2782
+ // [26] or picking from a number of weighted entries is suitable for this, but there may be other
+ // algorithms which achieve the same effect.
+
+ // add all the weights together, storing the accumulated weight per entry
+ urls.forEach(function (baseUrl) {
+ totalWeight += baseUrl.dvb_weight;
+ cumulWeights.push(totalWeight);
+ });
+
+ // pick a random number between zero and totalWeight
+ rn = Math.floor(Math.random() * (totalWeight - 1));
+
+ // select the index for the range rn falls within
+ cumulWeights.every(function (limit, index) {
+ idx = index;
+
+ if (rn < limit) {
+ return false;
+ }
+
+ return true;
+ });
+ }
+
+ return urls[idx];
+ }
+ }
+
+ function select(baseUrls) {
+ return baseUrls && selectByWeight(getNonBlacklistedBaseUrls(baseUrls));
+ }
+
+ instance = {
+ select: select
+ };
+
+ return instance;
+}
+
+DVBSelector.__dashjs_factory_name = 'DVBSelector';
+exports['default'] = _coreFactoryMaker2['default'].getClassFactory(DVBSelector);
+module.exports = exports['default'];
+
+},{"10":10}],140:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _modelsMediaPlayerModel = _dereq_(101);
+
+var _modelsMediaPlayerModel2 = _interopRequireDefault(_modelsMediaPlayerModel);
+
+var _controllersPlaybackController = _dereq_(68);
+
+var _controllersPlaybackController2 = _interopRequireDefault(_controllersPlaybackController);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+function BufferLevelRule(config) {
+
+ var context = this.context;
+ var dashMetrics = config.dashMetrics;
+ var metricsModel = config.metricsModel;
+ var textSourceBuffer = config.textSourceBuffer;
+
+ var mediaPlayerModel = undefined,
+ playbackController = undefined;
+
+ function setup() {
+ mediaPlayerModel = (0, _modelsMediaPlayerModel2['default'])(context).getInstance();
+ playbackController = (0, _controllersPlaybackController2['default'])(context).getInstance();
+ }
+
+ function execute(streamProcessor, type, videoTrackPresent) {
+ var bufferLevel = dashMetrics.getCurrentBufferLevel(metricsModel.getReadOnlyMetricsFor(type));
+ return bufferLevel < getBufferTarget(streamProcessor, type, videoTrackPresent);
+ }
+
+ function getBufferTarget(streamProcessor, type, videoTrackPresent) {
+ var bufferTarget = NaN;
+ var representationInfo = streamProcessor.getCurrentRepresentationInfo();
+ if (type === 'fragmentedText') {
+ bufferTarget = textSourceBuffer.getAllTracksAreDisabled() ? 0 : representationInfo.fragmentDuration;
+ } else if (type === 'audio' && videoTrackPresent) {
+ var videoBufferLevel = dashMetrics.getCurrentBufferLevel(metricsModel.getReadOnlyMetricsFor('video'));
+ bufferTarget = Math.floor(Math.max(videoBufferLevel, representationInfo.fragmentDuration));
+ } else {
+ var streamInfo = representationInfo.mediaInfo.streamInfo;
+ var abrController = streamProcessor.getABRController();
+ if (abrController.isPlayingAtTopQuality(streamInfo)) {
+ var isLongFormContent = streamInfo.manifestInfo.duration >= mediaPlayerModel.getLongFormContentDurationThreshold();
+ bufferTarget = isLongFormContent ? mediaPlayerModel.getBufferTimeAtTopQualityLongForm() : mediaPlayerModel.getBufferTimeAtTopQuality();
+ } else {
+ bufferTarget = mediaPlayerModel.getStableBufferTime();
+ }
+ }
+
+ return bufferTarget;
+ }
+
+ var instance = {
+ execute: execute,
+ getBufferTarget: getBufferTarget
+ };
+
+ setup();
+ return instance;
+}
+
+BufferLevelRule.__dashjs_factory_name = 'BufferLevelRule';
+exports['default'] = _coreFactoryMaker2['default'].getClassFactory(BufferLevelRule);
+module.exports = exports['default'];
+
+},{"10":10,"101":101,"68":68}],141:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreDebug = _dereq_(8);
+
+var _coreDebug2 = _interopRequireDefault(_coreDebug);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+function NextFragmentRequestRule(config) {
+
+ var context = this.context;
+ var log = (0, _coreDebug2['default'])(context).getInstance().log;
+ var adapter = config.adapter;
+ var sourceBufferController = config.sourceBufferController;
+ var textSourceBuffer = config.textSourceBuffer;
+
+ function execute(streamProcessor, requestToReplace) {
+
+ var representationInfo = streamProcessor.getCurrentRepresentationInfo();
+ var mediaInfo = representationInfo.mediaInfo;
+ var mediaType = mediaInfo.type;
+ var scheduleController = streamProcessor.getScheduleController();
+ var seekTarget = scheduleController.getSeekTarget();
+ var hasSeekTarget = !isNaN(seekTarget);
+ var buffer = streamProcessor.getBuffer();
+
+ var time = hasSeekTarget ? seekTarget : adapter.getIndexHandlerTime(streamProcessor);
+
+ if (isNaN(time) || mediaType === 'fragmentedText' && textSourceBuffer.getAllTracksAreDisabled()) {
+ return null;
+ }
+
+ if (hasSeekTarget) {
+ scheduleController.setSeekTarget(NaN);
+ }
+
+ /**
+ * This is critical for IE/Safari/EDGE
+ * */
+ if (buffer) {
+ var range = sourceBufferController.getBufferRange(streamProcessor.getBuffer(), time);
+ if (range !== null) {
+ log('Prior to making a request for time, NextFragmentRequestRule is aligning index handler\'s currentTime with bufferedRange.end.', time, ' was changed to ', range.end);
+ time = range.end;
+ }
+ }
+
+ var request = undefined;
+ if (requestToReplace) {
+ time = requestToReplace.startTime + requestToReplace.duration / 2;
+ request = adapter.getFragmentRequestForTime(streamProcessor, representationInfo, time, { timeThreshold: 0, ignoreIsFinished: true });
+ } else {
+ request = adapter.getFragmentRequestForTime(streamProcessor, representationInfo, time, { keepIdx: !hasSeekTarget });
+ if (request && streamProcessor.getFragmentModel().isFragmentLoaded(request)) {
+ request = adapter.getNextFragmentRequest(streamProcessor, representationInfo);
+ }
+ if (request) {
+ adapter.setIndexHandlerTime(streamProcessor, request.startTime + request.duration);
+ request.delayLoadingTime = new Date().getTime() + scheduleController.getTimeToLoadDelay();
+ scheduleController.setTimeToLoadDelay(0);
+ }
+ }
+
+ return request;
+ }
+
+ var instance = {
+ execute: execute
+ };
+
+ return instance;
+}
+
+NextFragmentRequestRule.__dashjs_factory_name = 'NextFragmentRequestRule';
+exports['default'] = _coreFactoryMaker2['default'].getClassFactory(NextFragmentRequestRule);
+module.exports = exports['default'];
+
+},{"10":10,"8":8}],142:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _SwitchRequest = _dereq_(130);
+
+var _SwitchRequest2 = _interopRequireDefault(_SwitchRequest);
+
+var _coreEventBus = _dereq_(9);
+
+var _coreEventBus2 = _interopRequireDefault(_coreEventBus);
+
+var _coreEventsEvents = _dereq_(13);
+
+var _coreEventsEvents2 = _interopRequireDefault(_coreEventsEvents);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var SEARCH_TIME_SPAN = 12 * 60 * 60; // set the time span that limits our search range to a 12 hours in seconds
+
+function LiveEdgeBinarySearchRule(config) {
+
+ var context = this.context;
+ var eventBus = (0, _coreEventBus2['default'])(context).getInstance();
+
+ var adapter = config.adapter;
+ var timelineConverter = config.timelineConverter;
+
+ var instance = undefined,
+ liveEdgeInitialSearchPosition = undefined,
+ liveEdgeSearchRange = undefined,
+ liveEdgeSearchStep = undefined,
+ representationInfo = undefined,
+ useBinarySearch = undefined,
+ fragmentDuration = undefined,
+ p = undefined,
+ callback = undefined,
+ fragmentLoader = undefined,
+ streamProcessor = undefined;
+
+ function setup() {
+ liveEdgeInitialSearchPosition = NaN;
+ liveEdgeSearchRange = null;
+ liveEdgeSearchStep = NaN;
+ representationInfo = null;
+ useBinarySearch = false;
+ fragmentDuration = NaN;
+ p = _SwitchRequest2['default'].DEFAULT;
+ }
+
+ function execute(rulesContext, callbackFunc) {
+ var request, DVRWindow; // all fragments are supposed to be available in this interval
+
+ callback = callbackFunc;
+ streamProcessor = rulesContext.getStreamProcessor();
+ fragmentLoader = streamProcessor.getFragmentLoader();
+ representationInfo = rulesContext.getTrackInfo();
+ fragmentDuration = representationInfo.fragmentDuration;
+ DVRWindow = representationInfo.DVRWindow; // all fragments are supposed to be available in this interval
+
+ // start position of the search, it is supposed to be a live edge - the last available fragment for the current mpd
+ liveEdgeInitialSearchPosition = DVRWindow.end;
+
+ if (representationInfo.useCalculatedLiveEdgeTime) {
+ //By default an expected live edge is the end of the last segment.
+ // A calculated live edge ('end' property of a range returned by TimelineConverter.calcSegmentAvailabilityRange)
+ // is used as an initial point for finding the actual live edge.
+ // But for SegmentTimeline mpds (w/o a negative @r) the end of the
+ // last segment is the actual live edge. At the same time, calculated live edge is an expected live edge.
+ // Thus, we need to switch an expected live edge and actual live edge for SegmentTimeline streams.
+ var actualLiveEdge = timelineConverter.getExpectedLiveEdge();
+ timelineConverter.setExpectedLiveEdge(liveEdgeInitialSearchPosition);
+ callback((0, _SwitchRequest2['default'])(context).create(actualLiveEdge, p));
+ return;
+ }
+
+ // we should search for a live edge in a time range which is limited by SEARCH_TIME_SPAN.
+ liveEdgeSearchRange = { start: Math.max(0, liveEdgeInitialSearchPosition - SEARCH_TIME_SPAN), end: liveEdgeInitialSearchPosition + SEARCH_TIME_SPAN };
+ // we have to use half of the availability interval (window) as a search step to ensure that we find a fragment in the window
+ liveEdgeSearchStep = Math.floor((DVRWindow.end - DVRWindow.start) / 2);
+ // start search from finding a request for the initial search time
+ request = adapter.getFragmentRequestForTime(streamProcessor, representationInfo, liveEdgeInitialSearchPosition, { ignoreIsFinished: true });
+ findLiveEdge(liveEdgeInitialSearchPosition, onSearchForFragmentSucceeded, onSearchForFragmentFailed, request);
+ }
+
+ function reset() {
+ liveEdgeInitialSearchPosition = NaN;
+ liveEdgeSearchRange = null;
+ liveEdgeSearchStep = NaN;
+ representationInfo = null;
+ useBinarySearch = false;
+ fragmentDuration = NaN;
+ streamProcessor = null;
+ fragmentLoader = null;
+ }
+
+ function findLiveEdge(searchTime, onSuccess, onError, request) {
+ var req;
+ if (request === null) {
+ // request can be null because it is out of the generated list of request. In this case we need to
+ // update the list and the DVRWindow
+ // try to get request object again
+ req = adapter.generateFragmentRequestForTime(streamProcessor, representationInfo, searchTime);
+ findLiveEdge(searchTime, onSuccess, onError, req);
+ } else {
+ var handler = function handler(e) {
+ eventBus.off(_coreEventsEvents2['default'].CHECK_FOR_EXISTENCE_COMPLETED, handler, this);
+ if (e.exists) {
+ onSuccess(e.request, searchTime);
+ } else {
+ onError(e.request, searchTime);
+ }
+ };
+
+ eventBus.on(_coreEventsEvents2['default'].CHECK_FOR_EXISTENCE_COMPLETED, handler, this);
+ fragmentLoader.checkForExistence(request);
+ }
+ }
+
+ function onSearchForFragmentFailed(request, lastSearchTime) {
+ var searchTime, req, searchInterval;
+
+ if (useBinarySearch) {
+ binarySearch(false, lastSearchTime);
+ return;
+ }
+
+ // we have not found any available fragments yet, update the search interval
+ searchInterval = lastSearchTime - liveEdgeInitialSearchPosition;
+ // we search forward and backward from the start position, increasing the search interval by the value of the half of the availability interval - liveEdgeSearchStep
+ searchTime = searchInterval > 0 ? liveEdgeInitialSearchPosition - searchInterval : liveEdgeInitialSearchPosition + Math.abs(searchInterval) + liveEdgeSearchStep;
+
+ // if the search time is out of the range bounds we have not be able to find live edge, stop trying
+ if (searchTime < liveEdgeSearchRange.start && searchTime > liveEdgeSearchRange.end) {
+ callback((0, _SwitchRequest2['default'])(context).create(null, p));
+ } else {
+ // continue searching for a first available fragment
+ req = adapter.getFragmentRequestForTime(streamProcessor, representationInfo, searchTime, { ignoreIsFinished: true });
+ findLiveEdge(searchTime, onSearchForFragmentSucceeded, onSearchForFragmentFailed, req);
+ }
+ }
+
+ function onSearchForFragmentSucceeded(request, lastSearchTime) {
+ var startTime = request.startTime;
+ var req, searchTime;
+
+ if (!useBinarySearch) {
+ // if the fragment duration is unknown we cannot use binary search because we will not be able to
+ // decide when to stop the search, so let the start time of the current fragment be a liveEdge
+ if (!representationInfo.fragmentDuration) {
+ callback((0, _SwitchRequest2['default'])(context).create(startTime, p));
+ return;
+ }
+ useBinarySearch = true;
+ liveEdgeSearchRange.end = startTime + 2 * liveEdgeSearchStep;
+
+ //if the first request has succeeded we should check next fragment - if it does not exist we have found live edge,
+ // otherwise start binary search to find live edge
+ if (lastSearchTime === liveEdgeInitialSearchPosition) {
+ searchTime = lastSearchTime + fragmentDuration;
+ req = adapter.getFragmentRequestForTime(streamProcessor, representationInfo, searchTime, { ignoreIsFinished: true });
+ findLiveEdge(searchTime, function () {
+ binarySearch(true, searchTime);
+ }, function () {
+ callback((0, _SwitchRequest2['default'])(context).create(searchTime, p));
+ }, req);
+
+ return;
+ }
+ }
+
+ binarySearch(true, lastSearchTime);
+ }
+
+ function binarySearch(lastSearchSucceeded, lastSearchTime) {
+ var isSearchCompleted, req, searchTime;
+
+ if (lastSearchSucceeded) {
+ liveEdgeSearchRange.start = lastSearchTime;
+ } else {
+ liveEdgeSearchRange.end = lastSearchTime;
+ }
+
+ isSearchCompleted = Math.floor(liveEdgeSearchRange.end - liveEdgeSearchRange.start) <= fragmentDuration;
+
+ if (isSearchCompleted) {
+ // search completed, we should take the time of the last found fragment. If the last search succeeded we
+ // take this time. Otherwise, we should subtract the time of the search step which is equal to fragment duration
+ callback((0, _SwitchRequest2['default'])(context).create(lastSearchSucceeded ? lastSearchTime : lastSearchTime - fragmentDuration, p));
+ } else {
+ // update the search time and continue searching
+ searchTime = (liveEdgeSearchRange.start + liveEdgeSearchRange.end) / 2;
+ req = adapter.getFragmentRequestForTime(streamProcessor, representationInfo, searchTime, { ignoreIsFinished: true });
+ findLiveEdge(searchTime, onSearchForFragmentSucceeded, onSearchForFragmentFailed, req);
+ }
+ }
+
+ instance = {
+ execute: execute,
+ reset: reset
+ };
+
+ setup();
+
+ return instance;
+}
+
+LiveEdgeBinarySearchRule.__dashjs_factory_name = 'LiveEdgeBinarySearchRule';
+exports['default'] = _coreFactoryMaker2['default'].getClassFactory(LiveEdgeBinarySearchRule);
+module.exports = exports['default'];
+
+},{"10":10,"13":13,"130":130,"9":9}],143:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _SwitchRequest = _dereq_(130);
+
+var _SwitchRequest2 = _interopRequireDefault(_SwitchRequest);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+function LiveEdgeWithTimeSynchronizationRule(config) {
+
+ var instance = undefined;
+ var context = this.context;
+ var timelineConverter = config.timelineConverter;
+
+ // if the time has been synchronized correctly (which it must have been
+ // to end up executing this rule), the last entry in the DVR window
+ // should be the live edge. if that is incorrect for whatever reason,
+ // playback will fail to start and some other action should be taken.
+ function execute(rulesContext, callback) {
+ var representationInfo = rulesContext.getTrackInfo();
+ var liveEdgeInitialSearchPosition = representationInfo.DVRWindow.end;
+ var p = _SwitchRequest2['default'].DEFAULT;
+
+ if (representationInfo.useCalculatedLiveEdgeTime) {
+ //By default an expected live edge is the end of the last segment.
+ // A calculated live edge ('end' property of a range returned by TimelineConverter.calcSegmentAvailabilityRange)
+ // is used as an initial point for finding the actual live edge.
+ // But for SegmentTimeline mpds (w/o a negative @r) the end of the
+ // last segment is the actual live edge. At the same time, calculated live edge is an expected live edge.
+ // Thus, we need to switch an expected live edge and actual live edge for SegmentTimeline streams.
+ var actualLiveEdge = timelineConverter.getExpectedLiveEdge();
+ timelineConverter.setExpectedLiveEdge(liveEdgeInitialSearchPosition);
+ callback((0, _SwitchRequest2['default'])(context).create(actualLiveEdge, p));
+ } else {
+ callback((0, _SwitchRequest2['default'])(context).create(liveEdgeInitialSearchPosition, p));
+ }
+ }
+
+ instance = {
+ execute: execute
+ };
+
+ return instance;
+}
+
+LiveEdgeWithTimeSynchronizationRule.__dashjs_factory_name = 'LiveEdgeWithTimeSynchronizationRule';
+exports['default'] = _coreFactoryMaker2['default'].getClassFactory(LiveEdgeWithTimeSynchronizationRule);
+module.exports = exports['default'];
+
+},{"10":10,"130":130}],144:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _dashUtilsTimelineConverter = _dereq_(37);
+
+var _dashUtilsTimelineConverter2 = _interopRequireDefault(_dashUtilsTimelineConverter);
+
+var _LiveEdgeBinarySearchRule = _dereq_(142);
+
+var _LiveEdgeBinarySearchRule2 = _interopRequireDefault(_LiveEdgeBinarySearchRule);
+
+var _LiveEdgeWithTimeSynchronizationRule = _dereq_(143);
+
+var _LiveEdgeWithTimeSynchronizationRule2 = _interopRequireDefault(_LiveEdgeWithTimeSynchronizationRule);
+
+var _dashDashAdapter = _dereq_(15);
+
+var _dashDashAdapter2 = _interopRequireDefault(_dashDashAdapter);
+
+var TIME_SYNCHRONIZED_RULES = 'withAccurateTimeSourceRules';
+var BEST_GUESS_RULES = 'bestGuestRules';
+
+function SynchronizationRulesCollection() {
+
+ var context = this.context;
+
+ var instance = undefined,
+ withAccurateTimeSourceRules = undefined,
+ bestGuestRules = undefined;
+
+ function initialize() {
+ withAccurateTimeSourceRules = [];
+ bestGuestRules = [];
+
+ withAccurateTimeSourceRules.push((0, _LiveEdgeWithTimeSynchronizationRule2['default'])(context).create({
+ timelineConverter: (0, _dashUtilsTimelineConverter2['default'])(context).getInstance()
+ }));
+
+ bestGuestRules.push((0, _LiveEdgeBinarySearchRule2['default'])(context).create({
+ timelineConverter: (0, _dashUtilsTimelineConverter2['default'])(context).getInstance(),
+ adapter: (0, _dashDashAdapter2['default'])(context).getInstance()
+ }));
+ }
+
+ function getRules(type) {
+ switch (type) {
+ case TIME_SYNCHRONIZED_RULES:
+ return withAccurateTimeSourceRules;
+ case BEST_GUESS_RULES:
+ return bestGuestRules;
+ default:
+ return null;
+ }
+ }
+
+ instance = {
+ initialize: initialize,
+ getRules: getRules
+ };
+
+ return instance;
+}
+
+SynchronizationRulesCollection.__dashjs_factory_name = 'SynchronizationRulesCollection';
+var factory = _coreFactoryMaker2['default'].getSingletonFactory(SynchronizationRulesCollection);
+factory.TIME_SYNCHRONIZED_RULES = TIME_SYNCHRONIZED_RULES;
+factory.BEST_GUESS_RULES = BEST_GUESS_RULES;
+exports['default'] = factory;
+module.exports = exports['default'];
+
+},{"10":10,"142":142,"143":143,"15":15,"37":37}],145:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreEventBus = _dereq_(9);
+
+var _coreEventBus2 = _interopRequireDefault(_coreEventBus);
+
+var _coreEventsEvents = _dereq_(13);
+
+var _coreEventsEvents2 = _interopRequireDefault(_coreEventsEvents);
+
+var _dashModelsDashManifestModel = _dereq_(22);
+
+var _dashModelsDashManifestModel2 = _interopRequireDefault(_dashModelsDashManifestModel);
+
+var _controllersBlacklistController = _dereq_(62);
+
+var _controllersBlacklistController2 = _interopRequireDefault(_controllersBlacklistController);
+
+var _rulesBaseUrlResolutionDVBSelector = _dereq_(139);
+
+var _rulesBaseUrlResolutionDVBSelector2 = _interopRequireDefault(_rulesBaseUrlResolutionDVBSelector);
+
+var _rulesBaseUrlResolutionBasicSelector = _dereq_(138);
+
+var _rulesBaseUrlResolutionBasicSelector2 = _interopRequireDefault(_rulesBaseUrlResolutionBasicSelector);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var URL_RESOLUTION_FAILED_GENERIC_ERROR_CODE = 1;
+var URL_RESOLUTION_FAILED_GENERIC_ERROR_MESSAGE = 'Failed to resolve a valid URL';
+
+function BaseURLSelector() {
+
+ var context = this.context;
+ var eventBus = (0, _coreEventBus2['default'])(context).getInstance();
+ var dashManifestModel = (0, _dashModelsDashManifestModel2['default'])(context).getInstance();
+
+ var instance = undefined,
+ serviceLocationBlacklistController = undefined,
+ basicSelector = undefined,
+ dvbSelector = undefined,
+ selector = undefined;
+
+ function setup() {
+ serviceLocationBlacklistController = (0, _controllersBlacklistController2['default'])(context).create({
+ updateEventName: _coreEventsEvents2['default'].SERVICE_LOCATION_BLACKLIST_CHANGED,
+ loadFailedEventName: _coreEventsEvents2['default'].FRAGMENT_LOADING_COMPLETED
+ });
+
+ basicSelector = (0, _rulesBaseUrlResolutionBasicSelector2['default'])(context).create({
+ blacklistController: serviceLocationBlacklistController
+ });
+
+ dvbSelector = (0, _rulesBaseUrlResolutionDVBSelector2['default'])(context).create({
+ blacklistController: serviceLocationBlacklistController
+ });
+
+ selector = basicSelector;
+ }
+
+ function chooseSelectorFromManifest(manifest) {
+ if (dashManifestModel.getIsDVB(manifest)) {
+ selector = dvbSelector;
+ } else {
+ selector = basicSelector;
+ }
+ }
+
+ function select(data) {
+ var baseUrls = data.baseUrls;
+ var selectedIdx = data.selectedIdx;
+
+ // Once a random selection has been carried out amongst a group of BaseURLs with the same
+ // @priority attribute value, then that choice should be re-used if the selection needs to be made again
+ // unless the blacklist has been modified or the available BaseURLs have changed.
+ if (!isNaN(selectedIdx)) {
+ return baseUrls[selectedIdx];
+ }
+
+ var selectedBaseUrl = selector.select(baseUrls);
+
+ if (!selectedBaseUrl) {
+ eventBus.trigger(_coreEventsEvents2['default'].URL_RESOLUTION_FAILED, {
+ error: new Error(URL_RESOLUTION_FAILED_GENERIC_ERROR_CODE, URL_RESOLUTION_FAILED_GENERIC_ERROR_MESSAGE)
+ });
+
+ return;
+ }
+
+ data.selectedIdx = baseUrls.indexOf(selectedBaseUrl);
+
+ return selectedBaseUrl;
+ }
+
+ function reset() {
+ serviceLocationBlacklistController.reset();
+ }
+
+ instance = {
+ chooseSelectorFromManifest: chooseSelectorFromManifest,
+ select: select,
+ reset: reset
+ };
+
+ setup();
+
+ return instance;
+}
+
+BaseURLSelector.__dashjs_factory_name = 'BaseURLSelector';
+var factory = _coreFactoryMaker2['default'].getClassFactory(BaseURLSelector);
+factory.URL_RESOLUTION_FAILED_GENERIC_ERROR_CODE = URL_RESOLUTION_FAILED_GENERIC_ERROR_CODE;
+factory.URL_RESOLUTION_FAILED_GENERIC_ERROR_MESSAGE = URL_RESOLUTION_FAILED_GENERIC_ERROR_MESSAGE;
+exports['default'] = factory;
+module.exports = exports['default'];
+
+},{"10":10,"13":13,"138":138,"139":139,"22":22,"62":62,"9":9}],146:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _IsoFile = _dereq_(153);
+
+var _IsoFile2 = _interopRequireDefault(_IsoFile);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _codemIsoboxer = _dereq_(6);
+
+var _codemIsoboxer2 = _interopRequireDefault(_codemIsoboxer);
+
+function BoxParser() /*config*/{
+
+ var instance = undefined;
+ var context = this.context;
+
+ /**
+ * @param {ArrayBuffer} data
+ * @returns {IsoFile|null}
+ * @memberof BoxParser#
+ */
+ function parse(data) {
+ if (!data) return null;
+
+ if (data.fileStart === undefined) {
+ data.fileStart = 0;
+ }
+
+ var parsedFile = _codemIsoboxer2['default'].parseBuffer(data);
+ var dashIsoFile = (0, _IsoFile2['default'])(context).create();
+
+ dashIsoFile.setData(parsedFile);
+
+ return dashIsoFile;
+ }
+
+ instance = {
+ parse: parse
+ };
+
+ return instance;
+}
+BoxParser.__dashjs_factory_name = 'BoxParser';
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(BoxParser);
+module.exports = exports['default'];
+
+},{"10":10,"153":153,"6":6}],147:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+function Capabilities() {
+
+ var instance = undefined,
+ encryptedMediaSupported = undefined;
+
+ function setup() {
+ encryptedMediaSupported = false;
+ }
+
+ function supportsMediaSource() {
+ var hasWebKit = ('WebKitMediaSource' in window);
+ var hasMediaSource = ('MediaSource' in window);
+
+ return hasWebKit || hasMediaSource;
+ }
+
+ /**
+ * Returns whether Encrypted Media Extensions are supported on this
+ * user agent
+ *
+ * @return {boolean} true if EME is supported, false otherwise
+ */
+ function supportsEncryptedMedia() {
+ return encryptedMediaSupported;
+ }
+
+ function setEncryptedMediaSupported(value) {
+ encryptedMediaSupported = value;
+ }
+
+ function supportsCodec(element, codec) {
+ var canPlay = element.canPlayType(codec);
+ return canPlay === 'probably' || canPlay === 'maybe';
+ }
+
+ instance = {
+ supportsMediaSource: supportsMediaSource,
+ supportsEncryptedMedia: supportsEncryptedMedia,
+ supportsCodec: supportsCodec,
+ setEncryptedMediaSupported: setEncryptedMediaSupported
+ };
+
+ setup();
+
+ return instance;
+}
+Capabilities.__dashjs_factory_name = 'Capabilities';
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(Capabilities);
+module.exports = exports['default'];
+
+},{"10":10}],148:[function(_dereq_,module,exports){
+/**
+* The copyright in this software is being made available under the BSD License,
+* included below. This software may be subject to other third party and contributor
+* rights, including patent rights, and no such rights are granted under this license.
+*
+* Copyright (c) 2013, Dash Industry Forum.
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without modification,
+* are permitted provided that the following conditions are met:
+* * Redistributions of source code must retain the above copyright notice, this
+* list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright notice,
+* this list of conditions and the following disclaimer in the documentation and/or
+* other materials provided with the distribution.
+* * Neither the name of Dash Industry Forum nor the names of its
+* contributors may be used to endorse or promote products derived from this software
+* without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+* POSSIBILITY OF SUCH DAMAGE.
+*/
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+function CustomTimeRanges() /*config*/{
+ var customTimeRangeArray = [];
+ var length = 0;
+
+ function add(start, end) {
+ var i = 0;
+
+ for (i = 0; i < this.customTimeRangeArray.length && start > this.customTimeRangeArray[i].start; i++);
+
+ this.customTimeRangeArray.splice(i, 0, { start: start, end: end });
+
+ for (i = 0; i < this.customTimeRangeArray.length - 1; i++) {
+ if (this.mergeRanges(i, i + 1)) {
+ i--;
+ }
+ }
+ this.length = this.customTimeRangeArray.length;
+ }
+
+ function clear() {
+ this.customTimeRangeArray = [];
+ this.length = 0;
+ }
+
+ function remove(start, end) {
+ for (var i = 0; i < this.customTimeRangeArray.length; i++) {
+ if (start <= this.customTimeRangeArray[i].start && end >= this.customTimeRangeArray[i].end) {
+ // |--------------Range i-------|
+ //|---------------Range to remove ---------------|
+ // or
+ //|--------------Range i-------|
+ //|--------------Range to remove ---------------|
+ // or
+ // |--------------Range i-------|
+ //|--------------Range to remove ---------------|
+ this.customTimeRangeArray.splice(i, 1);
+ i--;
+ } else if (start > this.customTimeRangeArray[i].start && end < this.customTimeRangeArray[i].end) {
+ //|-----------------Range i----------------|
+ // |-------Range to remove -----|
+ this.customTimeRangeArray.splice(i + 1, 0, { start: end, end: this.customTimeRangeArray[i].end });
+ this.customTimeRangeArray[i].end = start;
+ break;
+ } else if (start > this.customTimeRangeArray[i].start && start < this.customTimeRangeArray[i].end) {
+ //|-----------Range i----------|
+ // |---------Range to remove --------|
+ // or
+ //|-----------------Range i----------------|
+ // |-------Range to remove -----|
+ this.customTimeRangeArray[i].end = start;
+ } else if (end > this.customTimeRangeArray[i].start && end < this.customTimeRangeArray[i].end) {
+ // |-----------Range i----------|
+ //|---------Range to remove --------|
+ // or
+ //|-----------------Range i----------------|
+ //|-------Range to remove -----|
+ this.customTimeRangeArray[i].start = end;
+ }
+ }
+
+ this.length = this.customTimeRangeArray.length;
+ }
+
+ function mergeRanges(rangeIndex1, rangeIndex2) {
+ var range1 = this.customTimeRangeArray[rangeIndex1];
+ var range2 = this.customTimeRangeArray[rangeIndex2];
+
+ if (range1.start <= range2.start && range2.start <= range1.end && range1.end <= range2.end) {
+ //|-----------Range1----------|
+ // |-----------Range2----------|
+ range1.end = range2.end;
+ this.customTimeRangeArray.splice(rangeIndex2, 1);
+ return true;
+ } else if (range2.start <= range1.start && range1.start <= range2.end && range2.end <= range1.end) {
+ // |-----------Range1----------|
+ //|-----------Range2----------|
+ range1.start = range2.start;
+ this.customTimeRangeArray.splice(rangeIndex2, 1);
+ return true;
+ } else if (range2.start <= range1.start && range1.start <= range2.end && range1.end <= range2.end) {
+ // |--------Range1-------|
+ //|---------------Range2--------------|
+ this.customTimeRangeArray.splice(rangeIndex1, 1);
+ return true;
+ } else if (range1.start <= range2.start && range2.start <= range1.end && range2.end <= range1.end) {
+ //|-----------------Range1--------------|
+ // |-----------Range2----------|
+ this.customTimeRangeArray.splice(rangeIndex2, 1);
+ return true;
+ }
+ return false;
+ }
+
+ function start(index) {
+ return this.customTimeRangeArray[index].start;
+ }
+
+ function end(index) {
+ return this.customTimeRangeArray[index].end;
+ }
+
+ return {
+ customTimeRangeArray: customTimeRangeArray,
+ length: length,
+ add: add,
+ clear: clear,
+ remove: remove,
+ mergeRanges: mergeRanges,
+ start: start,
+ end: end
+ };
+}
+CustomTimeRanges.__dashjs_factory_name = 'CustomTimeRanges';
+exports['default'] = _coreFactoryMaker2['default'].getClassFactory(CustomTimeRanges);
+module.exports = exports['default'];
+
+},{"10":10}],149:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _modelsMediaPlayerModel = _dereq_(101);
+
+var _modelsMediaPlayerModel2 = _interopRequireDefault(_modelsMediaPlayerModel);
+
+var _coreDebug = _dereq_(8);
+
+var _coreDebug2 = _interopRequireDefault(_coreDebug);
+
+var legacyKeysAndReplacements = [{ oldKey: 'dashjs_vbitrate', newKey: 'dashjs_video_bitrate' }, { oldKey: 'dashjs_abitrate', newKey: 'dashjs_audio_bitrate' }, { oldKey: 'dashjs_vsettings', newKey: 'dashjs_video_settings' }, { oldKey: 'dashjs_asettings', newKey: 'dashjs_audio_settings' }];
+
+var LOCAL_STORAGE_BITRATE_KEY_TEMPLATE = 'dashjs_?_bitrate';
+var LOCAL_STORAGE_SETTINGS_KEY_TEMPLATE = 'dashjs_?_settings';
+
+var STORAGE_TYPE_LOCAL = 'localStorage';
+var STORAGE_TYPE_SESSION = 'sessionStorage';
+
+function DOMStorage() {
+
+ var context = this.context;
+ var log = (0, _coreDebug2['default'])(context).getInstance().log;
+
+ var instance = undefined,
+ supported = undefined,
+ mediaPlayerModel = undefined;
+
+ //type can be local, session
+ function isSupported(type) {
+ if (supported !== undefined) return supported;
+
+ supported = false;
+
+ var testKey = '1';
+ var testValue = '1';
+ var storage;
+
+ try {
+ if (typeof window !== 'undefined') {
+ storage = window[type];
+ }
+ } catch (error) {
+ log('Warning: DOMStorage access denied: ' + error.message);
+ return supported;
+ }
+
+ if (!storage || type !== STORAGE_TYPE_LOCAL && type !== STORAGE_TYPE_SESSION) {
+ return supported;
+ }
+
+ /* When Safari (OS X or iOS) is in private browsing mode, it appears as though localStorage is available, but trying to call setItem throws an exception.
+ http://stackoverflow.com/questions/14555347/html5-localstorage-error-with-safari-quota-exceeded-err-dom-exception-22-an
+ Check if the storage can be used
+ */
+ try {
+ storage.setItem(testKey, testValue);
+ storage.removeItem(testKey);
+ supported = true;
+ } catch (error) {
+ log('Warning: DOMStorage is supported, but cannot be used: ' + error.message);
+ }
+
+ return supported;
+ }
+
+ function translateLegacyKeys() {
+ if (isSupported(STORAGE_TYPE_LOCAL)) {
+ legacyKeysAndReplacements.forEach(function (entry) {
+ var value = localStorage.getItem(entry.oldKey);
+
+ if (value) {
+ localStorage.removeItem(entry.oldKey);
+
+ try {
+ localStorage.setItem(entry.newKey, value);
+ } catch (e) {
+ log(e.message);
+ }
+ }
+ });
+ }
+ }
+
+ function setup() {
+ mediaPlayerModel = (0, _modelsMediaPlayerModel2['default'])(context).getInstance();
+
+ translateLegacyKeys();
+ }
+
+ // Return current epoch time, ms, rounded to the nearest 10m to avoid fingerprinting user
+ function getTimestamp() {
+ var ten_minutes_ms = 60 * 1000 * 10;
+ return Math.round(new Date().getTime() / ten_minutes_ms) * ten_minutes_ms;
+ }
+
+ function canStore(storageType, key) {
+ return isSupported(storageType) && mediaPlayerModel['get' + key + 'CachingInfo']().enabled;
+ }
+
+ function getSavedMediaSettings(type) {
+ //Checks local storage to see if there is valid, non-expired media settings
+ if (!canStore(STORAGE_TYPE_LOCAL, 'LastMediaSettings')) return null;
+
+ var key = LOCAL_STORAGE_SETTINGS_KEY_TEMPLATE.replace(/\?/, type);
+ var obj = JSON.parse(localStorage.getItem(key)) || {};
+ var isExpired = new Date().getTime() - parseInt(obj.timestamp, 10) >= mediaPlayerModel.getLastMediaSettingsCachingInfo().ttl || false;
+ var settings = obj.settings;
+
+ if (isExpired) {
+ localStorage.removeItem(key);
+ settings = null;
+ }
+
+ return settings;
+ }
+
+ function getSavedBitrateSettings(type) {
+ var savedBitrate = NaN;
+ //Checks local storage to see if there is valid, non-expired bit rate
+ //hinting from the last play session to use as a starting bit rate.
+ if (canStore(STORAGE_TYPE_LOCAL, 'LastBitrate')) {
+ var key = LOCAL_STORAGE_BITRATE_KEY_TEMPLATE.replace(/\?/, type);
+ var obj = JSON.parse(localStorage.getItem(key)) || {};
+ var isExpired = new Date().getTime() - parseInt(obj.timestamp, 10) >= mediaPlayerModel.getLastBitrateCachingInfo().ttl || false;
+ var bitrate = parseInt(obj.bitrate, 10);
+
+ if (!isNaN(bitrate) && !isExpired) {
+ savedBitrate = bitrate;
+ log('Last saved bitrate for ' + type + ' was ' + bitrate);
+ } else if (isExpired) {
+ localStorage.removeItem(key);
+ }
+ }
+ return savedBitrate;
+ }
+
+ function setSavedMediaSettings(type, value) {
+ if (canStore(STORAGE_TYPE_LOCAL, 'LastMediaSettings')) {
+ var key = LOCAL_STORAGE_SETTINGS_KEY_TEMPLATE.replace(/\?/, type);
+ try {
+ localStorage.setItem(key, JSON.stringify({ settings: value, timestamp: getTimestamp() }));
+ } catch (e) {
+ log(e.message);
+ }
+ }
+ }
+
+ function setSavedBitrateSettings(type, bitrate) {
+ if (canStore(STORAGE_TYPE_LOCAL, 'LastBitrate') && bitrate) {
+ var key = LOCAL_STORAGE_BITRATE_KEY_TEMPLATE.replace(/\?/, type);
+ try {
+ localStorage.setItem(key, JSON.stringify({ bitrate: bitrate / 1000, timestamp: getTimestamp() }));
+ } catch (e) {
+ log(e.message);
+ }
+ }
+ }
+
+ instance = {
+ getSavedBitrateSettings: getSavedBitrateSettings,
+ setSavedBitrateSettings: setSavedBitrateSettings,
+ getSavedMediaSettings: getSavedMediaSettings,
+ setSavedMediaSettings: setSavedMediaSettings,
+ isSupported: isSupported
+ };
+
+ setup();
+ return instance;
+}
+
+DOMStorage.__dashjs_factory_name = 'DOMStorage';
+var factory = _coreFactoryMaker2['default'].getSingletonFactory(DOMStorage);
+exports['default'] = factory;
+module.exports = exports['default'];
+
+},{"10":10,"101":101,"8":8}],150:[function(_dereq_,module,exports){
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _voError = _dereq_(162);
+
+var _voError2 = _interopRequireDefault(_voError);
+
+/**
+ * Creates an instance of an EBMLParser class which implements a large subset
+ * of the functionality required to parse Matroska EBML
+ *
+ * @param {Object} config object with data member which is the buffer to parse
+ */
+function EBMLParser(config) {
+
+ var instance = undefined;
+
+ var data = new DataView(config.data);
+ var pos = 0;
+
+ function getPos() {
+ return pos;
+ }
+
+ function setPos(value) {
+ pos = value;
+ }
+
+ /**
+ * Consumes an EBML tag from the data stream.
+ *
+ * @param {Object} tag to parse, A tag is an object with at least a {number} tag and
+ * {boolean} required flag.
+ * @param {boolean} test whether or not the function should throw if a required
+ * tag is not found
+ * @return {boolean} whether or not the tag was found
+ * @throws will throw an exception if a required tag is not found and test
+ * param is false or undefined, or if the stream is malformed.
+ * @memberof EBMLParser
+ */
+ function consumeTag(tag, test) {
+ var found = true;
+ var bytesConsumed = 0;
+ var p1 = undefined;
+ var p2 = undefined;
+
+ if (test === undefined) {
+ test = false;
+ }
+
+ if (tag.tag > 0xFFFFFF) {
+ if (data.getUint32(pos) !== tag.tag) {
+ found = false;
+ }
+ bytesConsumed = 4;
+ } else if (tag.tag > 0xFFFF) {
+ // 3 bytes
+ p1 = data.getUint16(pos);
+ p2 = data.getUint8(pos + 2);
+
+ // shift p1 over a byte and add p2
+ if (p1 * 256 + p2 !== tag.tag) {
+ found = false;
+ }
+ bytesConsumed = 3;
+ } else if (tag.tag > 0xFF) {
+ if (data.getUint16(pos) !== tag.tag) {
+ found = false;
+ }
+ bytesConsumed = 2;
+ } else {
+ if (data.getUint8(pos) !== tag.tag) {
+ found = false;
+ }
+ bytesConsumed = 1;
+ }
+
+ if (!found && tag.required && !test) {
+ throw new _voError2['default']('required tag not found');
+ }
+
+ if (found) {
+ pos += bytesConsumed;
+ }
+
+ return found;
+ }
+
+ /**
+ * Consumes an EBML tag from the data stream. If the tag is found then this
+ * function will also remove the size field which follows the tag from the
+ * data stream.
+ *
+ * @param {Object} tag to parse, A tag is an object with at least a {number} tag and
+ * {boolean} required flag.
+ * @param {boolean} test whether or not the function should throw if a required
+ * tag is not found
+ * @return {boolean} whether or not the tag was found
+ * @throws will throw an exception if a required tag is not found and test
+ * param is false or undefined, or if the stream is malformedata.
+ * @memberof EBMLParser
+ */
+ function consumeTagAndSize(tag, test) {
+ var found = consumeTag(tag, test);
+
+ if (found) {
+ getMatroskaCodedNum();
+ }
+
+ return found;
+ }
+
+ /**
+ * Consumes an EBML tag from the data stream. If the tag is found then this
+ * function will also remove the size field which follows the tag from the
+ * data stream. It will use the value of the size field to parse a binary
+ * field, using a parser defined in the tag itself
+ *
+ * @param {Object} tag to parse, A tag is an object with at least a {number} tag,
+ * {boolean} required flag, and a parse function which takes a size parameter
+ * @return {boolean} whether or not the tag was found
+ * @throws will throw an exception if a required tag is not found,
+ * or if the stream is malformed
+ * @memberof EBMLParser
+ */
+ function parseTag(tag) {
+ var size = undefined;
+
+ consumeTag(tag);
+ size = getMatroskaCodedNum();
+ return instance[tag.parse](size);
+ }
+
+ /**
+ * Consumes an EBML tag from the data stream. If the tag is found then this
+ * function will also remove the size field which follows the tag from the
+ * data stream. It will use the value of the size field to skip over the
+ * entire section of EBML encapsulated by the tag.
+ *
+ * @param {Object} tag to parse, A tag is an object with at least a {number} tag, and
+ * {boolean} required flag
+ * @param {boolean} test a flag to indicate if an exception should be thrown
+ * if a required tag is not found
+ * @return {boolean} whether or not the tag was found
+ * @throws will throw an exception if a required tag is not found and test is
+ * false or undefined or if the stream is malformed
+ * @memberof EBMLParser
+ */
+ function skipOverElement(tag, test) {
+ var found = consumeTag(tag, test);
+ var headerSize = undefined;
+
+ if (found) {
+ headerSize = getMatroskaCodedNum();
+ pos += headerSize;
+ }
+
+ return found;
+ }
+
+ /**
+ * Returns and consumes a number encoded according to the Matroska EBML
+ * specification from the bitstream.
+ *
+ * @param {boolean} retainMSB whether or not to retain the Most Significant Bit (the
+ * first 1). this is usually true when reading Tag IDs.
+ * @return {number} the decoded number
+ * @throws will throw an exception if the bit stream is malformed or there is
+ * not enough data
+ * @memberof EBMLParser
+ */
+ function getMatroskaCodedNum(retainMSB) {
+ var bytesUsed = 1;
+ var mask = 0x80;
+ var maxBytes = 8;
+ var extraBytes = -1;
+ var num = 0;
+ var ch = data.getUint8(pos);
+ var i = undefined;
+
+ for (i = 0; i < maxBytes; i += 1) {
+ if ((ch & mask) === mask) {
+ num = retainMSB === undefined ? ch & ~mask : ch;
+ extraBytes = i;
+ break;
+ }
+ mask >>= 1;
+ }
+
+ for (i = 0; i < extraBytes; i += 1, bytesUsed += 1) {
+ num = num << 8 | 0xff & data.getUint8(pos + bytesUsed);
+ }
+
+ pos += bytesUsed;
+
+ return num;
+ }
+
+ /**
+ * Returns and consumes a float from the bitstream.
+ *
+ * @param {number} size 4 or 8 byte floats are supported
+ * @return {number} the decoded number
+ * @throws will throw an exception if the bit stream is malformed or there is
+ * not enough data
+ * @memberof EBMLParser
+ */
+ function getMatroskaFloat(size) {
+ var outFloat = undefined;
+
+ switch (size) {
+ case 4:
+ outFloat = data.getFloat32(pos);
+ pos += 4;
+ break;
+ case 8:
+ outFloat = data.getFloat64(pos);
+ pos += 8;
+ break;
+ }
+ return outFloat;
+ }
+
+ /**
+ * Consumes and returns an unsigned int from the bitstream.
+ *
+ * @param {number} size 1 to 8 bytes
+ * @return {number} the decoded number
+ * @throws will throw an exception if the bit stream is malformed or there is
+ * not enough data
+ * @memberof EBMLParser
+ */
+ function getMatroskaUint(size) {
+ var val = 0;
+ var i = undefined;
+
+ for (i = 0; i < size; i += 1) {
+ val <<= 8;
+ val |= data.getUint8(pos + i) & 0xff;
+ }
+
+ pos += size;
+ return val;
+ }
+
+ /**
+ * Tests whether there is more data in the bitstream for parsing
+ *
+ * @return {boolean} whether there is more data to parse
+ * @memberof EBMLParser
+ */
+ function moreData() {
+ return pos < data.byteLength;
+ }
+
+ instance = {
+ getPos: getPos,
+ setPos: setPos,
+ consumeTag: consumeTag,
+ consumeTagAndSize: consumeTagAndSize,
+ parseTag: parseTag,
+ skipOverElement: skipOverElement,
+ getMatroskaCodedNum: getMatroskaCodedNum,
+ getMatroskaFloat: getMatroskaFloat,
+ getMatroskaUint: getMatroskaUint,
+ moreData: moreData
+ };
+
+ return instance;
+}
+
+EBMLParser.__dashjs_factory_name = 'EBMLParser';
+exports['default'] = _coreFactoryMaker2['default'].getClassFactory(EBMLParser);
+module.exports = exports['default'];
+
+},{"10":10,"162":162}],151:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreEventBus = _dereq_(9);
+
+var _coreEventBus2 = _interopRequireDefault(_coreEventBus);
+
+var _coreEventsEvents = _dereq_(13);
+
+var _coreEventsEvents2 = _interopRequireDefault(_coreEventsEvents);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var CAPABILITY_ERROR_MEDIASOURCE = 'mediasource';
+var CAPABILITY_ERROR_MEDIAKEYS = 'mediakeys';
+
+var DOWNLOAD_ERROR_ID_MANIFEST = 'manifest';
+var DOWNLOAD_ERROR_ID_SIDX = 'SIDX';
+var DOWNLOAD_ERROR_ID_CONTENT = 'content';
+var DOWNLOAD_ERROR_ID_INITIALIZATION = 'initialization';
+var DOWNLOAD_ERROR_ID_XLINK = 'xlink';
+
+var MANIFEST_ERROR_ID_CODEC = 'codec';
+var MANIFEST_ERROR_ID_PARSE = 'parse';
+var MANIFEST_ERROR_ID_NOSTREAMS = 'nostreams';
+
+var TIMED_TEXT_ERROR_ID_PARSE = 'parse';
+
+function ErrorHandler() {
+
+ var instance = undefined;
+ var context = this.context;
+ var eventBus = (0, _coreEventBus2['default'])(context).getInstance();
+
+ // "mediasource"|"mediakeys"
+ function capabilityError(err) {
+ eventBus.trigger(_coreEventsEvents2['default'].ERROR, { error: 'capability', event: err });
+ }
+
+ // {id: "manifest"|"SIDX"|"content"|"initialization"|"xlink", url: "", request: {XMLHttpRequest instance}}
+ function downloadError(id, url, request) {
+ eventBus.trigger(_coreEventsEvents2['default'].ERROR, { error: 'download', event: { id: id, url: url, request: request } });
+ }
+
+ // {message: "", id: "codec"|"parse"|"nostreams", manifest: {parsed manifest}}
+ function manifestError(message, id, manifest, err) {
+ eventBus.trigger(_coreEventsEvents2['default'].ERROR, { error: 'manifestError', event: { message: message, id: id, manifest: manifest, event: err } });
+ }
+
+ // {message: '', id: 'parse', cc: ''}
+ function timedTextError(message, id, ccContent) {
+ eventBus.trigger(_coreEventsEvents2['default'].ERROR, { error: 'cc', event: { message: message, id: id, cc: ccContent } });
+ }
+
+ function mediaSourceError(err) {
+ eventBus.trigger(_coreEventsEvents2['default'].ERROR, { error: 'mediasource', event: err });
+ }
+
+ function mediaKeySessionError(err) {
+ eventBus.trigger(_coreEventsEvents2['default'].ERROR, { error: 'key_session', event: err });
+ }
+
+ function mediaKeyMessageError(err) {
+ eventBus.trigger(_coreEventsEvents2['default'].ERROR, { error: 'key_message', event: err });
+ }
+
+ instance = {
+ capabilityError: capabilityError,
+ downloadError: downloadError,
+ manifestError: manifestError,
+ timedTextError: timedTextError,
+ mediaSourceError: mediaSourceError,
+ mediaKeySessionError: mediaKeySessionError,
+ mediaKeyMessageError: mediaKeyMessageError
+ };
+
+ return instance;
+}
+
+ErrorHandler.__dashjs_factory_name = 'ErrorHandler';
+
+var factory = _coreFactoryMaker2['default'].getSingletonFactory(ErrorHandler);
+
+factory.CAPABILITY_ERROR_MEDIASOURCE = CAPABILITY_ERROR_MEDIASOURCE;
+factory.CAPABILITY_ERROR_MEDIAKEYS = CAPABILITY_ERROR_MEDIAKEYS;
+factory.DOWNLOAD_ERROR_ID_MANIFEST = DOWNLOAD_ERROR_ID_MANIFEST;
+factory.DOWNLOAD_ERROR_ID_SIDX = DOWNLOAD_ERROR_ID_SIDX;
+factory.DOWNLOAD_ERROR_ID_CONTENT = DOWNLOAD_ERROR_ID_CONTENT;
+factory.DOWNLOAD_ERROR_ID_INITIALIZATION = DOWNLOAD_ERROR_ID_INITIALIZATION;
+factory.DOWNLOAD_ERROR_ID_XLINK = DOWNLOAD_ERROR_ID_XLINK;
+factory.MANIFEST_ERROR_ID_CODEC = MANIFEST_ERROR_ID_CODEC;
+factory.MANIFEST_ERROR_ID_PARSE = MANIFEST_ERROR_ID_PARSE;
+factory.MANIFEST_ERROR_ID_NOSTREAMS = MANIFEST_ERROR_ID_NOSTREAMS;
+factory.TIMED_TEXT_ERROR_ID_PARSE = TIMED_TEXT_ERROR_ID_PARSE;
+
+exports['default'] = factory;
+module.exports = exports['default'];
+
+},{"10":10,"13":13,"9":9}],152:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * Represents data structure to keep and drive {DataChunk}
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+function InitCache() {
+
+ var data = {};
+
+ function save(chunk) {
+ var id = chunk.streamId;
+ var type = chunk.mediaInfo.type;
+ var quality = chunk.quality;
+
+ data[id] = data[id] || {};
+ data[id][type] = data[id][type] || {};
+ data[id][type][quality] = chunk;
+ }
+
+ function extract(streamId, mediaType, quality) {
+ return data[streamId][mediaType][quality];
+ }
+
+ function reset() {
+ data = {};
+ }
+
+ var instance = {
+ save: save,
+ extract: extract,
+ reset: reset
+ };
+
+ return instance;
+}
+
+InitCache.__dashjs_factory_name = 'InitCache';
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(InitCache);
+module.exports = exports['default'];
+
+},{"10":10}],153:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _voIsoBox = _dereq_(165);
+
+var _voIsoBox2 = _interopRequireDefault(_voIsoBox);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+function IsoFile() {
+
+ var instance = undefined,
+ parsedIsoFile = undefined,
+ commonProps = undefined,
+ sidxProps = undefined,
+ sidxRefProps = undefined,
+ emsgProps = undefined,
+ mdhdProps = undefined,
+ mfhdProps = undefined,
+ tfhdProps = undefined,
+ tfdtProps = undefined,
+ trunProps = undefined,
+ trunSampleProps = undefined;
+
+ /**
+ * @param {string} type
+ * @returns {IsoBox|null}
+ * @memberof IsoFile#
+ */
+ function getBox(type) {
+ if (!type || !parsedIsoFile || !parsedIsoFile.boxes || parsedIsoFile.boxes.length === 0) return null;
+
+ return convertToDashIsoBox(parsedIsoFile.fetch(type));
+ }
+
+ /**
+ * @param {string} type
+ * @returns {Array} array of {@link IsoBox}
+ * @memberof IsoFile#
+ */
+ function getBoxes(type) {
+ var boxData = parsedIsoFile.fetchAll(type);
+ var boxes = [];
+ var box;
+
+ for (var i = 0, ln = boxData.length; i < ln; i++) {
+ box = convertToDashIsoBox(boxData[i]);
+
+ if (box) {
+ boxes.push(box);
+ }
+ }
+
+ return boxes;
+ }
+
+ /**
+ * @param {string} value
+ * @memberof IsoFile#
+ */
+ function setData(value) {
+ parsedIsoFile = value;
+ }
+
+ /**
+ * @returns {IsoBox|null}
+ * @memberof IsoFile#
+ */
+ function getLastBox() {
+ if (!parsedIsoFile || !parsedIsoFile.boxes || !parsedIsoFile.boxes.length) return null;
+
+ var type = parsedIsoFile.boxes[parsedIsoFile.boxes.length - 1].type;
+ var boxes = getBoxes(type);
+
+ return boxes[boxes.length - 1];
+ }
+
+ /**
+ * @returns {number}
+ * @memberof IsoFile#
+ */
+ function getOffset() {
+ return parsedIsoFile._cursor.offset;
+ }
+
+ function setup() {
+ commonProps = {
+ offset: '_offset',
+ size: 'size',
+ type: 'type'
+ };
+
+ sidxProps = {
+ references: 'references',
+ timescale: 'timescale',
+ earliest_presentation_time: 'earliest_presentation_time',
+ first_offset: 'first_offset'
+ };
+
+ sidxRefProps = {
+ reference_type: 'reference_type',
+ referenced_size: 'referenced_size',
+ subsegment_duration: 'subsegment_duration'
+ };
+
+ emsgProps = {
+ id: 'id',
+ value: 'value',
+ timescale: 'timescale',
+ scheme_id_uri: 'scheme_id_uri',
+ presentation_time_delta: 'presentation_time_delta',
+ event_duration: 'event_duration',
+ message_data: 'message_data'
+ };
+
+ mdhdProps = {
+ timescale: 'timescale'
+ };
+
+ mfhdProps = {
+ sequence_number: 'sequence_number'
+ };
+
+ tfhdProps = {
+ base_data_offset: 'base_data_offset',
+ sample_description_index: 'sample_description_index',
+ default_sample_duration: 'default_sample_duration',
+ default_sample_size: 'default_sample_size',
+ default_sample_flags: 'default_sample_flags',
+ flags: 'flags'
+ };
+
+ tfdtProps = {
+ version: 'version',
+ baseMediaDecodeTime: 'baseMediaDecodeTime',
+ flags: 'flags'
+ };
+
+ trunProps = {
+ sample_count: 'sample_count',
+ first_sample_flags: 'first_sample_flags',
+ data_offset: 'data_offset',
+ flags: 'flags',
+ samples: 'samples'
+ };
+
+ trunSampleProps = {
+ sample_size: 'sample_size',
+ sample_duration: 'sample_duration',
+ sample_composition_time_offset: 'sample_composition_time_offset'
+ };
+ }
+
+ function copyProps(from, to, props) {
+ for (var prop in props) {
+ to[prop] = from[props[prop]];
+ }
+ }
+
+ function convertToDashIsoBox(boxData) {
+ if (!boxData) return null;
+
+ var box = new _voIsoBox2['default']();
+ var i, ln;
+
+ copyProps(boxData, box, commonProps);
+
+ if (boxData.hasOwnProperty('_incomplete')) {
+ box.isComplete = !boxData._incomplete;
+ }
+
+ switch (box.type) {
+ case 'sidx':
+ copyProps(boxData, box, sidxProps);
+ if (box.references) {
+ for (i = 0, ln = box.references.length; i < ln; i++) {
+ copyProps(boxData.references[i], box.references[i], sidxRefProps);
+ }
+ }
+ break;
+ case 'emsg':
+ copyProps(boxData, box, emsgProps);
+ break;
+ case 'mdhd':
+ copyProps(boxData, box, mdhdProps);
+ break;
+ case 'mfhd':
+ copyProps(boxData, box, mfhdProps);
+ break;
+ case 'tfhd':
+ copyProps(boxData, box, tfhdProps);
+ break;
+ case 'tfdt':
+ copyProps(boxData, box, tfdtProps);
+ break;
+ case 'trun':
+ copyProps(boxData, box, trunProps);
+ if (box.samples) {
+ for (i = 0, ln = box.samples.length; i < ln; i++) {
+ copyProps(boxData.samples[i], box.samples[i], trunSampleProps);
+ }
+ }
+ break;
+ }
+
+ return box;
+ }
+
+ instance = {
+ getBox: getBox,
+ getBoxes: getBoxes,
+ setData: setData,
+ getLastBox: getLastBox,
+ getOffset: getOffset
+ };
+
+ setup();
+
+ return instance;
+}
+IsoFile.__dashjs_factory_name = 'IsoFile';
+exports['default'] = _coreFactoryMaker2['default'].getClassFactory(IsoFile);
+module.exports = exports['default'];
+
+},{"10":10,"165":165}],154:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _rulesSynchronizationSynchronizationRulesCollection = _dereq_(144);
+
+var _rulesSynchronizationSynchronizationRulesCollection2 = _interopRequireDefault(_rulesSynchronizationSynchronizationRulesCollection);
+
+var _voError = _dereq_(162);
+
+var _voError2 = _interopRequireDefault(_voError);
+
+var _coreEventBus = _dereq_(9);
+
+var _coreEventBus2 = _interopRequireDefault(_coreEventBus);
+
+var _coreEventsEvents = _dereq_(13);
+
+var _coreEventsEvents2 = _interopRequireDefault(_coreEventsEvents);
+
+var _rulesRulesController = _dereq_(129);
+
+var _rulesRulesController2 = _interopRequireDefault(_rulesRulesController);
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var LIVE_EDGE_NOT_FOUND_ERROR_CODE = 1;
+
+function LiveEdgeFinder() {
+
+ var context = this.context;
+ var eventBus = (0, _coreEventBus2['default'])(context).getInstance();
+
+ var instance = undefined,
+ timelineConverter = undefined,
+ streamProcessor = undefined,
+ rulesController = undefined,
+ isSearchStarted = undefined,
+ searchStartTime = undefined,
+ rules = undefined,
+ liveEdge = undefined,
+ ruleSet = undefined;
+
+ function initialize(TimelineConverter, StreamProcessor) {
+ timelineConverter = TimelineConverter;
+ streamProcessor = StreamProcessor;
+ isSearchStarted = false;
+ searchStartTime = NaN;
+ liveEdge = null;
+ rulesController = (0, _rulesRulesController2['default'])(context).getInstance();
+ ruleSet = _rulesSynchronizationSynchronizationRulesCollection2['default'].BEST_GUESS_RULES;
+ eventBus.on(_coreEventsEvents2['default'].STREAM_INITIALIZED, onStreamInitialized, this);
+ }
+
+ function abortSearch() {
+ isSearchStarted = false;
+ searchStartTime = NaN;
+ }
+
+ function getLiveEdge() {
+ return liveEdge;
+ }
+
+ function reset() {
+ eventBus.off(_coreEventsEvents2['default'].STREAM_INITIALIZED, onStreamInitialized, this);
+ abortSearch();
+ liveEdge = null;
+ timelineConverter = null;
+ streamProcessor = null;
+ isSearchStarted = false;
+ searchStartTime = NaN;
+ ruleSet = null;
+ rulesController = null;
+ }
+
+ function onSearchCompleted(req) {
+ var searchTime = (new Date().getTime() - searchStartTime) / 1000;
+ liveEdge = req.value;
+ eventBus.trigger(_coreEventsEvents2['default'].LIVE_EDGE_SEARCH_COMPLETED, { liveEdge: liveEdge, searchTime: searchTime, error: liveEdge === null ? new _voError2['default'](LIVE_EDGE_NOT_FOUND_ERROR_CODE, 'live edge has not been found', null) : null });
+ }
+
+ function onStreamInitialized(e) {
+
+ if (!streamProcessor.isDynamic() || isSearchStarted || e.error) {
+ return;
+ }
+
+ ruleSet = timelineConverter.isTimeSyncCompleted() ? _rulesSynchronizationSynchronizationRulesCollection2['default'].TIME_SYNCHRONIZED_RULES : _rulesSynchronizationSynchronizationRulesCollection2['default'].BEST_GUESS_RULES;
+
+ rules = (0, _rulesSynchronizationSynchronizationRulesCollection2['default'])(context).getInstance().getRules(ruleSet);
+ isSearchStarted = true;
+ searchStartTime = new Date().getTime();
+
+ rulesController.applyRules(rules, streamProcessor, onSearchCompleted, null, function (currentValue, newValue) {
+ return newValue;
+ });
+ }
+
+ instance = {
+ initialize: initialize,
+ abortSearch: abortSearch,
+ getLiveEdge: getLiveEdge,
+ reset: reset
+ };
+
+ return instance;
+}
+LiveEdgeFinder.__dashjs_factory_name = 'LiveEdgeFinder';
+var factory = _coreFactoryMaker2['default'].getSingletonFactory(LiveEdgeFinder);
+factory.LIVE_EDGE_NOT_FOUND_ERROR_CODE = LIVE_EDGE_NOT_FOUND_ERROR_CODE;
+exports['default'] = factory;
+module.exports = exports['default'];
+
+},{"10":10,"129":129,"13":13,"144":144,"162":162,"9":9}],155:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+/**
+ * @module ObjectUtils
+ * @description Provides utility functions for objects
+ */
+function ObjectUtils() {
+
+ var instance = undefined;
+
+ /**
+ * Returns true if objects resolve to the same string. Only really useful
+ * when the user controls the object generation
+ * @return {boolean}
+ * @param {object} obj1
+ * @param {object} obj2
+ * @memberof module:ObjectUtils
+ * @instance
+ */
+ function areSimpleEquivalent(obj1, obj2) {
+ return JSON.stringify(obj1) === JSON.stringify(obj2);
+ }
+
+ instance = {
+ areSimpleEquivalent: areSimpleEquivalent
+ };
+
+ return instance;
+}
+
+ObjectUtils.__dashjs_factory_name = 'ObjectUtils';
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(ObjectUtils);
+module.exports = exports['default'];
+
+},{"10":10}],156:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+function RequestModifier() {
+
+ var instance = undefined;
+
+ function modifyRequestURL(url) {
+ return url;
+ }
+
+ function modifyRequestHeader(request) {
+ return request;
+ }
+
+ instance = {
+ modifyRequestURL: modifyRequestURL,
+ modifyRequestHeader: modifyRequestHeader
+ };
+
+ return instance;
+}
+
+RequestModifier.__dashjs_factory_name = 'RequestModifier';
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(RequestModifier);
+module.exports = exports['default'];
+
+},{"10":10}],157:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _externalsXml2json = _dereq_(4);
+
+var _externalsXml2json2 = _interopRequireDefault(_externalsXml2json);
+
+var _coreDebug = _dereq_(8);
+
+var _coreDebug2 = _interopRequireDefault(_coreDebug);
+
+var SECONDS_IN_HOUR = 60 * 60; // Expression of an hour in seconds
+var SECONDS_IN_MIN = 60; // Expression of a minute in seconds
+
+function TTMLParser() {
+
+ var context = this.context;
+ var log = (0, _coreDebug2['default'])(context).getInstance().log;
+
+ /*
+ * This TTML parser follows "EBU-TT-D SUBTITLING DISTRIBUTION FORMAT - tech3380" spec - https://tech.ebu.ch/docs/tech/tech3380.pdf.
+ * */
+ var instance = undefined,
+ timingRegex = undefined,
+ ttml = undefined,
+ // contains the whole ttml document received
+ ttmlStyling = undefined,
+ // contains the styling information from the document (from head following EBU-TT-D)
+ ttmlLayout = undefined,
+ // contains the positioning information from the document (from head following EBU-TT-D)
+ fontSize = undefined,
+ lineHeight = undefined,
+ linePadding = undefined,
+ defaultLayoutProperties = undefined,
+ defaultStyleProperties = undefined,
+ fontFamilies = undefined,
+ textAlign = undefined,
+ multiRowAlign = undefined,
+ wrapOption = undefined,
+ unicodeBidi = undefined,
+ displayAlign = undefined,
+ writingMode = undefined,
+ videoModel = undefined;
+
+ var cueCounter = 0; // Used to give every cue a unique ID.
+
+ function setConfig(config) {
+ if (!config) return;
+
+ if (config.videoModel) {
+ videoModel = config.videoModel;
+ }
+ }
+
+ /**
+ * Get the begin-end interval if present, or null otherwise.
+ *
+ * @param {Object} element - TTML element which may have begin and end attributes
+ */
+ function getInterval(element) {
+ if (element.hasOwnProperty('begin') && element.hasOwnProperty('end')) {
+ var beginTime = parseTimings(element.begin);
+ var endTime = parseTimings(element.end);
+ return [beginTime, endTime];
+ } else {
+ return null;
+ }
+ }
+
+ function getCueID() {
+ var id = 'cue_TTML_' + cueCounter;
+ cueCounter++;
+ return id;
+ }
+
+ /*
+ * Create list of intervals where spans start and end. Empty list if no times.
+ * Clip to interval using startInterval and endInterval and add these two times.
+ * Also support case when startInterval/endInteval not given (sideloaded file)
+ *
+ * @param {Array} spans - array of span elements
+ */
+ function createSpanIntervalList(spans, startInterval, endInterval) {
+
+ var spanChangeTimes = [];
+ var spanChangeTimeStrings = [];
+ var cue_intervals = [];
+
+ function addSpanTime(span, name) {
+ if (span.hasOwnProperty(name)) {
+ var timeString = span[name];
+ if (spanChangeTimeStrings.indexOf(timeString) < 0) {
+ spanChangeTimeStrings.push(timeString);
+ }
+ }
+ }
+
+ for (var i = 0; i < spans.length; i++) {
+ var span = spans[i];
+ addSpanTime(span, 'begin');
+ addSpanTime(span, 'end');
+ }
+ if (spanChangeTimeStrings.length === 0) {
+ return cue_intervals; // No span timing so no intervals.
+ }
+
+ if (typeof startInterval !== 'undefined' && typeof endInterval !== 'undefined') {
+ for (var i = 0; i < spanChangeTimeStrings.length; i++) {
+ var changeTime = parseTimings(spanChangeTimeStrings[i]);
+ if (startInterval < changeTime && changeTime < endInterval) {
+ spanChangeTimes.push(changeTime);
+ }
+ }
+ spanChangeTimes.push(startInterval);
+ spanChangeTimes.push(endInterval);
+ } else {
+ for (var i = 0; i < spanChangeTimeStrings.length; i++) {
+ spanChangeTimes.push(parseTimings(spanChangeTimeStrings[i]));
+ }
+ }
+ spanChangeTimes.sort(function (a, b) {
+ return a - b;
+ });
+ for (var i = 0; i < spanChangeTimes.length - 1; i++) {
+ cue_intervals.push([spanChangeTimes[i], spanChangeTimes[i + 1]]);
+ }
+ return cue_intervals;
+ }
+
+ function clipStartTime(startTime, intervalStart) {
+ if (typeof startInterval !== 'undefined') {
+ if (startTime < intervalStart) {
+ startTime = intervalStart;
+ }
+ }
+ return startTime;
+ }
+
+ function clipEndTime(endTime, intervalEnd) {
+ if (typeof intervalEnd !== 'undefined') {
+ if (endTime > intervalEnd) {
+ endTime = intervalEnd;
+ }
+ }
+ return endTime;
+ }
+
+ /*
+ * Get interval from entity that has begin and end properties.
+ * If intervalStart and intervalEnd defined, use them to clip the interval.
+ * Return null if no overlap with interval
+ */
+ function getClippedInterval(entity, intervalStart, intervalEnd) {
+ var startTime = parseTimings(entity.begin);
+ var endTime = parseTimings(entity.end);
+ startTime = clipStartTime(startTime, intervalStart);
+ endTime = clipEndTime(endTime, intervalEnd);
+ if (typeof intervalStart !== 'undefined' && typeof intervalEnd !== 'undefined') {
+ if (endTime < intervalStart || startTime > intervalEnd) {
+ log('TTML: Cue ' + startTime + '-' + endTime + ' outside interval ' + intervalStart + '-' + intervalEnd);
+ return null;
+ }
+ }
+ return [startTime, endTime];
+ }
+
+ /*
+ * Check if entity timing has some overlap with interval
+ */
+ function inIntervalOrNoTiming(entity, interval) {
+ var inInterval = true;
+ if (entity.hasOwnProperty('span')) {
+ var entityInterval = getInterval(entity.span);
+ if (entityInterval !== null) {
+ //Timing
+ inInterval = entityInterval[0] < interval[1] && entityInterval[1] > interval[0];
+ }
+ }
+ return inInterval;
+ }
+
+ /**
+ * Parse the raw data and process it to return the HTML element representing the cue.
+ * Return the region to be processed and controlled (hide/show) by the caption controller.
+ * @param {string} data - raw data received from the TextSourceBuffer
+ * @param {number} intervalStart
+ * @param {number} intervalEnd
+ *
+ */
+
+ function parse(data, intervalStart, intervalEnd) {
+ var tt = undefined,
+ // Top element
+ head = undefined,
+ // head in tt
+ body = undefined,
+ // body in tt
+ ttExtent = undefined,
+ // extent attribute of tt element
+ type = undefined;
+
+ var errorMsg = '';
+
+ var converter = new _externalsXml2json2['default']([], '', false);
+
+ // Parse the TTML in a JSON object.
+ ttml = converter.xml_str2json(data);
+
+ if (!ttml) {
+ throw new Error('TTML document could not be parsed');
+ }
+
+ if (videoModel.getTTMLRenderingDiv()) {
+ type = 'html';
+ }
+
+ // Check the document and compare to the specification (TTML and EBU-TT-D).
+ tt = ttml.tt;
+ if (!tt) {
+ throw new Error('TTML document lacks tt element');
+ }
+
+ // Get the namespace if there is one defined in the JSON object.
+ var ttNS = getNamespacePrefix(tt, 'http://www.w3.org/ns/ttml');
+
+ // Remove the namespace before each node if it exists:
+ if (ttNS) {
+ removeNamespacePrefix(tt, ttNS);
+ }
+
+ ttExtent = tt['tts:extent']; // Should check that tts is right namespace.
+
+ head = tt.head;
+ if (!head) {
+ throw new Error('TTML document lacks head element');
+ }
+ if (head.layout) {
+ ttmlLayout = head.layout.region_asArray; //Mandatory in EBU-TT-D
+ }
+ if (head.styling) {
+ ttmlStyling = head.styling.style_asArray; // Mandatory in EBU-TT-D
+ }
+ body = tt.body;
+ if (!body) {
+ throw new Error('TTML document lacks body element');
+ }
+
+ // Extract the cellResolution information
+ var cellResolution = getCellResolution();
+
+ // Recover the video width and height displayed by the player.
+ var videoWidth = videoModel.getElement().clientWidth;
+ var videoHeight = videoModel.getElement().clientHeight;
+
+ // Compute the CellResolution unit in order to process properties using sizing (fontSize, linePadding, etc).
+ var cellUnit = [videoWidth / cellResolution[0], videoHeight / cellResolution[1]];
+ defaultStyleProperties['font-size'] = cellUnit[1] + 'px;';
+
+ var regions = [];
+ if (ttmlLayout) {
+ for (var i = 0; i < ttmlLayout.length; i++) {
+ regions.push(processRegion(JSON.parse(JSON.stringify(ttmlLayout[i])), cellUnit));
+ }
+ }
+
+ // Get the namespace prefix.
+ var nsttp = getNamespacePrefix(ttml.tt, 'http://www.w3.org/ns/ttml#parameter');
+
+ // Set the framerate.
+ if (tt.hasOwnProperty(nsttp + ':frameRate')) {
+ tt.frameRate = parseInt(tt[nsttp + ':frameRate'], 10);
+ }
+ var captionArray = [];
+ // Extract the div
+ var divs = tt.body_asArray[0].__children;
+
+ // Timing is either on div, paragraph or span level.
+
+ for (var k = 0; k < divs.length; k++) {
+ var div = divs[k].div;
+ var divInterval = null; // This is mainly for image subtitles.
+
+ if (null !== (divInterval = getInterval(div))) {
+ // Timing on div level is not allowed by EBU-TT-D.
+ // We only use it for SMPTE-TT image subtitle profile.
+
+ // Layout should be defined by a region. Given early test material, we also support that it is on
+ // div level
+ var layout = undefined;
+ if (div.region) {
+ var region = findRegionFromID(ttmlLayout, div.region);
+ layout = getRelativePositioning(region, ttExtent);
+ }
+ if (!layout) {
+ layout = getRelativePositioning(div, ttExtent);
+ }
+
+ var images = tt.head.metadata.image_asArray; // TODO. Add URL image sources
+
+ if (div['smpte:backgroundImage'] !== undefined) {
+ for (var j = 0; j < images.length; j++) {
+ if ('#' + images[j]['xml:id'] === div['smpte:backgroundImage']) {
+ captionArray.push({
+ start: divInterval[0],
+ end: divInterval[1],
+ id: getCueID(),
+ data: 'data:image/' + images[j].imagetype.toLowerCase() + ';base64, ' + images[j].__text,
+ type: 'image',
+ layout: layout
+ });
+ }
+ }
+ }
+ continue; // Next div
+ }
+
+ var paragraphs = div.p_asArray;
+ // Check if cues is not empty or undefined.
+ if (divInterval === null && (!paragraphs || paragraphs.length === 0)) {
+ errorMsg = 'TTML has div that contains no timing and no paragraphs.';
+ log(errorMsg);
+ return captionArray;
+ }
+
+ for (var j2 = 0; j2 < paragraphs.length; j2++) {
+ var paragraph = paragraphs[j2];
+ var spans = paragraph.span_asArray;
+ var cueIntervals = [];
+ // For timing, the overall goal is to find the intervals where there should be cues
+ // The timing may either be on paragraph or span level.
+ if (paragraph.hasOwnProperty('begin') && paragraph.hasOwnProperty('end')) {
+ // Timing on paragraph level
+ var clippedInterval = getClippedInterval(paragraph, intervalStart, intervalEnd);
+ if (clippedInterval !== null) {
+ cueIntervals.push(clippedInterval);
+ }
+ } else {
+ // Timing must be on span level
+ cueIntervals = createSpanIntervalList(spans, intervalStart, intervalEnd);
+ }
+ if (cueIntervals.length === 0) {
+ errorMsg = 'TTML: Empty paragraph';
+ continue; // Nothing in this paragraph
+ }
+
+ var paragraphChildren = paragraph.__children;
+
+ for (var i2 = 0; i2 < cueIntervals.length; i2++) {
+ var interval = cueIntervals[i2];
+ var childrenInInterval = [];
+ for (var k2 = 0; k2 < paragraphChildren.length; k2++) {
+ var child = paragraphChildren[k2];
+ if (inIntervalOrNoTiming(child, interval)) {
+ childrenInInterval.push(child);
+ }
+ }
+ if (childrenInInterval.length === 0) {
+ continue; // No children to render
+ }
+
+ if (type === 'html') {
+ lineHeight = {};
+ linePadding = {};
+ fontSize = {};
+
+ /**
+ * Find the region defined for the cue.
+ */
+ // properties to be put in the "captionRegion" HTML element.
+ var cueRegionProperties = constructCueRegion(paragraph, div, cellUnit);
+
+ /**
+ * Find the style defined for the cue.
+ */
+ // properties to be put in the "paragraph" HTML element.
+ var cueStyleProperties = constructCueStyle(paragraph, cellUnit);
+
+ /**
+ * /!\ Create the cue HTML Element containing the whole cue.
+ */
+ var styleIDs = cueStyleProperties[1];
+ cueStyleProperties = cueStyleProperties[0];
+
+ // Final cue HTML element.
+ var cueParagraph = document.createElement('div');
+ cueParagraph.className = styleIDs;
+
+ // Create a wrapper containing the cue information about unicodeBidi and direction
+ // as they need to be defined on at this level.
+ // We append to the wrapper the cue itself.
+ var cueDirUniWrapper = constructCue(childrenInInterval, cellUnit);
+ cueDirUniWrapper.className = 'cueDirUniWrapper';
+
+ // If the style defines these two properties, we place them in cueContainer
+ // and delete them from the cue style so it is not added afterwards to the final cue.
+ if (arrayContains('unicode-bidi', cueStyleProperties)) {
+ cueDirUniWrapper.style.cssText += getPropertyFromArray('unicode-bidi', cueStyleProperties);
+ deletePropertyFromArray('unicode-bidi', cueStyleProperties);
+ }
+ if (arrayContains('direction', cueStyleProperties)) {
+ cueDirUniWrapper.style.cssText += getPropertyFromArray('direction', cueStyleProperties);
+ deletePropertyFromArray('direction', cueStyleProperties);
+ }
+
+ // Apply the linePadding property if it is specified in the cue style.
+ if (arrayContains('padding-left', cueStyleProperties) && arrayContains('padding-right', cueStyleProperties)) {
+ cueDirUniWrapper.innerHTML = applyLinePadding(cueDirUniWrapper, cueStyleProperties);
+ }
+
+ /**
+ * Clean and set the style and region for the cue to be returned.
+ */
+
+ // Remove the line padding property from being added at the "paragraph" element level.
+ if (arrayContains('padding-left', cueStyleProperties) && arrayContains('padding-right', cueStyleProperties)) {
+ deletePropertyFromArray('padding-left', cueStyleProperties);
+ deletePropertyFromArray('padding-right', cueStyleProperties);
+ }
+
+ // Remove the ID of the region from being added at the "paragraph" element level.
+ var regionID = '';
+ if (arrayContains('regionID', cueRegionProperties)) {
+ var wholeRegionID = getPropertyFromArray('regionID', cueRegionProperties);
+ regionID = wholeRegionID.slice(wholeRegionID.indexOf(':') + 1, wholeRegionID.length - 1);
+ }
+
+ // We link the p style to the finale cueParagraph element.
+ if (cueStyleProperties) {
+ cueParagraph.style.cssText = cueStyleProperties.join(' ') + 'display:flex;';
+ }
+ // We define the CSS style for the cue region.
+ if (cueRegionProperties) {
+ cueRegionProperties = cueRegionProperties.join(' ');
+ }
+
+ // We then place the cue wrapper inside the paragraph element.
+ cueParagraph.appendChild(cueDirUniWrapper);
+
+ // Final cue.
+ var finalCue = document.createElement('div');
+ finalCue.appendChild(cueParagraph);
+ finalCue.id = getCueID();
+ finalCue.style.cssText = 'position: absolute; margin: 0; display: flex; box-sizing: border-box; pointer-events: none;' + cueRegionProperties;
+
+ if (Object.keys(fontSize).length === 0) {
+ fontSize.defaultFontSize = '100';
+ }
+
+ // We add all the cue information in captionArray.
+ captionArray.push({
+ start: interval[0],
+ end: interval[1],
+ type: 'html',
+ cueHTMLElement: finalCue,
+ regions: regions,
+ regionID: regionID,
+ cueID: finalCue.id,
+ videoHeight: videoHeight,
+ videoWidth: videoWidth,
+ cellResolution: cellResolution,
+ fontSize: fontSize || {
+ defaultFontSize: '100'
+ },
+ lineHeight: lineHeight,
+ linePadding: linePadding
+ });
+ } else {
+ var text = '';
+ var textElements = childrenInInterval;
+ if (textElements.length) {
+ textElements.forEach(function (el) {
+ if (el.hasOwnProperty('span')) {
+ var spanElements = el.span.__children;
+ spanElements.forEach(function (spanEl) {
+ // If metadata is present, do not process.
+ if (spanElements.hasOwnProperty('metadata')) {
+ return;
+ }
+ // If the element is a string
+ if (spanEl.hasOwnProperty('#text')) {
+ text += spanEl['#text'].replace(/[\r\n]+/gm, ' ').trim();
+ // If the element is a 'br' tag
+ } else if ('br' in spanEl) {
+ // Create a br element.
+ text += '\n';
+ }
+ });
+ } else if (el.hasOwnProperty('br')) {
+ text += '\n';
+ } else {
+ text += el['#text'].replace(/[\r\n]+/gm, ' ').trim();
+ }
+ });
+ }
+
+ captionArray.push({
+ start: interval[0],
+ end: interval[1],
+ data: text,
+ type: 'text'
+ });
+ }
+ }
+ }
+ }
+
+ if (errorMsg !== '') {
+ log(errorMsg);
+ }
+
+ if (captionArray.length > 0) {
+ return captionArray;
+ } else {
+ // This seems too strong given that there are segments with no TTML subtitles
+ throw new Error(errorMsg);
+ }
+ }
+
+ function setup() {
+ /*
+ * This TTML parser follows "EBU-TT-D SUBTITLING DISTRIBUTION FORMAT - tech3380" spec - https://tech.ebu.ch/docs/tech/tech3380.pdf.
+ * */
+ timingRegex = /^([0-9][0-9]+):([0-5][0-9]):([0-5][0-9])|(60)(\.([0-9])+)?$/; // Regex defining the time
+ fontSize = {};
+ lineHeight = {};
+ linePadding = {};
+ defaultLayoutProperties = {
+ 'top': 'auto;',
+ 'left': 'auto;',
+ 'width': '90%;',
+ 'height': '10%;',
+ 'align-items': 'flex-start;',
+ 'overflow': 'visible;',
+ '-ms-writing-mode': 'lr-tb, horizontal-tb;',
+ '-webkit-writing-mode': 'horizontal-tb;',
+ '-moz-writing-mode': 'horizontal-tb;',
+ 'writing-mode': 'horizontal-tb;'
+ };
+ defaultStyleProperties = {
+ 'color': 'rgb(255,255,255);',
+ 'direction': 'ltr;',
+ 'font-family': 'monospace, sans-serif;',
+ 'font-style': 'normal;',
+ 'line-height': 'normal;',
+ 'font-weight': 'normal;',
+ 'text-align': 'start;',
+ 'justify-content': 'flex-start;',
+ 'text-decoration': 'none;',
+ 'unicode-bidi': 'normal;',
+ 'white-space': 'normal;',
+ 'width': '100%;'
+ };
+ fontFamilies = {
+ monospace: 'font-family: monospace;',
+ sansSerif: 'font-family: sans-serif;',
+ serif: 'font-family: serif;',
+ monospaceSansSerif: 'font-family: monospace, sans-serif;',
+ monospaceSerif: 'font-family: monospace, serif;',
+ proportionalSansSerif: 'font-family: Arial;',
+ proportionalSerif: 'font-family: Times New Roman;',
+ 'default': 'font-family: monospace, sans-serif;'
+ };
+ textAlign = {
+ right: ['justify-content: flex-end;', 'text-align: right;'],
+ start: ['justify-content: flex-start;', 'text-align: start;'],
+ center: ['justify-content: center;', 'text-align: center;'],
+ end: ['justify-content: flex-end;', 'text-align: end;'],
+ left: ['justify-content: flex-start;', 'text-align: left;']
+ };
+ multiRowAlign = {
+ start: 'text-align: start;',
+ center: 'text-align: center;',
+ end: 'text-align: end;',
+ auto: ''
+ };
+ wrapOption = {
+ wrap: 'white-space: normal;',
+ noWrap: 'white-space: nowrap;'
+ };
+ unicodeBidi = {
+ normal: 'unicode-bidi: normal;',
+ embed: 'unicode-bidi: embed;',
+ bidiOverride: 'unicode-bidi: bidi-override;'
+ };
+ displayAlign = {
+ before: 'align-items: flex-start;',
+ center: 'align-items: center;',
+ after: 'align-items: flex-end;'
+ };
+ writingMode = {
+ lrtb: '-webkit-writing-mode: horizontal-tb;' + 'writing-mode: horizontal-tb;',
+ rltb: '-webkit-writing-mode: horizontal-tb;' + 'writing-mode: horizontal-tb;' + 'direction: rtl;' + 'unicode-bidi: bidi-override;',
+ tbrl: '-webkit-writing-mode: vertical-rl;' + 'writing-mode: vertical-rl;' + '-webkit-text-orientation: upright;' + 'text-orientation: upright;',
+ tblr: '-webkit-writing-mode: vertical-lr;' + 'writing-mode: vertical-lr;' + '-webkit-text-orientation: upright;' + 'text-orientation: upright;',
+ lr: '-webkit-writing-mode: horizontal-tb;' + 'writing-mode: horizontal-tb;',
+ rl: '-webkit-writing-mode: horizontal-tb;' + 'writing-mode: horizontal-tb;' + 'direction: rtl;',
+ tb: '-webkit-writing-mode: vertical-rl;' + 'writing-mode: vertical-rl;' + '-webkit-text-orientation: upright;' + 'text-orientation: upright;'
+ };
+ }
+
+ function parseTimings(timingStr) {
+ // Test if the time provided by the caption is valid.
+ var test = timingRegex.test(timingStr);
+ var timeParts, parsedTime, frameRate;
+
+ if (!test) {
+ // Return NaN so it will throw an exception at internalParse if the time is incorrect.
+ return NaN;
+ }
+
+ timeParts = timingStr.split(':');
+
+ // Process the timings by decomposing it and converting it in numbers.
+ parsedTime = parseFloat(timeParts[0]) * SECONDS_IN_HOUR + parseFloat(timeParts[1]) * SECONDS_IN_MIN + parseFloat(timeParts[2]);
+
+ // In case a frameRate is provided, we adjust the parsed time.
+ if (timeParts[3]) {
+ frameRate = ttml.tt.frameRate;
+ if (frameRate && !isNaN(frameRate)) {
+ parsedTime += parseFloat(timeParts[3]) / frameRate;
+ } else {
+ return NaN;
+ }
+ }
+ return parsedTime;
+ }
+
+ function getNamespacePrefix(json, ns) {
+ // Obtain the namespace prefix.
+ var r = Object.keys(json).filter(function (k) {
+ return (k.split(':')[0] === 'xmlns' || k.split(':')[1] === 'xmlns') && json[k] === ns;
+ }).map(function (k) {
+ return k.split(':')[2] || k.split(':')[1];
+ });
+ if (r.length != 1) {
+ return null;
+ }
+ return r[0];
+ }
+
+ function removeNamespacePrefix(json, nsPrefix) {
+ for (var key in json) {
+ if (json.hasOwnProperty(key)) {
+ if ((typeof json[key] === 'object' || json[key] instanceof Object) && !Array.isArray(json[key])) {
+ removeNamespacePrefix(json[key], nsPrefix);
+ } else if (Array.isArray(json[key])) {
+ for (var i = 0; i < json[key].length; i++) {
+ removeNamespacePrefix(json[key][i], nsPrefix);
+ }
+ }
+ var newKey = key.slice(key.indexOf(nsPrefix) + nsPrefix.length + 1);
+ json[newKey] = json[key];
+ delete json[key];
+ }
+ }
+ }
+
+ // backgroundColor = background-color, convert from camelCase to dash.
+ function camelCaseToDash(key) {
+ return key.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
+ }
+
+ // Convert an RGBA value written in Hex to rgba(v,v,v,a).
+ function convertHexToRGBA(rgba) {
+ // Get the hexadecimal value without the #.
+ var hex = rgba.slice(1);
+ // Separate the values in pairs.
+ var hexMatrice = hex.match(/.{2}/g);
+ // Convert the alpha value in decimal between 0 and 1.
+ var alpha = parseFloat(parseInt(parseInt(hexMatrice[3], 16) / 255 * 1000, 10) / 1000);
+ // Get the standard RGB value.
+ var rgb = hexMatrice.slice(0, 3).map(function (i) {
+ return parseInt(i, 16);
+ });
+ // Return the RGBA value for CSS.
+ return 'rgba(' + rgb.join(',') + ',' + alpha + ');';
+ }
+
+ // Return whether or not an array contains a certain text
+ function arrayContains(text, array) {
+ for (var i = 0; i < array.length; i++) {
+ if (array[i].indexOf(text) > -1) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // Return the whole value that contains "text"
+ function getPropertyFromArray(text, array) {
+ for (var i = 0; i < array.length; i++) {
+ if (array[i].indexOf(text) > -1) {
+ return array[i];
+ }
+ }
+ return null;
+ }
+
+ // Delete a a property from an array.
+ function deletePropertyFromArray(property, array) {
+ array.splice(array.indexOf(getPropertyFromArray(property, array)), 1);
+ }
+
+ function mergeArrays(primeArray, arrayToAdd) {
+ for (var i = 0; i < primeArray.length; i++) {
+ for (var j = 0; j < arrayToAdd.length; j++) {
+ // Take only the name of the property
+ if (primeArray[i]) {
+ if (primeArray[i].split(':')[0].indexOf(arrayToAdd[j].split(':')[0]) > -1) {
+ primeArray.splice(i, 1);
+ }
+ }
+ }
+ }
+ return primeArray.concat(arrayToAdd);
+ }
+
+ /**
+ * Processing of styling information:
+ * - processStyle: return an array of strings with the cue style under a CSS style form.
+ * - findStyleFromID: Return the unprocessed style from TTMLStyling corresponding to the ID researched.
+ * - getProcessedStyle: Return the processed style(s) from the ID(s) received in entry.
+ * **/
+
+ // Compute the style properties to return an array with the cleaned properties.
+ function processStyle(cueStyle, cellUnit, includeRegionStyles) {
+ var properties = [];
+
+ // Clean up from the xml2json parsing:
+ for (var key in cueStyle) {
+ if (cueStyle.hasOwnProperty(key)) {
+ //Clean the properties from the parsing.
+ var newKey = key.replace('ebutts:', '');
+ newKey = newKey.replace('xml:', '');
+ newKey = newKey.replace('tts:', '');
+
+ // Clean the properties' names.
+ newKey = camelCaseToDash(newKey);
+ cueStyle[newKey] = cueStyle[key];
+ delete cueStyle[key];
+ }
+ }
+
+ // Line padding is computed from the cellResolution.
+ if ('line-padding' in cueStyle) {
+ var valuePadding = parseFloat(cueStyle['line-padding'].slice(cueStyle['line-padding'].indexOf(':') + 1, cueStyle['line-padding'].indexOf('c')));
+ if ('id' in cueStyle) {
+ linePadding[cueStyle.id] = valuePadding;
+ }
+ var valuePaddingInPx = valuePadding * cellUnit[0] + 'px;';
+ properties.push('padding-left:' + valuePaddingInPx);
+ properties.push('padding-right:' + valuePaddingInPx);
+ }
+ // Font size is computed from the cellResolution.
+ if ('font-size' in cueStyle) {
+ var valueFtSize = parseFloat(cueStyle['font-size'].slice(cueStyle['font-size'].indexOf(':') + 1, cueStyle['font-size'].indexOf('%')));
+ if ('id' in cueStyle) {
+ fontSize[cueStyle.id] = valueFtSize;
+ }
+ var valueFtSizeInPx = valueFtSize / 100 * cellUnit[1] + 'px;';
+ properties.push('font-size:' + valueFtSizeInPx);
+ }
+ // Line height is computed from the cellResolution.
+ if ('line-height' in cueStyle) {
+ if (cueStyle['line-height'] === 'normal') {
+ properties.push('line-height: normal;');
+ } else {
+ var valueLHSize = parseFloat(cueStyle['line-height'].slice(cueStyle['line-height'].indexOf(':') + 1, cueStyle['line-height'].indexOf('%')));
+ if ('id' in cueStyle) {
+ lineHeight[cueStyle.id] = valueLHSize;
+ }
+ var valueLHSizeInPx = valueLHSize / 100 * cellUnit[1] + 'px;';
+ properties.push('line-height' + ':' + valueLHSizeInPx);
+ }
+ }
+ // Font-family can be specified by a generic family name or a custom family name.
+ if ('font-family' in cueStyle) {
+ if (cueStyle['font-family'] in fontFamilies) {
+ properties.push(fontFamilies[cueStyle['font-family']]);
+ } else {
+ properties.push('font-family:' + cueStyle['font-family'] + ';');
+ }
+ }
+ // Text align needs to be set from two properties:
+ // The standard text-align CSS property.
+ // The justify-content property as we use flex boxes.
+ if ('text-align' in cueStyle) {
+ if (cueStyle['text-align'] in textAlign) {
+ properties.push(textAlign[cueStyle['text-align']][0]);
+ properties.push(textAlign[cueStyle['text-align']][1]);
+ }
+ }
+ // Multi Row align is set only by the text-align property.
+ // TODO: TO CHECK
+ if ('multi-row-align' in cueStyle) {
+ if (arrayContains('text-align', properties) && cueStyle['multi-row-align'] != 'auto') {
+ deletePropertyFromArray('text-align', properties);
+ }
+ if (cueStyle['multi-row-align'] in multiRowAlign) {
+ properties.push(multiRowAlign[cueStyle['multi-row-align']]);
+ }
+ }
+ // Background color can be specified from hexadecimal (RGB or RGBA) value.
+ var rgbaValue;
+ if ('background-color' in cueStyle) {
+ if (cueStyle['background-color'].indexOf('#') > -1 && cueStyle['background-color'].length - 1 === 8) {
+ rgbaValue = convertHexToRGBA(cueStyle['background-color']);
+ properties.push('background-color: ' + rgbaValue);
+ } else {
+ properties.push('background-color:' + cueStyle['background-color'] + ';');
+ }
+ }
+ // Color can be specified from hexadecimal (RGB or RGBA) value.
+ if ('color' in cueStyle) {
+ if (cueStyle.color.indexOf('#') > -1 && cueStyle.color.length - 1 === 8) {
+ rgbaValue = convertHexToRGBA(cueStyle.color);
+ properties.push('color: ' + rgbaValue);
+ } else {
+ properties.push('color:' + cueStyle.color + ';');
+ }
+ }
+ // Wrap option is determined by the white-space CSS property.
+ if ('wrap-option' in cueStyle) {
+ if (cueStyle['wrap-option'] in wrapOption) {
+ properties.push(wrapOption[cueStyle['wrap-option']]);
+ } else {
+ properties.push('white-space:' + cueStyle['wrap-option']);
+ }
+ }
+ // Unicode bidi is determined by the unicode-bidi CSS property.
+ if ('unicode-bidi' in cueStyle) {
+ if (cueStyle['unicode-bidi'] in unicodeBidi) {
+ properties.push(unicodeBidi[cueStyle['unicode-bidi']]);
+ } else {
+ properties.push('unicode-bidi:' + cueStyle['unicode-bidi']);
+ }
+ }
+
+ // Standard properties identical to CSS.
+
+ if ('font-style' in cueStyle) {
+ properties.push('font-style:' + cueStyle['font-style'] + ';');
+ }
+ if ('font-weight' in cueStyle) {
+ properties.push('font-weight:' + cueStyle['font-weight'] + ';');
+ }
+ if ('direction' in cueStyle) {
+ properties.push('direction:' + cueStyle.direction + ';');
+ }
+ if ('text-decoration' in cueStyle) {
+ properties.push('text-decoration:' + cueStyle['text-decoration'] + ';');
+ }
+
+ if (includeRegionStyles) {
+ properties = properties.concat(processRegion(cueStyle, cellUnit));
+ }
+
+ // Handle white-space preserve
+ if (ttml.tt.hasOwnProperty('xml:space')) {
+ if (ttml.tt['xml:space'] === 'preserve') {
+ properties.push('white-space: pre;');
+ }
+ }
+
+ return properties;
+ }
+
+ // Find the style set by comparing the style IDs available.
+ // Return null if no style is found
+ function findStyleFromID(ttmlStyling, cueStyleID) {
+ // For every styles available, search the corresponding style in ttmlStyling.
+ for (var j = 0; j < ttmlStyling.length; j++) {
+ var currStyle = ttmlStyling[j];
+ if (currStyle['xml:id'] === cueStyleID || currStyle.id === cueStyleID) {
+ // Return the style corresponding to the ID in parameter.
+ return currStyle;
+ }
+ }
+ return null;
+ }
+ // Return the computed style from a certain ID.
+ function getProcessedStyle(reference, cellUnit, includeRegionStyles) {
+ var styles = [];
+ var ids = reference.match(/\S+/g);
+ ids.forEach(function (id) {
+ // Find the style for each id received.
+ var cueStyle = findStyleFromID(ttmlStyling, id);
+ if (cueStyle) {
+ // Process the style for the cue in CSS form.
+ // Send a copy of the style object, so it does not modify the original by cleaning it.
+ var stylesFromId = processStyle(JSON.parse(JSON.stringify(cueStyle)), cellUnit, includeRegionStyles);
+ styles = styles.concat(stylesFromId);
+ }
+ });
+ return styles;
+ }
+
+ // Calculate relative left, top, width, height from extent and origin in percent.
+ // Return object with {left, top, width, height} as numbers in percent or null.
+ function getRelativePositioning(element, ttExtent) {
+
+ var pairRe = /([\d\.]+)(%|px)\s+([\d\.]+)(%|px)/;
+
+ if ('tts:extent' in element && 'tts:origin' in element) {
+ var extentParts = pairRe.exec(element['tts:extent']);
+ var originParts = pairRe.exec(element['tts:origin']);
+ if (extentParts === null || originParts === null) {
+ log('Bad extent or origin: ' + element['tts:extent'] + ' ' + element['tts:origin']);
+ return null;
+ }
+ var width = parseFloat(extentParts[1]);
+ var height = parseFloat(extentParts[3]);
+ var left = parseFloat(originParts[1]);
+ var _top = parseFloat(originParts[3]);
+
+ if (ttExtent) {
+ // Should give overall scale in pixels
+ var ttExtentParts = pairRe.exec(ttExtent);
+ if (ttExtentParts === null || ttExtentParts[2] !== 'px' || ttExtentParts[4] !== 'px') {
+ log('Bad tt.extent: ' + ttExtent);
+ return null;
+ }
+ var exWidth = parseFloat(ttExtentParts[1]);
+ var exHeight = parseFloat(ttExtentParts[3]);
+ if (extentParts[2] === 'px') {
+ width = width / exWidth * 100;
+ }
+ if (extentParts[4] === 'px') {
+ height = height / exHeight * 100;
+ }
+ if (originParts[2] === 'px') {
+ left = left / exWidth * 100;
+ }
+ if (originParts[4] === 'px') {
+ _top = _top / exHeight * 100;
+ }
+ }
+ return { 'left': left, 'top': _top, 'width': width, 'height': height };
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Processing of layout information:
+ * - processRegion: return an array of strings with the cue region under a CSS style form.
+ * - findRegionFromID: Return the unprocessed region from TTMLLayout corresponding to the ID researched.
+ * - getProcessedRegion: Return the processed region(s) from the ID(s) received in entry.
+ ***/
+
+ // Compute the region properties to return an array with the cleaned properties.
+ function processRegion(cueRegion, cellUnit) {
+ var properties = [];
+
+ // Clean up from the xml2json parsing:
+ for (var key in cueRegion) {
+ //Clean the properties from the parsing.
+ var newKey = key.replace('tts:', '');
+ newKey = newKey.replace('xml:', '');
+
+ // Clean the properties' names.
+ newKey = camelCaseToDash(newKey);
+ cueRegion[newKey] = cueRegion[key];
+ if (newKey !== key) {
+ delete cueRegion[key];
+ }
+ }
+ // Extent property corresponds to width and height
+ if ('extent' in cueRegion) {
+ var coordsExtent = cueRegion.extent.split(/\s/);
+ properties.push('width: ' + coordsExtent[0] + ';');
+ properties.push('height: ' + coordsExtent[1] + ';');
+ }
+ // Origin property corresponds to top and left
+ if ('origin' in cueRegion) {
+ var coordsOrigin = cueRegion.origin.split(/\s/);
+ properties.push('left: ' + coordsOrigin[0] + ';');
+ properties.push('top: ' + coordsOrigin[1] + ';');
+ }
+ // DisplayAlign property corresponds to vertical-align
+ if ('display-align' in cueRegion) {
+ properties.push(displayAlign[cueRegion['display-align']]);
+ }
+ // WritingMode is not yet implemented (for CSS3, to come)
+ if ('writing-mode' in cueRegion) {
+ properties.push(writingMode[cueRegion['writing-mode']]);
+ }
+ // Style will give to the region the style properties from the style selected
+ if ('style' in cueRegion) {
+ var styleFromID = getProcessedStyle(cueRegion.style, cellUnit, true);
+ properties = properties.concat(styleFromID);
+ }
+
+ // Standard properties identical to CSS.
+
+ if ('padding' in cueRegion) {
+ properties.push('padding:' + cueRegion.padding + ';');
+ }
+ if ('overflow' in cueRegion) {
+ properties.push('overflow:' + cueRegion.overflow + ';');
+ }
+ if ('show-background' in cueRegion) {
+ properties.push('show-background:' + cueRegion['show-background'] + ';');
+ }
+ if ('id' in cueRegion) {
+ properties.push('regionID:' + cueRegion.id + ';');
+ }
+
+ return properties;
+ }
+
+ // Find the region set by comparing the region IDs available.
+ // Return null if no region is found
+ function findRegionFromID(ttmlLayout, cueRegionID) {
+ // For every region available, search the corresponding style in ttmlLayout.
+ for (var j = 0; j < ttmlLayout.length; j++) {
+ var currReg = ttmlLayout[j];
+ if (currReg['xml:id'] === cueRegionID || currReg.id === cueRegionID) {
+ // Return the region corresponding to the ID in parameter.
+ return currReg;
+ }
+ }
+ return null;
+ }
+
+ // Return the computed region from a certain ID.
+ function getProcessedRegion(reference, cellUnit) {
+ var regions = [];
+ var ids = reference.match(/\S+/g);
+ ids.forEach(function (id) {
+ // Find the region for each id received.
+ var cueRegion = findRegionFromID(ttmlLayout, id);
+ if (cueRegion) {
+ // Process the region for the cue in CSS form.
+ // Send a copy of the style object, so it does not modify the original by cleaning it.
+ var regionsFromId = processRegion(JSON.parse(JSON.stringify(cueRegion)), cellUnit);
+ regions = regions.concat(regionsFromId);
+ }
+ });
+ return regions;
+ }
+
+ //Return the cellResolution defined by the TTML document.
+ function getCellResolution() {
+ var defaultCellResolution = [32, 15]; // Default cellResolution.
+ if (ttml.tt.hasOwnProperty('ttp:cellResolution')) {
+ return ttml.tt['ttp:cellResolution'].split(' ').map(parseFloat);
+ } else {
+ return defaultCellResolution;
+ }
+ }
+
+ // Return the cue wrapped into a span specifying its linePadding.
+ function applyLinePadding(cueHTML, cueStyle) {
+ // Extract the linePadding property from cueStyleProperties.
+ var linePaddingLeft = getPropertyFromArray('padding-left', cueStyle);
+ var linePaddingRight = getPropertyFromArray('padding-right', cueStyle);
+ var linePadding = linePaddingLeft.concat(' ' + linePaddingRight + ' ');
+
+ // Declaration of the HTML elements to be used in the cue innerHTML construction.
+ var outerHTMLBeforeBr = '';
+ var outerHTMLAfterBr = '';
+ var cueInnerHTML = '';
+
+ // List all the nodes of the subtitle.
+ var nodeList = Array.prototype.slice.call(cueHTML.children);
+ // Take a br element as reference.
+ var brElement = cueHTML.getElementsByClassName('lineBreak')[0];
+ // First index of the first br element.
+ var idx = nodeList.indexOf(brElement);
+ // array of all the br element indices
+ var indices = [];
+ // Find all the indices of the br elements.
+ while (idx != -1) {
+ indices.push(idx);
+ idx = nodeList.indexOf(brElement, idx + 1);
+ }
+
+ // Strings for the cue innerHTML construction.
+ var spanStringEnd = '<\/span>';
+ var br = '<br>';
+ var clonePropertyString = '<span' + ' class="spanPadding" ' + 'style="-webkit-box-decoration-break: clone; box-decoration-break: clone; ';
+
+ // If br elements are found:
+ if (indices.length) {
+ // For each index of a br element we compute the HTML coming before and/or after it.
+ indices.forEach(function (i, index) {
+ // If this is the first line break, we compute the HTML of the element coming before.
+ if (index === 0) {
+ var styleBefore = '';
+ // for each element coming before the line break, we add its HTML.
+ for (var j = 0; j < i; j++) {
+ outerHTMLBeforeBr += nodeList[j].outerHTML;
+ // If this is the first element, we add its style to the wrapper.
+ if (j === 0) {
+ styleBefore = linePadding.concat(nodeList[j].style.cssText);
+ }
+ }
+ // The before element will comprises the clone property (for line wrapping), the style that
+ // need to be applied (ex: background-color) and the rest og the HTML.
+ outerHTMLBeforeBr = clonePropertyString + styleBefore + '">' + outerHTMLBeforeBr;
+ }
+ // For every element of the list, we compute the element coming after the line break.s
+ var styleAfter = '';
+ // for each element coming after the line break, we add its HTML.
+ for (var k = i + 1; k < nodeList.length; k++) {
+ outerHTMLAfterBr += nodeList[k].outerHTML;
+ // If this is the last element, we add its style to the wrapper.
+ if (k === nodeList.length - 1) {
+ styleAfter += linePadding.concat(nodeList[k].style.cssText);
+ }
+ }
+
+ // The before element will comprises the clone property (for line wrapping), the style that
+ // need to be applied (ex: background-color) and the rest og the HTML.
+ outerHTMLAfterBr = clonePropertyString + styleAfter + '">' + outerHTMLAfterBr;
+
+ // For each line break we must add the before and/or after element to the final cue as well as
+ // the line break when needed.
+ if (outerHTMLBeforeBr && outerHTMLAfterBr && index === indices.length - 1) {
+ cueInnerHTML += outerHTMLBeforeBr + spanStringEnd + br + outerHTMLAfterBr + spanStringEnd;
+ } else if (outerHTMLBeforeBr && outerHTMLAfterBr && index !== indices.length - 1) {
+ cueInnerHTML += outerHTMLBeforeBr + spanStringEnd + br + outerHTMLAfterBr + spanStringEnd + br;
+ } else if (outerHTMLBeforeBr && !outerHTMLAfterBr) {
+ cueInnerHTML += outerHTMLBeforeBr + spanStringEnd;
+ } else if (!outerHTMLBeforeBr && outerHTMLAfterBr && index === indices.length - 1) {
+ cueInnerHTML += outerHTMLAfterBr + spanStringEnd;
+ } else if (!outerHTMLBeforeBr && outerHTMLAfterBr && index !== indices.length - 1) {
+ cueInnerHTML += outerHTMLAfterBr + spanStringEnd + br;
+ }
+ });
+ } else {
+ // If there is no line break in the subtitle, we simply wrap cue in a span indicating the linePadding.
+ var style = '';
+ for (var k = 0; k < nodeList.length; k++) {
+ style += nodeList[k].style.cssText;
+ }
+ cueInnerHTML = clonePropertyString + linePadding + style + '">' + cueHTML.innerHTML + spanStringEnd;
+ }
+ return cueInnerHTML;
+ }
+
+ /*
+ * Create the cue element
+ * I. The cues are text only:
+ * i) The cue contains a 'br' element
+ * ii) The cue contains a span element
+ * iii) The cue contains text
+ */
+
+ function constructCue(cueElements, cellUnit) {
+ var cue = document.createElement('div');
+ cueElements.forEach(function (el) {
+ // If metadata is present, do not process.
+ if (el.hasOwnProperty('metadata')) {
+ return;
+ }
+
+ /**
+ * If the p element contains spans: create the span elements.
+ */
+ if (el.hasOwnProperty('span')) {
+
+ // Stock the span subtitles in an array (in case there are only one value).
+ var spanElements = el.span.__children;
+
+ // Create the span element.
+ var spanHTMLElement = document.createElement('span');
+ // Extract the style of the span.
+ if (el.span.hasOwnProperty('style')) {
+ var spanStyle = getProcessedStyle(el.span.style, cellUnit);
+ spanHTMLElement.className = 'spanPadding ' + el.span.style;
+ spanHTMLElement.style.cssText = spanStyle.join(' ');
+ }
+
+ // if the span has more than one element, we check for each of them their nature (br or text).
+ spanElements.forEach(function (spanEl) {
+ // If metadata is present, do not process.
+ if (spanElements.hasOwnProperty('metadata')) {
+ return;
+ }
+ // If the element is a string
+ if (spanEl.hasOwnProperty('#text')) {
+ var textNode = document.createTextNode(spanEl['#text']);
+ spanHTMLElement.appendChild(textNode);
+ // If the element is a 'br' tag
+ } else if ('br' in spanEl) {
+ // To handle br inside span we need to add the current span
+ // to the cue and then create a br and add that the cue
+ // then create a new span that we use for the next line of
+ // text, that is a copy of the current span
+
+ // Add the current span to the cue, only if it has childNodes (text)
+ if (spanHTMLElement.hasChildNodes()) {
+ cue.appendChild(spanHTMLElement);
+ }
+
+ // Create a br and add that to the cue
+ var brEl = document.createElement('br');
+ brEl.className = 'lineBreak';
+ cue.appendChild(brEl);
+
+ // Create an replacement span and copy the style and classname from the old one
+ var newSpanHTMLElement = document.createElement('span');
+ newSpanHTMLElement.className = spanHTMLElement.className;
+ newSpanHTMLElement.style.cssText = spanHTMLElement.style.cssText;
+
+ // Replace the current span with the one we just created
+ spanHTMLElement = newSpanHTMLElement;
+ }
+ });
+ // We append the element to the cue container.
+ cue.appendChild(spanHTMLElement);
+ }
+
+ /**
+ * Create a br element if there is one in the cue.
+ */
+ else if (el.hasOwnProperty('br')) {
+ // We append the line break to the cue container.
+ var brEl = document.createElement('br');
+ brEl.className = 'lineBreak';
+ cue.appendChild(brEl);
+ }
+
+ /**
+ * Add the text that is not in any inline element
+ */
+ else if (el.hasOwnProperty('#text')) {
+ // Add the text to an individual span element (to add line padding if it is defined).
+ var textNode = document.createElement('span');
+ textNode.textContent = el['#text'];
+
+ // We append the element to the cue container.
+ cue.appendChild(textNode);
+ }
+ });
+ return cue;
+ }
+
+ function constructCueRegion(cue, div, cellUnit) {
+ var cueRegionProperties = []; // properties to be put in the "captionRegion" HTML element
+ // Obtain the region ID(s) assigned to the cue.
+ var pRegionID = cue.region;
+ // If div has a region.
+ var divRegionID = div.region;
+
+ var divRegion;
+ var pRegion;
+
+ // If the div element reference a region.
+ if (divRegionID) {
+ divRegion = getProcessedRegion(divRegionID, cellUnit);
+ }
+ // If the p element reference a region.
+ if (pRegionID) {
+ pRegion = cueRegionProperties.concat(getProcessedRegion(pRegionID, cellUnit));
+ if (divRegion) {
+ cueRegionProperties = mergeArrays(divRegion, pRegion);
+ } else {
+ cueRegionProperties = pRegion;
+ }
+ } else if (divRegion) {
+ cueRegionProperties = divRegion;
+ }
+
+ // Add initial/default values to what's not defined in the layout:
+ applyDefaultProperties(cueRegionProperties, defaultLayoutProperties);
+
+ return cueRegionProperties;
+ }
+
+ function constructCueStyle(cue, cellUnit) {
+ var cueStyleProperties = []; // properties to be put in the "paragraph" HTML element
+ // Obtain the style ID(s) assigned to the cue.
+ var pStyleID = cue.style;
+ // If body has a style.
+ var bodyStyleID = ttml.tt.body.style;
+ // If div has a style.
+ var divStyleID = ttml.tt.body.div.style;
+
+ var bodyStyle;
+ var divStyle;
+ var pStyle;
+ var styleIDs = '';
+
+ // If the body element reference a style.
+ if (bodyStyleID) {
+ bodyStyle = getProcessedStyle(bodyStyleID, cellUnit);
+ styleIDs = 'paragraph ' + bodyStyleID;
+ }
+
+ // If the div element reference a style.
+ if (divStyleID) {
+ divStyle = getProcessedStyle(divStyleID, cellUnit);
+ if (bodyStyle) {
+ divStyle = mergeArrays(bodyStyle, divStyle);
+ styleIDs += ' ' + divStyleID;
+ } else {
+ styleIDs = 'paragraph ' + divStyleID;
+ }
+ }
+
+ // If the p element reference a style.
+ if (pStyleID) {
+ pStyle = getProcessedStyle(pStyleID, cellUnit);
+ if (bodyStyle && divStyle) {
+ cueStyleProperties = mergeArrays(divStyle, pStyle);
+ styleIDs += ' ' + pStyleID;
+ } else if (bodyStyle) {
+ cueStyleProperties = mergeArrays(bodyStyle, pStyle);
+ styleIDs += ' ' + pStyleID;
+ } else if (divStyle) {
+ cueStyleProperties = mergeArrays(divStyle, pStyle);
+ styleIDs += ' ' + pStyleID;
+ } else {
+ cueStyleProperties = pStyle;
+ styleIDs = 'paragraph ' + pStyleID;
+ }
+ } else if (bodyStyle && !divStyle) {
+ cueStyleProperties = bodyStyle;
+ } else if (!bodyStyle && divStyle) {
+ cueStyleProperties = divStyle;
+ }
+
+ // Add initial/default values to what's not defined in the styling:
+ applyDefaultProperties(cueStyleProperties, defaultStyleProperties);
+
+ return [cueStyleProperties, styleIDs];
+ }
+
+ function applyDefaultProperties(array, defaultProperties) {
+ for (var key in defaultProperties) {
+ if (defaultProperties.hasOwnProperty(key)) {
+ if (!arrayContains(key, array)) {
+ array.push(key + ':' + defaultProperties[key]);
+ }
+ }
+ }
+ }
+
+ instance = {
+ parse: parse,
+ setConfig: setConfig
+ };
+
+ setup();
+ return instance;
+}
+TTMLParser.__dashjs_factory_name = 'TTMLParser';
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(TTMLParser);
+module.exports = exports['default'];
+
+},{"10":10,"4":4,"8":8}],158:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+/**
+ * @module URLUtils
+ * @description Provides utility functions for operating on URLs.
+ * Initially this is simply a method to determine the Base URL of a URL, but
+ * should probably include other things provided all over the place such as
+ * determining whether a URL is relative/absolute, resolving two paths etc.
+ */
+function URLUtils() {
+
+ var instance = undefined;
+
+ var absUrl = /^(?:(?:[a-z]+:)?\/)?\//i;
+ var httpUrlRegex = /^https?:\/\//i;
+ var originRegex = /^(https?:\/\/[^\/]+)\/?/i;
+
+ /**
+ * Returns a string that contains the Base URL of a URL, if determinable.
+ * @param {string} url - full url
+ * @return {string}
+ * @memberof module:URLUtils
+ * @instance
+ */
+ function parseBaseUrl(url) {
+ var base = '';
+
+ if (url.indexOf('/') !== -1) {
+ if (url.indexOf('?') !== -1) {
+ url = url.substring(0, url.indexOf('?'));
+ }
+ base = url.substring(0, url.lastIndexOf('/') + 1);
+ }
+
+ return base;
+ }
+
+ /**
+ * Returns a string that contains the scheme and origin of a URL,
+ * if determinable.
+ * @param {string} url - full url
+ * @return {string}
+ * @memberof module:URLUtils
+ * @instance
+ */
+ function parseOrigin(url) {
+ var matches = url.match(originRegex);
+
+ if (matches) {
+ return matches[1];
+ }
+
+ return '';
+ }
+
+ /**
+ * Determines whether the url is relative.
+ * @return {bool}
+ * @param {string} url
+ * @memberof module:URLUtils
+ * @instance
+ */
+ function isRelative(url) {
+ return !absUrl.test(url);
+ }
+
+ /**
+ * Determines whether the url is path-absolute.
+ * @return {bool}
+ * @param {string} url
+ * @memberof module:URLUtils
+ * @instance
+ */
+ function isPathAbsolute(url) {
+ return absUrl.test(url) && url.charAt(0) === '/';
+ }
+
+ /**
+ * Determines whether the url is an HTTP-URL as defined in ISO/IEC
+ * 23009-1:2014 3.1.15. ie URL with a fixed scheme of http or https
+ * @return {bool}
+ * @param {string} url
+ * @memberof module:URLUtils
+ * @instance
+ */
+ function isHTTPURL(url) {
+ return httpUrlRegex.test(url);
+ }
+
+ instance = {
+ parseBaseUrl: parseBaseUrl,
+ parseOrigin: parseOrigin,
+ isRelative: isRelative,
+ isPathAbsolute: isPathAbsolute,
+ isHTTPURL: isHTTPURL
+ };
+
+ return instance;
+}
+
+URLUtils.__dashjs_factory_name = 'URLUtils';
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(URLUtils);
+module.exports = exports['default'];
+
+},{"10":10}],159:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _coreFactoryMaker = _dereq_(10);
+
+var _coreFactoryMaker2 = _interopRequireDefault(_coreFactoryMaker);
+
+var _coreDebug = _dereq_(8);
+
+var _coreDebug2 = _interopRequireDefault(_coreDebug);
+
+function VTTParser() {
+ var context = this.context;
+ var log = (0, _coreDebug2['default'])(context).getInstance().log;
+
+ var instance = undefined,
+ regExNewLine = undefined,
+ regExToken = undefined,
+ regExWhiteSpace = undefined,
+ regExWhiteSpaceWordBoundary = undefined;
+
+ function setup() {
+ regExNewLine = /(?:\r\n|\r|\n)/gm;
+ regExToken = /-->/;
+ regExWhiteSpace = /(^[\s]+|[\s]+$)/g;
+ regExWhiteSpaceWordBoundary = /\s\b/g;
+ }
+
+ function parse(data) {
+ var captionArray = [];
+ var len, lastStartTime;
+
+ data = data.split(regExNewLine);
+ len = data.length;
+ lastStartTime = -1;
+
+ for (var i = 0; i < len; i++) {
+ var item = data[i];
+
+ if (item.length > 0 && item !== 'WEBVTT') {
+ if (item.match(regExToken)) {
+ var attributes = parseItemAttributes(item);
+ var cuePoints = attributes.cuePoints;
+ var styles = attributes.styles;
+ var text = getSublines(data, i + 1);
+ var startTime = convertCuePointTimes(cuePoints[0].replace(regExWhiteSpace, ''));
+ var endTime = convertCuePointTimes(cuePoints[1].replace(regExWhiteSpace, ''));
+
+ if (!isNaN(startTime) && !isNaN(endTime) && startTime >= lastStartTime && endTime > startTime) {
+ if (text !== '') {
+ lastStartTime = startTime;
+ //TODO Make VO external so other parsers can use.
+ captionArray.push({
+ start: startTime,
+ end: endTime,
+ data: text,
+ styles: styles
+ });
+ } else {
+ log('Skipping cue due to empty/malformed cue text');
+ }
+ } else {
+ log('Skipping cue due to incorrect cue timing');
+ }
+ }
+ }
+ }
+
+ return captionArray;
+ }
+
+ function convertCuePointTimes(time) {
+ var timeArray = time.split(':');
+ var len = timeArray.length - 1;
+
+ time = parseInt(timeArray[len - 1], 10) * 60 + parseFloat(timeArray[len]);
+
+ if (len === 2) {
+ time += parseInt(timeArray[0], 10) * 3600;
+ }
+
+ return time;
+ }
+
+ function parseItemAttributes(data) {
+ var vttCuePoints = data.split(regExToken);
+ var arr = vttCuePoints[1].split(regExWhiteSpaceWordBoundary);
+ arr.shift(); //remove first array index it is empty...
+ vttCuePoints[1] = arr[0];
+ arr.shift();
+ return { cuePoints: vttCuePoints, styles: getCaptionStyles(arr) };
+ }
+
+ function getCaptionStyles(arr) {
+ var styleObject = {};
+ arr.forEach(function (element) {
+ if (element.split(/:/).length > 1) {
+ var val = element.split(/:/)[1];
+ if (val && val.search(/%/) != -1) {
+ val = parseInt(val.replace(/%/, ''), 10);
+ }
+ if (element.match(/align/) || element.match(/A/)) {
+ styleObject.align = val;
+ }
+ if (element.match(/line/) || element.match(/L/)) {
+ styleObject.line = val;
+ }
+ if (element.match(/position/) || element.match(/P/)) {
+ styleObject.position = val;
+ }
+ if (element.match(/size/) || element.match(/S/)) {
+ styleObject.size = val;
+ }
+ }
+ });
+
+ return styleObject;
+ }
+
+ /*
+ * VTT can have multiple lines to display per cuepoint.
+ */
+ function getSublines(data, idx) {
+ var i = idx;
+
+ var subline = '';
+ var lineData = '';
+ var lineCount;
+
+ while (data[i] !== '' && i < data.length) {
+ i++;
+ }
+
+ lineCount = i - idx;
+ if (lineCount > 1) {
+ for (var j = 0; j < lineCount; j++) {
+ lineData = data[idx + j];
+ if (!lineData.match(regExToken)) {
+ subline += lineData;
+ if (j !== lineCount - 1) {
+ subline += '\n';
+ }
+ } else {
+ // caption text should not have '-->' in it
+ subline = '';
+ break;
+ }
+ }
+ } else {
+ lineData = data[idx];
+ if (!lineData.match(regExToken)) subline = lineData;
+ }
+ return decodeURI(subline);
+ }
+
+ instance = {
+ parse: parse
+ };
+
+ setup();
+ return instance;
+}
+VTTParser.__dashjs_factory_name = 'VTTParser';
+exports['default'] = _coreFactoryMaker2['default'].getSingletonFactory(VTTParser);
+module.exports = exports['default'];
+
+},{"10":10,"8":8}],160:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @class
+ * @ignore
+ */
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var BitrateInfo = function BitrateInfo() {
+ _classCallCheck(this, BitrateInfo);
+
+ this.mediaType = null;
+ this.bitrate = null;
+ this.width = null;
+ this.height = null;
+ this.qualityIndex = NaN;
+};
+
+exports["default"] = BitrateInfo;
+module.exports = exports["default"];
+
+},{}],161:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @class
+ * @ignore
+ */
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var DataChunk =
+//Represents a data structure that keep all the necessary info about a single init/media segment
+function DataChunk() {
+ _classCallCheck(this, DataChunk);
+
+ this.streamId = null;
+ this.mediaInfo = null;
+ this.segmentType = null;
+ this.quality = NaN;
+ this.index = NaN;
+ this.bytes = null;
+ this.start = NaN;
+ this.end = NaN;
+ this.duration = NaN;
+};
+
+exports["default"] = DataChunk;
+module.exports = exports["default"];
+
+},{}],162:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @class
+ * @ignore
+ */
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var Error = function Error(code, message, data) {
+ _classCallCheck(this, Error);
+
+ this.code = code || null;
+ this.message = message || null;
+ this.data = data || null;
+};
+
+exports["default"] = Error;
+module.exports = exports["default"];
+
+},{}],163:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @class
+ * @ignore
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+
+var FragmentRequest = function FragmentRequest() {
+ _classCallCheck(this, FragmentRequest);
+
+ this.action = FragmentRequest.ACTION_DOWNLOAD;
+ this.startTime = NaN;
+ this.mediaType = null;
+ this.mediaInfo = null;
+ this.type = null;
+ this.duration = NaN;
+ this.timescale = NaN;
+ this.range = null;
+ this.url = null;
+ this.serviceLocation = null;
+ this.requestStartDate = null;
+ this.firstByteDate = null;
+ this.requestEndDate = null;
+ this.quality = NaN;
+ this.index = NaN;
+ this.availabilityStartTime = null;
+ this.availabilityEndTime = null;
+ this.wallStartTime = null;
+ this.bytesLoaded = NaN;
+ this.bytesTotal = NaN;
+ this.delayLoadingTime = NaN;
+ this.responseType = 'arraybuffer';
+};
+
+FragmentRequest.ACTION_DOWNLOAD = 'download';
+FragmentRequest.ACTION_COMPLETE = 'complete';
+
+exports['default'] = FragmentRequest;
+module.exports = exports['default'];
+
+},{}],164:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @class
+ * @ignore
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+var _FragmentRequest2 = _dereq_(163);
+
+var _FragmentRequest3 = _interopRequireDefault(_FragmentRequest2);
+
+var HeadRequest = (function (_FragmentRequest) {
+ _inherits(HeadRequest, _FragmentRequest);
+
+ function HeadRequest(url) {
+ _classCallCheck(this, HeadRequest);
+
+ _get(Object.getPrototypeOf(HeadRequest.prototype), 'constructor', this).call(this);
+ this.url = url || null;
+ this.checkForExistenceOnly = true;
+ }
+
+ return HeadRequest;
+})(_FragmentRequest3['default']);
+
+exports['default'] = HeadRequest;
+module.exports = exports['default'];
+
+},{"163":163}],165:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @class
+ * @ignore
+ */
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var IsoBox = function IsoBox() {
+ _classCallCheck(this, IsoBox);
+
+ this.offset = NaN;
+ this.type = null;
+ this.size = NaN;
+ this.isComplete = true;
+};
+
+exports["default"] = IsoBox;
+module.exports = exports["default"];
+
+},{}],166:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @class
+ * @ignore
+ */
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var ManifestInfo = function ManifestInfo() {
+ _classCallCheck(this, ManifestInfo);
+
+ this.DVRWindowSize = NaN;
+ this.loadedTime = null;
+ this.availableFrom = null;
+ this.minBufferTime = NaN;
+ this.duration = NaN;
+ this.isDynamic = false;
+ this.maxFragmentDuration = null;
+};
+
+exports["default"] = ManifestInfo;
+module.exports = exports["default"];
+
+},{}],167:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @class
+ * @ignore
+ */
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var MediaInfo = function MediaInfo() {
+ _classCallCheck(this, MediaInfo);
+
+ this.id = null;
+ this.index = null;
+ this.type = null;
+ this.streamInfo = null;
+ this.representationCount = 0;
+ this.lang = null;
+ this.viewpoint = null;
+ this.accessibility = null;
+ this.audioChannelConfiguration = null;
+ this.roles = null;
+ this.codec = null;
+ this.mimeType = null;
+ this.contentProtection = null;
+ this.isText = false;
+ this.KID = null;
+ this.bitrateList = null;
+};
+
+exports["default"] = MediaInfo;
+module.exports = exports["default"];
+
+},{}],168:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @class
+ * @ignore
+ */
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var MetricsList = function MetricsList() {
+ _classCallCheck(this, MetricsList);
+
+ this.TcpList = [];
+ this.HttpList = [];
+ this.RepSwitchList = [];
+ this.BufferLevel = [];
+ this.BufferState = [];
+ this.PlayList = [];
+ this.DroppedFrames = [];
+ this.SchedulingInfo = [];
+ this.DVRInfo = [];
+ this.ManifestUpdate = [];
+ this.RequestsQueue = null;
+ this.DVBErrors = [];
+ this.BolaState = [];
+};
+
+exports["default"] = MetricsList;
+module.exports = exports["default"];
+
+},{}],169:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @class
+ * @ignore
+ */
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var StreamInfo = function StreamInfo() {
+ _classCallCheck(this, StreamInfo);
+
+ this.id = null;
+ this.index = null;
+ this.start = NaN;
+ this.duration = NaN;
+ this.manifestInfo = null;
+ this.isLast = true;
+ this.isFirst = true;
+};
+
+exports["default"] = StreamInfo;
+module.exports = exports["default"];
+
+},{}],170:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @class
+ * @ignore
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+var _FragmentRequest2 = _dereq_(163);
+
+var _FragmentRequest3 = _interopRequireDefault(_FragmentRequest2);
+
+var TextRequest = (function (_FragmentRequest) {
+ _inherits(TextRequest, _FragmentRequest);
+
+ function TextRequest(url, type) {
+ _classCallCheck(this, TextRequest);
+
+ _get(Object.getPrototypeOf(TextRequest.prototype), 'constructor', this).call(this);
+ this.url = url || null;
+ this.type = type || null;
+ this.mediaType = 'stream';
+ this.responseType = 'text';
+ }
+
+ return TextRequest;
+})(_FragmentRequest3['default']);
+
+exports['default'] = TextRequest;
+module.exports = exports['default'];
+
+},{"163":163}],171:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @class
+ * @ignore
+ */
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var TextTrackInfo = function TextTrackInfo() {
+ _classCallCheck(this, TextTrackInfo);
+
+ this.video = null;
+ this.captionData = null;
+ this.label = null;
+ this.lang = null;
+ this.defaultTrack = false;
+ this.kind = null;
+ this.isFragmented = false;
+ this.isEmbedded = false;
+};
+
+exports["default"] = TextTrackInfo;
+module.exports = exports["default"];
+
+},{}],172:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @class
+ * @ignore
+ */
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var TrackInfo = function TrackInfo() {
+ _classCallCheck(this, TrackInfo);
+
+ this.id = null;
+ this.quality = null;
+ this.DVRWindow = null;
+ this.fragmentDuration = null;
+ this.mediaInfo = null;
+ this.MSETimeOffset = null;
+};
+
+exports["default"] = TrackInfo;
+module.exports = exports["default"];
+
+},{}],173:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @class
+ * @ignore
+ */
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var URIFragmentData = function URIFragmentData() {
+ _classCallCheck(this, URIFragmentData);
+
+ this.t = null;
+ this.xywh = null;
+ this.track = null;
+ this.id = null;
+ this.s = null;
+};
+
+exports["default"] = URIFragmentData;
+
+/*
+ From Spec http://www.w3.org/TR/media-frags/
+
+ temporal (t) - This dimension denotes a specific time range in the original media, such as "starting at second 10, continuing until second 20";
+ spatial (xywh) - this dimension denotes a specific range of pixels in the original media, such as "a rectangle with size (100,100) with its top-left at coordinate (10,10)";
+ Media fragments support also addressing the media along two additional dimensions (in the advanced version defined in Media Fragments 1.0 URI (advanced)):
+ track (track) - this dimension denotes one or more tracks in the original media, such as "the english audio and the video track";
+ id (id) - this dimension denotes a named temporal fragment within the original media, such as "chapter 2", and can be seen as a convenient way of specifying a temporal fragment.
+
+
+ ## Note
+ Akamai is purposing to add #s=X to the ISO standard.
+ - (X) Value would be a start time to seek to at startup instead of starting at 0 or live edge
+ - Allows for seeking back before the start time unlike a temporal clipping.
+*/
+module.exports = exports["default"];
+
+},{}],174:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2016, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @class
+ * @ignore
+ */
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var BolaState = function BolaState() {
+ _classCallCheck(this, BolaState);
+
+ /**
+ * number
+ * @private
+ */
+ this._s = undefined;
+};
+
+exports["default"] = BolaState;
+module.exports = exports["default"];
+
+},{}],175:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @class
+ */
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var BufferLevel =
+/**
+ * @description This Object holds reference to the current buffer level and the time it was recorded.
+ */
+function BufferLevel() {
+ _classCallCheck(this, BufferLevel);
+
+ /**
+ * Real-Time | Time of the measurement of the buffer level.
+ * @public
+ */
+ this.t = null;
+ /**
+ * Level of the buffer in milliseconds. Indicates the playout duration for which
+ * media data of all active media components is available starting from the
+ * current playout time.
+ * @public
+ */
+ this.level = null;
+};
+
+exports["default"] = BufferLevel;
+module.exports = exports["default"];
+
+},{}],176:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+
+var _controllersBufferController = _dereq_(63);
+
+var _controllersBufferController2 = _interopRequireDefault(_controllersBufferController);
+
+/**
+ * @class
+ */
+
+var BufferState =
+/**
+ * @description This Object holds reference to the current buffer state of the video element.
+ */
+function BufferState() {
+ _classCallCheck(this, BufferState);
+
+ /**
+ * The Buffer Level Target determined by the BufferLevelRule.
+ * @public
+ */
+ this.target = null;
+ /**
+ * Current buffer state. Will be BufferController.BUFFER_EMPTY or BufferController.BUFFER_LOADED.
+ * @public
+ */
+ this.state = _controllersBufferController2['default'].BUFFER_EMPTY;
+};
+
+exports['default'] = BufferState;
+module.exports = exports['default'];
+
+},{"63":63}],177:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @class
+ */
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var DVRInfo =
+/**
+ * @description This Object holds reference to DVR availability window information.
+ */
+function DVRInfo() {
+ _classCallCheck(this, DVRInfo);
+
+ /**
+ * The current time of the video element when this was created.
+ * @public
+ */
+ this.time = null;
+ /**
+ * The current Segment Availability Range as an object with start and end properties.
+ * It's delta defined by the timeShiftBufferDepth MPD attribute.
+ * @public
+ */
+ this.range = null;
+ /**
+ * Reference to the internal ManifestInfo.js VO.
+ * @public
+ */
+ this.manifestInfo = null;
+};
+
+exports["default"] = DVRInfo;
+module.exports = exports["default"];
+
+},{}],178:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @class
+ */
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var DroppedFrames =
+/**
+ * @description This Object holds reference to DroppedFrames count and the time it was recorded.
+ */
+function DroppedFrames() {
+ _classCallCheck(this, DroppedFrames);
+
+ /**
+ * Real-Time | Time of the measurement of the dropped frames.
+ * @public
+ */
+ this.time = null;
+ /**
+ * Number of dropped frames
+ * @public
+ */
+ this.droppedFrames = null;
+};
+
+exports["default"] = DroppedFrames;
+module.exports = exports["default"];
+
+},{}],179:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @classdesc This Object holds reference to the HTTPRequest for manifest, fragment and xlink loading.
+ * Members which are not defined in ISO23009-1 Annex D should be prefixed by a _ so that they are ignored
+ * by Metrics Reporting code.
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+
+var HTTPRequest =
+/**
+ * @class
+ */
+function HTTPRequest() {
+ _classCallCheck(this, HTTPRequest);
+
+ /**
+ * Identifier of the TCP connection on which the HTTP request was sent.
+ * @public
+ */
+ this.tcpid = null;
+ /**
+ * This is an optional parameter and should not be included in HTTP request/response transactions for progressive download.
+ * The type of the request:
+ * - MPD
+ * - XLink expansion
+ * - Initialization Fragment
+ * - Index Fragment
+ * - Media Fragment
+ * - Bitstream Switching Fragment
+ * - other
+ * @public
+ */
+ this.type = null;
+ /**
+ * The original URL (before any redirects or failures)
+ * @public
+ */
+ this.url = null;
+ /**
+ * The actual URL requested, if different from above
+ * @public
+ */
+ this.actualurl = null;
+ /**
+ * The contents of the byte-range-spec part of the HTTP Range header.
+ * @public
+ */
+ this.range = null;
+ /**
+ * Real-Time | The real time at which the request was sent.
+ * @public
+ */
+ this.trequest = null;
+ /**
+ * Real-Time | The real time at which the first byte of the response was received.
+ * @public
+ */
+ this.tresponse = null;
+ /**
+ * The HTTP response code.
+ * @public
+ */
+ this.responsecode = null;
+ /**
+ * The duration of the throughput trace intervals (ms), for successful requests only.
+ * @public
+ */
+ this.interval = null;
+ /**
+ * Throughput traces, for successful requests only.
+ * @public
+ */
+ this.trace = [];
+
+ /**
+ * Type of stream ("audio" | "video" etc..)
+ * @public
+ */
+ this._stream = null;
+ /**
+ * Real-Time | The real time at which the request finished.
+ * @public
+ */
+ this._tfinish = null;
+ /**
+ * The duration of the media requests, if available, in milliseconds.
+ * @public
+ */
+ this._mediaduration = null;
+ /**
+ * all the response headers from request.
+ * @public
+ */
+ this._responseHeaders = null;
+ /**
+ * The selected service location for the request. string.
+ * @public
+ */
+ this._serviceLocation = null;
+}
+
+/**
+ * @classdesc This Object holds reference to the progress of the HTTPRequest.
+ */
+;
+
+var HTTPRequestTrace =
+/**
+* @class
+*/
+function HTTPRequestTrace() {
+ _classCallCheck(this, HTTPRequestTrace);
+
+ /**
+ * Real-Time | Measurement stream start.
+ * @public
+ */
+ this.s = null;
+ /**
+ * Measurement stream duration (ms).
+ * @public
+ */
+ this.d = null;
+ /**
+ * List of integers counting the bytes received in each trace interval within the measurement stream.
+ * @public
+ */
+ this.b = [];
+};
+
+HTTPRequest.MPD_TYPE = 'MPD';
+HTTPRequest.XLINK_EXPANSION_TYPE = 'XLinkExpansion';
+HTTPRequest.INIT_SEGMENT_TYPE = 'InitializationSegment';
+HTTPRequest.INDEX_SEGMENT_TYPE = 'IndexSegment';
+HTTPRequest.MEDIA_SEGMENT_TYPE = 'MediaSegment';
+HTTPRequest.BITSTREAM_SWITCHING_SEGMENT_TYPE = 'BitstreamSwitchingSegment';
+HTTPRequest.OTHER_TYPE = 'other';
+
+exports.HTTPRequest = HTTPRequest;
+exports.HTTPRequestTrace = HTTPRequestTrace;
+
+},{}],180:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @classdesc This Object holds reference to the manifest update information.
+ */
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var ManifestUpdate =
+/**
+ * @class
+ */
+function ManifestUpdate() {
+ _classCallCheck(this, ManifestUpdate);
+
+ /**
+ * Media Type Video | Audio | FragmentedText
+ * @public
+ */
+ this.mediaType = null;
+ /**
+ * MPD Type static | dynamic
+ * @public
+ */
+ this.type = null;
+ /**
+ * When this manifest update was requested
+ * @public
+ */
+ this.requestTime = null;
+ /**
+ * When this manifest update was received
+ * @public
+ */
+ this.fetchTime = null;
+ /**
+ * Calculated Availability Start time of the stream.
+ * @public
+ */
+ this.availabilityStartTime = null;
+ /**
+ * the seek point (liveEdge for dynamic, Stream[0].startTime for static)
+ * @public
+ */
+ this.presentationStartTime = 0;
+ /**
+ * The calculated difference between the server and client wall clock time
+ * @public
+ */
+ this.clientTimeOffset = 0;
+ /**
+ * Actual element.currentTime
+ * @public
+ */
+ this.currentTime = null;
+ /**
+ * Actual element.ranges
+ * @public
+ */
+ this.buffered = null;
+ /**
+ * Static is fixed value of zero. dynamic should be ((Now-@availabilityStartTime) - elementCurrentTime)
+ * @public
+ */
+ this.latency = 0;
+ /**
+ * Array holding list of StreamInfo VO Objects
+ * @public
+ */
+ this.streamInfo = [];
+ /**
+ * Array holding list of TrackInfo VO Objects
+ * @public
+ */
+ this.trackInfo = [];
+}
+
+/**
+ * @classdesc This Object holds reference to the current period's stream information when the manifest was updated.
+ */
+;
+
+var ManifestUpdateStreamInfo =
+/**
+ * @class
+ */
+function ManifestUpdateStreamInfo() {
+ _classCallCheck(this, ManifestUpdateStreamInfo);
+
+ /**
+ * Stream@id
+ * @public
+ */
+ this.id = null;
+ /**
+ * Period Index
+ * @public
+ */
+ this.index = null;
+ /**
+ * Stream@start
+ * @public
+ */
+ this.start = null;
+ /**
+ * Stream@duration
+ * @public
+ */
+ this.duration = null;
+}
+
+/**
+ * @classdesc This Object holds reference to the current representation's info when the manifest was updated.
+ */
+;
+
+var ManifestUpdateTrackInfo =
+/**
+ * @class
+ */
+function ManifestUpdateTrackInfo() {
+ _classCallCheck(this, ManifestUpdateTrackInfo);
+
+ /**
+ * Track@id
+ * @public
+ */
+ this.id = null;
+ /**
+ * Representation Index
+ * @public
+ */
+ this.index = null;
+ /**
+ * Media Type Video | Audio | FragmentedText
+ * @public
+ */
+ this.mediaType = null;
+ /**
+ * Which reprenset
+ * @public
+ */
+ this.streamIndex = null;
+ /**
+ * Holds reference to @presentationTimeOffset
+ * @public
+ */
+ this.presentationTimeOffset = null;
+ /**
+ * Holds reference to @startNumber
+ * @public
+ */
+ this.startNumber = null;
+ /**
+ * list|template|timeline
+ * @public
+ */
+ this.fragmentInfoType = null;
+};
+
+exports.ManifestUpdate = ManifestUpdate;
+exports.ManifestUpdateStreamInfo = ManifestUpdateStreamInfo;
+exports.ManifestUpdateTrackInfo = ManifestUpdateTrackInfo;
+
+},{}],181:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @classdesc a PlayList from ISO23009-1 Annex D, this Object holds reference to the playback session information
+ */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+
+var PlayList =
+/**
+ * @class
+ */
+function PlayList() {
+ _classCallCheck(this, PlayList);
+
+ /**
+ * Timestamp of the user action that starts the playback stream...
+ * @public
+ */
+ this.start = null;
+ /**
+ * Presentation time at which playout was requested by the user...
+ * @public
+ */
+ this.mstart = null;
+ /**
+ * Type of user action which triggered playout
+ * - New playout request (e.g. initial playout or seeking)
+ * - Resume from pause
+ * - Other user request (e.g. user-requested quality change)
+ * - Start of a metrics collection stream (hence earlier entries in the play list not collected)
+ * @public
+ */
+ this.starttype = null;
+
+ /**
+ * List of streams of continuous rendering of decoded samples.
+ * @public
+ */
+ this.trace = [];
+}
+
+/* Public Static Constants */
+;
+
+PlayList.INITIAL_PLAYOUT_START_REASON = 'initial_playout';
+PlayList.SEEK_START_REASON = 'seek';
+PlayList.RESUME_FROM_PAUSE_START_REASON = 'resume';
+PlayList.METRICS_COLLECTION_START_REASON = 'metrics_collection_start';
+
+/**
+ * @classdesc a PlayList.Trace from ISO23009-1 Annex D
+ */
+
+var PlayListTrace =
+/**
+ * @class
+ */
+function PlayListTrace() {
+ _classCallCheck(this, PlayListTrace);
+
+ /**
+ * The value of the Representation@id of the Representation from which the samples were taken.
+ * @type {string}
+ * @public
+ */
+ this.representationid = null;
+ /**
+ * If not present, this metrics concerns the Representation as a whole.
+ * If present, subreplevel indicates the greatest value of any
+ * Subrepresentation@level being rendered.
+ * @type {number}
+ * @public
+ */
+ this.subreplevel = null;
+ /**
+ * The time at which the first sample was rendered
+ * @type {number}
+ * @public
+ */
+ this.start = null;
+ /**
+ * The presentation time of the first sample rendered.
+ * @type {number}
+ * @public
+ */
+ this.mstart = null;
+ /**
+ * The duration of the continuously presented samples (which is the same in real time and media time). "Continuously presented" means that the media clock continued to advance at the playout speed throughout the interval. NOTE: the spec does not call out the units, but all other durations etc are in ms, and we use ms too.
+ * @type {number}
+ * @public
+ */
+ this.duration = null;
+ /**
+ * The playback speed relative to normal playback speed (i.e.normal forward playback speed is 1.0).
+ * @type {number}
+ * @public
+ */
+ this.playbackspeed = null;
+ /**
+ * The reason why continuous presentation of this Representation was stopped.
+ * representation switch
+ * rebuffering
+ * user request
+ * end of Period
+ * end of Stream
+ * end of content
+ * end of a metrics collection period
+ *
+ * @type {string}
+ * @public
+ */
+ this.stopreason = null;
+};
+
+PlayListTrace.REPRESENTATION_SWITCH_STOP_REASON = 'representation_switch';
+PlayListTrace.REBUFFERING_REASON = 'rebuffering';
+PlayListTrace.USER_REQUEST_STOP_REASON = 'user_request';
+PlayListTrace.END_OF_PERIOD_STOP_REASON = 'end_of_period';
+PlayListTrace.END_OF_CONTENT_STOP_REASON = 'end_of_content';
+PlayListTrace.METRICS_COLLECTION_STOP_REASON = 'metrics_collection_end';
+PlayListTrace.FAILURE_STOP_REASON = 'failure';
+
+exports.PlayList = PlayList;
+exports.PlayListTrace = PlayListTrace;
+
+},{}],182:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @class
+ */
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var RepresentationSwitch =
+/**
+ * @description This Object holds reference to the info at quality switch between two representations.
+ */
+function RepresentationSwitch() {
+ _classCallCheck(this, RepresentationSwitch);
+
+ /**
+ * Time of the switch event.
+ * @public
+ */
+ this.t = null;
+ /**
+ * The media presentation time of the earliest access unit
+ * (out of all media content components) played out from
+ * the Representation.
+ *
+ * @public
+ */
+ this.mt = null;
+ /**
+ * Value of Representation@id identifying the switch-to Representation.
+ * @public
+ */
+ this.to = null;
+ /**
+ * If not present, this metrics concerns the Representation as a whole.
+ * If present, lto indicates the value of SubRepresentation@level within
+ * Representation identifying the switch-to level of the Representation.
+ *
+ * @public
+ */
+ this.lto = null;
+};
+
+exports["default"] = RepresentationSwitch;
+module.exports = exports["default"];
+
+},{}],183:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @class
+ */
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var RequestsQueue =
+/**
+ * @description This Object holds reference to Fragment Model's request queues
+ */
+function RequestsQueue() {
+ _classCallCheck(this, RequestsQueue);
+
+ /**
+ * Array of all of the requests that have begun to load
+ * This request may not make it into the executed queue if it is abandon due to ABR rules for example.
+ * @public
+ */
+ this.loadingRequests = [];
+ /**
+ * Array of the The requests that have completed
+ * @public
+ */
+ this.executedRequests = [];
+};
+
+exports["default"] = RequestsQueue;
+module.exports = exports["default"];
+
+},{}],184:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @class
+ */
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var SchedulingInfo =
+/**
+ * @description This Object holds reference to the index handling of the current fragment being loaded or executed.
+ */
+function SchedulingInfo() {
+ _classCallCheck(this, SchedulingInfo);
+
+ /**
+ * Type of stream Audio | Video | FragmentedText
+ * @public
+ */
+ this.mediaType = null;
+ /**
+ * Time of the scheduling event.
+ * @public
+ */
+ this.t = null;
+
+ /**
+ * Type of fragment (initialization | media)
+ * @public
+ */
+ this.type = null;
+ /**
+ * Presentation start time of fragment
+ * @public
+ */
+ this.startTime = null;
+ /**
+ * Availability start time of fragment
+ * @public
+ */
+ this.availabilityStartTime = null;
+ /**
+ * Duration of fragment
+ * @public
+ */
+ this.duration = null;
+ /**
+ * Bit Rate Quality of fragment
+ * @public
+ */
+ this.quality = null;
+ /**
+ * Range of fragment
+ * @public
+ */
+ this.range = null;
+
+ /**
+ * Current state of fragment
+ * @public
+ */
+ this.state = null;
+};
+
+exports["default"] = SchedulingInfo;
+module.exports = exports["default"];
+
+},{}],185:[function(_dereq_,module,exports){
+/**
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2013, Dash Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @class
+ */
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var TCPConnection =
+/**
+ * @description This Object holds reference to the current tcp connection
+ */
+function TCPConnection() {
+ _classCallCheck(this, TCPConnection);
+
+ /**
+ * Identifier of the TCP connection on which the HTTP request was sent.
+ * @public
+ */
+ this.tcpid = null;
+ /**
+ * IP Address of the interface over which the client is receiving the TCP data.
+ * @public
+ */
+ this.dest = null;
+ /**
+ * Real-Time | The time at which the connection was opened (sending time of the initial SYN or connect socket operation).
+ * @public
+ */
+ this.topen = null;
+ /**
+ * Real-Time | The time at which the connection was closed (sending or reception time of FIN or RST or close socket operation).
+ * @public
+ */
+ this.tclose = null;
+ /**
+ * Connect time in ms (time from sending the initial SYN to receiving the ACK or completion of the connect socket operation).
+ * @public
+ */
+ this.tconnect = null;
+};
+
+exports["default"] = TCPConnection;
+module.exports = exports["default"];
+
+},{}]},{},[5])
+//# sourceMappingURL=dash.all.debug.js.map