@siteed/audio-studio 3.1.1 โ†’ 3.2.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 (96) hide show
  1. package/CHANGELOG.md +375 -4
  2. package/android/src/main/java/net/siteed/audiostudio/AudioStreamDecoder.kt +852 -0
  3. package/android/src/main/java/net/siteed/audiostudio/AudioStudioModule.kt +167 -3
  4. package/android/src/main/java/net/siteed/audiostudio/Constants.kt +4 -0
  5. package/build/cjs/errors/AudioStreamError.js +161 -0
  6. package/build/cjs/errors/AudioStreamError.js.map +1 -0
  7. package/build/cjs/errors/AudioStreamError.test.js +82 -0
  8. package/build/cjs/errors/AudioStreamError.test.js.map +1 -0
  9. package/build/cjs/index.js +7 -1
  10. package/build/cjs/index.js.map +1 -1
  11. package/build/cjs/streamAudioData.js +534 -0
  12. package/build/cjs/streamAudioData.js.map +1 -0
  13. package/build/cjs/utils/audioProcessing.js +14 -10
  14. package/build/cjs/utils/audioProcessing.js.map +1 -1
  15. package/build/esm/errors/AudioStreamError.js +156 -0
  16. package/build/esm/errors/AudioStreamError.js.map +1 -0
  17. package/build/esm/errors/AudioStreamError.test.js +80 -0
  18. package/build/esm/errors/AudioStreamError.test.js.map +1 -0
  19. package/build/esm/index.js +3 -1
  20. package/build/esm/index.js.map +1 -1
  21. package/build/esm/streamAudioData.js +527 -0
  22. package/build/esm/streamAudioData.js.map +1 -0
  23. package/build/esm/utils/audioProcessing.js +14 -10
  24. package/build/esm/utils/audioProcessing.js.map +1 -1
  25. package/build/types/errors/AudioStreamError.d.ts +25 -0
  26. package/build/types/errors/AudioStreamError.d.ts.map +1 -0
  27. package/build/types/errors/AudioStreamError.test.d.ts +2 -0
  28. package/build/types/errors/AudioStreamError.test.d.ts.map +1 -0
  29. package/build/types/index.d.ts +5 -1
  30. package/build/types/index.d.ts.map +1 -1
  31. package/build/types/streamAudioData.d.ts +119 -0
  32. package/build/types/streamAudioData.d.ts.map +1 -0
  33. package/build/types/utils/audioProcessing.d.ts +2 -2
  34. package/build/types/utils/audioProcessing.d.ts.map +1 -1
  35. package/ios/AudioProcessingHelpers.swift +10 -5
  36. package/ios/AudioStreamDecoder.swift +614 -0
  37. package/ios/AudioStudioModule.swift +186 -3
  38. package/package.json +163 -146
  39. package/scripts/README.md +58 -0
  40. package/src/errors/AudioStreamError.test.ts +92 -0
  41. package/src/errors/AudioStreamError.ts +199 -0
  42. package/src/index.ts +24 -0
  43. package/src/streamAudioData.ts +758 -0
  44. package/src/utils/audioProcessing.ts +25 -14
  45. package/android/src/androidTest/assets/chorus.wav +0 -0
  46. package/android/src/androidTest/assets/jfk.wav +0 -0
  47. package/android/src/androidTest/assets/osr_us_000_0010_8k.wav +0 -0
  48. package/android/src/androidTest/assets/recorder_hello_world.wav +0 -0
  49. package/android/src/androidTest/java/net/siteed/audiostudio/AudioFinalMetadataContractInstrumentedTest.kt +0 -190
  50. package/android/src/androidTest/java/net/siteed/audiostudio/AudioProcessorInstrumentedTest.kt +0 -197
  51. package/android/src/androidTest/java/net/siteed/audiostudio/AudioRecorderInstrumentedTest.kt +0 -487
  52. package/android/src/androidTest/java/net/siteed/audiostudio/AudioRecorderPerformanceInstrumentedTest.kt +0 -250
  53. package/android/src/androidTest/java/net/siteed/audiostudio/OpusRangeDecodeRegressionInstrumentedTest.kt +0 -186
  54. package/android/src/androidTest/java/net/siteed/audiostudio/integration/AudioFocusStrategyIntegrationTest.kt +0 -332
  55. package/android/src/androidTest/java/net/siteed/audiostudio/integration/BufferDurationIntegrationTest.kt +0 -324
  56. package/android/src/androidTest/java/net/siteed/audiostudio/integration/CompressedOnlyOutputTest.kt +0 -253
  57. package/android/src/androidTest/java/net/siteed/audiostudio/integration/DeviceDisconnectionFallbackTest.kt +0 -218
  58. package/android/src/androidTest/java/net/siteed/audiostudio/integration/EventEmissionIntervalTest.kt +0 -120
  59. package/android/src/androidTest/java/net/siteed/audiostudio/integration/M4aFormatTest.kt +0 -345
  60. package/android/src/androidTest/java/net/siteed/audiostudio/integration/OutputControlIntegrationTest.kt +0 -340
  61. package/android/src/androidTest/java/net/siteed/audiostudio/integration/PcmStreamingDurationTest.kt +0 -252
  62. package/android/src/androidTest/java/net/siteed/audiostudio/integration/README.md +0 -95
  63. package/android/src/androidTest/java/net/siteed/audiostudio/integration/run_integration_tests.sh +0 -43
  64. package/android/src/test/java/net/siteed/audiostudio/AndroidCallStateTest.kt +0 -37
  65. package/android/src/test/java/net/siteed/audiostudio/AndroidEventEmitterTest.kt +0 -28
  66. package/android/src/test/java/net/siteed/audiostudio/AudioFileHandlerTest.kt +0 -279
  67. package/android/src/test/java/net/siteed/audiostudio/AudioFocusStrategyTest.kt +0 -249
  68. package/android/src/test/java/net/siteed/audiostudio/AudioFormatTest.kt +0 -151
  69. package/android/src/test/java/net/siteed/audiostudio/AudioFormatUtilsTest.kt +0 -273
  70. package/android/src/test/java/net/siteed/audiostudio/DeviceDisconnectionFallbackUnitTest.kt +0 -140
  71. package/android/src/test/java/net/siteed/audiostudio/InterruptionAutoResumePolicyTest.kt +0 -49
  72. package/android/src/test/resources/chorus.wav +0 -0
  73. package/android/src/test/resources/generate_test_audio.py +0 -94
  74. package/android/src/test/resources/jfk.wav +0 -0
  75. package/android/src/test/resources/osr_us_000_0010_8k.wav +0 -0
  76. package/android/src/test/resources/recorder_hello_world.wav +0 -0
  77. package/ios/AudioStudioTests/AudioFileHandlerTests.swift +0 -338
  78. package/ios/AudioStudioTests/AudioFormatUtilsTests.swift +0 -331
  79. package/ios/AudioStudioTests/AudioTestHelpers.swift +0 -130
  80. package/ios/AudioStudioTests/CompressedOnlyOutputTests.swift +0 -334
  81. package/ios/AudioStudioTests/EventEmissionIntervalTests.swift +0 -105
  82. package/ios/AudioStudioTests/Info.plist +0 -22
  83. package/ios/AudioStudioTests/README.md +0 -39
  84. package/ios/AudioStudioTests/SimpleAudioTest.swift +0 -98
  85. package/ios/AudioStudioTests/TestAudioGenerator.swift +0 -75
  86. package/ios/tests/README.md +0 -41
  87. package/ios/tests/integration/buffer_and_fallback_test.swift +0 -178
  88. package/ios/tests/integration/buffer_duration_test.swift +0 -185
  89. package/ios/tests/integration/compressed_only_output_test.swift +0 -271
  90. package/ios/tests/integration/output_control_test.swift +0 -322
  91. package/ios/tests/integration/run_integration_tests.sh +0 -37
  92. package/ios/tests/opus_support_test_macos.swift +0 -154
  93. package/ios/tests/standalone/audio_processing_test.swift +0 -144
  94. package/ios/tests/standalone/audio_recording_test.swift +0 -277
  95. package/ios/tests/standalone/audio_streaming_test.swift +0 -249
  96. package/ios/tests/standalone/standalone_test.swift +0 -144
@@ -9,6 +9,10 @@ private let recordingInterruptedEvent: String = "onRecordingInterrupted"
9
9
  private let deviceChangedEvent: String = "deviceChangedEvent"
10
10
  private let trimProgressEvent: String = "TrimProgress"
11
11
  private let errorEvent: String = "error"
12
+ private let audioStreamChunkEvent: String = "AudioDataStreamChunk"
13
+ private let audioStreamProgressEvent: String = "AudioDataStreamProgress"
14
+ private let audioStreamCompleteEvent: String = "AudioDataStreamComplete"
15
+ private let audioStreamErrorEvent: String = "AudioDataStreamError"
12
16
  private let DEFAULT_SEGMENT_DURATION_MS = 100
13
17
  private let audioDeviceTypeBuiltinMic = "builtin_mic"
14
18
  private let audioDeviceTypeBluetooth = "bluetooth"
@@ -18,13 +22,16 @@ private let audioDeviceTypeWiredHeadphones = "wired_headphones"
18
22
  private let audioDeviceTypeSpeaker = "speaker"
19
23
  private let audioDeviceTypeUnknown = "unknown"
20
24
 
21
- public class AudioStudioModule: Module, AudioStreamManagerDelegate, AudioDeviceManagerDelegate {
25
+ public class AudioStudioModule: Module, AudioStreamManagerDelegate, AudioDeviceManagerDelegate, AudioStreamDecoderDelegate {
22
26
  private var streamManager = AudioStreamManager()
23
27
  private let notificationCenter = UNUserNotificationCenter.current()
24
28
  private let notificationIdentifier = "audio_recording_notification"
25
29
  private var deviceManager = AudioDeviceManager()
26
30
  private var deviceChangeObserver: Any?
27
31
 
32
+ private let streamDecodersLock = NSLock()
33
+ private var streamDecoders: [String: AudioStreamDecoder] = [:]
34
+
28
35
  // Serial queue for AVAudioEngine lifecycle ops (prepare/start/stop).
29
36
  // Prevents concurrent mutation of shared engine state and keeps callers
30
37
  // off the main thread to avoid UI freezes during heavy native init.
@@ -43,7 +50,11 @@ public class AudioStudioModule: Module, AudioStreamManagerDelegate, AudioDeviceM
43
50
  recordingInterruptedEvent,
44
51
  deviceChangedEvent,
45
52
  trimProgressEvent,
46
- errorEvent
53
+ errorEvent,
54
+ audioStreamChunkEvent,
55
+ audioStreamProgressEvent,
56
+ audioStreamCompleteEvent,
57
+ audioStreamErrorEvent
47
58
  ])
48
59
 
49
60
  OnCreate {
@@ -71,6 +82,20 @@ public class AudioStudioModule: Module, AudioStreamManagerDelegate, AudioDeviceM
71
82
  OnDestroy {
72
83
  Logger.debug("AudioStudioModule", "Module destroyed, stopping device monitoring.")
73
84
  _ = streamManager.stopRecording()
85
+ // Cancel any in-flight streamAudioData decoders before the module
86
+ // is torn down. Without this, decoder threads can outlive the
87
+ // module and try to emit events through a destroyed instance.
88
+ // Detach each decoder's delegate *before* cancelling so the
89
+ // terminal "cancelled" events the worker emits after observing
90
+ // `cancel()` are dropped instead of being forwarded.
91
+ self.streamDecodersLock.lock()
92
+ let inflight = self.streamDecoders
93
+ self.streamDecoders.removeAll()
94
+ self.streamDecodersLock.unlock()
95
+ for (_, decoder) in inflight {
96
+ decoder.delegate = nil
97
+ decoder.cancel()
98
+ }
74
99
  // Clear device manager delegate
75
100
  deviceManager.delegate = nil
76
101
  }
@@ -901,8 +926,166 @@ public class AudioStudioModule: Module, AudioStreamManagerDelegate, AudioDeviceM
901
926
  }
902
927
  }
903
928
  }
929
+
930
+ AsyncFunction("streamAudioData") { (options: [String: Any], promise: Promise) in
931
+ guard let requestId = options["requestId"] as? String,
932
+ let fileUri = options["fileUri"] as? String else {
933
+ promise.reject(
934
+ "ERR_AUDIO_STREAM_INVALID_RANGE",
935
+ "fileUri and requestId are required"
936
+ )
937
+ return
938
+ }
939
+
940
+ let streamFormat = options["streamFormat"] as? String ?? "float32"
941
+ guard streamFormat == "float32" else {
942
+ promise.reject(
943
+ "ERR_AUDIO_STREAM_UNSUPPORTED_FORMAT",
944
+ "Only streamFormat='float32' is supported"
945
+ )
946
+ return
947
+ }
948
+
949
+ let chunkDurationMs = options["chunkDurationMs"] as? Int ?? 1000
950
+ guard (10...60000).contains(chunkDurationMs) else {
951
+ promise.reject(
952
+ "ERR_AUDIO_STREAM_INVALID_RANGE",
953
+ "chunkDurationMs must be in [10, 60000]"
954
+ )
955
+ return
956
+ }
957
+
958
+ let opts = AudioStreamDecoder.Options(
959
+ requestId: requestId,
960
+ fileUri: fileUri,
961
+ startTimeMs: options["startTimeMs"] as? Double,
962
+ endTimeMs: options["endTimeMs"] as? Double,
963
+ targetSampleRate: options["targetSampleRate"] as? Double,
964
+ channels: options["channels"] as? Int,
965
+ normalizeAudio: options["normalizeAudio"] as? Bool ?? true,
966
+ chunkDurationMs: chunkDurationMs,
967
+ maxChunkBytes: options["maxChunkBytes"] as? Int,
968
+ maxBufferedChunks: options["maxBufferedChunks"] as? Int ?? 4,
969
+ backpressureTimeoutMs: options["backpressureTimeoutMs"] as? Double
970
+ )
971
+
972
+ let decoder = AudioStreamDecoder(options: opts)
973
+ decoder.delegate = self
974
+ self.streamDecodersLock.lock()
975
+ if self.streamDecoders[requestId] != nil {
976
+ self.streamDecodersLock.unlock()
977
+ promise.reject(
978
+ "ERR_AUDIO_STREAM_BUSY",
979
+ "requestId already in use"
980
+ )
981
+ return
982
+ }
983
+ self.streamDecoders[requestId] = decoder
984
+ self.streamDecodersLock.unlock()
985
+ decoder.start()
986
+ promise.resolve(["requestId": requestId])
987
+ }
988
+
989
+ AsyncFunction("cancelStreamAudioData") { (requestId: String, promise: Promise) in
990
+ self.streamDecodersLock.lock()
991
+ let decoder = self.streamDecoders[requestId]
992
+ self.streamDecodersLock.unlock()
993
+ decoder?.cancel()
994
+ promise.resolve(["requestId": requestId, "cancelled": decoder != nil])
995
+ }
996
+
997
+ Function("acknowledgeStreamAudioChunk") { (requestId: String, chunkIndex: Int) in
998
+ self.streamDecodersLock.lock()
999
+ let decoder = self.streamDecoders[requestId]
1000
+ self.streamDecodersLock.unlock()
1001
+ decoder?.acknowledgeChunk(chunkIndex)
1002
+ }
1003
+
1004
+ AsyncFunction("getAudioDecodeCapabilities") { (promise: Promise) in
1005
+ promise.resolve([
1006
+ "platform": "ios",
1007
+ "supportedInputFormats": [
1008
+ "audio/wav",
1009
+ "audio/aac",
1010
+ "audio/mp4",
1011
+ "audio/mpeg",
1012
+ "audio/x-m4a",
1013
+ "audio/caf",
1014
+ "audio/aiff",
1015
+ ],
1016
+ "supportedOutputFormats": ["float32"],
1017
+ "supportsCancellation": true,
1018
+ "supportsBackpressure": true,
1019
+ "supportsTimeRange": true,
1020
+ "supportsTargetSampleRate": true,
1021
+ "supportsChannelMixing": true,
1022
+ "knownLimitations": [
1023
+ "Opus/WebM input depends on AVFoundation codec availability for the iOS version."
1024
+ ],
1025
+ ])
1026
+ }
904
1027
  }
905
-
1028
+
1029
+ private func releaseStreamDecoder(_ requestId: String) {
1030
+ streamDecodersLock.lock()
1031
+ streamDecoders.removeValue(forKey: requestId)
1032
+ streamDecodersLock.unlock()
1033
+ }
1034
+
1035
+ /// Returns true when `requestId` is still tracked by the module. Used as
1036
+ /// the lifecycle gate for delegate sends: callbacks that race with
1037
+ /// `OnDestroy` (which clears the map *before* cancelling) see `false`
1038
+ /// and skip `sendEvent`, so we never push events through a destroyed
1039
+ /// React context.
1040
+ private func isActiveStreamDecoder(_ requestId: String) -> Bool {
1041
+ streamDecodersLock.lock()
1042
+ defer { streamDecodersLock.unlock() }
1043
+ return streamDecoders[requestId] != nil
1044
+ }
1045
+
1046
+ // MARK: - AudioStreamDecoderDelegate
1047
+
1048
+ public func streamDecoder(
1049
+ _ decoder: AudioStreamDecoder,
1050
+ didEmitChunk payload: [String: Any]
1051
+ ) {
1052
+ guard let requestId = payload["requestId"] as? String,
1053
+ isActiveStreamDecoder(requestId) else { return }
1054
+ sendEvent(audioStreamChunkEvent, payload)
1055
+ }
1056
+
1057
+ public func streamDecoder(
1058
+ _ decoder: AudioStreamDecoder,
1059
+ didReportProgress payload: [String: Any]
1060
+ ) {
1061
+ guard let requestId = payload["requestId"] as? String,
1062
+ isActiveStreamDecoder(requestId) else { return }
1063
+ sendEvent(audioStreamProgressEvent, payload)
1064
+ }
1065
+
1066
+ public func streamDecoder(
1067
+ _ decoder: AudioStreamDecoder,
1068
+ didCompleteWith payload: [String: Any]
1069
+ ) {
1070
+ guard let requestId = payload["requestId"] as? String,
1071
+ isActiveStreamDecoder(requestId) else { return }
1072
+ releaseStreamDecoder(requestId)
1073
+ sendEvent(audioStreamCompleteEvent, payload)
1074
+ }
1075
+
1076
+ public func streamDecoder(
1077
+ _ decoder: AudioStreamDecoder,
1078
+ didFailWith payload: [String: Any]
1079
+ ) {
1080
+ guard let requestId = payload["requestId"] as? String,
1081
+ isActiveStreamDecoder(requestId) else { return }
1082
+ if let code = payload["code"] as? String,
1083
+ code != "ERR_AUDIO_STREAM_CANCELLED" {
1084
+ releaseStreamDecoder(requestId)
1085
+ }
1086
+ sendEvent(audioStreamErrorEvent, payload)
1087
+ }
1088
+
906
1089
  func audioStreamManager(_ manager: AudioStreamManager, didReceiveInterruption info: [String: Any]) {
907
1090
  Logger.debug("AudioStudioModule", "Delegate: didReceiveInterruption: \(info)")
908
1091
  // Convert iOS interruption events to match the TypeScript types
package/package.json CHANGED
@@ -1,147 +1,164 @@
1
1
  {
2
- "name": "@siteed/audio-studio",
3
- "version": "3.1.1",
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/audiolab/blob/main/packages/audio-studio/README.md",
15
- "repository": {
16
- "type": "git",
17
- "url": "git+https://github.com/deeeed/audiolab.git",
18
- "directory": "packages/audio-studio"
19
- },
20
- "bugs": {
21
- "url": "https://github.com/deeeed/audiolab/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
- "prebuilt",
61
- "build",
62
- "!ios/build",
63
- "!android/build",
64
- "!android/gradle",
65
- "!android/gradlew",
66
- "!android/gradlew.bat",
67
- "!android/local.properties",
68
- "!**/__tests__",
69
- "!**/__fixtures__",
70
- "!**/__mocks__",
71
- "!**/.*"
72
- ],
73
- "scripts": {
74
- "build:wasm": "bash scripts/build-wasm.sh",
75
- "build": "rimraf build && yarn build:types && yarn build:cjs && yarn build:esm && yarn build:plugin && cp -r prebuilt/ build/cjs/prebuilt && cp -r prebuilt/ build/esm/prebuilt",
76
- "build:cjs": "tsc -p tsconfig.cjs.json",
77
- "build:esm": "tsc -p tsconfig.esm.json",
78
- "build:types": "tsc -p tsconfig.types.json",
79
- "build:plugin": "tsc --project plugin/tsconfig.json && cp plugin/build/index.js plugin/build/index.cjs",
80
- "build:plugin:dev": "expo-module build plugin",
81
- "build:dev": "expo-module build",
82
- "clean": "expo-module clean && rimraf build plugin/build",
83
- "lint": "expo-module lint",
84
- "lint:fix": "expo-module lint --fix",
85
- "test": "expo-module test",
86
- "test:android": "yarn test:android:unit && yarn test:android:instrumented",
87
- "test:android:unit": "cd ../../apps/playground/android && ./gradlew :siteed-audio-studio:test",
88
- "test:android:instrumented": "cd ../../apps/playground/android && ./gradlew :siteed-audio-studio:connectedAndroidTest",
89
- "test:android:unit:watch": "cd ../../apps/playground/android && ./gradlew :siteed-audio-studio:test --continuous",
90
- "test:ios": "cd ../../apps/playground/ios && xcodebuild -workspace AudioDevPlayground.xcworkspace -scheme AudioDevPlayground -destination 'platform=iOS Simulator,name=iPhone 15' build",
91
- "test:coverage": "cd ../../apps/playground/android && ./gradlew :siteed-audio-studio:jacocoTestReport",
92
- "typecheck": "tsc --noEmit",
93
- "docgen": "typedoc src/index.ts --plugin typedoc-plugin-markdown --readme none --out ../../documentation_site/docs/api-reference/API && node ../../scripts/escape-mdx-generics.js ../../documentation_site/docs/api-reference",
94
- "prepare": "yarn build && node -e \"require('fs').renameSync('./plugin/build/index.d.ts', './plugin/build/index.d.cts')\"",
95
- "prepublishOnly.disabled": "expo-module prepublishOnly",
96
- "expo-module": "expo-module",
97
- "open:ios": "open -a \"Xcode\" ../../apps/playground/ios",
98
- "open:android": "open -a \"Android Studio\" ../../apps/playground/android",
99
- "size": "bundle-size && size-limit",
100
- "release": "./publish.sh",
101
- "agent:test:unit": "yarn test:android:unit",
102
- "agent:test:integration": "yarn test:android:instrumented",
103
- "agent:compilation:check": "yarn typecheck && yarn build"
104
- },
105
- "devDependencies": {
106
- "@expo/config-plugins": "~54.0.0",
107
- "@expo/npm-proofread": "^1.0.1",
108
- "@siteed/publisher": "^0.4.18",
109
- "@size-limit/preset-big-lib": "^11.1.4",
110
- "@types/jest": "^29.5.12",
111
- "@types/node": "^20.12.7",
112
- "@types/react": "~19.0.10",
113
- "@typescript-eslint/eslint-plugin": "^7.7.0",
114
- "@typescript-eslint/parser": "^7.7.0",
115
- "bundle-size": "^1.1.5",
116
- "eslint": "^8.56.0",
117
- "eslint-config-prettier": "^9.1.0",
118
- "eslint-config-universe": "^12.0.0",
119
- "eslint-plugin-import": "^2.29.1",
120
- "eslint-plugin-prettier": "^5.1.3",
121
- "eslint-plugin-promise": "^6.1.1",
122
- "eslint-plugin-react": "^7.34.1",
123
- "expo": "^54.0.0",
124
- "expo-module-scripts": "^4.1.7",
125
- "expo-modules-core": "~3.0.0",
126
- "jest": "^29.7.0",
127
- "prettier": "^3.2.5",
128
- "react": "19.2.0",
129
- "react-native": "0.83.6",
130
- "rimraf": "^6.0.1",
131
- "size-limit": "^11.1.4",
132
- "ts-node": "^10.9.2",
133
- "typedoc": "^0.27.4",
134
- "typedoc-plugin-markdown": "~4.4.2",
135
- "typescript": "~5.8.3"
136
- },
137
- "peerDependencies": {
138
- "@expo/config-plugins": ">=7.0.0",
139
- "expo": ">=52.0.0",
140
- "react": "*",
141
- "react-native": "*"
142
- },
143
- "publishConfig": {
144
- "access": "public",
145
- "registry": "https://registry.npmjs.org"
146
- }
147
- }
2
+ "name": "@siteed/audio-studio",
3
+ "version": "3.2.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/audiolab/blob/main/packages/audio-studio/README.md",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "git+https://github.com/deeeed/audiolab.git",
18
+ "directory": "packages/audio-studio"
19
+ },
20
+ "bugs": {
21
+ "url": "https://github.com/deeeed/audiolab/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
+ "prebuilt",
61
+ "build",
62
+ "!ios/build",
63
+ "!android/build",
64
+ "!android/gradle",
65
+ "!android/gradlew",
66
+ "!android/gradlew.bat",
67
+ "!android/local.properties",
68
+ "!ios/AudioStudioTests",
69
+ "!ios/AudioStudioTests/**",
70
+ "!ios/tests",
71
+ "!ios/tests/**",
72
+ "!android/src/androidTest",
73
+ "!android/src/androidTest/**",
74
+ "!android/src/test",
75
+ "!android/src/test/**",
76
+ "!android/src/test/resources",
77
+ "!android/src/test/resources/**",
78
+ "!**/__tests__",
79
+ "!**/__fixtures__",
80
+ "!**/__mocks__",
81
+ "!**/.*"
82
+ ],
83
+ "scripts": {
84
+ "build:wasm": "bash scripts/build-wasm.sh",
85
+ "build": "rimraf build && yarn build:types && yarn build:cjs && yarn build:esm && yarn build:plugin && cp -r prebuilt/ build/cjs/prebuilt && cp -r prebuilt/ build/esm/prebuilt",
86
+ "build:cjs": "tsc -p tsconfig.cjs.json",
87
+ "build:esm": "tsc -p tsconfig.esm.json",
88
+ "build:types": "tsc -p tsconfig.types.json",
89
+ "build:plugin": "tsc --project plugin/tsconfig.json && cp plugin/build/index.js plugin/build/index.cjs",
90
+ "build:plugin:dev": "expo-module build plugin",
91
+ "build:dev": "expo-module build",
92
+ "clean": "expo-module clean && rimraf build plugin/build",
93
+ "lint": "expo-module lint",
94
+ "lint:fix": "expo-module lint --fix",
95
+ "test": "expo-module test",
96
+ "test:android": "yarn test:android:unit && yarn test:android:instrumented",
97
+ "test:android:unit": "cd ../../apps/playground/android && ./gradlew :siteed-audio-studio:test",
98
+ "test:android:instrumented": "cd ../../apps/playground/android && ./gradlew :siteed-audio-studio:connectedAndroidTest",
99
+ "test:android:unit:watch": "cd ../../apps/playground/android && ./gradlew :siteed-audio-studio:test --continuous",
100
+ "test:ios": "cd ../../apps/playground/ios && xcodebuild -workspace AudioDevPlayground.xcworkspace -scheme AudioDevPlayground -destination 'generic/platform=iOS Simulator' build",
101
+ "test:coverage": "cd ../../apps/playground/android && ./gradlew :siteed-audio-studio:jacocoTestReport",
102
+ "typecheck": "tsc --noEmit",
103
+ "docgen": "typedoc src/index.ts --plugin typedoc-plugin-markdown --readme none --out ../../documentation_site/docs/api-reference/API && node ../../scripts/escape-mdx-generics.js ../../documentation_site/docs/api-reference",
104
+ "prepare": "yarn build && node -e \"require('fs').renameSync('./plugin/build/index.d.ts', './plugin/build/index.d.cts')\"",
105
+ "prepublishOnly.disabled": "expo-module prepublishOnly",
106
+ "expo-module": "expo-module",
107
+ "open:ios": "open -a \"Xcode\" ../../apps/playground/ios",
108
+ "open:android": "open -a \"Android Studio\" ../../apps/playground/android",
109
+ "size": "bundle-size && size-limit",
110
+ "release": "./publish.sh",
111
+ "agent:test:unit": "yarn test:android:unit",
112
+ "agent:test:integration": "yarn test:android:instrumented",
113
+ "agent:compilation:check": "yarn typecheck && yarn build",
114
+ "android": "cd ../../apps/playground && yarn android",
115
+ "android:launch": "cd ../../apps/playground && yarn android:launch",
116
+ "validate:stream-long": "node scripts/validate-stream-long.mjs",
117
+ "android:device": "cd ../../apps/playground && yarn android:device",
118
+ "android:device:launch": "cd ../../apps/playground && yarn android:device:launch",
119
+ "summarize:stream-long": "node scripts/summarize-stream-long.mjs"
120
+ },
121
+ "devDependencies": {
122
+ "@expo/config-plugins": "~54.0.0",
123
+ "@expo/npm-proofread": "^1.0.1",
124
+ "@siteed/publisher": "^0.4.18",
125
+ "@size-limit/preset-big-lib": "^11.1.4",
126
+ "@types/jest": "^29.5.12",
127
+ "@types/node": "^20.12.7",
128
+ "@types/react": "~19.0.10",
129
+ "@typescript-eslint/eslint-plugin": "^7.7.0",
130
+ "@typescript-eslint/parser": "^7.7.0",
131
+ "bundle-size": "^1.1.5",
132
+ "eslint": "^8.56.0",
133
+ "eslint-config-prettier": "^9.1.0",
134
+ "eslint-config-universe": "^12.0.0",
135
+ "eslint-plugin-import": "^2.29.1",
136
+ "eslint-plugin-prettier": "^5.1.3",
137
+ "eslint-plugin-promise": "^6.1.1",
138
+ "eslint-plugin-react": "^7.34.1",
139
+ "expo": "^54.0.0",
140
+ "expo-module-scripts": "^4.1.7",
141
+ "expo-modules-core": "~3.0.0",
142
+ "jest": "^29.7.0",
143
+ "prettier": "^3.2.5",
144
+ "react": "19.2.0",
145
+ "react-native": "0.83.6",
146
+ "rimraf": "^6.0.1",
147
+ "size-limit": "^11.1.4",
148
+ "ts-jest": "^29.2.6",
149
+ "ts-node": "^10.9.2",
150
+ "typedoc": "^0.27.4",
151
+ "typedoc-plugin-markdown": "~4.4.2",
152
+ "typescript": "~5.8.3"
153
+ },
154
+ "peerDependencies": {
155
+ "@expo/config-plugins": ">=7.0.0",
156
+ "expo": ">=52.0.0",
157
+ "react": "*",
158
+ "react-native": "*"
159
+ },
160
+ "publishConfig": {
161
+ "access": "public",
162
+ "registry": "https://registry.npmjs.org"
163
+ }
164
+ }
@@ -0,0 +1,58 @@
1
+ # Test Scripts
2
+
3
+ This directory contains unified test scripts for expo-audio-studio.
4
+
5
+ ## run_tests.sh
6
+
7
+ A unified test runner that can execute tests for both Android and iOS platforms.
8
+
9
+ ### Usage
10
+
11
+ ```bash
12
+ ./scripts/run_tests.sh [platform] [type]
13
+ ```
14
+
15
+ ### Parameters
16
+
17
+ - **platform**: Which platform to test
18
+ - `all` (default) - Run tests for both platforms
19
+ - `android` - Run Android tests only
20
+ - `ios` - Run iOS tests only
21
+
22
+ - **type**: Which type of tests to run
23
+ - `all` (default) - Run all test types
24
+ - `unit` - Run unit tests (Android only)
25
+ - `instrumented` - Run instrumented tests (Android only)
26
+ - `standalone` - Run standalone Swift tests (iOS only)
27
+
28
+ ### Examples
29
+
30
+ ```bash
31
+ # Run all tests for both platforms
32
+ ./scripts/run_tests.sh
33
+
34
+ # Run Android tests only
35
+ ./scripts/run_tests.sh android
36
+
37
+ # Run Android unit tests only
38
+ ./scripts/run_tests.sh android unit
39
+
40
+ # Run iOS tests only
41
+ ./scripts/run_tests.sh ios
42
+
43
+ # Run all tests explicitly
44
+ ./scripts/run_tests.sh all all
45
+ ```
46
+
47
+ ### Requirements
48
+
49
+ - **Android**: Requires Android SDK and a connected device/emulator for instrumented tests
50
+ - **iOS**: Requires Swift compiler (comes with Xcode)
51
+
52
+ ### Output
53
+
54
+ The script provides colored output:
55
+ - ๐Ÿงช Test execution progress
56
+ - โœ… Success messages in green
57
+ - โŒ Failure messages in red
58
+ - Summary of tests passed/failed