react-native-audio-api
Version:
react-native-audio-api provides system for controlling audio in React Native environment compatible with Web Audio API specification
223 lines (222 loc) • 7.31 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 _jsxRuntime = require("react/jsx-runtime");
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,
source,
playbackRate,
preservesPitch,
volume,
onLoadStart,
onLoad,
onError,
onPositionChange,
onEnded: onEndedCallback,
onPlay,
onPause,
onVolumeChange
} = (0, _utils.useStableAudioProps)(props);
const audioRef = (0, _react.useRef)(null);
const [volumeState, setVolumeState] = (0, _react.useState)(volume);
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 [duration, setDuration] = (0, _react.useState)(0);
const lastElementVolumeRef = (0, _react.useRef)(muted ? 0 : volume);
const effectiveMutedState = (0, _react.useMemo)(() => {
return mutedState ?? muted;
}, [mutedState, muted]);
const effectiveVolumeState = (0, _react.useMemo)(() => {
return volumeState ?? volume;
}, [volumeState, volume]);
const reportedVolumeState = (0, _react.useMemo)(() => {
return effectiveMutedState ? 0 : effectiveVolumeState;
}, [effectiveMutedState, effectiveVolumeState]);
const path = (0, _react.useMemo)(() => {
if (!source) {
return '';
}
if (typeof source === 'string') {
return source;
}
if (typeof source === 'number') {
throw new Error('Asset source is not supported on web');
}
return source.uri ?? '';
}, [source]);
(0, _react.useEffect)(() => {
const el = audioRef.current;
if (!el) {
return;
}
el.loop = loop;
el.playbackRate = playbackRate;
// `preservesPitch` is non-standard but supported in modern browsers.
el.preservesPitch = preservesPitch;
}, [loop, playbackRate, preservesPitch]);
(0, _react.useEffect)(() => {
const el = audioRef.current;
if (!el) {
return;
}
el.volume = effectiveVolumeState;
}, [effectiveVolumeState]);
(0, _react.useEffect)(() => {
const el = audioRef.current;
if (!el) {
return;
}
el.muted = effectiveMutedState;
}, [effectiveMutedState]);
(0, _react.useEffect)(() => {
const el = audioRef.current;
if (!el) {
return;
}
const handleTimeUpdate = () => {
setCurrentTime(el.currentTime);
onPositionChange(el.currentTime);
};
const handleVolumeChange = () => {
const nextMuted = el.muted;
const nextVolume = nextMuted ? 0 : el.volume;
setMutedState(nextMuted);
setVolumeState(el.volume);
if (lastElementVolumeRef.current !== nextVolume) {
lastElementVolumeRef.current = nextVolume;
onVolumeChange(nextVolume);
}
};
el.addEventListener('timeupdate', handleTimeUpdate);
el.addEventListener('volumechange', handleVolumeChange);
setDuration(el.duration);
setCurrentTime(el.currentTime);
lastElementVolumeRef.current = el.muted ? 0 : el.volume;
return () => {
el.removeEventListener('timeupdate', handleTimeUpdate);
el.removeEventListener('volumechange', handleVolumeChange);
};
}, [onPositionChange, onVolumeChange, ready]);
const play = (0, _react.useCallback)(() => {
audioRef.current?.play();
setPlaybackState('playing');
onPlay();
}, [onPlay]);
const pause = (0, _react.useCallback)(() => {
audioRef.current?.pause();
setPlaybackState('paused');
onPause();
}, [onPause]);
const seekToTime = (0, _react.useCallback)(seconds => {
const el = audioRef.current;
if (!el) {
return;
}
const nextTime = duration > 0 ? Math.max(0, Math.min(seconds, duration)) : Math.max(0, seconds);
el.currentTime = nextTime;
setCurrentTime(nextTime);
}, [duration]);
const setVolume = (0, _react.useCallback)(next => {
setVolumeState(next);
}, []);
const setMuted = (0, _react.useCallback)(next => {
setMutedState(next);
}, []);
const setPlaybackRate = (0, _react.useCallback)(nextPlaybackRate => {
const el = audioRef.current;
if (!el) {
return;
}
el.playbackRate = nextPlaybackRate;
}, []);
(0, _react.useImperativeHandle)(ref, () => ({
play,
pause,
seekToTime,
setVolume,
setMuted,
setPlaybackRate
}), [pause, play, seekToTime, setMuted, setVolume, setPlaybackRate]);
const ctxValue = (0, _react.useMemo)(() => ({
play,
pause,
seekToTime,
setVolume,
ready,
volume: reportedVolumeState,
setMuted,
muted: effectiveMutedState,
playbackState,
currentTime,
duration,
autoPlay,
controls,
loop,
preload,
playbackRate,
preservesPitch,
audioContext: null
}), [play, pause, seekToTime, setVolume, ready, reportedVolumeState, setMuted, effectiveMutedState, playbackState, currentTime, duration, autoPlay, controls, loop, preload, playbackRate, preservesPitch]);
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_AudioTagContext.AudioComponentContext.Provider, {
value: ctxValue,
children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
style: {
alignSelf: 'stretch',
width: '100%'
},
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("audio", {
autoPlay: autoPlay,
controls: controls,
loop: loop,
muted: effectiveMutedState,
preload: preload,
src: path,
ref: audioRef,
onLoadStart: () => {
setReady(false);
onLoadStart();
},
onLoadedData: () => {
setReady(true);
onLoad();
},
onPlay: () => {
setPlaybackState('playing');
onPlay();
},
onPause: () => {
setPlaybackState(state => state === 'playing' ? 'paused' : state);
onPause();
},
onEnded: () => {
setPlaybackState('idle');
setCurrentTime(duration);
onEndedCallback();
},
onError: () => {
setReady(false);
onError(new Error('Failed to load audio element source'));
}
}), children]
})
});
}));
var _default = exports.default = Audio;
//# sourceMappingURL=Audio.web.js.map