@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
Maintainers
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.shManual Installation
Add the plugin to your project:
cordova plugin add ./cordova-plugin-audio-recorderAdd iOS platform (if not already added):
cordova platform add iosBuild 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
"Audio recorder plugin not available"
- Ensure the plugin is properly installed
- Check that the plugin is loaded after device ready
"Microphone permission not granted"
- Ensure the app has microphone permissions
- Check device settings for microphone access
"Failed to create audio recorder"
- Verify iOS platform is properly configured
- Check that AVFoundation and AudioToolbox frameworks are linked
"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.
