@siteed/expo-audio-studio 2.4.1 → 2.5.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 (80) hide show
  1. package/CHANGELOG.md +10 -1
  2. package/README.md +25 -0
  3. package/android/src/main/java/net/siteed/audiostream/AudioAnalysisData.kt +22 -0
  4. package/android/src/main/java/net/siteed/audiostream/AudioDeviceManager.kt +1501 -0
  5. package/android/src/main/java/net/siteed/audiostream/AudioFileHandler.kt +10 -5
  6. package/android/src/main/java/net/siteed/audiostream/AudioNotificationsManager.kt +27 -25
  7. package/android/src/main/java/net/siteed/audiostream/AudioProcessor.kt +73 -71
  8. package/android/src/main/java/net/siteed/audiostream/AudioRecorderManager.kt +576 -252
  9. package/android/src/main/java/net/siteed/audiostream/Constants.kt +17 -1
  10. package/android/src/main/java/net/siteed/audiostream/ExpoAudioStreamModule.kt +419 -155
  11. package/android/src/main/java/net/siteed/audiostream/LogUtils.kt +65 -0
  12. package/android/src/main/java/net/siteed/audiostream/RecordingConfig.kt +9 -1
  13. package/build/AudioAnalysis/AudioAnalysis.types.js.map +1 -1
  14. package/build/AudioDeviceManager.d.ts +107 -0
  15. package/build/AudioDeviceManager.d.ts.map +1 -0
  16. package/build/AudioDeviceManager.js +493 -0
  17. package/build/AudioDeviceManager.js.map +1 -0
  18. package/build/AudioRecorder.provider.d.ts.map +1 -1
  19. package/build/AudioRecorder.provider.js +3 -0
  20. package/build/AudioRecorder.provider.js.map +1 -1
  21. package/build/ExpoAudioStream.types.d.ts +90 -1
  22. package/build/ExpoAudioStream.types.d.ts.map +1 -1
  23. package/build/ExpoAudioStream.types.js +7 -1
  24. package/build/ExpoAudioStream.types.js.map +1 -1
  25. package/build/ExpoAudioStream.web.d.ts +37 -0
  26. package/build/ExpoAudioStream.web.d.ts.map +1 -1
  27. package/build/ExpoAudioStream.web.js +399 -54
  28. package/build/ExpoAudioStream.web.js.map +1 -1
  29. package/build/ExpoAudioStreamModule.d.ts.map +1 -1
  30. package/build/ExpoAudioStreamModule.js +20 -0
  31. package/build/ExpoAudioStreamModule.js.map +1 -1
  32. package/build/WebRecorder.web.d.ts +63 -10
  33. package/build/WebRecorder.web.d.ts.map +1 -1
  34. package/build/WebRecorder.web.js +277 -68
  35. package/build/WebRecorder.web.js.map +1 -1
  36. package/build/hooks/useAudioDevices.d.ts +14 -0
  37. package/build/hooks/useAudioDevices.d.ts.map +1 -0
  38. package/build/hooks/useAudioDevices.js +151 -0
  39. package/build/hooks/useAudioDevices.js.map +1 -0
  40. package/build/index.d.ts +2 -0
  41. package/build/index.d.ts.map +1 -1
  42. package/build/index.js +4 -0
  43. package/build/index.js.map +1 -1
  44. package/build/useAudioRecorder.d.ts +1 -0
  45. package/build/useAudioRecorder.d.ts.map +1 -1
  46. package/build/useAudioRecorder.js +20 -1
  47. package/build/useAudioRecorder.js.map +1 -1
  48. package/build/utils/BlobFix.d.ts.map +1 -1
  49. package/build/utils/BlobFix.js +2 -2
  50. package/build/utils/BlobFix.js.map +1 -1
  51. package/build/workers/InlineFeaturesExtractor.web.d.ts +1 -1
  52. package/build/workers/InlineFeaturesExtractor.web.d.ts.map +1 -1
  53. package/build/workers/InlineFeaturesExtractor.web.js +27 -26
  54. package/build/workers/InlineFeaturesExtractor.web.js.map +1 -1
  55. package/build/workers/inlineAudioWebWorker.web.d.ts +1 -1
  56. package/build/workers/inlineAudioWebWorker.web.d.ts.map +1 -1
  57. package/build/workers/inlineAudioWebWorker.web.js +25 -1
  58. package/build/workers/inlineAudioWebWorker.web.js.map +1 -1
  59. package/ios/AudioDeviceManager.swift +654 -0
  60. package/ios/AudioStreamManager.swift +964 -760
  61. package/ios/ExpoAudioStreamModule.swift +174 -19
  62. package/ios/Features.swift +1 -1
  63. package/ios/ISSUE_IOS.md +45 -0
  64. package/ios/Logger.swift +13 -1
  65. package/ios/RecordingSettings.swift +12 -0
  66. package/package.json +2 -2
  67. package/src/AudioAnalysis/AudioAnalysis.types.ts +2 -2
  68. package/src/AudioDeviceManager.ts +571 -0
  69. package/src/AudioRecorder.provider.tsx +3 -0
  70. package/src/ExpoAudioStream.types.ts +97 -1
  71. package/src/ExpoAudioStream.web.ts +513 -63
  72. package/src/ExpoAudioStreamModule.ts +23 -0
  73. package/src/WebRecorder.web.ts +346 -81
  74. package/src/hooks/useAudioDevices.ts +180 -0
  75. package/src/index.ts +6 -0
  76. package/src/types/crc-32.d.ts +6 -6
  77. package/src/useAudioRecorder.tsx +27 -1
  78. package/src/utils/BlobFix.ts +6 -4
  79. package/src/workers/InlineFeaturesExtractor.web.tsx +27 -26
  80. package/src/workers/inlineAudioWebWorker.web.tsx +25 -1
@@ -1 +1 @@
1
- {"version":3,"file":"WebRecorder.web.js","sourceRoot":"","sources":["../src/WebRecorder.web.ts"],"names":[],"mappings":"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","sourcesContent":["// packages/expo-audio-stream/src/WebRecorder.web.ts\n\nimport { AudioAnalysis } from './AudioAnalysis/AudioAnalysis.types'\nimport { ConsoleLike, RecordingConfig } from './ExpoAudioStream.types'\nimport {\n EmitAudioAnalysisFunction,\n EmitAudioEventFunction,\n} from './ExpoAudioStream.web'\nimport { encodingToBitDepth } from './utils/encodingToBitDepth'\nimport { InlineFeaturesExtractor } from './workers/InlineFeaturesExtractor.web'\nimport { InlineAudioWebWorker } from './workers/inlineAudioWebWorker.web'\n\ninterface AudioWorkletEvent {\n data: {\n command: string\n recordedData?: Float32Array\n sampleRate?: number\n }\n}\n\ninterface AudioFeaturesEvent {\n data: {\n command: string\n result: AudioAnalysis\n }\n}\n\nconst DEFAULT_WEB_BITDEPTH = 32\nconst DEFAULT_SEGMENT_DURATION_MS = 100\nconst DEFAULT_WEB_INTERVAL = 500\nconst DEFAULT_WEB_NUMBER_OF_CHANNELS = 1\n\nconst TAG = 'WebRecorder'\n\nexport class WebRecorder {\n private audioContext: AudioContext\n private audioWorkletNode!: AudioWorkletNode\n private featureExtractorWorker?: Worker\n private source: MediaStreamAudioSourceNode\n private emitAudioEventCallback: EmitAudioEventFunction\n private emitAudioAnalysisCallback: EmitAudioAnalysisFunction\n private config: RecordingConfig\n private position: number = 0\n private numberOfChannels: number // Number of audio channels\n private bitDepth: number // Bit depth of the audio\n private exportBitDepth: number // Bit depth of the audio\n private audioAnalysisData: AudioAnalysis // Keep updating the full audio analysis data with latest events\n private packetCount: number = 0\n private logger?: ConsoleLike\n private compressedMediaRecorder: MediaRecorder | null = null\n private compressedChunks: Blob[] = []\n private compressedSize: number = 0\n private pendingCompressedChunk: Blob | null = null\n private readonly wavMimeType = 'audio/wav'\n private dataPointIdCounter: number = 0 // Add this property to track the counter\n\n /**\n * Initializes a new WebRecorder instance for audio recording and processing\n * @param audioContext - The AudioContext to use for recording\n * @param source - The MediaStreamAudioSourceNode providing the audio input\n * @param recordingConfig - Configuration options for the recording\n * @param emitAudioEventCallback - Callback function for audio data events\n * @param emitAudioAnalysisCallback - Callback function for audio analysis events\n * @param logger - Optional logger for debugging information\n */\n constructor({\n audioContext,\n source,\n recordingConfig,\n emitAudioEventCallback,\n emitAudioAnalysisCallback,\n logger,\n }: {\n audioContext: AudioContext\n source: MediaStreamAudioSourceNode\n recordingConfig: RecordingConfig\n emitAudioEventCallback: EmitAudioEventFunction\n emitAudioAnalysisCallback: EmitAudioAnalysisFunction\n logger?: ConsoleLike\n }) {\n this.audioContext = audioContext\n this.source = source\n this.emitAudioEventCallback = emitAudioEventCallback\n this.emitAudioAnalysisCallback = emitAudioAnalysisCallback\n this.config = recordingConfig\n this.logger = logger\n\n const audioContextFormat = this.checkAudioContextFormat({\n sampleRate: this.audioContext.sampleRate,\n })\n this.logger?.debug('Initialized WebRecorder with config:', {\n sampleRate: audioContextFormat.sampleRate,\n bitDepth: audioContextFormat.bitDepth,\n numberOfChannels: audioContextFormat.numberOfChannels,\n })\n\n this.bitDepth = audioContextFormat.bitDepth\n this.numberOfChannels =\n audioContextFormat.numberOfChannels ||\n DEFAULT_WEB_NUMBER_OF_CHANNELS // Default to 1 if not available\n this.exportBitDepth =\n encodingToBitDepth({\n encoding: recordingConfig.encoding ?? 'pcm_32bit',\n }) ||\n audioContextFormat.bitDepth ||\n DEFAULT_WEB_BITDEPTH\n\n this.audioAnalysisData = {\n amplitudeRange: { min: 0, max: 0 },\n rmsRange: { min: 0, max: 0 },\n dataPoints: [],\n durationMs: 0,\n samples: 0,\n bitDepth: this.bitDepth,\n numberOfChannels: this.numberOfChannels,\n sampleRate: this.config.sampleRate || this.audioContext.sampleRate,\n segmentDurationMs:\n this.config.segmentDurationMs ?? DEFAULT_SEGMENT_DURATION_MS, // Default to 100ms segments\n }\n\n if (recordingConfig.enableProcessing) {\n this.initFeatureExtractorWorker()\n }\n\n // Initialize compressed recording if enabled\n if (recordingConfig.compression?.enabled) {\n this.initializeCompressedRecorder()\n }\n }\n\n /**\n * Initializes the audio worklet using an inline script\n * Creates and connects the audio processing pipeline\n */\n async init() {\n try {\n // Create and use inline audio worklet\n const blob = new Blob([InlineAudioWebWorker], {\n type: 'application/javascript',\n })\n const url = URL.createObjectURL(blob)\n await this.audioContext.audioWorklet.addModule(url)\n\n this.audioWorkletNode = new AudioWorkletNode(\n this.audioContext,\n 'recorder-processor'\n )\n\n this.audioWorkletNode.port.onmessage = async (\n event: AudioWorkletEvent\n ) => {\n const command = event.data.command\n if (command !== 'newData') return\n\n const pcmBufferFloat = event.data.recordedData\n if (!pcmBufferFloat) {\n this.logger?.warn('Received empty audio buffer', event)\n return\n }\n\n // Process data in smaller chunks and emit immediately\n const chunkSize = this.audioContext.sampleRate * 2 // Reduce to 2 seconds chunks\n const sampleRate =\n event.data.sampleRate ?? this.audioContext.sampleRate\n const duration = pcmBufferFloat.length / sampleRate\n\n // Calculate bytes per sample based on bit depth\n const bytesPerSample = this.bitDepth / 8\n\n // Emit chunks without storing them\n for (let i = 0; i < pcmBufferFloat.length; i += chunkSize) {\n const chunk = pcmBufferFloat.slice(i, i + chunkSize)\n const chunkPosition = this.position + i / sampleRate\n\n // Calculate byte positions and samples\n const startPosition = Math.floor(i * bytesPerSample)\n const endPosition = Math.floor(\n (i + chunk.length) * bytesPerSample\n )\n const samples = chunk.length // Number of samples in this chunk\n\n // Process features if enabled\n if (\n this.config.enableProcessing &&\n this.featureExtractorWorker\n ) {\n this.featureExtractorWorker.postMessage({\n command: 'process',\n channelData: chunk,\n sampleRate,\n segmentDurationMs:\n this.config.segmentDurationMs ??\n DEFAULT_SEGMENT_DURATION_MS, // Default to 100ms\n bitDepth: this.bitDepth,\n fullAudioDurationMs: chunkPosition * 1000,\n numberOfChannels: this.numberOfChannels,\n features: this.config.features,\n intervalAnalysis: this.config.intervalAnalysis,\n startPosition,\n endPosition,\n samples,\n })\n }\n\n // Emit chunk immediately\n this.emitAudioEventCallback({\n data: chunk,\n position: chunkPosition,\n compression: this.pendingCompressedChunk\n ? {\n data: this.pendingCompressedChunk,\n size: this.pendingCompressedChunk.size,\n totalSize: this.compressedSize,\n mimeType: 'audio/webm',\n format: 'opus',\n bitrate:\n this.config.compression?.bitrate ??\n 128000,\n }\n : undefined,\n })\n }\n\n this.position += duration\n this.pendingCompressedChunk = null\n }\n\n this.logger?.debug(\n `WebRecorder initialized -- recordSampleRate=${this.audioContext.sampleRate}`,\n this.config\n )\n this.audioWorkletNode.port.postMessage({\n command: 'init',\n recordSampleRate: this.audioContext.sampleRate,\n exportSampleRate:\n this.config.sampleRate ?? this.audioContext.sampleRate,\n bitDepth: this.bitDepth,\n exportBitDepth: this.exportBitDepth,\n channels: this.numberOfChannels,\n interval: this.config.interval ?? DEFAULT_WEB_INTERVAL,\n // enableLogging: !!this.logger,\n })\n\n // Connect the source to the AudioWorkletNode and start recording\n this.source.connect(this.audioWorkletNode)\n this.audioWorkletNode.connect(this.audioContext.destination)\n } catch (error) {\n console.error(`[${TAG}] Failed to initialize WebRecorder`, error)\n }\n }\n\n /**\n * Initializes the feature extractor worker for audio analysis\n * Creates an inline worker from a blob for audio feature extraction\n */\n initFeatureExtractorWorker() {\n try {\n const blob = new Blob([InlineFeaturesExtractor], {\n type: 'application/javascript',\n })\n const url = URL.createObjectURL(blob)\n this.featureExtractorWorker = new Worker(url)\n this.featureExtractorWorker.onmessage =\n this.handleFeatureExtractorMessage.bind(this)\n this.featureExtractorWorker.onerror = (error) => {\n console.error(`[${TAG}] Feature extractor worker error:`, error)\n }\n this.logger?.log(\n 'Feature extractor worker initialized successfully'\n )\n } catch (error) {\n console.error(\n `[${TAG}] Failed to initialize feature extractor worker`,\n error\n )\n }\n }\n\n /**\n * Processes audio analysis results from the feature extractor worker\n * Updates the audio analysis data and emits events\n * @param event - The event containing audio analysis results\n */\n handleFeatureExtractorMessage(event: AudioFeaturesEvent) {\n if (event.data.command === 'features') {\n const segmentResult = event.data.result\n\n // Update the dataPointIdCounter based on the last ID received\n if (\n segmentResult.dataPoints &&\n segmentResult.dataPoints.length > 0\n ) {\n const lastDataPoint =\n segmentResult.dataPoints[\n segmentResult.dataPoints.length - 1\n ]\n if (lastDataPoint && typeof lastDataPoint.id === 'number') {\n this.dataPointIdCounter = Math.max(\n this.dataPointIdCounter,\n lastDataPoint.id + 1\n )\n }\n }\n\n this.logger?.debug('[WebRecorder] Raw segment result:', {\n dataPointsLength: segmentResult.dataPoints.length,\n durationMs: segmentResult.durationMs,\n sampleRate: segmentResult.sampleRate,\n amplitudeRange: segmentResult.amplitudeRange,\n })\n\n // Ensure consistent sample rate in the result\n segmentResult.sampleRate =\n this.config.sampleRate || this.audioContext.sampleRate\n\n // Update the full audio analysis data with proper range merging\n this.audioAnalysisData.dataPoints.push(...segmentResult.dataPoints)\n this.audioAnalysisData.durationMs += segmentResult.durationMs\n\n // Make sure the sample rate is consistent\n this.audioAnalysisData.sampleRate = segmentResult.sampleRate\n\n // Properly merge amplitude ranges\n if (segmentResult.amplitudeRange) {\n if (!this.audioAnalysisData.amplitudeRange) {\n this.audioAnalysisData.amplitudeRange = {\n ...segmentResult.amplitudeRange,\n }\n } else {\n this.audioAnalysisData.amplitudeRange = {\n min: Math.min(\n this.audioAnalysisData.amplitudeRange.min,\n segmentResult.amplitudeRange.min\n ),\n max: Math.max(\n this.audioAnalysisData.amplitudeRange.max,\n segmentResult.amplitudeRange.max\n ),\n }\n }\n }\n\n // Properly merge RMS ranges\n if (segmentResult.rmsRange) {\n if (!this.audioAnalysisData.rmsRange) {\n this.audioAnalysisData.rmsRange = {\n ...segmentResult.rmsRange,\n }\n } else {\n this.audioAnalysisData.rmsRange = {\n min: Math.min(\n this.audioAnalysisData.rmsRange.min,\n segmentResult.rmsRange.min\n ),\n max: Math.max(\n this.audioAnalysisData.rmsRange.max,\n segmentResult.rmsRange.max\n ),\n }\n }\n }\n\n this.logger?.debug('features event segmentResult', segmentResult)\n this.logger?.debug(\n `features event audioAnalysisData duration=${this.audioAnalysisData.durationMs}`,\n this.audioAnalysisData\n )\n this.emitAudioAnalysisCallback(segmentResult)\n\n this.logger?.debug('[WebRecorder] Updated audioAnalysisData:', {\n dataPointsLength: this.audioAnalysisData.dataPoints.length,\n durationMs: this.audioAnalysisData.durationMs,\n sampleRate: this.audioAnalysisData.sampleRate,\n amplitudeRange: this.audioAnalysisData.amplitudeRange,\n })\n }\n }\n\n /**\n * Resets the data point ID counter\n * Used when starting a new recording\n */\n resetDataPointCounter() {\n this.dataPointIdCounter = 0\n\n // Reset the counter in the worker\n if (this.featureExtractorWorker) {\n this.featureExtractorWorker.postMessage({\n command: 'resetCounter',\n startCounterFrom: 0,\n })\n }\n }\n\n /**\n * Starts the audio recording process\n * Connects the audio nodes and begins capturing audio data\n */\n start() {\n this.source.connect(this.audioWorkletNode)\n this.audioWorkletNode.connect(this.audioContext.destination)\n this.packetCount = 0\n\n // Reset the counter when starting a new recording\n this.resetDataPointCounter()\n\n if (this.compressedMediaRecorder) {\n this.compressedMediaRecorder.start(this.config.interval ?? 1000)\n }\n }\n\n /**\n * Stops the audio recording process and returns the recorded data\n * @returns Promise resolving to an object containing PCM data and optional compressed blob\n */\n async stop(): Promise<{ pcmData: Float32Array; compressedBlob?: Blob }> {\n try {\n if (this.compressedMediaRecorder) {\n this.compressedMediaRecorder.stop()\n return {\n pcmData: new Float32Array(), // Return empty array since we're streaming\n compressedBlob: new Blob(this.compressedChunks, {\n type: 'audio/webm;codecs=opus',\n }),\n }\n }\n return { pcmData: new Float32Array() }\n } finally {\n this.cleanup()\n // Reset the chunks array\n this.compressedChunks = []\n this.compressedSize = 0\n this.pendingCompressedChunk = null\n }\n }\n\n /**\n * Cleans up resources when recording is stopped\n * Closes audio context and disconnects nodes\n */\n private cleanup() {\n if (this.audioContext) {\n this.audioContext.close()\n }\n if (this.audioWorkletNode) {\n this.audioWorkletNode.disconnect()\n }\n if (this.source) {\n this.source.disconnect()\n }\n this.stopMediaStreamTracks()\n }\n\n /**\n * Pauses the audio recording process\n * Disconnects audio nodes and pauses the media recorder\n */\n pause() {\n this.source.disconnect(this.audioWorkletNode) // Disconnect the source from the AudioWorkletNode\n this.audioWorkletNode.disconnect(this.audioContext.destination) // Disconnect the AudioWorkletNode from the destination\n this.audioWorkletNode.port.postMessage({ command: 'pause' })\n this.compressedMediaRecorder?.pause()\n }\n\n /**\n * Stops all media stream tracks to release hardware resources\n * Ensures recording indicators (like microphone icon) are turned off\n */\n stopMediaStreamTracks() {\n // Stop all audio tracks to stop the recording icon\n const tracks = this.source.mediaStream.getTracks()\n tracks.forEach((track) => track.stop())\n }\n\n /**\n * Determines the audio format capabilities of the current audio context\n * @param sampleRate - The sample rate to check\n * @returns Object containing format information (sample rate, bit depth, channels)\n */\n private checkAudioContextFormat({ sampleRate }: { sampleRate: number }) {\n // Create a silent AudioBuffer\n const frameCount = sampleRate * 1.0 // 1 second buffer\n const audioBuffer = this.audioContext.createBuffer(\n 1,\n frameCount,\n sampleRate\n )\n\n // Check the format\n const channelData = audioBuffer.getChannelData(0)\n const bitDepth = channelData.BYTES_PER_ELEMENT * 8 // 4 bytes per element means 32-bit\n\n return {\n sampleRate: audioBuffer.sampleRate,\n bitDepth,\n numberOfChannels: audioBuffer.numberOfChannels,\n }\n }\n\n /**\n * Resumes a paused recording\n * Reconnects audio nodes and resumes the media recorder\n */\n resume() {\n this.source.connect(this.audioWorkletNode)\n this.audioWorkletNode.connect(this.audioContext.destination)\n this.audioWorkletNode.port.postMessage({ command: 'resume' })\n this.compressedMediaRecorder?.resume()\n }\n\n /**\n * Initializes the compressed media recorder if compression is enabled\n * Sets up event handlers for compressed audio data\n */\n private initializeCompressedRecorder() {\n try {\n const mimeType = 'audio/webm;codecs=opus'\n if (!MediaRecorder.isTypeSupported(mimeType)) {\n this.logger?.warn(\n 'Opus compression not supported in this browser'\n )\n return\n }\n\n this.compressedMediaRecorder = new MediaRecorder(\n this.source.mediaStream,\n {\n mimeType,\n audioBitsPerSecond:\n this.config.compression?.bitrate ?? 128000,\n }\n )\n\n this.compressedMediaRecorder.ondataavailable = (event) => {\n if (event.data.size > 0) {\n this.compressedChunks.push(event.data)\n this.compressedSize += event.data.size\n this.pendingCompressedChunk = event.data\n }\n }\n } catch (error) {\n this.logger?.error(\n 'Failed to initialize compressed recorder:',\n error\n )\n }\n }\n\n /**\n * Processes features if enabled\n */\n processFeatures(\n chunk: Float32Array,\n sampleRate: number,\n chunkPosition: number,\n startPosition: number,\n endPosition: number,\n samples: number\n ) {\n if (this.config.enableProcessing && this.featureExtractorWorker) {\n this.featureExtractorWorker.postMessage({\n command: 'process',\n channelData: chunk,\n sampleRate,\n segmentDurationMs:\n this.config.segmentDurationMs ??\n DEFAULT_SEGMENT_DURATION_MS, // Default to 100ms\n bitDepth: this.bitDepth,\n fullAudioDurationMs: chunkPosition * 1000,\n numberOfChannels: this.numberOfChannels,\n features: this.config.features,\n intervalAnalysis: this.config.intervalAnalysis,\n startPosition,\n endPosition,\n samples,\n startCounterFrom: this.dataPointIdCounter, // Pass the current counter value\n })\n }\n }\n}\n"]}
1
+ {"version":3,"file":"WebRecorder.web.js","sourceRoot":"","sources":["../src/WebRecorder.web.ts"],"names":[],"mappings":"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","sourcesContent":["// packages/expo-audio-stream/src/WebRecorder.web.ts\n\nimport { AudioAnalysis } from './AudioAnalysis/AudioAnalysis.types'\nimport { ConsoleLike, RecordingConfig } from './ExpoAudioStream.types'\nimport {\n EmitAudioAnalysisFunction,\n EmitAudioEventFunction,\n} from './ExpoAudioStream.web'\nimport { encodingToBitDepth } from './utils/encodingToBitDepth'\nimport { InlineFeaturesExtractor } from './workers/InlineFeaturesExtractor.web'\nimport { InlineAudioWebWorker } from './workers/inlineAudioWebWorker.web'\n\ninterface AudioWorkletEvent {\n data: {\n command: string\n recordedData?: Float32Array\n sampleRate?: number\n position?: number\n }\n}\n\ninterface AudioFeaturesEvent {\n data: {\n command: string\n result: AudioAnalysis\n }\n}\n\nconst DEFAULT_WEB_BITDEPTH = 32\nconst DEFAULT_SEGMENT_DURATION_MS = 100\nconst DEFAULT_WEB_INTERVAL = 500\nconst DEFAULT_WEB_NUMBER_OF_CHANNELS = 1\n\nconst TAG = 'WebRecorder'\n\nexport class WebRecorder {\n public audioContext: AudioContext\n private audioWorkletNode!: AudioWorkletNode\n private featureExtractorWorker?: Worker\n private source: MediaStreamAudioSourceNode\n private emitAudioEventCallback: EmitAudioEventFunction\n private emitAudioAnalysisCallback: EmitAudioAnalysisFunction\n private config: RecordingConfig\n private position: number = 0\n private numberOfChannels: number // Number of audio channels\n private bitDepth: number // Bit depth of the audio\n private exportBitDepth: number // Bit depth of the audio\n private audioAnalysisData: AudioAnalysis // Keep updating the full audio analysis data with latest events\n private logger?: ConsoleLike\n private compressedMediaRecorder: MediaRecorder | null = null\n private compressedChunks: Blob[] = []\n private compressedSize: number = 0\n private pendingCompressedChunk: Blob | null = null\n private dataPointIdCounter: number = 0 // Add this property to track the counter\n private deviceDisconnectionHandler: (() => void) | null = null\n private mediaStream: MediaStream | null = null\n private onInterruptionCallback?: (event: {\n reason: string\n isPaused: boolean\n timestamp: number\n }) => void\n private _isDeviceDisconnected: boolean = false\n\n /**\n * Flag to indicate whether this is the first audio chunk after a device switch\n * Used to maintain proper duration counting\n */\n public isFirstChunkAfterSwitch: boolean = false\n\n /**\n * Gets whether the recording device has been disconnected\n */\n get isDeviceDisconnected(): boolean {\n return this._isDeviceDisconnected\n }\n\n /**\n * Initializes a new WebRecorder instance for audio recording and processing\n * @param audioContext - The AudioContext to use for recording\n * @param source - The MediaStreamAudioSourceNode providing the audio input\n * @param recordingConfig - Configuration options for the recording\n * @param emitAudioEventCallback - Callback function for audio data events\n * @param emitAudioAnalysisCallback - Callback function for audio analysis events\n * @param onInterruption - Callback for recording interruptions\n * @param logger - Optional logger for debugging information\n */\n constructor({\n audioContext,\n source,\n recordingConfig,\n emitAudioEventCallback,\n emitAudioAnalysisCallback,\n onInterruption,\n logger,\n }: {\n audioContext: AudioContext\n source: MediaStreamAudioSourceNode\n recordingConfig: RecordingConfig\n emitAudioEventCallback: EmitAudioEventFunction\n emitAudioAnalysisCallback: EmitAudioAnalysisFunction\n onInterruption?: (event: {\n reason: string\n isPaused: boolean\n timestamp: number\n }) => void\n logger?: ConsoleLike\n }) {\n this.audioContext = audioContext\n this.source = source\n this.emitAudioEventCallback = emitAudioEventCallback\n this.emitAudioAnalysisCallback = emitAudioAnalysisCallback\n this.config = recordingConfig\n this.logger = logger\n\n const audioContextFormat = this.checkAudioContextFormat({\n sampleRate: this.audioContext.sampleRate,\n })\n this.logger?.debug('Initialized WebRecorder with config:', {\n sampleRate: audioContextFormat.sampleRate,\n bitDepth: audioContextFormat.bitDepth,\n numberOfChannels: audioContextFormat.numberOfChannels,\n })\n\n this.bitDepth = audioContextFormat.bitDepth\n this.numberOfChannels =\n audioContextFormat.numberOfChannels ||\n DEFAULT_WEB_NUMBER_OF_CHANNELS // Default to 1 if not available\n this.exportBitDepth =\n encodingToBitDepth({\n encoding: recordingConfig.encoding ?? 'pcm_32bit',\n }) ||\n audioContextFormat.bitDepth ||\n DEFAULT_WEB_BITDEPTH\n\n this.audioAnalysisData = {\n amplitudeRange: { min: 0, max: 0 },\n rmsRange: { min: 0, max: 0 },\n dataPoints: [],\n durationMs: 0,\n samples: 0,\n bitDepth: this.bitDepth,\n numberOfChannels: this.numberOfChannels,\n sampleRate: this.config.sampleRate || this.audioContext.sampleRate,\n segmentDurationMs:\n this.config.segmentDurationMs ?? DEFAULT_SEGMENT_DURATION_MS, // Default to 100ms segments\n }\n\n if (recordingConfig.enableProcessing) {\n this.initFeatureExtractorWorker()\n }\n\n // Initialize compressed recording if enabled\n if (recordingConfig.compression?.enabled) {\n this.initializeCompressedRecorder()\n }\n\n this.mediaStream = source.mediaStream\n this.onInterruptionCallback = onInterruption\n\n // Setup device disconnection detection\n this.setupDeviceDisconnectionDetection()\n }\n\n /**\n * Initializes the audio worklet using an inline script\n * Creates and connects the audio processing pipeline\n */\n async init() {\n try {\n // Create and use inline audio worklet\n const blob = new Blob([InlineAudioWebWorker], {\n type: 'application/javascript',\n })\n const url = URL.createObjectURL(blob)\n await this.audioContext.audioWorklet.addModule(url)\n\n this.audioWorkletNode = new AudioWorkletNode(\n this.audioContext,\n 'recorder-processor'\n )\n\n this.audioWorkletNode.port.onmessage = async (\n event: AudioWorkletEvent\n ) => {\n const command = event.data.command\n if (command !== 'newData') return\n\n const pcmBufferFloat = event.data.recordedData\n if (!pcmBufferFloat) {\n this.logger?.warn('Received empty audio buffer', event)\n return\n }\n\n // Process data in smaller chunks and emit immediately\n const chunkSize = this.audioContext.sampleRate * 2 // Reduce to 2 seconds chunks\n const sampleRate =\n event.data.sampleRate ?? this.audioContext.sampleRate\n const duration = pcmBufferFloat.length / sampleRate\n\n // Use incoming position if provided by worklet, otherwise use our tracked position\n const incomingPosition =\n typeof event.data.position === 'number'\n ? event.data.position\n : this.position\n\n // Calculate bytes per sample based on bit depth\n const bytesPerSample = this.bitDepth / 8\n\n // Emit chunks without storing them\n for (let i = 0; i < pcmBufferFloat.length; i += chunkSize) {\n const chunk = pcmBufferFloat.slice(i, i + chunkSize)\n const chunkPosition = incomingPosition + i / sampleRate\n\n // Calculate byte positions and samples\n const startPosition = Math.floor(i * bytesPerSample)\n const endPosition = Math.floor(\n (i + chunk.length) * bytesPerSample\n )\n const samples = chunk.length // Number of samples in this chunk\n\n // Process features if enabled\n if (\n this.config.enableProcessing &&\n this.featureExtractorWorker\n ) {\n this.featureExtractorWorker.postMessage({\n command: 'process',\n channelData: chunk,\n sampleRate,\n segmentDurationMs:\n this.config.segmentDurationMs ??\n DEFAULT_SEGMENT_DURATION_MS, // Default to 100ms\n bitDepth: this.bitDepth,\n fullAudioDurationMs: chunkPosition * 1000,\n numberOfChannels: this.numberOfChannels,\n features: this.config.features,\n intervalAnalysis: this.config.intervalAnalysis,\n startPosition,\n endPosition,\n samples,\n })\n }\n\n // Emit chunk immediately\n this.emitAudioEventCallback({\n data: chunk,\n position: chunkPosition,\n compression: this.pendingCompressedChunk\n ? {\n data: this.pendingCompressedChunk,\n size: this.pendingCompressedChunk.size,\n totalSize: this.compressedSize,\n mimeType: 'audio/webm',\n format: 'opus',\n bitrate:\n this.config.compression?.bitrate ??\n 128000,\n }\n : undefined,\n })\n }\n\n // Update our position based on the worklet's position if provided\n this.position = incomingPosition + duration\n this.pendingCompressedChunk = null\n }\n\n this.logger?.debug(\n `WebRecorder initialized -- recordSampleRate=${this.audioContext.sampleRate}, startPosition=${this.position}`,\n this.config\n )\n this.audioWorkletNode.port.postMessage({\n command: 'init',\n recordSampleRate: this.audioContext.sampleRate,\n exportSampleRate:\n this.config.sampleRate ?? this.audioContext.sampleRate,\n bitDepth: this.bitDepth,\n exportBitDepth: this.exportBitDepth,\n channels: this.numberOfChannels,\n interval: this.config.interval ?? DEFAULT_WEB_INTERVAL,\n position: this.position, // Pass the current position to the processor\n // enableLogging: !!this.logger,\n })\n\n // Connect the source to the AudioWorkletNode and start recording\n this.source.connect(this.audioWorkletNode)\n this.audioWorkletNode.connect(this.audioContext.destination)\n } catch (error) {\n console.error(`[${TAG}] Failed to initialize WebRecorder`, error)\n }\n }\n\n /**\n * Initializes the feature extractor worker for audio analysis\n * Creates an inline worker from a blob for audio feature extraction\n */\n initFeatureExtractorWorker() {\n try {\n const blob = new Blob([InlineFeaturesExtractor], {\n type: 'application/javascript',\n })\n const url = URL.createObjectURL(blob)\n this.featureExtractorWorker = new Worker(url)\n this.featureExtractorWorker.onmessage =\n this.handleFeatureExtractorMessage.bind(this)\n this.featureExtractorWorker.onerror = (error) => {\n console.error(`[${TAG}] Feature extractor worker error:`, error)\n }\n\n // Initialize worker with counter if needed\n if (this.dataPointIdCounter > 0) {\n this.featureExtractorWorker.postMessage({\n command: 'resetCounter',\n value: this.dataPointIdCounter,\n })\n this.logger?.debug(\n `Initialized worker with counter value ${this.dataPointIdCounter}`\n )\n }\n\n this.logger?.log(\n 'Feature extractor worker initialized successfully'\n )\n } catch (error) {\n console.error(\n `[${TAG}] Failed to initialize feature extractor worker`,\n error\n )\n }\n }\n\n /**\n * Processes audio analysis results from the feature extractor worker\n * Updates the audio analysis data and emits events\n * @param event - The event containing audio analysis results\n */\n handleFeatureExtractorMessage(event: AudioFeaturesEvent) {\n if (event.data.command === 'features') {\n const segmentResult = event.data.result\n\n // Track existing IDs to prevent duplicates\n const existingIds = new Set(\n this.audioAnalysisData.dataPoints.map((dp) => dp.id)\n )\n\n // Filter out datapoints with duplicate IDs\n const uniqueNewDataPoints = segmentResult.dataPoints.filter(\n (dp) => {\n return !existingIds.has(dp.id)\n }\n )\n\n // Log filtered duplicates if any\n if (\n uniqueNewDataPoints.length < segmentResult.dataPoints.length &&\n this.logger?.warn\n ) {\n this.logger.warn(\n `Filtered ${segmentResult.dataPoints.length - uniqueNewDataPoints.length} duplicate datapoints`\n )\n }\n\n // Update counter based on the highest ID seen\n if (uniqueNewDataPoints.length > 0) {\n const lastDataPoint =\n uniqueNewDataPoints[uniqueNewDataPoints.length - 1]\n\n if (lastDataPoint && typeof lastDataPoint.id === 'number') {\n const nextIdValue = lastDataPoint.id + 1\n\n if (nextIdValue > this.dataPointIdCounter) {\n this.dataPointIdCounter = nextIdValue\n this.logger?.debug(\n `Counter updated to ${this.dataPointIdCounter}`\n )\n }\n }\n }\n\n // Add unique data points to our analysis data\n this.audioAnalysisData.dataPoints.push(...uniqueNewDataPoints)\n this.audioAnalysisData.durationMs += segmentResult.durationMs\n this.audioAnalysisData.sampleRate = segmentResult.sampleRate\n\n // Merge amplitude ranges\n if (segmentResult.amplitudeRange) {\n if (!this.audioAnalysisData.amplitudeRange) {\n this.audioAnalysisData.amplitudeRange = {\n ...segmentResult.amplitudeRange,\n }\n } else {\n this.audioAnalysisData.amplitudeRange = {\n min: Math.min(\n this.audioAnalysisData.amplitudeRange.min,\n segmentResult.amplitudeRange.min\n ),\n max: Math.max(\n this.audioAnalysisData.amplitudeRange.max,\n segmentResult.amplitudeRange.max\n ),\n }\n }\n }\n\n // Merge RMS ranges\n if (segmentResult.rmsRange) {\n if (!this.audioAnalysisData.rmsRange) {\n this.audioAnalysisData.rmsRange = {\n ...segmentResult.rmsRange,\n }\n } else {\n this.audioAnalysisData.rmsRange = {\n min: Math.min(\n this.audioAnalysisData.rmsRange.min,\n segmentResult.rmsRange.min\n ),\n max: Math.max(\n this.audioAnalysisData.rmsRange.max,\n segmentResult.rmsRange.max\n ),\n }\n }\n }\n\n // Send filtered result to avoid duplicate IDs\n const filteredSegmentResult = {\n ...segmentResult,\n dataPoints: uniqueNewDataPoints,\n }\n\n this.emitAudioAnalysisCallback(filteredSegmentResult)\n }\n }\n\n /**\n * Reset the data point counter to a specific value or zero\n * @param startCounterFrom Optional value to start the counter from (for continuing from previous recordings)\n */\n resetDataPointCounter(startCounterFrom?: number): void {\n // Set the counter with the passed value or 0\n this.dataPointIdCounter =\n startCounterFrom !== undefined ? startCounterFrom : 0\n this.logger?.debug(\n `Reset data point counter to ${this.dataPointIdCounter}`\n )\n\n // Update worker counter if available\n if (this.featureExtractorWorker) {\n this.featureExtractorWorker.postMessage({\n command: 'resetCounter',\n value: this.dataPointIdCounter,\n })\n } else {\n this.logger?.warn(\n 'No feature extractor worker available to update counter'\n )\n }\n }\n\n /**\n * Get the current data point counter value\n * @returns The current value of the data point counter\n */\n getDataPointCounter(): number {\n return this.dataPointIdCounter\n }\n\n /**\n * Prepares the recorder for continuity after device switch\n * Sets up all necessary state to maintain proper recording continuity\n */\n prepareForDeviceSwitch(): void {\n this.isFirstChunkAfterSwitch = true\n this.logger?.debug(\n `Prepared for device switch at position ${this.position}s`\n )\n }\n\n /**\n * Starts the audio recording process\n * Connects the audio nodes and begins capturing audio data\n * @param preserveCounters If true, do not reset the counter (used for device switching)\n */\n start(preserveCounters = false) {\n this.source.connect(this.audioWorkletNode)\n this.audioWorkletNode.connect(this.audioContext.destination)\n\n // Only reset the counter when not preserving state (e.g., for a fresh recording)\n if (!preserveCounters) {\n this.logger?.debug(\n 'Starting fresh recording, resetting counter to 0'\n )\n this.resetDataPointCounter(0) // Explicitly reset to 0 for new recordings\n this.isFirstChunkAfterSwitch = false\n } else {\n this.logger?.debug(\n `Preserving counter at ${this.dataPointIdCounter} during device switch`\n )\n }\n\n if (this.compressedMediaRecorder) {\n this.compressedMediaRecorder.start(this.config.interval ?? 1000)\n }\n }\n\n /**\n * Stops the audio recording process and returns the recorded data\n * @param externalAudioChunks Optional array of Float32Array chunks from previous devices\n * @returns Promise resolving to an object containing PCM data and optional compressed blob\n */\n async stop(\n externalAudioChunks?: Float32Array[]\n ): Promise<{ pcmData: Float32Array; compressedBlob?: Blob }> {\n try {\n // Log what's happening for debugging\n this.logger?.debug('Stopping recording and collecting final data')\n\n // Stop any compressed recording first\n if (\n this.compressedMediaRecorder &&\n this.compressedMediaRecorder.state !== 'inactive'\n ) {\n this.compressedMediaRecorder.stop()\n }\n\n // Wait for any pending compressed chunks to be processed\n if (this.compressedMediaRecorder) {\n // Small delay to ensure all data is processed\n await new Promise((resolve) => setTimeout(resolve, 100))\n }\n\n // Return the compressed blob if available\n return {\n pcmData: new Float32Array(), // Return empty array since we're streaming\n compressedBlob:\n this.compressedChunks.length > 0\n ? new Blob(this.compressedChunks, {\n type: 'audio/webm;codecs=opus',\n })\n : undefined,\n }\n } finally {\n this.cleanup()\n // Reset the chunks array\n this.compressedChunks = []\n this.compressedSize = 0\n this.pendingCompressedChunk = null\n }\n }\n\n /**\n * Cleans up resources when recording is stopped\n * Closes audio context and disconnects nodes\n */\n public cleanup() {\n // Remove device disconnection handler\n if (this.deviceDisconnectionHandler) {\n this.deviceDisconnectionHandler()\n this.deviceDisconnectionHandler = null\n }\n\n // Check if AudioContext is already closed before attempting to close it\n if (this.audioContext && this.audioContext.state !== 'closed') {\n try {\n this.audioContext.close()\n } catch (e) {\n // Ignore closure errors - this happens if already closed\n }\n }\n\n // Safely disconnect audioWorkletNode if it exists\n if (this.audioWorkletNode) {\n try {\n this.audioWorkletNode.disconnect()\n } catch (e) {\n // Ignore disconnection errors - node might be already disconnected\n }\n }\n\n // Safely disconnect source if it exists\n if (this.source) {\n try {\n this.source.disconnect()\n } catch (e) {\n // Ignore disconnection errors - source might be already disconnected\n }\n }\n\n // Always stop media stream tracks to release hardware resources\n this.stopMediaStreamTracks()\n\n // Mark as disconnected to prevent future errors\n this._isDeviceDisconnected = true\n }\n\n /**\n * Pauses the audio recording process\n * Disconnects audio nodes and pauses the media recorder\n */\n pause() {\n try {\n // Note: We're just pausing, not disconnecting the device\n // Simply disconnect nodes temporarily without marking device as disconnected\n this.source.disconnect(this.audioWorkletNode)\n this.audioWorkletNode.disconnect(this.audioContext.destination)\n this.audioWorkletNode.port.postMessage({ command: 'pause' })\n\n if (this.compressedMediaRecorder?.state === 'recording') {\n this.compressedMediaRecorder.pause()\n }\n\n this.logger?.debug('Recording paused successfully')\n } catch (error) {\n this.logger?.error('Error in pause(): ', error)\n // Already disconnected, just ignore and continue\n }\n }\n\n /**\n * Stops all media stream tracks to release hardware resources\n * Ensures recording indicators (like microphone icon) are turned off\n */\n public stopMediaStreamTracks() {\n // Stop all audio tracks to stop the recording icon\n if (this.mediaStream) {\n const tracks = this.mediaStream.getTracks()\n tracks.forEach((track) => track.stop())\n } else if (this.source?.mediaStream) {\n const tracks = this.source.mediaStream.getTracks()\n tracks.forEach((track) => track.stop())\n }\n }\n\n /**\n * Determines the audio format capabilities of the current audio context\n * @param sampleRate - The sample rate to check\n * @returns Object containing format information (sample rate, bit depth, channels)\n */\n private checkAudioContextFormat({ sampleRate }: { sampleRate: number }) {\n // Create a silent AudioBuffer\n const frameCount = sampleRate * 1.0 // 1 second buffer\n const audioBuffer = this.audioContext.createBuffer(\n 1,\n frameCount,\n sampleRate\n )\n\n // Check the format\n const channelData = audioBuffer.getChannelData(0)\n const bitDepth = channelData.BYTES_PER_ELEMENT * 8 // 4 bytes per element means 32-bit\n\n return {\n sampleRate: audioBuffer.sampleRate,\n bitDepth,\n numberOfChannels: audioBuffer.numberOfChannels,\n }\n }\n\n /**\n * Resumes a paused recording\n * Reconnects audio nodes and resumes the media recorder\n */\n resume() {\n // If device was disconnected, we can't resume\n if (this._isDeviceDisconnected) {\n this.logger?.warn('Cannot resume recording: device disconnected')\n return\n }\n\n try {\n this.source.connect(this.audioWorkletNode)\n this.audioWorkletNode.connect(this.audioContext.destination)\n this.audioWorkletNode.port.postMessage({ command: 'resume' })\n this.compressedMediaRecorder?.resume()\n } catch (error) {\n this.logger?.error('Error in resume(): ', error)\n }\n }\n\n /**\n * Initializes the compressed media recorder if compression is enabled\n * Sets up event handlers for compressed audio data\n */\n private initializeCompressedRecorder() {\n try {\n const mimeType = 'audio/webm;codecs=opus'\n if (!MediaRecorder.isTypeSupported(mimeType)) {\n this.logger?.warn(\n 'Opus compression not supported in this browser'\n )\n return\n }\n\n this.compressedMediaRecorder = new MediaRecorder(\n this.source.mediaStream,\n {\n mimeType,\n audioBitsPerSecond:\n this.config.compression?.bitrate ?? 128000,\n }\n )\n\n this.compressedMediaRecorder.ondataavailable = (event) => {\n if (event.data.size > 0) {\n this.compressedChunks.push(event.data)\n this.compressedSize += event.data.size\n this.pendingCompressedChunk = event.data\n }\n }\n } catch (error) {\n this.logger?.error(\n 'Failed to initialize compressed recorder:',\n error\n )\n }\n }\n\n /**\n * Processes features if enabled\n */\n processFeatures(\n chunk: Float32Array,\n sampleRate: number,\n chunkPosition: number,\n startPosition: number,\n endPosition: number,\n samples: number\n ) {\n if (this.config.enableProcessing && this.featureExtractorWorker) {\n this.featureExtractorWorker.postMessage({\n command: 'process',\n channelData: chunk,\n sampleRate,\n segmentDurationMs:\n this.config.segmentDurationMs ??\n DEFAULT_SEGMENT_DURATION_MS, // Default to 100ms\n bitDepth: this.bitDepth,\n fullAudioDurationMs: chunkPosition * 1000,\n numberOfChannels: this.numberOfChannels,\n features: this.config.features,\n intervalAnalysis: this.config.intervalAnalysis,\n startPosition,\n endPosition,\n samples,\n })\n }\n }\n\n /**\n * Sets up detection for device disconnection events\n */\n private setupDeviceDisconnectionDetection() {\n if (!this.mediaStream) return\n\n // Function to handle track ending (which happens on device disconnection)\n const handleTrackEnded = () => {\n this.logger?.warn('Audio track ended - device disconnected')\n this._isDeviceDisconnected = true\n\n // Use the callback to notify parent component about device disconnection\n if (this.onInterruptionCallback) {\n this.onInterruptionCallback({\n reason: 'deviceDisconnected',\n isPaused: true,\n timestamp: Date.now(),\n })\n this.logger?.debug('Notified about device disconnection')\n }\n\n // Ensure we disconnect nodes to prevent zombie recordings\n if (this.audioWorkletNode) {\n this.audioWorkletNode.port.postMessage({\n command: 'deviceDisconnected',\n })\n\n try {\n this.source.disconnect(this.audioWorkletNode)\n this.audioWorkletNode.disconnect()\n } catch (e) {\n // Ignore disconnection errors as the track might already be gone\n }\n }\n }\n\n // Add listeners to all audio tracks\n const tracks = this.mediaStream.getAudioTracks()\n tracks.forEach((track) => {\n track.addEventListener('ended', handleTrackEnded)\n })\n\n // Store the handler for cleanup\n this.deviceDisconnectionHandler = () => {\n tracks.forEach((track) => {\n track.removeEventListener('ended', handleTrackEnded)\n })\n }\n }\n\n /**\n * Explicitly set the position for continuous recording across device switches\n * @param position The position in seconds to continue from\n */\n setPosition(position: number): void {\n if (position >= 0) {\n this.position = position\n this.logger?.debug(`Position explicitly set to ${position} seconds`)\n } else {\n this.logger?.warn(`Invalid position value: ${position}, ignoring`)\n }\n }\n\n /**\n * Get the current position in seconds\n * @returns The current position\n */\n getPosition(): number {\n return this.position\n }\n\n /**\n * Gets the current compressed chunks\n * @returns Array of current compressed audio chunks\n */\n getCompressedChunks(): Blob[] {\n return [...this.compressedChunks]\n }\n\n /**\n * Sets the compressed chunks from a previous recorder\n * @param chunks Array of compressed chunks from a previous recorder\n */\n setCompressedChunks(chunks: Blob[]): void {\n if (chunks && chunks.length > 0) {\n this.logger?.debug(\n `Adding ${chunks.length} compressed chunks from previous device`\n )\n this.compressedChunks = [...chunks, ...this.compressedChunks]\n // Update size\n this.compressedSize = this.compressedChunks.reduce(\n (size, chunk) => size + chunk.size,\n 0\n )\n }\n }\n}\n"]}
@@ -0,0 +1,14 @@
1
+ import { AudioDevice } from '../ExpoAudioStream.types';
2
+ /**
3
+ * React hook for managing audio input devices
4
+ */
5
+ export declare function useAudioDevices(): {
6
+ devices: AudioDevice[];
7
+ currentDevice: AudioDevice | null;
8
+ loading: boolean;
9
+ error: Error | null;
10
+ selectDevice: (deviceId: string) => Promise<boolean>;
11
+ resetToDefaultDevice: () => Promise<boolean>;
12
+ refreshDevices: () => Promise<AudioDevice[]>;
13
+ };
14
+ //# sourceMappingURL=useAudioDevices.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAudioDevices.d.ts","sourceRoot":"","sources":["../../src/hooks/useAudioDevices.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AAEtD;;GAEG;AACH,wBAAgB,eAAe;;;;;6BAyEN,MAAM,KAAG,QAAQ,OAAO,CAAC;gCAiCK,QAAQ,OAAO,CAAC;0BA8BtB,QAAQ,WAAW,EAAE,CAAC;EAmCtE"}
@@ -0,0 +1,151 @@
1
+ import { useCallback, useEffect, useState } from 'react';
2
+ import { audioDeviceManager } from '../AudioDeviceManager';
3
+ /**
4
+ * React hook for managing audio input devices
5
+ */
6
+ export function useAudioDevices() {
7
+ const [devices, setDevices] = useState([]);
8
+ const [currentDevice, setCurrentDevice] = useState(null);
9
+ const [loading, setLoading] = useState(true);
10
+ const [error, setError] = useState(null);
11
+ // Load devices on mount
12
+ useEffect(() => {
13
+ let isMounted = true;
14
+ const loadDevices = async () => {
15
+ try {
16
+ setLoading(true);
17
+ setError(null);
18
+ // Load available devices
19
+ const availableDevices = await audioDeviceManager.getAvailableDevices();
20
+ if (isMounted)
21
+ setDevices(availableDevices);
22
+ // Get current device
23
+ const device = await audioDeviceManager.getCurrentDevice();
24
+ if (isMounted)
25
+ setCurrentDevice(device);
26
+ }
27
+ catch (err) {
28
+ console.error('Failed to load audio devices:', err);
29
+ if (isMounted)
30
+ setError(err instanceof Error
31
+ ? err
32
+ : new Error('Failed to load audio devices'));
33
+ }
34
+ finally {
35
+ if (isMounted)
36
+ setLoading(false);
37
+ }
38
+ };
39
+ loadDevices();
40
+ // Set up device change listener
41
+ const removeListener = audioDeviceManager.addDeviceChangeListener((updatedDevices) => {
42
+ if (isMounted) {
43
+ setDevices(updatedDevices);
44
+ // If our current device is no longer available, update it
45
+ if (currentDevice &&
46
+ !updatedDevices.some((d) => d.id === currentDevice.id)) {
47
+ audioDeviceManager
48
+ .getCurrentDevice()
49
+ .then((newDevice) => {
50
+ if (isMounted)
51
+ setCurrentDevice(newDevice);
52
+ });
53
+ }
54
+ }
55
+ });
56
+ return () => {
57
+ isMounted = false;
58
+ removeListener();
59
+ };
60
+ }, []);
61
+ /**
62
+ * Select a specific audio input device
63
+ * @param deviceId The ID of the device to select
64
+ * @returns Promise resolving to a boolean indicating success
65
+ */
66
+ const selectDevice = useCallback(async (deviceId) => {
67
+ try {
68
+ setLoading(true);
69
+ setError(null);
70
+ const success = await audioDeviceManager.selectDevice(deviceId);
71
+ if (success) {
72
+ // Get the updated current device after selection
73
+ const device = await audioDeviceManager.getCurrentDevice();
74
+ setCurrentDevice(device);
75
+ }
76
+ return success;
77
+ }
78
+ catch (err) {
79
+ console.error('Failed to select audio device:', err);
80
+ setError(err instanceof Error
81
+ ? err
82
+ : new Error('Failed to select audio device'));
83
+ return false;
84
+ }
85
+ finally {
86
+ setLoading(false);
87
+ }
88
+ }, []);
89
+ /**
90
+ * Reset to the default audio input device
91
+ * @returns Promise resolving to a boolean indicating success
92
+ */
93
+ const resetToDefaultDevice = useCallback(async () => {
94
+ try {
95
+ setLoading(true);
96
+ setError(null);
97
+ const success = await audioDeviceManager.resetToDefaultDevice();
98
+ if (success) {
99
+ // Get the updated current device after reset
100
+ const device = await audioDeviceManager.getCurrentDevice();
101
+ setCurrentDevice(device);
102
+ }
103
+ return success;
104
+ }
105
+ catch (err) {
106
+ console.error('Failed to reset to default audio device:', err);
107
+ setError(err instanceof Error
108
+ ? err
109
+ : new Error('Failed to reset to default audio device'));
110
+ return false;
111
+ }
112
+ finally {
113
+ setLoading(false);
114
+ }
115
+ }, []);
116
+ /**
117
+ * Refresh the list of available devices
118
+ */
119
+ const refreshDevices = useCallback(async () => {
120
+ try {
121
+ setLoading(true);
122
+ setError(null);
123
+ const updatedDevices = await audioDeviceManager.refreshDevices();
124
+ setDevices(updatedDevices);
125
+ // Also refresh the current device
126
+ const device = await audioDeviceManager.getCurrentDevice();
127
+ setCurrentDevice(device);
128
+ return updatedDevices;
129
+ }
130
+ catch (err) {
131
+ console.error('Failed to refresh audio devices:', err);
132
+ setError(err instanceof Error
133
+ ? err
134
+ : new Error('Failed to refresh audio devices'));
135
+ return [];
136
+ }
137
+ finally {
138
+ setLoading(false);
139
+ }
140
+ }, []);
141
+ return {
142
+ devices,
143
+ currentDevice,
144
+ loading,
145
+ error,
146
+ selectDevice,
147
+ resetToDefaultDevice,
148
+ refreshDevices,
149
+ };
150
+ }
151
+ //# sourceMappingURL=useAudioDevices.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAudioDevices.js","sourceRoot":"","sources":["../../src/hooks/useAudioDevices.ts"],"names":[],"mappings":"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","sourcesContent":["import { useCallback, useEffect, useState } from 'react'\n\nimport { audioDeviceManager } from '../AudioDeviceManager'\nimport { AudioDevice } from '../ExpoAudioStream.types'\n\n/**\n * React hook for managing audio input devices\n */\nexport function useAudioDevices() {\n const [devices, setDevices] = useState<AudioDevice[]>([])\n const [currentDevice, setCurrentDevice] = useState<AudioDevice | null>(null)\n const [loading, setLoading] = useState(true)\n const [error, setError] = useState<Error | null>(null)\n\n // Load devices on mount\n useEffect(() => {\n let isMounted = true\n\n const loadDevices = async () => {\n try {\n setLoading(true)\n setError(null)\n\n // Load available devices\n const availableDevices =\n await audioDeviceManager.getAvailableDevices()\n if (isMounted) setDevices(availableDevices)\n\n // Get current device\n const device = await audioDeviceManager.getCurrentDevice()\n if (isMounted) setCurrentDevice(device)\n } catch (err) {\n console.error('Failed to load audio devices:', err)\n if (isMounted)\n setError(\n err instanceof Error\n ? err\n : new Error('Failed to load audio devices')\n )\n } finally {\n if (isMounted) setLoading(false)\n }\n }\n\n loadDevices()\n\n // Set up device change listener\n const removeListener = audioDeviceManager.addDeviceChangeListener(\n (updatedDevices: AudioDevice[]) => {\n if (isMounted) {\n setDevices(updatedDevices)\n\n // If our current device is no longer available, update it\n if (\n currentDevice &&\n !updatedDevices.some(\n (d: AudioDevice) => d.id === currentDevice.id\n )\n ) {\n audioDeviceManager\n .getCurrentDevice()\n .then((newDevice: AudioDevice | null) => {\n if (isMounted) setCurrentDevice(newDevice)\n })\n }\n }\n }\n )\n\n return () => {\n isMounted = false\n removeListener()\n }\n }, [])\n\n /**\n * Select a specific audio input device\n * @param deviceId The ID of the device to select\n * @returns Promise resolving to a boolean indicating success\n */\n const selectDevice = useCallback(\n async (deviceId: string): Promise<boolean> => {\n try {\n setLoading(true)\n setError(null)\n\n const success = await audioDeviceManager.selectDevice(deviceId)\n\n if (success) {\n // Get the updated current device after selection\n const device = await audioDeviceManager.getCurrentDevice()\n setCurrentDevice(device)\n }\n\n return success\n } catch (err) {\n console.error('Failed to select audio device:', err)\n setError(\n err instanceof Error\n ? err\n : new Error('Failed to select audio device')\n )\n return false\n } finally {\n setLoading(false)\n }\n },\n []\n )\n\n /**\n * Reset to the default audio input device\n * @returns Promise resolving to a boolean indicating success\n */\n const resetToDefaultDevice = useCallback(async (): Promise<boolean> => {\n try {\n setLoading(true)\n setError(null)\n\n const success = await audioDeviceManager.resetToDefaultDevice()\n\n if (success) {\n // Get the updated current device after reset\n const device = await audioDeviceManager.getCurrentDevice()\n setCurrentDevice(device)\n }\n\n return success\n } catch (err) {\n console.error('Failed to reset to default audio device:', err)\n setError(\n err instanceof Error\n ? err\n : new Error('Failed to reset to default audio device')\n )\n return false\n } finally {\n setLoading(false)\n }\n }, [])\n\n /**\n * Refresh the list of available devices\n */\n const refreshDevices = useCallback(async (): Promise<AudioDevice[]> => {\n try {\n setLoading(true)\n setError(null)\n\n const updatedDevices = await audioDeviceManager.refreshDevices()\n setDevices(updatedDevices)\n\n // Also refresh the current device\n const device = await audioDeviceManager.getCurrentDevice()\n setCurrentDevice(device)\n\n return updatedDevices\n } catch (err) {\n console.error('Failed to refresh audio devices:', err)\n setError(\n err instanceof Error\n ? err\n : new Error('Failed to refresh audio devices')\n )\n return []\n } finally {\n setLoading(false)\n }\n }, [])\n\n return {\n devices,\n currentDevice,\n loading,\n error,\n selectDevice,\n resetToDefaultDevice,\n refreshDevices,\n }\n}\n"]}
package/build/index.d.ts CHANGED
@@ -9,6 +9,8 @@ import { useAudioRecorder } from './useAudioRecorder';
9
9
  export * from './utils/convertPCMToFloat32';
10
10
  export * from './utils/getWavFileInfo';
11
11
  export * from './utils/writeWavHeader';
12
+ export { AudioDeviceManager, audioDeviceManager } from './AudioDeviceManager';
13
+ export { useAudioDevices } from './hooks/useAudioDevices';
12
14
  export { AudioRecorderProvider, ExpoAudioStreamModule, extractRawWavAnalysis, extractAudioAnalysis, extractPreview, trimAudio, extractAudioData, extractMelSpectrogram, useAudioRecorder, useSharedAudioRecorder, };
13
15
  export type * from './AudioAnalysis/AudioAnalysis.types';
14
16
  export type * from './ExpoAudioStream.types';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACH,qBAAqB,EACrB,oBAAoB,EACvB,MAAM,sCAAsC,CAAA;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAA;AACnE,OAAO,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAA;AAC7E,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AAC/D,OAAO,EACH,qBAAqB,EACrB,sBAAsB,EACzB,MAAM,0BAA0B,CAAA;AACjC,OAAO,qBAAqB,MAAM,yBAAyB,CAAA;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAErD,cAAc,6BAA6B,CAAA;AAC3C,cAAc,wBAAwB,CAAA;AACtC,cAAc,wBAAwB,CAAA;AAEtC,OAAO,EACH,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,oBAAoB,EACpB,cAAc,EACd,SAAS,EACT,gBAAgB,EAChB,qBAAqB,EACrB,gBAAgB,EAChB,sBAAsB,GACzB,CAAA;AAED,mBAAmB,qCAAqC,CAAA;AACxD,mBAAmB,yBAAyB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACH,qBAAqB,EACrB,oBAAoB,EACvB,MAAM,sCAAsC,CAAA;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAA;AACnE,OAAO,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAA;AAC7E,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AAC/D,OAAO,EACH,qBAAqB,EACrB,sBAAsB,EACzB,MAAM,0BAA0B,CAAA;AACjC,OAAO,qBAAqB,MAAM,yBAAyB,CAAA;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAErD,cAAc,6BAA6B,CAAA;AAC3C,cAAc,wBAAwB,CAAA;AACtC,cAAc,wBAAwB,CAAA;AAGtC,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AAG7E,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAEzD,OAAO,EACH,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,oBAAoB,EACpB,cAAc,EACd,SAAS,EACT,gBAAgB,EAChB,qBAAqB,EACrB,gBAAgB,EAChB,sBAAsB,GACzB,CAAA;AAED,mBAAmB,qCAAqC,CAAA;AACxD,mBAAmB,yBAAyB,CAAA"}
package/build/index.js CHANGED
@@ -10,5 +10,9 @@ import { useAudioRecorder } from './useAudioRecorder';
10
10
  export * from './utils/convertPCMToFloat32';
11
11
  export * from './utils/getWavFileInfo';
12
12
  export * from './utils/writeWavHeader';
13
+ // Export AudioDeviceManager
14
+ export { AudioDeviceManager, audioDeviceManager } from './AudioDeviceManager';
15
+ // Export useAudioDevices hook
16
+ export { useAudioDevices } from './hooks/useAudioDevices';
13
17
  export { AudioRecorderProvider, ExpoAudioStreamModule, extractRawWavAnalysis, extractAudioAnalysis, extractPreview, trimAudio, extractAudioData, extractMelSpectrogram, useAudioRecorder, useSharedAudioRecorder, };
14
18
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,eAAe;AAEf,OAAO,EACH,qBAAqB,EACrB,oBAAoB,GACvB,MAAM,sCAAsC,CAAA;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAA;AACnE,OAAO,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAA;AAC7E,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AAC/D,OAAO,EACH,qBAAqB,EACrB,sBAAsB,GACzB,MAAM,0BAA0B,CAAA;AACjC,OAAO,qBAAqB,MAAM,yBAAyB,CAAA;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAErD,cAAc,6BAA6B,CAAA;AAC3C,cAAc,wBAAwB,CAAA;AACtC,cAAc,wBAAwB,CAAA;AAEtC,OAAO,EACH,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,oBAAoB,EACpB,cAAc,EACd,SAAS,EACT,gBAAgB,EAChB,qBAAqB,EACrB,gBAAgB,EAChB,sBAAsB,GACzB,CAAA","sourcesContent":["// src/index.ts\n\nimport {\n extractRawWavAnalysis,\n extractAudioAnalysis,\n} from './AudioAnalysis/extractAudioAnalysis'\nimport { extractAudioData } from './AudioAnalysis/extractAudioData'\nimport { extractMelSpectrogram } from './AudioAnalysis/extractMelSpectrogram'\nimport { extractPreview } from './AudioAnalysis/extractPreview'\nimport {\n AudioRecorderProvider,\n useSharedAudioRecorder,\n} from './AudioRecorder.provider'\nimport ExpoAudioStreamModule from './ExpoAudioStreamModule'\nimport { trimAudio } from './trimAudio'\nimport { useAudioRecorder } from './useAudioRecorder'\n\nexport * from './utils/convertPCMToFloat32'\nexport * from './utils/getWavFileInfo'\nexport * from './utils/writeWavHeader'\n\nexport {\n AudioRecorderProvider,\n ExpoAudioStreamModule,\n extractRawWavAnalysis,\n extractAudioAnalysis,\n extractPreview,\n trimAudio,\n extractAudioData,\n extractMelSpectrogram,\n useAudioRecorder,\n useSharedAudioRecorder,\n}\n\nexport type * from './AudioAnalysis/AudioAnalysis.types'\nexport type * from './ExpoAudioStream.types'\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,eAAe;AAEf,OAAO,EACH,qBAAqB,EACrB,oBAAoB,GACvB,MAAM,sCAAsC,CAAA;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAA;AACnE,OAAO,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAA;AAC7E,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AAC/D,OAAO,EACH,qBAAqB,EACrB,sBAAsB,GACzB,MAAM,0BAA0B,CAAA;AACjC,OAAO,qBAAqB,MAAM,yBAAyB,CAAA;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAErD,cAAc,6BAA6B,CAAA;AAC3C,cAAc,wBAAwB,CAAA;AACtC,cAAc,wBAAwB,CAAA;AAEtC,4BAA4B;AAC5B,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AAE7E,8BAA8B;AAC9B,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAEzD,OAAO,EACH,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,oBAAoB,EACpB,cAAc,EACd,SAAS,EACT,gBAAgB,EAChB,qBAAqB,EACrB,gBAAgB,EAChB,sBAAsB,GACzB,CAAA","sourcesContent":["// src/index.ts\n\nimport {\n extractRawWavAnalysis,\n extractAudioAnalysis,\n} from './AudioAnalysis/extractAudioAnalysis'\nimport { extractAudioData } from './AudioAnalysis/extractAudioData'\nimport { extractMelSpectrogram } from './AudioAnalysis/extractMelSpectrogram'\nimport { extractPreview } from './AudioAnalysis/extractPreview'\nimport {\n AudioRecorderProvider,\n useSharedAudioRecorder,\n} from './AudioRecorder.provider'\nimport ExpoAudioStreamModule from './ExpoAudioStreamModule'\nimport { trimAudio } from './trimAudio'\nimport { useAudioRecorder } from './useAudioRecorder'\n\nexport * from './utils/convertPCMToFloat32'\nexport * from './utils/getWavFileInfo'\nexport * from './utils/writeWavHeader'\n\n// Export AudioDeviceManager\nexport { AudioDeviceManager, audioDeviceManager } from './AudioDeviceManager'\n\n// Export useAudioDevices hook\nexport { useAudioDevices } from './hooks/useAudioDevices'\n\nexport {\n AudioRecorderProvider,\n ExpoAudioStreamModule,\n extractRawWavAnalysis,\n extractAudioAnalysis,\n extractPreview,\n trimAudio,\n extractAudioData,\n extractMelSpectrogram,\n useAudioRecorder,\n useSharedAudioRecorder,\n}\n\nexport type * from './AudioAnalysis/AudioAnalysis.types'\nexport type * from './ExpoAudioStream.types'\n"]}
@@ -6,6 +6,7 @@ export interface UseAudioRecorderProps {
6
6
  featuresExtratorUrl?: string;
7
7
  }
8
8
  export interface UseAudioRecorderState {
9
+ prepareRecording: (_: RecordingConfig) => Promise<void>;
9
10
  startRecording: (_: RecordingConfig) => Promise<StartRecordingResult>;
10
11
  stopRecording: () => Promise<AudioRecording>;
11
12
  pauseRecording: () => Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"useAudioRecorder.d.ts","sourceRoot":"","sources":["../src/useAudioRecorder.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAA;AACnE,OAAO,EAEH,cAAc,EAEd,eAAe,EACf,WAAW,EACX,eAAe,EACf,oBAAoB,EACvB,MAAM,yBAAyB,CAAA;AAShC,MAAM,WAAW,qBAAqB;IAClC,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAC/B;AAED,MAAM,WAAW,qBAAqB;IAClC,cAAc,EAAE,CAAC,CAAC,EAAE,eAAe,KAAK,OAAO,CAAC,oBAAoB,CAAC,CAAA;IACrE,aAAa,EAAE,MAAM,OAAO,CAAC,cAAc,CAAC,CAAA;IAC5C,cAAc,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IACnC,eAAe,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IACpC,WAAW,EAAE,OAAO,CAAA;IACpB,QAAQ,EAAE,OAAO,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,CAAC,EAAE,eAAe,CAAA;IAC7B,YAAY,CAAC,EAAE,aAAa,CAAA;CAC/B;AAkHD,wBAAgB,gBAAgB,CAAC,EAC7B,MAAM,EACN,eAAe,EACf,mBAAmB,GACtB,GAAE,qBAA0B,GAAG,qBAAqB,CA8cpD"}
1
+ {"version":3,"file":"useAudioRecorder.d.ts","sourceRoot":"","sources":["../src/useAudioRecorder.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAA;AACnE,OAAO,EAEH,cAAc,EAEd,eAAe,EACf,WAAW,EACX,eAAe,EACf,oBAAoB,EACvB,MAAM,yBAAyB,CAAA;AAShC,MAAM,WAAW,qBAAqB;IAClC,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAC/B;AAED,MAAM,WAAW,qBAAqB;IAClC,gBAAgB,EAAE,CAAC,CAAC,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACvD,cAAc,EAAE,CAAC,CAAC,EAAE,eAAe,KAAK,OAAO,CAAC,oBAAoB,CAAC,CAAA;IACrE,aAAa,EAAE,MAAM,OAAO,CAAC,cAAc,CAAC,CAAA;IAC5C,cAAc,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IACnC,eAAe,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IACpC,WAAW,EAAE,OAAO,CAAA;IACpB,QAAQ,EAAE,OAAO,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,CAAC,EAAE,eAAe,CAAA;IAC7B,YAAY,CAAC,EAAE,aAAa,CAAA;CAC/B;AAkHD,wBAAgB,gBAAgB,CAAC,EAC7B,MAAM,EACN,eAAe,EACf,mBAAmB,GACtB,GAAE,qBAA0B,GAAG,qBAAqB,CAuepD"}
@@ -159,7 +159,7 @@ export function useAudioRecorder({ logger, audioWorkletUrl, featuresExtratorUrl,
159
159
  min: newMin,
160
160
  max: newMax,
161
161
  };
162
- logger?.debug(`[handleAudioAnalysis] Updated analysis data: durationMs=${savedAnalysisData.durationMs}`, savedAnalysisData);
162
+ logger?.debug(`[handleAudioAnalysis] Updated analysis data: durationMs=${savedAnalysisData.durationMs}`, { dataPoints: savedAnalysisData.dataPoints.length });
163
163
  // Call the onAudioAnalysis callback if it exists in the recording config
164
164
  if (recordingConfigRef.current?.onAudioAnalysis) {
165
165
  recordingConfigRef.current
@@ -337,6 +337,24 @@ export function useAudioRecorder({ logger, audioWorkletUrl, featuresExtratorUrl,
337
337
  }
338
338
  return startResult;
339
339
  }, [handleAudioAnalysis, dispatch]);
340
+ const prepareRecording = useCallback(async (recordingOptions) => {
341
+ recordingConfigRef.current = recordingOptions;
342
+ logger?.debug(`preparing recording`, recordingOptions);
343
+ analysisRef.current = { ...defaultAnalysis }; // Reset analysis data
344
+ fullAnalysisRef.current = { ...defaultAnalysis };
345
+ const { onAudioStream, ...options } = recordingOptions;
346
+ // Store onAudioStream for later use when recording starts
347
+ if (typeof onAudioStream === 'function') {
348
+ onAudioStreamRef.current = onAudioStream;
349
+ }
350
+ else {
351
+ logger?.warn(`onAudioStream is not a function`, onAudioStream);
352
+ onAudioStreamRef.current = null;
353
+ }
354
+ // Call the native prepareRecording method
355
+ await ExpoAudioStream.prepareRecording(options);
356
+ logger?.debug(`recording prepared successfully`);
357
+ }, []);
340
358
  const stopRecording = useCallback(async () => {
341
359
  logger?.debug(`stoping recording`);
342
360
  const stopResult = await ExpoAudioStream.stopRecording();
@@ -412,6 +430,7 @@ export function useAudioRecorder({ logger, audioWorkletUrl, featuresExtratorUrl,
412
430
  };
413
431
  }, []); // Empty dependency array since we want this to run once
414
432
  return {
433
+ prepareRecording,
415
434
  startRecording,
416
435
  stopRecording,
417
436
  pauseRecording,