@independo/capacitor-voice-recorder 8.0.2-dev.1 → 8.1.0-dev.2
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.
- package/README.md +130 -32
- package/android/build.gradle +44 -1
- package/android/src/main/java/app/independo/capacitorvoicerecorder/VoiceRecorder.java +146 -0
- package/android/src/main/java/app/independo/capacitorvoicerecorder/adapters/PermissionChecker.java +8 -0
- package/android/src/main/java/app/independo/capacitorvoicerecorder/adapters/RecordDataMapper.java +32 -0
- package/android/src/main/java/app/independo/capacitorvoicerecorder/adapters/RecorderAdapter.java +39 -0
- package/android/src/main/java/app/independo/capacitorvoicerecorder/adapters/RecorderPlatform.java +25 -0
- package/android/src/main/java/app/independo/capacitorvoicerecorder/core/CurrentRecordingStatus.java +9 -0
- package/android/src/main/java/app/independo/capacitorvoicerecorder/core/ErrorCodes.java +19 -0
- package/android/src/main/java/{com/tchvu3/capacitorvoicerecorder → app/independo/capacitorvoicerecorder/core}/Messages.java +2 -1
- package/android/src/main/java/{com/tchvu3/capacitorvoicerecorder → app/independo/capacitorvoicerecorder/core}/RecordData.java +15 -1
- package/android/src/main/java/app/independo/capacitorvoicerecorder/core/RecordOptions.java +4 -0
- package/android/src/main/java/app/independo/capacitorvoicerecorder/core/ResponseFormat.java +18 -0
- package/android/src/main/java/{com/tchvu3/capacitorvoicerecorder → app/independo/capacitorvoicerecorder/core}/ResponseGenerator.java +7 -1
- package/android/src/main/java/app/independo/capacitorvoicerecorder/platform/CustomMediaRecorder.java +281 -0
- package/android/src/main/java/app/independo/capacitorvoicerecorder/platform/DefaultRecorderPlatform.java +86 -0
- package/android/src/main/java/app/independo/capacitorvoicerecorder/platform/NotSupportedOsVersion.java +4 -0
- package/android/src/main/java/app/independo/capacitorvoicerecorder/service/VoiceRecorderService.java +144 -0
- package/android/src/main/java/app/independo/capacitorvoicerecorder/service/VoiceRecorderServiceException.java +23 -0
- package/dist/docs.json +145 -5
- package/dist/esm/adapters/VoiceRecorderWebAdapter.d.ts +23 -0
- package/dist/esm/adapters/VoiceRecorderWebAdapter.js +41 -0
- package/dist/esm/adapters/VoiceRecorderWebAdapter.js.map +1 -0
- package/dist/esm/core/error-codes.d.ts +4 -0
- package/dist/esm/core/error-codes.js +21 -0
- package/dist/esm/core/error-codes.js.map +1 -0
- package/dist/esm/core/recording-contract.d.ts +3 -0
- package/dist/esm/core/recording-contract.js +15 -0
- package/dist/esm/core/recording-contract.js.map +1 -0
- package/dist/esm/core/response-format.d.ts +8 -0
- package/dist/esm/core/response-format.js +17 -0
- package/dist/esm/core/response-format.js.map +1 -0
- package/dist/esm/definitions.d.ts +36 -3
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/platform/web/VoiceRecorderImpl.d.ts +45 -0
- package/dist/esm/{VoiceRecorderImpl.js → platform/web/VoiceRecorderImpl.js} +20 -2
- package/dist/esm/platform/web/VoiceRecorderImpl.js.map +1 -0
- package/dist/esm/platform/web/get-blob-duration.js.map +1 -0
- package/dist/esm/{predefined-web-responses.d.ts → platform/web/predefined-web-responses.d.ts} +12 -1
- package/dist/esm/{predefined-web-responses.js → platform/web/predefined-web-responses.js} +11 -0
- package/dist/esm/platform/web/predefined-web-responses.js.map +1 -0
- package/dist/esm/service/VoiceRecorderService.d.ts +47 -0
- package/dist/esm/service/VoiceRecorderService.js +60 -0
- package/dist/esm/service/VoiceRecorderService.js.map +1 -0
- package/dist/esm/web.d.ts +12 -1
- package/dist/esm/web.js +26 -12
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +200 -9
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +200 -9
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/VoiceRecorder/Adapters/DefaultRecorderPlatform.swift +33 -0
- package/ios/Sources/VoiceRecorder/Adapters/RecordDataMapper.swift +38 -0
- package/ios/Sources/VoiceRecorder/Adapters/RecorderAdapter.swift +24 -0
- package/ios/Sources/VoiceRecorder/Adapters/RecorderPlatform.swift +11 -0
- package/ios/Sources/VoiceRecorder/Bridge/VoiceRecorder.swift +172 -0
- package/ios/Sources/VoiceRecorder/{CurrentRecordingStatus.swift → Core/CurrentRecordingStatus.swift} +2 -0
- package/ios/Sources/VoiceRecorder/Core/ErrorCodes.swift +16 -0
- package/ios/Sources/VoiceRecorder/{Messages.swift → Core/Messages.swift} +2 -0
- package/ios/Sources/VoiceRecorder/{RecordData.swift → Core/RecordData.swift} +6 -0
- package/ios/Sources/VoiceRecorder/Core/RecordOptions.swift +11 -0
- package/ios/Sources/VoiceRecorder/Core/ResponseFormat.swift +22 -0
- package/ios/Sources/VoiceRecorder/{ResponseGenerator.swift → Core/ResponseGenerator.swift} +6 -0
- package/ios/Sources/VoiceRecorder/Platform/CustomMediaRecorder.swift +359 -0
- package/ios/Sources/VoiceRecorder/Service/VoiceRecorderService.swift +128 -0
- package/ios/Sources/VoiceRecorder/Service/VoiceRecorderServiceError.swift +14 -0
- package/package.json +10 -4
- package/android/src/main/java/com/tchvu3/capacitorvoicerecorder/CurrentRecordingStatus.java +0 -7
- package/android/src/main/java/com/tchvu3/capacitorvoicerecorder/CustomMediaRecorder.java +0 -149
- package/android/src/main/java/com/tchvu3/capacitorvoicerecorder/NotSupportedOsVersion.java +0 -3
- package/android/src/main/java/com/tchvu3/capacitorvoicerecorder/RecordOptions.java +0 -3
- package/android/src/main/java/com/tchvu3/capacitorvoicerecorder/VoiceRecorder.java +0 -203
- package/dist/esm/VoiceRecorderImpl.d.ts +0 -27
- package/dist/esm/VoiceRecorderImpl.js.map +0 -1
- package/dist/esm/helper/get-blob-duration.js.map +0 -1
- package/dist/esm/predefined-web-responses.js.map +0 -1
- package/ios/Sources/VoiceRecorder/CustomMediaRecorder.swift +0 -113
- package/ios/Sources/VoiceRecorder/RecordOptions.swift +0 -8
- package/ios/Sources/VoiceRecorder/VoiceRecorder.swift +0 -147
- /package/dist/esm/{helper → platform/web}/get-blob-duration.d.ts +0 -0
- /package/dist/esm/{helper → platform/web}/get-blob-duration.js +0 -0
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import Foundation
|
|
2
|
-
import AVFoundation
|
|
3
|
-
|
|
4
|
-
class CustomMediaRecorder {
|
|
5
|
-
|
|
6
|
-
public var options: RecordOptions?
|
|
7
|
-
private var recordingSession: AVAudioSession!
|
|
8
|
-
private var audioRecorder: AVAudioRecorder!
|
|
9
|
-
private var audioFilePath: URL!
|
|
10
|
-
private var originalRecordingSessionCategory: AVAudioSession.Category!
|
|
11
|
-
private var status = CurrentRecordingStatus.NONE
|
|
12
|
-
|
|
13
|
-
private let settings = [
|
|
14
|
-
AVFormatIDKey: Int(kAudioFormatMPEG4AAC),
|
|
15
|
-
AVSampleRateKey: 44100,
|
|
16
|
-
AVNumberOfChannelsKey: 1,
|
|
17
|
-
AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue
|
|
18
|
-
]
|
|
19
|
-
|
|
20
|
-
private func getDirectoryToSaveAudioFile() -> URL {
|
|
21
|
-
if options?.directory != nil,
|
|
22
|
-
let directory = getDirectory(directory: options?.directory),
|
|
23
|
-
var outputDirURL = FileManager.default.urls(for: directory, in: .userDomainMask).first {
|
|
24
|
-
if let subDirectory = options?.subDirectory?.trimmingCharacters(in: CharacterSet(charactersIn: "/")) {
|
|
25
|
-
outputDirURL = outputDirURL.appendingPathComponent(subDirectory, isDirectory: true)
|
|
26
|
-
|
|
27
|
-
do {
|
|
28
|
-
if !FileManager.default.fileExists(atPath: outputDirURL.path) {
|
|
29
|
-
try FileManager.default.createDirectory(at: outputDirURL, withIntermediateDirectories: true)
|
|
30
|
-
}
|
|
31
|
-
} catch {
|
|
32
|
-
print("Error creating directory: \(error)")
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
return outputDirURL
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
return URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
public func startRecording(recordOptions: RecordOptions?) -> Bool {
|
|
43
|
-
do {
|
|
44
|
-
options = recordOptions
|
|
45
|
-
recordingSession = AVAudioSession.sharedInstance()
|
|
46
|
-
originalRecordingSessionCategory = recordingSession.category
|
|
47
|
-
try recordingSession.setCategory(AVAudioSession.Category.playAndRecord)
|
|
48
|
-
try recordingSession.setActive(true)
|
|
49
|
-
audioFilePath = getDirectoryToSaveAudioFile().appendingPathComponent("recording-\(Int(Date().timeIntervalSince1970 * 1000)).aac")
|
|
50
|
-
audioRecorder = try AVAudioRecorder(url: audioFilePath, settings: settings)
|
|
51
|
-
audioRecorder.record()
|
|
52
|
-
status = CurrentRecordingStatus.RECORDING
|
|
53
|
-
return true
|
|
54
|
-
} catch {
|
|
55
|
-
return false
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
public func stopRecording() {
|
|
60
|
-
do {
|
|
61
|
-
audioRecorder.stop()
|
|
62
|
-
try recordingSession.setActive(false)
|
|
63
|
-
try recordingSession.setCategory(originalRecordingSessionCategory)
|
|
64
|
-
originalRecordingSessionCategory = nil
|
|
65
|
-
audioRecorder = nil
|
|
66
|
-
recordingSession = nil
|
|
67
|
-
status = CurrentRecordingStatus.NONE
|
|
68
|
-
} catch {}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
public func getOutputFile() -> URL {
|
|
72
|
-
return audioFilePath
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
public func getDirectory(directory: String?) -> FileManager.SearchPathDirectory? {
|
|
76
|
-
if let directory = directory {
|
|
77
|
-
switch directory {
|
|
78
|
-
case "CACHE":
|
|
79
|
-
return .cachesDirectory
|
|
80
|
-
case "LIBRARY":
|
|
81
|
-
return .libraryDirectory
|
|
82
|
-
default:
|
|
83
|
-
return .documentDirectory
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
return nil
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
public func pauseRecording() -> Bool {
|
|
90
|
-
if(status == CurrentRecordingStatus.RECORDING) {
|
|
91
|
-
audioRecorder.pause()
|
|
92
|
-
status = CurrentRecordingStatus.PAUSED
|
|
93
|
-
return true
|
|
94
|
-
} else {
|
|
95
|
-
return false
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
public func resumeRecording() -> Bool {
|
|
100
|
-
if(status == CurrentRecordingStatus.PAUSED) {
|
|
101
|
-
audioRecorder.record()
|
|
102
|
-
status = CurrentRecordingStatus.RECORDING
|
|
103
|
-
return true
|
|
104
|
-
} else {
|
|
105
|
-
return false
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
public func getCurrentStatus() -> CurrentRecordingStatus {
|
|
110
|
-
return status
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
}
|
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
import Foundation
|
|
2
|
-
import AVFoundation
|
|
3
|
-
import Capacitor
|
|
4
|
-
|
|
5
|
-
@objc(VoiceRecorder)
|
|
6
|
-
public class VoiceRecorder: CAPPlugin, CAPBridgedPlugin {
|
|
7
|
-
public let identifier = "VoiceRecorder"
|
|
8
|
-
public let jsName = "VoiceRecorder"
|
|
9
|
-
public let pluginMethods: [CAPPluginMethod] = [
|
|
10
|
-
CAPPluginMethod(name: "canDeviceVoiceRecord", returnType: CAPPluginReturnPromise),
|
|
11
|
-
CAPPluginMethod(name: "requestAudioRecordingPermission", returnType: CAPPluginReturnPromise),
|
|
12
|
-
CAPPluginMethod(name: "hasAudioRecordingPermission", returnType: CAPPluginReturnPromise),
|
|
13
|
-
CAPPluginMethod(name: "startRecording", returnType: CAPPluginReturnPromise),
|
|
14
|
-
CAPPluginMethod(name: "stopRecording", returnType: CAPPluginReturnPromise),
|
|
15
|
-
CAPPluginMethod(name: "pauseRecording", returnType: CAPPluginReturnPromise),
|
|
16
|
-
CAPPluginMethod(name: "resumeRecording", returnType: CAPPluginReturnPromise),
|
|
17
|
-
CAPPluginMethod(name: "getCurrentStatus", returnType: CAPPluginReturnPromise),
|
|
18
|
-
]
|
|
19
|
-
|
|
20
|
-
private var customMediaRecorder: CustomMediaRecorder? = nil
|
|
21
|
-
|
|
22
|
-
@objc func canDeviceVoiceRecord(_ call: CAPPluginCall) {
|
|
23
|
-
call.resolve(ResponseGenerator.successResponse())
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
@objc func requestAudioRecordingPermission(_ call: CAPPluginCall) {
|
|
27
|
-
AVAudioSession.sharedInstance().requestRecordPermission { granted in
|
|
28
|
-
if granted {
|
|
29
|
-
call.resolve(ResponseGenerator.successResponse())
|
|
30
|
-
} else {
|
|
31
|
-
call.resolve(ResponseGenerator.failResponse())
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
@objc func hasAudioRecordingPermission(_ call: CAPPluginCall) {
|
|
37
|
-
call.resolve(ResponseGenerator.fromBoolean(doesUserGaveAudioRecordingPermission()))
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
@objc func startRecording(_ call: CAPPluginCall) {
|
|
41
|
-
if(!doesUserGaveAudioRecordingPermission()) {
|
|
42
|
-
call.reject(Messages.MISSING_PERMISSION)
|
|
43
|
-
return
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
if(customMediaRecorder != nil) {
|
|
47
|
-
call.reject(Messages.ALREADY_RECORDING)
|
|
48
|
-
return
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
customMediaRecorder = CustomMediaRecorder()
|
|
52
|
-
if(customMediaRecorder == nil) {
|
|
53
|
-
call.reject(Messages.CANNOT_RECORD_ON_THIS_PHONE)
|
|
54
|
-
return
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
let directory: String? = call.getString("directory")
|
|
58
|
-
let subDirectory: String? = call.getString("subDirectory")
|
|
59
|
-
let recordOptions = RecordOptions(directory: directory, subDirectory: subDirectory)
|
|
60
|
-
let successfullyStartedRecording = customMediaRecorder!.startRecording(recordOptions: recordOptions)
|
|
61
|
-
if successfullyStartedRecording == false {
|
|
62
|
-
call.reject(Messages.CANNOT_RECORD_ON_THIS_PHONE)
|
|
63
|
-
} else {
|
|
64
|
-
call.resolve(ResponseGenerator.successResponse())
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
@objc func stopRecording(_ call: CAPPluginCall) {
|
|
69
|
-
if(customMediaRecorder == nil) {
|
|
70
|
-
call.reject(Messages.RECORDING_HAS_NOT_STARTED)
|
|
71
|
-
return
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
customMediaRecorder?.stopRecording()
|
|
75
|
-
|
|
76
|
-
let audioFileUrl = customMediaRecorder?.getOutputFile()
|
|
77
|
-
if(audioFileUrl == nil) {
|
|
78
|
-
customMediaRecorder = nil
|
|
79
|
-
call.reject(Messages.FAILED_TO_FETCH_RECORDING)
|
|
80
|
-
return
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
let sendDataAsBase64 = customMediaRecorder?.options?.directory == nil
|
|
84
|
-
let recordData = RecordData(
|
|
85
|
-
recordDataBase64: sendDataAsBase64 ? readFileAsBase64(audioFileUrl) : nil,
|
|
86
|
-
mimeType: "audio/aac",
|
|
87
|
-
msDuration: getMsDurationOfAudioFile(audioFileUrl),
|
|
88
|
-
uri: sendDataAsBase64 ? nil : audioFileUrl!.path
|
|
89
|
-
)
|
|
90
|
-
customMediaRecorder = nil
|
|
91
|
-
if (sendDataAsBase64 && recordData.recordDataBase64 == nil) || recordData.msDuration < 0 {
|
|
92
|
-
call.reject(Messages.EMPTY_RECORDING)
|
|
93
|
-
} else {
|
|
94
|
-
call.resolve(ResponseGenerator.dataResponse(recordData.toDictionary()))
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
@objc func pauseRecording(_ call: CAPPluginCall) {
|
|
99
|
-
if(customMediaRecorder == nil) {
|
|
100
|
-
call.reject(Messages.RECORDING_HAS_NOT_STARTED)
|
|
101
|
-
} else {
|
|
102
|
-
call.resolve(ResponseGenerator.fromBoolean(customMediaRecorder?.pauseRecording() ?? false))
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
@objc func resumeRecording(_ call: CAPPluginCall) {
|
|
107
|
-
if(customMediaRecorder == nil) {
|
|
108
|
-
call.reject(Messages.RECORDING_HAS_NOT_STARTED)
|
|
109
|
-
} else {
|
|
110
|
-
call.resolve(ResponseGenerator.fromBoolean(customMediaRecorder?.resumeRecording() ?? false))
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
@objc func getCurrentStatus(_ call: CAPPluginCall) {
|
|
115
|
-
if(customMediaRecorder == nil) {
|
|
116
|
-
call.resolve(ResponseGenerator.statusResponse(CurrentRecordingStatus.NONE))
|
|
117
|
-
} else {
|
|
118
|
-
call.resolve(ResponseGenerator.statusResponse(customMediaRecorder?.getCurrentStatus() ?? CurrentRecordingStatus.NONE))
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
func doesUserGaveAudioRecordingPermission() -> Bool {
|
|
123
|
-
return AVAudioSession.sharedInstance().recordPermission == AVAudioSession.RecordPermission.granted
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
func readFileAsBase64(_ filePath: URL?) -> String? {
|
|
127
|
-
if(filePath == nil) {
|
|
128
|
-
return nil
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
do {
|
|
132
|
-
let fileData = try Data.init(contentsOf: filePath!)
|
|
133
|
-
let fileStream = fileData.base64EncodedString(options: NSData.Base64EncodingOptions.init(rawValue: 0))
|
|
134
|
-
return fileStream
|
|
135
|
-
} catch {}
|
|
136
|
-
|
|
137
|
-
return nil
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
func getMsDurationOfAudioFile(_ filePath: URL?) -> Int {
|
|
141
|
-
if filePath == nil {
|
|
142
|
-
return -1
|
|
143
|
-
}
|
|
144
|
-
return Int(CMTimeGetSeconds(AVURLAsset(url: filePath!).duration) * 1000)
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
}
|
|
File without changes
|
|
File without changes
|