react-native-audio-api
Version:
react-native-audio-api provides system for controlling audio in React Native environment compatible with Web Audio API specification
209 lines (207 loc) • 7.42 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _react = _interopRequireWildcard(require("react"));
var _reactNative = require("react-native");
var _AudioTagContext = require("./AudioTagContext");
var _utils = require("./utils");
var _AudioControls = _interopRequireDefault(require("./controls/AudioControls"));
var _useAudioSourceLoader = require("./useAudioSourceLoader");
var _jsxRuntime = require("react/jsx-runtime");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
const Audio = /*#__PURE__*/_react.default.memo(/*#__PURE__*/_react.default.forwardRef((props, ref) => {
const {
children
} = props;
const {
autoPlay,
controls,
loop,
muted,
preload,
forceDownload,
source,
playbackRate,
preservesPitch,
volume,
context,
onLoadStart,
onLoad,
onError,
onPositionChange,
onEnded: onEndedCallback,
onPlay,
onPause,
onVolumeChange
} = (0, _utils.useStableAudioProps)(props);
const [volumeState, setVolumeState] = (0, _react.useState)(null);
const [mutedState, setMutedState] = (0, _react.useState)(null);
const [ready, setReady] = (0, _react.useState)(false);
const [playbackState, setPlaybackState] = (0, _react.useState)('idle');
const [currentTime, setCurrentTime] = (0, _react.useState)(0);
const path = (0, _react.useMemo)(() => (0, _utils.resolveSourcePath)(source), [source]);
const lastEffectiveVolumeRef = (0, _react.useRef)(muted ? 0 : volume);
(0, _react.useEffect)(() => {
return () => {
fileSourceRef.current?.disconnect();
fileSourceRef.current?.pause();
fileSourceRef.current?.dispose();
fileSourceRef.current = null;
};
}, []); // eslint-disable-line react-hooks/exhaustive-deps
const effectiveMutedState = (0, _react.useMemo)(() => {
return mutedState ?? muted;
}, [mutedState, muted]);
const effectiveVolumeState = (0, _react.useMemo)(() => {
return effectiveMutedState ? 0 : volumeState ?? volume;
}, [effectiveMutedState, volumeState, volume]);
const effectiveVolumeRef = (0, _react.useRef)(effectiveVolumeState);
effectiveVolumeRef.current = effectiveVolumeState;
const playRef = (0, _react.useRef)(() => {});
const handleAutoPlay = (0, _react.useCallback)(() => {
playRef.current();
}, []);
const handleEnded = (0, _react.useCallback)(endedDuration => {
setPlaybackState('idle');
setCurrentTime(endedDuration);
onEndedCallback();
}, [onEndedCallback]);
const {
fileSourceRef,
ready: loaderReady,
duration,
loadForPlayback
} = (0, _useAudioSourceLoader.useAudioSourceLoader)({
context,
path,
source,
preloadMode: preload,
forceDownload,
loop,
playbackRate,
preservesPitch,
autoPlay,
effectiveVolumeRef,
onLoadStart,
onLoad,
onError,
onEnded: handleEnded,
onAutoPlay: handleAutoPlay
});
(0, _react.useEffect)(() => {
setReady(loaderReady);
}, [loaderReady]);
(0, _react.useEffect)(() => {
fileSourceRef.current?.setVolume(effectiveVolumeState);
}, [effectiveVolumeState, fileSourceRef]);
const play = (0, _react.useCallback)(async () => {
if (!fileSourceRef.current) {
const loaded = await loadForPlayback();
if (!loaded) {
return;
}
}
if (!fileSourceRef.current) {
return;
}
fileSourceRef.current.play();
setPlaybackState('playing');
onPlay();
}, [fileSourceRef, loadForPlayback, onPlay]);
playRef.current = () => {
play();
};
const pause = (0, _react.useCallback)(() => {
fileSourceRef.current?.pause();
setPlaybackState('paused');
onPause();
}, [onPause, fileSourceRef]);
const setPlaybackRate = (0, _react.useCallback)(nextPlaybackRate => {
fileSourceRef.current?.setPlaybackRate(nextPlaybackRate);
}, [fileSourceRef]);
const seekToTime = (0, _react.useCallback)(seconds => {
fileSourceRef.current?.seekToTime(seconds);
const nextTime = duration > 0 ? Math.max(0, Math.min(seconds, duration)) : Math.max(0, seconds);
setCurrentTime(nextTime);
onPositionChange(nextTime);
}, [duration, setCurrentTime, onPositionChange, fileSourceRef]);
(0, _react.useEffect)(() => {
if (!path) {
setPlaybackState('idle');
setCurrentTime(0);
}
}, [path]);
(0, _react.useEffect)(() => {
if (lastEffectiveVolumeRef.current !== effectiveVolumeState) {
lastEffectiveVolumeRef.current = effectiveVolumeState;
onVolumeChange(effectiveVolumeState);
}
}, [onVolumeChange, effectiveVolumeState]);
(0, _react.useEffect)(() => {
fileSourceRef.current?.setLoop(loop);
}, [loop, fileSourceRef]);
(0, _react.useEffect)(() => {
fileSourceRef.current?.setPlaybackRate(playbackRate);
}, [playbackRate, fileSourceRef]);
(0, _react.useEffect)(() => {
fileSourceRef.current?.setPreservesPitch(preservesPitch);
}, [preservesPitch, fileSourceRef]);
(0, _react.useEffect)(() => {
if (playbackState !== 'playing') {
return;
}
const fileSource = fileSourceRef.current;
fileSource?.startPositionTracking(seconds => {
setCurrentTime(seconds);
onPositionChange(seconds);
});
return () => {
fileSource?.stopPositionTracking();
};
}, [onPositionChange, playbackState, fileSourceRef]);
(0, _react.useImperativeHandle)(ref, () => ({
play,
pause,
seekToTime,
setVolume: setVolumeState,
setMuted: setMutedState,
setPlaybackRate,
getFileSourceNode: () => fileSourceRef.current?.getFileSourceNode() ?? null
}), [pause, play, seekToTime, setMutedState, setVolumeState, setPlaybackRate, fileSourceRef]);
const ctxValue = (0, _react.useMemo)(() => ({
play,
pause,
seekToTime,
setVolume: setVolumeState,
volume: effectiveVolumeState,
ready,
setMuted: setMutedState,
muted: effectiveMutedState,
playbackState,
currentTime,
duration,
autoPlay,
controls,
loop,
preload,
playbackRate,
preservesPitch,
sourcePath: path,
source
}), [play, pause, seekToTime, setVolumeState, effectiveVolumeState, ready, setMutedState, effectiveMutedState, playbackState, currentTime, duration, autoPlay, controls, loop, preload, playbackRate, preservesPitch, path, source]);
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_AudioTagContext.AudioComponentContext.Provider, {
value: ctxValue,
children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
style: {
alignSelf: 'stretch',
width: '100%'
},
children: [controls && /*#__PURE__*/(0, _jsxRuntime.jsx)(_AudioControls.default, {}), children]
})
});
}));
var _default = exports.default = Audio;
//# sourceMappingURL=Audio.js.map