nsplayer
Version:
NSPlayer, a player which supports quality list of dash and hls
312 lines (247 loc) • 11.3 kB
JavaScript
'use strict';
var global = typeof self !== 'undefined' ? self : globalThis;
var _defineProperty = require('@babel/runtime/helpers/defineProperty');
var index = require('./index-773e68b1.js');
var shaka = require('shaka-player');
var common = require('@newstudios/common');
require('delegates');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var _defineProperty__default = /*#__PURE__*/_interopDefaultLegacy(_defineProperty);
var shaka__default = /*#__PURE__*/_interopDefaultLegacy(shaka);
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty__default["default"](target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
class ShakaPlayer extends index.CorePlayer {
// private _maxWidth = 1e5
// private _maxHeight = 1e5
constructor(video, source, _fastSwitch = true, // private _capLevelToPlayerSize = false
capLevelToPlayerSize = false) {
super(video, source);
_defineProperty__default["default"](this, "_videoSizeObserverTimer", this._register(new common.IntervalTimer()));
_defineProperty__default["default"](this, "_initialBitrateMutable", this._register(new common.MutableDisposable()));
_defineProperty__default["default"](this, "_videoWidth", 0);
_defineProperty__default["default"](this, "_videoHeight", 0);
_defineProperty__default["default"](this, "_bufferMutable", this._register(new common.MutableDisposable()));
_defineProperty__default["default"](this, "_onVideoLevelSwitched", this._register(new common.Emitter()));
_defineProperty__default["default"](this, "onVideoLevelSwitched", this._onVideoLevelSwitched.event);
_defineProperty__default["default"](this, "videoSizeHandler", () => {
let changed = false;
if (this._videoWidth !== this.video.videoWidth) {
this._videoWidth = this.video.videoWidth;
changed = true;
}
if (this._videoHeight !== this.video.videoHeight) {
this._videoHeight = this.video.videoHeight;
changed = true;
}
if (changed && !isNaN(this._videoWidth) && !isNaN(this._videoHeight)) {
this._onVideoLevelSwitched.fire();
} // // capLevelToPlayerSize
// const maxWidth = this._capLevelToPlayerSize
// ? this.video.clientWidth * this.devicePixelRatio
// : 1e5
// const maxHeight = this._capLevelToPlayerSize
// ? this.video.clientHeight * this.devicePixelRatio
// : 1e5
// if (maxWidth !== this._maxWidth && !isNaN(maxWidth)) {
// this._maxWidth = maxWidth
// this._shakaPlayer.configure('abr.restrictions.maxWidth', maxWidth)
// }
// if (maxHeight !== this._maxHeight && !isNaN(maxHeight)) {
// this._maxHeight = maxHeight
// this._shakaPlayer.configure('abr.restrictions.maxHeight', maxHeight)
// }
});
this._fastSwitch = _fastSwitch;
const player = new shaka__default["default"].Player();
this._shakaPlayer = player; // https://github.com/google/shaka-player/pull/2330/commits/4f8e1286610e4ae667f0bb82f4f4fa97b451595c
this._shakaPlayer.configure({
manifest: {
dash: {
ignoreEmptyAdaptationSet: true,
ignoreMinBufferTime: true
}
},
streaming: {
bufferingGoal: 15,
inaccurateManifestTolerance: 1
},
abr: {
restrictToElementSize: capLevelToPlayerSize,
restrictToScreenSize: capLevelToPlayerSize
}
});
this.debugError();
this._register(common.toDisposable(() => player.destroy()));
}
debugError() {
const onError = common.Event.fromDOMEventEmitter(this._shakaPlayer, 'error');
this._register(onError(err => {
var _err$detail;
return console.warn('shaka error', ((_err$detail = err.detail) === null || _err$detail === void 0 ? void 0 : _err$detail.message) || '');
}));
}
startObserveVideoSize() {
this._videoSizeObserverTimer.cancelAndSet(this.videoSizeHandler, 1000);
}
// private get devicePixelRatio() {
// const w = window as any as Record<string, number>
// return (
// w.devicePixelRatio ||
// w.mozDevicePixelRatio ||
// w.webkitDevicePixelRatio ||
// w.msDevicePixelRatio ||
// 1
// )
// }
stopObserveVideoSize() {
this._videoSizeObserverTimer.cancel();
}
get name() {
return `SHAKAPlayer (${shaka__default["default"].Player.version})`;
}
get supportAutoQuality() {
// return shaka.Player.isBrowserSupported()
return true;
}
get bandwidthEstimate() {
return this._shakaPlayer.getStats().estimatedBandwidth;
}
setInitialBitrate(bitrate) {
// abr control doc https://github.com/shaka-project/shaka-player/issues/629
this._shakaPlayer.configure('abr.defaultBandwidthEstimate', bitrate); // if (this.ready) {
// return
// }
// this._initialBitrateMutable.value = this.onOncePlayListReady(() => {
// let index = 0
// const levels = this.levels
// for (let i = 0; i < levels.length; i++) {
// if ((levels[i].videoBandwidth || levels[i].bandwidth) <= bitrate) {
// index = i
// } else {
// break
// }
// }
// this.log('setInitialBitrate', 'async start level:', index)
// const isAuto = this.autoQualityEnabled
// if (isAuto) {
// this._shakaPlayer.configure('abr.enabled', false)
// }
// this._shakaPlayer.selectVariantTrack(levels[index], true)
// if (isAuto) {
// this._shakaPlayer.configure('abr.enabled', true)
// }
// })
}
setCapLevelToPlayerSize(capLevelToPlayerSize) {
this.log('setCapLevelToPlayerSize', capLevelToPlayerSize);
this._shakaPlayer.configure({
abr: {
restrictToElementSize: capLevelToPlayerSize,
restrictToScreenSize: capLevelToPlayerSize
}
}); // this._capLevelToPlayerSize = capLevelToPlayerSize
}
get capLevelToPlayerSize() {
return this._shakaPlayer.getConfiguration().abr.restrictToElementSize || this._shakaPlayer.getConfiguration().abr.restrictToScreenSize || false; // return this._capLevelToPlayerSize
}
get levels() {
return this._shakaPlayer.getVariantTracks().filter(track => track.type === 'variant' && typeof track.videoId === 'number' && typeof track.videoCodec === 'string');
}
get currentLevel() {
return this._shakaPlayer.getVariantTracks().find(track => track.type === 'variant' && typeof track.videoId === 'number' && track.active);
}
get nextLevel() {
return this._nextTrack;
}
get autoQualityEnabled() {
return this._shakaPlayer.getConfiguration().abr.enabled;
}
levelToQuality(level) {
const fps = index.computeFPS(level.frameRate);
return _objectSpread({
bitrate: typeof level.videoId === 'number' ? level.videoBandwidth || level.bandwidth : typeof level.audioId === 'number' ? level.audioBandwidth || level.bandwidth : level.bandwidth,
width: level.width || 0,
height: level.height || 0,
type: typeof level.videoId === 'number' ? 'video' : typeof level.audioId === 'number' ? 'audio' : undefined
}, fps ? {
fps
} : {});
}
findLevelIndexByQualityLevel(playLevel) {
// bitrate match
const idx = this.levels.findIndex(level => level.bandwidth === playLevel.bitrate);
if (idx >= 0) {
return idx;
} // short side match
const shortSide = Math.min(playLevel.width, playLevel.height);
return this.levels.findIndex(level => Math.min(level.width || 0, level.height || 0) === shortSide);
}
setAutoQualityState(auto) {
this._shakaPlayer.configure('abr.enabled', auto);
if (!auto) {
this._initialBitrateMutable.value = undefined;
}
}
setNextLevelIndex(index) {
const track = this.levels[index];
if (track) {
this._nextTrack = track;
if (this.ready) {
this._shakaPlayer.selectVariantTrack(track, true, this._fastSwitch ? 5 : 8);
} else if (!this.autoQualityEnabled) {
this.log('setNextLevelIndex', 'start level:', index, `${track.width}x${track.height}`);
this._shakaPlayer.selectVariantTrack(track);
}
this._initialBitrateMutable.value = undefined;
}
}
onInit(video, source) {
const player = this._shakaPlayer;
player.attach(video);
player.load(source.src, 0, source.mime);
const disposables = this._register(new common.DisposableStore());
common.Event.fromDOMEventEmitter(video, 'play')(this.startObserveVideoSize, this, disposables);
common.Event.fromDOMEventEmitter(video, 'pause')(this.stopObserveVideoSize, this, disposables);
const onTracksChanged = common.Event.fromDOMEventEmitter(player, 'trackschanged');
const onAutoLevelSwitched = common.Event.fromDOMEventEmitter(player, 'adaptation');
const onLoad = common.Event.fromDOMEventEmitter(player, 'loaded');
const onBuffering = common.Event.fromDOMEventEmitter(player, 'buffering');
const onManualLevelSwitched = common.Event.fromDOMEventEmitter(player, 'variantchanged'); // hack video event, workaround
onBuffering(evt => {
if (evt.buffering) {
this._bufferMutable.value = common.Event.fromDOMEventEmitter(video, ['playing', 'canplaythrough'])(() => {
video.dispatchEvent(new window.Event('waiting'));
});
if (!video.paused) {
video.dispatchEvent(new window.Event('waiting'));
}
} else {
this._bufferMutable.value = undefined;
if (!video.paused) {
video.dispatchEvent(new window.Event('playing'));
}
}
}, null, disposables);
onTracksChanged(this.updatePlayList, this, disposables);
onLoad(() => {
video.autoplay && video.play();
this.setReady();
}, null, disposables);
onAutoLevelSwitched(() => this._nextTrack = this.currentLevel, null, disposables); // FIXME should quote out this because onVideoLevelSwitched is already existed
// onAutoLevelSwitched(this.updateNextQualityLevel, this, disposables)
onManualLevelSwitched(this.updateNextQualityLevel, this, disposables);
this.onVideoLevelSwitched(this.updateQualityLevel, this, disposables);
}
}
_defineProperty__default["default"](ShakaPlayer, "_fixed", function fixPlayer() {
if (typeof window !== 'undefined') {
shaka__default["default"].polyfill.installAll(); // if (shaka.Player.isBrowserSupported()) {
// return true
// } else {
// console.warn('Shaka player not supported')
// }
return true;
}
return false;
}());
exports.ShakaPlayer = ShakaPlayer;