UNPKG

@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
'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;