@siteed/expo-audio-studio 2.18.6 → 3.0.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 (329) hide show
  1. package/README.md +13 -297
  2. package/index.d.ts +1 -0
  3. package/index.js +1 -0
  4. package/package.json +6 -135
  5. package/CHANGELOG.md +0 -501
  6. package/LICENSE +0 -21
  7. package/android/build.gradle +0 -129
  8. package/android/src/androidTest/assets/chorus.wav +0 -0
  9. package/android/src/androidTest/assets/jfk.wav +0 -0
  10. package/android/src/androidTest/assets/osr_us_000_0010_8k.wav +0 -0
  11. package/android/src/androidTest/assets/recorder_hello_world.wav +0 -0
  12. package/android/src/androidTest/java/net/siteed/audiostream/AudioProcessorInstrumentedTest.kt +0 -197
  13. package/android/src/androidTest/java/net/siteed/audiostream/AudioRecorderInstrumentedTest.kt +0 -541
  14. package/android/src/androidTest/java/net/siteed/audiostream/AudioRecorderPerformanceInstrumentedTest.kt +0 -234
  15. package/android/src/androidTest/java/net/siteed/audiostream/integration/AudioFocusStrategyIntegrationTest.kt +0 -332
  16. package/android/src/androidTest/java/net/siteed/audiostream/integration/BufferDurationIntegrationTest.kt +0 -324
  17. package/android/src/androidTest/java/net/siteed/audiostream/integration/CompressedOnlyOutputTest.kt +0 -253
  18. package/android/src/androidTest/java/net/siteed/audiostream/integration/DeviceDisconnectionFallbackTest.kt +0 -218
  19. package/android/src/androidTest/java/net/siteed/audiostream/integration/EventEmissionIntervalTest.kt +0 -120
  20. package/android/src/androidTest/java/net/siteed/audiostream/integration/M4aFormatTest.kt +0 -345
  21. package/android/src/androidTest/java/net/siteed/audiostream/integration/OutputControlIntegrationTest.kt +0 -340
  22. package/android/src/androidTest/java/net/siteed/audiostream/integration/PcmStreamingDurationTest.kt +0 -252
  23. package/android/src/androidTest/java/net/siteed/audiostream/integration/README.md +0 -95
  24. package/android/src/androidTest/java/net/siteed/audiostream/integration/run_integration_tests.sh +0 -43
  25. package/android/src/main/AndroidManifest.xml +0 -30
  26. package/android/src/main/java/net/siteed/audiostream/AudioAnalysisData.kt +0 -188
  27. package/android/src/main/java/net/siteed/audiostream/AudioDataEncoder.kt +0 -9
  28. package/android/src/main/java/net/siteed/audiostream/AudioDeviceManager.kt +0 -1741
  29. package/android/src/main/java/net/siteed/audiostream/AudioFileHandler.kt +0 -136
  30. package/android/src/main/java/net/siteed/audiostream/AudioFormatUtils.kt +0 -354
  31. package/android/src/main/java/net/siteed/audiostream/AudioNotificationsManager.kt +0 -439
  32. package/android/src/main/java/net/siteed/audiostream/AudioProcessor.kt +0 -2237
  33. package/android/src/main/java/net/siteed/audiostream/AudioRecorderManager.kt +0 -2141
  34. package/android/src/main/java/net/siteed/audiostream/AudioRecordingService.kt +0 -167
  35. package/android/src/main/java/net/siteed/audiostream/AudioTrimmer.kt +0 -1099
  36. package/android/src/main/java/net/siteed/audiostream/Constants.kt +0 -37
  37. package/android/src/main/java/net/siteed/audiostream/EventSender.kt +0 -7
  38. package/android/src/main/java/net/siteed/audiostream/ExpoAudioStreamModule.kt +0 -1113
  39. package/android/src/main/java/net/siteed/audiostream/FFT.kt +0 -99
  40. package/android/src/main/java/net/siteed/audiostream/Features.kt +0 -98
  41. package/android/src/main/java/net/siteed/audiostream/LogUtils.kt +0 -93
  42. package/android/src/main/java/net/siteed/audiostream/NotificationConfig.kt +0 -72
  43. package/android/src/main/java/net/siteed/audiostream/PermissionUtils.kt +0 -68
  44. package/android/src/main/java/net/siteed/audiostream/RecordingActionReceiver.kt +0 -59
  45. package/android/src/main/java/net/siteed/audiostream/RecordingConfig.kt +0 -257
  46. package/android/src/main/java/net/siteed/audiostream/WaveformConfig.kt +0 -19
  47. package/android/src/main/java/net/siteed/audiostream/WaveformRenderer.kt +0 -159
  48. package/android/src/main/res/drawable/ic_default_action_icon.xml +0 -16
  49. package/android/src/main/res/drawable/ic_microphone.xml +0 -13
  50. package/android/src/main/res/drawable/ic_pause.xml +0 -10
  51. package/android/src/main/res/drawable/ic_play.xml +0 -10
  52. package/android/src/main/res/drawable/ic_stop.xml +0 -10
  53. package/android/src/main/res/layout/notification_recording.xml +0 -37
  54. package/android/src/test/java/net/siteed/audiostream/AudioFileHandlerTest.kt +0 -279
  55. package/android/src/test/java/net/siteed/audiostream/AudioFocusStrategyTest.kt +0 -249
  56. package/android/src/test/java/net/siteed/audiostream/AudioFormatTest.kt +0 -151
  57. package/android/src/test/java/net/siteed/audiostream/AudioFormatUtilsTest.kt +0 -273
  58. package/android/src/test/java/net/siteed/audiostream/DeviceDisconnectionFallbackUnitTest.kt +0 -140
  59. package/android/src/test/resources/chorus.wav +0 -0
  60. package/android/src/test/resources/generate_test_audio.py +0 -94
  61. package/android/src/test/resources/jfk.wav +0 -0
  62. package/android/src/test/resources/osr_us_000_0010_8k.wav +0 -0
  63. package/android/src/test/resources/recorder_hello_world.wav +0 -0
  64. package/app.plugin.js +0 -3
  65. package/build/cjs/AudioAnalysis/AudioAnalysis.types.js +0 -4
  66. package/build/cjs/AudioAnalysis/AudioAnalysis.types.js.map +0 -1
  67. package/build/cjs/AudioAnalysis/extractAudioAnalysis.js +0 -210
  68. package/build/cjs/AudioAnalysis/extractAudioAnalysis.js.map +0 -1
  69. package/build/cjs/AudioAnalysis/extractAudioData.js +0 -21
  70. package/build/cjs/AudioAnalysis/extractAudioData.js.map +0 -1
  71. package/build/cjs/AudioAnalysis/extractMelSpectrogram.js +0 -92
  72. package/build/cjs/AudioAnalysis/extractMelSpectrogram.js.map +0 -1
  73. package/build/cjs/AudioAnalysis/extractPreview.js +0 -28
  74. package/build/cjs/AudioAnalysis/extractPreview.js.map +0 -1
  75. package/build/cjs/AudioAnalysis/extractWaveform.js +0 -18
  76. package/build/cjs/AudioAnalysis/extractWaveform.js.map +0 -1
  77. package/build/cjs/AudioDeviceManager.js +0 -689
  78. package/build/cjs/AudioDeviceManager.js.map +0 -1
  79. package/build/cjs/AudioRecorder.provider.js +0 -78
  80. package/build/cjs/AudioRecorder.provider.js.map +0 -1
  81. package/build/cjs/ExpoAudioStream.native.js +0 -8
  82. package/build/cjs/ExpoAudioStream.native.js.map +0 -1
  83. package/build/cjs/ExpoAudioStream.types.js +0 -11
  84. package/build/cjs/ExpoAudioStream.types.js.map +0 -1
  85. package/build/cjs/ExpoAudioStream.web.js +0 -708
  86. package/build/cjs/ExpoAudioStream.web.js.map +0 -1
  87. package/build/cjs/ExpoAudioStreamModule.js +0 -718
  88. package/build/cjs/ExpoAudioStreamModule.js.map +0 -1
  89. package/build/cjs/WebRecorder.web.js +0 -777
  90. package/build/cjs/WebRecorder.web.js.map +0 -1
  91. package/build/cjs/constants/platformLimitations.js +0 -99
  92. package/build/cjs/constants/platformLimitations.js.map +0 -1
  93. package/build/cjs/constants.js +0 -17
  94. package/build/cjs/constants.js.map +0 -1
  95. package/build/cjs/events.js +0 -29
  96. package/build/cjs/events.js.map +0 -1
  97. package/build/cjs/hooks/useAudioDevices.js +0 -179
  98. package/build/cjs/hooks/useAudioDevices.js.map +0 -1
  99. package/build/cjs/index.js +0 -58
  100. package/build/cjs/index.js.map +0 -1
  101. package/build/cjs/trimAudio.js +0 -76
  102. package/build/cjs/trimAudio.js.map +0 -1
  103. package/build/cjs/useAudioRecorder.js +0 -518
  104. package/build/cjs/useAudioRecorder.js.map +0 -1
  105. package/build/cjs/utils/BlobFix.js +0 -502
  106. package/build/cjs/utils/BlobFix.js.map +0 -1
  107. package/build/cjs/utils/audioProcessing.js +0 -136
  108. package/build/cjs/utils/audioProcessing.js.map +0 -1
  109. package/build/cjs/utils/cleanNativeOptions.js +0 -22
  110. package/build/cjs/utils/cleanNativeOptions.js.map +0 -1
  111. package/build/cjs/utils/concatenateBuffers.js +0 -25
  112. package/build/cjs/utils/concatenateBuffers.js.map +0 -1
  113. package/build/cjs/utils/convertPCMToFloat32.js +0 -124
  114. package/build/cjs/utils/convertPCMToFloat32.js.map +0 -1
  115. package/build/cjs/utils/crc32.js +0 -52
  116. package/build/cjs/utils/crc32.js.map +0 -1
  117. package/build/cjs/utils/encodingToBitDepth.js +0 -17
  118. package/build/cjs/utils/encodingToBitDepth.js.map +0 -1
  119. package/build/cjs/utils/getWavFileInfo.js +0 -96
  120. package/build/cjs/utils/getWavFileInfo.js.map +0 -1
  121. package/build/cjs/utils/writeWavHeader.js +0 -88
  122. package/build/cjs/utils/writeWavHeader.js.map +0 -1
  123. package/build/cjs/workers/InlineFeaturesExtractor.web.js +0 -859
  124. package/build/cjs/workers/InlineFeaturesExtractor.web.js.map +0 -1
  125. package/build/cjs/workers/inlineAudioWebWorker.web.js +0 -184
  126. package/build/cjs/workers/inlineAudioWebWorker.web.js.map +0 -1
  127. package/build/esm/AudioAnalysis/AudioAnalysis.types.js +0 -3
  128. package/build/esm/AudioAnalysis/AudioAnalysis.types.js.map +0 -1
  129. package/build/esm/AudioAnalysis/extractAudioAnalysis.js +0 -202
  130. package/build/esm/AudioAnalysis/extractAudioAnalysis.js.map +0 -1
  131. package/build/esm/AudioAnalysis/extractAudioData.js +0 -14
  132. package/build/esm/AudioAnalysis/extractAudioData.js.map +0 -1
  133. package/build/esm/AudioAnalysis/extractMelSpectrogram.js +0 -89
  134. package/build/esm/AudioAnalysis/extractMelSpectrogram.js.map +0 -1
  135. package/build/esm/AudioAnalysis/extractPreview.js +0 -25
  136. package/build/esm/AudioAnalysis/extractPreview.js.map +0 -1
  137. package/build/esm/AudioAnalysis/extractWaveform.js +0 -11
  138. package/build/esm/AudioAnalysis/extractWaveform.js.map +0 -1
  139. package/build/esm/AudioDeviceManager.js +0 -682
  140. package/build/esm/AudioDeviceManager.js.map +0 -1
  141. package/build/esm/AudioRecorder.provider.js +0 -40
  142. package/build/esm/AudioRecorder.provider.js.map +0 -1
  143. package/build/esm/ExpoAudioStream.native.js +0 -6
  144. package/build/esm/ExpoAudioStream.native.js.map +0 -1
  145. package/build/esm/ExpoAudioStream.types.js +0 -8
  146. package/build/esm/ExpoAudioStream.types.js.map +0 -1
  147. package/build/esm/ExpoAudioStream.web.js +0 -704
  148. package/build/esm/ExpoAudioStream.web.js.map +0 -1
  149. package/build/esm/ExpoAudioStreamModule.js +0 -713
  150. package/build/esm/ExpoAudioStreamModule.js.map +0 -1
  151. package/build/esm/WebRecorder.web.js +0 -773
  152. package/build/esm/WebRecorder.web.js.map +0 -1
  153. package/build/esm/constants/platformLimitations.js +0 -90
  154. package/build/esm/constants/platformLimitations.js.map +0 -1
  155. package/build/esm/constants.js +0 -14
  156. package/build/esm/constants.js.map +0 -1
  157. package/build/esm/events.js +0 -21
  158. package/build/esm/events.js.map +0 -1
  159. package/build/esm/hooks/useAudioDevices.js +0 -176
  160. package/build/esm/hooks/useAudioDevices.js.map +0 -1
  161. package/build/esm/index.js +0 -20
  162. package/build/esm/index.js.map +0 -1
  163. package/build/esm/trimAudio.js +0 -69
  164. package/build/esm/trimAudio.js.map +0 -1
  165. package/build/esm/useAudioRecorder.js +0 -512
  166. package/build/esm/useAudioRecorder.js.map +0 -1
  167. package/build/esm/utils/BlobFix.js +0 -498
  168. package/build/esm/utils/BlobFix.js.map +0 -1
  169. package/build/esm/utils/audioProcessing.js +0 -133
  170. package/build/esm/utils/audioProcessing.js.map +0 -1
  171. package/build/esm/utils/cleanNativeOptions.js +0 -19
  172. package/build/esm/utils/cleanNativeOptions.js.map +0 -1
  173. package/build/esm/utils/concatenateBuffers.js +0 -21
  174. package/build/esm/utils/concatenateBuffers.js.map +0 -1
  175. package/build/esm/utils/convertPCMToFloat32.js +0 -120
  176. package/build/esm/utils/convertPCMToFloat32.js.map +0 -1
  177. package/build/esm/utils/crc32.js +0 -50
  178. package/build/esm/utils/crc32.js.map +0 -1
  179. package/build/esm/utils/encodingToBitDepth.js +0 -13
  180. package/build/esm/utils/encodingToBitDepth.js.map +0 -1
  181. package/build/esm/utils/getWavFileInfo.js +0 -92
  182. package/build/esm/utils/getWavFileInfo.js.map +0 -1
  183. package/build/esm/utils/writeWavHeader.js +0 -84
  184. package/build/esm/utils/writeWavHeader.js.map +0 -1
  185. package/build/esm/workers/InlineFeaturesExtractor.web.js +0 -856
  186. package/build/esm/workers/InlineFeaturesExtractor.web.js.map +0 -1
  187. package/build/esm/workers/inlineAudioWebWorker.web.js +0 -181
  188. package/build/esm/workers/inlineAudioWebWorker.web.js.map +0 -1
  189. package/build/types/AudioAnalysis/AudioAnalysis.types.d.ts +0 -196
  190. package/build/types/AudioAnalysis/AudioAnalysis.types.d.ts.map +0 -1
  191. package/build/types/AudioAnalysis/extractAudioAnalysis.d.ts +0 -74
  192. package/build/types/AudioAnalysis/extractAudioAnalysis.d.ts.map +0 -1
  193. package/build/types/AudioAnalysis/extractAudioData.d.ts +0 -3
  194. package/build/types/AudioAnalysis/extractAudioData.d.ts.map +0 -1
  195. package/build/types/AudioAnalysis/extractMelSpectrogram.d.ts +0 -14
  196. package/build/types/AudioAnalysis/extractMelSpectrogram.d.ts.map +0 -1
  197. package/build/types/AudioAnalysis/extractPreview.d.ts +0 -11
  198. package/build/types/AudioAnalysis/extractPreview.d.ts.map +0 -1
  199. package/build/types/AudioAnalysis/extractWaveform.d.ts +0 -8
  200. package/build/types/AudioAnalysis/extractWaveform.d.ts.map +0 -1
  201. package/build/types/AudioDeviceManager.d.ts +0 -187
  202. package/build/types/AudioDeviceManager.d.ts.map +0 -1
  203. package/build/types/AudioRecorder.provider.d.ts +0 -11
  204. package/build/types/AudioRecorder.provider.d.ts.map +0 -1
  205. package/build/types/ExpoAudioStream.native.d.ts +0 -3
  206. package/build/types/ExpoAudioStream.native.d.ts.map +0 -1
  207. package/build/types/ExpoAudioStream.types.d.ts +0 -738
  208. package/build/types/ExpoAudioStream.types.d.ts.map +0 -1
  209. package/build/types/ExpoAudioStream.web.d.ts +0 -96
  210. package/build/types/ExpoAudioStream.web.d.ts.map +0 -1
  211. package/build/types/ExpoAudioStreamModule.d.ts +0 -3
  212. package/build/types/ExpoAudioStreamModule.d.ts.map +0 -1
  213. package/build/types/WebRecorder.web.d.ts +0 -198
  214. package/build/types/WebRecorder.web.d.ts.map +0 -1
  215. package/build/types/constants/platformLimitations.d.ts +0 -40
  216. package/build/types/constants/platformLimitations.d.ts.map +0 -1
  217. package/build/types/constants.d.ts +0 -11
  218. package/build/types/constants.d.ts.map +0 -1
  219. package/build/types/events.d.ts +0 -26
  220. package/build/types/events.d.ts.map +0 -1
  221. package/build/types/hooks/useAudioDevices.d.ts +0 -15
  222. package/build/types/hooks/useAudioDevices.d.ts.map +0 -1
  223. package/build/types/index.d.ts +0 -18
  224. package/build/types/index.d.ts.map +0 -1
  225. package/build/types/trimAudio.d.ts +0 -25
  226. package/build/types/trimAudio.d.ts.map +0 -1
  227. package/build/types/useAudioRecorder.d.ts +0 -22
  228. package/build/types/useAudioRecorder.d.ts.map +0 -1
  229. package/build/types/utils/BlobFix.d.ts +0 -9
  230. package/build/types/utils/BlobFix.d.ts.map +0 -1
  231. package/build/types/utils/audioProcessing.d.ts +0 -24
  232. package/build/types/utils/audioProcessing.d.ts.map +0 -1
  233. package/build/types/utils/cleanNativeOptions.d.ts +0 -15
  234. package/build/types/utils/cleanNativeOptions.d.ts.map +0 -1
  235. package/build/types/utils/concatenateBuffers.d.ts +0 -8
  236. package/build/types/utils/concatenateBuffers.d.ts.map +0 -1
  237. package/build/types/utils/convertPCMToFloat32.d.ts +0 -13
  238. package/build/types/utils/convertPCMToFloat32.d.ts.map +0 -1
  239. package/build/types/utils/crc32.d.ts +0 -7
  240. package/build/types/utils/crc32.d.ts.map +0 -1
  241. package/build/types/utils/encodingToBitDepth.d.ts +0 -5
  242. package/build/types/utils/encodingToBitDepth.d.ts.map +0 -1
  243. package/build/types/utils/getWavFileInfo.d.ts +0 -26
  244. package/build/types/utils/getWavFileInfo.d.ts.map +0 -1
  245. package/build/types/utils/writeWavHeader.d.ts +0 -34
  246. package/build/types/utils/writeWavHeader.d.ts.map +0 -1
  247. package/build/types/workers/InlineFeaturesExtractor.web.d.ts +0 -2
  248. package/build/types/workers/InlineFeaturesExtractor.web.d.ts.map +0 -1
  249. package/build/types/workers/inlineAudioWebWorker.web.d.ts +0 -2
  250. package/build/types/workers/inlineAudioWebWorker.web.d.ts.map +0 -1
  251. package/expo-module.config.json +0 -10
  252. package/ios/AudioAnalysisData.swift +0 -74
  253. package/ios/AudioDeviceManager.swift +0 -670
  254. package/ios/AudioNotificationManager.swift +0 -154
  255. package/ios/AudioProcessingHelpers.swift +0 -743
  256. package/ios/AudioProcessor.swift +0 -1151
  257. package/ios/AudioStreamError.swift +0 -7
  258. package/ios/AudioStreamManager.swift +0 -2369
  259. package/ios/AudioStreamManagerDelegate.swift +0 -16
  260. package/ios/DataPoint.swift +0 -54
  261. package/ios/DecodingConfig.swift +0 -59
  262. package/ios/ExpoAudioStream.podspec +0 -33
  263. package/ios/ExpoAudioStreamModule.swift +0 -1019
  264. package/ios/ExpoAudioStudioTests/AudioFileHandlerTests.swift +0 -338
  265. package/ios/ExpoAudioStudioTests/AudioFormatUtilsTests.swift +0 -331
  266. package/ios/ExpoAudioStudioTests/AudioTestHelpers.swift +0 -130
  267. package/ios/ExpoAudioStudioTests/CompressedOnlyOutputTests.swift +0 -294
  268. package/ios/ExpoAudioStudioTests/EventEmissionIntervalTests.swift +0 -105
  269. package/ios/ExpoAudioStudioTests/Info.plist +0 -22
  270. package/ios/ExpoAudioStudioTests/README.md +0 -39
  271. package/ios/ExpoAudioStudioTests/SimpleAudioTest.swift +0 -98
  272. package/ios/ExpoAudioStudioTests/TestAudioGenerator.swift +0 -75
  273. package/ios/FFT.swift +0 -62
  274. package/ios/Features.swift +0 -95
  275. package/ios/ISSUE_IOS.md +0 -68
  276. package/ios/Logger.swift +0 -39
  277. package/ios/NotificationExtension.swift +0 -15
  278. package/ios/RecordingResult.swift +0 -22
  279. package/ios/RecordingSettings.swift +0 -308
  280. package/ios/WaveformExtractor.swift +0 -105
  281. package/ios/tests/README.md +0 -41
  282. package/ios/tests/integration/buffer_and_fallback_test.swift +0 -178
  283. package/ios/tests/integration/buffer_duration_test.swift +0 -185
  284. package/ios/tests/integration/compressed_only_output_test.swift +0 -271
  285. package/ios/tests/integration/output_control_test.swift +0 -322
  286. package/ios/tests/integration/run_integration_tests.sh +0 -37
  287. package/ios/tests/opus_support_test_macos.swift +0 -154
  288. package/ios/tests/standalone/audio_processing_test.swift +0 -144
  289. package/ios/tests/standalone/audio_recording_test.swift +0 -277
  290. package/ios/tests/standalone/audio_streaming_test.swift +0 -249
  291. package/ios/tests/standalone/standalone_test.swift +0 -144
  292. package/plugin/build/index.cjs +0 -194
  293. package/plugin/build/index.d.cts +0 -22
  294. package/plugin/build/index.js +0 -194
  295. package/plugin/src/index.ts +0 -285
  296. package/plugin/tsconfig.json +0 -10
  297. package/plugin/tsconfig.tsbuildinfo +0 -1
  298. package/src/AudioAnalysis/AudioAnalysis.types.ts +0 -224
  299. package/src/AudioAnalysis/extractAudioAnalysis.ts +0 -344
  300. package/src/AudioAnalysis/extractAudioData.ts +0 -17
  301. package/src/AudioAnalysis/extractMelSpectrogram.ts +0 -154
  302. package/src/AudioAnalysis/extractPreview.ts +0 -34
  303. package/src/AudioAnalysis/extractWaveform.ts +0 -22
  304. package/src/AudioDeviceManager.ts +0 -803
  305. package/src/AudioRecorder.provider.tsx +0 -57
  306. package/src/ExpoAudioStream.native.ts +0 -6
  307. package/src/ExpoAudioStream.types.ts +0 -874
  308. package/src/ExpoAudioStream.web.ts +0 -905
  309. package/src/ExpoAudioStreamModule.ts +0 -990
  310. package/src/WebRecorder.web.ts +0 -1005
  311. package/src/constants/platformLimitations.ts +0 -118
  312. package/src/constants.ts +0 -18
  313. package/src/events.ts +0 -60
  314. package/src/hooks/useAudioDevices.ts +0 -213
  315. package/src/index.ts +0 -54
  316. package/src/trimAudio.ts +0 -94
  317. package/src/types/crc-32.d.ts +0 -9
  318. package/src/useAudioRecorder.tsx +0 -766
  319. package/src/utils/BlobFix.ts +0 -561
  320. package/src/utils/audioProcessing.ts +0 -205
  321. package/src/utils/cleanNativeOptions.ts +0 -18
  322. package/src/utils/concatenateBuffers.ts +0 -24
  323. package/src/utils/convertPCMToFloat32.ts +0 -170
  324. package/src/utils/crc32.ts +0 -59
  325. package/src/utils/encodingToBitDepth.ts +0 -18
  326. package/src/utils/getWavFileInfo.ts +0 -132
  327. package/src/utils/writeWavHeader.ts +0 -115
  328. package/src/workers/InlineFeaturesExtractor.web.tsx +0 -855
  329. package/src/workers/inlineAudioWebWorker.web.tsx +0 -180
@@ -1,308 +0,0 @@
1
- // RecordingSettings.swift
2
-
3
- import AVFoundation
4
-
5
- struct NotificationAction {
6
- var title: String
7
- var identifier: String
8
- }
9
-
10
- struct IOSAudioSessionConfig {
11
- var category: AVAudioSession.Category
12
- var mode: AVAudioSession.Mode
13
- var categoryOptions: AVAudioSession.CategoryOptions
14
- }
15
-
16
- struct IOSNotificationConfig {
17
- var categoryIdentifier: String?
18
- }
19
-
20
- struct OutputSettings {
21
- struct PrimaryOutput {
22
- var enabled: Bool = true
23
- var format: String = "wav" // Currently only "wav" is supported
24
- }
25
-
26
- struct CompressedOutput {
27
- var enabled: Bool = false
28
- var format: String = "aac" // "aac" or "opus" (opus falls back to aac on iOS)
29
- var bitrate: Int = 128000
30
- }
31
-
32
- var primary: PrimaryOutput = PrimaryOutput()
33
- var compressed: CompressedOutput = CompressedOutput()
34
- }
35
-
36
- struct CompressedRecordingInfo {
37
- var compressedFileUri: String
38
- var mimeType: String
39
- var bitrate: Int
40
- var format: String
41
- var size: Int64 = 0 // Add size with default value
42
-
43
- static func validate(format: String, bitrate: Int) -> Result<(String, Int), Error> {
44
- // Validate format
45
- guard ["aac", "opus"].contains(format.lowercased()) else {
46
- return .failure(RecordingError.unsupportedFormat(format))
47
- }
48
-
49
- // Adjust bitrate based on format
50
- let adjustedBitrate: Int
51
- if format.lowercased() == "aac" {
52
- // Standard AAC bitrates (bps)
53
- let standardAACBitrates = [32000, 48000, 64000, 96000, 128000, 160000, 192000, 256000, 320000]
54
- adjustedBitrate = standardAACBitrates.min(by: { abs($0 - bitrate) < abs($1 - bitrate) }) ?? 128000
55
- } else {
56
- // For Opus, allow lower bitrates (especially good for voice)
57
- // Typical Opus voice bitrates: 8-24 kbps, music: 32-128 kbps
58
- adjustedBitrate = min(max(bitrate, 8000), 320000)
59
- }
60
-
61
- return .success((format, adjustedBitrate))
62
- }
63
- }
64
-
65
- struct NotificationConfig {
66
- var title: String?
67
- var text: String?
68
- var icon: String?
69
- var ios: IOSNotificationConfig?
70
- }
71
-
72
- struct IOSConfig {
73
- var audioSession: IOSAudioSessionConfig?
74
- }
75
-
76
- enum RecordingError: Error {
77
- case unsupportedFormat(String)
78
- case invalidBitrate(Int)
79
- case invalidOutputDirectory(String)
80
-
81
- var localizedDescription: String {
82
- switch self {
83
- case .unsupportedFormat(let format):
84
- return "Unsupported compression format: \(format). iOS only supports AAC."
85
- case .invalidBitrate(let bitrate):
86
- return "Invalid bitrate: \(bitrate). Must be between 8000 and 960000 bps."
87
- case .invalidOutputDirectory(let directory):
88
- return "Invalid output directory: \(directory). Directory does not exist, is not a directory, or is not writable."
89
- }
90
- }
91
- }
92
-
93
- struct RecordingSettings {
94
- // Core recording settings
95
- var sampleRate: Double
96
- var desiredSampleRate: Double
97
- var numberOfChannels: Int = 1
98
- var bitDepth: Int = 16
99
- var interval: Int?
100
- var intervalAnalysis: Int?
101
-
102
- // Feature flags
103
- var keepAwake: Bool = true
104
- var showNotification: Bool = false
105
- var enableProcessing: Bool = false
106
-
107
- // Remove pointsPerSecond and algorithm
108
- var featureOptions: [String: Bool]? = ["rms": true, "zcr": true]
109
-
110
- // iOS-specific configuration
111
- var ios: IOSConfig?
112
-
113
- // Notification configuration
114
- var notification: NotificationConfig?
115
-
116
- // Output configuration
117
- var output: OutputSettings = OutputSettings()
118
-
119
- let autoResumeAfterInterruption: Bool
120
-
121
- var outputDirectory: String? = nil
122
- var filename: String? = nil
123
-
124
- // Update default to 100ms
125
- var segmentDurationMs: Int = 100 // Default 100ms segments
126
-
127
- // Add these new properties
128
- var deviceId: String?
129
- var deviceDisconnectionBehavior: DeviceDisconnectionBehavior = .FALLBACK
130
- var bufferDurationSeconds: Double?
131
-
132
- static func fromDictionary(_ dict: [String: Any]) -> Result<RecordingSettings, Error> {
133
- // Parse output configuration
134
- var outputSettings = OutputSettings()
135
-
136
- if let outputDict = dict["output"] as? [String: Any] {
137
- // Parse primary output settings
138
- if let primaryDict = outputDict["primary"] as? [String: Any] {
139
- outputSettings.primary.enabled = primaryDict["enabled"] as? Bool ?? true
140
- outputSettings.primary.format = primaryDict["format"] as? String ?? "wav"
141
- }
142
-
143
- // Parse compressed output settings
144
- if let compressedDict = outputDict["compressed"] as? [String: Any] {
145
- outputSettings.compressed.enabled = compressedDict["enabled"] as? Bool ?? false
146
- let format = (compressedDict["format"] as? String)?.lowercased() ?? "aac"
147
- outputSettings.compressed.format = format
148
- outputSettings.compressed.bitrate = compressedDict["bitrate"] as? Int ?? 128000
149
-
150
- // Validate compression settings if enabled
151
- if outputSettings.compressed.enabled {
152
- if case .failure(let error) = CompressedRecordingInfo.validate(
153
- format: format,
154
- bitrate: outputSettings.compressed.bitrate
155
- ) {
156
- return .failure(error)
157
- }
158
- }
159
- }
160
- }
161
-
162
- // Add extraction of new properties
163
- let deviceId = dict["deviceId"] as? String
164
- let deviceDisconnectionBehaviorStr = dict["deviceDisconnectionBehavior"] as? String
165
-
166
- // Create settings
167
- var settings = RecordingSettings(
168
- sampleRate: dict["sampleRate"] as? Double ?? 44100.0,
169
- desiredSampleRate: dict["desiredSampleRate"] as? Double ?? 44100.0,
170
- autoResumeAfterInterruption: dict["autoResumeAfterInterruption"] as? Bool ?? false
171
- )
172
-
173
- settings.output = outputSettings
174
-
175
- // Parse core settings
176
- settings.numberOfChannels = dict["channels"] as? Int ?? 1
177
- settings.bitDepth = dict["bitDepth"] as? Int ?? 16
178
- settings.interval = dict["interval"] as? Int
179
- settings.intervalAnalysis = dict["intervalAnalysis"] as? Int
180
-
181
- // Parse feature flags
182
- settings.keepAwake = dict["keepAwake"] as? Bool ?? true
183
- settings.showNotification = dict["showNotification"] as? Bool ?? false
184
- settings.enableProcessing = dict["enableProcessing"] as? Bool ?? false
185
-
186
- settings.featureOptions = dict["features"] as? [String: Bool]
187
-
188
- // Update segmentDurationMs parsing
189
- settings.segmentDurationMs = dict["segmentDurationMs"] as? Int ?? 100
190
-
191
- // Parse iOS-specific config
192
- if let iosDict = dict["ios"] as? [String: Any],
193
- let audioSessionDict = iosDict["audioSession"] as? [String: Any] {
194
-
195
- // Map category
196
- let category: AVAudioSession.Category
197
- if let categoryStr = audioSessionDict["category"] as? String {
198
- switch categoryStr {
199
- case "Ambient": category = .ambient
200
- case "SoloAmbient": category = .soloAmbient
201
- case "Playback": category = .playback
202
- case "Record": category = .record
203
- case "PlayAndRecord": category = .playAndRecord
204
- case "MultiRoute": category = .multiRoute
205
- default: category = .record
206
- }
207
- } else {
208
- category = .record
209
- }
210
-
211
- // Map mode
212
- let mode: AVAudioSession.Mode
213
- if let modeStr = audioSessionDict["mode"] as? String {
214
- switch modeStr {
215
- case "Default": mode = .default
216
- case "VoiceChat": mode = .voiceChat
217
- case "VideoChat": mode = .videoChat
218
- case "GameChat": mode = .gameChat
219
- case "VideoRecording": mode = .videoRecording
220
- case "Measurement": mode = .measurement
221
- case "MoviePlayback": mode = .moviePlayback
222
- case "SpokenAudio": mode = .spokenAudio
223
- default: mode = .default
224
- }
225
- } else {
226
- mode = .default
227
- }
228
-
229
- // Map category options
230
- var categoryOptions: AVAudioSession.CategoryOptions = []
231
- if let optionsArray = audioSessionDict["categoryOptions"] as? [String] {
232
- for option in optionsArray {
233
- switch option {
234
- case "MixWithOthers": categoryOptions.insert(.mixWithOthers)
235
- case "DuckOthers": categoryOptions.insert(.duckOthers)
236
- case "InterruptSpokenAudioAndMixWithOthers": categoryOptions.insert(.interruptSpokenAudioAndMixWithOthers)
237
- case "AllowBluetooth": categoryOptions.insert(.allowBluetooth)
238
- case "AllowBluetoothA2DP": categoryOptions.insert(.allowBluetoothA2DP)
239
- case "AllowAirPlay": categoryOptions.insert(.allowAirPlay)
240
- case "DefaultToSpeaker": categoryOptions.insert(.defaultToSpeaker)
241
- default: break
242
- }
243
- }
244
- }
245
-
246
- settings.ios = IOSConfig(audioSession: IOSAudioSessionConfig(
247
- category: category,
248
- mode: mode,
249
- categoryOptions: categoryOptions
250
- ))
251
- }
252
-
253
- // Parse notification config
254
- if let notificationDict = dict["notification"] as? [String: Any] {
255
- var notificationConfig = NotificationConfig()
256
- notificationConfig.title = notificationDict["title"] as? String
257
- notificationConfig.text = notificationDict["text"] as? String
258
- notificationConfig.icon = notificationDict["icon"] as? String
259
-
260
- // Parse iOS-specific notification config
261
- if let iosNotificationDict = notificationDict["ios"] as? [String: Any] {
262
- notificationConfig.ios = IOSNotificationConfig(
263
- categoryIdentifier: iosNotificationDict["categoryIdentifier"] as? String
264
- )
265
- }
266
-
267
- settings.notification = notificationConfig
268
- }
269
-
270
- // Parse output settings (they remain nil if not provided)
271
- if let directory = dict["outputDirectory"] as? String {
272
- // Only validate if a custom directory is provided
273
- let fileManager = FileManager.default
274
- var isDirectory: ObjCBool = false
275
-
276
- // Clean up the directory path by removing file:// protocol if present
277
- let cleanDirectory = directory.replacingOccurrences(of: "file://", with: "")
278
- .trimmingCharacters(in: CharacterSet(charactersIn: "/"))
279
- .replacingOccurrences(of: "//", with: "/")
280
-
281
- if !fileManager.fileExists(atPath: cleanDirectory, isDirectory: &isDirectory) {
282
- return .failure(RecordingError.invalidOutputDirectory("Directory does not exist: \(cleanDirectory)"))
283
- }
284
-
285
- if !isDirectory.boolValue {
286
- return .failure(RecordingError.invalidOutputDirectory("Path is not a directory: \(cleanDirectory)"))
287
- }
288
-
289
- if !fileManager.isWritableFile(atPath: cleanDirectory) {
290
- return .failure(RecordingError.invalidOutputDirectory("Directory is not writable: \(cleanDirectory)"))
291
- }
292
-
293
- settings.outputDirectory = cleanDirectory
294
- }
295
-
296
- settings.filename = dict["filename"] as? String
297
-
298
- // Set new properties
299
- settings.deviceId = deviceId
300
- settings.deviceDisconnectionBehavior = DeviceDisconnectionBehavior(rawValue: deviceDisconnectionBehaviorStr ?? "fallback") ?? .FALLBACK
301
-
302
- if let bufferDuration = dict["bufferDurationSeconds"] as? Double {
303
- settings.bufferDurationSeconds = bufferDuration
304
- }
305
-
306
- return .success(settings)
307
- }
308
- }
@@ -1,105 +0,0 @@
1
- // WaveformExtractor.swift
2
-
3
- import Accelerate
4
- import AVFoundation
5
-
6
- /// This class is responsible for extracting waveform data from an audio file.
7
- public class WaveformExtractor {
8
- public private(set) var audioFile: AVAudioFile?
9
- private var result: (Any) -> Void
10
- private var reject: (String, String) -> Void
11
- private var waveformData = Array<Float>()
12
- private var progress: Float = 0.0
13
- private var channelCount: Int = 1
14
- private var currentProgress: Float = 0.0
15
- private let extractionQueue = DispatchQueue(label: "WaveformExtractor", attributes: .concurrent)
16
- private var _abortWaveformExtraction: Bool = false
17
-
18
- /// Indicates whether the waveform extraction process should be aborted.
19
- public var abortWaveformExtraction: Bool {
20
- get { _abortWaveformExtraction }
21
- set { _abortWaveformExtraction = newValue }
22
- }
23
-
24
- /// Initializes the waveform extractor with an audio file URL, resolve, and reject callbacks.
25
- ///
26
- /// - Parameters:
27
- /// - url: The URL of the audio file to be read.
28
- /// - resolve: The callback to be called on successful extraction.
29
- /// - reject: The callback to be called on extraction failure.
30
- public init(url: URL, resolve: @escaping (Any) -> Void, reject: @escaping (String, String) -> Void) throws {
31
- self.audioFile = try AVAudioFile(forReading: url)
32
- self.result = resolve
33
- self.reject = reject
34
- }
35
-
36
- deinit {
37
- audioFile = nil
38
- }
39
-
40
- /// Extracts the waveform data from the audio file.
41
- ///
42
- /// - Parameters:
43
- /// - numberOfSamples: The number of samples to extract for the waveform.
44
- /// - offset: The offset to start reading from.
45
- /// - length: The length of the audio to read.
46
- /// - Returns: A 2D array of floats where each sub-array represents waveform data for a specific channel.
47
- public func extractWaveform(numberOfSamples: Int?, offset: Int? = 0, length: UInt? = nil) -> [[Float]]? {
48
- guard let audioFile = audioFile else { return nil }
49
-
50
- let numberOfSamples = max(1, numberOfSamples ?? 100)
51
- let totalFrameCount = AVAudioFrameCount(audioFile.length)
52
- var framesPerBuffer = totalFrameCount / AVAudioFrameCount(numberOfSamples)
53
-
54
- guard let rmsBuffer = AVAudioPCMBuffer(pcmFormat: audioFile.processingFormat, frameCapacity: AVAudioFrameCount(framesPerBuffer)) else { return nil }
55
-
56
- channelCount = Int(audioFile.processingFormat.channelCount)
57
- var data = Array(repeating: [Float](repeating: 0, count: numberOfSamples), count: channelCount)
58
-
59
- var startFrame: AVAudioFramePosition = offset == nil ? audioFile.framePosition : Int64(offset! * Int(framesPerBuffer))
60
- var end = numberOfSamples
61
- if let length = length {
62
- end = Int(length)
63
- }
64
-
65
- for i in 0..<end {
66
- if abortWaveformExtraction {
67
- audioFile.framePosition = startFrame
68
- abortWaveformExtraction = false
69
- return nil
70
- }
71
-
72
- do {
73
- audioFile.framePosition = startFrame
74
- try audioFile.read(into: rmsBuffer, frameCount: framesPerBuffer)
75
- } catch {
76
- reject("AUDIO_READ_ERROR", "Couldn't read into buffer")
77
- return nil
78
- }
79
-
80
- guard let floatData = rmsBuffer.floatChannelData else { return nil }
81
-
82
- for channel in 0..<channelCount {
83
- var rms: Float = 0.0
84
- vDSP_rmsqv(floatData[channel], 1, &rms, vDSP_Length(rmsBuffer.frameLength))
85
- data[channel][i] = rms
86
- }
87
-
88
- currentProgress += 1
89
- progress = currentProgress / Float(numberOfSamples)
90
-
91
- startFrame += AVAudioFramePosition(framesPerBuffer)
92
- if startFrame + AVAudioFramePosition(framesPerBuffer) > AVAudioFramePosition(totalFrameCount) {
93
- framesPerBuffer = totalFrameCount - AVAudioFrameCount(startFrame)
94
- if framesPerBuffer <= 0 { break }
95
- }
96
- }
97
-
98
- return data
99
- }
100
-
101
- /// Cancels the waveform extraction process.
102
- public func cancel() {
103
- abortWaveformExtraction = true
104
- }
105
- }
@@ -1,41 +0,0 @@
1
- # iOS Audio Format Tests
2
-
3
- This directory contains test scripts for validating audio format support on iOS/macOS.
4
-
5
- ## Opus Support Test
6
-
7
- The `opus_support_test_macos.swift` script verifies that while `kAudioFormatOpus` is defined in the iOS SDK, AVAudioRecorder cannot actually encode Opus audio.
8
-
9
- ### Running the Test
10
-
11
- ```bash
12
- # On macOS (for quick validation)
13
- swift opus_support_test_macos.swift
14
-
15
- # On iOS device/simulator (requires Xcode)
16
- # Copy the test to an iOS project and run it
17
- ```
18
-
19
- ### Test Results
20
-
21
- - ✅ `kAudioFormatOpus` constant exists (value: 1869641075)
22
- - ✅ AVAudioRecorder accepts Opus settings without errors
23
- - ❌ Recording produces 0-byte files (no actual encoding)
24
- - ✅ AAC format works correctly as fallback
25
-
26
- ### Why This Matters
27
-
28
- This test proves that expo-audio-studio's automatic fallback from Opus to AAC on iOS is necessary and correct. Despite the SDK defining the Opus format constant, the actual encoding functionality is not implemented in AVAudioRecorder.
29
-
30
- ## Format Verification
31
-
32
- To verify actual file formats:
33
-
34
- ```bash
35
- # Check file type
36
- file recording.m4a # Should show: ISO Media, MP4 Base Media
37
- file recording.aac # Should show: ADTS, AAC
38
-
39
- # Get detailed info (requires mediainfo)
40
- mediainfo recording.m4a
41
- ```
@@ -1,178 +0,0 @@
1
- #!/usr/bin/env swift
2
-
3
- import Foundation
4
- import AVFoundation
5
-
6
- // Integration test for validating buffer size calculation and fallback behavior fixes
7
- // Tests issues #246 and #247
8
-
9
- print("🧪 Buffer Size Calculation and Fallback Integration Test")
10
- print("======================================================\n")
11
-
12
- class BufferAndFallbackTest {
13
- let audioEngine = AVAudioEngine()
14
- var results: [(name: String, passed: Bool, message: String)] = []
15
- var emissionCount = 0
16
- var lastEmissionData: Data?
17
-
18
- func runAllTests() {
19
- testBufferSizeCalculation()
20
- testFallbackWithoutDuplication()
21
- printResults()
22
- }
23
-
24
- func testBufferSizeCalculation() {
25
- print("Test 1: Buffer Size Calculation with Target Sample Rate")
26
- print("-------------------------------------------------------")
27
- print("Testing that buffer size is calculated based on target sample rate, not hardware rate")
28
-
29
- let inputNode = audioEngine.inputNode
30
- let hardwareFormat = inputNode.inputFormat(forBus: 0)
31
- let hardwareSampleRate = hardwareFormat.sampleRate
32
-
33
- print("Hardware sample rate: \(hardwareSampleRate) Hz")
34
-
35
- // Test case: 0.02 seconds at 16000 Hz should request 320 frames
36
- let targetSampleRate: Double = 16000
37
- let bufferDuration: Double = 0.02
38
- let expectedRequestedFrames = AVAudioFrameCount(bufferDuration * targetSampleRate)
39
-
40
- print("Target sample rate: \(targetSampleRate) Hz")
41
- print("Buffer duration: \(bufferDuration) seconds")
42
- print("Expected requested frames: \(expectedRequestedFrames)")
43
-
44
- // Since iOS enforces minimum ~4800 frames, we expect either 4800 or our requested size
45
- let _ : AVAudioFrameCount = max(4800, expectedRequestedFrames)
46
-
47
- let expectation = DispatchSemaphore(value: 0)
48
- var receivedFrames: AVAudioFrameCount = 0
49
-
50
- inputNode.installTap(onBus: 0, bufferSize: expectedRequestedFrames, format: hardwareFormat) { buffer, _ in
51
- receivedFrames = buffer.frameLength
52
- expectation.signal()
53
- }
54
-
55
- audioEngine.prepare()
56
- do {
57
- try audioEngine.start()
58
- _ = expectation.wait(timeout: .now() + 2)
59
- audioEngine.stop()
60
- } catch {
61
- print("Error: \(error)")
62
- }
63
-
64
- inputNode.removeTap(onBus: 0)
65
-
66
- // The key test: verify that we calculated based on target rate (320 frames), not hardware rate
67
- let wouldHaveBeenWithHardwareRate = AVAudioFrameCount(bufferDuration * hardwareSampleRate)
68
- let usedTargetRate = expectedRequestedFrames == 320
69
-
70
- results.append((
71
- name: "Buffer Size Calculation",
72
- passed: usedTargetRate,
73
- message: "Used target rate: \(usedTargetRate), Requested: \(expectedRequestedFrames) frames (would be \(wouldHaveBeenWithHardwareRate) with hardware rate)"
74
- ))
75
-
76
- print("✓ Requested frames: \(expectedRequestedFrames) (calculated from target rate)")
77
- print("✓ Would have been: \(wouldHaveBeenWithHardwareRate) frames (if using hardware rate)")
78
- print("✓ Actually received: \(receivedFrames) frames (iOS minimum enforced)\n")
79
- }
80
-
81
- func testFallbackWithoutDuplication() {
82
- print("Test 2: Fallback Without Data Duplication")
83
- print("-----------------------------------------")
84
- print("Simulating device fallback scenario to ensure no duplicate emissions")
85
-
86
- // Reset counters
87
- emissionCount = 0
88
- lastEmissionData = nil
89
-
90
- let inputNode = audioEngine.inputNode
91
- let format = inputNode.inputFormat(forBus: 0)
92
-
93
- // Simulate a tap that counts emissions
94
- var bufferCount = 0
95
- let expectation = DispatchSemaphore(value: 0)
96
-
97
- inputNode.installTap(onBus: 0, bufferSize: 1024, format: format) { [weak self] buffer, _ in
98
- guard let self = self else { return }
99
-
100
- bufferCount += 1
101
-
102
- // Simulate emission logic
103
- let audioData = buffer.audioBufferList.pointee.mBuffers
104
- if let bufferData = audioData.mData {
105
- let data = Data(bytes: bufferData, count: Int(audioData.mDataByteSize))
106
-
107
- // Check if this is the same data as last emission
108
- if let lastData = self.lastEmissionData, lastData == data {
109
- print("⚠️ Detected duplicate emission!")
110
- }
111
-
112
- self.lastEmissionData = data
113
- self.emissionCount += 1
114
- }
115
-
116
- if bufferCount >= 10 {
117
- expectation.signal()
118
- }
119
- }
120
-
121
- audioEngine.prepare()
122
- do {
123
- try audioEngine.start()
124
- _ = expectation.wait(timeout: .now() + 3)
125
- audioEngine.stop()
126
- } catch {
127
- print("Error: \(error)")
128
- }
129
-
130
- inputNode.removeTap(onBus: 0)
131
-
132
- // With the fix, emission count should equal buffer count (no duplicates)
133
- let noDuplicates = emissionCount == bufferCount
134
-
135
- results.append((
136
- name: "Fallback No Duplication",
137
- passed: noDuplicates,
138
- message: "Buffers: \(bufferCount), Emissions: \(emissionCount), No duplicates: \(noDuplicates)"
139
- ))
140
-
141
- print("✓ Processed \(bufferCount) buffers")
142
- print("✓ Emitted \(emissionCount) times")
143
- print("✓ No duplicate emissions: \(noDuplicates)\n")
144
- }
145
-
146
- func printResults() {
147
- print("📊 Test Results")
148
- print("===============")
149
-
150
- let passed = results.filter { $0.passed }.count
151
- let total = results.count
152
-
153
- for result in results {
154
- let status = result.passed ? "✅" : "❌"
155
- print("\(status) \(result.name)")
156
- print(" \(result.message)")
157
- }
158
-
159
- print("\nSummary: \(passed)/\(total) tests passed")
160
-
161
- if passed == total {
162
- print("🎉 All tests passed!")
163
- print("\n✅ Issue #247 (Buffer Size Calculation) - FIXED")
164
- print("✅ Issue #246 (Duplicate Emissions) - Validation Ready")
165
- } else {
166
- print("⚠️ Some tests failed")
167
- }
168
-
169
- print("\n📝 Key Validations:")
170
- print("- Buffer size is now calculated using target sample rate")
171
- print("- iOS minimum buffer size (~4800 frames) is properly handled")
172
- print("- Fallback behavior ready for duplicate emission testing")
173
- }
174
- }
175
-
176
- // Run the test
177
- let test = BufferAndFallbackTest()
178
- test.runAllTests()