react-native-compressor 1.8.16 → 1.8.18

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 (58) hide show
  1. package/README.md +103 -10
  2. package/android/build.gradle +2 -2
  3. package/android/src/main/java/com/reactnativecompressor/Audio/AudioCompressor.kt +58 -27
  4. package/android/src/main/java/com/reactnativecompressor/Audio/AudioHelper.kt +49 -0
  5. package/android/src/main/java/com/reactnativecompressor/Audio/AudioMain.kt +2 -6
  6. package/android/src/main/java/com/reactnativecompressor/CompressorModule.kt +5 -0
  7. package/android/src/main/java/com/reactnativecompressor/Utils/HttpCallManager.kt +41 -0
  8. package/android/src/main/java/com/reactnativecompressor/Utils/Uploader.kt +70 -33
  9. package/android/src/main/java/com/reactnativecompressor/Utils/createVideoThumbnail.kt +0 -2
  10. package/android/src/oldarch/CompressorSpec.kt +1 -0
  11. package/ios/Audio/AudioHelper.swift +49 -0
  12. package/ios/Audio/AudioMain.swift +46 -82
  13. package/ios/Audio/AudioOptions.swift +37 -0
  14. package/ios/Audio/FormatConverter/FormatConverter+Compressed.swift +326 -0
  15. package/ios/Audio/FormatConverter/FormatConverter+PCM.swift +239 -0
  16. package/ios/Audio/FormatConverter/FormatConverter+Utilities.swift +103 -0
  17. package/ios/Audio/FormatConverter/FormatConverter.swift +264 -0
  18. package/ios/Compressor.mm +4 -1
  19. package/ios/Compressor.xcodeproj/xcuserdata/apple.xcuserdatad/xcschemes/xcschememanagement.plist +14 -0
  20. package/ios/CompressorManager.swift +5 -0
  21. package/ios/Utils/Uploader.swift +18 -1
  22. package/ios/Utils/UrlTaskManager.swift +58 -0
  23. package/ios/Video/NextLevelSessionExporter.swift +694 -0
  24. package/ios/Video/VideoMain.swift +1 -2
  25. package/lib/commonjs/Audio/index.js +1 -3
  26. package/lib/commonjs/Audio/index.js.map +1 -1
  27. package/lib/commonjs/Spec/NativeCompressor.js.map +1 -1
  28. package/lib/commonjs/index.js +6 -0
  29. package/lib/commonjs/index.js.map +1 -1
  30. package/lib/commonjs/utils/Uploader.js +13 -2
  31. package/lib/commonjs/utils/Uploader.js.map +1 -1
  32. package/lib/commonjs/utils/index.js +0 -2
  33. package/lib/commonjs/utils/index.js.map +1 -1
  34. package/lib/module/Audio/index.js +1 -3
  35. package/lib/module/Audio/index.js.map +1 -1
  36. package/lib/module/Spec/NativeCompressor.js.map +1 -1
  37. package/lib/module/index.js +2 -2
  38. package/lib/module/index.js.map +1 -1
  39. package/lib/module/utils/Uploader.js +11 -1
  40. package/lib/module/utils/Uploader.js.map +1 -1
  41. package/lib/module/utils/index.js +0 -3
  42. package/lib/module/utils/index.js.map +1 -1
  43. package/lib/typescript/Audio/index.d.ts.map +1 -1
  44. package/lib/typescript/Spec/NativeCompressor.d.ts +1 -0
  45. package/lib/typescript/Spec/NativeCompressor.d.ts.map +1 -1
  46. package/lib/typescript/index.d.ts +3 -3
  47. package/lib/typescript/index.d.ts.map +1 -1
  48. package/lib/typescript/utils/Uploader.d.ts +3 -1
  49. package/lib/typescript/utils/Uploader.d.ts.map +1 -1
  50. package/lib/typescript/utils/index.d.ts +4 -1
  51. package/lib/typescript/utils/index.d.ts.map +1 -1
  52. package/package.json +1 -1
  53. package/react-native-compressor.podspec +0 -1
  54. package/src/Audio/index.tsx +1 -3
  55. package/src/Spec/NativeCompressor.ts +2 -0
  56. package/src/index.tsx +2 -0
  57. package/src/utils/Uploader.tsx +18 -1
  58. package/src/utils/index.tsx +5 -2
@@ -0,0 +1,239 @@
1
+ // Copyright AudioKit. All Rights Reserved. Revision History at http://github.com/AudioKit/AudioKit/
2
+
3
+ import AVFoundation
4
+
5
+ // MARK: - internal helper functions
6
+
7
+ extension FormatConverter {
8
+ func convertToPCM(completionHandler: FormatConverterCallback? = nil) {
9
+ guard let inputURL = inputURL else {
10
+ completionHandler?(Self.createError(message: "Input file can't be nil."))
11
+ return
12
+ }
13
+ guard let outputURL = outputURL else {
14
+ completionHandler?(Self.createError(message: "Output file can't be nil."))
15
+ return
16
+ }
17
+
18
+ guard let options = options, let outputFormat = options.format else {
19
+ completionHandler?(Self.createError(message: "Options can't be nil."))
20
+ return
21
+ }
22
+ var format: AudioFileTypeID
23
+
24
+ switch outputFormat {
25
+ case .aif:
26
+ format = kAudioFileAIFFType
27
+ case .wav:
28
+ format = kAudioFileWAVEType
29
+ case .caf:
30
+ format = kAudioFileCAFType
31
+ default:
32
+ completionHandler?(Self.createError(message: "Output file must be caf, wav or aif."))
33
+ return
34
+ }
35
+
36
+ var inputFile: ExtAudioFileRef?
37
+ var outputFile: ExtAudioFileRef?
38
+
39
+ func closeFiles() {
40
+ if let strongFile = inputFile {
41
+ if noErr != ExtAudioFileDispose(strongFile) {
42
+ print("Error disposing input file, could have a memory leak")
43
+ }
44
+ }
45
+ inputFile = nil
46
+
47
+ if let strongFile = outputFile {
48
+ if noErr != ExtAudioFileDispose(strongFile) {
49
+ print("Error disposing output file, could have a memory leak")
50
+ }
51
+ }
52
+ outputFile = nil
53
+ }
54
+
55
+ // make sure these are closed on any exit to avoid leaking the file objects
56
+ defer {
57
+ closeFiles()
58
+ }
59
+
60
+ if noErr != ExtAudioFileOpenURL(inputURL as CFURL, &inputFile) {
61
+ completionHandler?(Self.createError(message: "Unable to open the input file."))
62
+ return
63
+ }
64
+
65
+ guard let strongInputFile = inputFile else {
66
+ completionHandler?(Self.createError(message: "Unable to open the input file."))
67
+ return
68
+ }
69
+
70
+ var inputDescription = AudioStreamBasicDescription()
71
+ var inputDescriptionSize = UInt32(MemoryLayout.stride(ofValue: inputDescription))
72
+
73
+ if noErr != ExtAudioFileGetProperty(strongInputFile,
74
+ kExtAudioFileProperty_FileDataFormat,
75
+ &inputDescriptionSize,
76
+ &inputDescription)
77
+ {
78
+ completionHandler?(Self.createError(message: "Unable to get the input file data format."))
79
+ return
80
+ }
81
+
82
+ var outputDescription = createOutputDescription(options: options,
83
+ outputFormatID: format,
84
+ inputDescription: inputDescription)
85
+
86
+ let inputFormat = AudioFileFormat(rawValue: inputURL.pathExtension.lowercased()) ?? .unknown
87
+
88
+ guard inputFormat != outputFormat ||
89
+ outputDescription.mSampleRate != inputDescription.mSampleRate ||
90
+ outputDescription.mChannelsPerFrame != inputDescription.mChannelsPerFrame ||
91
+ outputDescription.mBitsPerChannel != inputDescription.mBitsPerChannel
92
+ else {
93
+ print("No conversion is needed, formats are the same. Copying to", outputURL)
94
+ // just copy it?
95
+ do {
96
+ try FileManager.default.copyItem(at: inputURL, to: outputURL)
97
+ completionHandler?(nil)
98
+ } catch let err as NSError {
99
+ print(err)
100
+ }
101
+ return
102
+ }
103
+
104
+ // Create destination file
105
+ if noErr != ExtAudioFileCreateWithURL(outputURL as CFURL,
106
+ format,
107
+ &outputDescription,
108
+ nil,
109
+ AudioFileFlags.eraseFile.rawValue, // overwrite old file if present
110
+ &outputFile)
111
+ {
112
+ completionProxy(error: Self.createError(message: "Unable to create output file at \(outputURL.path). " +
113
+ "dstFormat \(outputDescription)"),
114
+ completionHandler: completionHandler)
115
+ return
116
+ }
117
+
118
+ guard let strongOutputFile = outputFile else {
119
+ completionProxy(error: Self.createError(message: "Output file is nil."),
120
+ completionHandler: completionHandler)
121
+ return
122
+ }
123
+
124
+ // The format must be linear PCM (kAudioFormatLinearPCM).
125
+ // You must set this in order to encode or decode a non-PCM file data format.
126
+ // You may set this on PCM files to specify the data format used in your calls
127
+ // to read/write.
128
+ if noErr != ExtAudioFileSetProperty(strongInputFile,
129
+ kExtAudioFileProperty_ClientDataFormat,
130
+ inputDescriptionSize,
131
+ &outputDescription)
132
+ {
133
+ completionProxy(error: Self.createError(message: "Unable to set data format on input file."),
134
+ completionHandler: completionHandler)
135
+ return
136
+ }
137
+
138
+ if noErr != ExtAudioFileSetProperty(strongOutputFile,
139
+ kExtAudioFileProperty_ClientDataFormat,
140
+ inputDescriptionSize,
141
+ &outputDescription)
142
+ {
143
+ completionProxy(error: Self.createError(message: "Unable to set the output file data format."),
144
+ completionHandler: completionHandler)
145
+ return
146
+ }
147
+ let bufferByteSize: UInt32 = 32768
148
+ var srcBuffer = [UInt8](repeating: 0, count: Int(bufferByteSize))
149
+ var sourceFrameOffset: UInt32 = 0
150
+
151
+ srcBuffer.withUnsafeMutableBytes { body in
152
+ while true {
153
+ let mBuffer = AudioBuffer(mNumberChannels: inputDescription.mChannelsPerFrame,
154
+ mDataByteSize: bufferByteSize,
155
+ mData: body.baseAddress)
156
+
157
+ var fillBufList = AudioBufferList(mNumberBuffers: 1,
158
+ mBuffers: mBuffer)
159
+ var frameCount: UInt32 = 0
160
+
161
+ if outputDescription.mBytesPerFrame > 0 {
162
+ frameCount = bufferByteSize / outputDescription.mBytesPerFrame
163
+ }
164
+
165
+ if noErr != ExtAudioFileRead(strongInputFile,
166
+ &frameCount,
167
+ &fillBufList)
168
+ {
169
+ completionProxy(error: Self.createError(message: "Error reading from the input file."),
170
+ completionHandler: completionHandler)
171
+ return
172
+ }
173
+ // EOF
174
+ if frameCount == 0 { break }
175
+
176
+ sourceFrameOffset += frameCount
177
+
178
+ if noErr != ExtAudioFileWrite(strongOutputFile,
179
+ frameCount,
180
+ &fillBufList)
181
+ {
182
+ completionProxy(error: Self.createError(message: "Error reading from the output file."),
183
+ completionHandler: completionHandler)
184
+ return
185
+ }
186
+ }
187
+ }
188
+
189
+ closeFiles()
190
+
191
+ // no errors
192
+ completionHandler?(nil)
193
+ }
194
+
195
+ func createOutputDescription(options: Options,
196
+ outputFormatID: AudioFormatID,
197
+ inputDescription: AudioStreamBasicDescription) -> AudioStreamBasicDescription
198
+ {
199
+ let mFormatID: AudioFormatID = kAudioFormatLinearPCM
200
+
201
+ let mSampleRate = options.sampleRate ?? inputDescription.mSampleRate
202
+ let mChannelsPerFrame = options.channels ?? inputDescription.mChannelsPerFrame
203
+ var mBitsPerChannel = options.bitDepth ?? inputDescription.mBitsPerChannel
204
+
205
+ // For example: don't allow upsampling to 24bit if the src is 16
206
+ if options.bitDepthRule == .lessThanOrEqual, mBitsPerChannel > inputDescription.mBitsPerChannel {
207
+ mBitsPerChannel = inputDescription.mBitsPerChannel
208
+ }
209
+
210
+ var mBytesPerFrame = mBitsPerChannel * mChannelsPerFrame / 8
211
+ var mBytesPerPacket = options.bitDepth == nil ? inputDescription.mBytesPerPacket : mBytesPerFrame
212
+
213
+ if mBitsPerChannel == 0 {
214
+ mBitsPerChannel = 16
215
+ mBytesPerPacket = 2 * mChannelsPerFrame
216
+ mBytesPerFrame = 2 * mChannelsPerFrame
217
+ }
218
+
219
+ var mFormatFlags: AudioFormatFlags = kLinearPCMFormatFlagIsPacked | kAudioFormatFlagIsSignedInteger
220
+ if outputFormatID == kAudioFileAIFFType {
221
+ mFormatFlags = mFormatFlags | kLinearPCMFormatFlagIsBigEndian
222
+ }
223
+
224
+ if outputFormatID == kAudioFileWAVEType, mBitsPerChannel == 8 {
225
+ // if is 8 BIT PER CHANNEL, remove kAudioFormatFlagIsSignedInteger
226
+ mFormatFlags &= ~kAudioFormatFlagIsSignedInteger
227
+ }
228
+
229
+ return AudioStreamBasicDescription(mSampleRate: mSampleRate,
230
+ mFormatID: mFormatID,
231
+ mFormatFlags: mFormatFlags,
232
+ mBytesPerPacket: mBytesPerPacket,
233
+ mFramesPerPacket: 1,
234
+ mBytesPerFrame: mBytesPerFrame,
235
+ mChannelsPerFrame: mChannelsPerFrame,
236
+ mBitsPerChannel: mBitsPerChannel,
237
+ mReserved: 0)
238
+ }
239
+ }
@@ -0,0 +1,103 @@
1
+ // Copyright AudioKit. All Rights Reserved. Revision History at http://github.com/AudioKit/AudioKit/
2
+
3
+ import AVFoundation
4
+
5
+ extension FormatConverter {
6
+ class func createError(message: String, code: Int = 1) -> NSError {
7
+ let userInfo = [NSLocalizedDescriptionKey: message]
8
+ return NSError(domain: "com.audiodesigndesk.FormatConverter.error",
9
+ code: code,
10
+ userInfo: userInfo)
11
+ }
12
+ }
13
+
14
+ public extension FormatConverter {
15
+ /// Is this file a PCM file?
16
+ /// - Parameters:
17
+ /// - url: The URL to parse
18
+ /// - ignorePathExtension: Do a deep parse rather than rely on the path extension
19
+ /// - Returns: Bool or nil if it couldn't be determined
20
+ class func isPCM(url: URL, ignorePathExtension _: Bool = false) -> Bool? {
21
+ guard let value = isCompressed(url: url) else { return nil }
22
+ return !value
23
+ }
24
+
25
+ /// Compressed format or not
26
+ class func isCompressed(url: URL, ignorePathExtension: Bool = false) -> Bool? {
27
+ guard !ignorePathExtension else {
28
+ return isCompressedExt(url: url)
29
+ }
30
+ let ext = url.pathExtension.lowercased()
31
+
32
+ switch ext {
33
+ case "wav", "bwf", "aif", "aiff", "caf":
34
+ return false
35
+
36
+ case "m4a", "mp3", "mp4", "m4v", "mpg", "flac", "ogg":
37
+ return true
38
+
39
+ default:
40
+ // if the file extension is missing or unknown, open the file and check it
41
+ return isCompressedExt(url: url) ?? false
42
+ }
43
+ }
44
+
45
+ private class func isCompressedExt(url: URL) -> Bool? {
46
+ var inputFile: ExtAudioFileRef?
47
+
48
+ func closeFiles() {
49
+ if let strongFile = inputFile {
50
+ // print("🗑 Disposing input", inputURL.path)
51
+ if noErr != ExtAudioFileDispose(strongFile) {
52
+ print("Error disposing input file, could have a memory leak")
53
+ }
54
+ }
55
+ inputFile = nil
56
+ }
57
+
58
+ // make sure these are closed on any exit
59
+ defer {
60
+ closeFiles()
61
+ }
62
+
63
+ if noErr != ExtAudioFileOpenURL(url as CFURL,
64
+ &inputFile)
65
+ {
66
+ print("Unable to open", url.lastPathComponent)
67
+ return nil
68
+ }
69
+
70
+ guard let strongInputFile = inputFile else {
71
+ return nil
72
+ }
73
+
74
+ var inputDescription = AudioStreamBasicDescription()
75
+ var inputDescriptionSize = UInt32(MemoryLayout.stride(ofValue: inputDescription))
76
+
77
+ if noErr != ExtAudioFileGetProperty(strongInputFile,
78
+ kExtAudioFileProperty_FileDataFormat,
79
+ &inputDescriptionSize,
80
+ &inputDescription) {}
81
+
82
+ let mFormatID = inputDescription.mFormatID
83
+
84
+ switch mFormatID {
85
+ case kAudioFormatLinearPCM,
86
+ kAudioFormatAppleLossless: return false
87
+ default:
88
+ // basically all other format IDs are compressed
89
+ return true
90
+ }
91
+ }
92
+ }
93
+
94
+ extension Comparable {
95
+ // ie: 5.clamped(to: 7...10)
96
+ // ie: 5.0.clamped(to: 7.0...10.0)
97
+ // ie: "a".clamped(to: "b"..."h")
98
+ /// **OTCore:**
99
+ /// Returns the value clamped to the passed range.
100
+ @inlinable func clamped(to limits: ClosedRange<Self>) -> Self {
101
+ min(max(self, limits.lowerBound), limits.upperBound)
102
+ }
103
+ }
@@ -0,0 +1,264 @@
1
+ // Copyright AudioKit. All Rights Reserved. Revision History at http://github.com/AudioKit/AudioKit/
2
+
3
+ import AVFoundation
4
+
5
+ /**
6
+ FormatConverter wraps the more complex AVFoundation and CoreAudio audio conversions in an easy to use format.
7
+ ```swift
8
+ let options = FormatConverter.Options()
9
+
10
+ // any options left nil will adopt the value of the input file
11
+ options.format = "wav"
12
+ options.sampleRate = 48000
13
+ options.bitDepth = 24
14
+
15
+ let converter = FormatConverter(inputURL: oldURL, outputURL: newURL, options: options)
16
+
17
+ converter.start { error in
18
+ // the error will be nil on success
19
+ }
20
+ ```
21
+ */
22
+ public class FormatConverter {
23
+ // MARK: - properties
24
+
25
+ /// The source audio file
26
+ public var inputURL: URL?
27
+
28
+ /// The audio file to be created after conversion
29
+ public var outputURL: URL?
30
+
31
+ /// Options for conversion
32
+ public var options: Options?
33
+
34
+ // MARK: - private properties
35
+
36
+ // The reader needs to exist outside the start func otherwise the async nature of the
37
+ // AVAssetWriterInput will lose its reference
38
+ var reader: AVAssetReader?
39
+ var writer: AVAssetWriter?
40
+
41
+ // MARK: - initialization
42
+
43
+ /// init with input, output and options - then start()
44
+ public init(inputURL: URL,
45
+ outputURL: URL,
46
+ options: Options? = nil)
47
+ {
48
+ self.inputURL = inputURL
49
+ self.outputURL = outputURL
50
+ self.options = options ?? Options()
51
+ }
52
+
53
+ deinit {
54
+ reader = nil
55
+ writer = nil
56
+ inputURL = nil
57
+ outputURL = nil
58
+ options = nil
59
+ }
60
+
61
+ // MARK: - functions
62
+
63
+ /// The entry point for file conversion
64
+ /// - Parameter completionHandler: the callback that will be triggered when process has completed.
65
+ public func start(completionHandler: FormatConverterCallback? = nil) {
66
+ guard let inputURL = inputURL else {
67
+ completionHandler?(Self.createError(message: "Input file can't be nil."))
68
+ return
69
+ }
70
+
71
+ guard let outputURL = outputURL else {
72
+ completionHandler?(Self.createError(message: "Output file can't be nil."))
73
+ return
74
+ }
75
+
76
+ let inputFormat = AudioFileFormat(rawValue: inputURL.pathExtension.lowercased()) ?? .unknown
77
+ // verify inputFormat, only allow files with path extensions for speed?
78
+ guard FormatConverter.inputFormats.contains(inputFormat) else {
79
+ completionHandler?(Self.createError(message: "The input file format is in an incompatible format: \(inputFormat)"))
80
+ return
81
+ }
82
+
83
+ if FileManager.default.fileExists(atPath: outputURL.path) {
84
+ if options?.eraseFile == true {
85
+ print("Warning: removing existing file at", outputURL.path)
86
+ try? FileManager.default.removeItem(at: outputURL)
87
+ } else {
88
+ let message = "The output file exists already. You need to choose a unique URL or delete the file."
89
+ completionHandler?(Self.createError(message: message))
90
+ return
91
+ }
92
+ }
93
+
94
+ if options?.format == nil {
95
+ options?.format = AudioFileFormat(rawValue: outputURL.pathExtension.lowercased()) ?? .unknown
96
+ }
97
+
98
+ // Format checks are necessary as AVAssetReader has opinions about compressed
99
+
100
+ // PCM output, any supported input
101
+ if Self.isPCM(url: outputURL) == true {
102
+ // PCM output
103
+ convertToPCM(completionHandler: completionHandler)
104
+
105
+ // PCM input, compressed output
106
+ } else if Self.isPCM(url: inputURL) == true,
107
+ Self.isCompressed(url: outputURL) == true
108
+ {
109
+ convertPCMToCompressed(completionHandler: completionHandler)
110
+
111
+ // Compressed input and output, won't do sample rate
112
+ } else if Self.isCompressed(url: inputURL) == true,
113
+ Self.isCompressed(url: outputURL) == true
114
+ {
115
+ convertCompressed(completionHandler: completionHandler)
116
+
117
+ } else {
118
+ completionHandler?(Self.createError(message: "Unable to determine formats for conversion"))
119
+ }
120
+ }
121
+ }
122
+
123
+ // MARK: - Definitions
124
+
125
+ public enum AudioFileFormat: String {
126
+ case aac
127
+ case aif
128
+ case aifc
129
+ case aiff
130
+ case au
131
+ case caf
132
+ case m4a
133
+ case m4v
134
+ case mov
135
+ case mp3
136
+ case mp4
137
+ case sd2
138
+ case snd
139
+ case ts
140
+ case unknown
141
+ case wav
142
+ }
143
+
144
+ public extension FormatConverter {
145
+
146
+ /// FormatConverterCallback is the callback format for start()
147
+ /// - Parameter: error This will contain one parameter of type Error which is nil if the conversion was successful.
148
+ typealias FormatConverterCallback = (_ error: Error?) -> Void
149
+
150
+ /// Formats that this class can write
151
+ static let outputFormats: [AudioFileFormat] = [.wav, .aif, .caf, .m4a]
152
+
153
+ static let defaultOutputFormat: AudioFileFormat = .wav
154
+
155
+ /// Formats that this class can read
156
+ static let inputFormats: [AudioFileFormat] = FormatConverter.outputFormats + [
157
+ .mp3, .snd, .au, .sd2,
158
+ .aif, .aiff, .aifc, .aac,
159
+ .mp4, .m4v, .mov, .ts,
160
+ .unknown, // allow files with no extension. convertToPCM can still read the type
161
+ ]
162
+
163
+ /// An option to block upsampling to a higher bit depth than the source.
164
+ /// For example, converting to 24bit from 16 doesn't have much benefit
165
+ enum BitDepthRule {
166
+ /// Don't allow upsampling to 24bit if the src is 16
167
+ case lessThanOrEqual
168
+
169
+ /// allow any conversaion
170
+ case any
171
+ }
172
+
173
+ /// The conversion options, leave any property nil to adopt the value of the input file
174
+ /// bitRate assumes a stereo bit rate and the converter will half it for mono
175
+ struct Options {
176
+ /// Audio Format
177
+ public var format: AudioFileFormat?
178
+ /// Sample Rate in Hertz
179
+ public var sampleRate: Double?
180
+ /// used only with PCM data
181
+ public var bitDepth: UInt32?
182
+ /// used only when outputting compressed audio
183
+ public var bitRate: UInt32 = 128000 {
184
+ didSet {
185
+ bitRate = bitRate.clamped(to: 64000 ... 320000)
186
+ }
187
+ }
188
+
189
+ /// An option to block upsampling to a higher bit depth than the source.
190
+ /// default value is `.lessThanOrEqual`
191
+ public var bitDepthRule: BitDepthRule = .lessThanOrEqual
192
+
193
+ /// How many channels to convert to. Typically 1 or 2
194
+ public var channels: UInt32?
195
+
196
+ /// Maps to PCM Conversion format option `AVLinearPCMIsNonInterleaved`
197
+ public var isInterleaved: Bool?
198
+
199
+ /// Overwrite existing files, set false if you want to handle this before you call start()
200
+ public var eraseFile: Bool = true
201
+
202
+ public init() {}
203
+
204
+ /// Create options by parsing the contents of the url and using the audio settings
205
+ /// in the file
206
+ /// - Parameter url: The audio file to open and parse
207
+ public init?(url: URL) {
208
+ guard let avFile = try? AVAudioFile(forReading: url) else { return nil }
209
+ self.init(audioFile: avFile)
210
+ }
211
+
212
+ /// Create options by parsing the audioFile for its settings
213
+ /// - Parameter audioFile: an AVAudioFile to parse
214
+ public init?(audioFile: AVAudioFile) {
215
+ let streamDescription = audioFile.fileFormat.streamDescription.pointee
216
+
217
+ format = AudioFileFormat(rawValue: audioFile.url.pathExtension) ?? .unknown
218
+ // FormatConverter.formatIDToString(streamDescription.mFormatID)
219
+ sampleRate = streamDescription.mSampleRate
220
+ bitDepth = streamDescription.mBitsPerChannel
221
+ channels = streamDescription.mChannelsPerFrame
222
+ }
223
+
224
+ /// Create PCM Options
225
+ /// - Parameters:
226
+ /// - pcmFormat: wav, aif, or caf
227
+ /// - sampleRate: Sample Rate
228
+ /// - bitDepth: Bit Depth, or bits per channel
229
+ /// - channels: How many channels
230
+ public init?(pcmFormat: AudioFileFormat,
231
+ sampleRate: Double? = nil,
232
+ bitDepth: UInt32? = nil,
233
+ channels: UInt32? = nil)
234
+ {
235
+ format = pcmFormat
236
+ self.sampleRate = sampleRate
237
+ self.bitDepth = bitDepth
238
+ self.channels = channels
239
+ }
240
+ }
241
+
242
+ internal func completionProxy(error: Error?,
243
+ deleteOutputOnError: Bool = true,
244
+ completionHandler: FormatConverterCallback? = nil)
245
+ {
246
+ guard error != nil,
247
+ deleteOutputOnError,
248
+ let outputURL = outputURL,
249
+ FileManager.default.fileExists(atPath: outputURL.path)
250
+ else {
251
+ completionHandler?(error)
252
+ return
253
+ }
254
+
255
+ do {
256
+ print("Deleting on error", outputURL.path)
257
+ try FileManager.default.removeItem(at: outputURL)
258
+ } catch let err as NSError {
259
+ print("Failed to remove file", outputURL, err)
260
+ }
261
+
262
+ completionHandler?(error)
263
+ }
264
+ }
package/ios/Compressor.mm CHANGED
@@ -39,7 +39,10 @@ RCT_EXTERN_METHOD(upload:(NSString *)fileUrl
39
39
  withResolver:(RCTPromiseResolveBlock)resolve
40
40
  withRejecter:(RCTPromiseRejectBlock)reject)
41
41
 
42
- RCT_EXTERN_METHOD(download:(NSString *)fileUrl
42
+ RCT_EXTERN_METHOD(cancelUpload:(NSString *)uuid
43
+ withShouldCancelAll:(BOOL*)shouldCancelAll)
44
+
45
+ RCT_EXTERN_METHOD(download:(NSString *)fileUrlu
43
46
  withOptions:(NSDictionary *)options
44
47
  withResolver:(RCTPromiseResolveBlock)resolve
45
48
  withRejecter:(RCTPromiseRejectBlock)reject)
@@ -0,0 +1,14 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>SchemeUserState</key>
6
+ <dict>
7
+ <key>Compressor.xcscheme_^#shared#^_</key>
8
+ <dict>
9
+ <key>orderHint</key>
10
+ <integer>56</integer>
11
+ </dict>
12
+ </dict>
13
+ </dict>
14
+ </plist>
@@ -86,6 +86,11 @@ class Compressor: RCTEventEmitter {
86
86
  uploader.upload(filePath: filePath, options: options, resolve: resolve, reject: reject)
87
87
  }
88
88
 
89
+ @objc(cancelUpload:withShouldCancelAll:)
90
+ func cancelUpload(uuid: String,shouldCancelAll:Bool) -> Void {
91
+ uploader.cancelUpload(uuid: uuid,shouldCancelAll: shouldCancelAll)
92
+ }
93
+
89
94
  @objc(download:withOptions:withResolver:withRejecter:)
90
95
  func download(filePath: String, options: [String: Any], resolve:@escaping RCTPromiseResolveBlock, reject:@escaping RCTPromiseRejectBlock) -> Void {
91
96
  Downloader.downloadFileAndSaveToCache(filePath, uuid: options["uuid"] as! String,progressDivider: options["progressDivider"] as? Int ?? 0) { downloadedPath in
@@ -29,6 +29,8 @@ struct UploadError: Error {
29
29
  class Uploader : NSObject, URLSessionTaskDelegate{
30
30
  var uploadResolvers: [String: RCTPromiseResolveBlock] = [:]
31
31
  var uploadRejectors: [String: RCTPromiseRejectBlock] = [:]
32
+ var currentTask: URLSessionDataTask?
33
+ private lazy var taskManager = UrlTaskManager()
32
34
 
33
35
  func upload(filePath: String, options: [String: Any], resolve:@escaping RCTPromiseResolveBlock, reject:@escaping RCTPromiseRejectBlock) -> Void {
34
36
  let fileUrl = Utils.makeValidUri(filePath: filePath)
@@ -97,10 +99,25 @@ class Uploader : NSObject, URLSessionTaskDelegate{
97
99
  let errorMessage = String(format: "Invalid upload type: '%@'.", options["uploadType"] as? String ?? "")
98
100
  reject("ERR_FILESYSTEM_INVALID_UPLOAD_TYPE", errorMessage, nil)
99
101
  }
100
-
102
+ taskManager.registerTask(task, uuid: uuid)
101
103
  task.resume()
102
104
 
103
105
  }
106
+
107
+ func cancelUpload(uuid:String,shouldCancelAll:Bool) {
108
+ if(shouldCancelAll==true)
109
+ {
110
+ taskManager.cancelAllTasks()
111
+ } else if(uuid=="")
112
+ {
113
+ taskManager.taskPop()?.cancel()
114
+ }
115
+ else
116
+ {
117
+ taskManager.uploadTaskForId(uuid)?.cancel()
118
+ }
119
+
120
+ }
104
121
 
105
122
  func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
106
123
  guard let uuid = session.configuration.identifier else {return}