2018-01-24 17:39:18 +00:00
|
|
|
// @flow
|
2017-06-05 18:00:02 +00:00
|
|
|
|
2018-02-26 19:37:12 +00:00
|
|
|
import React from 'react';
|
|
|
|
|
2017-06-05 18:00:02 +00:00
|
|
|
import AbstractAudio from '../AbstractAudio';
|
2018-01-24 17:39:18 +00:00
|
|
|
import type { AudioElement } from '../AbstractAudio';
|
2017-06-05 18:00:02 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The React/Web {@link Component} which is similar to and wraps around
|
|
|
|
* {@code HTMLAudioElement} in order to facilitate cross-platform source code.
|
|
|
|
*/
|
|
|
|
export default class Audio extends AbstractAudio {
|
|
|
|
/**
|
2018-02-26 19:37:12 +00:00
|
|
|
* Set to <code>true</code> when the whole file is loaded.
|
|
|
|
*/
|
|
|
|
_audioFileLoaded: boolean;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Reference to the HTML audio element, stored until the file is ready.
|
|
|
|
*/
|
2018-01-24 17:39:18 +00:00
|
|
|
_ref: ?AudioElement;
|
2018-02-26 19:37:12 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates new <code>Audio</code> element instance with given props.
|
2017-06-05 18:00:02 +00:00
|
|
|
*
|
2018-02-26 19:37:12 +00:00
|
|
|
* @param {Object} props - The read-only properties with which the new
|
|
|
|
* instance is to be initialized.
|
2017-06-05 18:00:02 +00:00
|
|
|
*/
|
2018-02-26 19:37:12 +00:00
|
|
|
constructor(props: Object) {
|
|
|
|
super(props);
|
|
|
|
|
|
|
|
// Bind event handlers so they are only bound once for every instance.
|
|
|
|
this._onCanPlayThrough = this._onCanPlayThrough.bind(this);
|
|
|
|
this._setRef = this._setRef.bind(this);
|
|
|
|
}
|
2017-06-05 18:00:02 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Implements React's {@link Component#render()}.
|
|
|
|
*
|
|
|
|
* @inheritdoc
|
|
|
|
* @returns {ReactElement}
|
|
|
|
*/
|
|
|
|
render() {
|
2018-02-26 19:37:12 +00:00
|
|
|
return (
|
|
|
|
<audio
|
2018-09-21 13:53:44 +00:00
|
|
|
loop = { Boolean(this.props.loop) }
|
2018-02-26 19:37:12 +00:00
|
|
|
onCanPlayThrough = { this._onCanPlayThrough }
|
|
|
|
preload = 'auto'
|
2018-01-24 17:39:18 +00:00
|
|
|
|
|
|
|
// $FlowFixMe
|
2018-02-26 19:37:12 +00:00
|
|
|
ref = { this._setRef }
|
|
|
|
src = { this.props.src } />
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2018-05-16 15:03:10 +00:00
|
|
|
/**
|
|
|
|
* Stops the audio HTML element.
|
|
|
|
*
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
|
|
|
stop() {
|
|
|
|
if (this._ref) {
|
|
|
|
this._ref.pause();
|
|
|
|
|
|
|
|
// $FlowFixMe
|
|
|
|
this._ref.currentTime = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-26 19:37:12 +00:00
|
|
|
/**
|
|
|
|
* If audio element reference has been set and the file has been
|
|
|
|
* loaded then {@link setAudioElementImpl} will be called to eventually add
|
|
|
|
* the audio to the Redux store.
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
|
|
|
_maybeSetAudioElementImpl() {
|
|
|
|
if (this._ref && this._audioFileLoaded) {
|
|
|
|
this.setAudioElementImpl(this._ref);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-24 17:39:18 +00:00
|
|
|
_onCanPlayThrough: () => void;
|
|
|
|
|
2018-02-26 19:37:12 +00:00
|
|
|
/**
|
|
|
|
* Called when 'canplaythrough' event is triggered on the audio element,
|
|
|
|
* which means that the whole file has been loaded.
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
|
|
|
_onCanPlayThrough() {
|
|
|
|
this._audioFileLoaded = true;
|
|
|
|
this._maybeSetAudioElementImpl();
|
|
|
|
}
|
|
|
|
|
2018-01-24 17:39:18 +00:00
|
|
|
_setRef: (?AudioElement) => void;
|
|
|
|
|
2018-02-26 19:37:12 +00:00
|
|
|
/**
|
|
|
|
* Sets the reference to the HTML audio element.
|
|
|
|
*
|
|
|
|
* @param {HTMLAudioElement} audioElement - The HTML audio element instance.
|
|
|
|
* @private
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-01-24 17:39:18 +00:00
|
|
|
_setRef(audioElement: ?AudioElement) {
|
2018-02-26 19:37:12 +00:00
|
|
|
this._ref = audioElement;
|
2018-01-24 17:39:18 +00:00
|
|
|
|
2018-02-26 19:37:12 +00:00
|
|
|
if (audioElement) {
|
|
|
|
this._maybeSetAudioElementImpl();
|
|
|
|
} else {
|
|
|
|
// AbstractAudioElement is supposed to trigger "removeAudio" only if
|
|
|
|
// it was previously added, so it's safe to just call it.
|
|
|
|
this.setAudioElementImpl(null);
|
|
|
|
|
|
|
|
// Reset the loaded flag, as the audio element is being removed from
|
|
|
|
// the DOM tree.
|
|
|
|
this._audioFileLoaded = false;
|
|
|
|
}
|
2017-06-05 18:00:02 +00:00
|
|
|
}
|
|
|
|
}
|