npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@management-and-computer-consultants/cordova-plugin-audio-recorder-ios

v1.0.0

Published

Cordova Audio Recorder Plugin for iOS - Records audio as WAV and converts to blob

Readme

Cordova Audio Recorder Plugin for iOS

A Cordova plugin for recording audio on iOS devices using AVFoundation. This plugin is specifically designed to work with Ionic1/AngularJS projects and provides comprehensive audio recording capabilities.

🎯 Features

  • Audio Recording: Record audio in WAV and M4A formats
  • Quality Control: Configurable audio quality settings
  • Pause/Resume: Pause and resume recording functionality
  • Interval Recording: Record for a specified duration automatically
  • Permission Handling: Built-in microphone permission management
  • Blob Conversion: Convert recorded audio to base64 blob for API transmission
  • State Management: Track recording state (stopped, recording, paused)
  • Platform Detection: Automatic iOS/Android platform detection and appropriate recording method selection

📋 Requirements

  • Cordova 9.0.0 or higher
  • cordova-ios 5.1.0 or higher
  • iOS 9.0 or higher
  • Xcode 10.0 or higher

🚀 Installation

Quick Installation (Recommended)

For Ionic1/AngularJS projects, use the provided installation script:

# Make sure you're in your Cordova project root directory
cd your-cordova-project

# Run the installation script
./cordova-plugin-audio-recorder/install-for-ionic1-project.sh

Manual Installation

  1. Add the plugin to your project:

    cordova plugin add ./cordova-plugin-audio-recorder
  2. Add iOS platform (if not already added):

    cordova platform add ios
  3. Build the project:

    cordova build ios

🔧 Usage

Platform Detection and Recording Setup

The plugin is designed to work alongside MediaRecorder API for Android, with automatic platform detection:

// Platform detection and recording function selection
$scope.startRecordingPlatform = function () {
    console.log('Platform detection for recording...');
    console.log('Device platform:', device.platform);

    // Check if we're on iOS
    if (device.platform === 'iOS' || device.platform === 'ios') {
        console.log('Using iOS audio recorder plugin');
        $scope.startRecordingIOS();
    } else {
        console.log('Using MediaRecorder API');
        $scope.startRecording();
    }
};

iOS-Specific Recording Implementation

// iOS-specific recording functions using cordova-plugin-audio-recorder
$scope.startRecordingIOS = function () {
    console.log('Starting iOS recording...');

    // Check if the audio recorder plugin is available
    if (!navigator.audioRecorder) {
        console.error('Audio recorder plugin not available');
        alert('Audio recording plugin not available on this device.');
        return;
    }

    // Configure recording options for continuous recording
    // Use M4A format for better iOS compatibility
    var recordingOptions = {
        quality: navigator.audioRecorder.Quality.HIGH,
        format: navigator.audioRecorder.Format.M4A, // Use M4A instead of WAV
        sampleRate: 44100,
        channels: 1,
        fileName: 'Audio_' + Date.now() // Remove the .m4a extension, let plugin handle it
    };

    console.log('iOS recording options:', recordingOptions);

    // Start continuous recording using the installed plugin
    navigator.audioRecorder.startRecording(
        function (result) {
            console.log('iOS recording started successfully:', result);

            // Set recording state
            $scope.data.isIOSRecording = true;
            $scope.data.recording = true;
            $scope.data.recordingStartTime = Date.now();

            // Start the timer
            $scope.startTimer();
            $scope.$apply();
        },
        function (error) {
            console.error('Failed to start iOS recording:', error);
            alert('Failed to start recording: ' + error);
        },
        recordingOptions
    );
};

iOS Permission Handling

// iOS-specific permission check
$scope.checkIOSAudioPermission = function () {
    console.log('Checking iOS audio permission...');

    if (!navigator.audioRecorder) {
        console.error('Audio recorder plugin not available');
        alert('Audio recording plugin not available on this device.');
        return;
    }

    // Check permission using the plugin
    navigator.audioRecorder.checkPermission(
        function (permission) {
            console.log('iOS permission status:', permission);
            if (permission === 'granted') {
                $scope.proceedWithIOSRecording();
            } else {
                // Request permission
                navigator.audioRecorder.requestPermission(
                    function (result) {
                        console.log('iOS permission granted:', result);
                        $scope.proceedWithIOSRecording();
                    },
                    function (error) {
                        console.error('iOS permission denied:', error);
                        alert('Audio permission is required to record. Please allow access in your app settings.');
                    }
                );
            }
        },
        function (error) {
            console.error('iOS permission check failed:', error);
            // Fallback to direct recording attempt
            $scope.proceedWithIOSRecording();
        }
    );
};

Stopping iOS Recording

$scope.stopRecordingIOS = function () {
    console.log("Stopping iOS recording...");

    if (!navigator.audioRecorder || !$scope.data.isIOSRecording) {
        console.log("No active recording to stop");
        return;
    }

    // Stop the recording
    navigator.audioRecorder.stopRecording(
        function (result) {
            console.log("iOS recording stopped successfully:", result);

            // Process the recorded audio
            if (result && result.audioData) {
                $scope.data.audioFileName = result.fileName || "Audio_" + Date.now() + ".m4a";
                $scope.data.audioFileSize = result.fileSize || 0;
                $scope.data.audioDuration = result.duration || 0;

                // Convert base64 to blob for API transmission
                var byteCharacters = atob(result.audioData);
                var byteNumbers = new Array(byteCharacters.length);
                for (var i = 0; i < byteCharacters.length; i++) {
                    byteNumbers[i] = byteCharacters.charCodeAt(i);
                }
                var byteArray = new Uint8Array(byteNumbers);
                $scope.data.wavBlob = new Blob([byteArray], {
                    type: result.mimeType || "audio/mp4",
                });

                // Create audio URL for playback
                $scope.data.audioFile = $sce.trustAsResourceUrl(result.audioBlob);
                $scope.data.audio = new Audio($scope.data.audioFile);

                // Set up audio playback events
                $scope.data.audio.onloadedmetadata = function () {
                    $scope.data.audioDuration = $scope.data.audio.duration;
                    $scope.$apply();
                };

                $scope.data.audio.ontimeupdate = function () {
                    $scope.data.time = Math.floor($scope.data.audio.currentTime);
                    $scope.$apply();
                };

                $scope.data.audio.onended = function () {
                    $scope.data.isAudio = false;
                    $scope.$apply();
                };

                $scope.data.isIOSRecording = false;
                $scope.data.recording = false;
                $scope.stopTimer();
                $scope.$apply();

                // Show save confirmation popup
                $ionicPopup.show({
                    title: "Save Recording",
                    template: "Are you sure, you want to save the recording?",
                    buttons: [
                        {
                            text: "No",
                            type: "button-dark",
                            onTap: function (e) {
                                $state.go("eyes-and-ear");
                            },
                        },
                        {
                            text: "Yes",
                            type: "button-positive",
                            onTap: function () {
                                $scope.saveRecording();
                            },
                        },
                    ],
                });
            } else {
                console.error("No audio data received from recording");
                alert("Failed to process recording: No audio data received");
            }
        },
        function (error) {
            console.error("Failed to stop iOS recording:", error);
            alert("Failed to stop recording: " + error);
        }
    );
};

Timer Integration

$scope.startTimer = function () {
    if ($scope.data.recordingTimer) clearInterval($scope.data.recordingTimer);
    $scope.data.recordingTimer = setInterval(function () {
        $scope.data.recordingTime -= 0.1;
        if ($scope.data.recordingTime <= 0) {
            $scope.data.recordingTime = 0;
            $scope.stopTimer(); // Stop the timer immediately
            if ($scope.data.recording) { // Only call if still recording
                if ($scope.data.isIOSRecording) {
                    $scope.stopRecordingIOS();
                } else {
                    $scope.stopRecording();
                }
            }
            return;
        }
        $scope.$apply();
    }, 100);
};

$scope.stopTimer = function () {
    if ($scope.data.recordingTimer) {
        clearInterval($scope.data.recordingTimer);
        $scope.data.recordingTimer = null;
    }
};

Cleanup on Controller Destroy

// Clean up when controller is destroyed
$scope.$on('$destroy', function () {
    $scope.stopTimer();

    // Stop iOS recording if active
    if ($scope.data.isIOSRecording && navigator.audioRecorder) {
        try {
            // For recordWithInterval, we can only cancel by setting the flag
            // The recording will automatically stop after the duration
            $scope.data.isCanceling = true;
            console.log('iOS recording will be canceled on destroy');
        } catch (error) {
            console.error('Error canceling iOS recording on destroy:', error);
        }
    }

    // Stop Android recording if active
    if ($scope.data.mediaRecorder && $scope.data.recording) {
        try {
            $scope.data.mediaRecorder.stop();
        } catch (error) {
            console.error('Error stopping recording on destroy:', error);
        }
    }

    // Stop all media streams
    if ($scope.data.mediaStream) {
        $scope.data.mediaStream.getTracks().forEach(function (track) {
            track.stop();
        });
        $scope.data.mediaStream = null;
    }
});

Basic Recording (Legacy API)

// Start recording
navigator.audioRecorder.startRecording(
    function(success) {
        console.log('Recording started:', success);
    },
    function(error) {
        console.error('Recording failed:', error);
    },
    {
        quality: navigator.audioRecorder.Quality.MEDIUM,
        format: navigator.audioRecorder.Format.M4A,
        sampleRate: 44100,
        channels: 1,
        fileName: 'my_recording.m4a'
    }
);

// Stop recording
navigator.audioRecorder.stopRecording(
    function(result) {
        console.log('Recording completed:', result);
        // result contains: audioData, audioBlob, filePath, duration, fileSize, format, mimeType
    },
    function(error) {
        console.error('Stop recording failed:', error);
    }
);

Permission Handling

// Request microphone permission
navigator.audioRecorder.requestPermission(
    function(status) {
        console.log('Permission status:', status); // 'granted' or 'denied'
    },
    function(error) {
        console.error('Permission request failed:', error);
    }
);

// Check current permission status
navigator.audioRecorder.checkPermission(
    function(status) {
        console.log('Current permission:', status);
    },
    function(error) {
        console.error('Permission check failed:', error);
    }
);

📱 API Reference

Constants

// Audio Quality
navigator.audioRecorder.Quality.LOW    // 0 - 64 kbps AAC
navigator.audioRecorder.Quality.MEDIUM // 1 - 128 kbps AAC (default)
navigator.audioRecorder.Quality.HIGH   // 2 - 256 kbps AAC

// Audio Format
navigator.audioRecorder.Format.WAV     // 'wav' - Uncompressed WAV
navigator.audioRecorder.Format.M4A     // 'm4a' - AAC in M4A container (recommended)
navigator.audioRecorder.Format.CAF     // 'caf' - Core Audio Format

// Recording State
navigator.audioRecorder.State.STOPPED  // 'stopped'
navigator.audioRecorder.State.RECORDING // 'recording'
navigator.audioRecorder.State.PAUSED   // 'paused'

Methods

| Method | Description | Parameters | |--------|-------------|------------| | startRecording | Start audio recording | success, error, options | | stopRecording | Stop current recording | success, error | | pauseRecording | Pause current recording | success, error | | resumeRecording | Resume paused recording | success, error | | getRecordingState | Get current recording state | success, error | | convertToBlob | Convert audio file to blob | filePath, success, error | | requestPermission | Request microphone permission | success, error | | checkPermission | Check microphone permission | success, error | | recordWithInterval | Record for specified duration | success, error, options |

Options

{
    quality: navigator.audioRecorder.Quality.MEDIUM, // Audio quality
    format: navigator.audioRecorder.Format.M4A,      // Audio format
    sampleRate: 44100,                               // Sample rate in Hz
    channels: 1,                                     // Number of channels (1=mono, 2=stereo)
    maxDuration: 300,                                // Maximum recording duration (seconds)
    fileName: null,                                  // Custom filename
    saveToLibrary: false,                            // Save to device audio library
    duration: 30                                     // For interval recording (seconds)
}

🔒 Permissions

The plugin automatically adds the following permission to your Info.plist:

<key>NSMicrophoneUsageDescription</key>
<string>This app requires Microphone to record audio for voice to text transcript</string>

🛠 Troubleshooting

Common Issues

  1. "Audio recorder plugin not available"

    • Ensure the plugin is properly installed
    • Check that the plugin is loaded after device ready
  2. "Microphone permission not granted"

    • Ensure the app has microphone permissions
    • Check device settings for microphone access
  3. "Failed to create audio recorder"

    • Verify iOS platform is properly configured
    • Check that AVFoundation and AudioToolbox frameworks are linked
  4. "Audio session activation failed"

    • Ensure no other audio is playing
    • Check audio session configuration

Debug Mode

Enable debug logging by checking the Xcode console for detailed error messages and status updates.

📄 License

Apache License 2.0

🤝 Contributing

This plugin is specifically maintained for Ionic1/AngularJS project compatibility. For issues or improvements, please ensure compatibility with the existing project structure.

📞 Support

For support with this plugin in your Ionic1/AngularJS project, refer to the project documentation or contact the development team.