@siteed/audio-studio 3.2.0-beta.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 (85) hide show
  1. package/CHANGELOG.md +356 -5
  2. package/android/src/main/java/net/siteed/audiostudio/AudioStreamDecoder.kt +306 -94
  3. package/android/src/main/java/net/siteed/audiostudio/AudioStudioModule.kt +39 -6
  4. package/build/cjs/errors/AudioStreamError.js +9 -0
  5. package/build/cjs/errors/AudioStreamError.js.map +1 -1
  6. package/build/cjs/errors/AudioStreamError.test.js +22 -1
  7. package/build/cjs/errors/AudioStreamError.test.js.map +1 -1
  8. package/build/cjs/streamAudioData.js +99 -32
  9. package/build/cjs/streamAudioData.js.map +1 -1
  10. package/build/cjs/utils/audioProcessing.js +14 -10
  11. package/build/cjs/utils/audioProcessing.js.map +1 -1
  12. package/build/esm/errors/AudioStreamError.js +9 -0
  13. package/build/esm/errors/AudioStreamError.js.map +1 -1
  14. package/build/esm/errors/AudioStreamError.test.js +22 -1
  15. package/build/esm/errors/AudioStreamError.test.js.map +1 -1
  16. package/build/esm/streamAudioData.js +99 -32
  17. package/build/esm/streamAudioData.js.map +1 -1
  18. package/build/esm/utils/audioProcessing.js +14 -10
  19. package/build/esm/utils/audioProcessing.js.map +1 -1
  20. package/build/types/errors/AudioStreamError.d.ts.map +1 -1
  21. package/build/types/streamAudioData.d.ts +5 -0
  22. package/build/types/streamAudioData.d.ts.map +1 -1
  23. package/build/types/utils/audioProcessing.d.ts +2 -2
  24. package/build/types/utils/audioProcessing.d.ts.map +1 -1
  25. package/ios/AudioStreamDecoder.swift +191 -100
  26. package/ios/AudioStudioModule.swift +48 -9
  27. package/package.json +163 -146
  28. package/scripts/README.md +58 -0
  29. package/src/errors/AudioStreamError.test.ts +29 -2
  30. package/src/errors/AudioStreamError.ts +14 -0
  31. package/src/streamAudioData.ts +146 -42
  32. package/src/utils/audioProcessing.ts +25 -14
  33. package/android/src/androidTest/assets/chorus.wav +0 -0
  34. package/android/src/androidTest/assets/jfk.wav +0 -0
  35. package/android/src/androidTest/assets/osr_us_000_0010_8k.wav +0 -0
  36. package/android/src/androidTest/assets/recorder_hello_world.wav +0 -0
  37. package/android/src/androidTest/java/net/siteed/audiostudio/AudioFinalMetadataContractInstrumentedTest.kt +0 -190
  38. package/android/src/androidTest/java/net/siteed/audiostudio/AudioProcessorInstrumentedTest.kt +0 -197
  39. package/android/src/androidTest/java/net/siteed/audiostudio/AudioRecorderInstrumentedTest.kt +0 -487
  40. package/android/src/androidTest/java/net/siteed/audiostudio/AudioRecorderPerformanceInstrumentedTest.kt +0 -250
  41. package/android/src/androidTest/java/net/siteed/audiostudio/OpusRangeDecodeRegressionInstrumentedTest.kt +0 -186
  42. package/android/src/androidTest/java/net/siteed/audiostudio/integration/AudioFocusStrategyIntegrationTest.kt +0 -332
  43. package/android/src/androidTest/java/net/siteed/audiostudio/integration/BufferDurationIntegrationTest.kt +0 -324
  44. package/android/src/androidTest/java/net/siteed/audiostudio/integration/CompressedOnlyOutputTest.kt +0 -253
  45. package/android/src/androidTest/java/net/siteed/audiostudio/integration/DeviceDisconnectionFallbackTest.kt +0 -218
  46. package/android/src/androidTest/java/net/siteed/audiostudio/integration/EventEmissionIntervalTest.kt +0 -120
  47. package/android/src/androidTest/java/net/siteed/audiostudio/integration/M4aFormatTest.kt +0 -345
  48. package/android/src/androidTest/java/net/siteed/audiostudio/integration/OutputControlIntegrationTest.kt +0 -340
  49. package/android/src/androidTest/java/net/siteed/audiostudio/integration/PcmStreamingDurationTest.kt +0 -252
  50. package/android/src/androidTest/java/net/siteed/audiostudio/integration/README.md +0 -95
  51. package/android/src/androidTest/java/net/siteed/audiostudio/integration/run_integration_tests.sh +0 -43
  52. package/android/src/test/java/net/siteed/audiostudio/AndroidCallStateTest.kt +0 -37
  53. package/android/src/test/java/net/siteed/audiostudio/AndroidEventEmitterTest.kt +0 -28
  54. package/android/src/test/java/net/siteed/audiostudio/AudioFileHandlerTest.kt +0 -279
  55. package/android/src/test/java/net/siteed/audiostudio/AudioFocusStrategyTest.kt +0 -249
  56. package/android/src/test/java/net/siteed/audiostudio/AudioFormatTest.kt +0 -151
  57. package/android/src/test/java/net/siteed/audiostudio/AudioFormatUtilsTest.kt +0 -273
  58. package/android/src/test/java/net/siteed/audiostudio/DeviceDisconnectionFallbackUnitTest.kt +0 -140
  59. package/android/src/test/java/net/siteed/audiostudio/InterruptionAutoResumePolicyTest.kt +0 -49
  60. package/android/src/test/resources/chorus.wav +0 -0
  61. package/android/src/test/resources/generate_test_audio.py +0 -94
  62. package/android/src/test/resources/jfk.wav +0 -0
  63. package/android/src/test/resources/osr_us_000_0010_8k.wav +0 -0
  64. package/android/src/test/resources/recorder_hello_world.wav +0 -0
  65. package/ios/AudioStudioTests/AudioFileHandlerTests.swift +0 -338
  66. package/ios/AudioStudioTests/AudioFormatUtilsTests.swift +0 -331
  67. package/ios/AudioStudioTests/AudioStreamDecoderTests.swift +0 -128
  68. package/ios/AudioStudioTests/AudioTestHelpers.swift +0 -130
  69. package/ios/AudioStudioTests/CompressedOnlyOutputTests.swift +0 -334
  70. package/ios/AudioStudioTests/EventEmissionIntervalTests.swift +0 -105
  71. package/ios/AudioStudioTests/Info.plist +0 -22
  72. package/ios/AudioStudioTests/README.md +0 -39
  73. package/ios/AudioStudioTests/SimpleAudioTest.swift +0 -98
  74. package/ios/AudioStudioTests/TestAudioGenerator.swift +0 -75
  75. package/ios/tests/README.md +0 -41
  76. package/ios/tests/integration/buffer_and_fallback_test.swift +0 -178
  77. package/ios/tests/integration/buffer_duration_test.swift +0 -185
  78. package/ios/tests/integration/compressed_only_output_test.swift +0 -271
  79. package/ios/tests/integration/output_control_test.swift +0 -322
  80. package/ios/tests/integration/run_integration_tests.sh +0 -37
  81. package/ios/tests/opus_support_test_macos.swift +0 -154
  82. package/ios/tests/standalone/audio_processing_test.swift +0 -144
  83. package/ios/tests/standalone/audio_recording_test.swift +0 -277
  84. package/ios/tests/standalone/audio_streaming_test.swift +0 -249
  85. package/ios/tests/standalone/standalone_test.swift +0 -144
package/package.json CHANGED
@@ -1,147 +1,164 @@
1
1
  {
2
- "name": "@siteed/audio-studio",
3
- "version": "3.2.0-beta.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
@@ -11,13 +11,18 @@ describe('AudioStreamError', () => {
11
11
  })
12
12
 
13
13
  it('maps native FILE_NOT_FOUND code', () => {
14
- const mapped = mapStreamError({ code: 'FILE_NOT_FOUND', message: 'gone' })
14
+ const mapped = mapStreamError({
15
+ code: 'FILE_NOT_FOUND',
16
+ message: 'gone',
17
+ })
15
18
  expect(mapped.code).toBe('ERR_AUDIO_STREAM_FILE_NOT_FOUND')
16
19
  expect(mapped.recoverable).toBe(false)
17
20
  })
18
21
 
19
22
  it('maps unsupported codec text', () => {
20
- const mapped = mapStreamError(new Error('No suitable codec for audio/opus'))
23
+ const mapped = mapStreamError(
24
+ new Error('No suitable codec for audio/opus')
25
+ )
21
26
  expect(mapped.code).toBe('ERR_AUDIO_STREAM_UNSUPPORTED_FORMAT')
22
27
  })
23
28
 
@@ -30,11 +35,33 @@ describe('AudioStreamError', () => {
30
35
  expect(mapped.recoverable).toBe(true)
31
36
  })
32
37
 
38
+ it('maps backpressure timeout as recoverable', () => {
39
+ const mapped = mapStreamError({
40
+ code: 'ERR_AUDIO_STREAM_BACKPRESSURE_TIMEOUT',
41
+ message: 'ack timed out',
42
+ })
43
+ expect(mapped.code).toBe('ERR_AUDIO_STREAM_BACKPRESSURE_TIMEOUT')
44
+ expect(mapped.recoverable).toBe(true)
45
+ })
46
+
33
47
  it('falls back to UNKNOWN', () => {
34
48
  const mapped = mapStreamError({})
35
49
  expect(mapped.code).toBe('ERR_AUDIO_STREAM_UNKNOWN')
36
50
  })
37
51
 
52
+ it('warns when native returns an unknown audio stream code', () => {
53
+ const warn = jest.spyOn(console, 'warn').mockImplementation(() => {})
54
+ const mapped = mapStreamError({
55
+ code: 'ERR_AUDIO_STREAM_FOOBAR',
56
+ message: 'new native code',
57
+ })
58
+ expect(mapped.code).toBe('ERR_AUDIO_STREAM_UNKNOWN')
59
+ expect(warn).toHaveBeenCalledWith(
60
+ '[AudioStreamError] Unknown native audio stream error code: ERR_AUDIO_STREAM_FOOBAR'
61
+ )
62
+ warn.mockRestore()
63
+ })
64
+
38
65
  it('preserves nativeCode and nativeMessage', () => {
39
66
  const mapped = mapStreamError({
40
67
  code: 'WEIRD_NATIVE_CODE',
@@ -80,6 +80,14 @@ function getNativeCode(err: unknown): string | undefined {
80
80
  return undefined
81
81
  }
82
82
 
83
+ function isUnknownAudioStreamCode(raw: string | undefined): boolean {
84
+ if (!raw) return false
85
+ return (
86
+ raw.toUpperCase().startsWith('ERR_AUDIO_STREAM_') &&
87
+ normalizeCode(raw) === null
88
+ )
89
+ }
90
+
83
91
  function normalizeCode(raw: string | undefined): AudioStreamErrorCode | null {
84
92
  if (!raw) return null
85
93
  const upper = raw.toUpperCase()
@@ -151,6 +159,12 @@ export function mapStreamError(
151
159
  const nativeCode = getNativeCode(err)
152
160
  const lower = nativeMessage.toLowerCase()
153
161
 
162
+ if (isUnknownAudioStreamCode(nativeCode)) {
163
+ console.warn(
164
+ `[AudioStreamError] Unknown native audio stream error code: ${nativeCode}`
165
+ )
166
+ }
167
+
154
168
  let code =
155
169
  normalizeCode(nativeCode) ??
156
170
  normalizeCode(nativeMessage) ??