@siteed/expo-audio-stream 1.9.1 → 1.9.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/CHANGELOG.md CHANGED
@@ -8,24 +8,31 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
8
8
  ## [Unreleased]
9
9
 
10
10
 
11
+ ## [1.9.2] - 2025-01-12
12
+ - ios bitrate verification to prevent invalid values ([035a180](https://github.com/deeeed/expo-audio-stream/commit/035a1800833264edcc59724aaa8a2e12d5c78dc2))
13
+
11
14
  ## [1.9.1] - 2025-01-12
12
15
  - ios potentially missing compressed file info ([88a628c](https://github.com/deeeed/expo-audio-stream/commit/88a628c35f2bfd626a2a5de1eb6950efd814619d))
13
16
 
17
+
14
18
  ## [1.9.0] - 2025-01-11
15
19
  - feat(web-audio): optimize memory usage and streaming performance for web audio recording (#75) ([7b93e12](https://github.com/deeeed/expo-audio-stream/commit/7b93e12aae4bc0599b06b48ca34a60f65587fc75))
16
20
 
17
21
 
22
+
18
23
  ## [1.8.0] - 2025-01-10
19
24
  - feat(audio): implement audio compression support ([ff4e060](https://github.com/deeeed/expo-audio-stream/commit/ff4e060fef1061804c1cc0126d4344d2d50daa9a))
20
25
 
21
26
 
22
27
 
28
+
23
29
  ## [1.7.2] - 2025-01-07
24
30
  - fix(audio-stream): correct WAV header handling in web audio recording ([9ba7de5](https://github.com/deeeed/expo-audio-stream/commit/9ba7de5b96ca4cc937dea261c80d3fda9c99e8f4))
25
31
 
26
32
 
27
33
 
28
34
 
35
+
29
36
  ## [1.7.1] - 2025-01-07
30
37
  - update notification to avoid triggering new alerts (#71) ([32dcfc5](https://github.com/deeeed/expo-audio-stream/commit/32dcfc55daf3236babefc17016f329c177d466fd))
31
38
 
@@ -33,6 +40,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
33
40
 
34
41
 
35
42
 
43
+
36
44
  ## [1.7.0] - 2025-01-05
37
45
  - feat(playground): enhance app configuration and build setup for production deployment (#58) ([929d443](https://github.com/deeeed/expo-audio-stream/commit/929d443145378b1430d215db5c00b13758420e2b))
38
46
  - chore(expo-audio-stream): release @siteed/expo-audio-stream@1.6.1 ([084e8ad](https://github.com/deeeed/expo-audio-stream/commit/084e8adb91da7874c9e608b55d9c7b2ffd7a8327))
@@ -46,6 +54,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
46
54
 
47
55
 
48
56
 
57
+
49
58
  ## [1.6.1] - 2024-12-11
50
59
  - chore(expo-audio-stream): remove git commit step from publish script ([4a772ce](https://github.com/deeeed/expo-audio-stream/commit/4a772ce93bb7405d9b8e981f46bdf8941a71ecfe))
51
60
  - chore: more publishing automation ([3693021](https://github.com/deeeed/expo-audio-stream/commit/369302107f9dca9dddd8ae68e6214481a39976ac))
@@ -63,6 +72,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
63
72
 
64
73
 
65
74
 
75
+
66
76
  ## [1.5.0] - 2024-12-10
67
77
  - UNPUBLISHED because of a bug in the build system
68
78
 
@@ -73,6 +83,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
73
83
 
74
84
 
75
85
 
86
+
76
87
  ## [1.4.0] - 2024-12-05
77
88
  - chore: remove unusded dependencies ([ad81dd5](https://github.com/deeeed/expo-audio-stream/commit/ad81dd560c93dd1d04995a323a4ae72d4de20f3e))
78
89
 
@@ -83,6 +94,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
83
94
 
84
95
 
85
96
 
97
+
86
98
  ## [1.3.1] - 2024-12-05
87
99
  - feat(web): implement throttling and optimize event processing (#49) ([da28765](https://github.com/deeeed/expo-audio-stream/commit/da2876524c2c9d6e0a980fde40a0197b929d8a7f))
88
100
 
@@ -93,6 +105,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
93
105
 
94
106
 
95
107
 
108
+
96
109
  ## [1.3.0] - 2024-11-28
97
110
  ### Added
98
111
  - refactor(permissions): standardize permission status response structure across platforms (#44) ([7c9c800](https://github.com/deeeed/expo-audio-stream/commit/7c9c800d83b7cea3516643371484d5e1f3b99e4c))
@@ -108,6 +121,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
108
121
 
109
122
 
110
123
 
124
+
111
125
  ## [1.2.5] - 2024-11-12
112
126
  ### Added
113
127
  - docs(license): add MIT license to all packages (6 files changed)
@@ -120,6 +134,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
120
134
 
121
135
 
122
136
 
137
+
123
138
  ## [1.2.4] - 2024-11-05
124
139
  ### Changed
125
140
  - Android minimum audio interval set to 10ms.
@@ -135,6 +150,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
135
150
 
136
151
 
137
152
 
153
+
138
154
  ## [1.2.0] - 2024-10-24
139
155
  ### Added
140
156
  - Feature: Keep device awake during recording with `keepAwake` option
@@ -150,6 +166,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
150
166
 
151
167
 
152
168
 
169
+
153
170
  ## [1.1.17] - 2024-10-21
154
171
  ### Added
155
172
  - Support bluetooth headset on ios
@@ -162,6 +179,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
162
179
 
163
180
 
164
181
 
182
+
165
183
  ## [1.0.0] - 2024-04-01
166
184
  ### Added
167
185
  - Initial release of @siteed/expo-audio-stream.
@@ -172,7 +190,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
172
190
  - Feature: Audio features extraction during recording.
173
191
  - Feature: Consistent WAV PCM recording format across all platforms.
174
192
 
175
- [unreleased]: https://github.com/deeeed/expo-audio-stream/compare/@siteed/expo-audio-stream@1.9.1...HEAD
193
+ [unreleased]: https://github.com/deeeed/expo-audio-stream/compare/@siteed/expo-audio-stream@1.9.2...HEAD
194
+ [1.9.2]: https://github.com/deeeed/expo-audio-stream/compare/@siteed/expo-audio-stream@1.9.1...@siteed/expo-audio-stream@1.9.2
176
195
  [1.9.1]: https://github.com/deeeed/expo-audio-stream/compare/@siteed/expo-audio-stream@1.9.0...@siteed/expo-audio-stream@1.9.1
177
196
  [1.9.0]: https://github.com/deeeed/expo-audio-stream/compare/@siteed/expo-audio-stream@1.8.0...@siteed/expo-audio-stream@1.9.0
178
197
  [1.8.0]: https://github.com/deeeed/expo-audio-stream/compare/@siteed/expo-audio-stream@1.7.2...@siteed/expo-audio-stream@1.8.0
@@ -410,13 +410,14 @@ class AudioStreamManager: NSObject {
410
410
  "interval": emissionInterval
411
411
  ]
412
412
 
413
- // Add compression info if enabled and file exists
413
+ // Add compression info if enabled
414
414
  if settings.enableCompressedOutput,
415
415
  let compressedURL = compressedFileURL,
416
416
  FileManager.default.fileExists(atPath: compressedURL.path) {
417
417
  do {
418
418
  let compressedAttributes = try FileManager.default.attributesOfItem(atPath: compressedURL.path)
419
419
  if let compressedSize = compressedAttributes[.size] as? Int64 {
420
+ Logger.debug("Compressed file status - Size: \(compressedSize)")
420
421
  let compressionBundle: [String: Any] = [
421
422
  "fileUri": compressedURL.absoluteString,
422
423
  "mimeType": compressedFormat == "aac" ? "audio/aac" : "audio/opus",
@@ -558,34 +559,47 @@ class AudioStreamManager: NSObject {
558
559
  AVSampleRateKey: settings.sampleRate,
559
560
  AVNumberOfChannelsKey: settings.numberOfChannels,
560
561
  AVEncoderBitRateKey: settings.compressedBitRate,
561
- AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue
562
+ AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue,
563
+ AVEncoderBitDepthHintKey: 16
562
564
  ]
563
565
 
564
- // Create directory if it doesn't exist
566
+ Logger.debug("Initializing compressed recording with settings: \(compressedSettings)")
567
+
565
568
  let tempDirectory = FileManager.default.temporaryDirectory
566
569
  try FileManager.default.createDirectory(at: tempDirectory, withIntermediateDirectories: true)
567
570
 
568
- // Create compressed file URL and ensure file exists
569
- compressedFileURL = tempDirectory.appendingPathComponent(UUID().uuidString)
570
- .appendingPathExtension(settings.compressedFormat)
571
-
572
- if let url = compressedFileURL {
573
- // Create empty file first
574
- FileManager.default.createFile(atPath: url.path, contents: nil)
571
+ // Use the same UUID as the main recording
572
+ if let recordingUUID = recordingUUID {
573
+ compressedFileURL = tempDirectory.appendingPathComponent(recordingUUID.uuidString)
574
+ .appendingPathExtension(settings.compressedFormat)
575
575
 
576
- // Then initialize recorder
577
- compressedRecorder = try AVAudioRecorder(url: url, settings: compressedSettings)
578
- if let recorder = compressedRecorder {
579
- recorder.prepareToRecord()
580
- recorder.record()
581
- compressedFormat = settings.compressedFormat
582
- compressedBitRate = settings.compressedBitRate
583
- Logger.debug("Compressed recording initialized at: \(url.path)")
576
+ if let url = compressedFileURL {
577
+ // Create empty file first
578
+ if FileManager.default.createFile(atPath: url.path, contents: nil) {
579
+ Logger.debug("Created empty file at: \(url.path)")
580
+ } else {
581
+ Logger.debug("Failed to create empty file at: \(url.path)")
582
+ }
583
+
584
+ // Then initialize recorder
585
+ compressedRecorder = try AVAudioRecorder(url: url, settings: compressedSettings)
586
+ if let recorder = compressedRecorder {
587
+ let prepared = recorder.prepareToRecord()
588
+ Logger.debug("Recorder prepared: \(prepared)")
589
+
590
+ let started = recorder.record()
591
+ Logger.debug("Recorder started: \(started)")
592
+
593
+ Logger.debug("Recorder current time: \(recorder.currentTime)")
594
+
595
+ compressedFormat = settings.compressedFormat
596
+ compressedBitRate = settings.compressedBitRate
597
+ Logger.debug("Compressed recording initialized - Format: \(compressedFormat), Bitrate: \(compressedBitRate)")
598
+ }
584
599
  }
585
600
  }
586
601
  } catch {
587
602
  Logger.debug("Failed to setup compressed recording: \(error)")
588
- // Don't fail the entire recording if compression fails
589
603
  compressedFileURL = nil
590
604
  compressedRecorder = nil
591
605
  }
@@ -1213,32 +1227,50 @@ class AudioStreamManager: NSObject {
1213
1227
  var compressionInfo: [String: Any]? = nil
1214
1228
  if settings.enableCompressedOutput, let compressedURL = compressedFileURL {
1215
1229
  do {
1216
- let compressedAttributes = try FileManager.default.attributesOfItem(atPath: compressedURL.path)
1217
- if let compressedSize = compressedAttributes[.size] as? Int64 {
1218
- let eventDataSize = compressedSize - lastEmittedCompressedSize
1219
-
1220
- // Read the new compressed data if there's new data
1221
- var compressedData: String? = nil
1222
- if eventDataSize > 0 {
1223
- let fileHandle = try FileHandle(forReadingFrom: compressedURL)
1224
- fileHandle.seek(toFileOffset: UInt64(lastEmittedCompressedSize))
1225
- let data = fileHandle.readData(ofLength: Int(eventDataSize))
1226
- compressedData = data.base64EncodedString()
1227
- fileHandle.closeFile()
1230
+ // Ensure file exists and has data
1231
+ if FileManager.default.fileExists(atPath: compressedURL.path) {
1232
+ let compressedAttributes = try FileManager.default.attributesOfItem(atPath: compressedURL.path)
1233
+ if let compressedSize = compressedAttributes[.size] as? Int64 {
1234
+ let eventDataSize = compressedSize - lastEmittedCompressedSize
1235
+
1236
+ Logger.debug("Compressed file status - Total size: \(compressedSize), New data size: \(eventDataSize)")
1237
+
1238
+ // Read the new compressed data if there's new data
1239
+ var compressedData: String? = nil
1240
+ if eventDataSize > 0 {
1241
+ do {
1242
+ let fileHandle = try FileHandle(forReadingFrom: compressedURL)
1243
+ defer { fileHandle.closeFile() }
1244
+
1245
+ fileHandle.seek(toFileOffset: UInt64(lastEmittedCompressedSize))
1246
+ let data = fileHandle.readData(ofLength: Int(eventDataSize))
1247
+ compressedData = data.base64EncodedString()
1248
+
1249
+ Logger.debug("Read compressed data of size: \(data.count)")
1250
+ } catch {
1251
+ Logger.debug("Error reading compressed data: \(error)")
1252
+ }
1253
+ }
1254
+
1255
+ lastEmittedCompressedSize = compressedSize
1256
+
1257
+ compressionInfo = [
1258
+ "position": recordingTime * 1000, // Convert to milliseconds
1259
+ "fileUri": compressedURL.absoluteString,
1260
+ "eventDataSize": eventDataSize,
1261
+ "totalSize": compressedSize,
1262
+ "data": compressedData ?? ""
1263
+ ]
1264
+
1265
+ Logger.debug("Compression info prepared: \(String(describing: compressionInfo))")
1266
+ } else {
1267
+ Logger.debug("Could not get compressed file size")
1228
1268
  }
1229
-
1230
- lastEmittedCompressedSize = compressedSize
1231
-
1232
- compressionInfo = [
1233
- "position": recordingTime * 1000, // Convert to milliseconds
1234
- "fileUri": compressedURL.absoluteString,
1235
- "eventDataSize": eventDataSize,
1236
- "totalSize": compressedSize,
1237
- "data": compressedData ?? ""
1238
- ]
1269
+ } else {
1270
+ Logger.debug("Compressed file does not exist at path: \(compressedURL.path)")
1239
1271
  }
1240
1272
  } catch {
1241
- Logger.debug("Failed to read compressed data: \(error)")
1273
+ Logger.debug("Error preparing compression info: \(error)")
1242
1274
  }
1243
1275
  }
1244
1276
 
@@ -23,18 +23,25 @@ struct CompressedRecordingInfo {
23
23
  var bitrate: Int
24
24
  var format: String
25
25
 
26
- static func validate(format: String, bitrate: Int) -> Result<Void, Error> {
26
+ static func validate(format: String, bitrate: Int) -> Result<(String, Int), Error> {
27
27
  // Validate format
28
28
  guard ["aac", "opus"].contains(format.lowercased()) else {
29
29
  return .failure(RecordingError.unsupportedFormat(format))
30
30
  }
31
31
 
32
- // Validate bitrate
33
- guard (8000...960000).contains(bitrate) else {
34
- return .failure(RecordingError.invalidBitrate(bitrate))
32
+ // Adjust bitrate based on format
33
+ let adjustedBitrate: Int
34
+ if format.lowercased() == "aac" {
35
+ // Standard AAC bitrates (bps)
36
+ let standardAACBitrates = [32000, 48000, 64000, 96000, 128000, 160000, 192000, 256000, 320000]
37
+ adjustedBitrate = standardAACBitrates.min(by: { abs($0 - bitrate) < abs($1 - bitrate) }) ?? 128000
38
+ } else {
39
+ // For Opus, allow lower bitrates (especially good for voice)
40
+ // Typical Opus voice bitrates: 8-24 kbps, music: 32-128 kbps
41
+ adjustedBitrate = min(max(bitrate, 8000), 320000)
35
42
  }
36
43
 
37
- return .success(())
44
+ return .success((format, adjustedBitrate))
38
45
  }
39
46
  }
40
47
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@siteed/expo-audio-stream",
3
- "version": "1.9.1",
3
+ "version": "1.9.2",
4
4
  "description": "stream audio crossplatform",
5
5
  "license": "MIT",
6
6
  "main": "build/index.js",