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

88 lines (86 loc) 4.05 kB
"use strict"; import { Image, Platform } from 'react-native'; import { NativeAudioAPIModule } from "../specs/index.js"; import { AudioApiError } from "../errors/index.js"; import { isBase64Source, isDataBlobString, isRemoteSource, resolveLocalFilePath } from "../utils/paths.js"; import { base64ToArrayBuffer } from "../utils/index.js"; import AudioBuffer from "./AudioBuffer.js"; class AudioDecoder { static instance = null; constructor() { this.decoder = globalThis.createAudioDecoder(); } async decodeAudioDataImplementation(input, sampleRate, fetchOptions) { const rate = sampleRate ?? 0; if (input instanceof ArrayBuffer) { return this.decodeFromArrayBuffer(input, rate); } const stringSource = this.resolveStringSource(input); this.assertSupportedStringSource(stringSource); if (isRemoteSource(stringSource)) { return this.decodeFromRemoteUrl(stringSource, rate, fetchOptions); } return this.decodeFromLocalFile(stringSource, rate); } async decodeFromArrayBuffer(arrayBuffer, sampleRate) { const buffer = await this.decoder.decodeWithMemoryBlock( // @ts-ignore internal function new Uint8Array(arrayBuffer), sampleRate); return new AudioBuffer(buffer); } resolveStringSource(input) { return typeof input === 'number' ? Image.resolveAssetSource(input).uri : input; } assertSupportedStringSource(source) { if (typeof source !== 'string') { throw new TypeError('Input must be a module, uri or ArrayBuffer'); } if (isBase64Source(source)) { throw new AudioApiError('Base64 source decoding is not currently supported, to decode raw PCM base64 strings use decodePCMInBase64 method.'); } if (isDataBlobString(source)) { throw new AudioApiError('Data Blob string decoding is not currently supported.'); } } async decodeFromRemoteUrl(url, sampleRate, fetchOptions) { const arrayBuffer = await fetch(url, fetchOptions).then(res => res.arrayBuffer()); return this.decodeFromArrayBuffer(arrayBuffer, sampleRate); } async decodeFromLocalFile(stringSource, sampleRate) { const useAndroidBundledAssetReader = Platform.OS === 'android' && !stringSource.startsWith('file://') && !__DEV__; // special workaround, because android bundled assets are passed as f.e. asset_example_file // which has to be handled on native side and extension is not passed with it so decode using memory if (useAndroidBundledAssetReader) { const base64Payload = await NativeAudioAPIModule.readAndroidReleaseAssetBytesAsBase64(stringSource); const arrayBuffer = base64ToArrayBuffer(base64Payload); return this.decodeFromArrayBuffer(arrayBuffer, sampleRate); } const filePath = resolveLocalFilePath(stringSource); const buffer = await this.decoder.decodeWithFilePath(filePath, sampleRate); return new AudioBuffer(buffer); } static getInstance() { if (!AudioDecoder.instance) { AudioDecoder.instance = new AudioDecoder(); } return AudioDecoder.instance; } async decodeAudioDataInstance(input, sampleRate, fetchOptions) { const audioBuffer = await this.decodeAudioDataImplementation(input, sampleRate, fetchOptions); if (!audioBuffer) { throw new AudioApiError('Failed to decode audio data.'); } return audioBuffer; } async decodePCMInBase64Instance(base64String, inputSampleRate, inputChannelCount, interleaved) { const buffer = await this.decoder.decodeWithPCMInBase64(base64String, inputSampleRate, inputChannelCount, interleaved); return new AudioBuffer(buffer); } } export async function decodeAudioData(input, sampleRate, fetchOptions) { return AudioDecoder.getInstance().decodeAudioDataInstance(input, sampleRate, fetchOptions); } export async function decodePCMInBase64(base64String, inputSampleRate, inputChannelCount, isInterleaved = true) { return AudioDecoder.getInstance().decodePCMInBase64Instance(base64String, inputSampleRate, inputChannelCount, isInterleaved); } //# sourceMappingURL=AudioDecoder.js.map