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

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 (58) hide show
  1. package/README.md +30 -1
  2. package/android/src/main/java/net/siteed/audiostudio/AudioRecorderManager.kt +142 -12
  3. package/android/src/main/java/net/siteed/audiostudio/AudioRecordingService.kt +1 -1
  4. package/android/src/main/java/net/siteed/audiostudio/AudioStudioModule.kt +5 -4
  5. package/android/src/main/java/net/siteed/audiostudio/Constants.kt +2 -1
  6. package/android/src/main/java/net/siteed/audiostudio/RecordingActionReceiver.kt +1 -1
  7. package/android/src/main/java/net/siteed/audiostudio/RecordingConfig.kt +5 -1
  8. package/build/cjs/AudioRecorder.provider.js +3 -37
  9. package/build/cjs/AudioRecorder.provider.js.map +1 -1
  10. package/build/cjs/AudioStudio.types.js.map +1 -1
  11. package/build/cjs/AudioStudio.web.js +125 -13
  12. package/build/cjs/AudioStudio.web.js.map +1 -1
  13. package/build/cjs/AudioStudioModule.js +6 -1
  14. package/build/cjs/AudioStudioModule.js.map +1 -1
  15. package/build/cjs/events.js +4 -0
  16. package/build/cjs/events.js.map +1 -1
  17. package/build/cjs/index.js +3 -1
  18. package/build/cjs/index.js.map +1 -1
  19. package/build/cjs/useAudioRecorder.js +139 -4
  20. package/build/cjs/useAudioRecorder.js.map +1 -1
  21. package/build/esm/AudioRecorder.provider.js +3 -4
  22. package/build/esm/AudioRecorder.provider.js.map +1 -1
  23. package/build/esm/AudioStudio.types.js.map +1 -1
  24. package/build/esm/AudioStudio.web.js +125 -13
  25. package/build/esm/AudioStudio.web.js.map +1 -1
  26. package/build/esm/AudioStudioModule.js +6 -1
  27. package/build/esm/AudioStudioModule.js.map +1 -1
  28. package/build/esm/events.js +3 -0
  29. package/build/esm/events.js.map +1 -1
  30. package/build/esm/index.js +1 -0
  31. package/build/esm/index.js.map +1 -1
  32. package/build/esm/useAudioRecorder.js +140 -5
  33. package/build/esm/useAudioRecorder.js.map +1 -1
  34. package/build/types/AudioStudio.types.d.ts +44 -1
  35. package/build/types/AudioStudio.types.d.ts.map +1 -1
  36. package/build/types/AudioStudio.web.d.ts +17 -1
  37. package/build/types/AudioStudio.web.d.ts.map +1 -1
  38. package/build/types/AudioStudioModule.d.ts.map +1 -1
  39. package/build/types/events.d.ts +2 -1
  40. package/build/types/events.d.ts.map +1 -1
  41. package/build/types/index.d.ts +1 -0
  42. package/build/types/index.d.ts.map +1 -1
  43. package/build/types/useAudioRecorder.d.ts +2 -0
  44. package/build/types/useAudioRecorder.d.ts.map +1 -1
  45. package/ios/AudioStreamManager.swift +103 -9
  46. package/ios/AudioStreamManagerDelegate.swift +1 -0
  47. package/ios/AudioStudio.podspec +1 -1
  48. package/ios/AudioStudioModule.swift +6 -0
  49. package/ios/RecordingSettings.swift +48 -43
  50. package/package.json +163 -163
  51. package/plugin/tsconfig.json +8 -2
  52. package/src/AudioStudio.types.ts +48 -1
  53. package/src/AudioStudio.web.ts +152 -13
  54. package/src/AudioStudioModule.ts +6 -1
  55. package/src/events.ts +13 -1
  56. package/src/index.ts +1 -0
  57. package/src/useAudioRecorder.tsx +182 -2
  58. package/scripts/README.md +0 -58
@@ -41,6 +41,8 @@ function audioRecorderReducer(state, action) {
41
41
  size: 0,
42
42
  compression: undefined,
43
43
  analysisData: defaultAnalysis,
44
+ maxDurationMs: undefined,
45
+ maxDurationReached: false,
44
46
  };
45
47
  case 'STOP':
46
48
  return {
@@ -51,6 +53,8 @@ function audioRecorderReducer(state, action) {
51
53
  size: 0,
52
54
  compression: undefined,
53
55
  analysisData: undefined,
56
+ // Preserve max-duration state after stop so UI and agentic
57
+ // validation can explain why recording ended. START resets it.
54
58
  };
55
59
  case 'PAUSE':
56
60
  return { ...state, isPaused: true, isRecording: false };
@@ -75,9 +79,17 @@ function audioRecorderReducer(state, action) {
75
79
  format: action.payload.compression.format,
76
80
  }
77
81
  : undefined,
82
+ maxDurationMs: action.payload.maxDurationMs,
83
+ maxDurationReached: action.payload.maxDurationReached,
78
84
  };
79
85
  return newState;
80
86
  }
87
+ case 'MAX_DURATION_REACHED':
88
+ return {
89
+ ...state,
90
+ maxDurationMs: action.payload.maxDurationMs,
91
+ maxDurationReached: true,
92
+ };
81
93
  case 'UPDATE_ANALYSIS':
82
94
  return {
83
95
  ...state,
@@ -102,6 +114,8 @@ function useAudioRecorder({ logger, audioWorkletUrl, featuresExtratorUrl, } = {}
102
114
  size: 0,
103
115
  compression: undefined,
104
116
  analysisData: undefined,
117
+ maxDurationMs: undefined,
118
+ maxDurationReached: false,
105
119
  });
106
120
  const startResultRef = (0, react_1.useRef)(null);
107
121
  const analysisListenerRef = (0, react_1.useRef)(null);
@@ -126,8 +140,11 @@ function useAudioRecorder({ logger, audioWorkletUrl, featuresExtratorUrl, } = {}
126
140
  durationMs: 0,
127
141
  size: 0,
128
142
  compression: undefined,
143
+ maxDurationMs: undefined,
144
+ maxDurationReached: false,
129
145
  });
130
146
  const recordingConfigRef = (0, react_1.useRef)(null);
147
+ const maxDurationHandledRef = (0, react_1.useRef)(false);
131
148
  // Generate unique instance ID for debugging
132
149
  const instanceId = (0, react_1.useId)().replace(/:/g, '').slice(0, 5);
133
150
  const handleAudioAnalysis = (0, react_1.useCallback)(async ({ analysis, visualizationDuration, }) => {
@@ -293,10 +310,104 @@ function useAudioRecorder({ logger, audioWorkletUrl, featuresExtratorUrl, } = {}
293
310
  logger?.error(`Error processing audio event:`, error);
294
311
  }
295
312
  }, []);
313
+ const handleMaxDurationReached = (0, react_1.useCallback)(async (event) => {
314
+ if (maxDurationHandledRef.current) {
315
+ return;
316
+ }
317
+ maxDurationHandledRef.current = true;
318
+ const config = recordingConfigRef.current;
319
+ const callbackEvent = {
320
+ ...event,
321
+ autoStopped: event.autoStopped || !!config?.autoStopOnMaxDuration,
322
+ };
323
+ stateRef.current.maxDurationMs = callbackEvent.maxDurationMs;
324
+ stateRef.current.maxDurationReached = true;
325
+ dispatch({
326
+ type: 'MAX_DURATION_REACHED',
327
+ payload: callbackEvent,
328
+ });
329
+ try {
330
+ config?.onMaxDurationReached?.(callbackEvent);
331
+ }
332
+ catch (error) {
333
+ logger?.error(`Error in max duration callback:`, error);
334
+ }
335
+ const finishStoppedState = () => {
336
+ if (analysisListenerRef.current) {
337
+ analysisListenerRef.current.remove();
338
+ analysisListenerRef.current = null;
339
+ }
340
+ onAudioStreamRef.current = null;
341
+ stateRef.current.isRecording = false;
342
+ stateRef.current.isPaused = false;
343
+ dispatch({ type: 'STOP' });
344
+ };
345
+ const waitForPlatformAutoStop = async () => {
346
+ const timeoutMs = 3000;
347
+ const startedAt = Date.now();
348
+ let lastStatus;
349
+ while (Date.now() - startedAt < timeoutMs) {
350
+ await new Promise((resolve) => setTimeout(resolve, 50));
351
+ try {
352
+ const currentStatus = audioStudio.status();
353
+ lastStatus = currentStatus;
354
+ if (!currentStatus.isRecording &&
355
+ !currentStatus.isPaused) {
356
+ finishStoppedState();
357
+ return;
358
+ }
359
+ }
360
+ catch (error) {
361
+ logger?.warn(`Error checking status after max duration auto-stop:`, error);
362
+ break;
363
+ }
364
+ }
365
+ if (lastStatus &&
366
+ (lastStatus.isRecording || lastStatus.isPaused)) {
367
+ try {
368
+ await audioStudio.stopRecording();
369
+ }
370
+ catch (error) {
371
+ logger?.warn(`Error completing max duration auto-stop fallback:`, error);
372
+ }
373
+ }
374
+ // At this point platform-owned auto-stop did not settle cleanly.
375
+ // Clear hook state so the UI does not stay stuck as recording.
376
+ finishStoppedState();
377
+ };
378
+ // Only the original event tells us whether the platform already
379
+ // owns auto-stop. Keep stream callbacks alive until status confirms
380
+ // stop completion so native final audio flushes can still reach JS.
381
+ if (event.autoStopped && stateRef.current.isRecording) {
382
+ await waitForPlatformAutoStop();
383
+ return;
384
+ }
385
+ if (config?.autoStopOnMaxDuration &&
386
+ !event.autoStopped &&
387
+ stateRef.current.isRecording) {
388
+ try {
389
+ await audioStudio.stopRecording();
390
+ finishStoppedState();
391
+ }
392
+ catch (error) {
393
+ logger?.error(`Error auto-stopping on max duration:`, error);
394
+ }
395
+ }
396
+ }, [audioStudio, dispatch, logger]);
296
397
  const checkStatus = (0, react_1.useCallback)(async () => {
297
398
  try {
298
399
  const status = audioStudio.status();
299
400
  logger?.debug(`Status: paused: ${status.isPaused} isRecording: ${status.isRecording} durationMs: ${status.durationMs} size: ${status.size}`, status.compression);
401
+ if (status.maxDurationReached === true &&
402
+ status.maxDurationMs != null &&
403
+ !stateRef.current.maxDurationReached) {
404
+ await handleMaxDurationReached({
405
+ durationMs: status.durationMs,
406
+ maxDurationMs: status.maxDurationMs,
407
+ overrunMs: Math.max(0, status.durationMs - status.maxDurationMs),
408
+ autoStopped: false,
409
+ });
410
+ }
300
411
  // Only dispatch if values actually changed
301
412
  if (status.isRecording !== stateRef.current.isRecording ||
302
413
  status.isPaused !== stateRef.current.isPaused) {
@@ -311,16 +422,24 @@ function useAudioRecorder({ logger, audioWorkletUrl, featuresExtratorUrl, } = {}
311
422
  });
312
423
  }
313
424
  if (status.durationMs !== stateRef.current.durationMs ||
314
- status.size !== stateRef.current.size) {
425
+ status.size !== stateRef.current.size ||
426
+ status.maxDurationMs !== stateRef.current.maxDurationMs ||
427
+ status.maxDurationReached !==
428
+ stateRef.current.maxDurationReached) {
315
429
  stateRef.current.durationMs = status.durationMs;
316
430
  stateRef.current.size = status.size;
317
431
  stateRef.current.compression = status.compression;
432
+ stateRef.current.maxDurationMs = status.maxDurationMs;
433
+ stateRef.current.maxDurationReached =
434
+ status.maxDurationReached ?? false;
318
435
  dispatch({
319
436
  type: 'UPDATE_STATUS',
320
437
  payload: {
321
438
  durationMs: status.durationMs,
322
439
  size: status.size,
323
440
  compression: status.compression,
441
+ maxDurationMs: status.maxDurationMs,
442
+ maxDurationReached: status.maxDurationReached,
324
443
  },
325
444
  });
326
445
  }
@@ -328,7 +447,7 @@ function useAudioRecorder({ logger, audioWorkletUrl, featuresExtratorUrl, } = {}
328
447
  catch (error) {
329
448
  logger?.error(`Error getting status:`, error);
330
449
  }
331
- }, [audioStudio, logger]); // Only depend on audioStudio and logger
450
+ }, [audioStudio, handleMaxDurationReached, logger]);
332
451
  // Update ref when state changes
333
452
  (0, react_1.useEffect)(() => {
334
453
  stateRef.current = {
@@ -337,6 +456,8 @@ function useAudioRecorder({ logger, audioWorkletUrl, featuresExtratorUrl, } = {}
337
456
  durationMs: state.durationMs,
338
457
  size: state.size,
339
458
  compression: state.compression,
459
+ maxDurationMs: state.maxDurationMs,
460
+ maxDurationReached: state.maxDurationReached ?? false,
340
461
  };
341
462
  }, [
342
463
  state.isRecording,
@@ -344,6 +465,8 @@ function useAudioRecorder({ logger, audioWorkletUrl, featuresExtratorUrl, } = {}
344
465
  state.durationMs,
345
466
  state.size,
346
467
  state.compression,
468
+ state.maxDurationMs,
469
+ state.maxDurationReached,
347
470
  ]);
348
471
  const startRecording = (0, react_1.useCallback)(async (recordingOptions) => {
349
472
  // Validate the encoding configuration
@@ -362,10 +485,11 @@ function useAudioRecorder({ logger, audioWorkletUrl, featuresExtratorUrl, } = {}
362
485
  encoding: validationResult.encoding,
363
486
  };
364
487
  recordingConfigRef.current = validatedOptions;
488
+ maxDurationHandledRef.current = false;
365
489
  logger?.debug(`start recording with validated config`, validatedOptions);
366
490
  analysisRef.current = { ...defaultAnalysis }; // Reset analysis data
367
491
  fullAnalysisRef.current = { ...defaultAnalysis };
368
- const { onAudioStream, onRecordingInterrupted, onAudioAnalysis, keepFullAnalysis: _keepFullAnalysis, ...options } = validatedOptions;
492
+ const { onAudioStream, onRecordingInterrupted, onMaxDurationReached, onAudioAnalysis, keepFullAnalysis: _keepFullAnalysis, ...options } = validatedOptions;
369
493
  const { enableProcessing } = options;
370
494
  const maxRecentDataDuration = 10000; // TODO compute maxRecentDataDuration based on screen dimensions
371
495
  if (typeof onAudioStream === 'function') {
@@ -402,7 +526,7 @@ function useAudioRecorder({ logger, audioWorkletUrl, featuresExtratorUrl, } = {}
402
526
  logger?.debug(`preparing recording`, recordingOptions);
403
527
  analysisRef.current = { ...defaultAnalysis }; // Reset analysis data
404
528
  fullAnalysisRef.current = { ...defaultAnalysis };
405
- const { onAudioStream, onRecordingInterrupted, onAudioAnalysis, keepFullAnalysis: _keepFullAnalysis, ...options } = recordingOptions;
529
+ const { onAudioStream, onRecordingInterrupted, onMaxDurationReached, onAudioAnalysis, keepFullAnalysis: _keepFullAnalysis, ...options } = recordingOptions;
406
530
  // Store onAudioStream for later use when recording starts
407
531
  if (typeof onAudioStream === 'function') {
408
532
  onAudioStreamRef.current = onAudioStream;
@@ -436,6 +560,7 @@ function useAudioRecorder({ logger, audioWorkletUrl, featuresExtratorUrl, } = {}
436
560
  onAudioStreamRef.current = null;
437
561
  // Note: We deliberately DON'T clear recordingConfigRef here to preserve interruption callback
438
562
  logger?.debug(`recording stopped`, stopResult);
563
+ maxDurationHandledRef.current = false;
439
564
  dispatch({ type: 'STOP' });
440
565
  return stopResult;
441
566
  }, [dispatch]);
@@ -451,6 +576,14 @@ function useAudioRecorder({ logger, audioWorkletUrl, featuresExtratorUrl, } = {}
451
576
  dispatch({ type: 'RESUME' });
452
577
  return resumeResult;
453
578
  }, [dispatch]);
579
+ (0, react_1.useEffect)(() => {
580
+ const subscription = (0, events_1.addMaxDurationReachedListener)(async (event) => {
581
+ await handleMaxDurationReached(event);
582
+ });
583
+ return () => {
584
+ subscription.remove();
585
+ };
586
+ }, [handleMaxDurationReached]);
454
587
  (0, react_1.useEffect)(() => {
455
588
  let intervalId;
456
589
  if (state.isRecording || state.isPaused) {
@@ -548,6 +681,8 @@ function useAudioRecorder({ logger, audioWorkletUrl, featuresExtratorUrl, } = {}
548
681
  size: state.size,
549
682
  compression: state.compression,
550
683
  analysisData: state.analysisData,
684
+ maxDurationMs: state.maxDurationMs,
685
+ maxDurationReached: state.maxDurationReached,
551
686
  };
552
687
  }
553
688
  //# 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 RecordingConfig,\n StartRecordingResult,\n} from './AudioStudio.types'\nimport AudioStudioModule from './AudioStudioModule'\nimport { validateRecordingConfig } from './constants/platformLimitations'\nimport {\n addAudioAnalysisListener,\n addAudioEventListener,\n AudioEventPayload,\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}\n\ninterface RecorderReducerState {\n isRecording: boolean\n isPaused: boolean\n durationMs: number\n size: number\n compression?: CompressionInfo\n analysisData?: AudioAnalysis\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 }\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 }\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 }\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 }\n return newState\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 })\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 })\n\n const recordingConfigRef = useRef<RecordingConfig | 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 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 // 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 ) {\n stateRef.current.durationMs = status.durationMs\n stateRef.current.size = status.size\n stateRef.current.compression = status.compression\n dispatch({\n type: 'UPDATE_STATUS',\n payload: {\n durationMs: status.durationMs,\n size: status.size,\n compression: status.compression,\n },\n })\n }\n } catch (error) {\n logger?.error(`Error getting status:`, error)\n }\n }, [audioStudio, logger]) // Only depend on audioStudio and 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 }\n }, [\n state.isRecording,\n state.isPaused,\n state.durationMs,\n state.size,\n state.compression,\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 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 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 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 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 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 }\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 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,5 +1,6 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
1
2
  // packages/audio-studio/src/AudioRecorder.provider.tsx
2
- import React, { createContext, useContext } from 'react';
3
+ import { createContext, useContext } from 'react';
3
4
  import { useAudioRecorder } from './useAudioRecorder';
4
5
  const initContext = {
5
6
  isRecording: false,
@@ -26,9 +27,7 @@ const initContext = {
26
27
  const AudioRecorderContext = createContext(initContext);
27
28
  export const AudioRecorderProvider = ({ children, config = {}, }) => {
28
29
  const audioRecorder = useAudioRecorder(config);
29
- return (<AudioRecorderContext.Provider value={audioRecorder}>
30
- {children}
31
- </AudioRecorderContext.Provider>);
30
+ return (_jsx(AudioRecorderContext.Provider, { value: audioRecorder, children: children }));
32
31
  };
33
32
  export const useSharedAudioRecorder = () => {
34
33
  const context = useContext(AudioRecorderContext);
@@ -1 +1 @@
1
- {"version":3,"file":"AudioRecorder.provider.js","sourceRoot":"","sources":["../../src/AudioRecorder.provider.tsx"],"names":[],"mappings":"AAAA,uDAAuD;AACvD,OAAO,KAAK,EAAE,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAA;AAGxD,OAAO,EAAyB,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAE5E,MAAM,WAAW,GAA0B;IACvC,WAAW,EAAE,KAAK;IAClB,QAAQ,EAAE,KAAK;IACf,UAAU,EAAE,CAAC;IACb,IAAI,EAAE,CAAC;IACP,WAAW,EAAE,SAAS;IACtB,cAAc,EAAE,KAAK,IAAI,EAAE;QACvB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;IACtD,CAAC;IACD,aAAa,EAAE,KAAK,IAAI,EAAE;QACtB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;IACtD,CAAC;IACD,cAAc,EAAE,KAAK,IAAI,EAAE;QACvB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;IACtD,CAAC;IACD,eAAe,EAAE,KAAK,IAAI,EAAE;QACxB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;IACtD,CAAC;IACD,gBAAgB,EAAE,KAAK,IAAI,EAAE;QACzB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;IACtD,CAAC;CACJ,CAAA;AAED,MAAM,oBAAoB,GAAG,aAAa,CAAwB,WAAW,CAAC,CAAA;AAO9E,MAAM,CAAC,MAAM,qBAAqB,GAAyC,CAAC,EACxE,QAAQ,EACR,MAAM,GAAG,EAAE,GACd,EAAE,EAAE;IACD,MAAM,aAAa,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAA;IAC9C,OAAO,CACH,CAAC,oBAAoB,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,CAChD;YAAA,CAAC,QAAQ,CACb;QAAA,EAAE,oBAAoB,CAAC,QAAQ,CAAC,CACnC,CAAA;AACL,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,EAAE;IACvC,MAAM,OAAO,GAAG,UAAU,CAAC,oBAAoB,CAAC,CAAA;IAChD,IAAI,CAAC,OAAO,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CACX,qEAAqE,CACxE,CAAA;IACL,CAAC;IACD,OAAO,OAAO,CAAA;AAClB,CAAC,CAAA","sourcesContent":["// packages/audio-studio/src/AudioRecorder.provider.tsx\nimport React, { createContext, useContext } from 'react'\n\nimport { UseAudioRecorderState } from './AudioStudio.types'\nimport { UseAudioRecorderProps, useAudioRecorder } from './useAudioRecorder'\n\nconst initContext: UseAudioRecorderState = {\n isRecording: false,\n isPaused: false,\n durationMs: 0,\n size: 0,\n compression: undefined,\n startRecording: async () => {\n throw new Error('AudioRecorderProvider not found')\n },\n stopRecording: async () => {\n throw new Error('AudioRecorderProvider not found')\n },\n pauseRecording: async () => {\n throw new Error('AudioRecorderProvider not found')\n },\n resumeRecording: async () => {\n throw new Error('AudioRecorderProvider not found')\n },\n prepareRecording: async () => {\n throw new Error('AudioRecorderProvider not found')\n },\n}\n\nconst AudioRecorderContext = createContext<UseAudioRecorderState>(initContext)\n\ninterface AudioRecorderProviderProps {\n children: React.ReactNode\n config?: UseAudioRecorderProps\n}\n\nexport const AudioRecorderProvider: React.FC<AudioRecorderProviderProps> = ({\n children,\n config = {},\n}) => {\n const audioRecorder = useAudioRecorder(config)\n return (\n <AudioRecorderContext.Provider value={audioRecorder}>\n {children}\n </AudioRecorderContext.Provider>\n )\n}\n\nexport const useSharedAudioRecorder = () => {\n const context = useContext(AudioRecorderContext)\n if (!context) {\n throw new Error(\n 'useSharedAudioRecorder must be used within an AudioRecorderProvider'\n )\n }\n return context\n}\n"]}
1
+ {"version":3,"file":"AudioRecorder.provider.js","sourceRoot":"","sources":["../../src/AudioRecorder.provider.tsx"],"names":[],"mappings":";AAAA,uDAAuD;AACvD,OAAc,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAA;AAGxD,OAAO,EAAyB,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAE5E,MAAM,WAAW,GAA0B;IACvC,WAAW,EAAE,KAAK;IAClB,QAAQ,EAAE,KAAK;IACf,UAAU,EAAE,CAAC;IACb,IAAI,EAAE,CAAC;IACP,WAAW,EAAE,SAAS;IACtB,cAAc,EAAE,KAAK,IAAI,EAAE;QACvB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;IACtD,CAAC;IACD,aAAa,EAAE,KAAK,IAAI,EAAE;QACtB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;IACtD,CAAC;IACD,cAAc,EAAE,KAAK,IAAI,EAAE;QACvB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;IACtD,CAAC;IACD,eAAe,EAAE,KAAK,IAAI,EAAE;QACxB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;IACtD,CAAC;IACD,gBAAgB,EAAE,KAAK,IAAI,EAAE;QACzB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;IACtD,CAAC;CACJ,CAAA;AAED,MAAM,oBAAoB,GAAG,aAAa,CAAwB,WAAW,CAAC,CAAA;AAO9E,MAAM,CAAC,MAAM,qBAAqB,GAAyC,CAAC,EACxE,QAAQ,EACR,MAAM,GAAG,EAAE,GACd,EAAE,EAAE;IACD,MAAM,aAAa,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAA;IAC9C,OAAO,CACH,KAAC,oBAAoB,CAAC,QAAQ,IAAC,KAAK,EAAE,aAAa,YAC9C,QAAQ,GACmB,CACnC,CAAA;AACL,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,EAAE;IACvC,MAAM,OAAO,GAAG,UAAU,CAAC,oBAAoB,CAAC,CAAA;IAChD,IAAI,CAAC,OAAO,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CACX,qEAAqE,CACxE,CAAA;IACL,CAAC;IACD,OAAO,OAAO,CAAA;AAClB,CAAC,CAAA","sourcesContent":["// packages/audio-studio/src/AudioRecorder.provider.tsx\nimport React, { createContext, useContext } from 'react'\n\nimport { UseAudioRecorderState } from './AudioStudio.types'\nimport { UseAudioRecorderProps, useAudioRecorder } from './useAudioRecorder'\n\nconst initContext: UseAudioRecorderState = {\n isRecording: false,\n isPaused: false,\n durationMs: 0,\n size: 0,\n compression: undefined,\n startRecording: async () => {\n throw new Error('AudioRecorderProvider not found')\n },\n stopRecording: async () => {\n throw new Error('AudioRecorderProvider not found')\n },\n pauseRecording: async () => {\n throw new Error('AudioRecorderProvider not found')\n },\n resumeRecording: async () => {\n throw new Error('AudioRecorderProvider not found')\n },\n prepareRecording: async () => {\n throw new Error('AudioRecorderProvider not found')\n },\n}\n\nconst AudioRecorderContext = createContext<UseAudioRecorderState>(initContext)\n\ninterface AudioRecorderProviderProps {\n children: React.ReactNode\n config?: UseAudioRecorderProps\n}\n\nexport const AudioRecorderProvider: React.FC<AudioRecorderProviderProps> = ({\n children,\n config = {},\n}) => {\n const audioRecorder = useAudioRecorder(config)\n return (\n <AudioRecorderContext.Provider value={audioRecorder}>\n {children}\n </AudioRecorderContext.Provider>\n )\n}\n\nexport const useSharedAudioRecorder = () => {\n const context = useContext(AudioRecorderContext)\n if (!context) {\n throw new Error(\n 'useSharedAudioRecorder must be used within an AudioRecorderProvider'\n )\n }\n return context\n}\n"]}