Adding retry when Icecast closes endpoint between tracks, causing 404
This commit is contained in:
@ -162,18 +162,17 @@ class OutputControl extends React.Component {
|
||||
Local browser
|
||||
</div>
|
||||
<div className="output-control__item__controls">
|
||||
<span
|
||||
className="output-control__item__action"
|
||||
onClick={(e) => coreActions.cachebustHttpStream()}
|
||||
>
|
||||
<Icon name="refresh" />
|
||||
</span>
|
||||
<MuteControl
|
||||
className="output-control__item__mute"
|
||||
noTooltip
|
||||
mute={http_streaming_mute}
|
||||
onMuteChange={(mute) => coreActions.set({ http_streaming_mute: mute })}
|
||||
/>
|
||||
<VolumeControl
|
||||
className="output-control__item__volume"
|
||||
volume={http_streaming_volume}
|
||||
mute={http_streaming_mute}
|
||||
onVolumeChange={(percent) => coreActions.set({ http_streaming_volume: percent })}
|
||||
onMuteChange={(mute) => coreActions.set({ http_streaming_mute: mute })}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
|
||||
import React, { createRef } from 'react';
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import * as coreActions from '../services/core/actions';
|
||||
@ -13,14 +13,18 @@ class Stream extends React.Component {
|
||||
play_state: '',
|
||||
cachebuster: `${Date.now()}`,
|
||||
url: null,
|
||||
loaded: false,
|
||||
retryCount: 0,
|
||||
};
|
||||
|
||||
this.audioRef = createRef();
|
||||
this.audio = new Audio();
|
||||
this.audio.onerror = (error) => this.onError(error);
|
||||
}
|
||||
|
||||
static getDerivedStateFromProps(props, state) {
|
||||
const {
|
||||
volume,
|
||||
mute,
|
||||
enabled: propEnabled,
|
||||
play_state: propPlayState,
|
||||
url: propUrl,
|
||||
@ -30,23 +34,28 @@ class Stream extends React.Component {
|
||||
} = props;
|
||||
const {
|
||||
play_state: statePlayState,
|
||||
enabled: stateEnabled,
|
||||
uri: stateUri,
|
||||
url: stateUrl,
|
||||
cachebuster,
|
||||
} = state;
|
||||
let { retryCount } = state;
|
||||
|
||||
// Same track as before, and still playing
|
||||
if (
|
||||
propUri
|
||||
&& propUri === stateUri
|
||||
&& propPlayState === statePlayState
|
||||
&& propEnabled === stateEnabled
|
||||
&& propUrl === stateUrl
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let url = null;
|
||||
let fullUrl = null;
|
||||
if (propEnabled && propUrl && propUri) {
|
||||
url = `${propUrl}?cb=${cachebuster}_${propUri}`;
|
||||
console.log(`Playing stream: ${url}`);
|
||||
fullUrl = `${propUrl}?cb=${cachebuster}_${propUri}`;
|
||||
retryCount = 0;
|
||||
}
|
||||
|
||||
return {
|
||||
@ -55,34 +64,60 @@ class Stream extends React.Component {
|
||||
uri: propUri,
|
||||
play_state: propPlayState,
|
||||
volume,
|
||||
url,
|
||||
mute,
|
||||
fullUrl,
|
||||
loaded: false,
|
||||
retryCount,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidUpdate = () => {
|
||||
const { volume } = this.props;
|
||||
if (this.audioRef.current) {
|
||||
this.audioRef.current.volume = volume / 100;
|
||||
componentDidUpdate = (prevProps, prevState) => {
|
||||
const {
|
||||
fullUrl,
|
||||
volume,
|
||||
} = this.state;
|
||||
const { mute } = this.props;
|
||||
if (!fullUrl) return null;
|
||||
|
||||
this.audio.muted = mute;
|
||||
this.audio.volume = volume / 100;
|
||||
|
||||
// Only update URL if it's changed. This prevents re-loading the stream when something unrelated
|
||||
// (like volume) was changed
|
||||
if (prevState.fullUrl !== fullUrl) {
|
||||
this.play(fullUrl);
|
||||
}
|
||||
}
|
||||
|
||||
render = () => {
|
||||
const { url } = this.state;
|
||||
if (!url) return null;
|
||||
return (
|
||||
<div key={url}>
|
||||
<audio autoPlay ref={this.audioRef}>
|
||||
<source src={url} />
|
||||
</audio>
|
||||
</div>
|
||||
);
|
||||
onError = (error) => {
|
||||
const { retryCount } = this.state;
|
||||
if (retryCount < 3) {
|
||||
console.error(`Audio failed to load. Retrying ${retryCount+1}/3`, error);
|
||||
setTimeout(
|
||||
() => {
|
||||
this.play();
|
||||
this.setState({ retryCount: retryCount + 1 });
|
||||
},
|
||||
250,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
play = (url = null) => {
|
||||
const { fullUrl } = this.state;
|
||||
console.info(`Playing stream: ${url || fullUrl}`);
|
||||
this.audio.src = url || fullUrl;
|
||||
this.audio.play();
|
||||
}
|
||||
|
||||
render = () => null;
|
||||
}
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
current_track: state.core.current_track || {},
|
||||
play_state: state.mopidy.play_state,
|
||||
enabled: state.core.http_streaming_enabled,
|
||||
mute: state.core.http_streaming_mute || false,
|
||||
volume: state.core.http_streaming_volume >= 0 ? state.core.http_streaming_volume : 50,
|
||||
url: (state.core.http_streaming_url ? state.core.http_streaming_url : null),
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user