@lahzenegar/video-react
Version:
Video-React is a web video player built from the ground up for an HTML5 world using React library.
309 lines (258 loc) • 9.9 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _typeof2 = require('babel-runtime/helpers/typeof');
var _typeof3 = _interopRequireDefault(_typeof2);
var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of');
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
var _inherits2 = require('babel-runtime/helpers/inherits');
var _inherits3 = _interopRequireDefault(_inherits2);
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _propTypes = require('prop-types');
var _propTypes2 = _interopRequireDefault(_propTypes);
var _hls = require('hls.js');
var _hls2 = _interopRequireDefault(_hls);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var HLSSource = function (_Component) {
(0, _inherits3.default)(HLSSource, _Component);
function HLSSource() {
(0, _classCallCheck3.default)(this, HLSSource);
var _this = (0, _possibleConstructorReturn3.default)(this, (HLSSource.__proto__ || (0, _getPrototypeOf2.default)(HLSSource)).apply(this, arguments));
_this.hls = new _hls2.default(_this.props.hlsOptions);
_this.levelLabels = ['low', 'medium', 'high'];
_this.noAudioTrack = false;
_this.snNumberToReload = undefined;
_this.skipNextOnMediaAttached = false;
_this.skipNextOnManifestParsed = false;
_this.onMediaAttached = _this.onMediaAttached.bind(_this);
_this.onManifestParsed = _this.onManifestParsed.bind(_this);
_this.onHlsError = _this.onHlsError.bind(_this);
_this.onLevelLoaded = _this.onLevelLoaded.bind(_this);
_this.onLevelSwitched = _this.onLevelSwitched.bind(_this);
_this.onLevelSwitching = _this.onLevelSwitching.bind(_this);
_this.onBufferCreated = _this.onBufferCreated.bind(_this);
_this.onFragParsingData = _this.onFragParsingData.bind(_this);
_this.onFragChanged = _this.onFragChanged.bind(_this);
return _this;
}
(0, _createClass3.default)(HLSSource, [{
key: 'componentDidMount',
value: function componentDidMount() {
var video = this.props.video;
if (_hls2.default.isSupported()) {
this.hls.attachMedia(video);
// hls events
this.hls.on(_hls2.default.Events.MEDIA_ATTACHED, this.onMediaAttached);
this.hls.on(_hls2.default.Events.MANIFEST_PARSED, this.onManifestParsed);
this.hls.on(_hls2.default.Events.ERROR, this.onHlsError);
this.hls.on(_hls2.default.Events.LEVEL_LOADED, this.onLevelLoaded);
this.hls.on(_hls2.default.Events.LEVEL_SWITCHED, this.onLevelSwitched);
this.hls.on(_hls2.default.Events.LEVEL_SWITCHING, this.onLevelSwitching);
this.hls.on(_hls2.default.Events.BUFFER_CREATED, this.onBufferCreated);
this.hls.on(_hls2.default.Events.FRAG_PARSING_DATA, this.onFragParsingData);
this.hls.on(_hls2.default.Events.FRAG_CHANGED, this.onFragChanged);
}
}
}, {
key: 'componentWillReceiveProps',
value: function componentWillReceiveProps(nextProps) {
if (this.props.player.activeTrack !== nextProps.player.activeTrack) {
this.hls.nextLevel = nextProps.player.activeTrack;
}
if (this.props.src !== nextProps.src) {
this.hls.stopLoad();
this.hls.loadSource(nextProps.src);
}
}
}, {
key: 'componentWillUnmount',
value: function componentWillUnmount() {
if (this.hls) {
this.hls.destroy();
}
}
}, {
key: 'onMediaAttached',
value: function onMediaAttached() {
if (this.skipNextOnMediaAttached) {
this.skipNextOnMediaAttached = false;
return;
}
var src = this.props.src;
this.hls.loadSource(src);
}
}, {
key: 'onManifestParsed',
value: function onManifestParsed(e, data) {
if (this.skipNextOnManifestParsed) {
this.skipNextOnManifestParsed = false;
return;
}
var actions = this.props.actions;
this.hls.startLoad();
actions.handleManifestParsed(this.hls);
this.buildTrackList(data.levels);
}
}, {
key: 'onLevelLoaded',
value: function onLevelLoaded(e, data) {
var _props = this.props,
actions = _props.actions,
dvrThreshold = _props.dvrThreshold,
_props$player = _props.player,
currentTime = _props$player.currentTime,
duration = _props$player.duration,
hls = _props$player.hls;
var isLive = data.details.live || false;
var hasDVR = false;
var mediaDuration = data.details.totalduration;
var playOffset = this.props.video.duration - mediaDuration;
if (isLive && mediaDuration > dvrThreshold) {
hasDVR = true;
}
if (isLive && hls && hls.levels[hls.currentLevel] && hls.levels[hls.currentLevel].details) {
var targetDuration = hls.levels[hls.currentLevel].details.targetduration;
var liveSync = hls.config.liveSyncDurationCount;
var liveOffset = targetDuration * liveSync;
var liveTime = duration - liveOffset;
var latency = liveTime - currentTime;
actions.handleMediaLatencyChange(liveTime, latency);
}
actions.handleMediaStateChange(hasDVR, isLive, mediaDuration, playOffset);
}
}, {
key: 'onLevelSwitched',
value: function onLevelSwitched(e, data) {
var actions = this.props.actions;
actions.handleRealTrackChange(data.level, false);
}
}, {
key: 'onLevelSwitching',
value: function onLevelSwitching(e, data) {
var actions = this.props.actions;
actions.handleRealTrackChange(data.level, true);
}
}, {
key: 'onHlsError',
value: function onHlsError(e, data) {
var onError = this.props.onError;
var recoverDecodingErrorDate = void 0,
recoverSwapAudioCodecDate = void 0;
if (data.fatal) {
switch (data.type) {
case _hls2.default.ErrorTypes.MEDIA_ERROR:
var now = new Date().getTime();
if (!recoverDecodingErrorDate || now - recoverDecodingErrorDate > 3000) {
recoverDecodingErrorDate = new Date().getTime();
this.hls.recoverMediaError();
} else if (!recoverSwapAudioCodecDate || now - recoverSwapAudioCodecDate > 3000) {
recoverSwapAudioCodecDate = new Date().getTime();
this.hls.swapAudioCodec();
this.hls.recoverMediaError();
}
break;
case _hls2.default.ErrorTypes.NETWORK_ERROR:
this.hls.startLoad();
break;
default:
this.hls.destroy();
break;
}
}
onError(e, data);
}
}, {
key: 'onBufferCreated',
value: function onBufferCreated(e, data) {
if ((0, _typeof3.default)(data.tracks) === 'object' && typeof data.tracks.audio === 'undefined') {
this.noAudioTrack = true;
}
}
}, {
key: 'onFragParsingData',
value: function onFragParsingData(e, data) {
if (data.type === 'audio') {
if (this.noAudioTrack && this.snNumberToReload === undefined) {
this.snNumberToReload = data.frag.sn;
}
}
}
}, {
key: 'onFragChanged',
value: function onFragChanged(e, data) {
if (this.noAudioTrack && this.snNumberToReload !== undefined) {
if (this.snNumberToReload <= data.frag.sn) {
this.hls.recoverMediaError();
this.noAudioTrack = false;
this.snNumberToReload = undefined;
this.skipNextOnMediaAttached = true;
this.skipNextOnManifestParsed = true;
}
}
}
}, {
key: 'buildTrackList',
value: function buildTrackList(levels) {
var _this2 = this;
var trackList = [];
var _props2 = this.props,
activeTrack = _props2.player,
actions = _props2.actions;
if (levels.length > 1) {
var autoLevel = {
id: -1,
label: 'اتوماتیک'
};
if (this.hls.manualLevel === -1) activeTrack = -1;
trackList.push(autoLevel);
}
levels.forEach(function (level, index) {
var quality = {};
quality.id = index;
quality.label = _this2._levelLabel(level, index);
trackList.push(quality);
if (index === _this2.hls.manualLevel) activeTrack = index;
});
actions.handleLoadLevels(trackList);
}
}, {
key: '_levelLabel',
value: function _levelLabel(level, index) {
if (level.height) return level.height + 'p';else if (level.width) return Math.round(level.width * 9 / 16) + 'p';else if (level.bitrate) return this.levelLabels[index] || parseInt(level.bitrate / 1000) + 'kbps';
return 0;
}
}, {
key: 'render',
value: function render() {
var _props3 = this.props,
src = _props3.src,
type = _props3.type;
return _react2.default.createElement('source', {
src: src,
type: type
});
}
}]);
return HLSSource;
}(_react.Component);
HLSSource.propTypes = {
src: _propTypes2.default.string,
type: _propTypes2.default.string,
video: _propTypes2.default.object,
autoPlay: _propTypes2.default.bool,
hlsOptions: _propTypes2.default.object,
onError: _propTypes2.default.func
};
HLSSource.defaultProps = {
hlsOptions: { liveSyncDurationCount: 3, debug: false },
type: 'application/x-mpegURL'
};
exports.default = HLSSource;