capacitor-voice-recorder-wav-stereo 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/CapacitorVoiceRecorderWavStereo.podspec +17 -0
  2. package/README.md +213 -0
  3. package/android/build.gradle +58 -0
  4. package/android/src/main/AndroidManifest.xml +3 -0
  5. package/android/src/main/java/com/tchvu3/capacitorvoicerecorder/CurrentRecordingStatus.java +7 -0
  6. package/android/src/main/java/com/tchvu3/capacitorvoicerecorder/CustomMediaRecorder.java +187 -0
  7. package/android/src/main/java/com/tchvu3/capacitorvoicerecorder/Messages.java +15 -0
  8. package/android/src/main/java/com/tchvu3/capacitorvoicerecorder/NotSupportedOsVersion.java +4 -0
  9. package/android/src/main/java/com/tchvu3/capacitorvoicerecorder/RecordData.java +51 -0
  10. package/android/src/main/java/com/tchvu3/capacitorvoicerecorder/ResponseGenerator.java +37 -0
  11. package/android/src/main/java/com/tchvu3/capacitorvoicerecorder/VoiceRecorder.java +217 -0
  12. package/android/src/main/res/.gitkeep +0 -0
  13. package/dist/docs.json +174 -0
  14. package/dist/esm/VoiceRecorderImpl.d.ts +19 -0
  15. package/dist/esm/VoiceRecorderImpl.js +172 -0
  16. package/dist/esm/VoiceRecorderImpl.js.map +1 -0
  17. package/dist/esm/definitions.d.ts +24 -0
  18. package/dist/esm/definitions.js +2 -0
  19. package/dist/esm/definitions.js.map +1 -0
  20. package/dist/esm/index.d.ts +4 -0
  21. package/dist/esm/index.js +7 -0
  22. package/dist/esm/index.js.map +1 -0
  23. package/dist/esm/predefined-web-responses.d.ts +12 -0
  24. package/dist/esm/predefined-web-responses.js +12 -0
  25. package/dist/esm/predefined-web-responses.js.map +1 -0
  26. package/dist/esm/web.d.ts +13 -0
  27. package/dist/esm/web.js +33 -0
  28. package/dist/esm/web.js.map +1 -0
  29. package/dist/plugin.cjs.js +228 -0
  30. package/dist/plugin.cjs.js.map +1 -0
  31. package/dist/plugin.js +230 -0
  32. package/dist/plugin.js.map +1 -0
  33. package/ios/Plugin/CurrentRecordingStatus.swift +9 -0
  34. package/ios/Plugin/CustomMediaRecorder.swift +82 -0
  35. package/ios/Plugin/Info.plist +24 -0
  36. package/ios/Plugin/Messages.swift +15 -0
  37. package/ios/Plugin/RecordData.swift +17 -0
  38. package/ios/Plugin/ResponseGenerator.swift +28 -0
  39. package/ios/Plugin/VoiceRecorder.swift +130 -0
  40. package/ios/Plugin/VoiceRecorderPlugin.h +10 -0
  41. package/ios/Plugin/VoiceRecorderPlugin.m +15 -0
  42. package/package.json +92 -0
@@ -0,0 +1,17 @@
1
+ require 'json'
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
4
+
5
+ Pod::Spec.new do |s|
6
+ s.name = 'CapacitorVoiceRecorderWavStereo'
7
+ s.version = package['version']
8
+ s.summary = package['description']
9
+ s.license = package['license']
10
+ s.homepage = package['repository']['url']
11
+ s.author = package['author']
12
+ s.source = { :git => package['repository']['url'], :tag => s.version.to_s }
13
+ s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}'
14
+ s.ios.deployment_target = '13.0'
15
+ s.dependency 'Capacitor'
16
+ s.swift_version = '5.1'
17
+ end
package/README.md ADDED
@@ -0,0 +1,213 @@
1
+ <p align="center">
2
+ <img src="https://user-images.githubusercontent.com/236501/85893648-1c92e880-b7a8-11ea-926d-95355b8175c7.png" width="128" height="128" />
3
+ </p>
4
+ <h3 align="center">Capacitor Voice Recorder</h3>
5
+ <p align="center"><strong><code>tchvu3/capacitor-voice-recorder</code></strong></p>
6
+ <p align="center">Capacitor plugin for simple voice recording (For Capacitor 5)</p>
7
+
8
+ <p align="center">
9
+ <img src="https://img.shields.io/maintenance/yes/2023" />
10
+ <a href="https://www.npmjs.com/package/capacitor-voice-recorder"><img src="https://img.shields.io/npm/l/capacitor-voice-recorder" /></a>
11
+ <br>
12
+ <a href="https://www.npmjs.com/package/capacitor-voice-recorder"><img src="https://img.shields.io/npm/dw/capacitor-voice-recorder" /></a>
13
+ <a href="https://www.npmjs.com/package/capacitor-voice-recorder"><img src="https://img.shields.io/npm/v/capacitor-voice-recorder" /></a>
14
+ </p>
15
+
16
+ ## Maintainers
17
+
18
+ | Maintainer | GitHub |
19
+ | -----------| -------|
20
+ | Avihu Harush | [tchvu3](https://github.com/tchvu3) |
21
+
22
+ ## Installation
23
+
24
+ ```
25
+ npm install --save capacitor-voice-recorder
26
+ npx cap sync
27
+ ```
28
+
29
+ #### ios note
30
+
31
+ Make sure to include the ```NSMicrophoneUsageDescription```
32
+ key, and a corresponding purpose string in your app's Info.plist
33
+
34
+ ## Configuration
35
+
36
+ No configuration required for this plugin.
37
+
38
+ ## Supported methods
39
+
40
+ | Name | Android | iOS | Web |
41
+ | :------------------------------ | :------ | :-- | :-- |
42
+ | canDeviceVoiceRecord | ✅ | ✅ | ✅ |
43
+ requestAudioRecordingPermission | ✅ | ✅ | ✅ |
44
+ | hasAudioRecordingPermission | ✅ | ✅ | ✅ |
45
+ | startRecording | ✅ | ✅ | ✅ |
46
+ | stopRecording | ✅ | ✅ | ✅ |
47
+ | pauseRecording | ✅ | ✅ | ✅ |
48
+ | resumeRecording | ✅ | ✅ | ✅ |
49
+ | getCurrentStatus | ✅ | ✅ | ✅ |
50
+
51
+ ## Explanation
52
+
53
+ * canDeviceVoiceRecord - on mobile this function will always return a promise that resolves to `{ value: true }`,
54
+ while in a browser it will be resolved to `{ value: true }` / `{ value: false }` based on the browser's ability to record.
55
+ note that this method does not take into account the permission status,
56
+ only if the browser itself is capable of recording at all.
57
+
58
+ ---
59
+
60
+ * requestAudioRecordingPermission - if the permission has already been provided then the promise will resolve with `{ value: true }`,
61
+ otherwise the promise will resolve to `{ value: true }` / `{ value: false }` based on the answer of the user to the request.
62
+
63
+ ---
64
+
65
+ * hasAudioRecordingPermission - will resolve to `{ value: true }` / `{ value: false }` based on the status of the permission.
66
+ please note that the web implementation of this plugin uses the Permissions API under the hood which is not widespread as of now.
67
+ as a result, if the status of the permission cannot be checked the promise will reject with `COULD_NOT_QUERY_PERMISSION_STATUS`.
68
+ in that case you have no choice but to use the `requestAudioRecordingPermission` function straight away or `startRecording` and capture any exception that is thrown.
69
+
70
+ ---
71
+
72
+ * startRecording - if the app lacks the required permission then the promise will reject with the message `MISSING_PERMISSION`.
73
+ if the current device cannot voice record at all (for example, due to old browser) then the promise will reject with `DEVICE_CANNOT_VOICE_RECORD`.
74
+ if there's a recording already running then the promise will reject with `ALREADY_RECORDING`,
75
+ and if other apps are using the microphone then the promise will reject
76
+ with `MICROPHONE_BEING_USED`. in a case of unknown error the promise will reject with `FAILED_TO_RECORD`.
77
+
78
+ ---
79
+
80
+ * stopRecording - will stop the recording that has been previously started. if the function `startRecording` has not been called beforehand
81
+ the promise will reject with `RECORDING_HAS_NOT_STARTED`.
82
+ if the recording has been stopped immediately after it has been started the promise will reject with `EMPTY_RECORDING`.
83
+ in a case of unknown error the promise will reject with `FAILED_TO_FETCH_RECORDING`.
84
+ in case of success, you will get the recording in base-64, the duration of the
85
+ recording in milliseconds, and the mime type.
86
+
87
+ ---
88
+
89
+ * pauseRecording - will pause an ongoing recording. note that if the recording has not started yet the promise
90
+ will reject with `RECORDING_HAS_NOT_STARTED`. in case of success the promise will resolve to `{ value: true }` if the pause
91
+ was successful or `{ value: false }` if the recording is already paused.
92
+ note that on certain mobile os versions this function is not supported.
93
+ in these cases the function will reject with `NOT_SUPPORTED_OS_VERSION` and your only viable options is to stop the recording instead.
94
+
95
+ ---
96
+
97
+ * resumeRecording - will resume a paused recording. note that if the recording has not started yet the promise
98
+ will reject with `RECORDING_HAS_NOT_STARTED`. in case of success the promise will resolve to `{ value: true }` if the resume
99
+ was successful or `{ value: false }` if the recording is already running.
100
+ note that on certain mobile os versions this function is not supported.
101
+ in these cases the function will reject with `NOT_SUPPORTED_OS_VERSION` and your only viable options is to stop the recording instead
102
+
103
+ ---
104
+
105
+ * getCurrentStatus - will let you know the current status of the current recording (if there is any at all).
106
+ will resolve with one of the following values: `{ status: "NONE" }` if the plugin is idle and waiting to start a new recording.
107
+ `{ status: "RECORDING" }` if the plugin is in the middle of recording and `{ status: "PAUSED" }` if the recording is paused right now.
108
+
109
+ ## Usage
110
+
111
+ ```
112
+
113
+ // only 'VoiceRecorder' is mandatory, the rest is for typing
114
+ import { VoiceRecorder, VoiceRecorderPlugin, RecordingData, GenericResponse, CurrentRecordingStatus } from 'capacitor-voice-recorder';
115
+
116
+ // will print true / false based on the ability of the current device (or web browser) to record audio
117
+ VoiceRecorder.canDeviceVoiceRecord().then((result: GenericResponse) => console.log(result.value))
118
+
119
+ /**
120
+ * will prompt the user to give the required permission, after that
121
+ * the function will print true / false based on the user response
122
+ */
123
+ VoiceRecorder.requestAudioRecordingPermission().then((result: GenericResponse) => console.log(result.value))
124
+
125
+ /**
126
+ * will print true / false based on the status of the recording permission.
127
+ * the promise will reject with "COULD_NOT_QUERY_PERMISSION_STATUS"
128
+ * if the current device cannot query the current status of the recording permission
129
+ */
130
+ VoiceRecorder.hasAudioRecordingPermission.then((result: GenericResponse) => console.log(result.value))
131
+
132
+ /**
133
+ * In case of success the promise will resolve to { value: true }
134
+ * in case of an error the promise will reject with one of the following messages:
135
+ * "MISSING_PERMISSION", "ALREADY_RECORDING", "MICROPHONE_BEING_USED", "DEVICE_CANNOT_VOICE_RECORD", or "FAILED_TO_RECORD"
136
+ */
137
+ VoiceRecorder.startRecording()
138
+ .then((result: GenericResponse) => console.log(result.value))
139
+ .catch(error => console.log(error))
140
+
141
+ /**
142
+ * In case of success the promise will resolve to:
143
+ * {"value": { recordDataBase64: string, msDuration: number, mimeType: string }},
144
+ * the file will be in one of several possible formats (more on that later).
145
+ * in case of an error the promise will reject with one of the following messages:
146
+ * "RECORDING_HAS_NOT_STARTED" or "FAILED_TO_FETCH_RECORDING"
147
+ */
148
+ VoiceRecorder.stopRecording()
149
+ .then((result: RecordingData) => console.log(result.value))
150
+ .catch(error => console.log(error))
151
+
152
+ /**
153
+ * will pause an ongoing recording. note that if the recording has not started yet the promise
154
+ * will reject with `RECORDING_HAS_NOT_STARTED`. in case of success the promise will resolve to `{ value: true }` if the pause
155
+ * was successful or `{ value: false }` if the recording is already paused.
156
+ * if the current mobile os does not support this method the promise will reject with `NOT_SUPPORTED_OS_VERSION`
157
+ */
158
+ VoiceRecorder.pauseRecording()
159
+ .then((result: GenericResponse) => console.log(result.value))
160
+ .catch(error => console.log(error))
161
+
162
+ /**
163
+ * will resume a paused recording. note that if the recording has not started yet the promise
164
+ * will reject with `RECORDING_HAS_NOT_STARTED`. in case of success the promise will resolve to `{ value: true }` if the resume
165
+ * was successful or `{ value: false }` if the recording is already running.
166
+ * if the current mobile os does not support this method the promise will reject with `NOT_SUPPORTED_OS_VERSION`
167
+ */
168
+ VoiceRecorder.resumeRecording()
169
+ .then((result: GenericResponse) => console.log(result.value))
170
+ .catch(error => console.log(error))
171
+
172
+ /**
173
+ * Will return the current status of the plugin.
174
+ * in this example one of these possible values will be printed: "NONE" / "RECORDING" / "PAUSED"
175
+ */
176
+ VoiceRecorder.getCurrentStatus()
177
+ .then((result: CurrentRecordingStatus) => console.log(result.status))
178
+ .catch(error => console.log(error))
179
+
180
+ ```
181
+
182
+ ## Format and Mime type
183
+
184
+ The plugin will return the recording in one of several possible formats.
185
+ the format is dependent on the os / web browser that the user uses.
186
+ on android and ios the mime type will be `audio/aac`, while on chrome and firefox it
187
+ will be `audio/webm;codecs=opus` and on safari it will be `audio/mp4`.
188
+ note that these 3 browsers has been tested on. the plugin should still work on
189
+ other browsers, as there is a list of mime types that the plugin checks against the
190
+ user's browser.
191
+
192
+ Note that this fact might cause unexpected behavior in case you'll try to play recordings
193
+ between several devices or browsers - as they not all support the same set of audio formats.
194
+ it is recommended to convert the recordings to a format that all your target devices supports.
195
+ as this plugin focuses on the recording aspect, it does not provide any conversion between formats.
196
+
197
+ ## Playback
198
+
199
+ To play the recorded file you can use plain javascript:
200
+
201
+ ```
202
+ const base64Sound = '...' // from plugin
203
+ const mimeType = '...' // from plugin
204
+ const audioRef = new Audio(`data:${mimeType};base64,${base64Sound}`)
205
+ audioRef.oncanplaythrough = () => audioRef.play()
206
+ audioRef.load()
207
+ ```
208
+
209
+ ## Donation
210
+
211
+ If you enjoy my work and find it useful, feel free to invite me to a cup of coffee :)
212
+
213
+ [!["Buy Me A Coffee"](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/tchvu3)
@@ -0,0 +1,58 @@
1
+ ext {
2
+ junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2'
3
+ androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.6.1'
4
+ androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.5'
5
+ androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.5.1'
6
+ }
7
+
8
+ buildscript {
9
+ repositories {
10
+ google()
11
+ mavenCentral()
12
+ }
13
+ dependencies {
14
+ classpath 'com.android.tools.build:gradle:8.2.1'
15
+ }
16
+ }
17
+
18
+ apply plugin: 'com.android.library'
19
+
20
+ android {
21
+ namespace "com.tchvu3.capacitorvoicerecorder"
22
+ compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 33
23
+ defaultConfig {
24
+ minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 22
25
+ targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 33
26
+ versionCode 1
27
+ versionName "1.0"
28
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
29
+ }
30
+ buildTypes {
31
+ release {
32
+ minifyEnabled false
33
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
34
+ }
35
+ }
36
+ lintOptions {
37
+ abortOnError false
38
+ }
39
+ compileOptions {
40
+ sourceCompatibility JavaVersion.VERSION_17
41
+ targetCompatibility JavaVersion.VERSION_17
42
+ }
43
+ }
44
+
45
+ repositories {
46
+ google()
47
+ mavenCentral()
48
+ }
49
+
50
+
51
+ dependencies {
52
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
53
+ implementation project(':capacitor-android')
54
+ implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
55
+ testImplementation "junit:junit:$junitVersion"
56
+ androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
57
+ androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
58
+ }
@@ -0,0 +1,3 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
+ <uses-permission android:name="android.permission.RECORD_AUDIO" />
3
+ </manifest>
@@ -0,0 +1,7 @@
1
+ package com.tchvu3.capacitorvoicerecorder;
2
+
3
+ public enum CurrentRecordingStatus {
4
+
5
+ RECORDING, PAUSED, NONE
6
+
7
+ }
@@ -0,0 +1,187 @@
1
+ package com.tchvu3.capacitorvoicerecorder;
2
+
3
+ import android.content.Context;
4
+ import android.media.AudioFormat;
5
+ import android.media.AudioRecord;
6
+ import android.media.MediaRecorder;
7
+ import android.os.Build;
8
+ import android.util.Log;
9
+
10
+ import java.io.File;
11
+ import java.io.FileOutputStream;
12
+ import java.io.FileInputStream;
13
+ import java.io.IOException;
14
+ import java.nio.ByteBuffer;
15
+ import java.nio.ByteOrder;
16
+
17
+
18
+ public class CustomMediaRecorder {
19
+
20
+ private final Context context;
21
+ private AudioRecord audioRecord;
22
+ private File outputFile;
23
+ private CurrentRecordingStatus currentRecordingStatus = CurrentRecordingStatus.NONE;
24
+ private Thread recordingThread;
25
+ private boolean isRecording = false;
26
+
27
+ private static final int SAMPLE_RATE = 44100;
28
+ private static final int CHANNEL_CONFIG = AudioFormat.CHANNEL_IN_STEREO;
29
+ private static final int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
30
+
31
+ public CustomMediaRecorder(Context context) {
32
+ this.context = context;
33
+ }
34
+
35
+ public void initializeAudioRecord() throws IOException {
36
+ int minBufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE, CHANNEL_CONFIG, AUDIO_FORMAT);
37
+ try {
38
+ audioRecord = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, SAMPLE_RATE, CHANNEL_CONFIG, AUDIO_FORMAT, minBufferSize);
39
+ } catch (SecurityException e) {
40
+ throw new IOException("Missing permission to record audio", e);
41
+ }
42
+ setRecorderOutputFile();
43
+ }
44
+
45
+ private void setRecorderOutputFile() throws IOException {
46
+ File outputDir = context.getCacheDir();
47
+ outputFile = File.createTempFile("voice_record_temp", ".wav", outputDir);
48
+ outputFile.deleteOnExit();
49
+ }
50
+
51
+ public void startRecording() throws IOException {
52
+ if (audioRecord == null) {
53
+ initializeAudioRecord();
54
+ }
55
+ audioRecord.startRecording();
56
+ isRecording = true;
57
+ currentRecordingStatus = CurrentRecordingStatus.RECORDING;
58
+
59
+ recordingThread = new Thread(this::writeAudioDataToFile, "AudioRecorder Thread");
60
+ recordingThread.start();
61
+ }
62
+
63
+ private void writeAudioDataToFile() {
64
+ byte[] data = new byte[AudioRecord.getMinBufferSize(SAMPLE_RATE, CHANNEL_CONFIG, AUDIO_FORMAT)];
65
+ FileOutputStream os = null;
66
+ try {
67
+ os = new FileOutputStream(outputFile);
68
+ while (isRecording) {
69
+ int read = audioRecord.read(data, 0, data.length);
70
+ if (AudioRecord.ERROR_INVALID_OPERATION != read) {
71
+ os.write(data);
72
+ }
73
+ }
74
+ } catch (IOException e) {
75
+ Log.e("CustomMediaRecorder", "Error writing audio data to file", e);
76
+ } finally {
77
+ try {
78
+ if (os != null) {
79
+ os.close();
80
+ }
81
+ } catch (IOException e) {
82
+ Log.e("CustomMediaRecorder", "Error closing output stream", e);
83
+ }
84
+ }
85
+ }
86
+
87
+ public void stopRecording() {
88
+ if (audioRecord != null) {
89
+ isRecording = false;
90
+ audioRecord.stop();
91
+ audioRecord.release();
92
+ audioRecord = null;
93
+ recordingThread = null;
94
+ currentRecordingStatus = CurrentRecordingStatus.NONE;
95
+ writeWavHeader();
96
+ }
97
+ }
98
+
99
+ private void writeWavHeader() {
100
+ try {
101
+ FileInputStream fis = new FileInputStream(outputFile);
102
+ byte[] audioData = new byte[(int) outputFile.length()];
103
+ int bytesRead = fis.read(audioData);
104
+ if (bytesRead < 0) {
105
+ Log.e("CustomMediaRecorder", "Error reading audio data from file");
106
+ } else if (bytesRead < audioData.length) {
107
+ Log.w("CustomMediaRecorder", "Audio data size mismatch");
108
+ }
109
+ fis.close();
110
+ byte[] header = createWavHeader(audioData.length);
111
+ FileOutputStream os = new FileOutputStream(outputFile);
112
+ os.write(header);
113
+ os.write(audioData);
114
+ os.close();
115
+ } catch (IOException e) {
116
+ Log.e("CustomMediaRecorder", "Error writing audio data to file", e);
117
+ }
118
+ }
119
+
120
+ private byte[] createWavHeader(int audioLength) {
121
+ int totalLength = audioLength + 36;
122
+ byte[] header = new byte[44];
123
+ ByteBuffer buffer = ByteBuffer.wrap(header).order(ByteOrder.LITTLE_ENDIAN);
124
+
125
+ buffer.put("RIFF".getBytes());
126
+ buffer.putInt(totalLength);
127
+ buffer.put("WAVE".getBytes());
128
+ buffer.put("fmt ".getBytes());
129
+ buffer.putInt(16);
130
+ buffer.putShort((short) 1);
131
+ buffer.putShort((short) 2);
132
+ buffer.putInt(SAMPLE_RATE);
133
+ buffer.putInt(SAMPLE_RATE * 2 * 2);
134
+ buffer.putShort((short) 4);
135
+ buffer.putShort((short) 16);
136
+ buffer.put("data".getBytes());
137
+ buffer.putInt(audioLength);
138
+
139
+ return header;
140
+ }
141
+
142
+ public File getOutputFile() {
143
+ return outputFile;
144
+ }
145
+
146
+ public boolean pauseRecording() throws NotSupportedOsVersion {
147
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
148
+ throw new NotSupportedOsVersion();
149
+ }
150
+
151
+ if (currentRecordingStatus == CurrentRecordingStatus.RECORDING) {
152
+ isRecording = false;
153
+ currentRecordingStatus = CurrentRecordingStatus.PAUSED;
154
+ return true;
155
+ } else {
156
+ return false;
157
+ }
158
+ }
159
+
160
+ public boolean resumeRecording() throws NotSupportedOsVersion {
161
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
162
+ throw new NotSupportedOsVersion();
163
+ }
164
+
165
+ if (currentRecordingStatus == CurrentRecordingStatus.PAUSED) {
166
+ isRecording = true;
167
+ currentRecordingStatus = CurrentRecordingStatus.RECORDING;
168
+ recordingThread = new Thread(this::writeAudioDataToFile, "AudioRecorder Thread");
169
+ recordingThread.start();
170
+ return true;
171
+ } else {
172
+ return false;
173
+ }
174
+ }
175
+
176
+ public CurrentRecordingStatus getCurrentStatus() {
177
+ return currentRecordingStatus;
178
+ }
179
+
180
+ public boolean deleteOutputFile() {
181
+ return outputFile.delete();
182
+ }
183
+
184
+ public static boolean canPhoneCreateMediaRecorder(Context ignoredContext) {
185
+ return true;
186
+ }
187
+ }
@@ -0,0 +1,15 @@
1
+ package com.tchvu3.capacitorvoicerecorder;
2
+
3
+ public abstract class Messages {
4
+
5
+ public static final String MISSING_PERMISSION = "MISSING_PERMISSION";
6
+ public static final String CANNOT_RECORD_ON_THIS_PHONE = "CANNOT_RECORD_ON_THIS_PHONE";
7
+ public static final String FAILED_TO_RECORD = "FAILED_TO_RECORD";
8
+ public static final String RECORDING_HAS_NOT_STARTED = "RECORDING_HAS_NOT_STARTED";
9
+ public static final String FAILED_TO_FETCH_RECORDING = "FAILED_TO_FETCH_RECORDING";
10
+ public static final String NOT_SUPPORTED_OS_VERSION = "NOT_SUPPORTED_OS_VERSION";
11
+ public static final String ALREADY_RECORDING = "ALREADY_RECORDING";
12
+ public static final String EMPTY_RECORDING = "EMPTY_RECORDING";
13
+ public static final String MICROPHONE_BEING_USED = "MICROPHONE_BEING_USED";
14
+
15
+ }
@@ -0,0 +1,4 @@
1
+ package com.tchvu3.capacitorvoicerecorder;
2
+
3
+ public class NotSupportedOsVersion extends Exception {
4
+ }
@@ -0,0 +1,51 @@
1
+ package com.tchvu3.capacitorvoicerecorder;
2
+
3
+ import com.getcapacitor.JSObject;
4
+
5
+ public class RecordData {
6
+
7
+ private String recordDataBase64;
8
+ private String mimeType;
9
+ private int msDuration;
10
+
11
+ public RecordData() {
12
+ }
13
+
14
+ public RecordData(String recordDataBase64, int msDuration, String mimeType) {
15
+ this.recordDataBase64 = recordDataBase64;
16
+ this.msDuration = msDuration;
17
+ this.mimeType = mimeType;
18
+ }
19
+
20
+ public String getRecordDataBase64() {
21
+ return recordDataBase64;
22
+ }
23
+
24
+ public void setRecordDataBase64(String recordDataBase64) {
25
+ this.recordDataBase64 = recordDataBase64;
26
+ }
27
+
28
+ public int getMsDuration() {
29
+ return msDuration;
30
+ }
31
+
32
+ public void setMsDuration(int msDuration) {
33
+ this.msDuration = msDuration;
34
+ }
35
+
36
+ public String getMimeType() {
37
+ return mimeType;
38
+ }
39
+
40
+ public void setMimeType(String mimeType) {
41
+ this.mimeType = mimeType;
42
+ }
43
+
44
+ public JSObject toJSObject() {
45
+ JSObject toReturn = new JSObject();
46
+ toReturn.put("recordDataBase64", recordDataBase64);
47
+ toReturn.put("msDuration", msDuration);
48
+ toReturn.put("mimeType", mimeType);
49
+ return toReturn;
50
+ }
51
+ }
@@ -0,0 +1,37 @@
1
+ package com.tchvu3.capacitorvoicerecorder;
2
+
3
+ import com.getcapacitor.JSObject;
4
+
5
+ public class ResponseGenerator {
6
+
7
+ private static final String VALUE_RESPONSE_KEY = "value";
8
+ private static final String STATUS_RESPONSE_KEY = "status";
9
+
10
+ public static JSObject fromBoolean(boolean value) {
11
+ return value ? successResponse() : failResponse();
12
+ }
13
+
14
+ public static JSObject successResponse() {
15
+ JSObject success = new JSObject();
16
+ success.put(VALUE_RESPONSE_KEY, true);
17
+ return success;
18
+ }
19
+
20
+ public static JSObject failResponse() {
21
+ JSObject success = new JSObject();
22
+ success.put(VALUE_RESPONSE_KEY, false);
23
+ return success;
24
+ }
25
+
26
+ public static JSObject dataResponse(Object data) {
27
+ JSObject success = new JSObject();
28
+ success.put(VALUE_RESPONSE_KEY, data);
29
+ return success;
30
+ }
31
+
32
+ public static JSObject statusResponse(CurrentRecordingStatus status) {
33
+ JSObject success = new JSObject();
34
+ success.put(STATUS_RESPONSE_KEY, status.name());
35
+ return success;
36
+ }
37
+ }