@siteed/audio-studio 3.2.1-beta.1 → 3.2.1-beta.2

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 (29) hide show
  1. package/CHANGELOG.md +12 -1
  2. package/README.md +12 -1
  3. package/build/cjs/AudioStudio.types.js.map +1 -1
  4. package/build/cjs/useAudioRecorder.js +115 -93
  5. package/build/cjs/useAudioRecorder.js.map +1 -1
  6. package/build/cjs/utils/nativeRecordingOptions.js +13 -0
  7. package/build/cjs/utils/nativeRecordingOptions.js.map +1 -0
  8. package/build/cjs/utils/nativeRecordingOptions.test.js +30 -0
  9. package/build/cjs/utils/nativeRecordingOptions.test.js.map +1 -0
  10. package/build/esm/AudioStudio.types.js.map +1 -1
  11. package/build/esm/useAudioRecorder.js +115 -93
  12. package/build/esm/useAudioRecorder.js.map +1 -1
  13. package/build/esm/utils/nativeRecordingOptions.js +10 -0
  14. package/build/esm/utils/nativeRecordingOptions.js.map +1 -0
  15. package/build/esm/utils/nativeRecordingOptions.test.js +28 -0
  16. package/build/esm/utils/nativeRecordingOptions.test.js.map +1 -0
  17. package/build/types/AudioStudio.types.d.ts +19 -5
  18. package/build/types/AudioStudio.types.d.ts.map +1 -1
  19. package/build/types/useAudioRecorder.d.ts +2 -1
  20. package/build/types/useAudioRecorder.d.ts.map +1 -1
  21. package/build/types/utils/nativeRecordingOptions.d.ts +28 -0
  22. package/build/types/utils/nativeRecordingOptions.d.ts.map +1 -0
  23. package/build/types/utils/nativeRecordingOptions.test.d.ts +2 -0
  24. package/build/types/utils/nativeRecordingOptions.test.d.ts.map +1 -0
  25. package/package.json +1 -1
  26. package/src/AudioStudio.types.ts +27 -5
  27. package/src/useAudioRecorder.tsx +161 -126
  28. package/src/utils/nativeRecordingOptions.test.ts +29 -0
  29. package/src/utils/nativeRecordingOptions.ts +20 -0
@@ -5,7 +5,7 @@ import { audioDeviceManager } from './AudioDeviceManager';
5
5
  import AudioStudioModule from './AudioStudioModule';
6
6
  import { validateRecordingConfig } from './constants/platformLimitations';
7
7
  import { addAudioAnalysisListener, addAudioEventListener, addMaxDurationReachedListener, addRecordingInterruptionListener, } from './events';
8
- import { cleanNativeOptions } from './utils/cleanNativeOptions';
8
+ import { createNativeRecordingOptions } from './utils/nativeRecordingOptions';
9
9
  const defaultAnalysis = {
10
10
  segmentDurationMs: 100,
11
11
  bitDepth: 32,
@@ -24,6 +24,31 @@ const defaultAnalysis = {
24
24
  },
25
25
  extractionTimeMs: 0,
26
26
  };
27
+ function finiteOrZero(value) {
28
+ return Number.isFinite(value) ? value : 0;
29
+ }
30
+ function sanitizeSerializableValue(value) {
31
+ if (typeof value === 'number') {
32
+ return finiteOrZero(value);
33
+ }
34
+ if (Array.isArray(value)) {
35
+ return value.map((item) => sanitizeSerializableValue(item));
36
+ }
37
+ if (value && typeof value === 'object') {
38
+ const sanitized = {};
39
+ for (const [key, nestedValue] of Object.entries(value)) {
40
+ sanitized[key] = sanitizeSerializableValue(nestedValue);
41
+ }
42
+ return sanitized;
43
+ }
44
+ return value;
45
+ }
46
+ function createSerializableAnalysis(analysis) {
47
+ return sanitizeSerializableValue(analysis);
48
+ }
49
+ function createRecordingSnapshot(recording) {
50
+ return sanitizeSerializableValue(recording);
51
+ }
27
52
  function audioRecorderReducer(state, action) {
28
53
  switch (action.type) {
29
54
  case 'START':
@@ -37,6 +62,7 @@ function audioRecorderReducer(state, action) {
37
62
  analysisData: defaultAnalysis,
38
63
  maxDurationMs: undefined,
39
64
  maxDurationReached: false,
65
+ lastRecordingReason: undefined,
40
66
  };
41
67
  case 'STOP':
42
68
  return {
@@ -47,6 +73,7 @@ function audioRecorderReducer(state, action) {
47
73
  size: 0,
48
74
  compression: undefined,
49
75
  analysisData: undefined,
76
+ lastRecordingReason: action.payload.reason,
50
77
  // Preserve max-duration state after stop so UI and agentic
51
78
  // validation can explain why recording ended. START resets it.
52
79
  };
@@ -110,6 +137,7 @@ export function useAudioRecorder({ logger, audioWorkletUrl, featuresExtratorUrl,
110
137
  analysisData: undefined,
111
138
  maxDurationMs: undefined,
112
139
  maxDurationReached: false,
140
+ lastRecordingReason: undefined,
113
141
  });
114
142
  const startResultRef = useRef(null);
115
143
  const analysisListenerRef = useRef(null);
@@ -139,6 +167,7 @@ export function useAudioRecorder({ logger, audioWorkletUrl, featuresExtratorUrl,
139
167
  });
140
168
  const recordingConfigRef = useRef(null);
141
169
  const maxDurationHandledRef = useRef(false);
170
+ const stopFinalizationRef = useRef(null);
142
171
  // Generate unique instance ID for debugging
143
172
  const instanceId = useId().replace(/:/g, '').slice(0, 5);
144
173
  const handleAudioAnalysis = useCallback(async ({ analysis, visualizationDuration, }) => {
@@ -304,6 +333,60 @@ export function useAudioRecorder({ logger, audioWorkletUrl, featuresExtratorUrl,
304
333
  logger?.error(`Error processing audio event:`, error);
305
334
  }
306
335
  }, []);
336
+ const finalizeRecordingStop = useCallback(async (reason) => {
337
+ if (stopFinalizationRef.current) {
338
+ return stopFinalizationRef.current;
339
+ }
340
+ const finalizePromise = (async () => {
341
+ const nativeStopResult = await audioStudio.stopRecording();
342
+ if (!nativeStopResult) {
343
+ throw new Error('Failed to stop recording');
344
+ }
345
+ const stopResult = createRecordingSnapshot(nativeStopResult);
346
+ if (shouldKeepFullAnalysis(recordingConfigRef.current)) {
347
+ stopResult.analysisData = createSerializableAnalysis(fullAnalysisRef.current);
348
+ }
349
+ else {
350
+ // `keepFullAnalysis` is a hook-level retention policy. If a platform
351
+ // starts returning native analysisData in the future, keep opt-out
352
+ // semantics explicit and avoid leaking a full history here.
353
+ delete stopResult.analysisData;
354
+ }
355
+ if (analysisListenerRef.current) {
356
+ analysisListenerRef.current.remove();
357
+ analysisListenerRef.current = null;
358
+ }
359
+ onAudioStreamRef.current = null;
360
+ stateRef.current.isRecording = false;
361
+ stateRef.current.isPaused = false;
362
+ // Note: We deliberately DON'T clear recordingConfigRef here to preserve callbacks.
363
+ logger?.debug(`recording stopped`, stopResult);
364
+ maxDurationHandledRef.current = false;
365
+ dispatch({
366
+ type: 'STOP',
367
+ payload: { reason },
368
+ });
369
+ const stoppedCallback = recordingConfigRef.current?.onRecordingStopped;
370
+ if (stoppedCallback) {
371
+ try {
372
+ void Promise.resolve(stoppedCallback(stopResult, reason)).catch((error) => {
373
+ logger?.error(`Error in recording stopped callback:`, error);
374
+ });
375
+ }
376
+ catch (error) {
377
+ logger?.error(`Error in recording stopped callback:`, error);
378
+ }
379
+ }
380
+ return stopResult;
381
+ })();
382
+ stopFinalizationRef.current = finalizePromise;
383
+ try {
384
+ return await finalizePromise;
385
+ }
386
+ finally {
387
+ stopFinalizationRef.current = null;
388
+ }
389
+ }, [audioStudio, dispatch, logger]);
307
390
  const handleMaxDurationReached = useCallback(async (event) => {
308
391
  if (maxDurationHandledRef.current) {
309
392
  return;
@@ -326,68 +409,15 @@ export function useAudioRecorder({ logger, audioWorkletUrl, featuresExtratorUrl,
326
409
  catch (error) {
327
410
  logger?.error(`Error in max duration callback:`, error);
328
411
  }
329
- const finishStoppedState = () => {
330
- if (analysisListenerRef.current) {
331
- analysisListenerRef.current.remove();
332
- analysisListenerRef.current = null;
333
- }
334
- onAudioStreamRef.current = null;
335
- stateRef.current.isRecording = false;
336
- stateRef.current.isPaused = false;
337
- dispatch({ type: 'STOP' });
338
- };
339
- const waitForPlatformAutoStop = async () => {
340
- const timeoutMs = 3000;
341
- const startedAt = Date.now();
342
- let lastStatus;
343
- while (Date.now() - startedAt < timeoutMs) {
344
- await new Promise((resolve) => setTimeout(resolve, 50));
345
- try {
346
- const currentStatus = audioStudio.status();
347
- lastStatus = currentStatus;
348
- if (!currentStatus.isRecording &&
349
- !currentStatus.isPaused) {
350
- finishStoppedState();
351
- return;
352
- }
353
- }
354
- catch (error) {
355
- logger?.warn(`Error checking status after max duration auto-stop:`, error);
356
- break;
357
- }
358
- }
359
- if (lastStatus &&
360
- (lastStatus.isRecording || lastStatus.isPaused)) {
361
- try {
362
- await audioStudio.stopRecording();
363
- }
364
- catch (error) {
365
- logger?.warn(`Error completing max duration auto-stop fallback:`, error);
366
- }
367
- }
368
- // At this point platform-owned auto-stop did not settle cleanly.
369
- // Clear hook state so the UI does not stay stuck as recording.
370
- finishStoppedState();
371
- };
372
- // Only the original event tells us whether the platform already
373
- // owns auto-stop. Keep stream callbacks alive until status confirms
374
- // stop completion so native final audio flushes can still reach JS.
375
- if (event.autoStopped && stateRef.current.isRecording) {
376
- await waitForPlatformAutoStop();
377
- return;
378
- }
379
- if (config?.autoStopOnMaxDuration &&
380
- !event.autoStopped &&
381
- stateRef.current.isRecording) {
412
+ if (config?.autoStopOnMaxDuration && stateRef.current.isRecording) {
382
413
  try {
383
- await audioStudio.stopRecording();
384
- finishStoppedState();
414
+ await finalizeRecordingStop('maxDuration');
385
415
  }
386
416
  catch (error) {
387
417
  logger?.error(`Error auto-stopping on max duration:`, error);
388
418
  }
389
419
  }
390
- }, [audioStudio, dispatch, logger]);
420
+ }, [dispatch, finalizeRecordingStop, logger]);
391
421
  const checkStatus = useCallback(async () => {
392
422
  try {
393
423
  const status = audioStudio.status();
@@ -415,25 +445,34 @@ export function useAudioRecorder({ logger, audioWorkletUrl, featuresExtratorUrl,
415
445
  },
416
446
  });
417
447
  }
448
+ const statusMaxDurationReached = status.maxDurationReached ?? false;
449
+ const preserveStoppedMaxDuration = !status.isRecording &&
450
+ !status.isPaused &&
451
+ stateRef.current.maxDurationReached &&
452
+ !statusMaxDurationReached;
453
+ const nextMaxDurationMs = preserveStoppedMaxDuration
454
+ ? stateRef.current.maxDurationMs
455
+ : status.maxDurationMs;
456
+ const nextMaxDurationReached = preserveStoppedMaxDuration
457
+ ? true
458
+ : statusMaxDurationReached;
418
459
  if (status.durationMs !== stateRef.current.durationMs ||
419
460
  status.size !== stateRef.current.size ||
420
- status.maxDurationMs !== stateRef.current.maxDurationMs ||
421
- status.maxDurationReached !==
422
- stateRef.current.maxDurationReached) {
461
+ nextMaxDurationMs !== stateRef.current.maxDurationMs ||
462
+ nextMaxDurationReached !== stateRef.current.maxDurationReached) {
423
463
  stateRef.current.durationMs = status.durationMs;
424
464
  stateRef.current.size = status.size;
425
465
  stateRef.current.compression = status.compression;
426
- stateRef.current.maxDurationMs = status.maxDurationMs;
427
- stateRef.current.maxDurationReached =
428
- status.maxDurationReached ?? false;
466
+ stateRef.current.maxDurationMs = nextMaxDurationMs;
467
+ stateRef.current.maxDurationReached = nextMaxDurationReached;
429
468
  dispatch({
430
469
  type: 'UPDATE_STATUS',
431
470
  payload: {
432
471
  durationMs: status.durationMs,
433
472
  size: status.size,
434
473
  compression: status.compression,
435
- maxDurationMs: status.maxDurationMs,
436
- maxDurationReached: status.maxDurationReached,
474
+ maxDurationMs: nextMaxDurationMs,
475
+ maxDurationReached: nextMaxDurationReached,
437
476
  },
438
477
  });
439
478
  }
@@ -483,8 +522,7 @@ export function useAudioRecorder({ logger, audioWorkletUrl, featuresExtratorUrl,
483
522
  logger?.debug(`start recording with validated config`, validatedOptions);
484
523
  analysisRef.current = { ...defaultAnalysis }; // Reset analysis data
485
524
  fullAnalysisRef.current = { ...defaultAnalysis };
486
- const { onAudioStream, onRecordingInterrupted, onMaxDurationReached, onAudioAnalysis, keepFullAnalysis: _keepFullAnalysis, ...options } = validatedOptions;
487
- const { enableProcessing } = options;
525
+ const { onAudioStream, enableProcessing } = validatedOptions;
488
526
  const maxRecentDataDuration = 10000; // TODO compute maxRecentDataDuration based on screen dimensions
489
527
  if (typeof onAudioStream === 'function') {
490
528
  onAudioStreamRef.current = onAudioStream;
@@ -493,8 +531,10 @@ export function useAudioRecorder({ logger, audioWorkletUrl, featuresExtratorUrl,
493
531
  logger?.warn(`onAudioStream is not a function`, onAudioStream);
494
532
  onAudioStreamRef.current = null;
495
533
  }
496
- // Strip undefined values and functions that can't cross the native bridge
497
- const cleanOptions = cleanNativeOptions(options);
534
+ // Strip hook-only values and undefineds that can't cross the native bridge.
535
+ // autoStopOnMaxDuration stays hook-owned so finalization can expose
536
+ // the same AudioRecording result as a manual stop.
537
+ const cleanOptions = createNativeRecordingOptions(validatedOptions);
498
538
  const startResult = await audioStudio.startRecording(cleanOptions);
499
539
  dispatch({ type: 'START' });
500
540
  startResultRef.current = startResult;
@@ -520,7 +560,7 @@ export function useAudioRecorder({ logger, audioWorkletUrl, featuresExtratorUrl,
520
560
  logger?.debug(`preparing recording`, recordingOptions);
521
561
  analysisRef.current = { ...defaultAnalysis }; // Reset analysis data
522
562
  fullAnalysisRef.current = { ...defaultAnalysis };
523
- const { onAudioStream, onRecordingInterrupted, onMaxDurationReached, onAudioAnalysis, keepFullAnalysis: _keepFullAnalysis, ...options } = recordingOptions;
563
+ const { onAudioStream } = recordingOptions;
524
564
  // Store onAudioStream for later use when recording starts
525
565
  if (typeof onAudioStream === 'function') {
526
566
  onAudioStreamRef.current = onAudioStream;
@@ -529,35 +569,16 @@ export function useAudioRecorder({ logger, audioWorkletUrl, featuresExtratorUrl,
529
569
  logger?.warn(`onAudioStream is not a function`, onAudioStream);
530
570
  onAudioStreamRef.current = null;
531
571
  }
532
- // Strip undefined values and functions that can't cross the native bridge
533
- const cleanOptions = cleanNativeOptions(options);
572
+ // Strip hook-only values and undefineds that can't cross the native bridge.
573
+ const cleanOptions = createNativeRecordingOptions(recordingOptions);
534
574
  // Call the native prepareRecording method
535
575
  await audioStudio.prepareRecording(cleanOptions);
536
576
  logger?.debug(`recording prepared successfully`);
537
577
  }, []);
538
578
  const stopRecording = useCallback(async () => {
539
579
  logger?.debug(`stoping recording`);
540
- const stopResult = await audioStudio.stopRecording();
541
- if (shouldKeepFullAnalysis(recordingConfigRef.current)) {
542
- stopResult.analysisData = fullAnalysisRef.current;
543
- }
544
- else {
545
- // `keepFullAnalysis` is a hook-level retention policy. If a platform
546
- // starts returning native analysisData in the future, keep opt-out
547
- // semantics explicit and avoid leaking a full history here.
548
- delete stopResult.analysisData;
549
- }
550
- if (analysisListenerRef.current) {
551
- analysisListenerRef.current.remove();
552
- analysisListenerRef.current = null;
553
- }
554
- onAudioStreamRef.current = null;
555
- // Note: We deliberately DON'T clear recordingConfigRef here to preserve interruption callback
556
- logger?.debug(`recording stopped`, stopResult);
557
- maxDurationHandledRef.current = false;
558
- dispatch({ type: 'STOP' });
559
- return stopResult;
560
- }, [dispatch]);
580
+ return finalizeRecordingStop('manual');
581
+ }, [finalizeRecordingStop, logger]);
561
582
  const pauseRecording = useCallback(async () => {
562
583
  logger?.debug(`pause recording`);
563
584
  const pauseResult = await audioStudio.pauseRecording();
@@ -677,6 +698,7 @@ export function useAudioRecorder({ logger, audioWorkletUrl, featuresExtratorUrl,
677
698
  analysisData: state.analysisData,
678
699
  maxDurationMs: state.maxDurationMs,
679
700
  maxDurationReached: state.maxDurationReached,
701
+ lastRecordingReason: state.lastRecordingReason,
680
702
  };
681
703
  }
682
704
  //# sourceMappingURL=useAudioRecorder.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useAudioRecorder.js","sourceRoot":"","sources":["../../src/useAudioRecorder.tsx"],"names":[],"mappings":"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","sourcesContent":["// src/useAudioRecorder.ts\nimport { EventSubscription, Platform } from 'expo-modules-core'\nimport { useCallback, useEffect, useReducer, useRef, useId } from 'react'\n\nimport { AudioAnalysis } from './AudioAnalysis/AudioAnalysis.types'\nimport { audioDeviceManager } from './AudioDeviceManager'\nimport {\n AudioDataEvent,\n AudioRecording,\n AudioStreamStatus,\n CompressionInfo,\n ConsoleLike,\n MaxDurationReachedEvent,\n RecordingConfig,\n StartRecordingResult,\n} from './AudioStudio.types'\nimport AudioStudioModule from './AudioStudioModule'\nimport { validateRecordingConfig } from './constants/platformLimitations'\nimport {\n addAudioAnalysisListener,\n addAudioEventListener,\n AudioEventPayload,\n addMaxDurationReachedListener,\n addRecordingInterruptionListener,\n} from './events'\nimport { cleanNativeOptions } from './utils/cleanNativeOptions'\n\nexport interface UseAudioRecorderProps {\n logger?: ConsoleLike\n audioWorkletUrl?: string\n featuresExtratorUrl?: string\n}\n\nexport interface UseAudioRecorderState {\n prepareRecording: (_: RecordingConfig) => Promise<void>\n startRecording: (_: RecordingConfig) => Promise<StartRecordingResult>\n stopRecording: () => Promise<AudioRecording>\n pauseRecording: () => Promise<void>\n resumeRecording: () => Promise<void>\n isRecording: boolean\n isPaused: boolean\n durationMs: number\n size: number\n compression?: CompressionInfo\n analysisData?: AudioAnalysis\n maxDurationMs?: number\n maxDurationReached?: boolean\n}\n\ninterface RecorderReducerState {\n isRecording: boolean\n isPaused: boolean\n durationMs: number\n size: number\n compression?: CompressionInfo\n analysisData?: AudioAnalysis\n maxDurationMs?: number\n maxDurationReached?: boolean\n}\n\ntype RecorderAction =\n | { type: 'START' | 'STOP' | 'PAUSE' | 'RESUME' }\n | {\n type: 'UPDATE_RECORDING_STATE'\n payload: {\n isRecording: boolean\n isPaused: boolean\n }\n }\n | {\n type: 'UPDATE_STATUS'\n payload: {\n durationMs: number\n size: number\n compression?: CompressionInfo\n maxDurationMs?: number\n maxDurationReached?: boolean\n }\n }\n | {\n type: 'MAX_DURATION_REACHED'\n payload: MaxDurationReachedEvent\n }\n | { type: 'UPDATE_ANALYSIS'; payload: AudioAnalysis }\n\nconst defaultAnalysis: AudioAnalysis = {\n segmentDurationMs: 100,\n bitDepth: 32,\n numberOfChannels: 1,\n durationMs: 0,\n sampleRate: 44100,\n samples: 0,\n dataPoints: [],\n rmsRange: {\n min: Number.POSITIVE_INFINITY,\n max: Number.NEGATIVE_INFINITY,\n },\n amplitudeRange: {\n min: Number.POSITIVE_INFINITY,\n max: Number.NEGATIVE_INFINITY,\n },\n extractionTimeMs: 0,\n}\n\nfunction audioRecorderReducer(\n state: RecorderReducerState,\n action: RecorderAction\n): RecorderReducerState {\n switch (action.type) {\n case 'START':\n return {\n ...state,\n isRecording: true,\n isPaused: false,\n durationMs: 0,\n size: 0,\n compression: undefined,\n analysisData: defaultAnalysis,\n maxDurationMs: undefined,\n maxDurationReached: false,\n }\n case 'STOP':\n return {\n ...state,\n isRecording: false,\n isPaused: false,\n durationMs: 0,\n size: 0,\n compression: undefined,\n analysisData: undefined,\n // Preserve max-duration state after stop so UI and agentic\n // validation can explain why recording ended. START resets it.\n }\n case 'PAUSE':\n return { ...state, isPaused: true, isRecording: false }\n case 'RESUME':\n return { ...state, isPaused: false, isRecording: true }\n case 'UPDATE_RECORDING_STATE':\n return {\n ...state,\n isPaused: action.payload.isPaused,\n isRecording: action.payload.isRecording,\n }\n case 'UPDATE_STATUS': {\n const newState = {\n ...state,\n durationMs: action.payload.durationMs,\n size: action.payload.size,\n compression: action.payload.compression\n ? {\n size: action.payload.compression.size,\n mimeType: action.payload.compression.mimeType,\n bitrate: action.payload.compression.bitrate,\n format: action.payload.compression.format,\n }\n : undefined,\n maxDurationMs: action.payload.maxDurationMs,\n maxDurationReached: action.payload.maxDurationReached,\n }\n return newState\n }\n case 'MAX_DURATION_REACHED':\n return {\n ...state,\n maxDurationMs: action.payload.maxDurationMs,\n maxDurationReached: true,\n }\n case 'UPDATE_ANALYSIS':\n return {\n ...state,\n analysisData: action.payload,\n }\n default:\n return state\n }\n}\n\ninterface HandleAudioAnalysisProps {\n analysis: AudioAnalysis\n visualizationDuration: number\n}\n\nfunction shouldKeepFullAnalysis(config?: RecordingConfig | null): boolean {\n return config?.keepFullAnalysis !== false\n}\n\nexport function useAudioRecorder({\n logger,\n audioWorkletUrl,\n featuresExtratorUrl,\n}: UseAudioRecorderProps = {}): UseAudioRecorderState {\n // Initialize AudioDeviceManager with logger (once)\n if (logger) {\n audioDeviceManager.setLogger(logger)\n }\n const [state, dispatch] = useReducer(audioRecorderReducer, {\n isRecording: false,\n isPaused: false,\n durationMs: 0,\n size: 0,\n compression: undefined,\n analysisData: undefined,\n maxDurationMs: undefined,\n maxDurationReached: false,\n })\n\n const startResultRef = useRef<StartRecordingResult | null>(null)\n\n const analysisListenerRef = useRef<EventSubscription | null>(null)\n // analysisRef is the current analysis data (last 10 seconds by default)\n const analysisRef = useRef<AudioAnalysis>({ ...defaultAnalysis })\n // fullAnalysisRef is the full analysis data (all data points)\n const fullAnalysisRef = useRef<AudioAnalysis>({\n ...defaultAnalysis,\n })\n\n // Instantiate the module for web with URLs\n const audioStudio =\n Platform.OS === 'web'\n ? AudioStudioModule({\n audioWorkletUrl,\n featuresExtratorUrl,\n logger,\n })\n : AudioStudioModule\n\n const onAudioStreamRef = useRef<\n ((_: AudioDataEvent) => Promise<void>) | null\n >(null)\n\n const stateRef = useRef({\n isRecording: false,\n isPaused: false,\n durationMs: 0,\n size: 0,\n compression: undefined as CompressionInfo | undefined,\n maxDurationMs: undefined as number | undefined,\n maxDurationReached: false,\n })\n\n const recordingConfigRef = useRef<RecordingConfig | null>(null)\n const maxDurationHandledRef = useRef(false)\n\n // Generate unique instance ID for debugging\n const instanceId = useId().replace(/:/g, '').slice(0, 5)\n\n const handleAudioAnalysis = useCallback(\n async ({\n analysis,\n visualizationDuration,\n }: HandleAudioAnalysisProps) => {\n const savedAnalysisData = analysisRef.current || {\n ...defaultAnalysis,\n }\n\n const maxDuration = visualizationDuration\n\n logger?.debug(\n `[handleAudioAnalysis] Received audio analysis: maxDuration=${maxDuration} analysis.dataPoints=${analysis.dataPoints.length} analysisData.dataPoints=${savedAnalysisData.dataPoints.length}`\n )\n\n // Combine data points\n const combinedDataPoints = [\n ...savedAnalysisData.dataPoints,\n ...analysis.dataPoints,\n ]\n\n const keepFullAnalysis = shouldKeepFullAnalysis(\n recordingConfigRef.current\n )\n const fullCombinedDataPoints = keepFullAnalysis\n ? [\n ...(fullAnalysisRef.current?.dataPoints ?? []),\n ...analysis.dataPoints,\n ]\n : undefined\n\n // Calculate the new duration\n // The number of segments is based on how many segments of segmentDurationMs can fit in visualizationDuration\n const numberOfSegments = Math.ceil(\n visualizationDuration / analysis.segmentDurationMs\n )\n // maxDataPoints should be the number of data points, not milliseconds\n const maxDataPoints = numberOfSegments\n\n logger?.debug(\n `[handleAudioAnalysis] Combined data points before trimming: numberOfSegments=${numberOfSegments} visualizationDuration=${visualizationDuration} combinedDataPointsLength=${combinedDataPoints.length} vs maxDataPoints=${maxDataPoints}`\n )\n\n // Trim data points to keep within the maximum number of data points\n if (combinedDataPoints.length > maxDataPoints) {\n combinedDataPoints.splice(\n 0,\n combinedDataPoints.length - maxDataPoints\n )\n }\n\n // Keep the full data points when requested for stopRecording().analysisData.\n if (keepFullAnalysis && fullCombinedDataPoints) {\n fullAnalysisRef.current = {\n ...fullAnalysisRef.current,\n dataPoints: fullCombinedDataPoints,\n }\n fullAnalysisRef.current.durationMs =\n fullCombinedDataPoints.length * analysis.segmentDurationMs\n }\n savedAnalysisData.dataPoints = combinedDataPoints\n savedAnalysisData.bitDepth =\n analysis.bitDepth || savedAnalysisData.bitDepth\n savedAnalysisData.durationMs =\n combinedDataPoints.length * analysis.segmentDurationMs\n\n // Update amplitude range\n const newMin = Math.min(\n savedAnalysisData.amplitudeRange.min,\n analysis.amplitudeRange.min\n )\n const newMax = Math.max(\n savedAnalysisData.amplitudeRange.max,\n analysis.amplitudeRange.max\n )\n\n savedAnalysisData.amplitudeRange = {\n min: newMin,\n max: newMax,\n }\n if (keepFullAnalysis) {\n fullAnalysisRef.current.amplitudeRange = {\n min: newMin,\n max: newMax,\n }\n }\n\n logger?.debug(\n `[handleAudioAnalysis] Updated analysis data: durationMs=${savedAnalysisData.durationMs}`,\n { dataPoints: savedAnalysisData.dataPoints.length }\n )\n\n // Call the onAudioAnalysis callback if it exists in the recording config\n if (recordingConfigRef.current?.onAudioAnalysis) {\n recordingConfigRef.current\n .onAudioAnalysis(analysis)\n .catch((error) => {\n logger?.warn(`Error processing audio analysis:`, error)\n })\n }\n\n // Update the ref\n analysisRef.current = savedAnalysisData\n\n // Dispatch the updated analysis data to state to trigger re-render\n dispatch({\n type: 'UPDATE_ANALYSIS',\n payload: { ...savedAnalysisData },\n })\n },\n [dispatch]\n )\n\n const handleAudioEvent = useCallback(\n async (eventData: AudioEventPayload) => {\n const {\n fileUri,\n deltaSize,\n totalSize,\n lastEmittedSize,\n position,\n streamUuid,\n encoded,\n pcmFloat32,\n mimeType,\n buffer,\n compression,\n } = eventData\n logger?.debug(`[handleAudioEvent] Received audio event:`, {\n fileUri,\n deltaSize,\n totalSize,\n position,\n mimeType,\n lastEmittedSize,\n streamUuid,\n encodedLength: encoded?.length,\n compression,\n })\n if (deltaSize === 0) {\n // Ignore packet with no data\n return\n }\n try {\n // Coming from native ( ios / android ) otherwise buffer is set\n if (Platform.OS !== 'web') {\n const compressionPayload =\n compression && startResultRef.current?.compression\n ? {\n data: compression.data,\n size: compression.totalSize,\n mimeType:\n startResultRef.current.compression\n ?.mimeType,\n bitrate:\n startResultRef.current.compression\n ?.bitrate,\n format: startResultRef.current.compression\n ?.format,\n }\n : undefined\n if (pcmFloat32 != null) {\n // Android new arch delivers Float32Array; iOS delivers number[] — normalize both\n const float32 =\n pcmFloat32 instanceof Float32Array\n ? pcmFloat32\n : new Float32Array(pcmFloat32 as number[])\n onAudioStreamRef.current?.({\n data: float32,\n streamFormat: 'float32',\n position,\n fileUri,\n eventDataSize: deltaSize,\n totalSize,\n compression: compressionPayload,\n })\n } else {\n if (!encoded) {\n logger?.error(`Encoded audio data is missing`)\n throw new Error('Encoded audio data is missing')\n }\n onAudioStreamRef.current?.({\n data: encoded,\n position,\n fileUri,\n eventDataSize: deltaSize,\n totalSize,\n compression: compressionPayload,\n })\n }\n } else if (buffer) {\n // Coming from web\n const webEvent: AudioDataEvent = {\n data: buffer,\n position,\n fileUri,\n eventDataSize: deltaSize,\n totalSize,\n compression:\n compression && startResultRef.current?.compression\n ? {\n data: compression.data,\n size: compression.totalSize,\n mimeType:\n startResultRef.current.compression\n ?.mimeType,\n bitrate:\n startResultRef.current.compression\n ?.bitrate,\n format: startResultRef.current.compression\n ?.format,\n }\n : undefined,\n }\n onAudioStreamRef.current?.(webEvent)\n logger?.debug(\n `[handleAudioEvent] Audio data sent to onAudioStream`,\n webEvent\n )\n }\n } catch (error) {\n logger?.error(`Error processing audio event:`, error)\n }\n },\n []\n )\n\n const handleMaxDurationReached = useCallback(\n async (event: MaxDurationReachedEvent) => {\n if (maxDurationHandledRef.current) {\n return\n }\n\n maxDurationHandledRef.current = true\n const config = recordingConfigRef.current\n const callbackEvent: MaxDurationReachedEvent = {\n ...event,\n autoStopped:\n event.autoStopped || !!config?.autoStopOnMaxDuration,\n }\n\n stateRef.current.maxDurationMs = callbackEvent.maxDurationMs\n stateRef.current.maxDurationReached = true\n dispatch({\n type: 'MAX_DURATION_REACHED',\n payload: callbackEvent,\n })\n\n try {\n config?.onMaxDurationReached?.(callbackEvent)\n } catch (error) {\n logger?.error(`Error in max duration callback:`, error)\n }\n\n const finishStoppedState = () => {\n if (analysisListenerRef.current) {\n analysisListenerRef.current.remove()\n analysisListenerRef.current = null\n }\n onAudioStreamRef.current = null\n stateRef.current.isRecording = false\n stateRef.current.isPaused = false\n dispatch({ type: 'STOP' })\n }\n\n const waitForPlatformAutoStop = async () => {\n const timeoutMs = 3000\n const startedAt = Date.now()\n let lastStatus: AudioStreamStatus | undefined\n\n while (Date.now() - startedAt < timeoutMs) {\n await new Promise((resolve) => setTimeout(resolve, 50))\n try {\n const currentStatus: AudioStreamStatus =\n audioStudio.status()\n lastStatus = currentStatus\n if (\n !currentStatus.isRecording &&\n !currentStatus.isPaused\n ) {\n finishStoppedState()\n return\n }\n } catch (error) {\n logger?.warn(\n `Error checking status after max duration auto-stop:`,\n error\n )\n break\n }\n }\n\n if (\n lastStatus &&\n (lastStatus.isRecording || lastStatus.isPaused)\n ) {\n try {\n await audioStudio.stopRecording()\n } catch (error) {\n logger?.warn(\n `Error completing max duration auto-stop fallback:`,\n error\n )\n }\n }\n // At this point platform-owned auto-stop did not settle cleanly.\n // Clear hook state so the UI does not stay stuck as recording.\n finishStoppedState()\n }\n\n // Only the original event tells us whether the platform already\n // owns auto-stop. Keep stream callbacks alive until status confirms\n // stop completion so native final audio flushes can still reach JS.\n if (event.autoStopped && stateRef.current.isRecording) {\n await waitForPlatformAutoStop()\n return\n }\n\n if (\n config?.autoStopOnMaxDuration &&\n !event.autoStopped &&\n stateRef.current.isRecording\n ) {\n try {\n await audioStudio.stopRecording()\n finishStoppedState()\n } catch (error) {\n logger?.error(`Error auto-stopping on max duration:`, error)\n }\n }\n },\n [audioStudio, dispatch, logger]\n )\n\n const checkStatus = useCallback(async () => {\n try {\n const status: AudioStreamStatus = audioStudio.status()\n logger?.debug(\n `Status: paused: ${status.isPaused} isRecording: ${status.isRecording} durationMs: ${status.durationMs} size: ${status.size}`,\n status.compression\n )\n\n if (\n status.maxDurationReached === true &&\n status.maxDurationMs != null &&\n !stateRef.current.maxDurationReached\n ) {\n await handleMaxDurationReached({\n durationMs: status.durationMs,\n maxDurationMs: status.maxDurationMs,\n overrunMs: Math.max(\n 0,\n status.durationMs - status.maxDurationMs\n ),\n autoStopped: false,\n })\n }\n\n // Only dispatch if values actually changed\n if (\n status.isRecording !== stateRef.current.isRecording ||\n status.isPaused !== stateRef.current.isPaused\n ) {\n stateRef.current.isRecording = status.isRecording\n stateRef.current.isPaused = status.isPaused\n dispatch({\n type: 'UPDATE_RECORDING_STATE',\n payload: {\n isRecording: status.isRecording,\n isPaused: status.isPaused,\n },\n })\n }\n\n if (\n status.durationMs !== stateRef.current.durationMs ||\n status.size !== stateRef.current.size ||\n status.maxDurationMs !== stateRef.current.maxDurationMs ||\n status.maxDurationReached !==\n stateRef.current.maxDurationReached\n ) {\n stateRef.current.durationMs = status.durationMs\n stateRef.current.size = status.size\n stateRef.current.compression = status.compression\n stateRef.current.maxDurationMs = status.maxDurationMs\n stateRef.current.maxDurationReached =\n status.maxDurationReached ?? false\n dispatch({\n type: 'UPDATE_STATUS',\n payload: {\n durationMs: status.durationMs,\n size: status.size,\n compression: status.compression,\n maxDurationMs: status.maxDurationMs,\n maxDurationReached: status.maxDurationReached,\n },\n })\n }\n } catch (error) {\n logger?.error(`Error getting status:`, error)\n }\n }, [audioStudio, handleMaxDurationReached, logger])\n\n // Update ref when state changes\n useEffect(() => {\n stateRef.current = {\n isRecording: state.isRecording,\n isPaused: state.isPaused,\n durationMs: state.durationMs,\n size: state.size,\n compression: state.compression,\n maxDurationMs: state.maxDurationMs,\n maxDurationReached: state.maxDurationReached ?? false,\n }\n }, [\n state.isRecording,\n state.isPaused,\n state.durationMs,\n state.size,\n state.compression,\n state.maxDurationMs,\n state.maxDurationReached,\n ])\n\n const startRecording = useCallback(\n async (recordingOptions: RecordingConfig) => {\n // Validate the encoding configuration\n const validationResult = validateRecordingConfig({\n encoding: recordingOptions.encoding,\n })\n\n // Log warnings if any\n if (validationResult.warnings.length > 0) {\n validationResult.warnings.forEach((warning) => {\n logger?.warn(warning)\n })\n }\n\n // Update recording options with validated values\n const validatedOptions = {\n ...recordingOptions,\n encoding: validationResult.encoding,\n }\n\n recordingConfigRef.current = validatedOptions\n maxDurationHandledRef.current = false\n logger?.debug(\n `start recording with validated config`,\n validatedOptions\n )\n\n analysisRef.current = { ...defaultAnalysis } // Reset analysis data\n fullAnalysisRef.current = { ...defaultAnalysis }\n const {\n onAudioStream,\n onRecordingInterrupted,\n onMaxDurationReached,\n onAudioAnalysis,\n keepFullAnalysis: _keepFullAnalysis,\n ...options\n } = validatedOptions\n const { enableProcessing } = options\n\n const maxRecentDataDuration = 10000 // TODO compute maxRecentDataDuration based on screen dimensions\n if (typeof onAudioStream === 'function') {\n onAudioStreamRef.current = onAudioStream\n } else {\n logger?.warn(`onAudioStream is not a function`, onAudioStream)\n onAudioStreamRef.current = null\n }\n // Strip undefined values and functions that can't cross the native bridge\n const cleanOptions = cleanNativeOptions(options)\n const startResult: StartRecordingResult =\n await audioStudio.startRecording(cleanOptions)\n dispatch({ type: 'START' })\n\n startResultRef.current = startResult\n\n if (enableProcessing) {\n logger?.debug(`Enabling audio analysis listener`)\n const listener = addAudioAnalysisListener(\n async (analysisData) => {\n try {\n await handleAudioAnalysis({\n analysis: analysisData,\n visualizationDuration: maxRecentDataDuration,\n })\n } catch (error) {\n logger?.warn(\n `Error processing audio analysis:`,\n error\n )\n }\n }\n )\n\n analysisListenerRef.current = listener\n }\n\n return startResult\n },\n [handleAudioAnalysis, dispatch]\n )\n\n const prepareRecording = useCallback(\n async (recordingOptions: RecordingConfig) => {\n recordingConfigRef.current = recordingOptions\n logger?.debug(`preparing recording`, recordingOptions)\n\n analysisRef.current = { ...defaultAnalysis } // Reset analysis data\n fullAnalysisRef.current = { ...defaultAnalysis }\n const {\n onAudioStream,\n onRecordingInterrupted,\n onMaxDurationReached,\n onAudioAnalysis,\n keepFullAnalysis: _keepFullAnalysis,\n ...options\n } = recordingOptions\n\n // Store onAudioStream for later use when recording starts\n if (typeof onAudioStream === 'function') {\n onAudioStreamRef.current = onAudioStream\n } else {\n logger?.warn(`onAudioStream is not a function`, onAudioStream)\n onAudioStreamRef.current = null\n }\n\n // Strip undefined values and functions that can't cross the native bridge\n const cleanOptions = cleanNativeOptions(options)\n // Call the native prepareRecording method\n await audioStudio.prepareRecording(cleanOptions)\n logger?.debug(`recording prepared successfully`)\n },\n []\n )\n\n const stopRecording = useCallback(async () => {\n logger?.debug(`stoping recording`)\n\n const stopResult: AudioRecording = await audioStudio.stopRecording()\n if (shouldKeepFullAnalysis(recordingConfigRef.current)) {\n stopResult.analysisData = fullAnalysisRef.current\n } else {\n // `keepFullAnalysis` is a hook-level retention policy. If a platform\n // starts returning native analysisData in the future, keep opt-out\n // semantics explicit and avoid leaking a full history here.\n delete stopResult.analysisData\n }\n\n if (analysisListenerRef.current) {\n analysisListenerRef.current.remove()\n analysisListenerRef.current = null\n }\n onAudioStreamRef.current = null\n\n // Note: We deliberately DON'T clear recordingConfigRef here to preserve interruption callback\n logger?.debug(`recording stopped`, stopResult)\n maxDurationHandledRef.current = false\n dispatch({ type: 'STOP' })\n return stopResult\n }, [dispatch])\n\n const pauseRecording = useCallback(async () => {\n logger?.debug(`pause recording`)\n const pauseResult = await audioStudio.pauseRecording()\n dispatch({ type: 'PAUSE' })\n return pauseResult\n }, [dispatch])\n\n const resumeRecording = useCallback(async () => {\n logger?.debug(`resume recording`)\n const resumeResult = await audioStudio.resumeRecording()\n dispatch({ type: 'RESUME' })\n return resumeResult\n }, [dispatch])\n\n useEffect(() => {\n const subscription = addMaxDurationReachedListener(async (event) => {\n await handleMaxDurationReached(event)\n })\n\n return () => {\n subscription.remove()\n }\n }, [handleMaxDurationReached])\n\n useEffect(() => {\n let intervalId: ReturnType<typeof setInterval> | undefined\n\n if (state.isRecording || state.isPaused) {\n // Immediately check status when starting\n checkStatus()\n\n // Start interval\n intervalId = setInterval(checkStatus, 1000)\n }\n\n return () => {\n if (intervalId) {\n clearInterval(intervalId)\n intervalId = undefined\n }\n }\n }, [checkStatus, state.isRecording, state.isPaused])\n\n useEffect(() => {\n logger?.debug(`Registering audio event listener`)\n const subscribeAudio = addAudioEventListener(handleAudioEvent)\n\n logger?.debug(\n `Subscribed to audio event listener and analysis listener`,\n {\n subscribeAudio,\n }\n )\n\n return () => {\n logger?.debug(`Removing audio event listener`)\n subscribeAudio.remove()\n }\n }, [handleAudioEvent, handleAudioAnalysis])\n\n useEffect(() => {\n // Add event subscription for recording interruptions\n logger?.debug(\n `Setting up recording interruption listener [${instanceId}]`\n )\n\n const subscription = addRecordingInterruptionListener((event) => {\n logger?.debug(\n `[${instanceId}] Received recording interruption event:`,\n event\n )\n\n // Handle device disconnection for UI updates\n if (event.reason === 'deviceDisconnected') {\n logger?.debug(\n `[${instanceId}] Device disconnected - temporarily hiding last device from UI`\n )\n\n // Get current device list before the native layer updates\n const currentDevices = audioDeviceManager.getRawDevices()\n\n // Wait a moment for native layer to update, then compare\n setTimeout(async () => {\n try {\n // Get updated devices without notifying yet\n const updatedDevices =\n await audioDeviceManager.getAvailableDevices({\n refresh: true,\n })\n\n // Find missing devices by comparing lists\n const missingDevices = currentDevices.filter(\n (oldDevice) =>\n !updatedDevices.some(\n (newDevice) => newDevice.id === oldDevice.id\n )\n )\n\n if (missingDevices.length > 0) {\n // Mark all missing devices as disconnected (silently)\n missingDevices.forEach((missingDevice) => {\n logger?.debug(\n `[${instanceId}] Confirmed disconnected device: ${missingDevice.name} (${missingDevice.id})`\n )\n audioDeviceManager.markDeviceAsDisconnected(\n missingDevice.id,\n false\n )\n })\n }\n\n // Notify listeners once with the final filtered state\n audioDeviceManager.notifyListeners()\n } catch (error) {\n logger?.warn(\n `[${instanceId}] Error in delayed device disconnection handling:`,\n error\n )\n }\n }, 500) // 500ms delay to let native layer update\n } else if (event.reason === 'deviceConnected') {\n // Device reconnected - force refresh to show it immediately\n logger?.debug(\n `[${instanceId}] Device connected, forcing refresh`\n )\n audioDeviceManager.forceRefreshDevices()\n }\n\n // Check if we have a callback configured\n logger?.debug(\n `[${instanceId}] recordingConfigRef.current exists:`,\n !!recordingConfigRef.current\n )\n\n if (recordingConfigRef.current?.onRecordingInterrupted) {\n try {\n logger?.debug(\n `[${instanceId}] Calling recording interruption callback`\n )\n recordingConfigRef.current.onRecordingInterrupted(event)\n } catch (error) {\n logger?.error(\n `[${instanceId}] Error in recording interruption callback:`,\n error\n )\n }\n } else {\n logger?.debug(\n `[${instanceId}] No recording interruption callback configured`\n )\n }\n })\n\n return () => {\n logger?.debug(\n `[${instanceId}] Removing recording interruption listener`\n )\n subscription.remove()\n }\n }, [instanceId, logger]) // Include instanceId and logger in dependencies\n\n return {\n prepareRecording,\n startRecording,\n stopRecording,\n pauseRecording,\n resumeRecording,\n isPaused: state.isPaused,\n isRecording: state.isRecording,\n durationMs: state.durationMs,\n size: state.size,\n compression: state.compression,\n analysisData: state.analysisData,\n maxDurationMs: state.maxDurationMs,\n maxDurationReached: state.maxDurationReached,\n }\n}\n"]}
1
+ {"version":3,"file":"useAudioRecorder.js","sourceRoot":"","sources":["../../src/useAudioRecorder.tsx"],"names":[],"mappings":"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","sourcesContent":["// src/useAudioRecorder.ts\nimport { EventSubscription, Platform } from 'expo-modules-core'\nimport { useCallback, useEffect, useReducer, useRef, useId } from 'react'\n\nimport { AudioAnalysis } from './AudioAnalysis/AudioAnalysis.types'\nimport { audioDeviceManager } from './AudioDeviceManager'\nimport {\n AudioDataEvent,\n AudioRecording,\n AudioStreamStatus,\n CompressionInfo,\n ConsoleLike,\n MaxDurationReachedEvent,\n RecordingConfig,\n RecordingStopReason,\n StartRecordingResult,\n} from './AudioStudio.types'\nimport AudioStudioModule from './AudioStudioModule'\nimport { validateRecordingConfig } from './constants/platformLimitations'\nimport {\n addAudioAnalysisListener,\n addAudioEventListener,\n AudioEventPayload,\n addMaxDurationReachedListener,\n addRecordingInterruptionListener,\n} from './events'\nimport { createNativeRecordingOptions } from './utils/nativeRecordingOptions'\n\nexport interface UseAudioRecorderProps {\n logger?: ConsoleLike\n audioWorkletUrl?: string\n featuresExtratorUrl?: string\n}\n\nexport interface UseAudioRecorderState {\n prepareRecording: (_: RecordingConfig) => Promise<void>\n startRecording: (_: RecordingConfig) => Promise<StartRecordingResult>\n stopRecording: () => Promise<AudioRecording>\n pauseRecording: () => Promise<void>\n resumeRecording: () => Promise<void>\n isRecording: boolean\n isPaused: boolean\n durationMs: number\n size: number\n compression?: CompressionInfo\n analysisData?: AudioAnalysis\n maxDurationMs?: number\n maxDurationReached?: boolean\n lastRecordingReason?: RecordingStopReason\n}\n\ninterface RecorderReducerState {\n isRecording: boolean\n isPaused: boolean\n durationMs: number\n size: number\n compression?: CompressionInfo\n analysisData?: AudioAnalysis\n maxDurationMs?: number\n maxDurationReached?: boolean\n lastRecordingReason?: RecordingStopReason\n}\n\ntype RecorderAction =\n | { type: 'START' | 'PAUSE' | 'RESUME' }\n | {\n type: 'STOP'\n payload: {\n reason: RecordingStopReason\n }\n }\n | {\n type: 'UPDATE_RECORDING_STATE'\n payload: {\n isRecording: boolean\n isPaused: boolean\n }\n }\n | {\n type: 'UPDATE_STATUS'\n payload: {\n durationMs: number\n size: number\n compression?: CompressionInfo\n maxDurationMs?: number\n maxDurationReached?: boolean\n }\n }\n | {\n type: 'MAX_DURATION_REACHED'\n payload: MaxDurationReachedEvent\n }\n | { type: 'UPDATE_ANALYSIS'; payload: AudioAnalysis }\n\nconst defaultAnalysis: AudioAnalysis = {\n segmentDurationMs: 100,\n bitDepth: 32,\n numberOfChannels: 1,\n durationMs: 0,\n sampleRate: 44100,\n samples: 0,\n dataPoints: [],\n rmsRange: {\n min: Number.POSITIVE_INFINITY,\n max: Number.NEGATIVE_INFINITY,\n },\n amplitudeRange: {\n min: Number.POSITIVE_INFINITY,\n max: Number.NEGATIVE_INFINITY,\n },\n extractionTimeMs: 0,\n}\n\nfunction finiteOrZero(value: number): number {\n return Number.isFinite(value) ? value : 0\n}\n\nfunction sanitizeSerializableValue<T>(value: T): T {\n if (typeof value === 'number') {\n return finiteOrZero(value) as T\n }\n\n if (Array.isArray(value)) {\n return value.map((item) => sanitizeSerializableValue(item)) as T\n }\n\n if (value && typeof value === 'object') {\n const sanitized: Record<string, unknown> = {}\n\n for (const [key, nestedValue] of Object.entries(\n value as Record<string, unknown>\n )) {\n sanitized[key] = sanitizeSerializableValue(nestedValue)\n }\n\n return sanitized as T\n }\n\n return value\n}\n\nfunction createSerializableAnalysis(analysis: AudioAnalysis): AudioAnalysis {\n return sanitizeSerializableValue(analysis)\n}\n\nfunction createRecordingSnapshot(recording: AudioRecording): AudioRecording {\n return sanitizeSerializableValue(recording)\n}\n\nfunction audioRecorderReducer(\n state: RecorderReducerState,\n action: RecorderAction\n): RecorderReducerState {\n switch (action.type) {\n case 'START':\n return {\n ...state,\n isRecording: true,\n isPaused: false,\n durationMs: 0,\n size: 0,\n compression: undefined,\n analysisData: defaultAnalysis,\n maxDurationMs: undefined,\n maxDurationReached: false,\n lastRecordingReason: undefined,\n }\n case 'STOP':\n return {\n ...state,\n isRecording: false,\n isPaused: false,\n durationMs: 0,\n size: 0,\n compression: undefined,\n analysisData: undefined,\n lastRecordingReason: action.payload.reason,\n // Preserve max-duration state after stop so UI and agentic\n // validation can explain why recording ended. START resets it.\n }\n case 'PAUSE':\n return { ...state, isPaused: true, isRecording: false }\n case 'RESUME':\n return { ...state, isPaused: false, isRecording: true }\n case 'UPDATE_RECORDING_STATE':\n return {\n ...state,\n isPaused: action.payload.isPaused,\n isRecording: action.payload.isRecording,\n }\n case 'UPDATE_STATUS': {\n const newState = {\n ...state,\n durationMs: action.payload.durationMs,\n size: action.payload.size,\n compression: action.payload.compression\n ? {\n size: action.payload.compression.size,\n mimeType: action.payload.compression.mimeType,\n bitrate: action.payload.compression.bitrate,\n format: action.payload.compression.format,\n }\n : undefined,\n maxDurationMs: action.payload.maxDurationMs,\n maxDurationReached: action.payload.maxDurationReached,\n }\n return newState\n }\n case 'MAX_DURATION_REACHED':\n return {\n ...state,\n maxDurationMs: action.payload.maxDurationMs,\n maxDurationReached: true,\n }\n case 'UPDATE_ANALYSIS':\n return {\n ...state,\n analysisData: action.payload,\n }\n default:\n return state\n }\n}\n\ninterface HandleAudioAnalysisProps {\n analysis: AudioAnalysis\n visualizationDuration: number\n}\n\nfunction shouldKeepFullAnalysis(config?: RecordingConfig | null): boolean {\n return config?.keepFullAnalysis !== false\n}\n\nexport function useAudioRecorder({\n logger,\n audioWorkletUrl,\n featuresExtratorUrl,\n}: UseAudioRecorderProps = {}): UseAudioRecorderState {\n // Initialize AudioDeviceManager with logger (once)\n if (logger) {\n audioDeviceManager.setLogger(logger)\n }\n const [state, dispatch] = useReducer(audioRecorderReducer, {\n isRecording: false,\n isPaused: false,\n durationMs: 0,\n size: 0,\n compression: undefined,\n analysisData: undefined,\n maxDurationMs: undefined,\n maxDurationReached: false,\n lastRecordingReason: undefined,\n })\n\n const startResultRef = useRef<StartRecordingResult | null>(null)\n\n const analysisListenerRef = useRef<EventSubscription | null>(null)\n // analysisRef is the current analysis data (last 10 seconds by default)\n const analysisRef = useRef<AudioAnalysis>({ ...defaultAnalysis })\n // fullAnalysisRef is the full analysis data (all data points)\n const fullAnalysisRef = useRef<AudioAnalysis>({\n ...defaultAnalysis,\n })\n\n // Instantiate the module for web with URLs\n const audioStudio =\n Platform.OS === 'web'\n ? AudioStudioModule({\n audioWorkletUrl,\n featuresExtratorUrl,\n logger,\n })\n : AudioStudioModule\n\n const onAudioStreamRef = useRef<\n ((_: AudioDataEvent) => Promise<void>) | null\n >(null)\n\n const stateRef = useRef({\n isRecording: false,\n isPaused: false,\n durationMs: 0,\n size: 0,\n compression: undefined as CompressionInfo | undefined,\n maxDurationMs: undefined as number | undefined,\n maxDurationReached: false,\n })\n\n const recordingConfigRef = useRef<RecordingConfig | null>(null)\n const maxDurationHandledRef = useRef(false)\n const stopFinalizationRef = useRef<Promise<AudioRecording> | null>(null)\n\n // Generate unique instance ID for debugging\n const instanceId = useId().replace(/:/g, '').slice(0, 5)\n\n const handleAudioAnalysis = useCallback(\n async ({\n analysis,\n visualizationDuration,\n }: HandleAudioAnalysisProps) => {\n const savedAnalysisData = analysisRef.current || {\n ...defaultAnalysis,\n }\n\n const maxDuration = visualizationDuration\n\n logger?.debug(\n `[handleAudioAnalysis] Received audio analysis: maxDuration=${maxDuration} analysis.dataPoints=${analysis.dataPoints.length} analysisData.dataPoints=${savedAnalysisData.dataPoints.length}`\n )\n\n // Combine data points\n const combinedDataPoints = [\n ...savedAnalysisData.dataPoints,\n ...analysis.dataPoints,\n ]\n\n const keepFullAnalysis = shouldKeepFullAnalysis(\n recordingConfigRef.current\n )\n const fullCombinedDataPoints = keepFullAnalysis\n ? [\n ...(fullAnalysisRef.current?.dataPoints ?? []),\n ...analysis.dataPoints,\n ]\n : undefined\n\n // Calculate the new duration\n // The number of segments is based on how many segments of segmentDurationMs can fit in visualizationDuration\n const numberOfSegments = Math.ceil(\n visualizationDuration / analysis.segmentDurationMs\n )\n // maxDataPoints should be the number of data points, not milliseconds\n const maxDataPoints = numberOfSegments\n\n logger?.debug(\n `[handleAudioAnalysis] Combined data points before trimming: numberOfSegments=${numberOfSegments} visualizationDuration=${visualizationDuration} combinedDataPointsLength=${combinedDataPoints.length} vs maxDataPoints=${maxDataPoints}`\n )\n\n // Trim data points to keep within the maximum number of data points\n if (combinedDataPoints.length > maxDataPoints) {\n combinedDataPoints.splice(\n 0,\n combinedDataPoints.length - maxDataPoints\n )\n }\n\n // Keep the full data points when requested for stopRecording().analysisData.\n if (keepFullAnalysis && fullCombinedDataPoints) {\n fullAnalysisRef.current = {\n ...fullAnalysisRef.current,\n dataPoints: fullCombinedDataPoints,\n }\n fullAnalysisRef.current.durationMs =\n fullCombinedDataPoints.length * analysis.segmentDurationMs\n }\n savedAnalysisData.dataPoints = combinedDataPoints\n savedAnalysisData.bitDepth =\n analysis.bitDepth || savedAnalysisData.bitDepth\n savedAnalysisData.durationMs =\n combinedDataPoints.length * analysis.segmentDurationMs\n\n // Update amplitude range\n const newMin = Math.min(\n savedAnalysisData.amplitudeRange.min,\n analysis.amplitudeRange.min\n )\n const newMax = Math.max(\n savedAnalysisData.amplitudeRange.max,\n analysis.amplitudeRange.max\n )\n\n savedAnalysisData.amplitudeRange = {\n min: newMin,\n max: newMax,\n }\n if (keepFullAnalysis) {\n fullAnalysisRef.current.amplitudeRange = {\n min: newMin,\n max: newMax,\n }\n }\n\n logger?.debug(\n `[handleAudioAnalysis] Updated analysis data: durationMs=${savedAnalysisData.durationMs}`,\n { dataPoints: savedAnalysisData.dataPoints.length }\n )\n\n // Call the onAudioAnalysis callback if it exists in the recording config\n if (recordingConfigRef.current?.onAudioAnalysis) {\n recordingConfigRef.current\n .onAudioAnalysis(analysis)\n .catch((error) => {\n logger?.warn(`Error processing audio analysis:`, error)\n })\n }\n\n // Update the ref\n analysisRef.current = savedAnalysisData\n\n // Dispatch the updated analysis data to state to trigger re-render\n dispatch({\n type: 'UPDATE_ANALYSIS',\n payload: { ...savedAnalysisData },\n })\n },\n [dispatch]\n )\n\n const handleAudioEvent = useCallback(\n async (eventData: AudioEventPayload) => {\n const {\n fileUri,\n deltaSize,\n totalSize,\n lastEmittedSize,\n position,\n streamUuid,\n encoded,\n pcmFloat32,\n mimeType,\n buffer,\n compression,\n } = eventData\n logger?.debug(`[handleAudioEvent] Received audio event:`, {\n fileUri,\n deltaSize,\n totalSize,\n position,\n mimeType,\n lastEmittedSize,\n streamUuid,\n encodedLength: encoded?.length,\n compression,\n })\n if (deltaSize === 0) {\n // Ignore packet with no data\n return\n }\n try {\n // Coming from native ( ios / android ) otherwise buffer is set\n if (Platform.OS !== 'web') {\n const compressionPayload =\n compression && startResultRef.current?.compression\n ? {\n data: compression.data,\n size: compression.totalSize,\n mimeType:\n startResultRef.current.compression\n ?.mimeType,\n bitrate:\n startResultRef.current.compression\n ?.bitrate,\n format: startResultRef.current.compression\n ?.format,\n }\n : undefined\n if (pcmFloat32 != null) {\n // Android new arch delivers Float32Array; iOS delivers number[] — normalize both\n const float32 =\n pcmFloat32 instanceof Float32Array\n ? pcmFloat32\n : new Float32Array(pcmFloat32 as number[])\n onAudioStreamRef.current?.({\n data: float32,\n streamFormat: 'float32',\n position,\n fileUri,\n eventDataSize: deltaSize,\n totalSize,\n compression: compressionPayload,\n })\n } else {\n if (!encoded) {\n logger?.error(`Encoded audio data is missing`)\n throw new Error('Encoded audio data is missing')\n }\n onAudioStreamRef.current?.({\n data: encoded,\n position,\n fileUri,\n eventDataSize: deltaSize,\n totalSize,\n compression: compressionPayload,\n })\n }\n } else if (buffer) {\n // Coming from web\n const webEvent: AudioDataEvent = {\n data: buffer,\n position,\n fileUri,\n eventDataSize: deltaSize,\n totalSize,\n compression:\n compression && startResultRef.current?.compression\n ? {\n data: compression.data,\n size: compression.totalSize,\n mimeType:\n startResultRef.current.compression\n ?.mimeType,\n bitrate:\n startResultRef.current.compression\n ?.bitrate,\n format: startResultRef.current.compression\n ?.format,\n }\n : undefined,\n }\n onAudioStreamRef.current?.(webEvent)\n logger?.debug(\n `[handleAudioEvent] Audio data sent to onAudioStream`,\n webEvent\n )\n }\n } catch (error) {\n logger?.error(`Error processing audio event:`, error)\n }\n },\n []\n )\n\n const finalizeRecordingStop = useCallback(\n async (reason: RecordingStopReason) => {\n if (stopFinalizationRef.current) {\n return stopFinalizationRef.current\n }\n\n const finalizePromise = (async () => {\n const nativeStopResult: AudioRecording | null =\n await audioStudio.stopRecording()\n\n if (!nativeStopResult) {\n throw new Error('Failed to stop recording')\n }\n\n const stopResult = createRecordingSnapshot(nativeStopResult)\n\n if (shouldKeepFullAnalysis(recordingConfigRef.current)) {\n stopResult.analysisData = createSerializableAnalysis(\n fullAnalysisRef.current\n )\n } else {\n // `keepFullAnalysis` is a hook-level retention policy. If a platform\n // starts returning native analysisData in the future, keep opt-out\n // semantics explicit and avoid leaking a full history here.\n delete stopResult.analysisData\n }\n\n if (analysisListenerRef.current) {\n analysisListenerRef.current.remove()\n analysisListenerRef.current = null\n }\n onAudioStreamRef.current = null\n\n stateRef.current.isRecording = false\n stateRef.current.isPaused = false\n\n // Note: We deliberately DON'T clear recordingConfigRef here to preserve callbacks.\n logger?.debug(`recording stopped`, stopResult)\n maxDurationHandledRef.current = false\n dispatch({\n type: 'STOP',\n payload: { reason },\n })\n\n const stoppedCallback =\n recordingConfigRef.current?.onRecordingStopped\n if (stoppedCallback) {\n try {\n void Promise.resolve(\n stoppedCallback(stopResult, reason)\n ).catch((error) => {\n logger?.error(\n `Error in recording stopped callback:`,\n error\n )\n })\n } catch (error) {\n logger?.error(\n `Error in recording stopped callback:`,\n error\n )\n }\n }\n\n return stopResult\n })()\n\n stopFinalizationRef.current = finalizePromise\n try {\n return await finalizePromise\n } finally {\n stopFinalizationRef.current = null\n }\n },\n [audioStudio, dispatch, logger]\n )\n\n const handleMaxDurationReached = useCallback(\n async (event: MaxDurationReachedEvent) => {\n if (maxDurationHandledRef.current) {\n return\n }\n\n maxDurationHandledRef.current = true\n const config = recordingConfigRef.current\n const callbackEvent: MaxDurationReachedEvent = {\n ...event,\n autoStopped:\n event.autoStopped || !!config?.autoStopOnMaxDuration,\n }\n\n stateRef.current.maxDurationMs = callbackEvent.maxDurationMs\n stateRef.current.maxDurationReached = true\n dispatch({\n type: 'MAX_DURATION_REACHED',\n payload: callbackEvent,\n })\n\n try {\n config?.onMaxDurationReached?.(callbackEvent)\n } catch (error) {\n logger?.error(`Error in max duration callback:`, error)\n }\n\n if (config?.autoStopOnMaxDuration && stateRef.current.isRecording) {\n try {\n await finalizeRecordingStop('maxDuration')\n } catch (error) {\n logger?.error(`Error auto-stopping on max duration:`, error)\n }\n }\n },\n [dispatch, finalizeRecordingStop, logger]\n )\n\n const checkStatus = useCallback(async () => {\n try {\n const status: AudioStreamStatus = audioStudio.status()\n logger?.debug(\n `Status: paused: ${status.isPaused} isRecording: ${status.isRecording} durationMs: ${status.durationMs} size: ${status.size}`,\n status.compression\n )\n\n if (\n status.maxDurationReached === true &&\n status.maxDurationMs != null &&\n !stateRef.current.maxDurationReached\n ) {\n await handleMaxDurationReached({\n durationMs: status.durationMs,\n maxDurationMs: status.maxDurationMs,\n overrunMs: Math.max(\n 0,\n status.durationMs - status.maxDurationMs\n ),\n autoStopped: false,\n })\n }\n\n // Only dispatch if values actually changed\n if (\n status.isRecording !== stateRef.current.isRecording ||\n status.isPaused !== stateRef.current.isPaused\n ) {\n stateRef.current.isRecording = status.isRecording\n stateRef.current.isPaused = status.isPaused\n dispatch({\n type: 'UPDATE_RECORDING_STATE',\n payload: {\n isRecording: status.isRecording,\n isPaused: status.isPaused,\n },\n })\n }\n\n const statusMaxDurationReached = status.maxDurationReached ?? false\n const preserveStoppedMaxDuration =\n !status.isRecording &&\n !status.isPaused &&\n stateRef.current.maxDurationReached &&\n !statusMaxDurationReached\n const nextMaxDurationMs = preserveStoppedMaxDuration\n ? stateRef.current.maxDurationMs\n : status.maxDurationMs\n const nextMaxDurationReached = preserveStoppedMaxDuration\n ? true\n : statusMaxDurationReached\n\n if (\n status.durationMs !== stateRef.current.durationMs ||\n status.size !== stateRef.current.size ||\n nextMaxDurationMs !== stateRef.current.maxDurationMs ||\n nextMaxDurationReached !== stateRef.current.maxDurationReached\n ) {\n stateRef.current.durationMs = status.durationMs\n stateRef.current.size = status.size\n stateRef.current.compression = status.compression\n stateRef.current.maxDurationMs = nextMaxDurationMs\n stateRef.current.maxDurationReached = nextMaxDurationReached\n dispatch({\n type: 'UPDATE_STATUS',\n payload: {\n durationMs: status.durationMs,\n size: status.size,\n compression: status.compression,\n maxDurationMs: nextMaxDurationMs,\n maxDurationReached: nextMaxDurationReached,\n },\n })\n }\n } catch (error) {\n logger?.error(`Error getting status:`, error)\n }\n }, [audioStudio, handleMaxDurationReached, logger])\n\n // Update ref when state changes\n useEffect(() => {\n stateRef.current = {\n isRecording: state.isRecording,\n isPaused: state.isPaused,\n durationMs: state.durationMs,\n size: state.size,\n compression: state.compression,\n maxDurationMs: state.maxDurationMs,\n maxDurationReached: state.maxDurationReached ?? false,\n }\n }, [\n state.isRecording,\n state.isPaused,\n state.durationMs,\n state.size,\n state.compression,\n state.maxDurationMs,\n state.maxDurationReached,\n ])\n\n const startRecording = useCallback(\n async (recordingOptions: RecordingConfig) => {\n // Validate the encoding configuration\n const validationResult = validateRecordingConfig({\n encoding: recordingOptions.encoding,\n })\n\n // Log warnings if any\n if (validationResult.warnings.length > 0) {\n validationResult.warnings.forEach((warning) => {\n logger?.warn(warning)\n })\n }\n\n // Update recording options with validated values\n const validatedOptions = {\n ...recordingOptions,\n encoding: validationResult.encoding,\n }\n\n recordingConfigRef.current = validatedOptions\n maxDurationHandledRef.current = false\n logger?.debug(\n `start recording with validated config`,\n validatedOptions\n )\n\n analysisRef.current = { ...defaultAnalysis } // Reset analysis data\n fullAnalysisRef.current = { ...defaultAnalysis }\n const { onAudioStream, enableProcessing } = validatedOptions\n\n const maxRecentDataDuration = 10000 // TODO compute maxRecentDataDuration based on screen dimensions\n if (typeof onAudioStream === 'function') {\n onAudioStreamRef.current = onAudioStream\n } else {\n logger?.warn(`onAudioStream is not a function`, onAudioStream)\n onAudioStreamRef.current = null\n }\n // Strip hook-only values and undefineds that can't cross the native bridge.\n // autoStopOnMaxDuration stays hook-owned so finalization can expose\n // the same AudioRecording result as a manual stop.\n const cleanOptions = createNativeRecordingOptions(validatedOptions)\n const startResult: StartRecordingResult =\n await audioStudio.startRecording(cleanOptions)\n dispatch({ type: 'START' })\n\n startResultRef.current = startResult\n\n if (enableProcessing) {\n logger?.debug(`Enabling audio analysis listener`)\n const listener = addAudioAnalysisListener(\n async (analysisData) => {\n try {\n await handleAudioAnalysis({\n analysis: analysisData,\n visualizationDuration: maxRecentDataDuration,\n })\n } catch (error) {\n logger?.warn(\n `Error processing audio analysis:`,\n error\n )\n }\n }\n )\n\n analysisListenerRef.current = listener\n }\n\n return startResult\n },\n [handleAudioAnalysis, dispatch]\n )\n\n const prepareRecording = useCallback(\n async (recordingOptions: RecordingConfig) => {\n recordingConfigRef.current = recordingOptions\n logger?.debug(`preparing recording`, recordingOptions)\n\n analysisRef.current = { ...defaultAnalysis } // Reset analysis data\n fullAnalysisRef.current = { ...defaultAnalysis }\n const { onAudioStream } = recordingOptions\n\n // Store onAudioStream for later use when recording starts\n if (typeof onAudioStream === 'function') {\n onAudioStreamRef.current = onAudioStream\n } else {\n logger?.warn(`onAudioStream is not a function`, onAudioStream)\n onAudioStreamRef.current = null\n }\n\n // Strip hook-only values and undefineds that can't cross the native bridge.\n const cleanOptions = createNativeRecordingOptions(recordingOptions)\n // Call the native prepareRecording method\n await audioStudio.prepareRecording(cleanOptions)\n logger?.debug(`recording prepared successfully`)\n },\n []\n )\n\n const stopRecording = useCallback(async () => {\n logger?.debug(`stoping recording`)\n return finalizeRecordingStop('manual')\n }, [finalizeRecordingStop, logger])\n\n const pauseRecording = useCallback(async () => {\n logger?.debug(`pause recording`)\n const pauseResult = await audioStudio.pauseRecording()\n dispatch({ type: 'PAUSE' })\n return pauseResult\n }, [dispatch])\n\n const resumeRecording = useCallback(async () => {\n logger?.debug(`resume recording`)\n const resumeResult = await audioStudio.resumeRecording()\n dispatch({ type: 'RESUME' })\n return resumeResult\n }, [dispatch])\n\n useEffect(() => {\n const subscription = addMaxDurationReachedListener(async (event) => {\n await handleMaxDurationReached(event)\n })\n\n return () => {\n subscription.remove()\n }\n }, [handleMaxDurationReached])\n\n useEffect(() => {\n let intervalId: ReturnType<typeof setInterval> | undefined\n\n if (state.isRecording || state.isPaused) {\n // Immediately check status when starting\n checkStatus()\n\n // Start interval\n intervalId = setInterval(checkStatus, 1000)\n }\n\n return () => {\n if (intervalId) {\n clearInterval(intervalId)\n intervalId = undefined\n }\n }\n }, [checkStatus, state.isRecording, state.isPaused])\n\n useEffect(() => {\n logger?.debug(`Registering audio event listener`)\n const subscribeAudio = addAudioEventListener(handleAudioEvent)\n\n logger?.debug(\n `Subscribed to audio event listener and analysis listener`,\n {\n subscribeAudio,\n }\n )\n\n return () => {\n logger?.debug(`Removing audio event listener`)\n subscribeAudio.remove()\n }\n }, [handleAudioEvent, handleAudioAnalysis])\n\n useEffect(() => {\n // Add event subscription for recording interruptions\n logger?.debug(\n `Setting up recording interruption listener [${instanceId}]`\n )\n\n const subscription = addRecordingInterruptionListener((event) => {\n logger?.debug(\n `[${instanceId}] Received recording interruption event:`,\n event\n )\n\n // Handle device disconnection for UI updates\n if (event.reason === 'deviceDisconnected') {\n logger?.debug(\n `[${instanceId}] Device disconnected - temporarily hiding last device from UI`\n )\n\n // Get current device list before the native layer updates\n const currentDevices = audioDeviceManager.getRawDevices()\n\n // Wait a moment for native layer to update, then compare\n setTimeout(async () => {\n try {\n // Get updated devices without notifying yet\n const updatedDevices =\n await audioDeviceManager.getAvailableDevices({\n refresh: true,\n })\n\n // Find missing devices by comparing lists\n const missingDevices = currentDevices.filter(\n (oldDevice) =>\n !updatedDevices.some(\n (newDevice) => newDevice.id === oldDevice.id\n )\n )\n\n if (missingDevices.length > 0) {\n // Mark all missing devices as disconnected (silently)\n missingDevices.forEach((missingDevice) => {\n logger?.debug(\n `[${instanceId}] Confirmed disconnected device: ${missingDevice.name} (${missingDevice.id})`\n )\n audioDeviceManager.markDeviceAsDisconnected(\n missingDevice.id,\n false\n )\n })\n }\n\n // Notify listeners once with the final filtered state\n audioDeviceManager.notifyListeners()\n } catch (error) {\n logger?.warn(\n `[${instanceId}] Error in delayed device disconnection handling:`,\n error\n )\n }\n }, 500) // 500ms delay to let native layer update\n } else if (event.reason === 'deviceConnected') {\n // Device reconnected - force refresh to show it immediately\n logger?.debug(\n `[${instanceId}] Device connected, forcing refresh`\n )\n audioDeviceManager.forceRefreshDevices()\n }\n\n // Check if we have a callback configured\n logger?.debug(\n `[${instanceId}] recordingConfigRef.current exists:`,\n !!recordingConfigRef.current\n )\n\n if (recordingConfigRef.current?.onRecordingInterrupted) {\n try {\n logger?.debug(\n `[${instanceId}] Calling recording interruption callback`\n )\n recordingConfigRef.current.onRecordingInterrupted(event)\n } catch (error) {\n logger?.error(\n `[${instanceId}] Error in recording interruption callback:`,\n error\n )\n }\n } else {\n logger?.debug(\n `[${instanceId}] No recording interruption callback configured`\n )\n }\n })\n\n return () => {\n logger?.debug(\n `[${instanceId}] Removing recording interruption listener`\n )\n subscription.remove()\n }\n }, [instanceId, logger]) // Include instanceId and logger in dependencies\n\n return {\n prepareRecording,\n startRecording,\n stopRecording,\n pauseRecording,\n resumeRecording,\n isPaused: state.isPaused,\n isRecording: state.isRecording,\n durationMs: state.durationMs,\n size: state.size,\n compression: state.compression,\n analysisData: state.analysisData,\n maxDurationMs: state.maxDurationMs,\n maxDurationReached: state.maxDurationReached,\n lastRecordingReason: state.lastRecordingReason,\n }\n}\n"]}
@@ -0,0 +1,10 @@
1
+ import { cleanNativeOptions } from './cleanNativeOptions';
2
+ export function createNativeRecordingOptions(recordingOptions) {
3
+ const { onAudioStream, onRecordingInterrupted, onMaxDurationReached, onRecordingStopped, onAudioAnalysis, keepFullAnalysis: _keepFullAnalysis,
4
+ // Keep hook-owned auto-stop out of the native bridge so the hook can
5
+ // reuse the same finalization path as manual stop and expose the
6
+ // resulting AudioRecording consistently.
7
+ autoStopOnMaxDuration: _autoStopOnMaxDuration, ...options } = recordingOptions;
8
+ return cleanNativeOptions(options);
9
+ }
10
+ //# sourceMappingURL=nativeRecordingOptions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nativeRecordingOptions.js","sourceRoot":"","sources":["../../../src/utils/nativeRecordingOptions.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AAEzD,MAAM,UAAU,4BAA4B,CAAC,gBAAiC;IAC1E,MAAM,EACF,aAAa,EACb,sBAAsB,EACtB,oBAAoB,EACpB,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EAAE,iBAAiB;IACnC,qEAAqE;IACrE,iEAAiE;IACjE,yCAAyC;IACzC,qBAAqB,EAAE,sBAAsB,EAC7C,GAAG,OAAO,EACb,GAAG,gBAAgB,CAAA;IAEpB,OAAO,kBAAkB,CAAC,OAAO,CAAC,CAAA;AACtC,CAAC","sourcesContent":["import { RecordingConfig } from '../AudioStudio.types'\nimport { cleanNativeOptions } from './cleanNativeOptions'\n\nexport function createNativeRecordingOptions(recordingOptions: RecordingConfig) {\n const {\n onAudioStream,\n onRecordingInterrupted,\n onMaxDurationReached,\n onRecordingStopped,\n onAudioAnalysis,\n keepFullAnalysis: _keepFullAnalysis,\n // Keep hook-owned auto-stop out of the native bridge so the hook can\n // reuse the same finalization path as manual stop and expose the\n // resulting AudioRecording consistently.\n autoStopOnMaxDuration: _autoStopOnMaxDuration,\n ...options\n } = recordingOptions\n\n return cleanNativeOptions(options)\n}\n"]}