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