Audio input capture plugin for Cordova and Capacitor - Real-time microphone access with streaming and file recording support.
This plugin enables audio capture from the device microphone, forwarding raw audio data in (near) real-time to the web layer of your application. It provides similar functionality to Navigator.getUserMedia() with broader platform support.
π Version 2.0 now supports both Cordova and Capacitor from a single codebase!
- Real-time audio streaming - Get PCM audio data as it's captured
- Web Audio API integration - Use as an AudioNode in your audio processing chain
- File recording - Save directly to WAV files
- Cross-platform - Android, iOS, and browser support
- Dual ecosystem - Works with both Cordova and Capacitor
- TypeScript support - Full type definitions included
- Optimized performance - Buffer pooling and efficient data transfer
- Flexible configuration - Multiple sample rates, formats, and audio sources
From the Cordova Plugin Repository:
cordova plugin add cordova-plugin-audioinputOr from GitHub:
cordova plugin add https://github.com/edimuj/cordova-plugin-audioinput.gitnpm install cordova-plugin-audioinput npx cap sync| Platform | Cordova | Capacitor | Notes |
|---|---|---|---|
| Android | β | β | API 22+ |
| iOS | β | β | iOS 13+ |
| Browser | β | β | Web Audio API |
import { AudioInput } from 'cordova-plugin-audioinput'; // Initialize with configuration await AudioInput.initialize({ sampleRate: 44100, bufferSize: 16384, channels: 1, format: 'PCM_16BIT', normalize: true }); // Check/request microphone permission const { granted } = await AudioInput.checkMicrophonePermission(); if (!granted) { await AudioInput.getMicrophonePermission(); } // Listen for audio data AudioInput.addListener('audioData', (event) => { console.log(`Received ${event.data.length} samples`); // Process audio data... }); // Start capturing await AudioInput.start({ sampleRate: 44100, bufferSize: 16384 }); // Stop capturing await AudioInput.stop();// Check permission first audioinput.checkMicrophonePermission(function(hasPermission) { if (hasPermission) { startCapture(); } else { audioinput.getMicrophonePermission(function(granted) { if (granted) { startCapture(); } }); } }); function startCapture() { // Listen for audio data window.addEventListener('audioinput', function(event) { console.log('Received ' + event.data.length + ' samples'); // Process audio data... }); // Start capturing audioinput.start({ sampleRate: 44100, bufferSize: 16384, channels: 1, format: audioinput.FORMAT.PCM_16BIT, normalize: true }); } // Stop capturing audioinput.stop();This method lets the plugin handle data conversion and provides an AudioNode for Web Audio API integration.
import { AudioInput } from 'cordova-plugin-audioinput'; async function setupWebAudio() { // Request permission const { granted } = await AudioInput.getMicrophonePermission(); if (!granted) return; // Start with Web Audio integration // Note: For Capacitor, use the Cordova API via window.audioinput for streamToWebAudio const audioinput = (window as any).audioinput; audioinput.start({ streamToWebAudio: true }); // Connect to speakers to hear the captured audio audioinput.connect(audioinput.getAudioContext().destination); }function startCapture() { audioinput.start({ streamToWebAudio: true }); // Connect to device speakers audioinput.connect(audioinput.getAudioContext().destination); } // Check and request permission audioinput.checkMicrophonePermission(function(hasPermission) { if (hasPermission) { startCapture(); } else { audioinput.getMicrophonePermission(function(granted) { if (granted) startCapture(); }); } });Use this method for direct access to raw audio data for custom processing.
import { AudioInput } from 'cordova-plugin-audioinput'; async function setupRawAudio() { // Request permission await AudioInput.getMicrophonePermission(); // Listen for audio data AudioInput.addListener('audioData', (event) => { // event.data is an array of audio samples processAudioData(event.data); }); // Listen for errors AudioInput.addListener('audioError', (event) => { console.error('Audio error:', event.message); }); // Start capturing await AudioInput.start({ sampleRate: 44100, bufferSize: 8192, channels: 1, format: 'PCM_16BIT', normalize: true }); } function processAudioData(samples: number[]) { // Your audio processing logic here console.log(`Processing ${samples.length} samples`); } // Stop when done async function stopRecording() { await AudioInput.stop(); await AudioInput.removeAllListeners(); }function onAudioInput(event) { // event.data is an array of audio samples console.log('Audio data received: ' + event.data.length + ' samples'); processAudioData(event.data); } function onAudioInputError(error) { console.error('Audio error:', JSON.stringify(error)); } // Listen to events window.addEventListener('audioinput', onAudioInput, false); window.addEventListener('audioinputerror', onAudioInputError, false); // Start capturing audioinput.start({ sampleRate: 44100, bufferSize: 8192, channels: 1, format: audioinput.FORMAT.PCM_16BIT, normalize: true }); // Stop capturing audioinput.stop();Save audio directly to WAV files on the device.
import { AudioInput } from 'cordova-plugin-audioinput'; import { Filesystem, Directory } from '@capacitor/filesystem'; async function recordToFile() { await AudioInput.getMicrophonePermission(); // Listen for recording finished event AudioInput.addListener('audioInputFinished', async (event) => { console.log('Recording saved to:', event.fileUrl); // File is now available at event.fileUrl }); // Start recording to file const fileUrl = 'file:///path/to/recording.wav'; await AudioInput.start({ sampleRate: 16000, bufferSize: 8192, channels: 1, format: 'PCM_16BIT', fileUrl: fileUrl }); // When ready to stop const result = await AudioInput.stop(); console.log('Stopped, file at:', result.fileUrl); }// Get access to the file system window.requestFileSystem(window.TEMPORARY, 5*1024*1024, function(fs) { fileSystem = fs; // Initialize with file system directory var captureCfg = { sampleRate: 16000, bufferSize: 8192, channels: 1, format: audioinput.FORMAT.PCM_16BIT, fileUrl: cordova.file.cacheDirectory }; audioinput.initialize(captureCfg, function() { console.log('Initialized with file system access'); }); }); // Start recording to file var captureCfg = { fileUrl: cordova.file.cacheDirectory + 'recording.wav' }; audioinput.start(captureCfg); // Stop and get file URL audioinput.stop(function(fileUrl) { console.log('Recording saved to:', fileUrl); // Read the file window.resolveLocalFileSystemURL(fileUrl, function(fileEntry) { fileEntry.file(function(file) { var reader = new FileReader(); reader.onloadend = function() { var blob = new Blob([new Uint8Array(this.result)], { type: 'audio/wav' }); // Use the blob... }; reader.readAsArrayBuffer(file); }); }); });interface AudioInputOptions { // Sample rate in Hz sampleRate?: number; // Default: 44100 // Available: 8000, 11025, 16000, 22050, 32000, 44100, 48000 // Buffer size in bytes (should be power of 2, <= 16384) bufferSize?: number; // Default: 16384 // Number of channels channels?: number; // Default: 1 (Mono) // 1 = Mono, 2 = Stereo // Audio format format?: 'PCM_16BIT' | 'PCM_8BIT'; // Default: 'PCM_16BIT' // Normalize audio data to -1.0 to 1.0 range normalize?: boolean; // Default: true // Normalization factor (audio divided by this value) normalizationFactor?: number; // Default: 32767.0 // Audio source type audioSourceType?: number; // Default: 0 (DEFAULT) // 0 = DEFAULT // 1 = MIC (Android only) // 5 = CAMCORDER // 6 = VOICE_RECOGNITION (Android only) // 7 = VOICE_COMMUNICATION // 9 = UNPROCESSED // File URL for saving (when set, no data events are fired) fileUrl?: string; // Example: 'file:///path/to/file.wav' // Cordova-specific options (use via window.audioinput) streamToWebAudio?: boolean; // Let plugin handle Web Audio conversion audioContext?: AudioContext; // Provide your own AudioContext concatenateMaxChunks?: number;// Chunks to merge (lower = lower latency) }import { SampleRate, AudioSourceType } from 'cordova-plugin-audioinput'; const config = { sampleRate: SampleRate.CD_AUDIO_44100Hz, audioSourceType: AudioSourceType.VOICE_COMMUNICATION };var config = { sampleRate: audioinput.SAMPLERATE.CD_AUDIO_44100Hz, channels: audioinput.CHANNELS.MONO, format: audioinput.FORMAT.PCM_16BIT, audioSourceType: audioinput.AUDIOSOURCE_TYPE.VOICE_COMMUNICATION };Available constants:
SAMPLERATE:TELEPHONE_8000Hz,CD_QUARTER_11025Hz,VOIP_16000Hz,CD_HALF_22050Hz,MINI_DV_32000Hz,CD_AUDIO_44100Hz,DVD_AUDIO_48000HzCHANNELS:MONO,STEREOFORMAT:PCM_16BIT,PCM_8BITAUDIOSOURCE_TYPE:DEFAULT,MIC,CAMCORDER,VOICE_RECOGNITION,VOICE_COMMUNICATION,UNPROCESSED
import { AudioInput } from 'cordova-plugin-audioinput'; // Initialize (optional - can also configure in start()) await AudioInput.initialize(options: AudioInputOptions): Promise<void> // Check microphone permission (doesn't prompt user) await AudioInput.checkMicrophonePermission(): Promise<{ granted: boolean }> // Request microphone permission (prompts user if needed) await AudioInput.getMicrophonePermission(): Promise<{ granted: boolean }> // Start audio capture await AudioInput.start(options: AudioInputOptions): Promise<void> // Stop audio capture await AudioInput.stop(): Promise<{ fileUrl?: string }> // Add event listener AudioInput.addListener( 'audioData' | 'audioError' | 'audioInputFinished', callback ): PluginListenerHandle // Remove all listeners await AudioInput.removeAllListeners(): Promise<void>// Initialize (optional) audioinput.initialize(captureCfg, onComplete) // Check microphone permission audioinput.checkMicrophonePermission(callback) // Request microphone permission audioinput.getMicrophonePermission(callback) // Start capturing audioinput.start(captureCfg) // Stop capturing audioinput.stop(onStopped) // Check if capturing audioinput.isCapturing(): boolean // Get current configuration audioinput.getCfg(): object // Web Audio API methods (when streamToWebAudio: true) audioinput.connect(audioNode) audioinput.disconnect() audioinput.getAudioContext(): AudioContextaudioData- Fired when audio data is available (if not recording to file)audioError- Fired when an error occursaudioInputFinished- Fired when file recording completes
audioinput- Fired when audio data is available (if not recording to file)audioinputerror- Fired when an error occursaudioinputfinished- Fired when file recording completes (hasfileproperty)
// Cordova example - works in both platforms via window.audioinput var audioContext = new AudioContext(); audioinput.start({ streamToWebAudio: true, audioContext: audioContext }); // Create a custom processing chain var analyser = audioContext.createAnalyser(); var filter = audioContext.createBiquadFilter(); filter.type = 'lowpass'; filter.frequency.value = 1000; // Connect: mic β filter β analyser β speakers audioinput.connect(filter); filter.connect(analyser); analyser.connect(audioContext.destination); // Visualize audio function visualize() { var dataArray = new Uint8Array(analyser.frequencyBinCount); analyser.getByteFrequencyData(dataArray); // Draw visualization... requestAnimationFrame(visualize); } visualize();// Capacitor example import { AudioInput } from 'cordova-plugin-audioinput'; let silenceThreshold = 0.01; // Adjust based on your needs let isSpeaking = false; AudioInput.addListener('audioData', (event) => { // Calculate RMS (Root Mean Square) for volume detection const samples = event.data; let sum = 0; for (let i = 0; i < samples.length; i++) { sum += samples[i] * samples[i]; } const rms = Math.sqrt(sum / samples.length); // Detect speech if (rms > silenceThreshold && !isSpeaking) { console.log('Speech started'); isSpeaking = true; } else if (rms <= silenceThreshold && isSpeaking) { console.log('Speech stopped'); isSpeaking = false; } }); await AudioInput.start({ normalize: true });- app-audioinput-demo - Cordova demo app
- The
demofolder contains usage examples:webaudio-demo- Web Audio API AudioNode integrationevents-demo- Event-based raw audio data handlingwav-demo- WAV encoding and playbackfile-demo- File saving (requires cordova-plugin-file)
- β Capacitor support - Full Capacitor plugin implementation
- β TypeScript - Complete type definitions for Capacitor
- β Modern languages - Kotlin (Android) and Swift (iOS) wrappers
- β Promise-based API - Async/await support in Capacitor
- β Performance optimizations - Buffer pooling, efficient Base64 encoding
- β Bug fixes - Multiple critical bugs fixed
- β 100% backward compatible - Existing Cordova apps work unchanged
See CHANGELOG.md for full details.
- Not all audio configuration combinations are supported by all devices
- Default settings work on most devices
- Bluetooth microphone support varies by device
- File recording always produces WAV format
Contributions are welcome! Please ensure changes don't break backward compatibility.
- Fork the project
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
If you find this plugin useful, please:
- β Star the project on GitHub
- π’ Share it with others
- π° Donate via PayPal
Your support helps keep this project maintained and improved!
- Created by: Edin Mujkanovic
- Contributors: All contributors
- v2.0 Capacitor support: Enhanced with modern architecture and optimizations