Skip to content

High-performance audio capture plugin enabling real-time microphone access in Cordova and Capacitor apps. Stream normalized audio data, record to files, and build audio analyzers, voice apps, and DSP applications with ease.

License

Notifications You must be signed in to change notification settings

exelerus/cordova-plugin-audioinput

Repository files navigation

cordova-plugin-audioinput

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!

✨ Features

  • 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

πŸ“¦ Installation

Cordova

From the Cordova Plugin Repository:

cordova plugin add cordova-plugin-audioinput

Or from GitHub:

cordova plugin add https://github.com/edimuj/cordova-plugin-audioinput.git

Capacitor

npm install cordova-plugin-audioinput npx cap sync

🎯 Supported Platforms

Platform Cordova Capacitor Notes
Android βœ… βœ… API 22+
iOS βœ… βœ… iOS 13+
Browser βœ… βœ… Web Audio API

πŸš€ Quick Start

Capacitor (TypeScript)

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();

Cordova (JavaScript)

// 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();

πŸ“– Usage Examples

Method 1: Web Audio API Integration (AudioNode)

This method lets the plugin handle data conversion and provides an AudioNode for Web Audio API integration.

Capacitor

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); }

Cordova

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(); }); } });

Method 2: Event-Based Raw Audio Data

Use this method for direct access to raw audio data for custom processing.

Capacitor

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(); }

Cordova

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();

Method 3: Recording to Files

Save audio directly to WAV files on the device.

Capacitor

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); }

Cordova (with cordova-plugin-file)

// 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); }); }); });

βš™οΈ Configuration Options

AudioInputOptions (Capacitor) / captureCfg (Cordova)

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) }

Helper Constants

Capacitor (TypeScript)

import { SampleRate, AudioSourceType } from 'cordova-plugin-audioinput'; const config = { sampleRate: SampleRate.CD_AUDIO_44100Hz, audioSourceType: AudioSourceType.VOICE_COMMUNICATION };

Cordova (JavaScript)

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_48000Hz
  • CHANNELS: MONO, STEREO
  • FORMAT: PCM_16BIT, PCM_8BIT
  • AUDIOSOURCE_TYPE: DEFAULT, MIC, CAMCORDER, VOICE_RECOGNITION, VOICE_COMMUNICATION, UNPROCESSED

πŸ“š API Reference

Capacitor API

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>

Cordova API

// 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(): AudioContext

Events

Capacitor Events

  • audioData - Fired when audio data is available (if not recording to file)
  • audioError - Fired when an error occurs
  • audioInputFinished - Fired when file recording completes

Cordova Events

  • audioinput - Fired when audio data is available (if not recording to file)
  • audioinputerror - Fired when an error occurs
  • audioinputfinished - Fired when file recording completes (has file property)

πŸ”§ Advanced Usage

Custom Audio Processing Chain (Web Audio API)

// 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();

Voice Activity Detection

// 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 });

πŸ’Ύ Demo Apps

  • app-audioinput-demo - Cordova demo app
  • The demo folder contains usage examples:
    • webaudio-demo - Web Audio API AudioNode integration
    • events-demo - Event-based raw audio data handling
    • wav-demo - WAV encoding and playback
    • file-demo - File saving (requires cordova-plugin-file)

πŸ†• What's New in v2.0

  • βœ… 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.

πŸ› Known Issues & Limitations

  • 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

🀝 Contributing

Contributions are welcome! Please ensure changes don't break backward compatibility.

  1. Fork the project
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

πŸ’– Support This Project

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!

πŸ“œ License

MIT License

πŸ‘ Credits

  • Created by: Edin Mujkanovic
  • Contributors: All contributors
  • v2.0 Capacitor support: Enhanced with modern architecture and optimizations

πŸ”— Links

About

High-performance audio capture plugin enabling real-time microphone access in Cordova and Capacitor apps. Stream normalized audio data, record to files, and build audio analyzers, voice apps, and DSP applications with ease.

Topics

Resources

License

Code of conduct

Stars

Watchers

Forks

Sponsor this project

Packages

No packages published

Contributors 13