Skip to content

Instantly share code, notes, and snippets.

@tlaitinen
Created July 27, 2018 10:18
Show Gist options
  • Select an option

  • Save tlaitinen/54c3074acfeb51ae18227065a69bb3e0 to your computer and use it in GitHub Desktop.

Select an option

Save tlaitinen/54c3074acfeb51ae18227065a69bb3e0 to your computer and use it in GitHub Desktop.
import React from 'react';
import {appConnect, createPropsMapper, PropsOf} from './app-connect';
import {RootState} from '../reducers';
import {
getPlayers,
setCurrentTime,
setBuffered,
setNextPlaying,
setPlaying,
setSeekTime,
setDuration,
signalPlaybackEnded
} from '../actions/player';
import * as debug from './debug';
type Props = PropsOf<typeof propsMapper>;
export class AudioSource extends React.Component<Props> {
audioEl: HTMLAudioElement | null;
prevPlaybackStarted?: number;
constructor(props:Props) {
super(props);
this.audioEl = null;
this.onPlay = this.onPlay.bind(this);
this.onPause = this.onPause.bind(this);
this.onEnded = this.onEnded.bind(this);
this.onProgress = this.onProgress.bind(this);
this.onDurationChange = this.onDurationChange.bind(this);
this.onTimeUpdate = this.onTimeUpdate.bind(this);
}
componentDidMount() {
if (this.audioEl) {
this.audioEl.play();
}
}
onPlay() {
const {setPlaying, playerId} = this.props;
setPlaying(playerId, true);
}
onPause() {
const {setPlaying, playerId} = this.props;
setPlaying(playerId, false);
}
onEnded() {
const {signalPlaybackEnded, setPlaying, playerId} = this.props;
setPlaying(playerId, false);
signalPlaybackEnded(playerId);
}
onProgress() {
const audioEl = this.audioEl;
if (!audioEl) {
return;
}
const {setBuffered, playerId} = this.props;
if (audioEl.buffered.length >= 1) {
setBuffered(playerId, audioEl.buffered.end(0));
}
}
onDurationChange() {
const {setDuration, playerId} = this.props;
if (!this.audioEl) {
return;
}
setDuration(playerId, this.audioEl.duration);
}
onTimeUpdate() {
const audioEl = this.audioEl;
if (!audioEl) {
return;
}
const {setCurrentTime, playerId} = this.props;
if (!isNaN(audioEl.currentTime)) {
setCurrentTime(playerId, audioEl.currentTime);
}
}
componentDidUpdate() {
const {player} = this.props;
if (!player || !this.audioEl) {
return;
}
const {playbackStarted} = player;
if (playbackStarted !== this.prevPlaybackStarted && playbackStarted) {
this.prevPlaybackStarted = playbackStarted;
try {
this.audioEl.load();
} catch (e) {
console.log(e);
}
try {
this.audioEl.play();
} catch (e) {
console.log(e);
}
}
}
componentWillReceiveProps(nextProps:Props) {
const {
player
} = nextProps;
if (!this.audioEl || !player) {
return;
}
const {
nextPlaying=null,
seekTime=null
} = player;
const {
playerId,
setNextPlaying,
setSeekTime
} = this.props;
if (nextPlaying !== null) {
if (nextPlaying === false) {
this.audioEl.pause();
} else {
this.audioEl.play();
}
setNextPlaying(playerId, null);
}
if (seekTime !== null && !isNaN(seekTime) && isFinite(seekTime)) {
this.audioEl.currentTime = seekTime;
setSeekTime(playerId, null);
}
}
render() {
debug.log('rendering AudioElement');
const {
player
} = this.props;
if (!player || !player.source) {
return null;
}
return (
<audio
style={{
display: 'hidden',
width: 0,
height: 0
}}
src={player.source}
autoPlay={true}
onPlay={this.onPlay}
onPause={this.onPause}
onEnded={this.onEnded}
onProgress={this.onProgress}
onCanPlayThrough={this.onProgress}
onCanPlay={this.onProgress}
onTimeUpdate={this.onTimeUpdate}
onDurationChange={this.onDurationChange}
ref={ref => { this.audioEl = ref; }}/>
);
}
}
const propsMapper = createPropsMapper({
fromState: (state:RootState, ownProps:{
playerId:string;
}) => ({
player: getPlayers(state)[ownProps.playerId]
}),
actions: () => ({
setCurrentTime,
setBuffered,
setPlaying,
setNextPlaying,
setSeekTime,
setDuration,
signalPlaybackEnded
})
});
export default appConnect(propsMapper)(AudioSource);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment