Add error recovery to video, remove some dead code

main
Chris Vickery 2019-10-22 14:23:14 -07:00
parent 3464aec62c
commit 255a766e44
2 changed files with 24 additions and 33 deletions

View File

@ -14,7 +14,6 @@ export default class HLS extends Component {
onLoadEnd: PropTypes.func, onLoadEnd: PropTypes.func,
onPlaySeek: PropTypes.func, onPlaySeek: PropTypes.func,
segmentProgress: PropTypes.func, segmentProgress: PropTypes.func,
shouldRestart: PropTypes.bool,
onRestart: PropTypes.func onRestart: PropTypes.func
}; };
@ -41,6 +40,26 @@ export default class HLS extends Component {
enableWorker: false, enableWorker: false,
disablePtsDtsCorrectionInMp4Remux: true disablePtsDtsCorrectionInMp4Remux: true
}); });
this.player.on(Hls.Events.ERROR, (event, data) => {
if (data.fatal) {
switch (data.type) {
case Hls.ErrorTypes.NETWORK_ERROR:
// try to recover network error
console.log("fatal network error encountered, try to recover");
this.player.startLoad();
break;
case Hls.ErrorTypes.MEDIA_ERROR:
console.log("fatal media error encountered, try to recover");
this.player.recoverMediaError();
break;
default:
// cannot recover
this.player.destroy();
this.player = null;
break;
}
}
});
this.loadSource(); this.loadSource();
} }
@ -78,6 +97,7 @@ export default class HLS extends Component {
// destroy hls video source // destroy hls video source
if (this.player) { if (this.player) {
this.player.destroy(); this.player.destroy();
this.player = null;
} }
} }

View File

@ -1,7 +1,7 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { StyleSheet, css } from 'aphrodite/no-important'; import { StyleSheet, css } from 'aphrodite/no-important';
import { derived as RouteApi, video as VideoApi } from '@commaai/comma-api'; import { video as VideoApi } from '@commaai/comma-api';
import HLS from './HLS'; import HLS from './HLS';
import RouteSeeker from './RouteSeeker/RouteSeeker'; import RouteSeeker from './RouteSeeker/RouteSeeker';
@ -50,7 +50,6 @@ export default class RouteVideoSync extends Component {
shouldShowJpeg: true, shouldShowJpeg: true,
isLoading: true, isLoading: true,
videoElement: null, videoElement: null,
shouldRestartHls: false
}; };
this.onLoadStart = this.onLoadStart.bind(this); this.onLoadStart = this.onLoadStart.bind(this);
@ -59,27 +58,12 @@ export default class RouteVideoSync extends Component {
this.onVideoElementAvailable = this.onVideoElementAvailable.bind(this); this.onVideoElementAvailable = this.onVideoElementAvailable.bind(this);
this.onUserSeek = this.onUserSeek.bind(this); this.onUserSeek = this.onUserSeek.bind(this);
this.onPlaySeek = this.onPlaySeek.bind(this); this.onPlaySeek = this.onPlaySeek.bind(this);
this.onHlsRestart = this.onHlsRestart.bind(this);
this.ratioTime = this.ratioTime.bind(this); this.ratioTime = this.ratioTime.bind(this);
} }
componentDidUpdate(nextProps) { componentDidUpdate(nextProps) {
const { const { userSeekTime } = this.props;
userSeekIndex,
message,
canFrameOffset,
userSeekTime
} = this.props;
const { videoElement } = this.state; const { videoElement } = this.state;
if (
userSeekIndex !== nextProps.userSeekIndex
|| canFrameOffset !== nextProps.canFrameOffset
|| (message
&& nextProps.message
&& message.entries.length !== nextProps.message.entries.length)
) {
this.setState({ shouldRestartHls: true });
}
if ( if (
nextProps.userSeekTime nextProps.userSeekTime
&& userSeekTime !== nextProps.userSeekTime && userSeekTime !== nextProps.userSeekTime
@ -103,22 +87,15 @@ export default class RouteVideoSync extends Component {
const funcSeekToRatio = () => onUserSeek(seekTime); const funcSeekToRatio = () => onUserSeek(seekTime);
if (Number.isNaN(videoElement.duration)) { if (Number.isNaN(videoElement.duration)) {
this.setState({ shouldRestartHls: true }, funcSeekToRatio);
return; return;
} }
videoElement.currentTime = seekTime; videoElement.currentTime = seekTime;
if (ratio === 0) { if (ratio !== 0) {
this.setState({ shouldRestartHls: true }, funcSeekToRatio);
} else {
funcSeekToRatio(); funcSeekToRatio();
} }
} }
onHlsRestart() {
this.setState({ shouldRestartHls: false });
}
onPlaySeek(offset) { onPlaySeek(offset) {
const { onPlaySeek } = this.props; const { onPlaySeek } = this.props;
this.seekTime = offset; this.seekTime = offset;
@ -204,7 +181,6 @@ export default class RouteVideoSync extends Component {
render() { render() {
const { const {
isLoading, isLoading,
shouldRestartHls,
shouldShowJpeg, shouldShowJpeg,
videoElement videoElement
} = this.state; } = this.state;
@ -244,8 +220,6 @@ export default class RouteVideoSync extends Component {
onUserSeek={this.onUserSeek} onUserSeek={this.onUserSeek}
onPlaySeek={this.onPlaySeek} onPlaySeek={this.onPlaySeek}
segmentProgress={this.segmentProgress} segmentProgress={this.segmentProgress}
shouldRestart={shouldRestartHls}
onRestart={this.onHlsRestart}
/> />
<RouteSeeker <RouteSeeker
className={css(Styles.seekBar)} className={css(Styles.seekBar)}
@ -268,11 +242,8 @@ export default class RouteVideoSync extends Component {
} }
RouteVideoSync.propTypes = { RouteVideoSync.propTypes = {
userSeekIndex: PropTypes.number.isRequired,
segment: PropTypes.array.isRequired, segment: PropTypes.array.isRequired,
message: PropTypes.object,
thumbnails: PropTypes.array, thumbnails: PropTypes.array,
canFrameOffset: PropTypes.number.isRequired,
url: PropTypes.string.isRequired, url: PropTypes.string.isRequired,
playing: PropTypes.bool.isRequired, playing: PropTypes.bool.isRequired,
onPlaySeek: PropTypes.func.isRequired, onPlaySeek: PropTypes.func.isRequired,