@siteed/audio-studio 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.
- package/CHANGELOG.md +535 -0
- package/LICENSE +21 -0
- package/README.md +167 -0
- package/android/build.gradle +143 -0
- package/android/src/androidTest/assets/chorus.wav +0 -0
- package/android/src/androidTest/assets/jfk.wav +0 -0
- package/android/src/androidTest/assets/osr_us_000_0010_8k.wav +0 -0
- package/android/src/androidTest/assets/recorder_hello_world.wav +0 -0
- package/android/src/androidTest/java/net/siteed/audiostudio/AudioProcessorInstrumentedTest.kt +197 -0
- package/android/src/androidTest/java/net/siteed/audiostudio/AudioRecorderInstrumentedTest.kt +541 -0
- package/android/src/androidTest/java/net/siteed/audiostudio/AudioRecorderPerformanceInstrumentedTest.kt +234 -0
- package/android/src/androidTest/java/net/siteed/audiostudio/integration/AudioFocusStrategyIntegrationTest.kt +332 -0
- package/android/src/androidTest/java/net/siteed/audiostudio/integration/BufferDurationIntegrationTest.kt +324 -0
- package/android/src/androidTest/java/net/siteed/audiostudio/integration/CompressedOnlyOutputTest.kt +253 -0
- package/android/src/androidTest/java/net/siteed/audiostudio/integration/DeviceDisconnectionFallbackTest.kt +218 -0
- package/android/src/androidTest/java/net/siteed/audiostudio/integration/EventEmissionIntervalTest.kt +120 -0
- package/android/src/androidTest/java/net/siteed/audiostudio/integration/M4aFormatTest.kt +345 -0
- package/android/src/androidTest/java/net/siteed/audiostudio/integration/OutputControlIntegrationTest.kt +340 -0
- package/android/src/androidTest/java/net/siteed/audiostudio/integration/PcmStreamingDurationTest.kt +252 -0
- package/android/src/androidTest/java/net/siteed/audiostudio/integration/README.md +95 -0
- package/android/src/androidTest/java/net/siteed/audiostudio/integration/run_integration_tests.sh +43 -0
- package/android/src/main/AndroidManifest.xml +30 -0
- package/android/src/main/CMakeLists.txt +29 -0
- package/android/src/main/java/net/siteed/audiostudio/AudioAnalysisData.kt +188 -0
- package/android/src/main/java/net/siteed/audiostudio/AudioDataEncoder.kt +9 -0
- package/android/src/main/java/net/siteed/audiostudio/AudioDeviceManager.kt +1741 -0
- package/android/src/main/java/net/siteed/audiostudio/AudioFeaturesNative.kt +26 -0
- package/android/src/main/java/net/siteed/audiostudio/AudioFileHandler.kt +136 -0
- package/android/src/main/java/net/siteed/audiostudio/AudioFormatUtils.kt +354 -0
- package/android/src/main/java/net/siteed/audiostudio/AudioNotificationsManager.kt +439 -0
- package/android/src/main/java/net/siteed/audiostudio/AudioProcessor.kt +2237 -0
- package/android/src/main/java/net/siteed/audiostudio/AudioRecorderManager.kt +2163 -0
- package/android/src/main/java/net/siteed/audiostudio/AudioRecordingService.kt +167 -0
- package/android/src/main/java/net/siteed/audiostudio/AudioStudioModule.kt +1112 -0
- package/android/src/main/java/net/siteed/audiostudio/AudioTrimmer.kt +1099 -0
- package/android/src/main/java/net/siteed/audiostudio/Constants.kt +37 -0
- package/android/src/main/java/net/siteed/audiostudio/EventSender.kt +7 -0
- package/android/src/main/java/net/siteed/audiostudio/FFT.kt +100 -0
- package/android/src/main/java/net/siteed/audiostudio/Features.kt +98 -0
- package/android/src/main/java/net/siteed/audiostudio/LogUtils.kt +93 -0
- package/android/src/main/java/net/siteed/audiostudio/MelSpectrogramNative.kt +36 -0
- package/android/src/main/java/net/siteed/audiostudio/NotificationConfig.kt +72 -0
- package/android/src/main/java/net/siteed/audiostudio/PermissionUtils.kt +68 -0
- package/android/src/main/java/net/siteed/audiostudio/RecordingActionReceiver.kt +59 -0
- package/android/src/main/java/net/siteed/audiostudio/RecordingConfig.kt +259 -0
- package/android/src/main/java/net/siteed/audiostudio/WaveformConfig.kt +19 -0
- package/android/src/main/java/net/siteed/audiostudio/WaveformRenderer.kt +159 -0
- package/android/src/main/jni/AudioFeaturesJNI.cpp +152 -0
- package/android/src/main/jni/MelSpectrogramJNI.cpp +165 -0
- package/android/src/main/res/drawable/ic_default_action_icon.xml +16 -0
- package/android/src/main/res/drawable/ic_microphone.xml +13 -0
- package/android/src/main/res/drawable/ic_pause.xml +10 -0
- package/android/src/main/res/drawable/ic_play.xml +10 -0
- package/android/src/main/res/drawable/ic_stop.xml +10 -0
- package/android/src/main/res/layout/notification_recording.xml +37 -0
- package/android/src/test/java/net/siteed/audiostudio/AudioFileHandlerTest.kt +279 -0
- package/android/src/test/java/net/siteed/audiostudio/AudioFocusStrategyTest.kt +249 -0
- package/android/src/test/java/net/siteed/audiostudio/AudioFormatTest.kt +151 -0
- package/android/src/test/java/net/siteed/audiostudio/AudioFormatUtilsTest.kt +273 -0
- package/android/src/test/java/net/siteed/audiostudio/DeviceDisconnectionFallbackUnitTest.kt +140 -0
- package/android/src/test/resources/chorus.wav +0 -0
- package/android/src/test/resources/generate_test_audio.py +94 -0
- package/android/src/test/resources/jfk.wav +0 -0
- package/android/src/test/resources/osr_us_000_0010_8k.wav +0 -0
- package/android/src/test/resources/recorder_hello_world.wav +0 -0
- package/app.plugin.js +3 -0
- package/build/cjs/AudioAnalysis/AudioAnalysis.types.js +4 -0
- package/build/cjs/AudioAnalysis/AudioAnalysis.types.js.map +1 -0
- package/build/cjs/AudioAnalysis/audioFeaturesWasm.js +164 -0
- package/build/cjs/AudioAnalysis/audioFeaturesWasm.js.map +1 -0
- package/build/cjs/AudioAnalysis/extractAudioAnalysis.js +213 -0
- package/build/cjs/AudioAnalysis/extractAudioAnalysis.js.map +1 -0
- package/build/cjs/AudioAnalysis/extractAudioData.js +21 -0
- package/build/cjs/AudioAnalysis/extractAudioData.js.map +1 -0
- package/build/cjs/AudioAnalysis/extractMelSpectrogram.js +90 -0
- package/build/cjs/AudioAnalysis/extractMelSpectrogram.js.map +1 -0
- package/build/cjs/AudioAnalysis/extractPreview.js +28 -0
- package/build/cjs/AudioAnalysis/extractPreview.js.map +1 -0
- package/build/cjs/AudioAnalysis/extractWaveform.js +18 -0
- package/build/cjs/AudioAnalysis/extractWaveform.js.map +1 -0
- package/build/cjs/AudioAnalysis/melSpectrogramWasm.js +149 -0
- package/build/cjs/AudioAnalysis/melSpectrogramWasm.js.map +1 -0
- package/build/cjs/AudioDeviceManager.js +688 -0
- package/build/cjs/AudioDeviceManager.js.map +1 -0
- package/build/cjs/AudioRecorder.provider.js +78 -0
- package/build/cjs/AudioRecorder.provider.js.map +1 -0
- package/build/cjs/AudioStudio.native.js +8 -0
- package/build/cjs/AudioStudio.native.js.map +1 -0
- package/build/cjs/AudioStudio.types.js +11 -0
- package/build/cjs/AudioStudio.types.js.map +1 -0
- package/build/cjs/AudioStudio.web.js +708 -0
- package/build/cjs/AudioStudio.web.js.map +1 -0
- package/build/cjs/AudioStudioModule.js +718 -0
- package/build/cjs/AudioStudioModule.js.map +1 -0
- package/build/cjs/WebRecorder.web.js +865 -0
- package/build/cjs/WebRecorder.web.js.map +1 -0
- package/build/cjs/constants/platformLimitations.js +99 -0
- package/build/cjs/constants/platformLimitations.js.map +1 -0
- package/build/cjs/constants.js +20 -0
- package/build/cjs/constants.js.map +1 -0
- package/build/cjs/events.js +29 -0
- package/build/cjs/events.js.map +1 -0
- package/build/cjs/hooks/useAudioDevices.js +179 -0
- package/build/cjs/hooks/useAudioDevices.js.map +1 -0
- package/build/cjs/index.js +64 -0
- package/build/cjs/index.js.map +1 -0
- package/build/cjs/trimAudio.js +76 -0
- package/build/cjs/trimAudio.js.map +1 -0
- package/build/cjs/useAudioRecorder.js +535 -0
- package/build/cjs/useAudioRecorder.js.map +1 -0
- package/build/cjs/utils/BlobFix.js +502 -0
- package/build/cjs/utils/BlobFix.js.map +1 -0
- package/build/cjs/utils/audioProcessing.js +136 -0
- package/build/cjs/utils/audioProcessing.js.map +1 -0
- package/build/cjs/utils/cleanNativeOptions.js +22 -0
- package/build/cjs/utils/cleanNativeOptions.js.map +1 -0
- package/build/cjs/utils/concatenateBuffers.js +25 -0
- package/build/cjs/utils/concatenateBuffers.js.map +1 -0
- package/build/cjs/utils/convertPCMToFloat32.js +124 -0
- package/build/cjs/utils/convertPCMToFloat32.js.map +1 -0
- package/build/cjs/utils/crc32.js +52 -0
- package/build/cjs/utils/crc32.js.map +1 -0
- package/build/cjs/utils/encodingToBitDepth.js +17 -0
- package/build/cjs/utils/encodingToBitDepth.js.map +1 -0
- package/build/cjs/utils/getWavFileInfo.js +96 -0
- package/build/cjs/utils/getWavFileInfo.js.map +1 -0
- package/build/cjs/utils/writeWavHeader.js +88 -0
- package/build/cjs/utils/writeWavHeader.js.map +1 -0
- package/build/cjs/workers/InlineFeaturesExtractor.web.js +294 -0
- package/build/cjs/workers/InlineFeaturesExtractor.web.js.map +1 -0
- package/build/cjs/workers/inlineAudioWebWorker.web.js +190 -0
- package/build/cjs/workers/inlineAudioWebWorker.web.js.map +1 -0
- package/build/cjs/workers/wasmGlueString.web.js +27 -0
- package/build/cjs/workers/wasmGlueString.web.js.map +1 -0
- package/build/esm/AudioAnalysis/AudioAnalysis.types.js +3 -0
- package/build/esm/AudioAnalysis/AudioAnalysis.types.js.map +1 -0
- package/build/esm/AudioAnalysis/audioFeaturesWasm.js +126 -0
- package/build/esm/AudioAnalysis/audioFeaturesWasm.js.map +1 -0
- package/build/esm/AudioAnalysis/extractAudioAnalysis.js +205 -0
- package/build/esm/AudioAnalysis/extractAudioAnalysis.js.map +1 -0
- package/build/esm/AudioAnalysis/extractAudioData.js +14 -0
- package/build/esm/AudioAnalysis/extractAudioData.js.map +1 -0
- package/build/esm/AudioAnalysis/extractMelSpectrogram.js +86 -0
- package/build/esm/AudioAnalysis/extractMelSpectrogram.js.map +1 -0
- package/build/esm/AudioAnalysis/extractPreview.js +25 -0
- package/build/esm/AudioAnalysis/extractPreview.js.map +1 -0
- package/build/esm/AudioAnalysis/extractWaveform.js +11 -0
- package/build/esm/AudioAnalysis/extractWaveform.js.map +1 -0
- package/build/esm/AudioAnalysis/melSpectrogramWasm.js +111 -0
- package/build/esm/AudioAnalysis/melSpectrogramWasm.js.map +1 -0
- package/build/esm/AudioDeviceManager.js +681 -0
- package/build/esm/AudioDeviceManager.js.map +1 -0
- package/build/esm/AudioRecorder.provider.js +40 -0
- package/build/esm/AudioRecorder.provider.js.map +1 -0
- package/build/esm/AudioStudio.native.js +6 -0
- package/build/esm/AudioStudio.native.js.map +1 -0
- package/build/esm/AudioStudio.types.js +8 -0
- package/build/esm/AudioStudio.types.js.map +1 -0
- package/build/esm/AudioStudio.web.js +704 -0
- package/build/esm/AudioStudio.web.js.map +1 -0
- package/build/esm/AudioStudioModule.js +713 -0
- package/build/esm/AudioStudioModule.js.map +1 -0
- package/build/esm/WebRecorder.web.js +861 -0
- package/build/esm/WebRecorder.web.js.map +1 -0
- package/build/esm/constants/platformLimitations.js +90 -0
- package/build/esm/constants/platformLimitations.js.map +1 -0
- package/build/esm/constants.js +17 -0
- package/build/esm/constants.js.map +1 -0
- package/build/esm/events.js +21 -0
- package/build/esm/events.js.map +1 -0
- package/build/esm/hooks/useAudioDevices.js +176 -0
- package/build/esm/hooks/useAudioDevices.js.map +1 -0
- package/build/esm/index.js +23 -0
- package/build/esm/index.js.map +1 -0
- package/build/esm/trimAudio.js +69 -0
- package/build/esm/trimAudio.js.map +1 -0
- package/build/esm/useAudioRecorder.js +529 -0
- package/build/esm/useAudioRecorder.js.map +1 -0
- package/build/esm/utils/BlobFix.js +498 -0
- package/build/esm/utils/BlobFix.js.map +1 -0
- package/build/esm/utils/audioProcessing.js +133 -0
- package/build/esm/utils/audioProcessing.js.map +1 -0
- package/build/esm/utils/cleanNativeOptions.js +19 -0
- package/build/esm/utils/cleanNativeOptions.js.map +1 -0
- package/build/esm/utils/concatenateBuffers.js +21 -0
- package/build/esm/utils/concatenateBuffers.js.map +1 -0
- package/build/esm/utils/convertPCMToFloat32.js +120 -0
- package/build/esm/utils/convertPCMToFloat32.js.map +1 -0
- package/build/esm/utils/crc32.js +50 -0
- package/build/esm/utils/crc32.js.map +1 -0
- package/build/esm/utils/encodingToBitDepth.js +13 -0
- package/build/esm/utils/encodingToBitDepth.js.map +1 -0
- package/build/esm/utils/getWavFileInfo.js +92 -0
- package/build/esm/utils/getWavFileInfo.js.map +1 -0
- package/build/esm/utils/writeWavHeader.js +84 -0
- package/build/esm/utils/writeWavHeader.js.map +1 -0
- package/build/esm/workers/InlineFeaturesExtractor.web.js +291 -0
- package/build/esm/workers/InlineFeaturesExtractor.web.js.map +1 -0
- package/build/esm/workers/inlineAudioWebWorker.web.js +187 -0
- package/build/esm/workers/inlineAudioWebWorker.web.js.map +1 -0
- package/build/esm/workers/wasmGlueString.web.js +24 -0
- package/build/esm/workers/wasmGlueString.web.js.map +1 -0
- package/build/types/AudioAnalysis/AudioAnalysis.types.d.ts +198 -0
- package/build/types/AudioAnalysis/AudioAnalysis.types.d.ts.map +1 -0
- package/build/types/AudioAnalysis/audioFeaturesWasm.d.ts +24 -0
- package/build/types/AudioAnalysis/audioFeaturesWasm.d.ts.map +1 -0
- package/build/types/AudioAnalysis/extractAudioAnalysis.d.ts +74 -0
- package/build/types/AudioAnalysis/extractAudioAnalysis.d.ts.map +1 -0
- package/build/types/AudioAnalysis/extractAudioData.d.ts +3 -0
- package/build/types/AudioAnalysis/extractAudioData.d.ts.map +1 -0
- package/build/types/AudioAnalysis/extractMelSpectrogram.d.ts +20 -0
- package/build/types/AudioAnalysis/extractMelSpectrogram.d.ts.map +1 -0
- package/build/types/AudioAnalysis/extractPreview.d.ts +11 -0
- package/build/types/AudioAnalysis/extractPreview.d.ts.map +1 -0
- package/build/types/AudioAnalysis/extractWaveform.d.ts +8 -0
- package/build/types/AudioAnalysis/extractWaveform.d.ts.map +1 -0
- package/build/types/AudioAnalysis/melSpectrogramWasm.d.ts +16 -0
- package/build/types/AudioAnalysis/melSpectrogramWasm.d.ts.map +1 -0
- package/build/types/AudioDeviceManager.d.ts +187 -0
- package/build/types/AudioDeviceManager.d.ts.map +1 -0
- package/build/types/AudioRecorder.provider.d.ts +11 -0
- package/build/types/AudioRecorder.provider.d.ts.map +1 -0
- package/build/types/AudioStudio.native.d.ts +3 -0
- package/build/types/AudioStudio.native.d.ts.map +1 -0
- package/build/types/AudioStudio.types.d.ts +760 -0
- package/build/types/AudioStudio.types.d.ts.map +1 -0
- package/build/types/AudioStudio.web.d.ts +96 -0
- package/build/types/AudioStudio.web.d.ts.map +1 -0
- package/build/types/AudioStudioModule.d.ts +3 -0
- package/build/types/AudioStudioModule.d.ts.map +1 -0
- package/build/types/WebRecorder.web.d.ts +208 -0
- package/build/types/WebRecorder.web.d.ts.map +1 -0
- package/build/types/constants/platformLimitations.d.ts +40 -0
- package/build/types/constants/platformLimitations.d.ts.map +1 -0
- package/build/types/constants.d.ts +14 -0
- package/build/types/constants.d.ts.map +1 -0
- package/build/types/events.d.ts +29 -0
- package/build/types/events.d.ts.map +1 -0
- package/build/types/hooks/useAudioDevices.d.ts +15 -0
- package/build/types/hooks/useAudioDevices.d.ts.map +1 -0
- package/build/types/index.d.ts +21 -0
- package/build/types/index.d.ts.map +1 -0
- package/build/types/trimAudio.d.ts +25 -0
- package/build/types/trimAudio.d.ts.map +1 -0
- package/build/types/useAudioRecorder.d.ts +22 -0
- package/build/types/useAudioRecorder.d.ts.map +1 -0
- package/build/types/utils/BlobFix.d.ts +9 -0
- package/build/types/utils/BlobFix.d.ts.map +1 -0
- package/build/types/utils/audioProcessing.d.ts +24 -0
- package/build/types/utils/audioProcessing.d.ts.map +1 -0
- package/build/types/utils/cleanNativeOptions.d.ts +15 -0
- package/build/types/utils/cleanNativeOptions.d.ts.map +1 -0
- package/build/types/utils/concatenateBuffers.d.ts +8 -0
- package/build/types/utils/concatenateBuffers.d.ts.map +1 -0
- package/build/types/utils/convertPCMToFloat32.d.ts +13 -0
- package/build/types/utils/convertPCMToFloat32.d.ts.map +1 -0
- package/build/types/utils/crc32.d.ts +7 -0
- package/build/types/utils/crc32.d.ts.map +1 -0
- package/build/types/utils/encodingToBitDepth.d.ts +5 -0
- package/build/types/utils/encodingToBitDepth.d.ts.map +1 -0
- package/build/types/utils/getWavFileInfo.d.ts +26 -0
- package/build/types/utils/getWavFileInfo.d.ts.map +1 -0
- package/build/types/utils/writeWavHeader.d.ts +34 -0
- package/build/types/utils/writeWavHeader.d.ts.map +1 -0
- package/build/types/workers/InlineFeaturesExtractor.web.d.ts +2 -0
- package/build/types/workers/InlineFeaturesExtractor.web.d.ts.map +1 -0
- package/build/types/workers/inlineAudioWebWorker.web.d.ts +2 -0
- package/build/types/workers/inlineAudioWebWorker.web.d.ts.map +1 -0
- package/build/types/workers/wasmGlueString.web.d.ts +2 -0
- package/build/types/workers/wasmGlueString.web.d.ts.map +1 -0
- package/cpp/AudioFeatures.cpp +274 -0
- package/cpp/AudioFeatures.h +85 -0
- package/cpp/AudioFeaturesBridge.cpp +146 -0
- package/cpp/AudioFeaturesBridge.h +47 -0
- package/cpp/MelSpectrogram.cpp +227 -0
- package/cpp/MelSpectrogram.h +82 -0
- package/cpp/MelSpectrogramBridge.cpp +112 -0
- package/cpp/MelSpectrogramBridge.h +33 -0
- package/cpp/kiss_fft/COPYING +11 -0
- package/cpp/kiss_fft/_kiss_fft_guts.h +167 -0
- package/cpp/kiss_fft/kiss_fft.c +424 -0
- package/cpp/kiss_fft/kiss_fft.h +160 -0
- package/cpp/kiss_fft/kiss_fft_log.h +36 -0
- package/cpp/kiss_fft/kiss_fftr.c +155 -0
- package/cpp/kiss_fft/kiss_fftr.h +54 -0
- package/expo-module.config.json +10 -0
- package/ios/AudioAnalysisData.swift +74 -0
- package/ios/AudioDeviceManager.swift +670 -0
- package/ios/AudioFeaturesWrapper.h +21 -0
- package/ios/AudioFeaturesWrapper.mm +63 -0
- package/ios/AudioNotificationManager.swift +154 -0
- package/ios/AudioProcessingHelpers.swift +797 -0
- package/ios/AudioProcessor.swift +1191 -0
- package/ios/AudioStreamError.swift +7 -0
- package/ios/AudioStreamManager.swift +2369 -0
- package/ios/AudioStreamManagerDelegate.swift +16 -0
- package/ios/AudioStudio.podspec +39 -0
- package/ios/AudioStudioModule.swift +1111 -0
- package/ios/AudioStudioTests/AudioFileHandlerTests.swift +338 -0
- package/ios/AudioStudioTests/AudioFormatUtilsTests.swift +331 -0
- package/ios/AudioStudioTests/AudioTestHelpers.swift +130 -0
- package/ios/AudioStudioTests/CompressedOnlyOutputTests.swift +294 -0
- package/ios/AudioStudioTests/EventEmissionIntervalTests.swift +105 -0
- package/ios/AudioStudioTests/Info.plist +22 -0
- package/ios/AudioStudioTests/README.md +39 -0
- package/ios/AudioStudioTests/SimpleAudioTest.swift +98 -0
- package/ios/AudioStudioTests/TestAudioGenerator.swift +75 -0
- package/ios/DataPoint.swift +54 -0
- package/ios/DecodingConfig.swift +59 -0
- package/ios/FFT.swift +62 -0
- package/ios/Features.swift +95 -0
- package/ios/ISSUE_IOS.md +68 -0
- package/ios/Logger.swift +39 -0
- package/ios/MelSpectrogramWrapper.h +30 -0
- package/ios/MelSpectrogramWrapper.mm +97 -0
- package/ios/NotificationExtension.swift +15 -0
- package/ios/RecordingResult.swift +22 -0
- package/ios/RecordingSettings.swift +311 -0
- package/ios/WaveformExtractor.swift +105 -0
- package/ios/tests/README.md +41 -0
- package/ios/tests/integration/buffer_and_fallback_test.swift +178 -0
- package/ios/tests/integration/buffer_duration_test.swift +185 -0
- package/ios/tests/integration/compressed_only_output_test.swift +271 -0
- package/ios/tests/integration/output_control_test.swift +322 -0
- package/ios/tests/integration/run_integration_tests.sh +37 -0
- package/ios/tests/opus_support_test_macos.swift +154 -0
- package/ios/tests/standalone/audio_processing_test.swift +144 -0
- package/ios/tests/standalone/audio_recording_test.swift +277 -0
- package/ios/tests/standalone/audio_streaming_test.swift +249 -0
- package/ios/tests/standalone/standalone_test.swift +144 -0
- package/package.json +146 -0
- package/plugin/build/index.cjs +194 -0
- package/plugin/build/index.d.cts +22 -0
- package/plugin/build/index.js +194 -0
- package/plugin/src/index.ts +285 -0
- package/plugin/tsconfig.json +10 -0
- package/plugin/tsconfig.tsbuildinfo +1 -0
- package/prebuilt/wasm/mel-spectrogram.js +18 -0
- package/src/AudioAnalysis/AudioAnalysis.types.ts +226 -0
- package/src/AudioAnalysis/audio-features-wasm.d.ts +37 -0
- package/src/AudioAnalysis/audioFeaturesWasm.ts +200 -0
- package/src/AudioAnalysis/extractAudioAnalysis.ts +350 -0
- package/src/AudioAnalysis/extractAudioData.ts +17 -0
- package/src/AudioAnalysis/extractMelSpectrogram.ts +140 -0
- package/src/AudioAnalysis/extractPreview.ts +34 -0
- package/src/AudioAnalysis/extractWaveform.ts +22 -0
- package/src/AudioAnalysis/mel-spectrogram-wasm.d.ts +48 -0
- package/src/AudioAnalysis/melSpectrogramWasm.ts +179 -0
- package/src/AudioDeviceManager.ts +800 -0
- package/src/AudioRecorder.provider.tsx +57 -0
- package/src/AudioStudio.native.ts +6 -0
- package/src/AudioStudio.types.ts +899 -0
- package/src/AudioStudio.web.ts +911 -0
- package/src/AudioStudioModule.ts +984 -0
- package/src/WebRecorder.web.ts +1114 -0
- package/src/constants/platformLimitations.ts +118 -0
- package/src/constants.ts +21 -0
- package/src/events.ts +63 -0
- package/src/hooks/useAudioDevices.ts +213 -0
- package/src/index.ts +67 -0
- package/src/trimAudio.ts +94 -0
- package/src/types/crc-32.d.ts +9 -0
- package/src/useAudioRecorder.tsx +784 -0
- package/src/utils/BlobFix.ts +561 -0
- package/src/utils/audioProcessing.ts +205 -0
- package/src/utils/cleanNativeOptions.ts +18 -0
- package/src/utils/concatenateBuffers.ts +24 -0
- package/src/utils/convertPCMToFloat32.ts +170 -0
- package/src/utils/crc32.ts +59 -0
- package/src/utils/encodingToBitDepth.ts +18 -0
- package/src/utils/getWavFileInfo.ts +132 -0
- package/src/utils/writeWavHeader.ts +115 -0
- package/src/workers/InlineFeaturesExtractor.web.tsx +291 -0
- package/src/workers/inlineAudioWebWorker.web.tsx +186 -0
- package/src/workers/wasmGlueString.web.ts +23 -0
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
package net.siteed.audiostudio
|
|
2
|
+
|
|
3
|
+
import android.Manifest
|
|
4
|
+
import android.content.Context
|
|
5
|
+
import android.util.Log
|
|
6
|
+
import androidx.test.ext.junit.runners.AndroidJUnit4
|
|
7
|
+
import androidx.test.platform.app.InstrumentationRegistry
|
|
8
|
+
import androidx.test.rule.GrantPermissionRule
|
|
9
|
+
import expo.modules.kotlin.Promise
|
|
10
|
+
import org.junit.After
|
|
11
|
+
import org.junit.Assert.*
|
|
12
|
+
import org.junit.Before
|
|
13
|
+
import org.junit.Rule
|
|
14
|
+
import org.junit.Test
|
|
15
|
+
import org.junit.runner.RunWith
|
|
16
|
+
import java.io.File
|
|
17
|
+
import java.util.concurrent.CountDownLatch
|
|
18
|
+
import java.util.concurrent.TimeUnit
|
|
19
|
+
import kotlin.system.measureTimeMillis
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Performance tests for measuring stop recording times.
|
|
23
|
+
*/
|
|
24
|
+
@RunWith(AndroidJUnit4::class)
|
|
25
|
+
class AudioRecorderPerformanceInstrumentedTest {
|
|
26
|
+
|
|
27
|
+
@get:Rule
|
|
28
|
+
val grantPermissionRule: GrantPermissionRule = GrantPermissionRule.grant(
|
|
29
|
+
Manifest.permission.RECORD_AUDIO
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
private lateinit var context: Context
|
|
33
|
+
private lateinit var filesDir: File
|
|
34
|
+
private lateinit var audioRecorderManager: AudioRecorderManager
|
|
35
|
+
private lateinit var testEventSender: TestEventSender
|
|
36
|
+
private lateinit var permissionUtils: PermissionUtils
|
|
37
|
+
private lateinit var audioDataEncoder: AudioDataEncoder
|
|
38
|
+
|
|
39
|
+
companion object {
|
|
40
|
+
private const val TAG = "PerformanceTest"
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Test event sender to capture events
|
|
44
|
+
private class TestEventSender : EventSender {
|
|
45
|
+
override fun sendExpoEvent(eventName: String, params: android.os.Bundle) {
|
|
46
|
+
// No-op for performance tests
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
@Before
|
|
51
|
+
fun setUp() {
|
|
52
|
+
context = InstrumentationRegistry.getInstrumentation().targetContext
|
|
53
|
+
filesDir = context.filesDir
|
|
54
|
+
testEventSender = TestEventSender()
|
|
55
|
+
permissionUtils = PermissionUtils(context)
|
|
56
|
+
audioDataEncoder = AudioDataEncoder()
|
|
57
|
+
|
|
58
|
+
// Initialize AudioRecorderManager
|
|
59
|
+
audioRecorderManager = AudioRecorderManager.initialize(
|
|
60
|
+
context = context,
|
|
61
|
+
filesDir = filesDir,
|
|
62
|
+
permissionUtils = permissionUtils,
|
|
63
|
+
audioDataEncoder = audioDataEncoder,
|
|
64
|
+
eventSender = testEventSender,
|
|
65
|
+
enablePhoneStateHandling = false,
|
|
66
|
+
enableBackgroundAudio = false
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
// Clean up any existing audio files
|
|
70
|
+
cleanupAudioFiles()
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
@After
|
|
74
|
+
fun tearDown() {
|
|
75
|
+
// Stop any ongoing recording
|
|
76
|
+
if (audioRecorderManager.isRecording) {
|
|
77
|
+
val promise = object : Promise {
|
|
78
|
+
override fun resolve(value: Any?) {}
|
|
79
|
+
override fun reject(code: String, message: String?, cause: Throwable?) {}
|
|
80
|
+
}
|
|
81
|
+
audioRecorderManager.stopRecording(promise)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Clean up
|
|
85
|
+
AudioRecorderManager.destroy()
|
|
86
|
+
cleanupAudioFiles()
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
private fun cleanupAudioFiles() {
|
|
90
|
+
filesDir.listFiles()?.forEach { file ->
|
|
91
|
+
if (file.name.endsWith(".wav") || file.name.endsWith(".aac") || file.name.endsWith(".opus")) {
|
|
92
|
+
file.delete()
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
@Test
|
|
98
|
+
fun measureStopTime_5seconds() {
|
|
99
|
+
runPerformanceTest(5_000L, "5 second recording")
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
@Test
|
|
103
|
+
fun measureStopTime_30seconds() {
|
|
104
|
+
runPerformanceTest(30_000L, "30 second recording")
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
@Test
|
|
108
|
+
fun measureStopTime_1minute() {
|
|
109
|
+
runPerformanceTest(60_000L, "1 minute recording")
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
@Test
|
|
113
|
+
fun measureStopTime_2minutes() {
|
|
114
|
+
runPerformanceTest(120_000L, "2 minute recording")
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
@Test
|
|
118
|
+
fun measureStopTime_5minutes() {
|
|
119
|
+
runPerformanceTest(300_000L, "5 minute recording")
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
@Test
|
|
123
|
+
fun measureStopTime_10minutes() {
|
|
124
|
+
runPerformanceTest(600_000L, "10 minute recording")
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
@Test
|
|
128
|
+
fun measureStopTime_15minutes() {
|
|
129
|
+
runPerformanceTest(900_000L, "15 minute recording")
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
private fun runPerformanceTest(recordingDurationMs: Long, testName: String) {
|
|
133
|
+
val recordingOptions = mapOf(
|
|
134
|
+
"sampleRate" to 44100,
|
|
135
|
+
"channels" to 1,
|
|
136
|
+
"encoding" to "pcm_16bit",
|
|
137
|
+
"interval" to 1000,
|
|
138
|
+
"enableProcessing" to false,
|
|
139
|
+
"showNotification" to false,
|
|
140
|
+
"output" to mapOf(
|
|
141
|
+
"primary" to mapOf("enabled" to true),
|
|
142
|
+
"compressed" to mapOf("enabled" to false)
|
|
143
|
+
)
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
// Start recording
|
|
147
|
+
val startLatch = CountDownLatch(1)
|
|
148
|
+
audioRecorderManager.startRecording(recordingOptions, object : Promise {
|
|
149
|
+
override fun resolve(value: Any?) {
|
|
150
|
+
startLatch.countDown()
|
|
151
|
+
}
|
|
152
|
+
override fun reject(code: String, message: String?, cause: Throwable?) {
|
|
153
|
+
fail("Start recording failed: $message")
|
|
154
|
+
}
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
assertTrue("Recording should start", startLatch.await(5, TimeUnit.SECONDS))
|
|
158
|
+
assertTrue("Recording should be active", audioRecorderManager.isRecording)
|
|
159
|
+
|
|
160
|
+
// Record for specified duration
|
|
161
|
+
Thread.sleep(recordingDurationMs)
|
|
162
|
+
|
|
163
|
+
// Measure stop time
|
|
164
|
+
val stopLatch = CountDownLatch(1)
|
|
165
|
+
var fileSize = 0L
|
|
166
|
+
var stopResult: Map<String, Any>? = null
|
|
167
|
+
|
|
168
|
+
val stopDuration = measureTimeMillis {
|
|
169
|
+
audioRecorderManager.stopRecording(object : Promise {
|
|
170
|
+
override fun resolve(value: Any?) {
|
|
171
|
+
when (value) {
|
|
172
|
+
is android.os.Bundle -> {
|
|
173
|
+
fileSize = value.getLong("size", 0)
|
|
174
|
+
stopResult = bundleToMap(value)
|
|
175
|
+
}
|
|
176
|
+
is Map<*, *> -> {
|
|
177
|
+
@Suppress("UNCHECKED_CAST")
|
|
178
|
+
stopResult = value as? Map<String, Any>
|
|
179
|
+
fileSize = (stopResult?.get("size") as? Long) ?: 0
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
stopLatch.countDown()
|
|
183
|
+
}
|
|
184
|
+
override fun reject(code: String, message: String?, cause: Throwable?) {
|
|
185
|
+
fail("Stop recording failed: $message")
|
|
186
|
+
}
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
assertTrue("Stop should complete", stopLatch.await(10, TimeUnit.SECONDS))
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Log results
|
|
193
|
+
val fileSizeMB = fileSize / (1024.0 * 1024.0)
|
|
194
|
+
Log.i(TAG, """
|
|
195
|
+
Performance Test: $testName
|
|
196
|
+
- Recording Duration: ${recordingDurationMs}ms
|
|
197
|
+
- Stop Duration: ${stopDuration}ms
|
|
198
|
+
- File Size: ${"%.2f".format(fileSizeMB)}MB
|
|
199
|
+
- Performance: ${if (stopDuration < getTargetTime(recordingDurationMs)) "PASS" else "FAIL"}
|
|
200
|
+
""".trimIndent())
|
|
201
|
+
|
|
202
|
+
println("""
|
|
203
|
+
Performance Test: $testName
|
|
204
|
+
- Recording Duration: ${recordingDurationMs}ms
|
|
205
|
+
- Stop Duration: ${stopDuration}ms
|
|
206
|
+
- File Size: ${"%.2f".format(fileSizeMB)}MB
|
|
207
|
+
- Performance: ${if (stopDuration < getTargetTime(recordingDurationMs)) "PASS" else "FAIL"}
|
|
208
|
+
""".trimIndent())
|
|
209
|
+
|
|
210
|
+
assertFalse("Recording should not be active", audioRecorderManager.isRecording)
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
private fun getTargetTime(recordingDurationMs: Long): Long {
|
|
214
|
+
return when {
|
|
215
|
+
recordingDurationMs <= 5_000 -> 100
|
|
216
|
+
recordingDurationMs <= 30_000 -> 150
|
|
217
|
+
recordingDurationMs <= 60_000 -> 200
|
|
218
|
+
recordingDurationMs <= 300_000 -> 500
|
|
219
|
+
else -> 750
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
private fun bundleToMap(bundle: android.os.Bundle): Map<String, Any> {
|
|
224
|
+
val map = mutableMapOf<String, Any>()
|
|
225
|
+
for (key in bundle.keySet()) {
|
|
226
|
+
val value = bundle.get(key)
|
|
227
|
+
when (value) {
|
|
228
|
+
is android.os.Bundle -> map[key] = bundleToMap(value)
|
|
229
|
+
else -> value?.let { map[key] = it }
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return map
|
|
233
|
+
}
|
|
234
|
+
}
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
package net.siteed.audiostudio.integration
|
|
2
|
+
|
|
3
|
+
import android.media.AudioManager
|
|
4
|
+
import android.content.Context
|
|
5
|
+
import androidx.test.ext.junit.runners.AndroidJUnit4
|
|
6
|
+
import androidx.test.platform.app.InstrumentationRegistry
|
|
7
|
+
import org.junit.Test
|
|
8
|
+
import org.junit.Assert.*
|
|
9
|
+
import org.junit.Before
|
|
10
|
+
import org.junit.After
|
|
11
|
+
import org.junit.runner.RunWith
|
|
12
|
+
import net.siteed.audiostudio.RecordingConfig
|
|
13
|
+
import java.io.File
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Integration tests for audio focus strategy functionality.
|
|
17
|
+
* These tests run on actual Android devices/emulators to validate that
|
|
18
|
+
* audio focus strategies work correctly in real scenarios.
|
|
19
|
+
*/
|
|
20
|
+
@RunWith(AndroidJUnit4::class)
|
|
21
|
+
class AudioFocusStrategyIntegrationTest {
|
|
22
|
+
|
|
23
|
+
private lateinit var context: Context
|
|
24
|
+
private lateinit var audioManager: AudioManager
|
|
25
|
+
private lateinit var filesDir: File
|
|
26
|
+
|
|
27
|
+
@Before
|
|
28
|
+
fun setUp() {
|
|
29
|
+
context = InstrumentationRegistry.getInstrumentation().targetContext
|
|
30
|
+
audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
|
31
|
+
filesDir = context.filesDir
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@After
|
|
35
|
+
fun tearDown() {
|
|
36
|
+
// Clean up any test files
|
|
37
|
+
val testFiles = filesDir.listFiles { _, name ->
|
|
38
|
+
name.startsWith("test_audio_focus_")
|
|
39
|
+
}
|
|
40
|
+
testFiles?.forEach { it.delete() }
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
@Test
|
|
44
|
+
fun testRecordingConfigWithBackgroundStrategy() {
|
|
45
|
+
val options = mapOf(
|
|
46
|
+
"sampleRate" to 44100,
|
|
47
|
+
"channels" to 1,
|
|
48
|
+
"encoding" to "pcm_16bit",
|
|
49
|
+
"keepAwake" to true,
|
|
50
|
+
"autoResumeAfterInterruption" to true,
|
|
51
|
+
"android" to mapOf(
|
|
52
|
+
"audioFocusStrategy" to "background"
|
|
53
|
+
)
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
val result = RecordingConfig.fromMap(options)
|
|
57
|
+
assertTrue("Config creation should succeed", result.isSuccess)
|
|
58
|
+
|
|
59
|
+
val (config, audioFormat) = result.getOrThrow()
|
|
60
|
+
|
|
61
|
+
// Verify audio focus strategy configuration
|
|
62
|
+
assertEquals("Audio focus strategy should be background", "background", config.audioFocusStrategy)
|
|
63
|
+
assertTrue("keepAwake should be true for background recording", config.keepAwake)
|
|
64
|
+
assertTrue("autoResumeAfterInterruption should be true", config.autoResumeAfterInterruption)
|
|
65
|
+
|
|
66
|
+
// Verify audio format is properly configured
|
|
67
|
+
assertNotNull("Audio format should be created", audioFormat)
|
|
68
|
+
assertEquals("MIME type should be audio/wav", "audio/wav", audioFormat.mimeType)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
@Test
|
|
72
|
+
fun testRecordingConfigWithInteractiveStrategy() {
|
|
73
|
+
val options = mapOf(
|
|
74
|
+
"sampleRate" to 44100,
|
|
75
|
+
"channels" to 1,
|
|
76
|
+
"encoding" to "pcm_16bit",
|
|
77
|
+
"keepAwake" to false,
|
|
78
|
+
"autoResumeAfterInterruption" to true,
|
|
79
|
+
"android" to mapOf(
|
|
80
|
+
"audioFocusStrategy" to "interactive"
|
|
81
|
+
)
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
val result = RecordingConfig.fromMap(options)
|
|
85
|
+
assertTrue("Config creation should succeed", result.isSuccess)
|
|
86
|
+
|
|
87
|
+
val (config, audioFormat) = result.getOrThrow()
|
|
88
|
+
|
|
89
|
+
// Verify audio focus strategy configuration
|
|
90
|
+
assertEquals("Audio focus strategy should be interactive", "interactive", config.audioFocusStrategy)
|
|
91
|
+
assertFalse("keepAwake should be false for interactive recording", config.keepAwake)
|
|
92
|
+
assertTrue("autoResumeAfterInterruption should be true", config.autoResumeAfterInterruption)
|
|
93
|
+
|
|
94
|
+
// Verify audio format is properly configured
|
|
95
|
+
assertNotNull("Audio format should be created", audioFormat)
|
|
96
|
+
assertEquals("MIME type should be audio/wav", "audio/wav", audioFormat.mimeType)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
@Test
|
|
100
|
+
fun testRecordingConfigWithCommunicationStrategy() {
|
|
101
|
+
val options = mapOf(
|
|
102
|
+
"sampleRate" to 16000, // Common speech sample rate
|
|
103
|
+
"channels" to 1,
|
|
104
|
+
"encoding" to "pcm_16bit",
|
|
105
|
+
"keepAwake" to false,
|
|
106
|
+
"autoResumeAfterInterruption" to true,
|
|
107
|
+
"android" to mapOf(
|
|
108
|
+
"audioFocusStrategy" to "communication"
|
|
109
|
+
)
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
val result = RecordingConfig.fromMap(options)
|
|
113
|
+
assertTrue("Config creation should succeed", result.isSuccess)
|
|
114
|
+
|
|
115
|
+
val (config, audioFormat) = result.getOrThrow()
|
|
116
|
+
|
|
117
|
+
// Verify audio focus strategy configuration
|
|
118
|
+
assertEquals("Audio focus strategy should be communication", "communication", config.audioFocusStrategy)
|
|
119
|
+
assertEquals("Sample rate should be 16000 for speech", 16000, config.sampleRate)
|
|
120
|
+
assertFalse("keepAwake should be false", config.keepAwake)
|
|
121
|
+
assertTrue("autoResumeAfterInterruption should be true", config.autoResumeAfterInterruption)
|
|
122
|
+
|
|
123
|
+
// Verify audio format is properly configured
|
|
124
|
+
assertNotNull("Audio format should be created", audioFormat)
|
|
125
|
+
assertEquals("MIME type should be audio/wav", "audio/wav", audioFormat.mimeType)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
@Test
|
|
129
|
+
fun testRecordingConfigWithNoneStrategy() {
|
|
130
|
+
val options = mapOf(
|
|
131
|
+
"sampleRate" to 44100,
|
|
132
|
+
"channels" to 1,
|
|
133
|
+
"encoding" to "pcm_16bit",
|
|
134
|
+
"keepAwake" to false,
|
|
135
|
+
"android" to mapOf(
|
|
136
|
+
"audioFocusStrategy" to "none"
|
|
137
|
+
)
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
val result = RecordingConfig.fromMap(options)
|
|
141
|
+
assertTrue("Config creation should succeed", result.isSuccess)
|
|
142
|
+
|
|
143
|
+
val (config, audioFormat) = result.getOrThrow()
|
|
144
|
+
|
|
145
|
+
// Verify audio focus strategy configuration
|
|
146
|
+
assertEquals("Audio focus strategy should be none", "none", config.audioFocusStrategy)
|
|
147
|
+
|
|
148
|
+
// Verify audio format is properly configured
|
|
149
|
+
assertNotNull("Audio format should be created", audioFormat)
|
|
150
|
+
assertEquals("MIME type should be audio/wav", "audio/wav", audioFormat.mimeType)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
@Test
|
|
154
|
+
fun testStrategyOverrideBehavior() {
|
|
155
|
+
val options = mapOf(
|
|
156
|
+
"sampleRate" to 44100,
|
|
157
|
+
"channels" to 1,
|
|
158
|
+
"encoding" to "pcm_16bit",
|
|
159
|
+
"keepAwake" to true, // This would normally default to background
|
|
160
|
+
"android" to mapOf(
|
|
161
|
+
"audioFocusStrategy" to "communication" // But we override to communication
|
|
162
|
+
)
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
val result = RecordingConfig.fromMap(options)
|
|
166
|
+
assertTrue("Config creation should succeed", result.isSuccess)
|
|
167
|
+
|
|
168
|
+
val (config, audioFormat) = result.getOrThrow()
|
|
169
|
+
|
|
170
|
+
// Verify that explicit strategy overrides keepAwake defaults
|
|
171
|
+
assertEquals("Audio focus strategy should be communication (overriding keepAwake default)", "communication", config.audioFocusStrategy)
|
|
172
|
+
assertTrue("keepAwake should still be true", config.keepAwake)
|
|
173
|
+
|
|
174
|
+
// Verify audio format is properly configured
|
|
175
|
+
assertNotNull("Audio format should be created", audioFormat)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
@Test
|
|
179
|
+
fun testAudioFocusStrategyWithCompression() {
|
|
180
|
+
val options = mapOf(
|
|
181
|
+
"sampleRate" to 44100,
|
|
182
|
+
"channels" to 1,
|
|
183
|
+
"encoding" to "pcm_16bit",
|
|
184
|
+
"android" to mapOf(
|
|
185
|
+
"audioFocusStrategy" to "background"
|
|
186
|
+
),
|
|
187
|
+
"output" to mapOf(
|
|
188
|
+
"compressed" to mapOf(
|
|
189
|
+
"enabled" to true,
|
|
190
|
+
"format" to "aac",
|
|
191
|
+
"bitrate" to 128000
|
|
192
|
+
)
|
|
193
|
+
)
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
val result = RecordingConfig.fromMap(options)
|
|
197
|
+
assertTrue("Config creation should succeed", result.isSuccess)
|
|
198
|
+
|
|
199
|
+
val (config, audioFormat) = result.getOrThrow()
|
|
200
|
+
|
|
201
|
+
// Verify audio focus strategy works with compression
|
|
202
|
+
assertEquals("Audio focus strategy should be background", "background", config.audioFocusStrategy)
|
|
203
|
+
assertTrue("Compressed output should be enabled", config.output.compressed.enabled)
|
|
204
|
+
assertEquals("Compression format should be aac", "aac", config.output.compressed.format)
|
|
205
|
+
assertEquals("Bitrate should be 128000", 128000, config.output.compressed.bitrate)
|
|
206
|
+
|
|
207
|
+
// Verify audio format is properly configured
|
|
208
|
+
assertNotNull("Audio format should be created", audioFormat)
|
|
209
|
+
assertEquals("MIME type should be audio/wav", "audio/wav", audioFormat.mimeType)
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
@Test
|
|
213
|
+
fun testAudioFocusStrategyWithNotifications() {
|
|
214
|
+
val options = mapOf(
|
|
215
|
+
"sampleRate" to 44100,
|
|
216
|
+
"channels" to 1,
|
|
217
|
+
"encoding" to "pcm_16bit",
|
|
218
|
+
"showNotification" to true,
|
|
219
|
+
"showWaveformInNotification" to true,
|
|
220
|
+
"android" to mapOf(
|
|
221
|
+
"audioFocusStrategy" to "background"
|
|
222
|
+
),
|
|
223
|
+
"notification" to mapOf(
|
|
224
|
+
"title" to "Recording Audio",
|
|
225
|
+
"text" to "Background recording in progress",
|
|
226
|
+
"icon" to "ic_mic"
|
|
227
|
+
)
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
val result = RecordingConfig.fromMap(options)
|
|
231
|
+
assertTrue("Config creation should succeed", result.isSuccess)
|
|
232
|
+
|
|
233
|
+
val (config, audioFormat) = result.getOrThrow()
|
|
234
|
+
|
|
235
|
+
// Verify audio focus strategy works with notifications
|
|
236
|
+
assertEquals("Audio focus strategy should be background", "background", config.audioFocusStrategy)
|
|
237
|
+
assertTrue("Notifications should be enabled", config.showNotification)
|
|
238
|
+
assertTrue("Waveform in notification should be enabled", config.showWaveformInNotification)
|
|
239
|
+
assertEquals("Notification title should match", "Recording Audio", config.notification.title)
|
|
240
|
+
assertEquals("Notification text should match", "Background recording in progress", config.notification.text)
|
|
241
|
+
assertEquals("Notification icon should match", "ic_mic", config.notification.icon)
|
|
242
|
+
|
|
243
|
+
// Verify audio format is properly configured
|
|
244
|
+
assertNotNull("Audio format should be created", audioFormat)
|
|
245
|
+
assertEquals("MIME type should be audio/wav", "audio/wav", audioFormat.mimeType)
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
@Test
|
|
249
|
+
fun testAudioFocusStrategyValidation() {
|
|
250
|
+
// Test all valid strategies
|
|
251
|
+
val strategies = listOf("background", "interactive", "communication", "none")
|
|
252
|
+
|
|
253
|
+
for (strategy in strategies) {
|
|
254
|
+
val options = mapOf(
|
|
255
|
+
"sampleRate" to 44100,
|
|
256
|
+
"channels" to 1,
|
|
257
|
+
"encoding" to "pcm_16bit",
|
|
258
|
+
"android" to mapOf(
|
|
259
|
+
"audioFocusStrategy" to strategy
|
|
260
|
+
)
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
val result = RecordingConfig.fromMap(options)
|
|
264
|
+
assertTrue("Config creation should succeed for strategy: $strategy", result.isSuccess)
|
|
265
|
+
|
|
266
|
+
val (config, _) = result.getOrThrow()
|
|
267
|
+
assertEquals("Audio focus strategy should be $strategy", strategy, config.audioFocusStrategy)
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
@Test
|
|
272
|
+
fun testInvalidAudioFocusStrategyHandling() {
|
|
273
|
+
val options = mapOf(
|
|
274
|
+
"sampleRate" to 44100,
|
|
275
|
+
"channels" to 1,
|
|
276
|
+
"encoding" to "pcm_16bit",
|
|
277
|
+
"android" to mapOf(
|
|
278
|
+
"audioFocusStrategy" to "invalid_strategy"
|
|
279
|
+
)
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
val result = RecordingConfig.fromMap(options)
|
|
283
|
+
assertTrue("Config creation should succeed even with invalid strategy", result.isSuccess)
|
|
284
|
+
|
|
285
|
+
val (config, _) = result.getOrThrow()
|
|
286
|
+
assertEquals("Invalid strategy should be preserved", "invalid_strategy", config.audioFocusStrategy)
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
@Test
|
|
290
|
+
fun testCompleteAudioFocusConfiguration() {
|
|
291
|
+
val options = mapOf(
|
|
292
|
+
"sampleRate" to 44100,
|
|
293
|
+
"channels" to 1,
|
|
294
|
+
"encoding" to "pcm_16bit",
|
|
295
|
+
"keepAwake" to true,
|
|
296
|
+
"autoResumeAfterInterruption" to true,
|
|
297
|
+
"showNotification" to true,
|
|
298
|
+
"showWaveformInNotification" to false,
|
|
299
|
+
"enableProcessing" to false,
|
|
300
|
+
"android" to mapOf(
|
|
301
|
+
"audioFocusStrategy" to "communication"
|
|
302
|
+
),
|
|
303
|
+
"notification" to mapOf(
|
|
304
|
+
"title" to "Voice Call Recording",
|
|
305
|
+
"text" to "Call in progress",
|
|
306
|
+
"icon" to "ic_call"
|
|
307
|
+
)
|
|
308
|
+
)
|
|
309
|
+
|
|
310
|
+
val result = RecordingConfig.fromMap(options)
|
|
311
|
+
assertTrue("Config creation should succeed", result.isSuccess)
|
|
312
|
+
|
|
313
|
+
val (config, audioFormat) = result.getOrThrow()
|
|
314
|
+
|
|
315
|
+
// Verify complete configuration
|
|
316
|
+
assertEquals("Audio focus strategy should be communication", "communication", config.audioFocusStrategy)
|
|
317
|
+
assertEquals("Sample rate should be 44100", 44100, config.sampleRate)
|
|
318
|
+
assertEquals("Channels should be 1", 1, config.channels)
|
|
319
|
+
assertEquals("Encoding should be pcm_16bit", "pcm_16bit", config.encoding)
|
|
320
|
+
assertTrue("keepAwake should be true", config.keepAwake)
|
|
321
|
+
assertFalse("showWaveformInNotification should be false", config.showWaveformInNotification)
|
|
322
|
+
assertTrue("showNotification should be true", config.showNotification)
|
|
323
|
+
assertTrue("autoResumeAfterInterruption should be true", config.autoResumeAfterInterruption)
|
|
324
|
+
assertFalse("enableProcessing should be false", config.enableProcessing)
|
|
325
|
+
assertEquals("Notification title should match", "Voice Call Recording", config.notification.title)
|
|
326
|
+
assertEquals("Notification text should match", "Call in progress", config.notification.text)
|
|
327
|
+
|
|
328
|
+
// Verify audio format is properly configured
|
|
329
|
+
assertNotNull("Audio format should be created", audioFormat)
|
|
330
|
+
assertEquals("MIME type should be audio/wav", "audio/wav", audioFormat.mimeType)
|
|
331
|
+
}
|
|
332
|
+
}
|