@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.
- package/CHANGELOG.md +12 -1
- package/README.md +12 -1
- package/build/cjs/AudioStudio.types.js.map +1 -1
- package/build/cjs/useAudioRecorder.js +115 -93
- package/build/cjs/useAudioRecorder.js.map +1 -1
- package/build/cjs/utils/nativeRecordingOptions.js +13 -0
- package/build/cjs/utils/nativeRecordingOptions.js.map +1 -0
- package/build/cjs/utils/nativeRecordingOptions.test.js +30 -0
- package/build/cjs/utils/nativeRecordingOptions.test.js.map +1 -0
- package/build/esm/AudioStudio.types.js.map +1 -1
- package/build/esm/useAudioRecorder.js +115 -93
- package/build/esm/useAudioRecorder.js.map +1 -1
- package/build/esm/utils/nativeRecordingOptions.js +10 -0
- package/build/esm/utils/nativeRecordingOptions.js.map +1 -0
- package/build/esm/utils/nativeRecordingOptions.test.js +28 -0
- package/build/esm/utils/nativeRecordingOptions.test.js.map +1 -0
- package/build/types/AudioStudio.types.d.ts +19 -5
- package/build/types/AudioStudio.types.d.ts.map +1 -1
- package/build/types/useAudioRecorder.d.ts +2 -1
- package/build/types/useAudioRecorder.d.ts.map +1 -1
- package/build/types/utils/nativeRecordingOptions.d.ts +28 -0
- package/build/types/utils/nativeRecordingOptions.d.ts.map +1 -0
- package/build/types/utils/nativeRecordingOptions.test.d.ts +2 -0
- package/build/types/utils/nativeRecordingOptions.test.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/AudioStudio.types.ts +27 -5
- package/src/useAudioRecorder.tsx +161 -126
- package/src/utils/nativeRecordingOptions.test.ts +29 -0
- 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 {
|
|
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
|
-
|
|
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
|
|
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
|
-
}, [
|
|
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
|
-
|
|
421
|
-
|
|
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 =
|
|
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:
|
|
436
|
-
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,
|
|
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
|
|
497
|
-
|
|
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
|
|
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
|
|
533
|
-
const cleanOptions =
|
|
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
|
-
|
|
541
|
-
|
|
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"]}
|