npm package: @management-and-computer-consultants/cordova-plugin-audio-recorder-ios
Description: Cordova Audio Recorder Plugin for iOS - Records audio as WAV and converts to blob
Author: Management and Computer Consultants
Latest version: 1.0.0

# 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:

```bash
# 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:**
   ```bash
   cordova plugin add ./cordova-plugin-audio-recorder
   ```

2. **Add iOS platform (if not already added):**
   ```bash
   cordova platform add ios
   ```

3. **Build the project:**
   ```bash
   cordova build ios
   ```

## 🔧 Usage

### Platform Detection and Recording Setup

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

```javascript
// 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

```javascript
// 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

```javascript
// 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

```javascript
$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

```javascript
$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

```javascript
// 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)

```javascript
// 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

```javascript
// 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

```javascript
// 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

```javascript
{
    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`:

```xml
<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.