UNPKG

react-native-audio-api

Version:

react-native-audio-api provides system for controlling audio in React Native environment compatible with Web Audio API specification

207 lines (206 loc) • 6.69 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.useAudioSourceLoader = useAudioSourceLoader; var _react = require("react"); var _reactNative = require("react-native"); var _AudioFileUtils = require("../core/AudioFileUtils"); var _errors = require("../errors"); var _specs = require("../specs"); var _utils = require("../utils"); var _remoteHttpSource = require("../utils/remoteHttpSource"); var _AudioFileSourceNode = require("./AudioFileSourceNode"); var _utils2 = require("./utils"); function useAudioSourceLoader({ context, path, source, preloadMode, forceDownload, loop, playbackRate, preservesPitch, autoPlay, effectiveVolumeRef, onLoadStart, onLoad, onError, onEnded, onAutoPlay }) { const [ready, setReady] = (0, _react.useState)(false); const [duration, setDuration] = (0, _react.useState)(0); const fileSourceRef = (0, _react.useRef)(null); const sourceRef = (0, _react.useRef)(null); const isFetchingCancelled = (0, _react.useRef)(false); const fullDataFetched = (0, _react.useRef)(false); const onLoadStartRef = (0, _react.useRef)(onLoadStart); onLoadStartRef.current = onLoadStart; const onLoadRef = (0, _react.useRef)(onLoad); onLoadRef.current = onLoad; const onErrorRef = (0, _react.useRef)(onError); onErrorRef.current = onError; const onEndedRef = (0, _react.useRef)(onEnded); onEndedRef.current = onEnded; const onAutoPlayRef = (0, _react.useRef)(onAutoPlay); onAutoPlayRef.current = onAutoPlay; const playbackRateRef = (0, _react.useRef)(playbackRate); playbackRateRef.current = playbackRate; const preservesPitchRef = (0, _react.useRef)(preservesPitch); preservesPitchRef.current = preservesPitch; const disposeSource = (0, _react.useCallback)(() => { fileSourceRef.current?.stopPositionTracking(); fileSourceRef.current?.dispose(); sourceRef.current = null; fullDataFetched.current = false; }, []); const spawnFileSource = (0, _react.useCallback)(() => { const nextSource = sourceRef.current; if (!context || !nextSource) { return false; } fileSourceRef.current?.dispose(); const initialVolume = effectiveVolumeRef.current; const initialPlaybackRate = playbackRateRef.current; const initialPreservesPitch = preservesPitchRef.current; const node = context.context.createFileSource({ source: nextSource, headers: (0, _utils2.getSourceHeaders)(source), loop, volume: initialVolume, playbackRate: initialPlaybackRate, preservesPitch: initialPreservesPitch }); if (!node) { onErrorRef.current(new _errors.NotSupportedError('This file format requires FFmpeg build')); return false; } const fileSource = new _AudioFileSourceNode.AudioFileSourceNode(context, node); const { duration: nextDuration } = fileSource.attach({ loop, onEnded: () => { onEndedRef.current(nextDuration); spawnFileSource(); } }); fileSource.setVolume(initialVolume); fileSource.setPlaybackRate(initialPlaybackRate); fileSource.setPreservesPitch(initialPreservesPitch); fileSourceRef.current = fileSource; setDuration(nextDuration); onLoadRef.current(); if (autoPlay) { onAutoPlayRef.current(); } return true; }, [autoPlay, context, effectiveVolumeRef, loop, source]); const loadPlaybackSource = (0, _react.useCallback)(async () => { if (!path) { return false; } isFetchingCancelled.current = false; setReady(false); onLoadStartRef.current(); const headers = (0, _utils2.getSourceHeaders)(source); try { if ((0, _remoteHttpSource.isRemoteHttpUrl)(path)) { sourceRef.current = await (0, _remoteHttpSource.loadRemoteHttpSource)(path, headers, forceDownload); } else if (_reactNative.Platform.OS === 'android' && !__DEV__ && !path.startsWith('file://')) { const base64Payload = await _specs.NativeAudioAPIModule.readAndroidReleaseAssetBytesAsBase64(path); sourceRef.current = (0, _utils.base64ToArrayBuffer)(base64Payload); } else if (path.startsWith('file://')) { sourceRef.current = path.replace('file://', ''); } else { sourceRef.current = path; } fullDataFetched.current = true; if (!isFetchingCancelled.current && spawnFileSource()) { setReady(true); return true; } return false; } catch (error) { if (!isFetchingCancelled.current) { onErrorRef.current(error); } setReady(false); return false; } }, [forceDownload, path, source, spawnFileSource]); const probeMetadataOnly = (0, _react.useCallback)(async () => { if (!(0, _remoteHttpSource.isRemoteHttpUrl)(path)) { setReady(true); return; } isFetchingCancelled.current = false; setReady(false); onLoadStartRef.current(); const headers = (0, _utils2.getSourceHeaders)(source); try { const probedDuration = await (0, _AudioFileUtils.probeDuration)(path, context?.sampleRate, headers); if (probedDuration && !isFetchingCancelled.current) { setDuration(probedDuration); } setReady(true); } catch (error) { if (!isFetchingCancelled.current) { onErrorRef.current(error); } setReady(false); } }, [context?.sampleRate, path, source]); const loadForPlayback = (0, _react.useCallback)(async () => { if (fullDataFetched.current) { return fileSourceRef.current != null; } return loadPlaybackSource(); }, [loadPlaybackSource]); (0, _react.useEffect)(() => { isFetchingCancelled.current = false; fullDataFetched.current = false; if (!path) { setReady(false); setDuration(0); disposeSource(); return () => { isFetchingCancelled.current = true; disposeSource(); }; } if (preloadMode === 'none') { setReady(true); return () => { isFetchingCancelled.current = true; disposeSource(); }; } if (preloadMode === 'metadata') { if (!(0, _utils.isFfmpegEnabled)()) { setReady(true); } else { probeMetadataOnly(); } return () => { isFetchingCancelled.current = true; disposeSource(); }; } loadPlaybackSource(); return () => { isFetchingCancelled.current = true; disposeSource(); }; }, [disposeSource, loadPlaybackSource, path, preloadMode, probeMetadataOnly]); return { fileSourceRef, ready, duration, setDuration, loadForPlayback, disposeSource }; } //# sourceMappingURL=useAudioSourceLoader.js.map