react-hifi
Version:
A set of react components wich provides simple abstraption to manipulate HTML5 AudioContext API (Equalizer, visualisation, stereo, basic controls)
210 lines • 9.05 kB
JavaScript
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
var react_1 = __importDefault(require("react"));
var plugins_1 = require("../plugins");
var SoundStatus;
(function (SoundStatus) {
SoundStatus["PAUSED"] = "PAUSED";
SoundStatus["PLAYING"] = "PLAYING";
SoundStatus["STOPPED"] = "STOPPED";
})(SoundStatus || (SoundStatus = {}));
var Destination = plugins_1.pluginFactory({
createNode: function (audioContext) {
return audioContext.destination;
},
});
var SoundErrors;
(function (SoundErrors) {
SoundErrors["MEDIA_ERR_ABORTED"] = "Video playback aborted by the user.";
SoundErrors["MEDIA_ERR_NETWORK"] = "A network error caused the audio download to fail.";
SoundErrors["MEDIA_ERR_DECODE"] = "The audio playback was aborted due to a corruption problem.";
SoundErrors["MEDIA_ERR_SRC_NOT_SUPPORTED"] = "The audio playback can not be loaded, either because the server or network failed or because the format is not supported.";
SoundErrors["UNKNOWN"] = "An unknown error occurred during audio playback loading.";
})(SoundErrors = exports.SoundErrors || (exports.SoundErrors = {}));
/**
* Sound Component
*/
var Sound = /** @class */ (function (_super) {
__extends(Sound, _super);
function Sound(props) {
var _this = _super.call(this, props) || this;
_this.state = {
audioContext: new AudioContext(),
audioNodes: [],
};
_this.handleTimeUpdate = _this.handleTimeUpdate.bind(_this);
_this.attachRef = _this.attachRef.bind(_this);
_this.handleRegisterPlugin = _this.handleRegisterPlugin.bind(_this);
_this.handleError = _this.handleError.bind(_this);
return _this;
}
Sound.prototype.attachRef = function (element) {
if (element) {
this.audio = element;
}
};
Sound.prototype.renderPlugins = function () {
var _this = this;
var children = this.props.children;
if (Array.isArray(children)) {
var flatChildren = children.flat();
return flatChildren.map(function (plugin, idx) { return (react_1.default.createElement(plugin.type, __assign({}, plugin.props, { key: idx, audioContext: _this.state.audioContext, previousNode: _this.state.audioNodes[idx], onRegister: _this.handleRegisterPlugin }))); }).concat([
react_1.default.createElement(Destination, { key: flatChildren.length, audioContext: this.state.audioContext, previousNode: this.state.audioNodes[flatChildren.length - 1] }),
]);
}
else if (children) {
return [
react_1.default.createElement(children.type, __assign({}, children.props, { key: 1, audioContext: this.state.audioContext, previousNode: this.state.audioNodes[0], onRegister: this.handleRegisterPlugin })),
react_1.default.createElement(Destination, { key: 2, audioContext: this.state.audioContext, previousNode: this.state.audioNodes[1] }),
];
}
else {
return null;
}
};
Sound.prototype.handleRegisterPlugin = function (plugin) {
this.setState({
audioNodes: this.state.audioNodes.concat([plugin]),
});
};
Sound.prototype.handleTimeUpdate = function (_a) {
var target = _a.target;
if (this.props.onPlaying) {
this.props.onPlaying({
position: target.currentTime,
duration: target.duration,
});
}
};
Sound.prototype.setPlayerState = function (status) {
switch (status) {
case Sound.status.PAUSED:
this.pause();
break;
case Sound.status.STOPPED:
this.stop();
break;
case Sound.status.PLAYING:
default:
this.play();
break;
}
};
Sound.prototype.shouldUpdatePosition = function (_a) {
var position = _a.position;
var nextPosition = this.props.position;
if ((position || position === 0) && (nextPosition || nextPosition === 0)) {
var dif = nextPosition - position;
return position > nextPosition || dif > 1;
}
else {
return false;
}
};
Sound.prototype.setPosition = function (position) {
this.audio.currentTime = position;
};
Sound.prototype.play = function () {
var _this = this;
this.state.audioContext.resume().then(function () { return _this.audio.play(); });
};
Sound.prototype.pause = function () {
var _this = this;
this.state.audioContext.suspend().then(function () { return _this.audio.pause(); });
};
Sound.prototype.stop = function () {
this.pause();
this.audio.currentTime = 0;
};
Sound.prototype.handleError = function (evt) {
var error;
switch (evt.target.error.code) {
case evt.target.error.MEDIA_ERR_ABORTED:
error = new Error(SoundErrors.MEDIA_ERR_ABORTED);
break;
case evt.target.error.MEDIA_ERR_NETWORK:
error = new Error(SoundErrors.MEDIA_ERR_NETWORK);
break;
case evt.target.error.MEDIA_ERR_DECODE:
error = new Error(SoundErrors.MEDIA_ERR_DECODE);
break;
case evt.target.error.MEDIA_ERR_SRC_NOT_SUPPORTED:
error = new Error(SoundErrors.MEDIA_ERR_SRC_NOT_SUPPORTED);
break;
default:
error = new Error(SoundErrors.UNKNOWN);
break;
}
this.props.onError && this.props.onError(error);
};
Sound.prototype.componentDidUpdate = function (prevProps) {
var _a = this.props, playStatus = _a.playStatus, url = _a.url;
if ((playStatus && prevProps.playStatus !== playStatus) || url !== prevProps.url) {
this.setPlayerState(playStatus);
}
if (this.shouldUpdatePosition(prevProps)) {
this.setPosition(this.props.position);
}
};
Sound.prototype.componentDidMount = function () {
this.source = this.state.audioContext.createMediaElementSource(this.audio);
if (!this.props.children) {
this.source.connect(this.state.audioContext.destination);
}
else {
this.setState({
audioNodes: [this.source],
});
}
this.setPlayerState(this.props.playStatus);
this.props.position && this.setPosition(this.props.position);
};
Sound.prototype.componentWillUnmount = function () {
this.state.audioContext.close();
};
Sound.prototype.componentDidCatch = function (err) {
this.state.audioContext.close();
this.props.onError && this.props.onError(err);
};
Sound.prototype.render = function () {
var _a = this.props, url = _a.url, onPlaying = _a.onPlaying, onFinishedPlaying = _a.onFinishedPlaying, onLoad = _a.onLoad, onLoading = _a.onLoading;
return (react_1.default.createElement(react_1.default.Fragment, null,
react_1.default.createElement("audio", { crossOrigin: "anonymous", style: { visibility: 'hidden' }, src: Array.isArray(url) ? undefined : url, ref: this.attachRef, onTimeUpdate: onPlaying ? this.handleTimeUpdate : undefined, onEnded: onFinishedPlaying, onLoadStart: onLoading, onCanPlay: onLoad, onError: this.handleError }, Array.isArray(url) &&
url.map(function (_a, index) {
var url = _a.url, type = _a.type;
return react_1.default.createElement("source", { key: index, type: type, src: url });
})),
this.renderPlugins()));
};
Sound.status = SoundStatus;
return Sound;
}(react_1.default.Component));
exports.Sound = Sound;
//# sourceMappingURL=index.js.map