@dr.pogodin/react-native-audio
v1.11.0
Published
React Native: access to the audio input stream
Downloads
140
Maintainers
Readme
React Native Audio
React Native (RN) Audio library for Android, iOS, and macOS (Catalyst) platforms, with support of new and old RN architectures. It covers:
- Input audio stream (microphone) listening / recording.
- Audio samples playback.
- Utility functions for audio system management.
- More stuff to come...
Sponsored By
Contributors
Content
- Installation
- Getting Started
- API Reference
- Classes
- InputAudioStream — Represents individual input audio streams.
- constructor() — Creates a new InputAudioStream instance.
- .addChunkListener() — Adds a new audio data chunk listener to the stream.
- .addErrorListener() — Adds a new error listener to the stream.
- .destroy() — Destroys the stream — stops recording, and releases all related resources.
- .mute() — Mutes the stream.
- .removeChunkListener() — Removes an audio data chunk listener from the stream.
- .removeErrorListener() — Removes an error listener from the stream.
- .start() — Starts the audio stream recording.
- .stop() — Stops the stream.
- .unmute() — Unmutes a previously muted stream.
- .active — true when the stream is started and recoding.
- .audioFormat — Holds the audio format value provided to the constructor().
- .audioSource — Holds the audio source value provided to the constructor().
- .channelConfig — Holds the channel mode value provided to the constructor().
- .muted — true when the stream is muted.
- .sampleRate — Holds the stream's sample rate in [Hz].
- .samplingSize — Holds the stream's sampling (audio data chunk) size, per channel.
- .stopInBackground — true if the stream is configured to stop automatically when the app leaves foreground, and to start again when it returns to the foreground.
- SamplePlayer — Represents an audio sample player.
- constructor() — Creates a new SamplePlayer instance.
- .addErrorListener() — Adds a new error listener to the player.
- .destroy() — Destroys the player, releasing all related resources.
- .load() — Loads an (additional) audio sample.
- .play() — Plays an audio sample.
- .removeErrorListener() — Removes an error listener from the player.
- .stop() — Stops an audio sample playback.
- .unload() — Unloads an audio sample.
- InputAudioStream — Represents individual input audio streams.
- Constants
- AUDIO_FORMATS — Provides valid .audioFormat values.
- AUDIO_SOURCES — Provides valid .audioSource values.
- CHANNEL_CONFIGS — Provides valid .channelConfig values.
- IS_MAC_CATALYST — true if app is running on macOS (Catalyst).
- Functions
- configAudioSystem() — Configures audio system (input & output devices) for iOS, does nothing on Android.
- getInputAvailable() — Resolves true if device has an available audio input source.
- Types
- ChunkListener — The type of audio data chunk listeners that can be connected to a stream with .addChunkListener() method.
- ErrorListener — The type of error listeners that can be connected to
InputAudioStream and SamplePlayer instances using their corresponding
.addErrorListener()
methods (see stream method, and player method).
- Classes
Installation
Install the package and its peer dependencies
npx install-peerdeps @dr.pogodin/react-native-audio
Follow react-native-permissions documentation to setup your app for asking the user for the RECORD_AUDIO (Android) and/or Microphone (iOS) permissions. react-native-audio library will automatically ask for these permissions, if needed, when a stream .start() method is called, provided the app has been correctly configured to ask for them.
Getting Started
A better Getting Started tutorial is to be written, however the main idea is this:
import {
AUDIO_FORMATS,
AUDIO_SOURCES,
CHANNEL_CONFIGS,
InputAudioStream,
} from "@dr.pogodin/react-native-audio";
function createAndStartAudioStream() {
const stream = new InputAudioStream(
AUDIO_SOURCES.RAW,
44100, // Sample rate in Hz.
CHANNEL_CONFIGS.MONO,
AUDIO_FORMATS.PCM_16BIT,
4096, // Sampling size.
);
stream.addErrorListener((error) => {
// Do something with a stream error.
});
stream.addChunkListener((chunk, chunkId) => {
// Pause the stream for the chunk processing. The point is: if your chunk
// processing in this function is too slow, and chunks arrive faster than
// this callback is able to handle them, it will rapidly crash the app,
// with out of memory error. Muting the stream ignores any new chunks
// until stream.unmute() is called, thus protecting from the crash.
// And if your chunk processing is rapid enough, not chunks won't be
// skipped. The "chunkId" argument is just sequential chunk numbers,
// by which you may judge whether any chunks have been skipped between
// this callback calls or not.
stream.mute();
// Do something with the chunk.
// Resumes the stream.
stream.unmute();
});
stream.start();
// Call stream.destroy() to stop the stream and release any associated
// resources. If you need to temporarily stop and then resume the stream,
// use .mute() and .unmute() methods instead.
}
and on top of this the library will include other auxiliary methods related to audio input and output.
API Reference
Classes
InputAudioStream
class InputAudioStream;
The InputAudioStream class, as its name suggests, represents individual input audio streams, capturing audio data in the configured format from the specified audio source.
constructor()
const stream = new InputAudioStream(
audioSource: AUDIO_SOURCES,
sampleRate: number,
channelConfig: CHANNEL_CONFIGS,
audioFormat: AUDIO_FORMATS,
samplingSize: number,
stopInBackground: boolean = true,
);
Creates a new InputAudioStream instance. The newly created stream does not record audio, neither consumes resources at the native side until its .start() method is called.
audioSource
— AUDIO_SOURCES — The audio source this stream will listen to. Currently, it is supported for Android only; on iOS this value is just ignored, and the stream captures audio data from the default input source of the device.sampleRate
— number — Sample rate [Hz]. 44100 Hz is the recommended value, as it is the only rate that is guaranteed to work on all Android (and many other) devices.channelConfig
— CHANNEL_CONFIGS — Mono or Stereo stream mode.audioFormat
— AUDIO_FORMATS — Audio format.samplingSize
— number — Sampling (data chunk) size, expressed as the number of samples per channel in the chunk.stopInBackground
— boolean — Optional. It true (default) the stream will automatically pause itself when the app leaves the foreground, and the stream will automatically resume itself when the app returns to the foreground.
.addChunkListener()
stream.addChunkListener(listener: ChunkListener): void;
Adds a new audio data chunk listener to the stream. See .removeChunkListener() to subsequently remove the listener from the stream.
Note: It is safe to call it repeatedly for the same listener & stream pair — the listener still won't be added to the stream more than once.
listener
— ChunkListener — The callback to call with audio data chunks when they arrive.
.addErrorListener()
stream.addErrorListener(listener: ErrorListener): void;
Adds a new error listener to the stream. See .removeErrorListener() to subsequently remove the listener from the stream.
Note: It is safe to call it repeatedly for the same listener & stream pair — the listener still won't be added to the stream more than once.
listener
— ErrorListener — The callback to call with error details, if any error happens in the stream.
.destroy()
stream.destroy(): void;
Destroys the stream — stops the recording, and releases all related resources, both at the native and JS sides. Once a stream is destroyed, it cannot be re-used.
.mute()
stream.mute(): void;
Mutes the stream. A muted stream still continues to capture audio data chunks from the audio source, and thus keeps incrementing chunk IDs (see ChunkListener), but it discards all data chunks immediately after the capture, without sending them to the JavaScript layer, thus causing the minimal performance and memory overhead possible without interrupting the recording.
Calling .mute() on a muted, or non-active (not recording) audio stream has no effect. See also .active, .muted.
.removeChunkListener()
stream.removeChunkListener(listener: ChunkListener): void;
Removes the listener from the stream. No operation if given listener
is not
connected to the stream. See .addChunkListener() to add the listener.
listener
— ChunkListener — The listener to disconnect.
.removeErrorListener()
stream.removeErrorListener(listener: ErrorListener): void;
Removes the listener from the stream. No operation if given listener
is not
connected to the stream. See .addErrorListener() to connect the listener.
listener
— ErrorListener — The listener to disconnect.
.start()
stream.start(): Promise<boolean>;
Starts the audio stream recording. This method actually initializes the stream on the native side, and starts the recording.
Note: If necessary, this method will ask app user for the audio recoding permission, using the react-native-permissions library.
- Resolves to boolean value — true if the stream has started successfully and is .active, false otherwise.
.stop()
stream.stop(): Promise<void>;
Stops the stream. Unlike the .mute() method, .stop() actually stops the audio stream and releases its resources on the native side; however, unlike the .destroy() method, it does not release its resource in the JS layer (i.e. does not drop references to all connected listeners), thus allowing to .start() this stream instance again (which will technically will init a new stream on the native side, but it will be opaque to the end user on the JS side).
- Resolves once the stream is stopped.
.unmute()
stream.unmute(): void;
Unmutes a previously .muted stream. It has no effect if called on inactive (non started), or already muted stream.
.active
stream.active: boolean;
Read-only. true when the stream is started and recording, false otherwise.
Note: .active will be true for a started and .muted stream.
.audioFormat
stream.audioFormat: AUDIO_FORMATS;
Read-only. Holds the audio format value provided to InputAudioStream's constructor(). AUDIO_FORMATS enum provides valid format values.
.audioSource
stream.audioSource: AUDIO_SOURCES;
Read-only. Holds the audio source value provided to InputAudioStream's constructor(). As of now it only has an affect on Android devices, and it is ignored for iOS. AUDIO_SOURCES enum provides valid audio source values.
.channelConfig
stream.channelConfig: CHANNEL_CONFIGS;
Read-only. Holds the channel mode (Mono or Stereo) value provided to InputAudioStream's constructor(). CHANNEL_CONFIGS enum provides valid channel mode values.
.muted
stream.muted: boolean;
Read-only. true when the stream is muted by .mute(), false otherwise.
.sampleRate
stream.sampleRate: number;
Read-only. Holds the stream's sample rate provided to the stream constructor(), in [Hz].
.samplingSize
stream.samplingSize: number;
Read-only. Holds the stream's sampling (audio data chunk) size, provided to the stream constructor(). The value is the number of samples per channel, thus for multi-channel streams the actual chunk size will be a multiple of this number, and also the sample size in bytes may vary for different .audioFormat.
.stopInBackground
stream.stopInBackground: boolean;
Read-only. true if the stream is set to automatically .stop() when the app leaves foreground, and .start() again when it returns to the foreground.
SamplePlayer
class SamplePlayer;
Represents an audio sample player. It is intended for loading into the memory a set of short audio fragments, which then can be played at demand with a low latency.
On Android we use SoundPool for the underlying implementation, you may check its documentation for further details. In particular note: each decoded sound is internally limited to one megabyte storage, whcih represents approximately 5.6 seconds at 44.1Hz stereo (the duration is proportionally longer at lower sample rates or a channel mask of mono).
constructor()
const player = new SamplePlayer();
Creates a new SamplePlayer instance. Note that this creation of SamplePlayer instance already allocates some resources at the native side, thus to release those resources you MUST USE its .destroy() method once the instance is not needed anymore.
.addErrorListener()
player.addErrorListener(listener: ErrorListener): void;
Adds an error listener to the player. Does nothing if given listener
is
already added to this player.
listener
— ErrorListener — Error listener.
.destroy()
player.destroy(): Promise<void>;
Destroys player instance, releasing all related resources. Once destroyed the player instance can't be reused.
- Resolves once completed.
.load()
player.load(sampleName: string, samplePath: string): Promise<void>;
Loads an (additional) audio sample into the player.
sampleName
— string — Sample name, by which you'll refer to the loaded sample in other methods, like .play(), SamplePlayer.stop(), and .unload(). If it matches a name of a previously loaded sample, that sample will be replaced.samplePath
— string — Path to the sample file on the device. For now, only loading samples from regular files is supported (e.g. not possible to load from Android asset, without first copying the asset into a regular file).- Resolves once the sample is loaded and decoded, thus ready to be played.
.play()
player.play(sampleName: string, loop: boolean): Promise<void>;
Plays an audio sample, previously loaded with .load() method.
NOTE: In the current implementation, starting a sample playback always stops the ongoing playback of a sample previously played by the same player, if any. There is no technical barrier to support playback of multiple samples at the same time, it just needs some more development effort.
NOTE: Use .addErrorListener() method to recieve details of any errors that happen during the playback. Although .play() itself rejects if the playback fails to start, that rejection message does not provide any details beyond the fact of the failure, and it also does not capture any further errors (as the playback itself is asynchronous).
sampleName
— string — Sample name, assinged when loading it with the .load() method.loop
— boolean — Set true to infinitely loop the sample; or false to play it once.- Resolves once the playback is launched; rejects if the playback fails to start due to some error.
.removeErrorListener()
player.removeErrorListener(listener: ErrorListener): void;
Removes listener
from this player
, or does nothing if the listener is not
connected to the player.
listener
— ErrorListener — Error listener to disconnect.
.stop()
player.stop(sampleName: string): Promise<void>;
Stops sample playback, does nothing if the sample is not being played by this player.
sampleName
— string — Sample name.- Resolves once completed.
.unload()
player.unload(sampleName: string): Promise<void>;
Unloads an audio sample previouly loaded into this player.
sampleName
— string — Sample name.- Resolves once completed.
Constants
AUDIO_FORMATS
enum AUDIO_FORMATS {
PCM_8BIT: number;
PCM_16BIT: number;
PCM_FLOAT: number;
};
Provides valid .audioFormat values. See Android documentation for exact definitions of these three formats; they should be the same on iOS devices.
Note: At least Android allows for other audio formats, which we may include here in future.
AUDIO_SOURCES
enum AUDIO_SOURCES {
CAMCODER: number;
DEFAULT: number;
MIC: number;
REMOTE_SUBMIX: number;
RAW: number;
VOICE_CALL: number;
VOICE_COMMUNICATION: number;
VOICE_DOWNLINK: number;
VOICE_PERFORMANCE: number;
VOICE_RECOGNITION: number;
VOICE_UPLINK: number;
};
Provides valid .audioSource values. As of now, they have effect for Android devices only, and for them they represent corresponding values of MediaRecorder.AudioSource.
CHANNEL_CONFIGS
enum CHANNEL_CONFIGS {
MONO: number;
STEREO: number;
};
Provides valid .channelConfig values.
Note: As of now, it provides only two values, MONO and STEREO, however, at least Android seems to support additional channels, which might be added in future, see Android's AudioFormat documentation.
IS_MAC_CATALYST
const IS_MAC_CATALYST: boolean;
Equals true if the app is running on the macOS (Catalyst) platform; false otherwise.
Functions
configAudioSystem()
function configAudioSystem(): Promise<void>;
Configures audio system (input & output devices).
Currently it does nothing on Android; on iOS it (re-)configures the audio session, setting the Play & Record category and activating the session.
Note: On iOS, if Play & Record category is not available on the device, it sets the Playback category instead; and if neither category is available, the function rejects its result promise. The function also sets the following options for the iOS audio session: AllowBluetooth, AllowBluetoothA2DP, and DefaultToSpeaker.
See iOS documentation for further details about iOS audio sessions and categories.
- Resolves once completed.
getInputAvailable()
function getInputAvailable(): Promise<boolean>;
- Resolves true if device has an available audio input source, false otherwise.
Types
ChunkListener
type ChunkListener = (chunk: Buffer, chunkId: number) => void;
The type of audio data chunk listeners that can be connected to an InputAudioStream with .addChunkListener() method.
chunk
— Buffer — Audio data chunk in the format specified upon the audio stream construction. Buffer implementation for RN is provided by thebuffer
library.chunkId
— number — Consequtive chunk number. When a stream is .muted the chunk numbers are still incremented for discarted audio chunks, thuschunkId
may be used to judge whether any chunks were missed while a stream was muted.
ErrorListener
type ErrorListener = (error: Error) => void;
The type of error listeners that can be connected to an InputAudioStream with .addErrorListener() method.
error
— Error — Stream error.