@siteed/expo-audio-studio 2.8.6 → 2.10.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 (70) hide show
  1. package/CHANGELOG.md +17 -1
  2. package/android/build.gradle +9 -0
  3. package/android/src/androidTest/assets/chorus.wav +0 -0
  4. package/android/src/androidTest/assets/jfk.wav +0 -0
  5. package/android/src/androidTest/assets/osr_us_000_0010_8k.wav +0 -0
  6. package/android/src/androidTest/assets/recorder_hello_world.wav +0 -0
  7. package/android/src/androidTest/java/net/siteed/audiostream/AudioProcessorInstrumentedTest.kt +197 -0
  8. package/android/src/androidTest/java/net/siteed/audiostream/AudioRecorderInstrumentedTest.kt +541 -0
  9. package/android/src/androidTest/java/net/siteed/audiostream/integration/BufferDurationIntegrationTest.kt +324 -0
  10. package/android/src/androidTest/java/net/siteed/audiostream/integration/OutputControlIntegrationTest.kt +340 -0
  11. package/android/src/androidTest/java/net/siteed/audiostream/integration/README.md +95 -0
  12. package/android/src/androidTest/java/net/siteed/audiostream/integration/run_integration_tests.sh +28 -0
  13. package/android/src/main/java/net/siteed/audiostream/AudioFormatUtils.kt +264 -13
  14. package/android/src/main/java/net/siteed/audiostream/AudioProcessor.kt +3 -15
  15. package/android/src/main/java/net/siteed/audiostream/AudioRecorderManager.kt +118 -55
  16. package/android/src/main/java/net/siteed/audiostream/LogUtils.kt +32 -4
  17. package/android/src/main/java/net/siteed/audiostream/RecordingConfig.kt +50 -15
  18. package/android/src/test/java/net/siteed/audiostream/AudioFileHandlerTest.kt +279 -0
  19. package/android/src/test/java/net/siteed/audiostream/AudioFormatUtilsTest.kt +273 -0
  20. package/android/src/test/resources/chorus.wav +0 -0
  21. package/android/src/test/resources/generate_test_audio.py +94 -0
  22. package/android/src/test/resources/jfk.wav +0 -0
  23. package/android/src/test/resources/osr_us_000_0010_8k.wav +0 -0
  24. package/android/src/test/resources/recorder_hello_world.wav +0 -0
  25. package/build/cjs/AudioAnalysis/AudioAnalysis.types.js.map +1 -1
  26. package/build/cjs/ExpoAudioStream.types.js.map +1 -1
  27. package/build/cjs/ExpoAudioStream.web.js +38 -35
  28. package/build/cjs/ExpoAudioStream.web.js.map +1 -1
  29. package/build/cjs/WebRecorder.web.js +122 -102
  30. package/build/cjs/WebRecorder.web.js.map +1 -1
  31. package/build/esm/AudioAnalysis/AudioAnalysis.types.js.map +1 -1
  32. package/build/esm/ExpoAudioStream.types.js.map +1 -1
  33. package/build/esm/ExpoAudioStream.web.js +38 -35
  34. package/build/esm/ExpoAudioStream.web.js.map +1 -1
  35. package/build/esm/WebRecorder.web.js +122 -102
  36. package/build/esm/WebRecorder.web.js.map +1 -1
  37. package/build/types/AudioAnalysis/AudioAnalysis.types.d.ts +3 -1
  38. package/build/types/AudioAnalysis/AudioAnalysis.types.d.ts.map +1 -1
  39. package/build/types/ExpoAudioStream.types.d.ts +54 -22
  40. package/build/types/ExpoAudioStream.types.d.ts.map +1 -1
  41. package/build/types/ExpoAudioStream.web.d.ts.map +1 -1
  42. package/build/types/WebRecorder.web.d.ts +19 -3
  43. package/build/types/WebRecorder.web.d.ts.map +1 -1
  44. package/ios/AudioNotificationManager.swift +2 -6
  45. package/ios/AudioStreamManager.swift +116 -50
  46. package/ios/ExpoAudioStream.podspec +6 -0
  47. package/ios/ExpoAudioStreamModule.swift +11 -8
  48. package/ios/ExpoAudioStudioTests/AudioFileHandlerTests.swift +338 -0
  49. package/ios/ExpoAudioStudioTests/AudioFormatUtilsTests.swift +331 -0
  50. package/ios/ExpoAudioStudioTests/AudioTestHelpers.swift +130 -0
  51. package/ios/ExpoAudioStudioTests/Info.plist +22 -0
  52. package/ios/ExpoAudioStudioTests/SimpleAudioTest.swift +98 -0
  53. package/ios/ExpoAudioStudioTests/TestAudioGenerator.swift +75 -0
  54. package/ios/RecordingSettings.swift +53 -22
  55. package/ios/tests/integration/buffer_duration_test.swift +185 -0
  56. package/ios/tests/integration/output_control_test.swift +322 -0
  57. package/ios/tests/integration/run_integration_tests.sh +27 -0
  58. package/ios/tests/standalone/audio_processing_test.swift +144 -0
  59. package/ios/tests/standalone/audio_recording_test.swift +277 -0
  60. package/ios/tests/standalone/audio_streaming_test.swift +249 -0
  61. package/ios/tests/standalone/standalone_test.swift +144 -0
  62. package/package.json +140 -133
  63. package/src/AudioAnalysis/AudioAnalysis.types.ts +8 -1
  64. package/src/ExpoAudioStream.types.ts +66 -22
  65. package/src/ExpoAudioStream.web.ts +45 -39
  66. package/src/WebRecorder.web.ts +164 -130
  67. package/android/src/main/test/java/net/siteed/audiostream/AudioProcessorTest.kt +0 -56
  68. package/ios/siteedexpoaudiostudio.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
  69. package/ios/siteedexpoaudiostudio.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
  70. /package/plugin/build/{index.d.ts → index.d.cts} +0 -0
@@ -0,0 +1,144 @@
1
+ #!/usr/bin/env swift
2
+
3
+ import Foundation
4
+ import AVFoundation
5
+
6
+ // Simple test framework
7
+ struct TestResult {
8
+ let name: String
9
+ let passed: Bool
10
+ let message: String
11
+ }
12
+
13
+ class SimpleTest {
14
+ var results: [TestResult] = []
15
+
16
+ func assert(_ condition: Bool, _ message: String, file: String = #file, line: Int = #line) {
17
+ let testName = "\(file.split(separator: "/").last ?? ""):\(line)"
18
+ results.append(TestResult(name: testName, passed: condition, message: message))
19
+ if !condition {
20
+ print("❌ FAILED: \(message) at \(testName)")
21
+ }
22
+ }
23
+
24
+ func assertEqual<T: Equatable>(_ a: T, _ b: T, _ message: String = "", file: String = #file, line: Int = #line) {
25
+ let passed = a == b
26
+ let msg = message.isEmpty ? "\(a) should equal \(b)" : message
27
+ assert(passed, msg, file: file, line: line)
28
+ }
29
+
30
+ func run() {
31
+ print("🧪 Running iOS Audio Tests...\n")
32
+
33
+ testWAVHeader()
34
+ testAudioBuffer()
35
+
36
+ // Print summary
37
+ let passed = results.filter { $0.passed }.count
38
+ let total = results.count
39
+
40
+ print("\n📊 Test Summary:")
41
+ print(" Total: \(total)")
42
+ print(" Passed: \(passed)")
43
+ print(" Failed: \(total - passed)")
44
+
45
+ if passed == total {
46
+ print("\n✅ All tests passed!")
47
+ } else {
48
+ print("\n❌ Some tests failed!")
49
+ exit(1)
50
+ }
51
+ }
52
+
53
+ func testWAVHeader() {
54
+ print("Testing WAV header creation...")
55
+
56
+ let sampleRate = 44100
57
+ let channels = 2
58
+ let bitsPerSample = 16
59
+ let dataSize = 1024
60
+
61
+ // Create header
62
+ var header = Data()
63
+
64
+ // RIFF chunk
65
+ header.append("RIFF".data(using: .ascii)!)
66
+ var fileSize = UInt32(dataSize + 36).littleEndian
67
+ header.append(Data(bytes: &fileSize, count: 4))
68
+ header.append("WAVE".data(using: .ascii)!)
69
+
70
+ // fmt chunk
71
+ header.append("fmt ".data(using: .ascii)!)
72
+ var fmtSize = UInt32(16).littleEndian
73
+ header.append(Data(bytes: &fmtSize, count: 4))
74
+ var audioFormat = UInt16(1).littleEndian
75
+ header.append(Data(bytes: &audioFormat, count: 2))
76
+ var numChannels = UInt16(channels).littleEndian
77
+ header.append(Data(bytes: &numChannels, count: 2))
78
+ var sampleRateValue = UInt32(sampleRate).littleEndian
79
+ header.append(Data(bytes: &sampleRateValue, count: 4))
80
+ let byteRate = sampleRate * channels * (bitsPerSample / 8)
81
+ var byteRateValue = UInt32(byteRate).littleEndian
82
+ header.append(Data(bytes: &byteRateValue, count: 4))
83
+ let blockAlign = channels * (bitsPerSample / 8)
84
+ var blockAlignValue = UInt16(blockAlign).littleEndian
85
+ header.append(Data(bytes: &blockAlignValue, count: 2))
86
+ var bitsPerSampleValue = UInt16(bitsPerSample).littleEndian
87
+ header.append(Data(bytes: &bitsPerSampleValue, count: 2))
88
+
89
+ // data chunk
90
+ header.append("data".data(using: .ascii)!)
91
+ var dataSizeValue = UInt32(dataSize).littleEndian
92
+ header.append(Data(bytes: &dataSizeValue, count: 4))
93
+
94
+ // Tests
95
+ assertEqual(header.count, 44, "WAV header should be 44 bytes")
96
+
97
+ let riffHeader = String(data: header[0..<4], encoding: .ascii)
98
+ assertEqual(riffHeader, "RIFF", "Should have RIFF header")
99
+
100
+ let waveFormat = String(data: header[8..<12], encoding: .ascii)
101
+ assertEqual(waveFormat, "WAVE", "Should have WAVE format")
102
+
103
+ print("✓ WAV header test completed")
104
+ }
105
+
106
+ func testAudioBuffer() {
107
+ print("\nTesting audio buffer creation...")
108
+
109
+ let sampleRate = 44100.0
110
+ let duration = 0.1
111
+ let frequency = 440.0
112
+
113
+ let frameCount = Int(sampleRate * duration)
114
+ let format = AVAudioFormat(standardFormatWithSampleRate: sampleRate, channels: 1)!
115
+
116
+ guard let buffer = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: AVAudioFrameCount(frameCount)) else {
117
+ assert(false, "Failed to create audio buffer")
118
+ return
119
+ }
120
+
121
+ buffer.frameLength = AVAudioFrameCount(frameCount)
122
+
123
+ // Generate sine wave
124
+ let channelData = buffer.floatChannelData![0]
125
+ for frame in 0..<frameCount {
126
+ let phase = 2.0 * Double.pi * frequency * Double(frame) / sampleRate
127
+ channelData[frame] = Float(sin(phase) * 0.5)
128
+ }
129
+
130
+ // Tests
131
+ assertEqual(Int(buffer.frameLength), frameCount, "Frame length should match")
132
+ assertEqual(buffer.format.sampleRate, sampleRate, "Sample rate should match")
133
+ assertEqual(Int(buffer.format.channelCount), 1, "Should have 1 channel")
134
+
135
+ let middleSample = channelData[frameCount / 4]
136
+ assert(abs(middleSample) > 0.001, "Middle sample should not be zero")
137
+
138
+ print("✓ Audio buffer test completed")
139
+ }
140
+ }
141
+
142
+ // Run the tests
143
+ let test = SimpleTest()
144
+ test.run()
package/package.json CHANGED
@@ -1,134 +1,141 @@
1
1
  {
2
- "name": "@siteed/expo-audio-studio",
3
- "version": "2.8.6",
4
- "description": "Comprehensive audio processing library for React Native and Expo with recording, analysis, visualization, and streaming capabilities across iOS, Android, and web",
5
- "license": "MIT",
6
- "type": "commonjs",
7
- "main": "./build/cjs/index.js",
8
- "module": "./build/esm/index.js",
9
- "types": "./build/types/index.d.ts",
10
- "expo": {
11
- "plugin": "./app.plugin.js"
12
- },
13
- "author": "Arthur Breton <abreton@siteed.net> (https://github.com/deeeed)",
14
- "homepage": "https://github.com/deeeed/expo-audio-stream/blob/main/packages/expo-audio-studio/README.md",
15
- "repository": {
16
- "type": "git",
17
- "url": "git+https://github.com/deeeed/expo-audio-stream.git",
18
- "directory": "packages/expo-audio-studio"
19
- },
20
- "bugs": {
21
- "url": "https://github.com/deeeed/expo-audio-stream/issues"
22
- },
23
- "keywords": [
24
- "react-native",
25
- "expo",
26
- "audio",
27
- "recording",
28
- "audio-analysis",
29
- "audio-processing",
30
- "audio-visualization",
31
- "waveform",
32
- "spectrogram",
33
- "mel-spectrogram",
34
- "mfcc",
35
- "audio-features",
36
- "audio-compression",
37
- "opus",
38
- "aac",
39
- "pcm",
40
- "wav",
41
- "cross-platform",
42
- "background-recording",
43
- "audio-trimming",
44
- "dual-stream"
45
- ],
46
- "files": [
47
- "src",
48
- "android",
49
- "ios",
50
- "cpp",
51
- "plugin",
52
- "app.plugin.js",
53
- "LICENSE",
54
- "CHANGELOG.md",
55
- "generated",
56
- "expo-module.config.json",
57
- "README.md",
58
- "package.json",
59
- "*.podspec",
60
- "build",
61
- "!ios/build",
62
- "!android/build",
63
- "!android/gradle",
64
- "!android/gradlew",
65
- "!android/gradlew.bat",
66
- "!android/local.properties",
67
- "!**/__tests__",
68
- "!**/__fixtures__",
69
- "!**/__mocks__",
70
- "!**/.*"
71
- ],
72
- "scripts": {
73
- "build": "rimraf build && yarn build:types && yarn build:cjs && yarn build:esm && yarn build:plugin",
74
- "build:cjs": "tsc -p tsconfig.cjs.json",
75
- "build:esm": "tsc -p tsconfig.esm.json",
76
- "build:types": "tsc -p tsconfig.types.json",
77
- "build:plugin": "tsc --build plugin/tsconfig.json",
78
- "build:plugin:dev": "expo-module build plugin",
79
- "build:dev": "expo-module build",
80
- "clean": "expo-module clean && rimraf build plugin/build",
81
- "lint": "expo-module lint",
82
- "test": "expo-module test",
83
- "typecheck": "tsc --noEmit",
84
- "docgen": "typedoc src/index.ts --plugin typedoc-plugin-markdown --readme none --out ../../documentation_site/docs/api-reference/API",
85
- "prepare": "yarn build && node -e \"require('fs').renameSync('./plugin/build/index.d.ts', './plugin/build/index.d.cts')\"",
86
- "prepublishOnly": "expo-module prepublishOnly",
87
- "expo-module": "expo-module",
88
- "open:ios": "open -a \"Xcode\" ../../apps/playground/ios",
89
- "open:android": "open -a \"Android Studio\" ../../apps/playground/android",
90
- "size": "bundle-size && size-limit",
91
- "release": "./publish.sh"
92
- },
93
- "devDependencies": {
94
- "@expo/config-plugins": "~10.0.0",
95
- "@siteed/publisher": "^0.4.18",
96
- "@size-limit/preset-big-lib": "^11.1.4",
97
- "@types/jest": "^29.5.12",
98
- "@types/node": "^20.12.7",
99
- "@types/react": "~19.0.10",
100
- "@typescript-eslint/eslint-plugin": "^7.7.0",
101
- "@typescript-eslint/parser": "^7.7.0",
102
- "bundle-size": "^1.1.5",
103
- "eslint": "^8.56.0",
104
- "eslint-config-prettier": "^9.1.0",
105
- "eslint-config-universe": "^12.0.0",
106
- "eslint-plugin-import": "^2.29.1",
107
- "eslint-plugin-prettier": "^5.1.3",
108
- "eslint-plugin-promise": "^6.1.1",
109
- "eslint-plugin-react": "^7.34.1",
110
- "expo": "^53.0.9",
111
- "expo-module-scripts": "^4.0.2",
112
- "jest": "^29.7.0",
113
- "prettier": "^3.2.5",
114
- "react-native": "0.79.2",
115
- "rimraf": "^6.0.1",
116
- "size-limit": "^11.1.4",
117
- "ts-node": "^10.9.2",
118
- "typedoc": "^0.27.4",
119
- "typedoc-plugin-markdown": "~4.4.2",
120
- "typescript": "~5.8.3"
121
- },
122
- "peerDependencies": {
123
- "expo": "*",
124
- "react": "*",
125
- "react-native": "*"
126
- },
127
- "publishConfig": {
128
- "access": "public",
129
- "registry": "https://registry.npmjs.org"
130
- },
131
- "dependencies": {
132
- "expo-modules-core": "~2.3.13"
133
- }
134
- }
2
+ "name": "@siteed/expo-audio-studio",
3
+ "version": "2.10.0",
4
+ "description": "Comprehensive audio processing library for React Native and Expo with recording, analysis, visualization, and streaming capabilities across iOS, Android, and web",
5
+ "license": "MIT",
6
+ "type": "commonjs",
7
+ "main": "./build/cjs/index.js",
8
+ "module": "./build/esm/index.js",
9
+ "types": "./build/types/index.d.ts",
10
+ "expo": {
11
+ "plugin": "./app.plugin.js"
12
+ },
13
+ "author": "Arthur Breton <abreton@siteed.net> (https://github.com/deeeed)",
14
+ "homepage": "https://github.com/deeeed/expo-audio-stream/blob/main/packages/expo-audio-studio/README.md",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "git+https://github.com/deeeed/expo-audio-stream.git",
18
+ "directory": "packages/expo-audio-studio"
19
+ },
20
+ "bugs": {
21
+ "url": "https://github.com/deeeed/expo-audio-stream/issues"
22
+ },
23
+ "keywords": [
24
+ "react-native",
25
+ "expo",
26
+ "audio",
27
+ "recording",
28
+ "audio-analysis",
29
+ "audio-processing",
30
+ "audio-visualization",
31
+ "waveform",
32
+ "spectrogram",
33
+ "mel-spectrogram",
34
+ "mfcc",
35
+ "audio-features",
36
+ "audio-compression",
37
+ "opus",
38
+ "aac",
39
+ "pcm",
40
+ "wav",
41
+ "cross-platform",
42
+ "background-recording",
43
+ "audio-trimming",
44
+ "dual-stream"
45
+ ],
46
+ "files": [
47
+ "src",
48
+ "android",
49
+ "ios",
50
+ "cpp",
51
+ "plugin",
52
+ "app.plugin.js",
53
+ "LICENSE",
54
+ "CHANGELOG.md",
55
+ "generated",
56
+ "expo-module.config.json",
57
+ "README.md",
58
+ "package.json",
59
+ "*.podspec",
60
+ "build",
61
+ "!ios/build",
62
+ "!android/build",
63
+ "!android/gradle",
64
+ "!android/gradlew",
65
+ "!android/gradlew.bat",
66
+ "!android/local.properties",
67
+ "!**/__tests__",
68
+ "!**/__fixtures__",
69
+ "!**/__mocks__",
70
+ "!**/.*"
71
+ ],
72
+ "scripts": {
73
+ "build": "rimraf build && yarn build:types && yarn build:cjs && yarn build:esm && yarn build:plugin",
74
+ "build:cjs": "tsc -p tsconfig.cjs.json",
75
+ "build:esm": "tsc -p tsconfig.esm.json",
76
+ "build:types": "tsc -p tsconfig.types.json",
77
+ "build:plugin": "tsc --build plugin/tsconfig.json",
78
+ "build:plugin:dev": "expo-module build plugin",
79
+ "build:dev": "expo-module build",
80
+ "clean": "expo-module clean && rimraf build plugin/build",
81
+ "lint": "expo-module lint",
82
+ "test": "expo-module test",
83
+ "test:android": "yarn test:android:unit && yarn test:android:instrumented",
84
+ "test:android:unit": "cd ../../apps/playground/android && ./gradlew :siteed-expo-audio-studio:test",
85
+ "test:android:instrumented": "cd ../../apps/playground/android && ./gradlew :siteed-expo-audio-studio:connectedAndroidTest",
86
+ "test:android:unit:watch": "cd ../../apps/playground/android && ./gradlew :siteed-expo-audio-studio:test --continuous",
87
+ "test:ios": "cd ios && xcodebuild test -workspace ExpoAudioStudio.xcworkspace -scheme ExpoAudioStudio -destination 'platform=iOS Simulator,name=iPhone 14'",
88
+ "test:coverage": "cd ../../apps/playground/android && ./gradlew :siteed-expo-audio-studio:jacocoTestReport",
89
+ "typecheck": "tsc --noEmit",
90
+ "docgen": "typedoc src/index.ts --plugin typedoc-plugin-markdown --readme none --out ../../documentation_site/docs/api-reference/API",
91
+ "prepare": "yarn build && node -e \"require('fs').renameSync('./plugin/build/index.d.ts', './plugin/build/index.d.cts')\"",
92
+ "prepublishOnly.disabled": "expo-module prepublishOnly",
93
+ "expo-module": "expo-module",
94
+ "open:ios": "open -a \"Xcode\" ../../apps/playground/ios",
95
+ "open:android": "open -a \"Android Studio\" ../../apps/playground/android",
96
+ "size": "bundle-size && size-limit",
97
+ "release": "./publish.sh"
98
+ },
99
+ "devDependencies": {
100
+ "@expo/config-plugins": "~10.0.0",
101
+ "@expo/npm-proofread": "^1.0.1",
102
+ "@siteed/publisher": "^0.4.18",
103
+ "@size-limit/preset-big-lib": "^11.1.4",
104
+ "@types/jest": "^29.5.12",
105
+ "@types/node": "^20.12.7",
106
+ "@types/react": "~19.0.10",
107
+ "@typescript-eslint/eslint-plugin": "^7.7.0",
108
+ "@typescript-eslint/parser": "^7.7.0",
109
+ "bundle-size": "^1.1.5",
110
+ "eslint": "^8.56.0",
111
+ "eslint-config-prettier": "^9.1.0",
112
+ "eslint-config-universe": "^12.0.0",
113
+ "eslint-plugin-import": "^2.29.1",
114
+ "eslint-plugin-prettier": "^5.1.3",
115
+ "eslint-plugin-promise": "^6.1.1",
116
+ "eslint-plugin-react": "^7.34.1",
117
+ "expo": "^53.0.9",
118
+ "expo-module-scripts": "^4.1.7",
119
+ "jest": "^29.7.0",
120
+ "prettier": "^3.2.5",
121
+ "react-native": "0.79.2",
122
+ "rimraf": "^6.0.1",
123
+ "size-limit": "^11.1.4",
124
+ "ts-node": "^10.9.2",
125
+ "typedoc": "^0.27.4",
126
+ "typedoc-plugin-markdown": "~4.4.2",
127
+ "typescript": "~5.8.3"
128
+ },
129
+ "peerDependencies": {
130
+ "expo": "*",
131
+ "react": "*",
132
+ "react-native": "*"
133
+ },
134
+ "publishConfig": {
135
+ "access": "public",
136
+ "registry": "https://registry.npmjs.org"
137
+ },
138
+ "dependencies": {
139
+ "expo-modules-core": "~2.3.13"
140
+ }
141
+ }
@@ -55,12 +55,17 @@ export interface AudioFeatures {
55
55
 
56
56
  /**
57
57
  * Options to specify which audio features to extract.
58
+ * Note: Advanced features (spectral features, chromagram, pitch, etc.) are experimental,
59
+ * especially during live recording, due to high processing requirements.
58
60
  */
59
61
  export interface AudioFeaturesOptions {
62
+ // Basic features - well optimized
60
63
  energy?: boolean
61
- mfcc?: boolean
62
64
  rms?: boolean
63
65
  zcr?: boolean
66
+
67
+ // Advanced features - experimental, may impact performance in live recording
68
+ mfcc?: boolean
64
69
  spectralCentroid?: boolean
65
70
  spectralFlatness?: boolean
66
71
  spectralRolloff?: boolean
@@ -72,6 +77,8 @@ export interface AudioFeaturesOptions {
72
77
  spectralContrast?: boolean
73
78
  tonnetz?: boolean
74
79
  pitch?: boolean
80
+
81
+ // Utility
75
82
  crc32?: boolean
76
83
  }
77
84
 
@@ -209,15 +209,7 @@ export interface IOSConfig {
209
209
 
210
210
  /** Web platform specific configuration options */
211
211
  export interface WebConfig {
212
- /**
213
- * Whether to store uncompressed audio data for WAV generation
214
- *
215
- * When true, all PCM chunks are stored in memory to create a WAV file when compression is disabled
216
- * When false, uncompressed audio won't be available, but memory usage will be lower
217
- *
218
- * Default: true (for backward compatibility)
219
- */
220
- storeUncompressedAudio?: boolean
212
+ // Reserved for future web-specific options
221
213
  }
222
214
 
223
215
  // Add new type for interruption reasons
@@ -291,6 +283,45 @@ export const DeviceDisconnectionBehavior = {
291
283
  export type DeviceDisconnectionBehaviorType =
292
284
  (typeof DeviceDisconnectionBehavior)[keyof typeof DeviceDisconnectionBehavior]
293
285
 
286
+ /**
287
+ * Configuration for audio output files during recording
288
+ */
289
+ export interface OutputConfig {
290
+ /**
291
+ * Configuration for the primary (uncompressed) output file
292
+ */
293
+ primary?: {
294
+ /** Whether to create the primary output file (default: true) */
295
+ enabled?: boolean
296
+ /** Format for the primary output (currently only 'wav' is supported) */
297
+ format?: 'wav'
298
+ }
299
+
300
+ /**
301
+ * Configuration for the compressed output file
302
+ */
303
+ compressed?: {
304
+ /** Whether to create a compressed output file (default: false) */
305
+ enabled?: boolean
306
+ /**
307
+ * Format for compression
308
+ * - 'aac': Advanced Audio Coding - supported on all platforms
309
+ * - 'opus': Opus encoding - supported on Android and Web; on iOS will automatically fall back to AAC
310
+ */
311
+ format?: 'aac' | 'opus'
312
+ /** Bitrate for compression in bits per second (default: 128000) */
313
+ bitrate?: number
314
+ }
315
+
316
+ // Future enhancement: Post-processing pipeline
317
+ // postProcessing?: {
318
+ // normalize?: boolean
319
+ // trimSilence?: boolean
320
+ // noiseReduction?: boolean
321
+ // customProcessors?: AudioProcessor[]
322
+ // }
323
+ }
324
+
294
325
  export interface RecordingConfig {
295
326
  /** Sample rate for recording in Hz (16000, 44100, or 48000) */
296
327
  sampleRate?: SampleRate
@@ -340,19 +371,16 @@ export interface RecordingConfig {
340
371
  /** Callback function to handle audio features extraction results */
341
372
  onAudioAnalysis?: (_: AudioAnalysisEvent) => Promise<void>
342
373
 
343
- /** Configuration for audio compression */
344
- compression?: {
345
- /** Enable audio compression */
346
- enabled: boolean
347
- /**
348
- * Format for compression
349
- * - 'aac': Advanced Audio Coding - supported on all platforms
350
- * - 'opus': Opus encoding - supported on Android and Web; on iOS will automatically fall back to AAC
351
- */
352
- format: 'aac' | 'opus'
353
- /** Bitrate for compression in bits per second */
354
- bitrate?: number
355
- }
374
+ /**
375
+ * Configuration for audio output files
376
+ *
377
+ * Examples:
378
+ * - Primary only (default): `{ primary: { enabled: true } }`
379
+ * - Compressed only: `{ primary: { enabled: false }, compressed: { enabled: true, format: 'aac' } }`
380
+ * - Both outputs: `{ compressed: { enabled: true } }`
381
+ * - Streaming only: `{ primary: { enabled: false } }`
382
+ */
383
+ output?: OutputConfig
356
384
 
357
385
  /** Whether to automatically resume recording after an interruption (default is false) */
358
386
  autoResumeAfterInterruption?: boolean
@@ -370,6 +398,22 @@ export interface RecordingConfig {
370
398
 
371
399
  /** How to handle device disconnection during recording */
372
400
  deviceDisconnectionBehavior?: DeviceDisconnectionBehaviorType
401
+
402
+ /**
403
+ * Buffer duration in seconds. Controls the size of audio buffers
404
+ * used during recording. Smaller values reduce latency but increase
405
+ * CPU usage. Larger values improve efficiency but increase latency.
406
+ *
407
+ * Platform Notes:
408
+ * - iOS/macOS: Minimum effective 0.1s, uses accumulation below
409
+ * - Android: Respects all sizes within hardware limits
410
+ * - Web: Fully configurable
411
+ *
412
+ * Default: undefined (uses platform default ~23ms at 44.1kHz)
413
+ * Recommended: 0.01 - 0.5 seconds
414
+ * Optimal iOS: >= 0.1 seconds
415
+ */
416
+ bufferDurationSeconds?: number
373
417
  }
374
418
 
375
419
  export interface NotificationConfig {