mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
fix merge conflicts
This commit is contained in:
parent
bcfee41a57
commit
d33230d361
97 changed files with 1205 additions and 811 deletions
|
@ -16,12 +16,12 @@
|
|||
},
|
||||
"devDependencies": {},
|
||||
"ignore": [],
|
||||
"version": "1.0.25",
|
||||
"_release": "1.0.25",
|
||||
"version": "1.0.26",
|
||||
"_release": "1.0.26",
|
||||
"_resolution": {
|
||||
"type": "version",
|
||||
"tag": "1.0.25",
|
||||
"commit": "f2e83b0e30527b5182ceb043d170ad7188368245"
|
||||
"tag": "1.0.26",
|
||||
"commit": "6fe8727397b13e87e3afaeee600f600269e0ee18"
|
||||
},
|
||||
"_source": "git://github.com/MediaBrowser/Emby.ApiClient.Javascript.git",
|
||||
"_target": "~1.0.3",
|
||||
|
|
|
@ -420,6 +420,7 @@
|
|||
saveUserInfoIntoCredentials(server, result.User);
|
||||
credentialProvider.credentials(credentials);
|
||||
|
||||
apiClient.serverInfo(server);
|
||||
afterConnected(apiClient, options);
|
||||
|
||||
onLocalUserSignIn(server, server.LastConnectionMode, result.User);
|
||||
|
@ -748,44 +749,38 @@
|
|||
|
||||
console.log('Begin getConnectServers');
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
if (!credentials.ConnectAccessToken || !credentials.ConnectUserId) {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
|
||||
if (!credentials.ConnectAccessToken || !credentials.ConnectUserId) {
|
||||
resolve([]);
|
||||
return;
|
||||
var url = "https://connect.emby.media/service/servers?userId=" + credentials.ConnectUserId;
|
||||
|
||||
return ajax({
|
||||
type: "GET",
|
||||
url: url,
|
||||
dataType: "json",
|
||||
headers: {
|
||||
"X-Application": appName + "/" + appVersion,
|
||||
"X-Connect-UserToken": credentials.ConnectAccessToken
|
||||
}
|
||||
|
||||
var url = "https://connect.emby.media/service/servers?userId=" + credentials.ConnectUserId;
|
||||
|
||||
ajax({
|
||||
type: "GET",
|
||||
url: url,
|
||||
dataType: "json",
|
||||
headers: {
|
||||
"X-Application": appName + "/" + appVersion,
|
||||
"X-Connect-UserToken": credentials.ConnectAccessToken
|
||||
}
|
||||
|
||||
}).then(function (servers) {
|
||||
|
||||
servers = servers.map(function (i) {
|
||||
return {
|
||||
ExchangeToken: i.AccessKey,
|
||||
ConnectServerId: i.Id,
|
||||
Id: i.SystemId,
|
||||
Name: i.Name,
|
||||
RemoteAddress: i.Url,
|
||||
LocalAddress: i.LocalAddress,
|
||||
UserLinkType: (i.UserType || '').toLowerCase() == "guest" ? "Guest" : "LinkedUser"
|
||||
};
|
||||
});
|
||||
|
||||
resolve(servers);
|
||||
|
||||
}, function () {
|
||||
resolve([]);
|
||||
}).then(function (servers) {
|
||||
|
||||
return servers.map(function (i) {
|
||||
return {
|
||||
ExchangeToken: i.AccessKey,
|
||||
ConnectServerId: i.Id,
|
||||
Id: i.SystemId,
|
||||
Name: i.Name,
|
||||
RemoteAddress: i.Url,
|
||||
LocalAddress: i.LocalAddress,
|
||||
UserLinkType: (i.UserType || '').toLowerCase() == "guest" ? "Guest" : "LinkedUser"
|
||||
};
|
||||
});
|
||||
|
||||
}, function () {
|
||||
return [];
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -858,9 +853,8 @@
|
|||
|
||||
var info = {
|
||||
Id: foundServer.Id,
|
||||
LocalAddress: foundServer.Address,
|
||||
LocalAddress: convertEndpointAddressToManualAddress(foundServer) || foundServer.Address,
|
||||
Name: foundServer.Name,
|
||||
ManualAddress: convertEndpointAddressToManualAddress(foundServer),
|
||||
DateLastLocalConnection: new Date().getTime()
|
||||
};
|
||||
|
||||
|
@ -1467,13 +1461,10 @@
|
|||
self.getRegistrationInfo = function (feature, apiClient) {
|
||||
|
||||
if (isConnectUserSupporter()) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
resolve({
|
||||
Name: feature,
|
||||
IsRegistered: true,
|
||||
IsTrial: false
|
||||
});
|
||||
return Promise.resolve({
|
||||
Name: feature,
|
||||
IsRegistered: true,
|
||||
IsTrial: false
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -15,12 +15,12 @@
|
|||
},
|
||||
"devDependencies": {},
|
||||
"ignore": [],
|
||||
"version": "1.0.18",
|
||||
"_release": "1.0.18",
|
||||
"version": "1.0.21",
|
||||
"_release": "1.0.21",
|
||||
"_resolution": {
|
||||
"type": "version",
|
||||
"tag": "1.0.18",
|
||||
"commit": "a251227c4635bcac732075e494b2d8a4e7956d26"
|
||||
"tag": "1.0.21",
|
||||
"commit": "dd73237b9d554d45a664e820042804c6d129d280"
|
||||
},
|
||||
"_source": "git://github.com/MediaBrowser/emby-webcomponents.git",
|
||||
"_target": "~1.0.0",
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
define(['browser'], function (browser) {
|
||||
define(['browser'], function (browser) {
|
||||
|
||||
function canPlayH264() {
|
||||
var v = document.createElement('video');
|
||||
|
@ -67,7 +67,7 @@
|
|||
function canPlayHls(src) {
|
||||
|
||||
if (_canPlayHls == null) {
|
||||
_canPlayHls = window.MediaSource != null || canPlayNativeHls();
|
||||
_canPlayHls = canPlayNativeHls() || canPlayHlsWithMSE();
|
||||
}
|
||||
return _canPlayHls;
|
||||
}
|
||||
|
@ -83,6 +83,15 @@
|
|||
return false;
|
||||
}
|
||||
|
||||
function canPlayHlsWithMSE() {
|
||||
if (window.MediaSource != null) {
|
||||
// text tracks don’t work with this in firefox
|
||||
return !browser.firefox;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return function () {
|
||||
|
||||
var bitrateSetting = 100000000;
|
||||
|
|
25
dashboard-ui/bower_components/emby-webcomponents/images/basicimageloader.js
vendored
Normal file
25
dashboard-ui/bower_components/emby-webcomponents/images/basicimageloader.js
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
define([], function () {
|
||||
|
||||
function loadImage(elem, url) {
|
||||
|
||||
if (elem.tagName !== "IMG") {
|
||||
|
||||
var tmp = new Image();
|
||||
|
||||
tmp.onload = function () {
|
||||
elem.style.backgroundImage = "url('" + url + "')";
|
||||
};
|
||||
tmp.src = url;
|
||||
|
||||
} else {
|
||||
elem.setAttribute("src", url);
|
||||
}
|
||||
|
||||
return Promise.resolve(elem);
|
||||
}
|
||||
|
||||
return {
|
||||
loadImage: loadImage
|
||||
};
|
||||
|
||||
});
|
175
dashboard-ui/bower_components/emby-webcomponents/images/imagehelper.js
vendored
Normal file
175
dashboard-ui/bower_components/emby-webcomponents/images/imagehelper.js
vendored
Normal file
|
@ -0,0 +1,175 @@
|
|||
define(['visibleinviewport', 'imageloader'], function (visibleinviewport, imageLoader) {
|
||||
|
||||
var thresholdX = screen.availWidth;
|
||||
var thresholdY = screen.availHeight;
|
||||
|
||||
var wheelEvent = (document.implementation.hasFeature('Event.wheel', '3.0') ? 'wheel' : 'mousewheel');
|
||||
|
||||
function isVisible(elem) {
|
||||
return visibleinviewport(elem, true, thresholdX, thresholdY);
|
||||
}
|
||||
|
||||
function fillImage(elem) {
|
||||
var source = elem.getAttribute('data-src');
|
||||
if (source) {
|
||||
imageLoader.loadImage(elem, source);
|
||||
elem.setAttribute("data-src", '');
|
||||
}
|
||||
}
|
||||
|
||||
function cancelAll(tokens) {
|
||||
for (var i = 0, length = tokens.length; i < length; i++) {
|
||||
|
||||
tokens[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
function unveilElements(images) {
|
||||
|
||||
if (!images.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var cancellationTokens = [];
|
||||
function unveilInternal(tokenIndex) {
|
||||
|
||||
var remaining = [];
|
||||
var anyFound = false;
|
||||
var out = false;
|
||||
|
||||
// TODO: This out construct assumes left to right, top to bottom
|
||||
|
||||
for (var i = 0, length = images.length; i < length; i++) {
|
||||
|
||||
if (cancellationTokens[tokenIndex]) {
|
||||
return;
|
||||
}
|
||||
var img = images[i];
|
||||
if (!out && isVisible(img)) {
|
||||
anyFound = true;
|
||||
fillImage(img);
|
||||
} else {
|
||||
|
||||
if (anyFound) {
|
||||
out = true;
|
||||
}
|
||||
remaining.push(img);
|
||||
}
|
||||
}
|
||||
|
||||
images = remaining;
|
||||
|
||||
if (!images.length) {
|
||||
document.removeEventListener('focus', unveil, true);
|
||||
document.removeEventListener('scroll', unveil, true);
|
||||
document.removeEventListener(wheelEvent, unveil, true);
|
||||
window.removeEventListener('resize', unveil, true);
|
||||
}
|
||||
}
|
||||
|
||||
function unveil() {
|
||||
|
||||
cancelAll(cancellationTokens);
|
||||
|
||||
var index = cancellationTokens.length;
|
||||
cancellationTokens.length++;
|
||||
|
||||
setTimeout(function () {
|
||||
unveilInternal(index);
|
||||
}, 1);
|
||||
}
|
||||
|
||||
document.addEventListener('scroll', unveil, true);
|
||||
document.addEventListener('focus', unveil, true);
|
||||
document.addEventListener(wheelEvent, unveil, true);
|
||||
window.addEventListener('resize', unveil, true);
|
||||
|
||||
unveil();
|
||||
}
|
||||
|
||||
function fillImages(elems) {
|
||||
|
||||
for (var i = 0, length = elems.length; i < length; i++) {
|
||||
var elem = elems[0];
|
||||
var source = elem.getAttribute('data-src');
|
||||
if (source) {
|
||||
ImageStore.setImageInto(elem, source);
|
||||
elem.setAttribute("data-src", '');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function lazyChildren(elem) {
|
||||
|
||||
unveilElements(elem.getElementsByClassName('lazy'));
|
||||
}
|
||||
|
||||
function lazyImage(elem, url) {
|
||||
|
||||
elem.setAttribute('data-src', url);
|
||||
fillImages([elem]);
|
||||
}
|
||||
|
||||
function getPrimaryImageAspectRatio(items) {
|
||||
|
||||
var values = [];
|
||||
|
||||
for (var i = 0, length = items.length; i < length; i++) {
|
||||
|
||||
var ratio = items[i].PrimaryImageAspectRatio || 0;
|
||||
|
||||
if (!ratio) {
|
||||
continue;
|
||||
}
|
||||
|
||||
values[values.length] = ratio;
|
||||
}
|
||||
|
||||
if (!values.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Use the median
|
||||
values.sort(function (a, b) { return a - b; });
|
||||
|
||||
var half = Math.floor(values.length / 2);
|
||||
|
||||
var result;
|
||||
|
||||
if (values.length % 2)
|
||||
result = values[half];
|
||||
else
|
||||
result = (values[half - 1] + values[half]) / 2.0;
|
||||
|
||||
// If really close to 2:3 (poster image), just return 2:3
|
||||
var aspect2x3 = 2 / 3;
|
||||
if (Math.abs(aspect2x3 - result) <= .15) {
|
||||
return aspect2x3;
|
||||
}
|
||||
|
||||
// If really close to 16:9 (episode image), just return 16:9
|
||||
var aspect16x9 = 16 / 9;
|
||||
if (Math.abs(aspect16x9 - result) <= .2) {
|
||||
return aspect16x9;
|
||||
}
|
||||
|
||||
// If really close to 1 (square image), just return 1
|
||||
if (Math.abs(1 - result) <= .15) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// If really close to 4:3 (poster image), just return 2:3
|
||||
var aspect4x3 = 4 / 3;
|
||||
if (Math.abs(aspect4x3 - result) <= .15) {
|
||||
return aspect4x3;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return {
|
||||
lazyChildren: lazyChildren,
|
||||
getPrimaryImageAspectRatio: getPrimaryImageAspectRatio
|
||||
};
|
||||
|
||||
});
|
164
dashboard-ui/bower_components/emby-webcomponents/images/persistentimageloader.js
vendored
Normal file
164
dashboard-ui/bower_components/emby-webcomponents/images/persistentimageloader.js
vendored
Normal file
|
@ -0,0 +1,164 @@
|
|||
define(['cryptojs-md5'], function () {
|
||||
|
||||
function setImageIntoElement(elem, url) {
|
||||
|
||||
if (elem.tagName !== "IMG") {
|
||||
|
||||
elem.style.backgroundImage = "url('" + url + "')";
|
||||
|
||||
} else {
|
||||
elem.setAttribute("src", url);
|
||||
}
|
||||
}
|
||||
|
||||
// Request Quota (only for File System API)
|
||||
var requestedBytes = 1024 * 1024 * 1500;
|
||||
var imageCacheDirectoryEntry;
|
||||
var imageCacheFolder = 'images';
|
||||
|
||||
function createDir(rootDirEntry, folders, callback, errorCallback) {
|
||||
// Throw out './' or '/' and move on to prevent something like '/foo/.//bar'.
|
||||
if (folders[0] == '.' || folders[0] == '') {
|
||||
folders = folders.slice(1);
|
||||
}
|
||||
rootDirEntry.getDirectory(folders[0], { create: true }, function (dirEntry) {
|
||||
// Recursively add the new subfolder (if we still have another to create).
|
||||
if (folders.length > 1) {
|
||||
createDir(dirEntry, folders.slice(1), callback, errorCallback);
|
||||
} else {
|
||||
callback(dirEntry);
|
||||
}
|
||||
}, errorCallback);
|
||||
}
|
||||
|
||||
navigator.webkitPersistentStorage.requestQuota(
|
||||
requestedBytes, function (grantedBytes) {
|
||||
|
||||
var requestMethod = window.webkitRequestFileSystem || window.requestFileSystem;
|
||||
|
||||
requestMethod(PERSISTENT, grantedBytes, function (fs) {
|
||||
|
||||
fileSystem = fs;
|
||||
|
||||
createDir(fileSystem.root, imageCacheFolder.split('/'), function (dirEntry) {
|
||||
|
||||
imageCacheDirectoryEntry = dirEntry;
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
function getCacheKey(url) {
|
||||
|
||||
// Try to strip off the domain to share the cache between local and remote connections
|
||||
var index = url.indexOf('://');
|
||||
|
||||
if (index != -1) {
|
||||
url = url.substring(index + 3);
|
||||
|
||||
index = url.indexOf('/');
|
||||
|
||||
if (index != -1) {
|
||||
url = url.substring(index + 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return CryptoJS.MD5(url).toString();
|
||||
}
|
||||
|
||||
function downloadToFile(url, dir, filename, callback, errorCallback) {
|
||||
|
||||
console.log('Downloading ' + url);
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', url, true);
|
||||
xhr.responseType = "arraybuffer";
|
||||
|
||||
xhr.onload = function (e) {
|
||||
if (this.status == 200) {
|
||||
writeData(dir, filename, this.getResponseHeader('Content-Type'), this.response, callback, errorCallback);
|
||||
} else {
|
||||
errorCallback();
|
||||
}
|
||||
}
|
||||
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
function writeData(dir, filename, fileType, data, callback, errorCallback) {
|
||||
|
||||
dir.getFile(filename, { create: true }, function (fileEntry) {
|
||||
|
||||
// Create a FileWriter object for our FileEntry (log.txt).
|
||||
fileEntry.createWriter(function (fileWriter) {
|
||||
|
||||
fileWriter.onwriteend = function (e) {
|
||||
callback(fileEntry);
|
||||
};
|
||||
|
||||
fileWriter.onerror = errorCallback;
|
||||
|
||||
// Create a new Blob and write it to log.txt.
|
||||
var blob = new Blob([data], { type: fileType });
|
||||
|
||||
fileWriter.write(blob);
|
||||
|
||||
}, errorCallback);
|
||||
|
||||
}, errorCallback);
|
||||
}
|
||||
|
||||
function getImageUrl(originalUrl) {
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
if (originalUrl.indexOf('tag=') != -1) {
|
||||
originalUrl += "&accept=webp";
|
||||
}
|
||||
|
||||
var key = getCacheKey(originalUrl);
|
||||
|
||||
var fileEntryCallback = function (fileEntry) {
|
||||
resolve(fileEntry.toURL());
|
||||
};
|
||||
|
||||
var errorCallback = function (e) {
|
||||
console.log('Imagestore error: ' + e.name);
|
||||
reject();
|
||||
};
|
||||
|
||||
if (!fileSystem || !imageCacheDirectoryEntry) {
|
||||
errorCallback('');
|
||||
return;
|
||||
}
|
||||
|
||||
var path = '/' + imageCacheFolder + "/" + key;
|
||||
|
||||
fileSystem.root.getFile(path, { create: false }, fileEntryCallback, function () {
|
||||
|
||||
downloadToFile(originalUrl, imageCacheDirectoryEntry, key, fileEntryCallback, errorCallback);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
var fileSystem;
|
||||
|
||||
return {
|
||||
loadImage: function (elem, url) {
|
||||
|
||||
return getImageUrl(url).then(function (localUrl) {
|
||||
|
||||
setImageIntoElement(elem, localUrl);
|
||||
return elem;
|
||||
|
||||
}, function () {
|
||||
setImageIntoElement(elem, url);
|
||||
return elem;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
});
|
13
dashboard-ui/bower_components/hls.js/.bower.json
vendored
13
dashboard-ui/bower_components/hls.js/.bower.json
vendored
|
@ -1,13 +1,13 @@
|
|||
{
|
||||
"name": "hls.js",
|
||||
"version": "0.4.5",
|
||||
"version": "0.4.6",
|
||||
"description": "Media Source Extension - HLS library, by/for Dailymotion",
|
||||
"homepage": "https://github.com/dailymotion/hls.js",
|
||||
"authors": [
|
||||
"Guillaume du Pontavice <guillaume.dupontavice@dailymotion.com>"
|
||||
],
|
||||
"main": "dist/hls.js",
|
||||
"private": true,
|
||||
"private": false,
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
|
@ -15,14 +15,13 @@
|
|||
"test",
|
||||
"tests"
|
||||
],
|
||||
"_release": "0.4.5",
|
||||
"_release": "0.4.6",
|
||||
"_resolution": {
|
||||
"type": "version",
|
||||
"tag": "v0.4.5",
|
||||
"commit": "908ac4a44a182bdbede9c1830828983c18532ca0"
|
||||
"tag": "v0.4.6",
|
||||
"commit": "eb4bfb0ebadda9797d8020e7b3a2d2c699444cab"
|
||||
},
|
||||
"_source": "git://github.com/dailymotion/hls.js.git",
|
||||
"_target": "~0.4.5",
|
||||
"_originalSource": "dailymotion/hls.js",
|
||||
"_direct": true
|
||||
"_originalSource": "dailymotion/hls.js"
|
||||
}
|
18
dashboard-ui/bower_components/hls.js/API.md
vendored
18
dashboard-ui/bower_components/hls.js/API.md
vendored
|
@ -186,6 +186,8 @@ configuration parameters could be provided to hls.js upon instantiation of Hls O
|
|||
maxBufferLength : 30,
|
||||
maxMaxBufferLength : 600,
|
||||
maxBufferSize : 60*1000*1000,
|
||||
maxBufferHole : 0.3,
|
||||
maxSeekHole : 2,
|
||||
liveSyncDurationCount : 3,
|
||||
liveMaxLatencyDurationCount: 10,
|
||||
enableWorker : true,
|
||||
|
@ -240,6 +242,20 @@ this is the guaranteed buffer length hls.js will try to reach, regardless of max
|
|||
|
||||
'minimum' maximum buffer size in bytes. if buffer size upfront is bigger than this value, no fragment will be loaded.
|
||||
|
||||
#### ```maxBufferHole```
|
||||
(default 0.3s)
|
||||
|
||||
'maximum' inter-fragment buffer hole tolerance that hls.js can cope with.
|
||||
When switching between quality level, fragments might not be perfectly aligned.
|
||||
This could result in small overlapping or hole in media buffer. This tolerance factor helps cope with this.
|
||||
|
||||
#### ```maxSeekHole```
|
||||
(default 2s)
|
||||
|
||||
in case playback is stalled, and a buffered range is available upfront, less than maxSeekHole seconds from current media position,
|
||||
hls.js will jump over this buffer hole to reach the beginning of this following buffered range.
|
||||
```maxSeekHole``` allows to configure this jumpable threshold.
|
||||
|
||||
#### ```maxMaxBufferLength```
|
||||
(default 600s)
|
||||
|
||||
|
@ -499,7 +515,7 @@ full list of Events available below :
|
|||
- `Hls.Events.LEVEL_PTS_UPDATED` - fired when a level's PTS information has been updated after parsing a fragment
|
||||
- data: { details : levelDetails object, level : id of updated level, drift: PTS drift observed when parsing last fragment }
|
||||
- `Hls.Events.LEVEL_SWITCH` - fired when a level switch is requested
|
||||
- data: { levelId : id of new level }
|
||||
- data: { level : id of new level, it is the index of the array `Hls.levels` }
|
||||
- `Hls.Events.KEY_LOADING` - fired when a decryption key loading starts
|
||||
- data: { frag : fragment object}
|
||||
- `Hls.Events.KEY_LOADED` - fired when a decryption key loading is completed
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
{
|
||||
"name": "hls.js",
|
||||
"version": "0.4.5",
|
||||
"version": "0.4.6",
|
||||
"description": "Media Source Extension - HLS library, by/for Dailymotion",
|
||||
"homepage": "https://github.com/dailymotion/hls.js",
|
||||
"authors": [
|
||||
"Guillaume du Pontavice <guillaume.dupontavice@dailymotion.com>"
|
||||
],
|
||||
"main": "dist/hls.js",
|
||||
"private": true,
|
||||
"private": false,
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
|
|
|
@ -718,14 +718,6 @@ function timeRangesToString(r) {
|
|||
events.buffer.push(event);
|
||||
refreshCanvas();
|
||||
|
||||
var decodedFrames, droppedFrames;
|
||||
if(navigator.userAgent.toLowerCase().indexOf('firefox') !== -1) {
|
||||
decodedFrames = v.mozDecodedFrames;
|
||||
droppedFrames = v.mozParsedFrames-v.mozPresentedFrames;
|
||||
} else {
|
||||
decodedFrames = v.webkitDecodedFrameCount;
|
||||
droppedFrames = v.webkitDroppedFrameCount;
|
||||
}
|
||||
var log = "Duration:"
|
||||
+ v.duration + "<br>"
|
||||
+ "Buffered:"
|
||||
|
@ -733,11 +725,16 @@ function timeRangesToString(r) {
|
|||
+ "Seekable:"
|
||||
+ timeRangesToString(v.seekable) + "<br>"
|
||||
+ "Played:"
|
||||
+ timeRangesToString(v.played) + "<br>"
|
||||
+ "Decoded Frames:"
|
||||
+ decodedFrames + "<br>"
|
||||
+ "Dropped Frames:"
|
||||
+ droppedFrames + "<br>";
|
||||
+ timeRangesToString(v.played) + "<br>";
|
||||
|
||||
|
||||
var videoPlaybackQuality = v.getVideoPlaybackQuality;
|
||||
if(videoPlaybackQuality && typeof(videoPlaybackQuality) === typeof(Function)) {
|
||||
log+="Dropped Frames:"+ v.getVideoPlaybackQuality().droppedVideoFrames + "<br>";
|
||||
log+="Corrupted Frames:"+ v.getVideoPlaybackQuality().corruptedVideoFrames + "<br>";
|
||||
} else if(v.webkitDroppedFrameCount) {
|
||||
log+="Dropped Frames:"+ v.webkitDroppedFrameCount + "<br>";
|
||||
}
|
||||
$("#buffered_log").html(log);
|
||||
$("#HlsStats").text(JSON.stringify(sortObject(stats),null,"\t"));
|
||||
ctx.fillStyle = "blue";
|
||||
|
|
398
dashboard-ui/bower_components/hls.js/dist/hls.js
vendored
398
dashboard-ui/bower_components/hls.js/dist/hls.js
vendored
|
@ -371,34 +371,42 @@ Object.defineProperty(exports, '__esModule', {
|
|||
|
||||
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; }; })();
|
||||
|
||||
var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _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; 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 _events = require('../events');
|
||||
|
||||
var _events2 = _interopRequireDefault(_events);
|
||||
|
||||
var AbrController = (function () {
|
||||
var _eventHandler = require('../event-handler');
|
||||
|
||||
var _eventHandler2 = _interopRequireDefault(_eventHandler);
|
||||
|
||||
var AbrController = (function (_EventHandler) {
|
||||
_inherits(AbrController, _EventHandler);
|
||||
|
||||
function AbrController(hls) {
|
||||
_classCallCheck(this, AbrController);
|
||||
|
||||
this.hls = hls;
|
||||
_get(Object.getPrototypeOf(AbrController.prototype), 'constructor', this).call(this, hls, _events2['default'].FRAG_LOAD_PROGRESS);
|
||||
this.lastfetchlevel = 0;
|
||||
this._autoLevelCapping = -1;
|
||||
this._nextAutoLevel = -1;
|
||||
this.onflp = this.onFragmentLoadProgress.bind(this);
|
||||
hls.on(_events2['default'].FRAG_LOAD_PROGRESS, this.onflp);
|
||||
}
|
||||
|
||||
_createClass(AbrController, [{
|
||||
key: 'destroy',
|
||||
value: function destroy() {
|
||||
this.hls.off(_events2['default'].FRAG_LOAD_PROGRESS, this.onflp);
|
||||
_eventHandler2['default'].prototype.destroy.call(this);
|
||||
}
|
||||
}, {
|
||||
key: 'onFragmentLoadProgress',
|
||||
value: function onFragmentLoadProgress(event, data) {
|
||||
key: 'onFragLoadProgress',
|
||||
value: function onFragLoadProgress(data) {
|
||||
var stats = data.stats;
|
||||
if (stats.aborted === undefined) {
|
||||
this.lastfetchduration = (performance.now() - stats.trequest) / 1000;
|
||||
|
@ -466,12 +474,12 @@ var AbrController = (function () {
|
|||
}]);
|
||||
|
||||
return AbrController;
|
||||
})();
|
||||
})(_eventHandler2['default']);
|
||||
|
||||
exports['default'] = AbrController;
|
||||
module.exports = exports['default'];
|
||||
|
||||
},{"../events":18}],4:[function(require,module,exports){
|
||||
},{"../event-handler":18,"../events":19}],4:[function(require,module,exports){
|
||||
/*
|
||||
* Level Controller
|
||||
*/
|
||||
|
@ -484,40 +492,40 @@ Object.defineProperty(exports, '__esModule', {
|
|||
|
||||
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; }; })();
|
||||
|
||||
var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _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; 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 _events = require('../events');
|
||||
|
||||
var _events2 = _interopRequireDefault(_events);
|
||||
|
||||
var _eventHandler = require('../event-handler');
|
||||
|
||||
var _eventHandler2 = _interopRequireDefault(_eventHandler);
|
||||
|
||||
var _utilsLogger = require('../utils/logger');
|
||||
|
||||
var _errors = require('../errors');
|
||||
|
||||
var LevelController = (function () {
|
||||
var LevelController = (function (_EventHandler) {
|
||||
_inherits(LevelController, _EventHandler);
|
||||
|
||||
function LevelController(hls) {
|
||||
_classCallCheck(this, LevelController);
|
||||
|
||||
this.hls = hls;
|
||||
this.onml = this.onManifestLoaded.bind(this);
|
||||
this.onll = this.onLevelLoaded.bind(this);
|
||||
this.onerr = this.onError.bind(this);
|
||||
_get(Object.getPrototypeOf(LevelController.prototype), 'constructor', this).call(this, hls, _events2['default'].MANIFEST_LOADED, _events2['default'].LEVEL_LOADED, _events2['default'].ERROR);
|
||||
this.ontick = this.tick.bind(this);
|
||||
hls.on(_events2['default'].MANIFEST_LOADED, this.onml);
|
||||
hls.on(_events2['default'].LEVEL_LOADED, this.onll);
|
||||
hls.on(_events2['default'].ERROR, this.onerr);
|
||||
this._manualLevel = this._autoLevelCapping = -1;
|
||||
}
|
||||
|
||||
_createClass(LevelController, [{
|
||||
key: 'destroy',
|
||||
value: function destroy() {
|
||||
var hls = this.hls;
|
||||
hls.off(_events2['default'].MANIFEST_LOADED, this.onml);
|
||||
hls.off(_events2['default'].LEVEL_LOADED, this.onll);
|
||||
hls.off(_events2['default'].ERROR, this.onerr);
|
||||
if (this.timer) {
|
||||
clearInterval(this.timer);
|
||||
}
|
||||
|
@ -525,7 +533,7 @@ var LevelController = (function () {
|
|||
}
|
||||
}, {
|
||||
key: 'onManifestLoaded',
|
||||
value: function onManifestLoaded(event, data) {
|
||||
value: function onManifestLoaded(data) {
|
||||
var levels0 = [],
|
||||
levels = [],
|
||||
bitrateStart,
|
||||
|
@ -626,7 +634,7 @@ var LevelController = (function () {
|
|||
}
|
||||
}, {
|
||||
key: 'onError',
|
||||
value: function onError(event, data) {
|
||||
value: function onError(data) {
|
||||
if (data.fatal) {
|
||||
return;
|
||||
}
|
||||
|
@ -688,7 +696,7 @@ var LevelController = (function () {
|
|||
}
|
||||
}, {
|
||||
key: 'onLevelLoaded',
|
||||
value: function onLevelLoaded(event, data) {
|
||||
value: function onLevelLoaded(data) {
|
||||
// check if current playlist is a live playlist
|
||||
if (data.details.live && !this.timer) {
|
||||
// if live playlist we will have to reload it periodically
|
||||
|
@ -769,12 +777,12 @@ var LevelController = (function () {
|
|||
}]);
|
||||
|
||||
return LevelController;
|
||||
})();
|
||||
})(_eventHandler2['default']);
|
||||
|
||||
exports['default'] = LevelController;
|
||||
module.exports = exports['default'];
|
||||
|
||||
},{"../errors":17,"../events":18,"../utils/logger":28}],5:[function(require,module,exports){
|
||||
},{"../errors":17,"../event-handler":18,"../events":19,"../utils/logger":29}],5:[function(require,module,exports){
|
||||
/*
|
||||
* MSE Media Controller
|
||||
*/
|
||||
|
@ -787,10 +795,14 @@ Object.defineProperty(exports, '__esModule', {
|
|||
|
||||
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; }; })();
|
||||
|
||||
var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _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; 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 _demuxDemuxer = require('../demux/demuxer');
|
||||
|
||||
var _demuxDemuxer2 = _interopRequireDefault(_demuxDemuxer);
|
||||
|
@ -799,6 +811,10 @@ var _events = require('../events');
|
|||
|
||||
var _events2 = _interopRequireDefault(_events);
|
||||
|
||||
var _eventHandler = require('../event-handler');
|
||||
|
||||
var _eventHandler2 = _interopRequireDefault(_eventHandler);
|
||||
|
||||
var _utilsLogger = require('../utils/logger');
|
||||
|
||||
var _utilsBinarySearch = require('../utils/binary-search');
|
||||
|
@ -825,42 +841,27 @@ var State = {
|
|||
BUFFER_FLUSHING: 8
|
||||
};
|
||||
|
||||
var MSEMediaController = (function () {
|
||||
var MSEMediaController = (function (_EventHandler) {
|
||||
_inherits(MSEMediaController, _EventHandler);
|
||||
|
||||
function MSEMediaController(hls) {
|
||||
_classCallCheck(this, MSEMediaController);
|
||||
|
||||
_get(Object.getPrototypeOf(MSEMediaController.prototype), 'constructor', this).call(this, hls, _events2['default'].MEDIA_ATTACHING, _events2['default'].MEDIA_DETACHING, _events2['default'].MANIFEST_PARSED, _events2['default'].LEVEL_LOADED, _events2['default'].KEY_LOADED, _events2['default'].FRAG_LOADED, _events2['default'].FRAG_PARSING_INIT_SEGMENT, _events2['default'].FRAG_PARSING_DATA, _events2['default'].FRAG_PARSED, _events2['default'].ERROR);
|
||||
this.config = hls.config;
|
||||
this.audioCodecSwap = false;
|
||||
this.hls = hls;
|
||||
this.ticks = 0;
|
||||
// Source Buffer listeners
|
||||
this.onsbue = this.onSBUpdateEnd.bind(this);
|
||||
this.onsbe = this.onSBUpdateError.bind(this);
|
||||
// internal listeners
|
||||
this.onmediaatt0 = this.onMediaAttaching.bind(this);
|
||||
this.onmediadet0 = this.onMediaDetaching.bind(this);
|
||||
this.onmp = this.onManifestParsed.bind(this);
|
||||
this.onll = this.onLevelLoaded.bind(this);
|
||||
this.onfl = this.onFragLoaded.bind(this);
|
||||
this.onkl = this.onKeyLoaded.bind(this);
|
||||
this.onis = this.onInitSegment.bind(this);
|
||||
this.onfpg = this.onFragParsing.bind(this);
|
||||
this.onfp = this.onFragParsed.bind(this);
|
||||
this.onerr = this.onError.bind(this);
|
||||
this.ontick = this.tick.bind(this);
|
||||
hls.on(_events2['default'].MEDIA_ATTACHING, this.onmediaatt0);
|
||||
hls.on(_events2['default'].MEDIA_DETACHING, this.onmediadet0);
|
||||
hls.on(_events2['default'].MANIFEST_PARSED, this.onmp);
|
||||
}
|
||||
|
||||
_createClass(MSEMediaController, [{
|
||||
key: 'destroy',
|
||||
value: function destroy() {
|
||||
this.stop();
|
||||
var hls = this.hls;
|
||||
hls.off(_events2['default'].MEDIA_ATTACHING, this.onmediaatt0);
|
||||
hls.off(_events2['default'].MEDIA_DETACHING, this.onmediadet0);
|
||||
hls.off(_events2['default'].MANIFEST_PARSED, this.onmp);
|
||||
_eventHandler2['default'].prototype.destroy.call(this);
|
||||
this.state = State.IDLE;
|
||||
}
|
||||
}, {
|
||||
|
@ -894,13 +895,6 @@ var MSEMediaController = (function () {
|
|||
this.timer = setInterval(this.ontick, 100);
|
||||
this.level = -1;
|
||||
this.fragLoadError = 0;
|
||||
hls.on(_events2['default'].FRAG_LOADED, this.onfl);
|
||||
hls.on(_events2['default'].FRAG_PARSING_INIT_SEGMENT, this.onis);
|
||||
hls.on(_events2['default'].FRAG_PARSING_DATA, this.onfpg);
|
||||
hls.on(_events2['default'].FRAG_PARSED, this.onfp);
|
||||
hls.on(_events2['default'].ERROR, this.onerr);
|
||||
hls.on(_events2['default'].LEVEL_LOADED, this.onll);
|
||||
hls.on(_events2['default'].KEY_LOADED, this.onkl);
|
||||
}
|
||||
}, {
|
||||
key: 'stop',
|
||||
|
@ -935,14 +929,6 @@ var MSEMediaController = (function () {
|
|||
this.demuxer.destroy();
|
||||
this.demuxer = null;
|
||||
}
|
||||
var hls = this.hls;
|
||||
hls.off(_events2['default'].FRAG_LOADED, this.onfl);
|
||||
hls.off(_events2['default'].FRAG_PARSED, this.onfp);
|
||||
hls.off(_events2['default'].FRAG_PARSING_DATA, this.onfpg);
|
||||
hls.off(_events2['default'].LEVEL_LOADED, this.onll);
|
||||
hls.off(_events2['default'].KEY_LOADED, this.onkl);
|
||||
hls.off(_events2['default'].FRAG_PARSING_INIT_SEGMENT, this.onis);
|
||||
hls.off(_events2['default'].ERROR, this.onerr);
|
||||
}
|
||||
}, {
|
||||
key: 'tick',
|
||||
|
@ -1001,7 +987,7 @@ var MSEMediaController = (function () {
|
|||
// we are not at playback start, get next load level from level Controller
|
||||
level = hls.nextLoadLevel;
|
||||
}
|
||||
var bufferInfo = this.bufferInfo(pos, 0.3),
|
||||
var bufferInfo = this.bufferInfo(pos, this.config.maxBufferHole),
|
||||
bufferLen = bufferInfo.len,
|
||||
bufferEnd = bufferInfo.end,
|
||||
fragPrevious = this.fragPrevious,
|
||||
|
@ -1020,7 +1006,9 @@ var MSEMediaController = (function () {
|
|||
this.level = level;
|
||||
levelDetails = this.levels[level].details;
|
||||
// if level info not retrieved yet, switch state and wait for level retrieval
|
||||
if (typeof levelDetails === 'undefined') {
|
||||
// if live playlist, ensure that new playlist has been refreshed to avoid loading/try to load
|
||||
// a useless and outdated fragment (that might even introduce load error if it is already out of the live playlist)
|
||||
if (typeof levelDetails === 'undefined' || levelDetails.live && this.levelLastLoaded !== level) {
|
||||
this.state = State.WAITING_LEVEL;
|
||||
break;
|
||||
}
|
||||
|
@ -1176,7 +1164,7 @@ var MSEMediaController = (function () {
|
|||
}
|
||||
pos = v.currentTime;
|
||||
var fragLoadedDelay = (frag.expectedLen - frag.loaded) / loadRate;
|
||||
var bufferStarvationDelay = this.bufferInfo(pos, 0.3).end - pos;
|
||||
var bufferStarvationDelay = this.bufferInfo(pos, this.config.maxBufferHole).end - pos;
|
||||
var fragLevelNextLoadedDelay = frag.duration * this.levels[hls.nextLoadLevel].bitrate / (8 * loadRate); //bps/Bps
|
||||
/* if we have less than 2 frag duration in buffer and if frag loaded delay is greater than buffer starvation delay
|
||||
... and also bigger than duration needed to load fragment at next level ...*/
|
||||
|
@ -1363,6 +1351,7 @@ var MSEMediaController = (function () {
|
|||
bufferLen = bufferEnd - pos;
|
||||
} else if (pos + maxHoleDuration < start) {
|
||||
bufferStartNext = start;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return { len: bufferLen, start: bufferStart, end: bufferEnd, nextStart: bufferStartNext };
|
||||
|
@ -1605,7 +1594,7 @@ var MSEMediaController = (function () {
|
|||
}
|
||||
}, {
|
||||
key: 'onMediaAttaching',
|
||||
value: function onMediaAttaching(event, data) {
|
||||
value: function onMediaAttaching(data) {
|
||||
var media = this.media = data.media;
|
||||
// setup the media source
|
||||
var ms = this.mediaSource = new MediaSource();
|
||||
|
@ -1680,7 +1669,7 @@ var MSEMediaController = (function () {
|
|||
if (this.state === State.FRAG_LOADING) {
|
||||
// check if currently loaded fragment is inside buffer.
|
||||
//if outside, cancel fragment loading, otherwise do nothing
|
||||
if (this.bufferInfo(this.media.currentTime, 0.3).len === 0) {
|
||||
if (this.bufferInfo(this.media.currentTime, this.config.maxBufferHole).len === 0) {
|
||||
_utilsLogger.logger.log('seeking outside of buffer while fragment load in progress, cancel fragment load');
|
||||
var fragCurrent = this.fragCurrent;
|
||||
if (fragCurrent) {
|
||||
|
@ -1732,7 +1721,7 @@ var MSEMediaController = (function () {
|
|||
}
|
||||
}, {
|
||||
key: 'onManifestParsed',
|
||||
value: function onManifestParsed(event, data) {
|
||||
value: function onManifestParsed(data) {
|
||||
var aac = false,
|
||||
heaac = false,
|
||||
codecs;
|
||||
|
@ -1761,13 +1750,14 @@ var MSEMediaController = (function () {
|
|||
}
|
||||
}, {
|
||||
key: 'onLevelLoaded',
|
||||
value: function onLevelLoaded(event, data) {
|
||||
value: function onLevelLoaded(data) {
|
||||
var newDetails = data.details,
|
||||
newLevelId = data.level,
|
||||
curLevel = this.levels[newLevelId],
|
||||
duration = newDetails.totalduration;
|
||||
|
||||
_utilsLogger.logger.log('level ' + newLevelId + ' loaded [' + newDetails.startSN + ',' + newDetails.endSN + '],duration:' + duration);
|
||||
this.levelLastLoaded = newLevelId;
|
||||
|
||||
if (newDetails.live) {
|
||||
var curDetails = curLevel.details;
|
||||
|
@ -1816,7 +1806,7 @@ var MSEMediaController = (function () {
|
|||
}
|
||||
}, {
|
||||
key: 'onFragLoaded',
|
||||
value: function onFragLoaded(event, data) {
|
||||
value: function onFragLoaded(data) {
|
||||
var fragCurrent = this.fragCurrent;
|
||||
if (this.state === State.FRAG_LOADING && fragCurrent && data.frag.level === fragCurrent.level && data.frag.sn === fragCurrent.sn) {
|
||||
if (this.fragBitrateTest === true) {
|
||||
|
@ -1854,8 +1844,8 @@ var MSEMediaController = (function () {
|
|||
this.fragLoadError = 0;
|
||||
}
|
||||
}, {
|
||||
key: 'onInitSegment',
|
||||
value: function onInitSegment(event, data) {
|
||||
key: 'onFragParsingInitSegment',
|
||||
value: function onFragParsingInitSegment(data) {
|
||||
if (this.state === State.PARSING) {
|
||||
// check if codecs have been explicitely defined in the master playlist for this level;
|
||||
// if yes use these ones instead of the ones parsed from the demux
|
||||
|
@ -1913,8 +1903,8 @@ var MSEMediaController = (function () {
|
|||
}
|
||||
}
|
||||
}, {
|
||||
key: 'onFragParsing',
|
||||
value: function onFragParsing(event, data) {
|
||||
key: 'onFragParsingData',
|
||||
value: function onFragParsingData(data) {
|
||||
if (this.state === State.PARSING) {
|
||||
this.tparse2 = Date.now();
|
||||
var level = this.levels[this.level],
|
||||
|
@ -1931,7 +1921,7 @@ var MSEMediaController = (function () {
|
|||
//trigger handler right now
|
||||
this.tick();
|
||||
} else {
|
||||
_utilsLogger.logger.warn('not in PARSING state, discarding ' + event);
|
||||
_utilsLogger.logger.warn('not in PARSING state, ignoring FRAG_PARSING_DATA event');
|
||||
}
|
||||
}
|
||||
}, {
|
||||
|
@ -1946,7 +1936,7 @@ var MSEMediaController = (function () {
|
|||
}
|
||||
}, {
|
||||
key: 'onError',
|
||||
value: function onError(event, data) {
|
||||
value: function onError(data) {
|
||||
switch (data.details) {
|
||||
case _errors.ErrorDetails.FRAG_LOAD_ERROR:
|
||||
case _errors.ErrorDetails.FRAG_LOAD_TIMEOUT:
|
||||
|
@ -1971,7 +1961,7 @@ var MSEMediaController = (function () {
|
|||
_utilsLogger.logger.error('mediaController: ' + data.details + ' reaches max retry, redispatch as fatal ...');
|
||||
// redispatch same error but with fatal set to true
|
||||
data.fatal = true;
|
||||
this.hls.trigger(event, data);
|
||||
this.hls.trigger(_events2['default'].ERROR, data);
|
||||
this.state = State.ERROR;
|
||||
}
|
||||
}
|
||||
|
@ -2037,14 +2027,14 @@ var MSEMediaController = (function () {
|
|||
// playhead moving or media not playing
|
||||
jumpThreshold = 0;
|
||||
} else {
|
||||
_utilsLogger.logger.trace('playback seems stuck');
|
||||
_utilsLogger.logger.log('playback seems stuck');
|
||||
}
|
||||
// if we are below threshold, try to jump if next buffer range is close
|
||||
if (bufferInfo.len <= jumpThreshold) {
|
||||
// no buffer available @ currentTime, check if next buffer is close (more than 5ms diff but within a 300 ms range)
|
||||
// no buffer available @ currentTime, check if next buffer is close (more than 5ms diff but within a config.maxSeekHole second range)
|
||||
var nextBufferStart = bufferInfo.nextStart,
|
||||
delta = nextBufferStart - currentTime;
|
||||
if (nextBufferStart && delta < 0.3 && delta > 0.005 && !media.seeking) {
|
||||
if (nextBufferStart && delta < this.config.maxSeekHole && delta > 0.005 && !media.seeking) {
|
||||
// next buffer is close ! adjust currentTime to nextBufferStart
|
||||
// this will ensure effective video decoding
|
||||
_utilsLogger.logger.log('adjust currentTime from ' + currentTime + ' to ' + nextBufferStart);
|
||||
|
@ -2145,12 +2135,12 @@ var MSEMediaController = (function () {
|
|||
}]);
|
||||
|
||||
return MSEMediaController;
|
||||
})();
|
||||
})(_eventHandler2['default']);
|
||||
|
||||
exports['default'] = MSEMediaController;
|
||||
module.exports = exports['default'];
|
||||
|
||||
},{"../demux/demuxer":13,"../errors":17,"../events":18,"../helper/level-helper":19,"../utils/binary-search":27,"../utils/logger":28}],6:[function(require,module,exports){
|
||||
},{"../demux/demuxer":13,"../errors":17,"../event-handler":18,"../events":19,"../helper/level-helper":20,"../utils/binary-search":28,"../utils/logger":29}],6:[function(require,module,exports){
|
||||
/*
|
||||
*
|
||||
* This file contains an adaptation of the AES decryption algorithm
|
||||
|
@ -2675,7 +2665,7 @@ var Decrypter = (function () {
|
|||
exports['default'] = Decrypter;
|
||||
module.exports = exports['default'];
|
||||
|
||||
},{"../errors":17,"../utils/logger":28,"./aes128-decrypter":7}],9:[function(require,module,exports){
|
||||
},{"../errors":17,"../utils/logger":29,"./aes128-decrypter":7}],9:[function(require,module,exports){
|
||||
/**
|
||||
* AAC demuxer
|
||||
*/
|
||||
|
@ -2804,7 +2794,7 @@ var AACDemuxer = (function () {
|
|||
exports['default'] = AACDemuxer;
|
||||
module.exports = exports['default'];
|
||||
|
||||
},{"../demux/id3":15,"../utils/logger":28,"./adts":10}],10:[function(require,module,exports){
|
||||
},{"../demux/id3":15,"../utils/logger":29,"./adts":10}],10:[function(require,module,exports){
|
||||
/**
|
||||
* ADTS parser helper
|
||||
*/
|
||||
|
@ -2952,7 +2942,7 @@ var ADTS = (function () {
|
|||
exports['default'] = ADTS;
|
||||
module.exports = exports['default'];
|
||||
|
||||
},{"../errors":17,"../utils/logger":28}],11:[function(require,module,exports){
|
||||
},{"../errors":17,"../utils/logger":29}],11:[function(require,module,exports){
|
||||
/* inline demuxer.
|
||||
* probe fragments and instantiate appropriate demuxer depending on content type (TSDemuxer, AACDemuxer, ...)
|
||||
*/
|
||||
|
@ -3024,7 +3014,7 @@ var DemuxerInline = (function () {
|
|||
exports['default'] = DemuxerInline;
|
||||
module.exports = exports['default'];
|
||||
|
||||
},{"../demux/aacdemuxer":9,"../demux/tsdemuxer":16,"../errors":17,"../events":18}],12:[function(require,module,exports){
|
||||
},{"../demux/aacdemuxer":9,"../demux/tsdemuxer":16,"../errors":17,"../events":19}],12:[function(require,module,exports){
|
||||
/* demuxer web worker.
|
||||
* - listen to worker message, and trigger DemuxerInline upon reception of Fragments.
|
||||
* - provides MP4 Boxes back to main thread using [transferable objects](https://developers.google.com/web/updates/2011/12/Transferable-Objects-Lightning-Fast) in order to minimize message passing overhead.
|
||||
|
@ -3131,7 +3121,7 @@ var DemuxerWorker = function DemuxerWorker(self) {
|
|||
exports['default'] = DemuxerWorker;
|
||||
module.exports = exports['default'];
|
||||
|
||||
},{"../demux/demuxer-inline":11,"../events":18,"../remux/mp4-remuxer":25,"events":1}],13:[function(require,module,exports){
|
||||
},{"../demux/demuxer-inline":11,"../events":19,"../remux/mp4-remuxer":26,"events":1}],13:[function(require,module,exports){
|
||||
'use strict';
|
||||
|
||||
Object.defineProperty(exports, '__esModule', {
|
||||
|
@ -3281,7 +3271,7 @@ var Demuxer = (function () {
|
|||
exports['default'] = Demuxer;
|
||||
module.exports = exports['default'];
|
||||
|
||||
},{"../crypt/decrypter":8,"../demux/demuxer-inline":11,"../demux/demuxer-worker":12,"../events":18,"../remux/mp4-remuxer":25,"../utils/logger":28,"webworkify":2}],14:[function(require,module,exports){
|
||||
},{"../crypt/decrypter":8,"../demux/demuxer-inline":11,"../demux/demuxer-worker":12,"../events":19,"../remux/mp4-remuxer":26,"../utils/logger":29,"webworkify":2}],14:[function(require,module,exports){
|
||||
/**
|
||||
* Parser for exponential Golomb codes, a variable-bitwidth number encoding scheme used by h264.
|
||||
*/
|
||||
|
@ -3620,7 +3610,7 @@ var ExpGolomb = (function () {
|
|||
exports['default'] = ExpGolomb;
|
||||
module.exports = exports['default'];
|
||||
|
||||
},{"../utils/logger":28}],15:[function(require,module,exports){
|
||||
},{"../utils/logger":29}],15:[function(require,module,exports){
|
||||
/**
|
||||
* ID3 parser
|
||||
*/
|
||||
|
@ -3774,7 +3764,7 @@ var ID3 = (function () {
|
|||
exports['default'] = ID3;
|
||||
module.exports = exports['default'];
|
||||
|
||||
},{"../utils/logger":28}],16:[function(require,module,exports){
|
||||
},{"../utils/logger":29}],16:[function(require,module,exports){
|
||||
/**
|
||||
* highly optimized TS demuxer:
|
||||
* parse PAT, PMT
|
||||
|
@ -4402,7 +4392,7 @@ var TSDemuxer = (function () {
|
|||
exports['default'] = TSDemuxer;
|
||||
module.exports = exports['default'];
|
||||
|
||||
},{"../errors":17,"../events":18,"../utils/logger":28,"./adts":10,"./exp-golomb":14}],17:[function(require,module,exports){
|
||||
},{"../errors":17,"../events":19,"../utils/logger":29,"./adts":10,"./exp-golomb":14}],17:[function(require,module,exports){
|
||||
'use strict';
|
||||
|
||||
Object.defineProperty(exports, '__esModule', {
|
||||
|
@ -4453,12 +4443,105 @@ var ErrorDetails = {
|
|||
exports.ErrorDetails = ErrorDetails;
|
||||
|
||||
},{}],18:[function(require,module,exports){
|
||||
/*
|
||||
*
|
||||
* All objects in the event handling chain should inherit from this class
|
||||
*
|
||||
*/
|
||||
|
||||
//import {logger} from './utils/logger';
|
||||
|
||||
'use strict';
|
||||
|
||||
Object.defineProperty(exports, '__esModule', {
|
||||
value: true
|
||||
});
|
||||
exports['default'] = {
|
||||
|
||||
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 EventHandler = (function () {
|
||||
function EventHandler(hls) {
|
||||
_classCallCheck(this, EventHandler);
|
||||
|
||||
this.hls = hls;
|
||||
this.onEvent = this.onEvent.bind(this);
|
||||
|
||||
for (var _len = arguments.length, events = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
||||
events[_key - 1] = arguments[_key];
|
||||
}
|
||||
|
||||
this.handledEvents = events;
|
||||
this.useGenericHandler = true;
|
||||
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
_createClass(EventHandler, [{
|
||||
key: 'destroy',
|
||||
value: function destroy() {
|
||||
this.unregisterListeners();
|
||||
}
|
||||
}, {
|
||||
key: 'isEventHandler',
|
||||
value: function isEventHandler() {
|
||||
return typeof this.handledEvents === 'object' && this.handledEvents.length && typeof this.onEvent === 'function';
|
||||
}
|
||||
}, {
|
||||
key: 'registerListeners',
|
||||
value: function registerListeners() {
|
||||
if (this.isEventHandler()) {
|
||||
this.handledEvents.forEach((function (event) {
|
||||
if (event === 'hlsEventGeneric') {
|
||||
throw new Error('Forbidden event name: ' + event);
|
||||
}
|
||||
this.hls.on(event, this.onEvent);
|
||||
}).bind(this));
|
||||
}
|
||||
}
|
||||
}, {
|
||||
key: 'unregisterListeners',
|
||||
value: function unregisterListeners() {
|
||||
if (this.isEventHandler()) {
|
||||
this.handledEvents.forEach((function (event) {
|
||||
this.hls.off(event, this.onEvent);
|
||||
}).bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* arguments: event (string), data (any)
|
||||
*/
|
||||
}, {
|
||||
key: 'onEvent',
|
||||
value: function onEvent(event, data) {
|
||||
this.onEventGeneric(event, data);
|
||||
}
|
||||
}, {
|
||||
key: 'onEventGeneric',
|
||||
value: function onEventGeneric(event, data) {
|
||||
var eventToFunction = function eventToFunction(event, data) {
|
||||
var funcName = 'on' + event.replace('hls', '');
|
||||
if (typeof this[funcName] !== 'function') {
|
||||
throw new Error('Event ' + event + ' has no generic handler in this ' + this.constructor.name + ' class (tried ' + funcName + ')');
|
||||
}
|
||||
return this[funcName].bind(this, data);
|
||||
};
|
||||
eventToFunction.call(this, event, data).call();
|
||||
}
|
||||
}]);
|
||||
|
||||
return EventHandler;
|
||||
})();
|
||||
|
||||
exports['default'] = EventHandler;
|
||||
module.exports = exports['default'];
|
||||
|
||||
},{}],19:[function(require,module,exports){
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
// fired before MediaSource is attaching to media element - data: { media }
|
||||
MEDIA_ATTACHING: 'hlsMediaAttaching',
|
||||
// fired when MediaSource has been succesfully attached to media element - data: { }
|
||||
|
@ -4480,7 +4563,7 @@ exports['default'] = {
|
|||
// fired when a level's details have been updated based on previous details, after it has been loaded. - data: { details : levelDetails object, level : id of updated level }
|
||||
LEVEL_UPDATED: 'hlsLevelUpdated',
|
||||
// fired when a level's PTS information has been updated after parsing a fragment - data: { details : levelDetails object, level : id of updated level, drift: PTS drift observed when parsing last fragment }
|
||||
LEVEL_PTS_UPDATED: 'hlsPTSUpdated',
|
||||
LEVEL_PTS_UPDATED: 'hlsLevelPtsUpdated',
|
||||
// fired when a level switch is requested - data: { level : id of new level }
|
||||
LEVEL_SWITCH: 'hlsLevelSwitch',
|
||||
// fired when a fragment loading starts - data: { frag : fragment object}
|
||||
|
@ -4494,7 +4577,7 @@ exports['default'] = {
|
|||
// fired when Init Segment has been extracted from fragment - data: { moov : moov MP4 box, codecs : codecs found while parsing fragment}
|
||||
FRAG_PARSING_INIT_SEGMENT: 'hlsFragParsingInitSegment',
|
||||
// fired when parsing id3 is completed - data: { samples : [ id3 samples pes ] }
|
||||
FRAG_PARSING_METADATA: 'hlsFraParsingMetadata',
|
||||
FRAG_PARSING_METADATA: 'hlsFragParsingMetadata',
|
||||
// fired when moof/mdat have been extracted from fragment - data: { moof : moof MP4 box, mdat : mdat MP4 box}
|
||||
FRAG_PARSING_DATA: 'hlsFragParsingData',
|
||||
// fired when fragment parsing is completed - data: undefined
|
||||
|
@ -4504,7 +4587,7 @@ exports['default'] = {
|
|||
// fired when fragment matching with current media position is changing - data : { frag : fragment object }
|
||||
FRAG_CHANGED: 'hlsFragChanged',
|
||||
// Identifier for a FPS drop event - data: {curentDropped, currentDecoded, totalDroppedFrames}
|
||||
FPS_DROP: 'hlsFPSDrop',
|
||||
FPS_DROP: 'hlsFpsDrop',
|
||||
// Identifier for an error event - data: { type : error type, details : error details, fatal : if true, hls.js cannot/will not try to recover, if false, hls.js will try to recover,other error specific data}
|
||||
ERROR: 'hlsError',
|
||||
// fired when hls.js instance starts destroying. Different from MEDIA_DETACHED as one could want to detach and reattach a media to the instance of hls.js to handle mid-rolls for example
|
||||
|
@ -4514,9 +4597,8 @@ exports['default'] = {
|
|||
// fired when a decrypt key loading is completed - data: { frag : fragment object, payload : key payload, stats : { trequest, tfirst, tload, length}}
|
||||
KEY_LOADED: 'hlsKeyLoaded'
|
||||
};
|
||||
module.exports = exports['default'];
|
||||
|
||||
},{}],19:[function(require,module,exports){
|
||||
},{}],20:[function(require,module,exports){
|
||||
/**
|
||||
* Level Helper class, providing methods dealing with playlist sliding and drift
|
||||
*/
|
||||
|
@ -4662,7 +4744,7 @@ var LevelHelper = (function () {
|
|||
exports['default'] = LevelHelper;
|
||||
module.exports = exports['default'];
|
||||
|
||||
},{"../utils/logger":28}],20:[function(require,module,exports){
|
||||
},{"../utils/logger":29}],21:[function(require,module,exports){
|
||||
/**
|
||||
* HLS interface
|
||||
*/
|
||||
|
@ -4750,6 +4832,8 @@ var Hls = (function () {
|
|||
debug: false,
|
||||
maxBufferLength: 30,
|
||||
maxBufferSize: 60 * 1000 * 1000,
|
||||
maxBufferHole: 0.3,
|
||||
maxSeekHole: 2,
|
||||
liveSyncDurationCount: 3,
|
||||
liveMaxLatencyDurationCount: Infinity,
|
||||
maxMaxBufferLength: 600,
|
||||
|
@ -5016,7 +5100,7 @@ var Hls = (function () {
|
|||
exports['default'] = Hls;
|
||||
module.exports = exports['default'];
|
||||
|
||||
},{"./controller/abr-controller":3,"./controller/level-controller":4,"./controller/mse-media-controller":5,"./errors":17,"./events":18,"./loader/fragment-loader":21,"./loader/key-loader":22,"./loader/playlist-loader":23,"./utils/logger":28,"./utils/xhr-loader":30,"events":1}],21:[function(require,module,exports){
|
||||
},{"./controller/abr-controller":3,"./controller/level-controller":4,"./controller/mse-media-controller":5,"./errors":17,"./events":19,"./loader/fragment-loader":22,"./loader/key-loader":23,"./loader/playlist-loader":24,"./utils/logger":29,"./utils/xhr-loader":31,"events":1}],22:[function(require,module,exports){
|
||||
/*
|
||||
* Fragment Loader
|
||||
*/
|
||||
|
@ -5029,23 +5113,31 @@ Object.defineProperty(exports, '__esModule', {
|
|||
|
||||
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; }; })();
|
||||
|
||||
var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _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; 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 _events = require('../events');
|
||||
|
||||
var _events2 = _interopRequireDefault(_events);
|
||||
|
||||
var _eventHandler = require('../event-handler');
|
||||
|
||||
var _eventHandler2 = _interopRequireDefault(_eventHandler);
|
||||
|
||||
var _errors = require('../errors');
|
||||
|
||||
var FragmentLoader = (function () {
|
||||
var FragmentLoader = (function (_EventHandler) {
|
||||
_inherits(FragmentLoader, _EventHandler);
|
||||
|
||||
function FragmentLoader(hls) {
|
||||
_classCallCheck(this, FragmentLoader);
|
||||
|
||||
this.hls = hls;
|
||||
this.onfl = this.onFragLoading.bind(this);
|
||||
hls.on(_events2['default'].FRAG_LOADING, this.onfl);
|
||||
_get(Object.getPrototypeOf(FragmentLoader.prototype), 'constructor', this).call(this, hls, _events2['default'].FRAG_LOADING);
|
||||
}
|
||||
|
||||
_createClass(FragmentLoader, [{
|
||||
|
@ -5055,11 +5147,11 @@ var FragmentLoader = (function () {
|
|||
this.loader.destroy();
|
||||
this.loader = null;
|
||||
}
|
||||
this.hls.off(_events2['default'].FRAG_LOADING, this.onfl);
|
||||
_eventHandler2['default'].prototype.destroy.call(this);
|
||||
}
|
||||
}, {
|
||||
key: 'onFragLoading',
|
||||
value: function onFragLoading(event, data) {
|
||||
value: function onFragLoading(data) {
|
||||
var frag = data.frag;
|
||||
this.frag = frag;
|
||||
this.frag.loaded = 0;
|
||||
|
@ -5097,12 +5189,12 @@ var FragmentLoader = (function () {
|
|||
}]);
|
||||
|
||||
return FragmentLoader;
|
||||
})();
|
||||
})(_eventHandler2['default']);
|
||||
|
||||
exports['default'] = FragmentLoader;
|
||||
module.exports = exports['default'];
|
||||
|
||||
},{"../errors":17,"../events":18}],22:[function(require,module,exports){
|
||||
},{"../errors":17,"../event-handler":18,"../events":19}],23:[function(require,module,exports){
|
||||
/*
|
||||
* Decrypt key Loader
|
||||
*/
|
||||
|
@ -5115,25 +5207,33 @@ Object.defineProperty(exports, '__esModule', {
|
|||
|
||||
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; }; })();
|
||||
|
||||
var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _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; 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 _events = require('../events');
|
||||
|
||||
var _events2 = _interopRequireDefault(_events);
|
||||
|
||||
var _eventHandler = require('../event-handler');
|
||||
|
||||
var _eventHandler2 = _interopRequireDefault(_eventHandler);
|
||||
|
||||
var _errors = require('../errors');
|
||||
|
||||
var KeyLoader = (function () {
|
||||
var KeyLoader = (function (_EventHandler) {
|
||||
_inherits(KeyLoader, _EventHandler);
|
||||
|
||||
function KeyLoader(hls) {
|
||||
_classCallCheck(this, KeyLoader);
|
||||
|
||||
this.hls = hls;
|
||||
_get(Object.getPrototypeOf(KeyLoader.prototype), 'constructor', this).call(this, hls, _events2['default'].KEY_LOADING);
|
||||
this.decryptkey = null;
|
||||
this.decrypturl = null;
|
||||
this.ondkl = this.onDecryptKeyLoading.bind(this);
|
||||
hls.on(_events2['default'].KEY_LOADING, this.ondkl);
|
||||
}
|
||||
|
||||
_createClass(KeyLoader, [{
|
||||
|
@ -5143,11 +5243,11 @@ var KeyLoader = (function () {
|
|||
this.loader.destroy();
|
||||
this.loader = null;
|
||||
}
|
||||
this.hls.off(_events2['default'].KEY_LOADING, this.ondkl);
|
||||
_eventHandler2['default'].prototype.destroy.call(this);
|
||||
}
|
||||
}, {
|
||||
key: 'onDecryptKeyLoading',
|
||||
value: function onDecryptKeyLoading(event, data) {
|
||||
key: 'onKeyLoading',
|
||||
value: function onKeyLoading(data) {
|
||||
var frag = this.frag = data.frag,
|
||||
decryptdata = frag.decryptdata,
|
||||
uri = decryptdata.uri;
|
||||
|
@ -5191,12 +5291,12 @@ var KeyLoader = (function () {
|
|||
}]);
|
||||
|
||||
return KeyLoader;
|
||||
})();
|
||||
})(_eventHandler2['default']);
|
||||
|
||||
exports['default'] = KeyLoader;
|
||||
module.exports = exports['default'];
|
||||
|
||||
},{"../errors":17,"../events":18}],23:[function(require,module,exports){
|
||||
},{"../errors":17,"../event-handler":18,"../events":19}],24:[function(require,module,exports){
|
||||
/**
|
||||
* Playlist Loader
|
||||
*/
|
||||
|
@ -5209,14 +5309,22 @@ Object.defineProperty(exports, '__esModule', {
|
|||
|
||||
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; }; })();
|
||||
|
||||
var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _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; 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 _events = require('../events');
|
||||
|
||||
var _events2 = _interopRequireDefault(_events);
|
||||
|
||||
var _eventHandler = require('../event-handler');
|
||||
|
||||
var _eventHandler2 = _interopRequireDefault(_eventHandler);
|
||||
|
||||
var _errors = require('../errors');
|
||||
|
||||
var _utilsUrl = require('../utils/url');
|
||||
|
@ -5229,15 +5337,13 @@ var _utilsAttrList2 = _interopRequireDefault(_utilsAttrList);
|
|||
|
||||
//import {logger} from '../utils/logger';
|
||||
|
||||
var PlaylistLoader = (function () {
|
||||
var PlaylistLoader = (function (_EventHandler) {
|
||||
_inherits(PlaylistLoader, _EventHandler);
|
||||
|
||||
function PlaylistLoader(hls) {
|
||||
_classCallCheck(this, PlaylistLoader);
|
||||
|
||||
this.hls = hls;
|
||||
this.onml = this.onManifestLoading.bind(this);
|
||||
this.onll = this.onLevelLoading.bind(this);
|
||||
hls.on(_events2['default'].MANIFEST_LOADING, this.onml);
|
||||
hls.on(_events2['default'].LEVEL_LOADING, this.onll);
|
||||
_get(Object.getPrototypeOf(PlaylistLoader.prototype), 'constructor', this).call(this, hls, _events2['default'].MANIFEST_LOADING, _events2['default'].LEVEL_LOADING);
|
||||
}
|
||||
|
||||
_createClass(PlaylistLoader, [{
|
||||
|
@ -5248,17 +5354,16 @@ var PlaylistLoader = (function () {
|
|||
this.loader = null;
|
||||
}
|
||||
this.url = this.id = null;
|
||||
this.hls.off(_events2['default'].MANIFEST_LOADING, this.onml);
|
||||
this.hls.off(_events2['default'].LEVEL_LOADING, this.onll);
|
||||
_eventHandler2['default'].prototype.destroy.call(this);
|
||||
}
|
||||
}, {
|
||||
key: 'onManifestLoading',
|
||||
value: function onManifestLoading(event, data) {
|
||||
value: function onManifestLoading(data) {
|
||||
this.load(data.url, null);
|
||||
}
|
||||
}, {
|
||||
key: 'onLevelLoading',
|
||||
value: function onLevelLoading(event, data) {
|
||||
value: function onLevelLoading(data) {
|
||||
this.load(data.url, data.level, data.id);
|
||||
}
|
||||
}, {
|
||||
|
@ -5525,12 +5630,12 @@ var PlaylistLoader = (function () {
|
|||
}]);
|
||||
|
||||
return PlaylistLoader;
|
||||
})();
|
||||
})(_eventHandler2['default']);
|
||||
|
||||
exports['default'] = PlaylistLoader;
|
||||
module.exports = exports['default'];
|
||||
|
||||
},{"../errors":17,"../events":18,"../utils/attr-list":26,"../utils/url":29}],24:[function(require,module,exports){
|
||||
},{"../errors":17,"../event-handler":18,"../events":19,"../utils/attr-list":27,"../utils/url":30}],25:[function(require,module,exports){
|
||||
/**
|
||||
* Generate MP4 Box
|
||||
*/
|
||||
|
@ -6035,7 +6140,7 @@ var MP4 = (function () {
|
|||
exports['default'] = MP4;
|
||||
module.exports = exports['default'];
|
||||
|
||||
},{}],25:[function(require,module,exports){
|
||||
},{}],26:[function(require,module,exports){
|
||||
/**
|
||||
* fMP4 remuxer
|
||||
*/
|
||||
|
@ -6194,6 +6299,7 @@ var MP4Remuxer = (function () {
|
|||
dts,
|
||||
ptsnorm,
|
||||
dtsnorm,
|
||||
flags,
|
||||
samples = [];
|
||||
/* concatenate the video data and construct the mdat in place
|
||||
(need 8 more bytes to fill length and mpdat type) */
|
||||
|
@ -6217,7 +6323,7 @@ var MP4Remuxer = (function () {
|
|||
dts = avcSample.dts - this._initDTS;
|
||||
// ensure DTS is not bigger than PTS
|
||||
dts = Math.min(pts, dts);
|
||||
//logger.log(`Video/PTS/DTS:${pts}/${dts}`);
|
||||
//logger.log(`Video/PTS/DTS:${Math.round(pts/90)}/${Math.round(dts/90)}`);
|
||||
// if not first AVC sample of video track, normalize PTS/DTS with previous sample value
|
||||
// and ensure that sample duration is positive
|
||||
if (lastDTS !== undefined) {
|
||||
|
@ -6267,13 +6373,14 @@ var MP4Remuxer = (function () {
|
|||
degradPrio: 0
|
||||
}
|
||||
};
|
||||
flags = mp4Sample.flags;
|
||||
if (avcSample.key === true) {
|
||||
// the current sample is a key frame
|
||||
mp4Sample.flags.dependsOn = 2;
|
||||
mp4Sample.flags.isNonSync = 0;
|
||||
flags.dependsOn = 2;
|
||||
flags.isNonSync = 0;
|
||||
} else {
|
||||
mp4Sample.flags.dependsOn = 1;
|
||||
mp4Sample.flags.isNonSync = 1;
|
||||
flags.dependsOn = 1;
|
||||
flags.isNonSync = 1;
|
||||
}
|
||||
samples.push(mp4Sample);
|
||||
lastDTS = dtsnorm;
|
||||
|
@ -6288,7 +6395,7 @@ var MP4Remuxer = (function () {
|
|||
track.len = 0;
|
||||
track.nbNalu = 0;
|
||||
if (samples.length && navigator.userAgent.toLowerCase().indexOf('chrome') > -1) {
|
||||
var flags = samples[0].flags;
|
||||
flags = samples[0].flags;
|
||||
// chrome workaround, mark first sample as being a Random Access Point to avoid sourcebuffer append issue
|
||||
// https://code.google.com/p/chromium/issues/detail?id=229412
|
||||
flags.dependsOn = 2;
|
||||
|
@ -6344,7 +6451,7 @@ var MP4Remuxer = (function () {
|
|||
unit = aacSample.unit;
|
||||
pts = aacSample.pts - this._initDTS;
|
||||
dts = aacSample.dts - this._initDTS;
|
||||
//logger.log(`Audio/PTS:${aacSample.pts.toFixed(0)}`);
|
||||
//logger.log(`Audio/PTS:${Math.round(pts/90)}`);
|
||||
// if not first sample
|
||||
if (lastDTS !== undefined) {
|
||||
ptsnorm = this._PTSNormalize(pts, lastDTS);
|
||||
|
@ -6490,7 +6597,7 @@ var MP4Remuxer = (function () {
|
|||
exports['default'] = MP4Remuxer;
|
||||
module.exports = exports['default'];
|
||||
|
||||
},{"../errors":17,"../events":18,"../remux/mp4-generator":24,"../utils/logger":28}],26:[function(require,module,exports){
|
||||
},{"../errors":17,"../events":19,"../remux/mp4-generator":25,"../utils/logger":29}],27:[function(require,module,exports){
|
||||
|
||||
// adapted from https://github.com/kanongil/node-m3u8parse/blob/master/attrlist.js
|
||||
'use strict';
|
||||
|
@ -6598,7 +6705,7 @@ var AttrList = (function () {
|
|||
exports['default'] = AttrList;
|
||||
module.exports = exports['default'];
|
||||
|
||||
},{}],27:[function(require,module,exports){
|
||||
},{}],28:[function(require,module,exports){
|
||||
"use strict";
|
||||
|
||||
var BinarySearch = {
|
||||
|
@ -6643,7 +6750,7 @@ var BinarySearch = {
|
|||
|
||||
module.exports = BinarySearch;
|
||||
|
||||
},{}],28:[function(require,module,exports){
|
||||
},{}],29:[function(require,module,exports){
|
||||
'use strict';
|
||||
|
||||
Object.defineProperty(exports, '__esModule', {
|
||||
|
@ -6725,7 +6832,7 @@ exports.enableLogs = enableLogs;
|
|||
var logger = exportedLogger;
|
||||
exports.logger = logger;
|
||||
|
||||
},{}],29:[function(require,module,exports){
|
||||
},{}],30:[function(require,module,exports){
|
||||
'use strict';
|
||||
|
||||
var URLHelper = {
|
||||
|
@ -6806,7 +6913,7 @@ var URLHelper = {
|
|||
|
||||
module.exports = URLHelper;
|
||||
|
||||
},{}],30:[function(require,module,exports){
|
||||
},{}],31:[function(require,module,exports){
|
||||
/**
|
||||
* XHR based logger
|
||||
*/
|
||||
|
@ -6877,7 +6984,7 @@ var XhrLoader = (function () {
|
|||
key: 'loadInternal',
|
||||
value: function loadInternal() {
|
||||
var xhr = this.loader = new XMLHttpRequest();
|
||||
xhr.onreadystatechange = this.statechange.bind(this);
|
||||
xhr.onloadend = this.loadend.bind(this);
|
||||
xhr.onprogress = this.loadprogress.bind(this);
|
||||
|
||||
xhr.open('GET', this.url, true);
|
||||
|
@ -6893,14 +7000,13 @@ var XhrLoader = (function () {
|
|||
xhr.send();
|
||||
}
|
||||
}, {
|
||||
key: 'statechange',
|
||||
value: function statechange(event) {
|
||||
key: 'loadend',
|
||||
value: function loadend(event) {
|
||||
var xhr = event.currentTarget,
|
||||
status = xhr.status,
|
||||
stats = this.stats;
|
||||
// don't proceed if xhr has been aborted
|
||||
// 4 = Response from server has been completely loaded.
|
||||
if (!stats.aborted && xhr.readyState === 4) {
|
||||
if (!stats.aborted) {
|
||||
// http status between 200 to 299 are all successful
|
||||
if (status >= 200 && status < 300) {
|
||||
window.clearTimeout(this.timeoutHandle);
|
||||
|
@ -6949,6 +7055,6 @@ var XhrLoader = (function () {
|
|||
exports['default'] = XhrLoader;
|
||||
module.exports = exports['default'];
|
||||
|
||||
},{"../utils/logger":28}]},{},[20])(20)
|
||||
},{"../utils/logger":29}]},{},[21])(21)
|
||||
});
|
||||
//# sourceMappingURL=hls.js.map
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "hls.js",
|
||||
"version": "0.4.5",
|
||||
"version": "0.4.6",
|
||||
"description": "Media Source Extension - HLS library, by/for Dailymotion",
|
||||
"homepage": "https://github.com/dailymotion/hls.js",
|
||||
"authors": "Guillaume du Pontavice <guillaume.dupontavice@dailymotion.com>",
|
||||
|
|
|
@ -3,23 +3,22 @@
|
|||
*/
|
||||
|
||||
import Event from '../events';
|
||||
import EventHandler from '../event-handler';
|
||||
|
||||
class AbrController {
|
||||
class AbrController extends EventHandler {
|
||||
|
||||
constructor(hls) {
|
||||
this.hls = hls;
|
||||
super(hls, Event.FRAG_LOAD_PROGRESS);
|
||||
this.lastfetchlevel = 0;
|
||||
this._autoLevelCapping = -1;
|
||||
this._nextAutoLevel = -1;
|
||||
this.onflp = this.onFragmentLoadProgress.bind(this);
|
||||
hls.on(Event.FRAG_LOAD_PROGRESS, this.onflp);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.hls.off(Event.FRAG_LOAD_PROGRESS, this.onflp);
|
||||
EventHandler.prototype.destroy.call(this);
|
||||
}
|
||||
|
||||
onFragmentLoadProgress(event, data) {
|
||||
onFragLoadProgress(data) {
|
||||
var stats = data.stats;
|
||||
if (stats.aborted === undefined) {
|
||||
this.lastfetchduration = (performance.now() - stats.trequest) / 1000;
|
||||
|
|
|
@ -3,35 +3,29 @@
|
|||
*/
|
||||
|
||||
import Event from '../events';
|
||||
import EventHandler from '../event-handler';
|
||||
import {logger} from '../utils/logger';
|
||||
import {ErrorTypes, ErrorDetails} from '../errors';
|
||||
|
||||
class LevelController {
|
||||
class LevelController extends EventHandler {
|
||||
|
||||
constructor(hls) {
|
||||
this.hls = hls;
|
||||
this.onml = this.onManifestLoaded.bind(this);
|
||||
this.onll = this.onLevelLoaded.bind(this);
|
||||
this.onerr = this.onError.bind(this);
|
||||
super(hls,
|
||||
Event.MANIFEST_LOADED,
|
||||
Event.LEVEL_LOADED,
|
||||
Event.ERROR);
|
||||
this.ontick = this.tick.bind(this);
|
||||
hls.on(Event.MANIFEST_LOADED, this.onml);
|
||||
hls.on(Event.LEVEL_LOADED, this.onll);
|
||||
hls.on(Event.ERROR, this.onerr);
|
||||
this._manualLevel = this._autoLevelCapping = -1;
|
||||
}
|
||||
|
||||
destroy() {
|
||||
var hls = this.hls;
|
||||
hls.off(Event.MANIFEST_LOADED, this.onml);
|
||||
hls.off(Event.LEVEL_LOADED, this.onll);
|
||||
hls.off(Event.ERROR, this.onerr);
|
||||
if (this.timer) {
|
||||
clearInterval(this.timer);
|
||||
}
|
||||
this._manualLevel = -1;
|
||||
}
|
||||
|
||||
onManifestLoaded(event, data) {
|
||||
onManifestLoaded(data) {
|
||||
var levels0 = [], levels = [], bitrateStart, i, bitrateSet = {}, videoCodecFound = false, audioCodecFound = false, hls = this.hls;
|
||||
|
||||
// regroup redundant level together
|
||||
|
@ -166,7 +160,7 @@ class LevelController {
|
|||
this._startLevel = newLevel;
|
||||
}
|
||||
|
||||
onError(event, data) {
|
||||
onError(data) {
|
||||
if(data.fatal) {
|
||||
return;
|
||||
}
|
||||
|
@ -224,7 +218,7 @@ class LevelController {
|
|||
}
|
||||
}
|
||||
|
||||
onLevelLoaded(event, data) {
|
||||
onLevelLoaded(data) {
|
||||
// check if current playlist is a live playlist
|
||||
if (data.details.live && !this.timer) {
|
||||
// if live playlist we will have to reload it periodically
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
import Demuxer from '../demux/demuxer';
|
||||
import Event from '../events';
|
||||
import EventHandler from '../event-handler';
|
||||
import {logger} from '../utils/logger';
|
||||
import BinarySearch from '../utils/binary-search';
|
||||
import LevelHelper from '../helper/level-helper';
|
||||
|
@ -23,39 +24,31 @@ const State = {
|
|||
BUFFER_FLUSHING : 8
|
||||
};
|
||||
|
||||
class MSEMediaController {
|
||||
class MSEMediaController extends EventHandler {
|
||||
|
||||
constructor(hls) {
|
||||
super(hls, Event.MEDIA_ATTACHING,
|
||||
Event.MEDIA_DETACHING,
|
||||
Event.MANIFEST_PARSED,
|
||||
Event.LEVEL_LOADED,
|
||||
Event.KEY_LOADED,
|
||||
Event.FRAG_LOADED,
|
||||
Event.FRAG_PARSING_INIT_SEGMENT,
|
||||
Event.FRAG_PARSING_DATA,
|
||||
Event.FRAG_PARSED,
|
||||
Event.ERROR);
|
||||
this.config = hls.config;
|
||||
this.audioCodecSwap = false;
|
||||
this.hls = hls;
|
||||
this.ticks = 0;
|
||||
// Source Buffer listeners
|
||||
this.onsbue = this.onSBUpdateEnd.bind(this);
|
||||
this.onsbe = this.onSBUpdateError.bind(this);
|
||||
// internal listeners
|
||||
this.onmediaatt0 = this.onMediaAttaching.bind(this);
|
||||
this.onmediadet0 = this.onMediaDetaching.bind(this);
|
||||
this.onmp = this.onManifestParsed.bind(this);
|
||||
this.onll = this.onLevelLoaded.bind(this);
|
||||
this.onfl = this.onFragLoaded.bind(this);
|
||||
this.onkl = this.onKeyLoaded.bind(this);
|
||||
this.onis = this.onInitSegment.bind(this);
|
||||
this.onfpg = this.onFragParsing.bind(this);
|
||||
this.onfp = this.onFragParsed.bind(this);
|
||||
this.onerr = this.onError.bind(this);
|
||||
this.ontick = this.tick.bind(this);
|
||||
hls.on(Event.MEDIA_ATTACHING, this.onmediaatt0);
|
||||
hls.on(Event.MEDIA_DETACHING, this.onmediadet0);
|
||||
hls.on(Event.MANIFEST_PARSED, this.onmp);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.stop();
|
||||
var hls = this.hls;
|
||||
hls.off(Event.MEDIA_ATTACHING, this.onmediaatt0);
|
||||
hls.off(Event.MEDIA_DETACHING, this.onmediadet0);
|
||||
hls.off(Event.MANIFEST_PARSED, this.onmp);
|
||||
EventHandler.prototype.destroy.call(this);
|
||||
this.state = State.IDLE;
|
||||
}
|
||||
|
||||
|
@ -87,13 +80,6 @@ class MSEMediaController {
|
|||
this.timer = setInterval(this.ontick, 100);
|
||||
this.level = -1;
|
||||
this.fragLoadError = 0;
|
||||
hls.on(Event.FRAG_LOADED, this.onfl);
|
||||
hls.on(Event.FRAG_PARSING_INIT_SEGMENT, this.onis);
|
||||
hls.on(Event.FRAG_PARSING_DATA, this.onfpg);
|
||||
hls.on(Event.FRAG_PARSED, this.onfp);
|
||||
hls.on(Event.ERROR, this.onerr);
|
||||
hls.on(Event.LEVEL_LOADED, this.onll);
|
||||
hls.on(Event.KEY_LOADED, this.onkl);
|
||||
}
|
||||
|
||||
stop() {
|
||||
|
@ -128,14 +114,6 @@ class MSEMediaController {
|
|||
this.demuxer.destroy();
|
||||
this.demuxer = null;
|
||||
}
|
||||
var hls = this.hls;
|
||||
hls.off(Event.FRAG_LOADED, this.onfl);
|
||||
hls.off(Event.FRAG_PARSED, this.onfp);
|
||||
hls.off(Event.FRAG_PARSING_DATA, this.onfpg);
|
||||
hls.off(Event.LEVEL_LOADED, this.onll);
|
||||
hls.off(Event.KEY_LOADED, this.onkl);
|
||||
hls.off(Event.FRAG_PARSING_INIT_SEGMENT, this.onis);
|
||||
hls.off(Event.ERROR, this.onerr);
|
||||
}
|
||||
|
||||
tick() {
|
||||
|
@ -189,7 +167,7 @@ class MSEMediaController {
|
|||
// we are not at playback start, get next load level from level Controller
|
||||
level = hls.nextLoadLevel;
|
||||
}
|
||||
var bufferInfo = this.bufferInfo(pos,0.3),
|
||||
var bufferInfo = this.bufferInfo(pos,this.config.maxBufferHole),
|
||||
bufferLen = bufferInfo.len,
|
||||
bufferEnd = bufferInfo.end,
|
||||
fragPrevious = this.fragPrevious,
|
||||
|
@ -208,7 +186,9 @@ class MSEMediaController {
|
|||
this.level = level;
|
||||
levelDetails = this.levels[level].details;
|
||||
// if level info not retrieved yet, switch state and wait for level retrieval
|
||||
if (typeof levelDetails === 'undefined') {
|
||||
// if live playlist, ensure that new playlist has been refreshed to avoid loading/try to load
|
||||
// a useless and outdated fragment (that might even introduce load error if it is already out of the live playlist)
|
||||
if (typeof levelDetails === 'undefined' || levelDetails.live && this.levelLastLoaded !== level) {
|
||||
this.state = State.WAITING_LEVEL;
|
||||
break;
|
||||
}
|
||||
|
@ -364,7 +344,7 @@ class MSEMediaController {
|
|||
}
|
||||
pos = v.currentTime;
|
||||
var fragLoadedDelay = (frag.expectedLen - frag.loaded) / loadRate;
|
||||
var bufferStarvationDelay = this.bufferInfo(pos,0.3).end - pos;
|
||||
var bufferStarvationDelay = this.bufferInfo(pos,this.config.maxBufferHole).end - pos;
|
||||
var fragLevelNextLoadedDelay = frag.duration * this.levels[hls.nextLoadLevel].bitrate / (8 * loadRate); //bps/Bps
|
||||
/* if we have less than 2 frag duration in buffer and if frag loaded delay is greater than buffer starvation delay
|
||||
... and also bigger than duration needed to load fragment at next level ...*/
|
||||
|
@ -545,6 +525,7 @@ class MSEMediaController {
|
|||
bufferLen = bufferEnd - pos;
|
||||
} else if ((pos + maxHoleDuration) < start) {
|
||||
bufferStartNext = start;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return {len: bufferLen, start: bufferStart, end: bufferEnd, nextStart : bufferStartNext};
|
||||
|
@ -797,7 +778,7 @@ class MSEMediaController {
|
|||
}
|
||||
}
|
||||
|
||||
onMediaAttaching(event, data) {
|
||||
onMediaAttaching(data) {
|
||||
var media = this.media = data.media;
|
||||
// setup the media source
|
||||
var ms = this.mediaSource = new MediaSource();
|
||||
|
@ -870,7 +851,7 @@ class MSEMediaController {
|
|||
if (this.state === State.FRAG_LOADING) {
|
||||
// check if currently loaded fragment is inside buffer.
|
||||
//if outside, cancel fragment loading, otherwise do nothing
|
||||
if (this.bufferInfo(this.media.currentTime,0.3).len === 0) {
|
||||
if (this.bufferInfo(this.media.currentTime,this.config.maxBufferHole).len === 0) {
|
||||
logger.log('seeking outside of buffer while fragment load in progress, cancel fragment load');
|
||||
var fragCurrent = this.fragCurrent;
|
||||
if (fragCurrent) {
|
||||
|
@ -919,7 +900,7 @@ class MSEMediaController {
|
|||
}
|
||||
|
||||
|
||||
onManifestParsed(event, data) {
|
||||
onManifestParsed(data) {
|
||||
var aac = false, heaac = false, codecs;
|
||||
data.levels.forEach(level => {
|
||||
// detect if we have different kind of audio codecs used amongst playlists
|
||||
|
@ -945,13 +926,14 @@ class MSEMediaController {
|
|||
}
|
||||
}
|
||||
|
||||
onLevelLoaded(event,data) {
|
||||
onLevelLoaded(data) {
|
||||
var newDetails = data.details,
|
||||
newLevelId = data.level,
|
||||
curLevel = this.levels[newLevelId],
|
||||
duration = newDetails.totalduration;
|
||||
|
||||
logger.log(`level ${newLevelId} loaded [${newDetails.startSN},${newDetails.endSN}],duration:${duration}`);
|
||||
this.levelLastLoaded = newLevelId;
|
||||
|
||||
if (newDetails.live) {
|
||||
var curDetails = curLevel.details;
|
||||
|
@ -998,7 +980,7 @@ class MSEMediaController {
|
|||
}
|
||||
}
|
||||
|
||||
onFragLoaded(event, data) {
|
||||
onFragLoaded(data) {
|
||||
var fragCurrent = this.fragCurrent;
|
||||
if (this.state === State.FRAG_LOADING &&
|
||||
fragCurrent &&
|
||||
|
@ -1039,7 +1021,7 @@ class MSEMediaController {
|
|||
this.fragLoadError = 0;
|
||||
}
|
||||
|
||||
onInitSegment(event, data) {
|
||||
onFragParsingInitSegment(data) {
|
||||
if (this.state === State.PARSING) {
|
||||
// check if codecs have been explicitely defined in the master playlist for this level;
|
||||
// if yes use these ones instead of the ones parsed from the demux
|
||||
|
@ -1098,7 +1080,7 @@ class MSEMediaController {
|
|||
}
|
||||
}
|
||||
|
||||
onFragParsing(event, data) {
|
||||
onFragParsingData(data) {
|
||||
if (this.state === State.PARSING) {
|
||||
this.tparse2 = Date.now();
|
||||
var level = this.levels[this.level],
|
||||
|
@ -1115,7 +1097,7 @@ class MSEMediaController {
|
|||
//trigger handler right now
|
||||
this.tick();
|
||||
} else {
|
||||
logger.warn(`not in PARSING state, discarding ${event}`);
|
||||
logger.warn(`not in PARSING state, ignoring FRAG_PARSING_DATA event`);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1128,7 +1110,7 @@ class MSEMediaController {
|
|||
}
|
||||
}
|
||||
|
||||
onError(event, data) {
|
||||
onError(data) {
|
||||
switch(data.details) {
|
||||
case ErrorDetails.FRAG_LOAD_ERROR:
|
||||
case ErrorDetails.FRAG_LOAD_TIMEOUT:
|
||||
|
@ -1153,7 +1135,7 @@ class MSEMediaController {
|
|||
logger.error(`mediaController: ${data.details} reaches max retry, redispatch as fatal ...`);
|
||||
// redispatch same error but with fatal set to true
|
||||
data.fatal = true;
|
||||
this.hls.trigger(event, data);
|
||||
this.hls.trigger(Event.ERROR, data);
|
||||
this.state = State.ERROR;
|
||||
}
|
||||
}
|
||||
|
@ -1216,14 +1198,14 @@ _checkBuffer() {
|
|||
// playhead moving or media not playing
|
||||
jumpThreshold = 0;
|
||||
} else {
|
||||
logger.trace('playback seems stuck');
|
||||
logger.log('playback seems stuck');
|
||||
}
|
||||
// if we are below threshold, try to jump if next buffer range is close
|
||||
if(bufferInfo.len <= jumpThreshold) {
|
||||
// no buffer available @ currentTime, check if next buffer is close (more than 5ms diff but within a 300 ms range)
|
||||
// no buffer available @ currentTime, check if next buffer is close (more than 5ms diff but within a config.maxSeekHole second range)
|
||||
var nextBufferStart = bufferInfo.nextStart, delta = nextBufferStart-currentTime;
|
||||
if(nextBufferStart &&
|
||||
(delta < 0.3) &&
|
||||
(delta < this.config.maxSeekHole) &&
|
||||
(delta > 0.005) &&
|
||||
!media.seeking) {
|
||||
// next buffer is close ! adjust currentTime to nextBufferStart
|
||||
|
|
66
dashboard-ui/bower_components/hls.js/src/event-handler.js
vendored
Normal file
66
dashboard-ui/bower_components/hls.js/src/event-handler.js
vendored
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
*
|
||||
* All objects in the event handling chain should inherit from this class
|
||||
*
|
||||
*/
|
||||
|
||||
//import {logger} from './utils/logger';
|
||||
|
||||
class EventHandler {
|
||||
|
||||
constructor(hls, ...events) {
|
||||
this.hls = hls;
|
||||
this.onEvent = this.onEvent.bind(this);
|
||||
this.handledEvents = events;
|
||||
this.useGenericHandler = true;
|
||||
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.unregisterListeners();
|
||||
}
|
||||
|
||||
isEventHandler() {
|
||||
return typeof this.handledEvents === 'object' && this.handledEvents.length && typeof this.onEvent === 'function';
|
||||
}
|
||||
|
||||
registerListeners() {
|
||||
if (this.isEventHandler()) {
|
||||
this.handledEvents.forEach(function(event) {
|
||||
if (event === 'hlsEventGeneric') {
|
||||
throw new Error('Forbidden event name: ' + event);
|
||||
}
|
||||
this.hls.on(event, this.onEvent);
|
||||
}.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
unregisterListeners() {
|
||||
if (this.isEventHandler()) {
|
||||
this.handledEvents.forEach(function(event) {
|
||||
this.hls.off(event, this.onEvent);
|
||||
}.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* arguments: event (string), data (any)
|
||||
*/
|
||||
onEvent(event, data) {
|
||||
this.onEventGeneric(event, data);
|
||||
}
|
||||
|
||||
onEventGeneric(event, data) {
|
||||
var eventToFunction = function(event, data) {
|
||||
var funcName = 'on' + event.replace('hls', '');
|
||||
if (typeof this[funcName] !== 'function') {
|
||||
throw new Error(`Event ${event} has no generic handler in this ${this.constructor.name} class (tried ${funcName})`);
|
||||
}
|
||||
return this[funcName].bind(this, data);
|
||||
};
|
||||
eventToFunction.call(this, event, data).call();
|
||||
}
|
||||
}
|
||||
|
||||
export default EventHandler;
|
|
@ -1,4 +1,4 @@
|
|||
export default {
|
||||
module.exports = {
|
||||
// fired before MediaSource is attaching to media element - data: { media }
|
||||
MEDIA_ATTACHING: 'hlsMediaAttaching',
|
||||
// fired when MediaSource has been succesfully attached to media element - data: { }
|
||||
|
@ -20,7 +20,7 @@ export default {
|
|||
// fired when a level's details have been updated based on previous details, after it has been loaded. - data: { details : levelDetails object, level : id of updated level }
|
||||
LEVEL_UPDATED: 'hlsLevelUpdated',
|
||||
// fired when a level's PTS information has been updated after parsing a fragment - data: { details : levelDetails object, level : id of updated level, drift: PTS drift observed when parsing last fragment }
|
||||
LEVEL_PTS_UPDATED: 'hlsPTSUpdated',
|
||||
LEVEL_PTS_UPDATED: 'hlsLevelPtsUpdated',
|
||||
// fired when a level switch is requested - data: { level : id of new level }
|
||||
LEVEL_SWITCH: 'hlsLevelSwitch',
|
||||
// fired when a fragment loading starts - data: { frag : fragment object}
|
||||
|
@ -34,7 +34,7 @@ export default {
|
|||
// fired when Init Segment has been extracted from fragment - data: { moov : moov MP4 box, codecs : codecs found while parsing fragment}
|
||||
FRAG_PARSING_INIT_SEGMENT: 'hlsFragParsingInitSegment',
|
||||
// fired when parsing id3 is completed - data: { samples : [ id3 samples pes ] }
|
||||
FRAG_PARSING_METADATA: 'hlsFraParsingMetadata',
|
||||
FRAG_PARSING_METADATA: 'hlsFragParsingMetadata',
|
||||
// fired when moof/mdat have been extracted from fragment - data: { moof : moof MP4 box, mdat : mdat MP4 box}
|
||||
FRAG_PARSING_DATA: 'hlsFragParsingData',
|
||||
// fired when fragment parsing is completed - data: undefined
|
||||
|
@ -44,7 +44,7 @@ export default {
|
|||
// fired when fragment matching with current media position is changing - data : { frag : fragment object }
|
||||
FRAG_CHANGED: 'hlsFragChanged',
|
||||
// Identifier for a FPS drop event - data: {curentDropped, currentDecoded, totalDroppedFrames}
|
||||
FPS_DROP: 'hlsFPSDrop',
|
||||
FPS_DROP: 'hlsFpsDrop',
|
||||
// Identifier for an error event - data: { type : error type, details : error details, fatal : if true, hls.js cannot/will not try to recover, if false, hls.js will try to recover,other error specific data}
|
||||
ERROR: 'hlsError',
|
||||
// fired when hls.js instance starts destroying. Different from MEDIA_DETACHED as one could want to detach and reattach a media to the instance of hls.js to handle mid-rolls for example
|
||||
|
|
|
@ -41,6 +41,8 @@ class Hls {
|
|||
debug: false,
|
||||
maxBufferLength: 30,
|
||||
maxBufferSize: 60 * 1000 * 1000,
|
||||
maxBufferHole: 0.3,
|
||||
maxSeekHole: 2,
|
||||
liveSyncDurationCount:3,
|
||||
liveMaxLatencyDurationCount: Infinity,
|
||||
maxMaxBufferLength: 600,
|
||||
|
|
|
@ -3,14 +3,13 @@
|
|||
*/
|
||||
|
||||
import Event from '../events';
|
||||
import EventHandler from '../event-handler';
|
||||
import {ErrorTypes, ErrorDetails} from '../errors';
|
||||
|
||||
class FragmentLoader {
|
||||
class FragmentLoader extends EventHandler {
|
||||
|
||||
constructor(hls) {
|
||||
this.hls = hls;
|
||||
this.onfl = this.onFragLoading.bind(this);
|
||||
hls.on(Event.FRAG_LOADING, this.onfl);
|
||||
super(hls, Event.FRAG_LOADING);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
|
@ -18,10 +17,10 @@ class FragmentLoader {
|
|||
this.loader.destroy();
|
||||
this.loader = null;
|
||||
}
|
||||
this.hls.off(Event.FRAG_LOADING, this.onfl);
|
||||
EventHandler.prototype.destroy.call(this);
|
||||
}
|
||||
|
||||
onFragLoading(event, data) {
|
||||
onFragLoading(data) {
|
||||
var frag = data.frag;
|
||||
this.frag = frag;
|
||||
this.frag.loaded = 0;
|
||||
|
|
|
@ -3,16 +3,15 @@
|
|||
*/
|
||||
|
||||
import Event from '../events';
|
||||
import EventHandler from '../event-handler';
|
||||
import {ErrorTypes, ErrorDetails} from '../errors';
|
||||
|
||||
class KeyLoader {
|
||||
class KeyLoader extends EventHandler {
|
||||
|
||||
constructor(hls) {
|
||||
this.hls = hls;
|
||||
super(hls, Event.KEY_LOADING);
|
||||
this.decryptkey = null;
|
||||
this.decrypturl = null;
|
||||
this.ondkl = this.onDecryptKeyLoading.bind(this);
|
||||
hls.on(Event.KEY_LOADING, this.ondkl);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
|
@ -20,10 +19,10 @@ class KeyLoader {
|
|||
this.loader.destroy();
|
||||
this.loader = null;
|
||||
}
|
||||
this.hls.off(Event.KEY_LOADING, this.ondkl);
|
||||
EventHandler.prototype.destroy.call(this);
|
||||
}
|
||||
|
||||
onDecryptKeyLoading(event, data) {
|
||||
onKeyLoading(data) {
|
||||
var frag = this.frag = data.frag,
|
||||
decryptdata = frag.decryptdata,
|
||||
uri = decryptdata.uri;
|
||||
|
|
|
@ -3,19 +3,18 @@
|
|||
*/
|
||||
|
||||
import Event from '../events';
|
||||
import EventHandler from '../event-handler';
|
||||
import {ErrorTypes, ErrorDetails} from '../errors';
|
||||
import URLHelper from '../utils/url';
|
||||
import AttrList from '../utils/attr-list';
|
||||
//import {logger} from '../utils/logger';
|
||||
|
||||
class PlaylistLoader {
|
||||
class PlaylistLoader extends EventHandler {
|
||||
|
||||
constructor(hls) {
|
||||
this.hls = hls;
|
||||
this.onml = this.onManifestLoading.bind(this);
|
||||
this.onll = this.onLevelLoading.bind(this);
|
||||
hls.on(Event.MANIFEST_LOADING, this.onml);
|
||||
hls.on(Event.LEVEL_LOADING, this.onll);
|
||||
super(hls,
|
||||
Event.MANIFEST_LOADING,
|
||||
Event.LEVEL_LOADING);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
|
@ -24,15 +23,14 @@ class PlaylistLoader {
|
|||
this.loader = null;
|
||||
}
|
||||
this.url = this.id = null;
|
||||
this.hls.off(Event.MANIFEST_LOADING, this.onml);
|
||||
this.hls.off(Event.LEVEL_LOADING, this.onll);
|
||||
EventHandler.prototype.destroy.call(this);
|
||||
}
|
||||
|
||||
onManifestLoading(event, data) {
|
||||
onManifestLoading(data) {
|
||||
this.load(data.url, null);
|
||||
}
|
||||
|
||||
onLevelLoading(event, data) {
|
||||
onLevelLoading(data) {
|
||||
this.load(data.url, data.level, data.id);
|
||||
}
|
||||
|
||||
|
|
|
@ -129,6 +129,7 @@ class MP4Remuxer {
|
|||
mdat, moof,
|
||||
firstPTS, firstDTS, lastDTS,
|
||||
pts, dts, ptsnorm, dtsnorm,
|
||||
flags,
|
||||
samples = [];
|
||||
/* concatenate the video data and construct the mdat in place
|
||||
(need 8 more bytes to fill length and mpdat type) */
|
||||
|
@ -152,7 +153,7 @@ class MP4Remuxer {
|
|||
dts = avcSample.dts - this._initDTS;
|
||||
// ensure DTS is not bigger than PTS
|
||||
dts = Math.min(pts,dts);
|
||||
//logger.log(`Video/PTS/DTS:${pts}/${dts}`);
|
||||
//logger.log(`Video/PTS/DTS:${Math.round(pts/90)}/${Math.round(dts/90)}`);
|
||||
// if not first AVC sample of video track, normalize PTS/DTS with previous sample value
|
||||
// and ensure that sample duration is positive
|
||||
if (lastDTS !== undefined) {
|
||||
|
@ -201,13 +202,14 @@ class MP4Remuxer {
|
|||
degradPrio: 0
|
||||
}
|
||||
};
|
||||
flags = mp4Sample.flags;
|
||||
if (avcSample.key === true) {
|
||||
// the current sample is a key frame
|
||||
mp4Sample.flags.dependsOn = 2;
|
||||
mp4Sample.flags.isNonSync = 0;
|
||||
flags.dependsOn = 2;
|
||||
flags.isNonSync = 0;
|
||||
} else {
|
||||
mp4Sample.flags.dependsOn = 1;
|
||||
mp4Sample.flags.isNonSync = 1;
|
||||
flags.dependsOn = 1;
|
||||
flags.isNonSync = 1;
|
||||
}
|
||||
samples.push(mp4Sample);
|
||||
lastDTS = dtsnorm;
|
||||
|
@ -222,7 +224,7 @@ class MP4Remuxer {
|
|||
track.len = 0;
|
||||
track.nbNalu = 0;
|
||||
if(samples.length && navigator.userAgent.toLowerCase().indexOf('chrome') > -1) {
|
||||
var flags = samples[0].flags;
|
||||
flags = samples[0].flags;
|
||||
// chrome workaround, mark first sample as being a Random Access Point to avoid sourcebuffer append issue
|
||||
// https://code.google.com/p/chromium/issues/detail?id=229412
|
||||
flags.dependsOn = 2;
|
||||
|
@ -270,7 +272,7 @@ class MP4Remuxer {
|
|||
unit = aacSample.unit;
|
||||
pts = aacSample.pts - this._initDTS;
|
||||
dts = aacSample.dts - this._initDTS;
|
||||
//logger.log(`Audio/PTS:${aacSample.pts.toFixed(0)}`);
|
||||
//logger.log(`Audio/PTS:${Math.round(pts/90)}`);
|
||||
// if not first sample
|
||||
if (lastDTS !== undefined) {
|
||||
ptsnorm = this._PTSNormalize(pts, lastDTS);
|
||||
|
|
|
@ -49,7 +49,7 @@ class XhrLoader {
|
|||
|
||||
loadInternal() {
|
||||
var xhr = this.loader = new XMLHttpRequest();
|
||||
xhr.onreadystatechange = this.statechange.bind(this);
|
||||
xhr.onloadend = this.loadend.bind(this);
|
||||
xhr.onprogress = this.loadprogress.bind(this);
|
||||
|
||||
xhr.open('GET', this.url, true);
|
||||
|
@ -65,13 +65,12 @@ class XhrLoader {
|
|||
xhr.send();
|
||||
}
|
||||
|
||||
statechange(event) {
|
||||
loadend(event) {
|
||||
var xhr = event.currentTarget,
|
||||
status = xhr.status,
|
||||
stats = this.stats;
|
||||
// don't proceed if xhr has been aborted
|
||||
// 4 = Response from server has been completely loaded.
|
||||
if (!stats.aborted && xhr.readyState === 4) {
|
||||
if (!stats.aborted) {
|
||||
// http status between 200 to 299 are all successful
|
||||
if (status >= 200 && status < 300) {
|
||||
window.clearTimeout(this.timeoutHandle);
|
||||
|
|
|
@ -29,14 +29,14 @@
|
|||
"webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
|
||||
},
|
||||
"ignore": [],
|
||||
"homepage": "https://github.com/polymerelements/iron-behaviors",
|
||||
"homepage": "https://github.com/PolymerElements/iron-behaviors",
|
||||
"_release": "1.0.12",
|
||||
"_resolution": {
|
||||
"type": "version",
|
||||
"tag": "v1.0.12",
|
||||
"commit": "657f526a2382a659cdf4e13be87ecc89261588a3"
|
||||
},
|
||||
"_source": "git://github.com/polymerelements/iron-behaviors.git",
|
||||
"_source": "git://github.com/PolymerElements/iron-behaviors.git",
|
||||
"_target": "^1.0.0",
|
||||
"_originalSource": "polymerelements/iron-behaviors"
|
||||
"_originalSource": "PolymerElements/iron-behaviors"
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "paper-input",
|
||||
"version": "1.1.4",
|
||||
"version": "1.1.5",
|
||||
"description": "Material design text fields",
|
||||
"authors": [
|
||||
"The Polymer Authors"
|
||||
|
@ -44,14 +44,14 @@
|
|||
"iron-validator-behavior": "PolymerElements/iron-validator-behavior#^1.0.0",
|
||||
"paper-icon-button": "PolymerElements/paper-icon-button#^1.0.0",
|
||||
"test-fixture": "PolymerElements/test-fixture#^1.0.0",
|
||||
"web-component-tester": "Polymer/web-component-tester#^3.4.0",
|
||||
"web-component-tester": "^4.0.0",
|
||||
"webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
|
||||
},
|
||||
"_release": "1.1.4",
|
||||
"_release": "1.1.5",
|
||||
"_resolution": {
|
||||
"type": "version",
|
||||
"tag": "v1.1.4",
|
||||
"commit": "8ca01ac3cafc61abd980d262875ffca0c79640fa"
|
||||
"tag": "v1.1.5",
|
||||
"commit": "0aa8318b5e026688f94c78c7673acabf5bad0f17"
|
||||
},
|
||||
"_source": "git://github.com/polymerelements/paper-input.git",
|
||||
"_target": "^1.0.9",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "paper-input",
|
||||
"version": "1.1.4",
|
||||
"version": "1.1.5",
|
||||
"description": "Material design text fields",
|
||||
"authors": [
|
||||
"The Polymer Authors"
|
||||
|
@ -44,7 +44,7 @@
|
|||
"iron-validator-behavior": "PolymerElements/iron-validator-behavior#^1.0.0",
|
||||
"paper-icon-button": "PolymerElements/paper-icon-button#^1.0.0",
|
||||
"test-fixture": "PolymerElements/test-fixture#^1.0.0",
|
||||
"web-component-tester": "Polymer/web-component-tester#^3.4.0",
|
||||
"web-component-tester": "^4.0.0",
|
||||
"webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||
*/
|
||||
|
||||
/**
|
||||
* The label for this input. Bind this to `<label>`'s content and `hidden` property, e.g.
|
||||
* The label for this input. If you're using PaperInputBehavior to
|
||||
* implement your own paper-input-like element, bind this to
|
||||
* `<label>`'s content and `hidden` property, e.g.
|
||||
* `<label hidden$="[[!label]]">[[label]]</label>` in your `template`
|
||||
*/
|
||||
label: {
|
||||
|
@ -40,7 +42,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||
},
|
||||
|
||||
/**
|
||||
* The value for this input. Bind this to the `<input is="iron-input">`'s `bindValue`
|
||||
* The value for this input. If you're using PaperInputBehavior to
|
||||
* implement your own paper-input-like element, bind this to
|
||||
* the `<input is="iron-input">`'s `bindValue`
|
||||
* property, or the value property of your input that is `notify:true`.
|
||||
*/
|
||||
value: {
|
||||
|
@ -49,8 +53,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||
},
|
||||
|
||||
/**
|
||||
* Set to true to disable this input. Bind this to both the `<paper-input-container>`'s
|
||||
* and the input's `disabled` property.
|
||||
* Set to true to disable this input. If you're using PaperInputBehavior to
|
||||
* implement your own paper-input-like element, bind this to
|
||||
* both the `<paper-input-container>`'s and the input's `disabled` property.
|
||||
*/
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
|
@ -58,9 +63,10 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||
},
|
||||
|
||||
/**
|
||||
* Returns true if the value is invalid. Bind this to both the `<paper-input-container>`'s
|
||||
* and the input's `invalid` property.
|
||||
*
|
||||
* Returns true if the value is invalid. If you're using PaperInputBehavior to
|
||||
* implement your own paper-input-like element, bind this to both the
|
||||
* `<paper-input-container>`'s and the input's `invalid` property.
|
||||
*
|
||||
* If `autoValidate` is true, the `invalid` attribute is managed automatically,
|
||||
* which can clobber attempts to manage it manually.
|
||||
*/
|
||||
|
@ -71,48 +77,55 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||
},
|
||||
|
||||
/**
|
||||
* Set to true to prevent the user from entering invalid input. Bind this to the
|
||||
* `<input is="iron-input">`'s `preventInvalidInput` property.
|
||||
* Set to true to prevent the user from entering invalid input. If you're
|
||||
* using PaperInputBehavior to implement your own paper-input-like element,
|
||||
* bind this to `<input is="iron-input">`'s `preventInvalidInput` property.
|
||||
*/
|
||||
preventInvalidInput: {
|
||||
type: Boolean
|
||||
},
|
||||
|
||||
/**
|
||||
* Set this to specify the pattern allowed by `preventInvalidInput`. Bind this to the
|
||||
* `<input is="iron-input">`'s `allowedPattern` property.
|
||||
* Set this to specify the pattern allowed by `preventInvalidInput`. If
|
||||
* you're using PaperInputBehavior to implement your own paper-input-like
|
||||
* element, bind this to the `<input is="iron-input">`'s `allowedPattern`
|
||||
* property.
|
||||
*/
|
||||
allowedPattern: {
|
||||
type: String
|
||||
},
|
||||
|
||||
/**
|
||||
* The type of the input. The supported types are `text`, `number` and `password`. Bind this
|
||||
* to the `<input is="iron-input">`'s `type` property.
|
||||
* The type of the input. The supported types are `text`, `number` and `password`.
|
||||
* If you're using PaperInputBehavior to implement your own paper-input-like element,
|
||||
* bind this to the `<input is="iron-input">`'s `type` property.
|
||||
*/
|
||||
type: {
|
||||
type: String
|
||||
},
|
||||
|
||||
/**
|
||||
* The datalist of the input (if any). This should match the id of an existing `<datalist>`. Bind this
|
||||
* to the `<input is="iron-input">`'s `list` property.
|
||||
* The datalist of the input (if any). This should match the id of an existing `<datalist>`.
|
||||
* If you're using PaperInputBehavior to implement your own paper-input-like
|
||||
* element, bind this to the `<input is="iron-input">`'s `list` property.
|
||||
*/
|
||||
list: {
|
||||
type: String
|
||||
},
|
||||
|
||||
/**
|
||||
* A pattern to validate the `input` with. Bind this to the `<input is="iron-input">`'s
|
||||
* `pattern` property.
|
||||
* A pattern to validate the `input` with. If you're using PaperInputBehavior to
|
||||
* implement your own paper-input-like element, bind this to
|
||||
* the `<input is="iron-input">`'s `pattern` property.
|
||||
*/
|
||||
pattern: {
|
||||
type: String
|
||||
},
|
||||
|
||||
/**
|
||||
* Set to true to mark the input as required. Bind this to the `<input is="iron-input">`'s
|
||||
* `required` property.
|
||||
* Set to true to mark the input as required. If you're using PaperInputBehavior to
|
||||
* implement your own paper-input-like element, bind this to
|
||||
* the `<input is="iron-input">`'s `required` property.
|
||||
*/
|
||||
required: {
|
||||
type: Boolean,
|
||||
|
@ -120,8 +133,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||
},
|
||||
|
||||
/**
|
||||
* The error message to display when the input is invalid. Bind this to the
|
||||
* `<paper-input-error>`'s content, if using.
|
||||
* The error message to display when the input is invalid. If you're using
|
||||
* PaperInputBehavior to implement your own paper-input-like element,
|
||||
* bind this to the `<paper-input-error>`'s content, if using.
|
||||
*/
|
||||
errorMessage: {
|
||||
type: String
|
||||
|
@ -136,8 +150,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||
},
|
||||
|
||||
/**
|
||||
* Set to true to disable the floating label. Bind this to the `<paper-input-container>`'s
|
||||
* `noLabelFloat` property.
|
||||
* Set to true to disable the floating label. If you're using PaperInputBehavior to
|
||||
* implement your own paper-input-like element, bind this to
|
||||
* the `<paper-input-container>`'s `noLabelFloat` property.
|
||||
*/
|
||||
noLabelFloat: {
|
||||
type: Boolean,
|
||||
|
@ -145,8 +160,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||
},
|
||||
|
||||
/**
|
||||
* Set to true to always float the label. Bind this to the `<paper-input-container>`'s
|
||||
* `alwaysFloatLabel` property.
|
||||
* Set to true to always float the label. If you're using PaperInputBehavior to
|
||||
* implement your own paper-input-like element, bind this to
|
||||
* the `<paper-input-container>`'s `alwaysFloatLabel` property.
|
||||
*/
|
||||
alwaysFloatLabel: {
|
||||
type: Boolean,
|
||||
|
@ -154,8 +170,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||
},
|
||||
|
||||
/**
|
||||
* Set to true to auto-validate the input value. Bind this to the `<paper-input-container>`'s
|
||||
* `autoValidate` property.
|
||||
* Set to true to auto-validate the input value. If you're using PaperInputBehavior to
|
||||
* implement your own paper-input-like element, bind this to
|
||||
* the `<paper-input-container>`'s `autoValidate` property.
|
||||
*/
|
||||
autoValidate: {
|
||||
type: Boolean,
|
||||
|
@ -163,8 +180,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||
},
|
||||
|
||||
/**
|
||||
* Name of the validator to use. Bind this to the `<input is="iron-input">`'s `validator`
|
||||
* property.
|
||||
* Name of the validator to use. If you're using PaperInputBehavior to
|
||||
* implement your own paper-input-like element, bind this to
|
||||
* the `<input is="iron-input">`'s `validator` property.
|
||||
*/
|
||||
validator: {
|
||||
type: String
|
||||
|
@ -173,7 +191,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||
// HTMLInputElement attributes for binding if needed
|
||||
|
||||
/**
|
||||
* Bind this to the `<input is="iron-input">`'s `autocomplete` property.
|
||||
* If you're using PaperInputBehavior to implement your own paper-input-like
|
||||
* element, bind this to the `<input is="iron-input">`'s `autocomplete` property.
|
||||
*/
|
||||
autocomplete: {
|
||||
type: String,
|
||||
|
@ -181,29 +200,34 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||
},
|
||||
|
||||
/**
|
||||
* Bind this to the `<input is="iron-input">`'s `autofocus` property.
|
||||
* If you're using PaperInputBehavior to implement your own paper-input-like
|
||||
* element, bind this to the `<input is="iron-input">`'s `autofocus` property.
|
||||
*/
|
||||
autofocus: {
|
||||
type: Boolean
|
||||
},
|
||||
|
||||
/**
|
||||
* Bind this to the `<input is="iron-input">`'s `inputmode` property.
|
||||
* If you're using PaperInputBehavior to implement your own paper-input-like
|
||||
* element, bind this to the `<input is="iron-input">`'s `inputmode` property.
|
||||
*/
|
||||
inputmode: {
|
||||
type: String
|
||||
},
|
||||
|
||||
/**
|
||||
* Bind this to the `<input is="iron-input">`'s `minlength` property.
|
||||
* The minimum length of the input value.
|
||||
* If you're using PaperInputBehavior to implement your own paper-input-like
|
||||
* element, bind this to the `<input is="iron-input">`'s `minlength` property.
|
||||
*/
|
||||
minlength: {
|
||||
type: Number
|
||||
},
|
||||
|
||||
/**
|
||||
* The maximum length of the input value. Bind this to the `<input is="iron-input">`'s
|
||||
* `maxlength` property.
|
||||
* The maximum length of the input value.
|
||||
* If you're using PaperInputBehavior to implement your own paper-input-like
|
||||
* element, bind this to the `<input is="iron-input">`'s `maxlength` property.
|
||||
*/
|
||||
maxlength: {
|
||||
type: Number
|
||||
|
@ -211,7 +235,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||
|
||||
/**
|
||||
* The minimum (numeric or date-time) input value.
|
||||
* Bind this to the `<input is="iron-input">`'s `min` property.
|
||||
* If you're using PaperInputBehavior to implement your own paper-input-like
|
||||
* element, bind this to the `<input is="iron-input">`'s `min` property.
|
||||
*/
|
||||
min: {
|
||||
type: String
|
||||
|
@ -220,7 +245,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||
/**
|
||||
* The maximum (numeric or date-time) input value.
|
||||
* Can be a String (e.g. `"2000-1-1"`) or a Number (e.g. `2`).
|
||||
* Bind this to the `<input is="iron-input">`'s `max` property.
|
||||
* If you're using PaperInputBehavior to implement your own paper-input-like
|
||||
* element, bind this to the `<input is="iron-input">`'s `max` property.
|
||||
*/
|
||||
max: {
|
||||
type: String
|
||||
|
@ -228,14 +254,16 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||
|
||||
/**
|
||||
* Limits the numeric or date-time increments.
|
||||
* Bind this to the `<input is="iron-input">`'s `step` property.
|
||||
* If you're using PaperInputBehavior to implement your own paper-input-like
|
||||
* element, bind this to the `<input is="iron-input">`'s `step` property.
|
||||
*/
|
||||
step: {
|
||||
type: String
|
||||
},
|
||||
|
||||
/**
|
||||
* Bind this to the `<input is="iron-input">`'s `name` property.
|
||||
* If you're using PaperInputBehavior to implement your own paper-input-like
|
||||
* element, bind this to the `<input is="iron-input">`'s `name` property.
|
||||
*/
|
||||
name: {
|
||||
type: String
|
||||
|
@ -251,7 +279,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||
},
|
||||
|
||||
/**
|
||||
* Bind this to the `<input is="iron-input">`'s `readonly` property.
|
||||
* If you're using PaperInputBehavior to implement your own paper-input-like
|
||||
* element, bind this to the `<input is="iron-input">`'s `readonly` property.
|
||||
*/
|
||||
readonly: {
|
||||
type: Boolean,
|
||||
|
@ -259,7 +288,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||
},
|
||||
|
||||
/**
|
||||
* Bind this to the `<input is="iron-input">`'s `size` property.
|
||||
* If you're using PaperInputBehavior to implement your own paper-input-like
|
||||
* element, bind this to the `<input is="iron-input">`'s `size` property.
|
||||
*/
|
||||
size: {
|
||||
type: Number
|
||||
|
@ -268,7 +298,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||
// Nonstandard attributes for binding if needed
|
||||
|
||||
/**
|
||||
* Bind this to the `<input is="iron-input">`'s `autocapitalize` property.
|
||||
* If you're using PaperInputBehavior to implement your own paper-input-like
|
||||
* element, bind this to the `<input is="iron-input">`'s `autocapitalize` property.
|
||||
*/
|
||||
autocapitalize: {
|
||||
type: String,
|
||||
|
@ -276,7 +307,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||
},
|
||||
|
||||
/**
|
||||
* Bind this to the `<input is="iron-input">`'s `autocorrect` property.
|
||||
* If you're using PaperInputBehavior to implement your own paper-input-like
|
||||
* element, bind this to the `<input is="iron-input">`'s `autocorrect` property.
|
||||
*/
|
||||
autocorrect: {
|
||||
type: String,
|
||||
|
@ -284,28 +316,36 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||
},
|
||||
|
||||
/**
|
||||
* Bind this to the `<input is="iron-input">`'s `autosave` property, used with type=search.
|
||||
* If you're using PaperInputBehavior to implement your own paper-input-like
|
||||
* element, bind this to the `<input is="iron-input">`'s `autosave` property,
|
||||
* used with type=search.
|
||||
*/
|
||||
autosave: {
|
||||
type: String
|
||||
},
|
||||
|
||||
/**
|
||||
* Bind this to the `<input is="iron-input">`'s `results` property, used with type=search.
|
||||
* If you're using PaperInputBehavior to implement your own paper-input-like
|
||||
* element, bind this to the `<input is="iron-input">`'s `results` property,
|
||||
* used with type=search.
|
||||
*/
|
||||
results: {
|
||||
type: Number
|
||||
},
|
||||
|
||||
/**
|
||||
* Bind this to the `<input is="iron-input">`'s `accept` property, used with type=file.
|
||||
* If you're using PaperInputBehavior to implement your own paper-input-like
|
||||
* element, bind this to the `<input is="iron-input">`'s `accept` property,
|
||||
* used with type=file.
|
||||
*/
|
||||
accept: {
|
||||
type: String
|
||||
},
|
||||
|
||||
/**
|
||||
* Bind this to the `<input is="iron-input">`'s `multiple` property, used with type=file.
|
||||
* If you're using PaperInputBehavior to implement your own paper-input-like
|
||||
* element, bind this to the`<input is="iron-input">`'s `multiple` property,
|
||||
* used with type=file.
|
||||
*/
|
||||
multiple: {
|
||||
type: Boolean
|
||||
|
@ -354,8 +394,20 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||
return this.inputElement;
|
||||
},
|
||||
|
||||
registered: function() {
|
||||
// These types have some default placeholder text; overlapping
|
||||
// the label on top of it looks terrible. Auto-float the label in this case.
|
||||
this._typesThatHaveText = ["date", "datetime", "datetime-local", "month",
|
||||
"time", "week", "file"];
|
||||
},
|
||||
|
||||
attached: function() {
|
||||
this._updateAriaLabelledBy();
|
||||
|
||||
if (this.inputElement &&
|
||||
this._typesThatHaveText.indexOf(this.inputElement.type) !== -1) {
|
||||
this.alwaysFloatLabel = true;
|
||||
}
|
||||
},
|
||||
|
||||
_appendStringWithSpace: function(str, more) {
|
||||
|
|
|
@ -39,9 +39,10 @@ for `suffix`).
|
|||
</paper-input>
|
||||
|
||||
A `paper-input` can use the native `type=search` or `type=file` features.
|
||||
However, since we can't control the native styling of the input, in these cases
|
||||
it's recommended to use a placeholder text, or `always-float-label`,
|
||||
as to not overlap the native UI (search icon, file button, etc.).
|
||||
However, since we can't control the native styling of the input (search icon,
|
||||
file button, date placeholder, etc.), in these cases the label will be
|
||||
automatically floated. The `placeholder` attribute can still be used for
|
||||
additional informational text.
|
||||
|
||||
<paper-input label="search!" type="search"
|
||||
placeholder="search for cats" autosave="test" results="5">
|
||||
|
@ -100,6 +101,7 @@ style this element.
|
|||
aria-labelledby$="[[_ariaLabelledBy]]"
|
||||
aria-describedby$="[[_ariaDescribedBy]]"
|
||||
disabled$="[[disabled]]"
|
||||
title$="[[title]]"
|
||||
bind-value="{{value}}"
|
||||
invalid="{{invalid}}"
|
||||
prevent-invalid-input="[[preventInvalidInput]]"
|
||||
|
|
|
@ -70,7 +70,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||
</template>
|
||||
</test-fixture>
|
||||
|
||||
|
||||
<test-fixture id="required-char-counter">
|
||||
<template>
|
||||
<paper-input auto-validate char-counter required error-message="error"></paper-input>
|
||||
|
@ -95,6 +94,12 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||
</template>
|
||||
</test-fixture>
|
||||
|
||||
<test-fixture id="date">
|
||||
<template>
|
||||
<paper-input label="foo" type="date"></paper-input>
|
||||
</template>
|
||||
</test-fixture>
|
||||
|
||||
<letters-only></letters-only>
|
||||
|
||||
<test-fixture id="validator">
|
||||
|
@ -121,6 +126,18 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||
assert.ok(floatingLabel);
|
||||
});
|
||||
|
||||
test('special types autofloat the label', function() {
|
||||
var input = fixture('date');
|
||||
// Browsers that don't support special <input> types like `date` fallback
|
||||
// to `text`, so make sure to only test if type is still preserved after
|
||||
// the element is attached.
|
||||
if (input.inputElement.type === "date") {
|
||||
assert.equal(input.alwaysFloatLabel, true);
|
||||
var floatingLabel = Polymer.dom(Polymer.dom(input.root).querySelector('paper-input-container').root).querySelector('.label-is-floating');
|
||||
assert.ok(floatingLabel);
|
||||
}
|
||||
});
|
||||
|
||||
test('always-float-label attribute works without placeholder', function() {
|
||||
var input = fixture('always-float-label');
|
||||
var container = Polymer.dom(input.root).querySelector('paper-input-container');
|
||||
|
|
|
@ -24,14 +24,14 @@
|
|||
"web-component-tester": "*"
|
||||
},
|
||||
"private": true,
|
||||
"homepage": "https://github.com/polymer/polymer",
|
||||
"homepage": "https://github.com/Polymer/polymer",
|
||||
"_release": "1.2.3",
|
||||
"_resolution": {
|
||||
"type": "version",
|
||||
"tag": "v1.2.3",
|
||||
"commit": "aa535d1675342007cbf64dc9c66497cf74cbc616"
|
||||
},
|
||||
"_source": "git://github.com/polymer/polymer.git",
|
||||
"_source": "git://github.com/Polymer/polymer.git",
|
||||
"_target": "^1.0.0",
|
||||
"_originalSource": "polymer/polymer"
|
||||
"_originalSource": "Polymer/polymer"
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue