cordova-plugin-audioinput
v2.1.3
Published
Audio input capture plugin for Cordova and Capacitor - real-time microphone access with streaming and file recording support
Maintainers
Readme
cordova-plugin-audioinput
Real-time microphone capture for Cordova and Capacitor with a single package.
Use this plugin when you need low-latency PCM chunks in JavaScript (streaming, VAD, waveform analysis, custom DSP) and when MediaRecorder is too high-level or too delayed.
Why This Plugin Exists
Mobile apps often need raw, continuous microphone frames, not just encoded audio blobs.
This plugin gives you:
- low-latency PCM chunk streaming to JS
- file recording support (WAV)
- one package for Cordova + Capacitor
- Android, iOS, and web implementations
Features
- Real-time PCM streaming (
audioData/audioinputevents) - Cordova native bridge now streams binary PCM payloads (ArrayBuffer) for lower bridge overhead
- Optional normalization (
-1.0 .. 1.0) for easier JS DSP - Optional WAV recording via
fileUrl - Microphone permission helpers
- TypeScript definitions for Capacitor
- Cordova Web Audio integration (
streamToWebAudio,connect,disconnect)
Platform Support
| Platform | Cordova | Capacitor | | --- | --- | --- | | Android | ✅ | ✅ | | iOS | ✅ | ✅ | | Browser | ✅ | ✅ |
Notes:
- Capacitor Android build config defaults to
minSdkVersion 24. - Capacitor iOS podspec uses deployment target
14.0. - Web support is intended for development/lightweight browser use-cases.
Installation
Cordova
cordova plugin add cordova-plugin-audioinputCapacitor
npm install cordova-plugin-audioinput
npx cap synciOS Permission String
Ensure NSMicrophoneUsageDescription exists in your app Info.plist.
Example:
<key>NSMicrophoneUsageDescription</key>
<string>This app needs microphone access to capture audio.</string>Quick Start (Capacitor)
import { AudioInput } from 'cordova-plugin-audioinput';
await AudioInput.initialize({
sampleRate: 44100,
bufferSize: 16384,
channels: 1,
format: 'PCM_16BIT',
normalize: true,
});
const permission = await AudioInput.checkMicrophonePermission();
if (!permission.granted) {
const requested = await AudioInput.getMicrophonePermission();
if (!requested.granted) throw new Error('Microphone permission denied');
}
const audioDataHandle = await AudioInput.addListener('audioData', event => {
// event.data is number[]
console.log('samples:', event.data.length);
});
const errorHandle = await AudioInput.addListener('audioError', event => {
console.error('audio error:', event.message);
});
await AudioInput.start();
// ... later
await AudioInput.stop();
await audioDataHandle.remove();
await errorHandle.remove();Capacitor File Recording
import { AudioInput } from 'cordova-plugin-audioinput';
await AudioInput.addListener('audioInputFinished', event => {
console.log('WAV file:', event.fileUrl);
});
await AudioInput.start({
sampleRate: 16000,
channels: 1,
format: 'PCM_16BIT',
fileUrl: 'file:///path/to/recording.wav',
});
// stop() resolves when capture stops.
// fileUrl is delivered via audioInputFinished event.
await AudioInput.stop();Quick Start (Cordova)
function onAudioInput(event) {
console.log('samples:', event.data.length);
}
function onAudioInputError(event) {
console.error('audio error:', event.message);
}
window.addEventListener('audioinput', onAudioInput, false);
window.addEventListener('audioinputerror', onAudioInputError, false);
audioinput.checkMicrophonePermission(function (hasPermission) {
if (hasPermission) {
startCapture();
return;
}
audioinput.getMicrophonePermission(function (granted) {
if (granted) startCapture();
});
});
function startCapture() {
audioinput.start({
sampleRate: 44100,
bufferSize: 16384,
channels: 1,
format: audioinput.FORMAT.PCM_16BIT,
normalize: true,
});
}
function stopCapture() {
audioinput.stop(function (fileUrl) {
if (fileUrl) console.log('Saved file:', fileUrl);
});
}API (Capacitor)
Methods
initialize(options: AudioInputOptions): Promise<void>checkMicrophonePermission(): Promise<{ granted: boolean }>getMicrophonePermission(): Promise<{ granted: boolean }>start(options?: AudioInputOptions): Promise<void>stop(): Promise<{ fileUrl?: string }>isCapturing(): Promise<{ capturing: boolean }>getCfg(): Promise<AudioInputOptions>removeAllListeners(): Promise<void>
Events
audioData→{ data: number[], sampleRate?, channels?, format?, timestamp? }audioError→{ message: string, code?: string }audioInputFinished→{ fileUrl: string, timestamp?: number }stateChange→{ state: 'idle' | 'capturing' | 'stopped' | 'error', message?, timestamp? }
API (Cordova)
Methods
audioinput.initialize(captureCfg, onComplete)audioinput.checkMicrophonePermission(callback)audioinput.getMicrophonePermission(callback)audioinput.start(captureCfg)audioinput.stop(onStopped)audioinput.isCapturing()audioinput.getCfg()audioinput.connect(audioNode)audioinput.disconnect()audioinput.getAudioContext()
Events
audioinput→{ data, sampleRate?, channels?, format?, timestamp? }audioinputerror→{ message }audioinputfinished→{ file, timestamp? }audioinputstatechange→{ state, message?, timestamp? }
Configuration (AudioInputOptions / captureCfg)
| Option | Type | Default | Notes |
| --- | --- | --- | --- |
| sampleRate | number | 44100 | Common values: 8000, 16000, 22050, 44100, 48000 |
| bufferSize | number | 16384 | Power-of-two is recommended |
| channels | 1 \| 2 | 1 | Mono or stereo |
| format | 'PCM_16BIT' \| 'PCM_8BIT' | 'PCM_16BIT' | PCM_16BIT recommended |
| normalize | boolean | true | Normalize to float range -1..1 |
| normalizationFactor | number | 32767.0 | Used when normalize=true |
| audioSourceType | number | 0 | See source constants |
| fileUrl | string | undefined | Record to WAV file instead of streaming events |
Cordova-only additions:
| Option | Type | Default | Notes |
| --- | --- | --- | --- |
| streamToWebAudio | boolean | false | Pipe captured audio through Web Audio API |
| audioContext | AudioContext | auto | Provide your own context |
| concatenateMaxChunks | number | 10 | Queue merge tuning |
Constants
Capacitor
import { SampleRate, AudioSourceType } from 'cordova-plugin-audioinput';Cordova
audioinput.SAMPLERATE
audioinput.CHANNELS
audioinput.FORMAT
audioinput.AUDIOSOURCE_TYPEPerformance Tips
- Prefer
PCM_16BITunless you have a hard requirement forPCM_8BIT. - Start with mono (
channels: 1) andsampleRate: 16000for speech workloads. - Use larger
bufferSizefor lower CPU usage and smallerbufferSizefor lower latency. - If you only need files, set
fileUrland skip streaming processing. - Run
npm run bench:jsfor a quick synthetic JS hot-path benchmark.
Known Limitations
- Device support for sample-rate/channel combinations varies.
- Bluetooth microphone routing behavior varies by OS/device.
streamToWebAudiois a Cordova API surface (viawindow.audioinput).- Web implementation does not persist
fileUrlrecordings (it emits anaudioErrorwarning and continues streaming).
Demo / Test Apps
- app-audioinput-demo
- Local harnesses in
test-apps:test-apps/cordova-test-apptest-apps/capacitor-test-app
Changelog
See CHANGELOG.md.
Contributing
PRs are welcome. Please keep backward compatibility for existing Cordova integrations.
License
MIT — see LICENSE.
