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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/CHANGELOG.md +12 -1
  2. package/README.md +41 -1
  3. package/android/src/main/java/net/siteed/audiostudio/AudioRecorderManager.kt +130 -0
  4. package/android/src/main/java/net/siteed/audiostudio/AudioStudioModule.kt +1 -0
  5. package/android/src/main/java/net/siteed/audiostudio/Constants.kt +2 -1
  6. package/android/src/main/java/net/siteed/audiostudio/RecordingConfig.kt +5 -1
  7. package/build/cjs/AudioStudio.types.js.map +1 -1
  8. package/build/cjs/AudioStudio.web.js +125 -13
  9. package/build/cjs/AudioStudio.web.js.map +1 -1
  10. package/build/cjs/AudioStudioModule.js +6 -1
  11. package/build/cjs/AudioStudioModule.js.map +1 -1
  12. package/build/cjs/events.js +4 -0
  13. package/build/cjs/events.js.map +1 -1
  14. package/build/cjs/index.js +3 -1
  15. package/build/cjs/index.js.map +1 -1
  16. package/build/cjs/useAudioRecorder.js +187 -30
  17. package/build/cjs/useAudioRecorder.js.map +1 -1
  18. package/build/cjs/utils/nativeRecordingOptions.js +13 -0
  19. package/build/cjs/utils/nativeRecordingOptions.js.map +1 -0
  20. package/build/cjs/utils/nativeRecordingOptions.test.js +30 -0
  21. package/build/cjs/utils/nativeRecordingOptions.test.js.map +1 -0
  22. package/build/esm/AudioStudio.types.js.map +1 -1
  23. package/build/esm/AudioStudio.web.js +125 -13
  24. package/build/esm/AudioStudio.web.js.map +1 -1
  25. package/build/esm/AudioStudioModule.js +6 -1
  26. package/build/esm/AudioStudioModule.js.map +1 -1
  27. package/build/esm/events.js +3 -0
  28. package/build/esm/events.js.map +1 -1
  29. package/build/esm/index.js +1 -0
  30. package/build/esm/index.js.map +1 -1
  31. package/build/esm/useAudioRecorder.js +188 -31
  32. package/build/esm/useAudioRecorder.js.map +1 -1
  33. package/build/esm/utils/nativeRecordingOptions.js +10 -0
  34. package/build/esm/utils/nativeRecordingOptions.js.map +1 -0
  35. package/build/esm/utils/nativeRecordingOptions.test.js +28 -0
  36. package/build/esm/utils/nativeRecordingOptions.test.js.map +1 -0
  37. package/build/types/AudioStudio.types.d.ts +58 -1
  38. package/build/types/AudioStudio.types.d.ts.map +1 -1
  39. package/build/types/AudioStudio.web.d.ts +17 -1
  40. package/build/types/AudioStudio.web.d.ts.map +1 -1
  41. package/build/types/AudioStudioModule.d.ts.map +1 -1
  42. package/build/types/events.d.ts +2 -1
  43. package/build/types/events.d.ts.map +1 -1
  44. package/build/types/index.d.ts +1 -0
  45. package/build/types/index.d.ts.map +1 -1
  46. package/build/types/useAudioRecorder.d.ts +4 -1
  47. package/build/types/useAudioRecorder.d.ts.map +1 -1
  48. package/build/types/utils/nativeRecordingOptions.d.ts +28 -0
  49. package/build/types/utils/nativeRecordingOptions.d.ts.map +1 -0
  50. package/build/types/utils/nativeRecordingOptions.test.d.ts +2 -0
  51. package/build/types/utils/nativeRecordingOptions.test.d.ts.map +1 -0
  52. package/ios/AudioStreamManager.swift +103 -9
  53. package/ios/AudioStreamManagerDelegate.swift +1 -0
  54. package/ios/AudioStudioModule.swift +6 -0
  55. package/ios/RecordingSettings.swift +48 -43
  56. package/package.json +1 -1
  57. package/src/AudioStudio.types.ts +70 -1
  58. package/src/AudioStudio.web.ts +152 -13
  59. package/src/AudioStudioModule.ts +6 -1
  60. package/src/events.ts +13 -1
  61. package/src/index.ts +1 -0
  62. package/src/useAudioRecorder.tsx +260 -45
  63. package/src/utils/nativeRecordingOptions.test.ts +29 -0
  64. package/src/utils/nativeRecordingOptions.ts +20 -0
@@ -32,7 +32,13 @@ class AudioStudioWeb extends expo_modules_core_1.LegacyEventEmitter {
32
32
  totalCompressedSize = 0;
33
33
  maxBufferSize;
34
34
  eventCallback;
35
- constructor({ audioWorkletUrl, featuresExtratorUrl, logger, maxBufferSize = constants_1.DEFAULT_MAX_BUFFER_SIZE, }) {
35
+ moduleEventEmitter;
36
+ maxDurationTimer;
37
+ maxDurationTargetMs = 0;
38
+ maxDurationAccumulatedActiveMs = 0;
39
+ maxDurationSegmentStartMs = 0;
40
+ maxDurationReached = false;
41
+ constructor({ audioWorkletUrl, featuresExtratorUrl, logger, maxBufferSize = constants_1.DEFAULT_MAX_BUFFER_SIZE, emitEvent, }) {
36
42
  const mockNativeModule = {
37
43
  addListener: () => { },
38
44
  removeListeners: () => { },
@@ -59,6 +65,100 @@ class AudioStudioWeb extends expo_modules_core_1.LegacyEventEmitter {
59
65
  this.audioWorkletUrl = audioWorkletUrl;
60
66
  this.featuresExtratorUrl = featuresExtratorUrl;
61
67
  this.maxBufferSize = maxBufferSize;
68
+ this.moduleEventEmitter = emitEvent;
69
+ }
70
+ emitModuleEvent(eventName, params) {
71
+ this.emit(eventName, params);
72
+ this.moduleEventEmitter?.(eventName, params);
73
+ }
74
+ resetMaxDurationState(preserveReached = false) {
75
+ if (this.maxDurationTimer) {
76
+ clearTimeout(this.maxDurationTimer);
77
+ this.maxDurationTimer = undefined;
78
+ }
79
+ this.maxDurationSegmentStartMs = 0;
80
+ if (!preserveReached || !this.maxDurationReached) {
81
+ this.maxDurationTargetMs = 0;
82
+ this.maxDurationAccumulatedActiveMs = 0;
83
+ this.maxDurationReached = false;
84
+ }
85
+ }
86
+ getMaxDurationActiveMs(now = performance.now()) {
87
+ if (this.maxDurationSegmentStartMs <= 0) {
88
+ return this.maxDurationAccumulatedActiveMs;
89
+ }
90
+ return (this.maxDurationAccumulatedActiveMs +
91
+ (now - this.maxDurationSegmentStartMs));
92
+ }
93
+ scheduleMaxDurationTimer() {
94
+ if (this.maxDurationTargetMs <= 0 ||
95
+ this.maxDurationReached ||
96
+ !this.isRecording ||
97
+ this.isPaused) {
98
+ return;
99
+ }
100
+ if (this.maxDurationTimer) {
101
+ clearTimeout(this.maxDurationTimer);
102
+ }
103
+ const remainingMs = Math.max(0, this.maxDurationTargetMs - this.getMaxDurationActiveMs());
104
+ this.maxDurationTimer = setTimeout(() => {
105
+ this.maxDurationTimer = undefined;
106
+ this.emitMaxDurationReached();
107
+ }, remainingMs);
108
+ }
109
+ startMaxDurationTimer(recordingConfig) {
110
+ this.resetMaxDurationState();
111
+ const targetMs = Number(recordingConfig.maxDurationMs ?? 0);
112
+ if (!Number.isFinite(targetMs) || targetMs <= 0) {
113
+ return;
114
+ }
115
+ this.maxDurationTargetMs = targetMs;
116
+ this.maxDurationSegmentStartMs = performance.now();
117
+ this.scheduleMaxDurationTimer();
118
+ }
119
+ pauseMaxDurationTimer() {
120
+ if (this.maxDurationTimer) {
121
+ clearTimeout(this.maxDurationTimer);
122
+ this.maxDurationTimer = undefined;
123
+ }
124
+ if (this.maxDurationSegmentStartMs > 0) {
125
+ this.maxDurationAccumulatedActiveMs = this.getMaxDurationActiveMs();
126
+ this.maxDurationSegmentStartMs = 0;
127
+ }
128
+ }
129
+ resumeMaxDurationTimer() {
130
+ if (this.maxDurationTargetMs <= 0 || this.maxDurationReached) {
131
+ return;
132
+ }
133
+ this.maxDurationSegmentStartMs = performance.now();
134
+ this.scheduleMaxDurationTimer();
135
+ }
136
+ emitMaxDurationReached() {
137
+ if (this.maxDurationTargetMs <= 0 || this.maxDurationReached) {
138
+ return;
139
+ }
140
+ const durationMs = Math.round(this.getMaxDurationActiveMs());
141
+ this.maxDurationReached = true;
142
+ const autoStopped = !!this.recordingConfig?.autoStopOnMaxDuration;
143
+ this.emitModuleEvent('MaxDurationReached', {
144
+ durationMs,
145
+ maxDurationMs: this.maxDurationTargetMs,
146
+ overrunMs: Math.max(0, durationMs - this.maxDurationTargetMs),
147
+ streamUuid: this.streamUuid ?? undefined,
148
+ autoStopped,
149
+ });
150
+ if (autoStopped) {
151
+ this.stopRecording().catch((error) => {
152
+ this.logger?.error('Error auto-stopping on max duration:', error);
153
+ });
154
+ }
155
+ }
156
+ flushExpiredMaxDuration() {
157
+ if (this.maxDurationTargetMs > 0 &&
158
+ !this.maxDurationReached &&
159
+ this.getMaxDurationActiveMs() >= this.maxDurationTargetMs) {
160
+ this.emitMaxDurationReached();
161
+ }
62
162
  }
63
163
  // Utility to handle user media stream
64
164
  async getMediaStream() {
@@ -188,6 +288,7 @@ class AudioStudioWeb extends expo_modules_core_1.LegacyEventEmitter {
188
288
  this.currentInterval = recordingConfig.interval ?? 1000;
189
289
  this.currentIntervalAnalysis = recordingConfig.intervalAnalysis ?? 500;
190
290
  this.lastEmittedAnalysisTime = Date.now();
291
+ this.startMaxDurationTimer(recordingConfig);
191
292
  // Use custom filename if provided, otherwise fallback to timestamp
192
293
  if (recordingConfig.filename) {
193
294
  // Remove any existing extension from the filename
@@ -224,9 +325,10 @@ class AudioStudioWeb extends expo_modules_core_1.LegacyEventEmitter {
224
325
  // Update local state if the interruption should pause recording
225
326
  if (event.isPaused) {
226
327
  this.isPaused = true;
328
+ this.pausedTime = Date.now();
329
+ this.pauseMaxDurationTimer();
227
330
  // If this is a device disconnection, handle according to behavior setting
228
331
  if (event.reason === 'deviceDisconnected') {
229
- this.pausedTime = Date.now();
230
332
  // Check if we should try fallback to another device
231
333
  if (this.recordingConfig?.deviceDisconnectionBehavior ===
232
334
  'fallback') {
@@ -235,7 +337,7 @@ class AudioStudioWeb extends expo_modules_core_1.LegacyEventEmitter {
235
337
  this.handleDeviceFallback().catch((error) => {
236
338
  // If fallback fails, emit warning
237
339
  this.logger?.error('Device fallback failed:', error);
238
- this.emit('onRecordingInterrupted', {
340
+ this.emitModuleEvent('onRecordingInterrupted', {
239
341
  reason: 'deviceSwitchFailed',
240
342
  isPaused: true,
241
343
  timestamp: Date.now(),
@@ -246,17 +348,17 @@ class AudioStudioWeb extends expo_modules_core_1.LegacyEventEmitter {
246
348
  else {
247
349
  // Just warn about disconnection if fallback not enabled
248
350
  this.logger?.warn('Device disconnected - recording paused automatically');
249
- this.emit('onRecordingInterrupted', event);
351
+ this.emitModuleEvent('onRecordingInterrupted', event);
250
352
  }
251
353
  }
252
354
  else {
253
355
  // For other interruption types, just emit the event
254
- this.emit('onRecordingInterrupted', event);
356
+ this.emitModuleEvent('onRecordingInterrupted', event);
255
357
  }
256
358
  }
257
359
  else {
258
360
  // If not causing a pause, just forward the event
259
- this.emit('onRecordingInterrupted', event);
361
+ this.emitModuleEvent('onRecordingInterrupted', event);
260
362
  }
261
363
  }
262
364
  /**
@@ -278,7 +380,7 @@ class AudioStudioWeb extends expo_modules_core_1.LegacyEventEmitter {
278
380
  * Handler for audio analysis events from the WebRecorder
279
381
  */
280
382
  customRecorderAnalysisCallback(audioAnalysisData) {
281
- this.emit('AudioAnalysis', audioAnalysisData);
383
+ this.emitModuleEvent('AudioAnalysis', audioAnalysisData);
282
384
  }
283
385
  // Get recording duration
284
386
  getRecordingDuration() {
@@ -306,6 +408,7 @@ class AudioStudioWeb extends expo_modules_core_1.LegacyEventEmitter {
306
408
  else {
307
409
  this.currentDurationMs += chunkDurationMs;
308
410
  }
411
+ this.flushExpiredMaxDuration();
309
412
  const audioEventPayload = {
310
413
  fileUri,
311
414
  mimeType: `audio/${this.extension}`,
@@ -324,7 +427,7 @@ class AudioStudioWeb extends expo_modules_core_1.LegacyEventEmitter {
324
427
  }
325
428
  : undefined,
326
429
  };
327
- this.emit('AudioData', audioEventPayload);
430
+ this.emitModuleEvent('AudioData', audioEventPayload);
328
431
  }
329
432
  // Stop recording
330
433
  async stopRecording() {
@@ -333,6 +436,7 @@ class AudioStudioWeb extends expo_modules_core_1.LegacyEventEmitter {
333
436
  }
334
437
  this.logger?.debug('Starting stop process');
335
438
  try {
439
+ this.pauseMaxDurationTimer();
336
440
  const { compressedBlob, uncompressedBlob } = await this.customRecorder.stop();
337
441
  this.isRecording = false;
338
442
  this.isPaused = false;
@@ -400,6 +504,7 @@ class AudioStudioWeb extends expo_modules_core_1.LegacyEventEmitter {
400
504
  this.totalCompressedSize = 0;
401
505
  this.lastEmittedCompressionSize = 0;
402
506
  this.audioChunks = [];
507
+ this.resetMaxDurationState(true);
403
508
  return result;
404
509
  }
405
510
  catch (error) {
@@ -422,12 +527,14 @@ class AudioStudioWeb extends expo_modules_core_1.LegacyEventEmitter {
422
527
  }
423
528
  this.isPaused = true;
424
529
  this.pausedTime = Date.now();
530
+ this.pauseMaxDurationTimer();
425
531
  }
426
532
  catch (error) {
427
533
  this.logger?.error('Error in pauseRecording', error);
428
534
  // Even if the pause operation failed, make sure our state is consistent
429
535
  this.isPaused = true;
430
536
  this.pausedTime = Date.now();
537
+ this.pauseMaxDurationTimer();
431
538
  }
432
539
  }
433
540
  // Resume recording
@@ -455,7 +562,8 @@ class AudioStudioWeb extends expo_modules_core_1.LegacyEventEmitter {
455
562
  const pauseDuration = Date.now() - this.pausedTime;
456
563
  this.recordingStartTime += pauseDuration;
457
564
  this.pausedTime = 0;
458
- this.emit('onRecordingInterrupted', {
565
+ this.resumeMaxDurationTimer();
566
+ this.emitModuleEvent('onRecordingInterrupted', {
459
567
  reason: 'userResumed',
460
568
  isPaused: false,
461
569
  timestamp: Date.now(),
@@ -464,7 +572,7 @@ class AudioStudioWeb extends expo_modules_core_1.LegacyEventEmitter {
464
572
  catch (error) {
465
573
  this.logger?.error('Resume failed:', error);
466
574
  // Fallback to emitting a general failure if resume fails unexpectedly
467
- this.emit('onRecordingInterrupted', {
575
+ this.emitModuleEvent('onRecordingInterrupted', {
468
576
  reason: 'resumeFailed', // Use a more specific reason
469
577
  isPaused: true, // Remain paused if resume fails
470
578
  timestamp: Date.now(),
@@ -474,6 +582,7 @@ class AudioStudioWeb extends expo_modules_core_1.LegacyEventEmitter {
474
582
  }
475
583
  // Get current status
476
584
  status() {
585
+ this.flushExpiredMaxDuration();
477
586
  const durationMs = this.getRecordingDuration();
478
587
  const status = {
479
588
  isRecording: this.isRecording,
@@ -494,6 +603,8 @@ class AudioStudioWeb extends expo_modules_core_1.LegacyEventEmitter {
494
603
  compressedFileUri: `${this.streamUuid}.webm`,
495
604
  }
496
605
  : undefined,
606
+ maxDurationMs: this.maxDurationTargetMs > 0 ? this.maxDurationTargetMs : undefined,
607
+ maxDurationReached: this.maxDurationReached,
497
608
  };
498
609
  return status;
499
610
  }
@@ -544,7 +655,7 @@ class AudioStudioWeb extends expo_modules_core_1.LegacyEventEmitter {
544
655
  // Try to get a fallback device
545
656
  const fallbackDeviceInfo = await this.getFallbackDevice();
546
657
  if (!fallbackDeviceInfo) {
547
- this.emit('onRecordingInterrupted', {
658
+ this.emitModuleEvent('onRecordingInterrupted', {
548
659
  reason: 'deviceSwitchFailed',
549
660
  isPaused: true,
550
661
  timestamp: Date.now(),
@@ -592,6 +703,7 @@ class AudioStudioWeb extends expo_modules_core_1.LegacyEventEmitter {
592
703
  // Update recording state
593
704
  this.isPaused = false;
594
705
  this.recordingStartTime = Date.now();
706
+ this.resumeMaxDurationTimer();
595
707
  // Restore size counters to maintain continuity
596
708
  this.currentSize = previousTotalSize;
597
709
  this.lastEmittedSize = previousLastEmittedSize;
@@ -609,7 +721,7 @@ class AudioStudioWeb extends expo_modules_core_1.LegacyEventEmitter {
609
721
  catch (error) {
610
722
  this.logger?.error('Failed to start recording with fallback device', error);
611
723
  this.isPaused = true;
612
- this.emit('onRecordingInterrupted', {
724
+ this.emitModuleEvent('onRecordingInterrupted', {
613
725
  reason: 'deviceSwitchFailed',
614
726
  isPaused: true,
615
727
  timestamp: Date.now(),
@@ -621,7 +733,7 @@ class AudioStudioWeb extends expo_modules_core_1.LegacyEventEmitter {
621
733
  catch (error) {
622
734
  this.logger?.error('Failed to use fallback device', error);
623
735
  this.isPaused = true;
624
- this.emit('onRecordingInterrupted', {
736
+ this.emitModuleEvent('onRecordingInterrupted', {
625
737
  reason: 'deviceSwitchFailed',
626
738
  isPaused: true,
627
739
  timestamp: Date.now(),
@@ -1 +1 @@
1
- {"version":3,"file":"AudioStudio.web.js","sourceRoot":"","sources":["../../src/AudioStudio.web.ts"],"names":[],"mappings":"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","sourcesContent":["// src/AudioStudio.web.ts\nimport { LegacyEventEmitter } from 'expo-modules-core'\n\nimport { AudioAnalysis } from './AudioAnalysis/AudioAnalysis.types'\nimport {\n AudioRecording,\n AudioStreamStatus,\n BitDepth,\n ConsoleLike,\n RecordingConfig,\n RecordingInterruptionReason,\n StartRecordingResult,\n} from './AudioStudio.types'\nimport { WebRecorder } from './WebRecorder.web'\nimport {\n DEFAULT_BIT_DEPTH,\n DEFAULT_INTERVAL_MS,\n DEFAULT_ANALYSIS_INTERVAL_MS,\n DEFAULT_MAX_BUFFER_SIZE,\n} from './constants'\nimport { AudioEventPayload } from './events'\nimport { encodingToBitDepth } from './utils/encodingToBitDepth'\n\nexport interface AudioStreamEvent {\n type: string\n device?: string\n timestamp: Date\n}\n\nexport interface AudioStudioOptions {\n logger?: ConsoleLike\n eventCallback?: (event: AudioStreamEvent) => void\n}\n\nexport interface EmitAudioEventProps {\n data: Float32Array\n position: number\n compression?: {\n data: Blob\n size: number\n totalSize: number\n mimeType: string\n format: string\n bitrate: number\n }\n}\nexport type EmitAudioEventFunction = (_: EmitAudioEventProps) => void\nexport type EmitAudioAnalysisFunction = (_: AudioAnalysis) => void\n\nexport interface AudioStudioWebProps {\n logger?: ConsoleLike\n audioWorkletUrl: string\n featuresExtratorUrl: string\n maxBufferSize?: number // Maximum number of chunks to keep in memory\n}\n\nexport class AudioStudioWeb extends LegacyEventEmitter {\n customRecorder: WebRecorder | null\n audioChunks: Float32Array[]\n isRecording: boolean\n isPaused: boolean\n recordingStartTime: number\n pausedTime: number\n currentDurationMs: number\n currentSize: number\n currentInterval: number\n currentIntervalAnalysis: number\n lastEmittedSize: number\n lastEmittedTime: number\n lastEmittedCompressionSize: number\n lastEmittedAnalysisTime: number\n streamUuid: string | null\n extension: 'webm' | 'wav' = 'wav' // Default extension is 'wav'\n recordingConfig?: RecordingConfig\n bitDepth: BitDepth // Bit depth of the audio\n audioWorkletUrl: string\n featuresExtratorUrl: string\n logger?: ConsoleLike\n latestPosition: number = 0\n totalCompressedSize: number = 0\n private readonly maxBufferSize: number\n private eventCallback?: (event: AudioStreamEvent) => void\n\n constructor({\n audioWorkletUrl,\n featuresExtratorUrl,\n logger,\n maxBufferSize = DEFAULT_MAX_BUFFER_SIZE,\n }: AudioStudioWebProps) {\n const mockNativeModule = {\n addListener: () => {},\n removeListeners: () => {},\n }\n super(mockNativeModule) // Pass the mock native module to the parent class\n\n this.logger = logger\n this.customRecorder = null\n this.audioChunks = []\n this.isRecording = false\n this.isPaused = false\n this.recordingStartTime = 0\n this.pausedTime = 0\n this.currentDurationMs = 0\n this.currentSize = 0\n this.bitDepth = DEFAULT_BIT_DEPTH\n this.currentInterval = DEFAULT_INTERVAL_MS\n this.currentIntervalAnalysis = DEFAULT_ANALYSIS_INTERVAL_MS\n this.lastEmittedSize = 0\n this.lastEmittedTime = 0\n this.latestPosition = 0\n this.lastEmittedCompressionSize = 0\n this.lastEmittedAnalysisTime = 0\n this.streamUuid = null // Initialize UUID on first recording start\n this.audioWorkletUrl = audioWorkletUrl\n this.featuresExtratorUrl = featuresExtratorUrl\n this.maxBufferSize = maxBufferSize\n }\n\n // Utility to handle user media stream\n async getMediaStream() {\n try {\n this.logger?.debug('Requesting user media (microphone)...')\n\n // First check if the browser supports the necessary audio APIs\n if (!navigator?.mediaDevices?.getUserMedia) {\n this.logger?.error(\n 'Browser does not support mediaDevices.getUserMedia'\n )\n throw new Error('Browser does not support audio recording')\n }\n\n // Get media with detailed audio constraints for better diagnostics\n const constraints = {\n audio: {\n echoCancellation: true,\n noiseSuppression: true,\n autoGainControl: true,\n // Add deviceId constraint if specified\n ...(this.recordingConfig?.deviceId\n ? {\n deviceId: {\n exact: this.recordingConfig.deviceId,\n },\n }\n : {}),\n },\n }\n\n this.logger?.debug('Media constraints:', constraints)\n\n const stream =\n await navigator.mediaDevices.getUserMedia(constraints)\n\n // Get detailed info about the audio track for debugging\n const audioTracks = stream.getAudioTracks()\n if (audioTracks.length > 0) {\n const track = audioTracks[0]\n const settings = track.getSettings()\n this.logger?.debug('Audio track obtained:', {\n label: track.label,\n id: track.id,\n enabled: track.enabled,\n muted: track.muted,\n readyState: track.readyState,\n settings,\n })\n } else {\n this.logger?.warn('Stream has no audio tracks!')\n }\n\n return stream\n } catch (error) {\n this.logger?.error('Failed to get media stream:', error)\n throw error\n }\n }\n\n // Prepare recording with options\n async prepareRecording(\n recordingConfig: RecordingConfig = {}\n ): Promise<boolean> {\n if (this.isRecording) {\n this.logger?.warn(\n 'Cannot prepare: Recording is already in progress'\n )\n return false\n }\n\n try {\n // Check permissions and initialize basic settings\n await this.getMediaStream().then((stream) => {\n // Just verify we can access the microphone by getting a stream, then release it\n stream.getTracks().forEach((track) => track.stop())\n })\n\n this.bitDepth = encodingToBitDepth({\n encoding: recordingConfig.encoding ?? 'pcm_32bit',\n })\n\n // Store recording configuration for later use\n this.recordingConfig = recordingConfig\n\n // Use custom filename if provided, otherwise fallback to timestamp\n if (recordingConfig.filename) {\n // Remove any existing extension from the filename\n this.streamUuid = recordingConfig.filename.replace(\n /\\.[^/.]+$/,\n ''\n )\n } else {\n this.streamUuid = Date.now().toString()\n }\n\n this.logger?.debug('Recording preparation completed successfully')\n return true\n } catch (error) {\n this.logger?.error('Error preparing recording:', error)\n return false\n }\n }\n\n // Start recording with options\n async startRecording(\n recordingConfig: RecordingConfig = {}\n ): Promise<StartRecordingResult> {\n if (this.isRecording) {\n throw new Error('Recording is already in progress')\n }\n\n // If we haven't prepared or have different settings, prepare now\n if (\n !this.recordingConfig ||\n this.recordingConfig.sampleRate !== recordingConfig.sampleRate ||\n this.recordingConfig.channels !== recordingConfig.channels ||\n this.recordingConfig.encoding !== recordingConfig.encoding\n ) {\n await this.prepareRecording(recordingConfig)\n } else {\n this.logger?.debug(\n 'Using previously prepared recording configuration'\n )\n }\n\n // Save recording config for reference\n this.recordingConfig = recordingConfig\n\n const audioContext = new (window.AudioContext ||\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore - Allow webkitAudioContext for Safari\n window.webkitAudioContext)()\n const stream = await this.getMediaStream()\n\n const source = audioContext.createMediaStreamSource(stream)\n\n this.customRecorder = new WebRecorder({\n logger: this.logger,\n audioContext,\n source,\n recordingConfig,\n emitAudioEventCallback: this.customRecorderEventCallback.bind(this),\n emitAudioAnalysisCallback:\n this.customRecorderAnalysisCallback.bind(this),\n onInterruption: this.handleRecordingInterruption.bind(this),\n })\n await this.customRecorder.init()\n this.customRecorder.start()\n\n this.isRecording = true\n this.recordingStartTime = Date.now()\n this.pausedTime = 0\n this.isPaused = false\n this.lastEmittedSize = 0\n this.lastEmittedTime = 0\n this.lastEmittedCompressionSize = 0\n this.currentInterval = recordingConfig.interval ?? 1000\n this.currentIntervalAnalysis = recordingConfig.intervalAnalysis ?? 500\n this.lastEmittedAnalysisTime = Date.now()\n\n // Use custom filename if provided, otherwise fallback to timestamp\n if (recordingConfig.filename) {\n // Remove any existing extension from the filename\n this.streamUuid = recordingConfig.filename.replace(/\\.[^/.]+$/, '')\n } else {\n this.streamUuid = Date.now().toString()\n }\n\n const fileUri = `${this.streamUuid}.${this.extension}`\n const streamConfig: StartRecordingResult = {\n fileUri,\n mimeType: `audio/${this.extension}`,\n bitDepth: this.bitDepth,\n channels: recordingConfig.channels ?? 1,\n sampleRate: recordingConfig.sampleRate ?? 44100,\n compression: recordingConfig.output?.compressed?.enabled\n ? {\n ...recordingConfig.output.compressed,\n bitrate:\n recordingConfig.output.compressed.bitrate ?? 128000,\n size: 0,\n mimeType: 'audio/webm',\n format:\n recordingConfig.output.compressed.format ?? 'opus',\n compressedFileUri: '',\n }\n : undefined,\n }\n return streamConfig\n }\n\n /**\n * Centralized handler for recording interruptions\n */\n private handleRecordingInterruption(event: {\n reason: RecordingInterruptionReason | string\n isPaused: boolean\n timestamp: number\n message?: string\n }): void {\n this.logger?.debug(`Received recording interruption: ${event.reason}`)\n\n // Update local state if the interruption should pause recording\n if (event.isPaused) {\n this.isPaused = true\n\n // If this is a device disconnection, handle according to behavior setting\n if (event.reason === 'deviceDisconnected') {\n this.pausedTime = Date.now()\n\n // Check if we should try fallback to another device\n if (\n this.recordingConfig?.deviceDisconnectionBehavior ===\n 'fallback'\n ) {\n this.logger?.debug(\n 'Device disconnected with fallback behavior - attempting to switch to default device'\n )\n\n // Try to restart with default device\n this.handleDeviceFallback().catch((error) => {\n // If fallback fails, emit warning\n this.logger?.error('Device fallback failed:', error)\n this.emit('onRecordingInterrupted', {\n reason: 'deviceSwitchFailed',\n isPaused: true,\n timestamp: Date.now(),\n message:\n 'Failed to switch to fallback device. Recording paused.',\n })\n })\n } else {\n // Just warn about disconnection if fallback not enabled\n this.logger?.warn(\n 'Device disconnected - recording paused automatically'\n )\n this.emit('onRecordingInterrupted', event)\n }\n } else {\n // For other interruption types, just emit the event\n this.emit('onRecordingInterrupted', event)\n }\n } else {\n // If not causing a pause, just forward the event\n this.emit('onRecordingInterrupted', event)\n }\n }\n\n /**\n * Handler for audio events from the WebRecorder\n */\n private customRecorderEventCallback({\n data,\n position,\n compression,\n }: EmitAudioEventProps): void {\n // Keep only the latest chunks based on maxBufferSize\n this.audioChunks.push(new Float32Array(data))\n if (this.audioChunks.length > this.maxBufferSize) {\n this.audioChunks.shift() // Remove oldest chunk\n }\n this.currentSize += data.byteLength\n this.emitAudioEvent({ data, position, compression })\n this.lastEmittedTime = Date.now()\n this.lastEmittedSize = this.currentSize\n this.lastEmittedCompressionSize = compression?.size ?? 0\n }\n\n /**\n * Handler for audio analysis events from the WebRecorder\n */\n private customRecorderAnalysisCallback(\n audioAnalysisData: AudioAnalysis\n ): void {\n this.emit('AudioAnalysis', audioAnalysisData)\n }\n\n // Get recording duration\n private getRecordingDuration(): number {\n if (!this.isRecording) {\n return 0\n }\n\n return this.currentDurationMs\n }\n\n emitAudioEvent({ data, position, compression }: EmitAudioEventProps) {\n const fileUri = `${this.streamUuid}.${this.extension}`\n if (compression?.size) {\n this.lastEmittedCompressionSize = compression.size\n this.totalCompressedSize = compression.totalSize\n }\n\n // Update latest position for tracking\n this.latestPosition = position\n\n // Calculate duration of this chunk in ms\n const sampleRate = this.recordingConfig?.sampleRate || 44100\n const chunkDurationMs = (data.length / sampleRate) * 1000\n\n // Handle duration calculation\n if (this.customRecorder?.isFirstChunkAfterSwitch) {\n this.logger?.debug(\n `Processing first chunk after device switch, duration preserved at ${this.currentDurationMs}ms`\n )\n this.customRecorder.isFirstChunkAfterSwitch = false\n } else {\n this.currentDurationMs += chunkDurationMs\n }\n\n const audioEventPayload: AudioEventPayload = {\n fileUri,\n mimeType: `audio/${this.extension}`,\n lastEmittedSize: this.lastEmittedSize,\n deltaSize: data.byteLength,\n position,\n totalSize: this.currentSize,\n buffer: data,\n streamUuid: this.streamUuid ?? '',\n compression: compression\n ? {\n data: compression?.data,\n totalSize: this.totalCompressedSize,\n eventDataSize: compression?.size ?? 0,\n position,\n }\n : undefined,\n }\n\n this.emit('AudioData', audioEventPayload)\n }\n\n // Stop recording\n async stopRecording(): Promise<AudioRecording> {\n if (!this.customRecorder) {\n throw new Error('Recorder is not initialized')\n }\n\n this.logger?.debug('Starting stop process')\n\n try {\n const { compressedBlob, uncompressedBlob } =\n await this.customRecorder.stop()\n\n this.isRecording = false\n this.isPaused = false\n\n let compression: AudioRecording['compression']\n let fileUri = `${this.streamUuid}.${this.extension}`\n let mimeType = `audio/${this.extension}`\n\n // Handle both compressed and uncompressed blobs according to new output configuration\n const primaryEnabled =\n this.recordingConfig?.output?.primary?.enabled ?? true\n const compressedEnabled =\n this.recordingConfig?.output?.compressed?.enabled ?? false\n\n // Process compressed blob if available and enabled\n if (compressedBlob && compressedEnabled) {\n const compressedUri = URL.createObjectURL(compressedBlob)\n const compressedInfo = {\n compressedFileUri: compressedUri,\n size: compressedBlob.size,\n mimeType: 'audio/webm',\n format:\n this.recordingConfig?.output?.compressed?.format ??\n 'opus',\n bitrate:\n this.recordingConfig?.output?.compressed?.bitrate ??\n 128000,\n }\n\n // Store compression info\n compression = compressedInfo\n\n // If primary is disabled, use compressed as main file\n if (!primaryEnabled) {\n this.logger?.debug(\n 'Using compressed audio as primary output (primary disabled)'\n )\n fileUri = compressedUri\n mimeType = 'audio/webm'\n }\n }\n\n // Process uncompressed WAV if available and primary is enabled\n if (uncompressedBlob && primaryEnabled) {\n const wavUri = URL.createObjectURL(uncompressedBlob)\n fileUri = wavUri\n mimeType = 'audio/wav'\n } else if (!primaryEnabled && !compressedEnabled) {\n // No outputs enabled - streaming only mode\n this.logger?.debug('No outputs enabled - streaming only mode')\n fileUri = ''\n mimeType = 'audio/wav'\n }\n\n // Use the stored streamUuid for the final filename\n const filename = fileUri\n ? `${this.streamUuid}.${this.extension}`\n : 'stream-only'\n const result: AudioRecording = {\n fileUri,\n filename,\n bitDepth: this.bitDepth,\n createdAt: this.recordingStartTime,\n channels: this.recordingConfig?.channels ?? 1,\n sampleRate: this.recordingConfig?.sampleRate ?? 44100,\n durationMs: this.currentDurationMs,\n size: primaryEnabled ? this.currentSize : 0,\n mimeType,\n compression,\n }\n\n // Reset after creating the result\n this.streamUuid = null\n\n // Reset recording state variables to prepare for next recording\n this.currentDurationMs = 0\n this.currentSize = 0\n this.lastEmittedSize = 0\n this.totalCompressedSize = 0\n this.lastEmittedCompressionSize = 0\n this.audioChunks = []\n\n return result\n } catch (error) {\n this.logger?.error('Error stopping recording:', error)\n throw error\n }\n }\n\n // Pause recording\n async pauseRecording() {\n if (!this.isRecording) {\n throw new Error('Recording is not active')\n }\n\n if (this.isPaused) {\n this.logger?.debug('Recording already paused, skipping')\n return\n }\n\n try {\n if (this.customRecorder) {\n this.customRecorder.pause()\n }\n this.isPaused = true\n this.pausedTime = Date.now()\n } catch (error) {\n this.logger?.error('Error in pauseRecording', error)\n // Even if the pause operation failed, make sure our state is consistent\n this.isPaused = true\n this.pausedTime = Date.now()\n }\n }\n\n // Resume recording\n async resumeRecording() {\n if (!this.isPaused) {\n throw new Error('Recording is not paused')\n }\n\n this.logger?.debug('Resuming recording', {\n deviceDisconnectionBehavior:\n this.recordingConfig?.deviceDisconnectionBehavior,\n isDeviceDisconnected: this.customRecorder?.isDeviceDisconnected,\n })\n\n try {\n // If we have no recorder, or if the device is disconnected, always attempt fallback\n if (\n !this.customRecorder ||\n this.customRecorder.isDeviceDisconnected\n ) {\n this.logger?.debug(\n 'No recorder exists or device disconnected - attempting fallback on resume'\n )\n await this.handleDeviceFallback()\n // handleDeviceFallback will manage resuming if successful, or emit error if failed.\n return\n }\n\n // Normal resume path - device is still connected\n this.customRecorder.resume()\n this.isPaused = false\n\n // Adjust the recording start time to account for the pause duration\n const pauseDuration = Date.now() - this.pausedTime\n this.recordingStartTime += pauseDuration\n this.pausedTime = 0\n\n this.emit('onRecordingInterrupted', {\n reason: 'userResumed',\n isPaused: false,\n timestamp: Date.now(),\n })\n } catch (error) {\n this.logger?.error('Resume failed:', error)\n // Fallback to emitting a general failure if resume fails unexpectedly\n this.emit('onRecordingInterrupted', {\n reason: 'resumeFailed', // Use a more specific reason\n isPaused: true, // Remain paused if resume fails\n timestamp: Date.now(),\n message:\n 'Failed to resume recording. Please stop and start again.',\n })\n }\n }\n\n // Get current status\n status() {\n const durationMs = this.getRecordingDuration()\n\n const status: AudioStreamStatus = {\n isRecording: this.isRecording,\n isPaused: this.isPaused,\n durationMs,\n size: this.currentSize,\n interval: this.currentInterval,\n intervalAnalysis: this.currentIntervalAnalysis,\n mimeType: `audio/${this.extension}`,\n compression: this.recordingConfig?.output?.compressed?.enabled\n ? {\n size: this.totalCompressedSize,\n mimeType: 'audio/webm',\n format:\n this.recordingConfig.output.compressed.format ??\n 'opus',\n bitrate:\n this.recordingConfig.output.compressed.bitrate ??\n 128000,\n compressedFileUri: `${this.streamUuid}.webm`,\n }\n : undefined,\n }\n return status\n }\n\n /**\n * Handles device fallback when the current device is disconnected\n */\n private async handleDeviceFallback(): Promise<boolean> {\n this.logger?.debug('Starting device fallback procedure')\n\n if (!this.isRecording) {\n return false\n }\n\n try {\n // Save important state before switching\n const currentPosition = this.latestPosition\n const existingAudioChunks = [...this.audioChunks]\n\n // Save compressed chunks if available\n let compressedChunks: Blob[] = []\n if (this.customRecorder) {\n try {\n compressedChunks = this.customRecorder.getCompressedChunks()\n } catch (err) {\n this.logger?.warn('Failed to get compressed chunks:', err)\n }\n }\n\n // Save the current counter value for continuity\n let currentDataPointCounter = 0\n if (this.customRecorder) {\n currentDataPointCounter =\n this.customRecorder.getDataPointCounter()\n }\n\n // Clean up existing recorder\n if (this.customRecorder) {\n try {\n this.customRecorder.cleanup()\n } catch (cleanupError) {\n this.logger?.warn('Error during cleanup:', cleanupError)\n }\n }\n\n // Keep recording state true but mark as paused\n this.isPaused = true\n this.pausedTime = Date.now()\n\n // Store current size and other stats\n const previousTotalSize = this.currentSize\n const previousLastEmittedSize = this.lastEmittedSize\n const previousCompressedSize = this.totalCompressedSize\n\n // Try to get a fallback device\n const fallbackDeviceInfo = await this.getFallbackDevice()\n if (!fallbackDeviceInfo) {\n this.emit('onRecordingInterrupted', {\n reason: 'deviceSwitchFailed',\n isPaused: true,\n timestamp: Date.now(),\n message:\n 'Failed to switch to fallback device. Recording paused.',\n })\n return false\n }\n\n // Start recording with the new device\n try {\n const stream = await this.requestPermissionsAndGetUserMedia(\n fallbackDeviceInfo.deviceId\n )\n const audioContext = new (window.AudioContext ||\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore - Allow webkitAudioContext for Safari\n window.webkitAudioContext)()\n\n const source = audioContext.createMediaStreamSource(stream)\n\n // Create a new recorder with the fallback device\n this.customRecorder = new WebRecorder({\n logger: this.logger,\n audioContext,\n source,\n recordingConfig: this.recordingConfig || {},\n emitAudioEventCallback:\n this.customRecorderEventCallback.bind(this),\n emitAudioAnalysisCallback:\n this.customRecorderAnalysisCallback.bind(this),\n onInterruption: this.handleRecordingInterruption.bind(this),\n })\n\n await this.customRecorder.init()\n\n // Set the initial position to continue from the previous device\n this.customRecorder.setPosition(currentPosition)\n\n // Reset the data point counter to continue from where the previous device left off\n if (currentDataPointCounter > 0) {\n this.customRecorder.resetDataPointCounter(\n currentDataPointCounter\n )\n }\n\n // Prepare the recorder to handle the device switch properly\n this.customRecorder.prepareForDeviceSwitch()\n\n // Restore the existing audio chunks\n if (existingAudioChunks.length > 0) {\n this.audioChunks = existingAudioChunks\n }\n\n // Restore compressed chunks if available\n if (compressedChunks.length > 0) {\n this.customRecorder.setCompressedChunks(compressedChunks)\n }\n\n // Start the new recorder while preserving counters\n this.customRecorder.start(true)\n\n // Update recording state\n this.isPaused = false\n this.recordingStartTime = Date.now()\n\n // Restore size counters to maintain continuity\n this.currentSize = previousTotalSize\n this.lastEmittedSize = previousLastEmittedSize\n this.totalCompressedSize = previousCompressedSize\n\n // Notify that we switched to a fallback device\n if (this.eventCallback) {\n this.eventCallback({\n type: 'deviceFallback',\n device: fallbackDeviceInfo.deviceId,\n timestamp: new Date(),\n })\n }\n return true\n } catch (error) {\n this.logger?.error(\n 'Failed to start recording with fallback device',\n error\n )\n this.isPaused = true\n this.emit('onRecordingInterrupted', {\n reason: 'deviceSwitchFailed',\n isPaused: true,\n timestamp: Date.now(),\n message:\n 'Failed to switch to fallback device. Recording paused.',\n })\n return false\n }\n } catch (error) {\n this.logger?.error('Failed to use fallback device', error)\n this.isPaused = true\n this.emit('onRecordingInterrupted', {\n reason: 'deviceSwitchFailed',\n isPaused: true,\n timestamp: Date.now(),\n message:\n 'Failed to switch to fallback device. Recording paused.',\n })\n return false\n }\n }\n\n /**\n * Attempts to get a fallback audio device\n */\n private async getFallbackDevice(): Promise<MediaDeviceInfo | null> {\n try {\n // Get list of available audio input devices\n const devices = await navigator.mediaDevices.enumerateDevices()\n const audioInputDevices = devices.filter(\n (device) => device.kind === 'audioinput'\n )\n\n if (audioInputDevices.length === 0) {\n return null\n }\n\n // Try to find a device that's not the current one\n if (this.customRecorder) {\n try {\n // Use mediaDevices.enumerateDevices to find the current active device\n const tracks = navigator.mediaDevices\n .getUserMedia({ audio: true })\n .then((stream) => {\n const track = stream.getAudioTracks()[0]\n return track ? track.label : ''\n })\n .catch(() => '')\n\n const currentTrackLabel = await tracks\n\n if (currentTrackLabel) {\n // Find a device with a different label\n const differentDevice = audioInputDevices.find(\n (device) =>\n device.label &&\n device.label !== currentTrackLabel\n )\n\n if (differentDevice) {\n return differentDevice\n }\n }\n } catch (err) {\n this.logger?.warn(\n 'Error determining current device, using default',\n err\n )\n }\n }\n\n // Return the first available device (default device)\n return audioInputDevices[0]\n } catch (error) {\n this.logger?.error('Error finding fallback device:', error)\n return null\n }\n }\n\n /**\n * Gets user media with specific device ID\n */\n private async requestPermissionsAndGetUserMedia(\n deviceId: string\n ): Promise<MediaStream> {\n try {\n // Request the specific device\n return await navigator.mediaDevices.getUserMedia({\n audio: {\n deviceId: { exact: deviceId },\n },\n })\n } catch (error) {\n this.logger?.error(\n `Failed to get media for device ${deviceId}`,\n error\n )\n // Try with default constraints as fallback\n return await navigator.mediaDevices.getUserMedia({ audio: true })\n }\n }\n\n init(options?: AudioStudioOptions): Promise<void> {\n try {\n this.logger = options?.logger\n this.eventCallback = options?.eventCallback\n return Promise.resolve()\n } catch (error) {\n this.logger?.error('Error initializing AudioStudio', error)\n return Promise.reject(error)\n }\n }\n}\n"]}
1
+ {"version":3,"file":"AudioStudio.web.js","sourceRoot":"","sources":["../../src/AudioStudio.web.ts"],"names":[],"mappings":"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","sourcesContent":["// src/AudioStudio.web.ts\nimport { LegacyEventEmitter } from 'expo-modules-core'\n\nimport { AudioAnalysis } from './AudioAnalysis/AudioAnalysis.types'\nimport {\n AudioRecording,\n AudioStreamStatus,\n BitDepth,\n ConsoleLike,\n RecordingConfig,\n RecordingInterruptionReason,\n StartRecordingResult,\n} from './AudioStudio.types'\nimport { WebRecorder } from './WebRecorder.web'\nimport {\n DEFAULT_BIT_DEPTH,\n DEFAULT_INTERVAL_MS,\n DEFAULT_ANALYSIS_INTERVAL_MS,\n DEFAULT_MAX_BUFFER_SIZE,\n} from './constants'\nimport { AudioEventPayload } from './events'\nimport { encodingToBitDepth } from './utils/encodingToBitDepth'\n\nexport interface AudioStreamEvent {\n type: string\n device?: string\n timestamp: Date\n}\n\nexport interface AudioStudioOptions {\n logger?: ConsoleLike\n eventCallback?: (event: AudioStreamEvent) => void\n}\n\nexport interface EmitAudioEventProps {\n data: Float32Array\n position: number\n compression?: {\n data: Blob\n size: number\n totalSize: number\n mimeType: string\n format: string\n bitrate: number\n }\n}\nexport type EmitAudioEventFunction = (_: EmitAudioEventProps) => void\nexport type EmitAudioAnalysisFunction = (_: AudioAnalysis) => void\n\nexport interface AudioStudioWebProps {\n logger?: ConsoleLike\n audioWorkletUrl: string\n featuresExtratorUrl: string\n maxBufferSize?: number // Maximum number of chunks to keep in memory\n emitEvent?: (eventName: string, params: unknown) => void\n}\n\nexport class AudioStudioWeb extends LegacyEventEmitter {\n customRecorder: WebRecorder | null\n audioChunks: Float32Array[]\n isRecording: boolean\n isPaused: boolean\n recordingStartTime: number\n pausedTime: number\n currentDurationMs: number\n currentSize: number\n currentInterval: number\n currentIntervalAnalysis: number\n lastEmittedSize: number\n lastEmittedTime: number\n lastEmittedCompressionSize: number\n lastEmittedAnalysisTime: number\n streamUuid: string | null\n extension: 'webm' | 'wav' = 'wav' // Default extension is 'wav'\n recordingConfig?: RecordingConfig\n bitDepth: BitDepth // Bit depth of the audio\n audioWorkletUrl: string\n featuresExtratorUrl: string\n logger?: ConsoleLike\n latestPosition: number = 0\n totalCompressedSize: number = 0\n private readonly maxBufferSize: number\n private eventCallback?: (event: AudioStreamEvent) => void\n private readonly moduleEventEmitter?: (eventName: string, params: unknown) => void\n private maxDurationTimer?: ReturnType<typeof setTimeout>\n private maxDurationTargetMs = 0\n private maxDurationAccumulatedActiveMs = 0\n private maxDurationSegmentStartMs = 0\n private maxDurationReached = false\n\n constructor({\n audioWorkletUrl,\n featuresExtratorUrl,\n logger,\n maxBufferSize = DEFAULT_MAX_BUFFER_SIZE,\n emitEvent,\n }: AudioStudioWebProps) {\n const mockNativeModule = {\n addListener: () => {},\n removeListeners: () => {},\n }\n super(mockNativeModule) // Pass the mock native module to the parent class\n\n this.logger = logger\n this.customRecorder = null\n this.audioChunks = []\n this.isRecording = false\n this.isPaused = false\n this.recordingStartTime = 0\n this.pausedTime = 0\n this.currentDurationMs = 0\n this.currentSize = 0\n this.bitDepth = DEFAULT_BIT_DEPTH\n this.currentInterval = DEFAULT_INTERVAL_MS\n this.currentIntervalAnalysis = DEFAULT_ANALYSIS_INTERVAL_MS\n this.lastEmittedSize = 0\n this.lastEmittedTime = 0\n this.latestPosition = 0\n this.lastEmittedCompressionSize = 0\n this.lastEmittedAnalysisTime = 0\n this.streamUuid = null // Initialize UUID on first recording start\n this.audioWorkletUrl = audioWorkletUrl\n this.featuresExtratorUrl = featuresExtratorUrl\n this.maxBufferSize = maxBufferSize\n this.moduleEventEmitter = emitEvent\n }\n\n private emitModuleEvent(eventName: string, params: unknown) {\n this.emit(eventName, params)\n this.moduleEventEmitter?.(eventName, params)\n }\n\n private resetMaxDurationState(preserveReached = false) {\n if (this.maxDurationTimer) {\n clearTimeout(this.maxDurationTimer)\n this.maxDurationTimer = undefined\n }\n this.maxDurationSegmentStartMs = 0\n if (!preserveReached || !this.maxDurationReached) {\n this.maxDurationTargetMs = 0\n this.maxDurationAccumulatedActiveMs = 0\n this.maxDurationReached = false\n }\n }\n\n private getMaxDurationActiveMs(now = performance.now()) {\n if (this.maxDurationSegmentStartMs <= 0) {\n return this.maxDurationAccumulatedActiveMs\n }\n return (\n this.maxDurationAccumulatedActiveMs +\n (now - this.maxDurationSegmentStartMs)\n )\n }\n\n private scheduleMaxDurationTimer() {\n if (\n this.maxDurationTargetMs <= 0 ||\n this.maxDurationReached ||\n !this.isRecording ||\n this.isPaused\n ) {\n return\n }\n\n if (this.maxDurationTimer) {\n clearTimeout(this.maxDurationTimer)\n }\n\n const remainingMs = Math.max(\n 0,\n this.maxDurationTargetMs - this.getMaxDurationActiveMs()\n )\n this.maxDurationTimer = setTimeout(() => {\n this.maxDurationTimer = undefined\n this.emitMaxDurationReached()\n }, remainingMs)\n }\n\n private startMaxDurationTimer(recordingConfig: RecordingConfig) {\n this.resetMaxDurationState()\n const targetMs = Number(recordingConfig.maxDurationMs ?? 0)\n if (!Number.isFinite(targetMs) || targetMs <= 0) {\n return\n }\n\n this.maxDurationTargetMs = targetMs\n this.maxDurationSegmentStartMs = performance.now()\n this.scheduleMaxDurationTimer()\n }\n\n private pauseMaxDurationTimer() {\n if (this.maxDurationTimer) {\n clearTimeout(this.maxDurationTimer)\n this.maxDurationTimer = undefined\n }\n if (this.maxDurationSegmentStartMs > 0) {\n this.maxDurationAccumulatedActiveMs = this.getMaxDurationActiveMs()\n this.maxDurationSegmentStartMs = 0\n }\n }\n\n private resumeMaxDurationTimer() {\n if (this.maxDurationTargetMs <= 0 || this.maxDurationReached) {\n return\n }\n this.maxDurationSegmentStartMs = performance.now()\n this.scheduleMaxDurationTimer()\n }\n\n private emitMaxDurationReached() {\n if (this.maxDurationTargetMs <= 0 || this.maxDurationReached) {\n return\n }\n\n const durationMs = Math.round(this.getMaxDurationActiveMs())\n this.maxDurationReached = true\n const autoStopped = !!this.recordingConfig?.autoStopOnMaxDuration\n this.emitModuleEvent('MaxDurationReached', {\n durationMs,\n maxDurationMs: this.maxDurationTargetMs,\n overrunMs: Math.max(0, durationMs - this.maxDurationTargetMs),\n streamUuid: this.streamUuid ?? undefined,\n autoStopped,\n })\n if (autoStopped) {\n this.stopRecording().catch((error) => {\n this.logger?.error(\n 'Error auto-stopping on max duration:',\n error\n )\n })\n }\n }\n\n private flushExpiredMaxDuration() {\n if (\n this.maxDurationTargetMs > 0 &&\n !this.maxDurationReached &&\n this.getMaxDurationActiveMs() >= this.maxDurationTargetMs\n ) {\n this.emitMaxDurationReached()\n }\n }\n\n // Utility to handle user media stream\n async getMediaStream() {\n try {\n this.logger?.debug('Requesting user media (microphone)...')\n\n // First check if the browser supports the necessary audio APIs\n if (!navigator?.mediaDevices?.getUserMedia) {\n this.logger?.error(\n 'Browser does not support mediaDevices.getUserMedia'\n )\n throw new Error('Browser does not support audio recording')\n }\n\n // Get media with detailed audio constraints for better diagnostics\n const constraints = {\n audio: {\n echoCancellation: true,\n noiseSuppression: true,\n autoGainControl: true,\n // Add deviceId constraint if specified\n ...(this.recordingConfig?.deviceId\n ? {\n deviceId: {\n exact: this.recordingConfig.deviceId,\n },\n }\n : {}),\n },\n }\n\n this.logger?.debug('Media constraints:', constraints)\n\n const stream =\n await navigator.mediaDevices.getUserMedia(constraints)\n\n // Get detailed info about the audio track for debugging\n const audioTracks = stream.getAudioTracks()\n if (audioTracks.length > 0) {\n const track = audioTracks[0]\n const settings = track.getSettings()\n this.logger?.debug('Audio track obtained:', {\n label: track.label,\n id: track.id,\n enabled: track.enabled,\n muted: track.muted,\n readyState: track.readyState,\n settings,\n })\n } else {\n this.logger?.warn('Stream has no audio tracks!')\n }\n\n return stream\n } catch (error) {\n this.logger?.error('Failed to get media stream:', error)\n throw error\n }\n }\n\n // Prepare recording with options\n async prepareRecording(\n recordingConfig: RecordingConfig = {}\n ): Promise<boolean> {\n if (this.isRecording) {\n this.logger?.warn(\n 'Cannot prepare: Recording is already in progress'\n )\n return false\n }\n\n try {\n // Check permissions and initialize basic settings\n await this.getMediaStream().then((stream) => {\n // Just verify we can access the microphone by getting a stream, then release it\n stream.getTracks().forEach((track) => track.stop())\n })\n\n this.bitDepth = encodingToBitDepth({\n encoding: recordingConfig.encoding ?? 'pcm_32bit',\n })\n\n // Store recording configuration for later use\n this.recordingConfig = recordingConfig\n\n // Use custom filename if provided, otherwise fallback to timestamp\n if (recordingConfig.filename) {\n // Remove any existing extension from the filename\n this.streamUuid = recordingConfig.filename.replace(\n /\\.[^/.]+$/,\n ''\n )\n } else {\n this.streamUuid = Date.now().toString()\n }\n\n this.logger?.debug('Recording preparation completed successfully')\n return true\n } catch (error) {\n this.logger?.error('Error preparing recording:', error)\n return false\n }\n }\n\n // Start recording with options\n async startRecording(\n recordingConfig: RecordingConfig = {}\n ): Promise<StartRecordingResult> {\n if (this.isRecording) {\n throw new Error('Recording is already in progress')\n }\n\n // If we haven't prepared or have different settings, prepare now\n if (\n !this.recordingConfig ||\n this.recordingConfig.sampleRate !== recordingConfig.sampleRate ||\n this.recordingConfig.channels !== recordingConfig.channels ||\n this.recordingConfig.encoding !== recordingConfig.encoding\n ) {\n await this.prepareRecording(recordingConfig)\n } else {\n this.logger?.debug(\n 'Using previously prepared recording configuration'\n )\n }\n\n // Save recording config for reference\n this.recordingConfig = recordingConfig\n\n const audioContext = new (window.AudioContext ||\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore - Allow webkitAudioContext for Safari\n window.webkitAudioContext)()\n const stream = await this.getMediaStream()\n\n const source = audioContext.createMediaStreamSource(stream)\n\n this.customRecorder = new WebRecorder({\n logger: this.logger,\n audioContext,\n source,\n recordingConfig,\n emitAudioEventCallback: this.customRecorderEventCallback.bind(this),\n emitAudioAnalysisCallback:\n this.customRecorderAnalysisCallback.bind(this),\n onInterruption: this.handleRecordingInterruption.bind(this),\n })\n await this.customRecorder.init()\n this.customRecorder.start()\n\n this.isRecording = true\n this.recordingStartTime = Date.now()\n this.pausedTime = 0\n this.isPaused = false\n this.lastEmittedSize = 0\n this.lastEmittedTime = 0\n this.lastEmittedCompressionSize = 0\n this.currentInterval = recordingConfig.interval ?? 1000\n this.currentIntervalAnalysis = recordingConfig.intervalAnalysis ?? 500\n this.lastEmittedAnalysisTime = Date.now()\n this.startMaxDurationTimer(recordingConfig)\n\n // Use custom filename if provided, otherwise fallback to timestamp\n if (recordingConfig.filename) {\n // Remove any existing extension from the filename\n this.streamUuid = recordingConfig.filename.replace(/\\.[^/.]+$/, '')\n } else {\n this.streamUuid = Date.now().toString()\n }\n\n const fileUri = `${this.streamUuid}.${this.extension}`\n const streamConfig: StartRecordingResult = {\n fileUri,\n mimeType: `audio/${this.extension}`,\n bitDepth: this.bitDepth,\n channels: recordingConfig.channels ?? 1,\n sampleRate: recordingConfig.sampleRate ?? 44100,\n compression: recordingConfig.output?.compressed?.enabled\n ? {\n ...recordingConfig.output.compressed,\n bitrate:\n recordingConfig.output.compressed.bitrate ?? 128000,\n size: 0,\n mimeType: 'audio/webm',\n format:\n recordingConfig.output.compressed.format ?? 'opus',\n compressedFileUri: '',\n }\n : undefined,\n }\n return streamConfig\n }\n\n /**\n * Centralized handler for recording interruptions\n */\n private handleRecordingInterruption(event: {\n reason: RecordingInterruptionReason | string\n isPaused: boolean\n timestamp: number\n message?: string\n }): void {\n this.logger?.debug(`Received recording interruption: ${event.reason}`)\n\n // Update local state if the interruption should pause recording\n if (event.isPaused) {\n this.isPaused = true\n this.pausedTime = Date.now()\n this.pauseMaxDurationTimer()\n\n // If this is a device disconnection, handle according to behavior setting\n if (event.reason === 'deviceDisconnected') {\n // Check if we should try fallback to another device\n if (\n this.recordingConfig?.deviceDisconnectionBehavior ===\n 'fallback'\n ) {\n this.logger?.debug(\n 'Device disconnected with fallback behavior - attempting to switch to default device'\n )\n\n // Try to restart with default device\n this.handleDeviceFallback().catch((error) => {\n // If fallback fails, emit warning\n this.logger?.error('Device fallback failed:', error)\n this.emitModuleEvent('onRecordingInterrupted', {\n reason: 'deviceSwitchFailed',\n isPaused: true,\n timestamp: Date.now(),\n message:\n 'Failed to switch to fallback device. Recording paused.',\n })\n })\n } else {\n // Just warn about disconnection if fallback not enabled\n this.logger?.warn(\n 'Device disconnected - recording paused automatically'\n )\n this.emitModuleEvent('onRecordingInterrupted', event)\n }\n } else {\n // For other interruption types, just emit the event\n this.emitModuleEvent('onRecordingInterrupted', event)\n }\n } else {\n // If not causing a pause, just forward the event\n this.emitModuleEvent('onRecordingInterrupted', event)\n }\n }\n\n /**\n * Handler for audio events from the WebRecorder\n */\n private customRecorderEventCallback({\n data,\n position,\n compression,\n }: EmitAudioEventProps): void {\n // Keep only the latest chunks based on maxBufferSize\n this.audioChunks.push(new Float32Array(data))\n if (this.audioChunks.length > this.maxBufferSize) {\n this.audioChunks.shift() // Remove oldest chunk\n }\n this.currentSize += data.byteLength\n this.emitAudioEvent({ data, position, compression })\n this.lastEmittedTime = Date.now()\n this.lastEmittedSize = this.currentSize\n this.lastEmittedCompressionSize = compression?.size ?? 0\n }\n\n /**\n * Handler for audio analysis events from the WebRecorder\n */\n private customRecorderAnalysisCallback(\n audioAnalysisData: AudioAnalysis\n ): void {\n this.emitModuleEvent('AudioAnalysis', audioAnalysisData)\n }\n\n // Get recording duration\n private getRecordingDuration(): number {\n if (!this.isRecording) {\n return 0\n }\n\n return this.currentDurationMs\n }\n\n emitAudioEvent({ data, position, compression }: EmitAudioEventProps) {\n const fileUri = `${this.streamUuid}.${this.extension}`\n if (compression?.size) {\n this.lastEmittedCompressionSize = compression.size\n this.totalCompressedSize = compression.totalSize\n }\n\n // Update latest position for tracking\n this.latestPosition = position\n\n // Calculate duration of this chunk in ms\n const sampleRate = this.recordingConfig?.sampleRate || 44100\n const chunkDurationMs = (data.length / sampleRate) * 1000\n\n // Handle duration calculation\n if (this.customRecorder?.isFirstChunkAfterSwitch) {\n this.logger?.debug(\n `Processing first chunk after device switch, duration preserved at ${this.currentDurationMs}ms`\n )\n this.customRecorder.isFirstChunkAfterSwitch = false\n } else {\n this.currentDurationMs += chunkDurationMs\n }\n this.flushExpiredMaxDuration()\n\n const audioEventPayload: AudioEventPayload = {\n fileUri,\n mimeType: `audio/${this.extension}`,\n lastEmittedSize: this.lastEmittedSize,\n deltaSize: data.byteLength,\n position,\n totalSize: this.currentSize,\n buffer: data,\n streamUuid: this.streamUuid ?? '',\n compression: compression\n ? {\n data: compression?.data,\n totalSize: this.totalCompressedSize,\n eventDataSize: compression?.size ?? 0,\n position,\n }\n : undefined,\n }\n\n this.emitModuleEvent('AudioData', audioEventPayload)\n }\n\n // Stop recording\n async stopRecording(): Promise<AudioRecording> {\n if (!this.customRecorder) {\n throw new Error('Recorder is not initialized')\n }\n\n this.logger?.debug('Starting stop process')\n\n try {\n this.pauseMaxDurationTimer()\n const { compressedBlob, uncompressedBlob } =\n await this.customRecorder.stop()\n\n this.isRecording = false\n this.isPaused = false\n\n let compression: AudioRecording['compression']\n let fileUri = `${this.streamUuid}.${this.extension}`\n let mimeType = `audio/${this.extension}`\n\n // Handle both compressed and uncompressed blobs according to new output configuration\n const primaryEnabled =\n this.recordingConfig?.output?.primary?.enabled ?? true\n const compressedEnabled =\n this.recordingConfig?.output?.compressed?.enabled ?? false\n\n // Process compressed blob if available and enabled\n if (compressedBlob && compressedEnabled) {\n const compressedUri = URL.createObjectURL(compressedBlob)\n const compressedInfo = {\n compressedFileUri: compressedUri,\n size: compressedBlob.size,\n mimeType: 'audio/webm',\n format:\n this.recordingConfig?.output?.compressed?.format ??\n 'opus',\n bitrate:\n this.recordingConfig?.output?.compressed?.bitrate ??\n 128000,\n }\n\n // Store compression info\n compression = compressedInfo\n\n // If primary is disabled, use compressed as main file\n if (!primaryEnabled) {\n this.logger?.debug(\n 'Using compressed audio as primary output (primary disabled)'\n )\n fileUri = compressedUri\n mimeType = 'audio/webm'\n }\n }\n\n // Process uncompressed WAV if available and primary is enabled\n if (uncompressedBlob && primaryEnabled) {\n const wavUri = URL.createObjectURL(uncompressedBlob)\n fileUri = wavUri\n mimeType = 'audio/wav'\n } else if (!primaryEnabled && !compressedEnabled) {\n // No outputs enabled - streaming only mode\n this.logger?.debug('No outputs enabled - streaming only mode')\n fileUri = ''\n mimeType = 'audio/wav'\n }\n\n // Use the stored streamUuid for the final filename\n const filename = fileUri\n ? `${this.streamUuid}.${this.extension}`\n : 'stream-only'\n const result: AudioRecording = {\n fileUri,\n filename,\n bitDepth: this.bitDepth,\n createdAt: this.recordingStartTime,\n channels: this.recordingConfig?.channels ?? 1,\n sampleRate: this.recordingConfig?.sampleRate ?? 44100,\n durationMs: this.currentDurationMs,\n size: primaryEnabled ? this.currentSize : 0,\n mimeType,\n compression,\n }\n\n // Reset after creating the result\n this.streamUuid = null\n\n // Reset recording state variables to prepare for next recording\n this.currentDurationMs = 0\n this.currentSize = 0\n this.lastEmittedSize = 0\n this.totalCompressedSize = 0\n this.lastEmittedCompressionSize = 0\n this.audioChunks = []\n this.resetMaxDurationState(true)\n\n return result\n } catch (error) {\n this.logger?.error('Error stopping recording:', error)\n throw error\n }\n }\n\n // Pause recording\n async pauseRecording() {\n if (!this.isRecording) {\n throw new Error('Recording is not active')\n }\n\n if (this.isPaused) {\n this.logger?.debug('Recording already paused, skipping')\n return\n }\n\n try {\n if (this.customRecorder) {\n this.customRecorder.pause()\n }\n this.isPaused = true\n this.pausedTime = Date.now()\n this.pauseMaxDurationTimer()\n } catch (error) {\n this.logger?.error('Error in pauseRecording', error)\n // Even if the pause operation failed, make sure our state is consistent\n this.isPaused = true\n this.pausedTime = Date.now()\n this.pauseMaxDurationTimer()\n }\n }\n\n // Resume recording\n async resumeRecording() {\n if (!this.isPaused) {\n throw new Error('Recording is not paused')\n }\n\n this.logger?.debug('Resuming recording', {\n deviceDisconnectionBehavior:\n this.recordingConfig?.deviceDisconnectionBehavior,\n isDeviceDisconnected: this.customRecorder?.isDeviceDisconnected,\n })\n\n try {\n // If we have no recorder, or if the device is disconnected, always attempt fallback\n if (\n !this.customRecorder ||\n this.customRecorder.isDeviceDisconnected\n ) {\n this.logger?.debug(\n 'No recorder exists or device disconnected - attempting fallback on resume'\n )\n await this.handleDeviceFallback()\n // handleDeviceFallback will manage resuming if successful, or emit error if failed.\n return\n }\n\n // Normal resume path - device is still connected\n this.customRecorder.resume()\n this.isPaused = false\n\n // Adjust the recording start time to account for the pause duration\n const pauseDuration = Date.now() - this.pausedTime\n this.recordingStartTime += pauseDuration\n this.pausedTime = 0\n this.resumeMaxDurationTimer()\n\n this.emitModuleEvent('onRecordingInterrupted', {\n reason: 'userResumed',\n isPaused: false,\n timestamp: Date.now(),\n })\n } catch (error) {\n this.logger?.error('Resume failed:', error)\n // Fallback to emitting a general failure if resume fails unexpectedly\n this.emitModuleEvent('onRecordingInterrupted', {\n reason: 'resumeFailed', // Use a more specific reason\n isPaused: true, // Remain paused if resume fails\n timestamp: Date.now(),\n message:\n 'Failed to resume recording. Please stop and start again.',\n })\n }\n }\n\n // Get current status\n status() {\n this.flushExpiredMaxDuration()\n const durationMs = this.getRecordingDuration()\n\n const status: AudioStreamStatus = {\n isRecording: this.isRecording,\n isPaused: this.isPaused,\n durationMs,\n size: this.currentSize,\n interval: this.currentInterval,\n intervalAnalysis: this.currentIntervalAnalysis,\n mimeType: `audio/${this.extension}`,\n compression: this.recordingConfig?.output?.compressed?.enabled\n ? {\n size: this.totalCompressedSize,\n mimeType: 'audio/webm',\n format:\n this.recordingConfig.output.compressed.format ??\n 'opus',\n bitrate:\n this.recordingConfig.output.compressed.bitrate ??\n 128000,\n compressedFileUri: `${this.streamUuid}.webm`,\n }\n : undefined,\n maxDurationMs:\n this.maxDurationTargetMs > 0 ? this.maxDurationTargetMs : undefined,\n maxDurationReached: this.maxDurationReached,\n }\n return status\n }\n\n /**\n * Handles device fallback when the current device is disconnected\n */\n private async handleDeviceFallback(): Promise<boolean> {\n this.logger?.debug('Starting device fallback procedure')\n\n if (!this.isRecording) {\n return false\n }\n\n try {\n // Save important state before switching\n const currentPosition = this.latestPosition\n const existingAudioChunks = [...this.audioChunks]\n\n // Save compressed chunks if available\n let compressedChunks: Blob[] = []\n if (this.customRecorder) {\n try {\n compressedChunks = this.customRecorder.getCompressedChunks()\n } catch (err) {\n this.logger?.warn('Failed to get compressed chunks:', err)\n }\n }\n\n // Save the current counter value for continuity\n let currentDataPointCounter = 0\n if (this.customRecorder) {\n currentDataPointCounter =\n this.customRecorder.getDataPointCounter()\n }\n\n // Clean up existing recorder\n if (this.customRecorder) {\n try {\n this.customRecorder.cleanup()\n } catch (cleanupError) {\n this.logger?.warn('Error during cleanup:', cleanupError)\n }\n }\n\n // Keep recording state true but mark as paused\n this.isPaused = true\n this.pausedTime = Date.now()\n\n // Store current size and other stats\n const previousTotalSize = this.currentSize\n const previousLastEmittedSize = this.lastEmittedSize\n const previousCompressedSize = this.totalCompressedSize\n\n // Try to get a fallback device\n const fallbackDeviceInfo = await this.getFallbackDevice()\n if (!fallbackDeviceInfo) {\n this.emitModuleEvent('onRecordingInterrupted', {\n reason: 'deviceSwitchFailed',\n isPaused: true,\n timestamp: Date.now(),\n message:\n 'Failed to switch to fallback device. Recording paused.',\n })\n return false\n }\n\n // Start recording with the new device\n try {\n const stream = await this.requestPermissionsAndGetUserMedia(\n fallbackDeviceInfo.deviceId\n )\n const audioContext = new (window.AudioContext ||\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore - Allow webkitAudioContext for Safari\n window.webkitAudioContext)()\n\n const source = audioContext.createMediaStreamSource(stream)\n\n // Create a new recorder with the fallback device\n this.customRecorder = new WebRecorder({\n logger: this.logger,\n audioContext,\n source,\n recordingConfig: this.recordingConfig || {},\n emitAudioEventCallback:\n this.customRecorderEventCallback.bind(this),\n emitAudioAnalysisCallback:\n this.customRecorderAnalysisCallback.bind(this),\n onInterruption: this.handleRecordingInterruption.bind(this),\n })\n\n await this.customRecorder.init()\n\n // Set the initial position to continue from the previous device\n this.customRecorder.setPosition(currentPosition)\n\n // Reset the data point counter to continue from where the previous device left off\n if (currentDataPointCounter > 0) {\n this.customRecorder.resetDataPointCounter(\n currentDataPointCounter\n )\n }\n\n // Prepare the recorder to handle the device switch properly\n this.customRecorder.prepareForDeviceSwitch()\n\n // Restore the existing audio chunks\n if (existingAudioChunks.length > 0) {\n this.audioChunks = existingAudioChunks\n }\n\n // Restore compressed chunks if available\n if (compressedChunks.length > 0) {\n this.customRecorder.setCompressedChunks(compressedChunks)\n }\n\n // Start the new recorder while preserving counters\n this.customRecorder.start(true)\n\n // Update recording state\n this.isPaused = false\n this.recordingStartTime = Date.now()\n this.resumeMaxDurationTimer()\n\n // Restore size counters to maintain continuity\n this.currentSize = previousTotalSize\n this.lastEmittedSize = previousLastEmittedSize\n this.totalCompressedSize = previousCompressedSize\n\n // Notify that we switched to a fallback device\n if (this.eventCallback) {\n this.eventCallback({\n type: 'deviceFallback',\n device: fallbackDeviceInfo.deviceId,\n timestamp: new Date(),\n })\n }\n return true\n } catch (error) {\n this.logger?.error(\n 'Failed to start recording with fallback device',\n error\n )\n this.isPaused = true\n this.emitModuleEvent('onRecordingInterrupted', {\n reason: 'deviceSwitchFailed',\n isPaused: true,\n timestamp: Date.now(),\n message:\n 'Failed to switch to fallback device. Recording paused.',\n })\n return false\n }\n } catch (error) {\n this.logger?.error('Failed to use fallback device', error)\n this.isPaused = true\n this.emitModuleEvent('onRecordingInterrupted', {\n reason: 'deviceSwitchFailed',\n isPaused: true,\n timestamp: Date.now(),\n message:\n 'Failed to switch to fallback device. Recording paused.',\n })\n return false\n }\n }\n\n /**\n * Attempts to get a fallback audio device\n */\n private async getFallbackDevice(): Promise<MediaDeviceInfo | null> {\n try {\n // Get list of available audio input devices\n const devices = await navigator.mediaDevices.enumerateDevices()\n const audioInputDevices = devices.filter(\n (device) => device.kind === 'audioinput'\n )\n\n if (audioInputDevices.length === 0) {\n return null\n }\n\n // Try to find a device that's not the current one\n if (this.customRecorder) {\n try {\n // Use mediaDevices.enumerateDevices to find the current active device\n const tracks = navigator.mediaDevices\n .getUserMedia({ audio: true })\n .then((stream) => {\n const track = stream.getAudioTracks()[0]\n return track ? track.label : ''\n })\n .catch(() => '')\n\n const currentTrackLabel = await tracks\n\n if (currentTrackLabel) {\n // Find a device with a different label\n const differentDevice = audioInputDevices.find(\n (device) =>\n device.label &&\n device.label !== currentTrackLabel\n )\n\n if (differentDevice) {\n return differentDevice\n }\n }\n } catch (err) {\n this.logger?.warn(\n 'Error determining current device, using default',\n err\n )\n }\n }\n\n // Return the first available device (default device)\n return audioInputDevices[0]\n } catch (error) {\n this.logger?.error('Error finding fallback device:', error)\n return null\n }\n }\n\n /**\n * Gets user media with specific device ID\n */\n private async requestPermissionsAndGetUserMedia(\n deviceId: string\n ): Promise<MediaStream> {\n try {\n // Request the specific device\n return await navigator.mediaDevices.getUserMedia({\n audio: {\n deviceId: { exact: deviceId },\n },\n })\n } catch (error) {\n this.logger?.error(\n `Failed to get media for device ${deviceId}`,\n error\n )\n // Try with default constraints as fallback\n return await navigator.mediaDevices.getUserMedia({ audio: true })\n }\n }\n\n init(options?: AudioStudioOptions): Promise<void> {\n try {\n this.logger = options?.logger\n this.eventCallback = options?.eventCallback\n return Promise.resolve()\n } catch (error) {\n this.logger?.error('Error initializing AudioStudio', error)\n return Promise.reject(error)\n }\n }\n}\n"]}
@@ -8,7 +8,12 @@ let AudioStudioModule;
8
8
  if (react_native_1.Platform.OS === 'web') {
9
9
  let instance = null;
10
10
  AudioStudioModule = (webProps) => {
11
- instance ??= new AudioStudio_web_1.AudioStudioWeb(webProps);
11
+ instance ??= new AudioStudio_web_1.AudioStudioWeb({
12
+ ...webProps,
13
+ emitEvent: (eventName, params) => {
14
+ AudioStudioModule.sendEvent(eventName, params);
15
+ },
16
+ });
12
17
  return instance;
13
18
  };
14
19
  AudioStudioModule.requestPermissionsAsync = async () => {
@@ -1 +1 @@
1
- {"version":3,"file":"AudioStudioModule.js","sourceRoot":"","sources":["../../src/AudioStudioModule.ts"],"names":[],"mappings":"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","sourcesContent":["import { requireNativeModule } from 'expo-modules-core'\nimport { Platform } from 'react-native'\n\nimport { AudioStudioWeb, AudioStudioWebProps } from './AudioStudio.web'\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet AudioStudioModule: any\n\nif (Platform.OS === 'web') {\n let instance: AudioStudioWeb | null = null\n\n AudioStudioModule = (webProps: AudioStudioWebProps) => {\n instance ??= new AudioStudioWeb(webProps)\n return instance\n }\n AudioStudioModule.requestPermissionsAsync = async () => {\n try {\n const stream = await navigator.mediaDevices.getUserMedia({\n audio: true,\n })\n stream.getTracks().forEach((track) => track.stop())\n return {\n status: 'granted',\n expires: 'never',\n canAskAgain: true,\n granted: true,\n }\n } catch {\n return {\n status: 'denied',\n expires: 'never',\n canAskAgain: true,\n granted: false,\n }\n }\n }\n AudioStudioModule.getPermissionsAsync = async () => {\n let maybeStatus: string | null = null\n\n if (navigator?.permissions?.query) {\n try {\n const { state } = await navigator.permissions.query({\n name: 'microphone' as PermissionName,\n })\n maybeStatus = state\n } catch {\n maybeStatus = null\n }\n }\n\n switch (maybeStatus) {\n case 'granted':\n return {\n status: 'granted',\n expires: 'never',\n canAskAgain: true,\n granted: true,\n }\n case 'denied':\n return {\n status: 'denied',\n expires: 'never',\n canAskAgain: true,\n granted: false,\n }\n default:\n return await AudioStudioModule.requestPermissionsAsync()\n }\n }\n // Add a sendEvent method for web\n AudioStudioModule.sendEvent = (eventName: string, params: any) => {\n // This will be picked up by the LegacyEventEmitter in trimAudio.ts\n AudioStudioModule.listeners?.[eventName]?.forEach(\n (listener: Function) => {\n listener(params)\n }\n )\n }\n\n // Initialize listeners object\n AudioStudioModule.listeners = {}\n\n // Add methods for event listeners that LegacyEventEmitter will use\n AudioStudioModule.addListener = (eventName: string, listener: Function) => {\n if (!AudioStudioModule.listeners[eventName]) {\n AudioStudioModule.listeners[eventName] = []\n }\n AudioStudioModule.listeners[eventName].push(listener)\n\n // Return an object with a remove method\n return {\n remove: () => {\n const index =\n AudioStudioModule.listeners[eventName].indexOf(listener)\n if (index !== -1) {\n AudioStudioModule.listeners[eventName].splice(index, 1)\n }\n },\n }\n }\n\n AudioStudioModule.removeAllListeners = (eventName: string) => {\n if (AudioStudioModule.listeners[eventName]) {\n delete AudioStudioModule.listeners[eventName]\n }\n }\n\n AudioStudioModule.prepareRecording = async (options: any) => {\n // For web platform, we'll implement a simplified version that just checks permissions\n // and does minimal setup. The actual recording setup will still happen in startRecording.\n try {\n // Check for microphone permissions\n const permissionsResult =\n await AudioStudioModule.getPermissionsAsync()\n if (!permissionsResult.granted) {\n throw new Error('Microphone permission not granted')\n }\n\n // If using a web instance, call its prepareRecording method\n if (instance) {\n return await instance.prepareRecording(options)\n }\n\n return true\n } catch (error) {\n console.error('Error preparing recording:', error)\n throw error\n }\n }\n}\n\nif (Platform.OS !== 'web') {\n AudioStudioModule = requireNativeModule('AudioStudio')\n}\n\nexport default AudioStudioModule\n"]}
1
+ {"version":3,"file":"AudioStudioModule.js","sourceRoot":"","sources":["../../src/AudioStudioModule.ts"],"names":[],"mappings":"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","sourcesContent":["import { requireNativeModule } from 'expo-modules-core'\nimport { Platform } from 'react-native'\n\nimport { AudioStudioWeb, AudioStudioWebProps } from './AudioStudio.web'\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet AudioStudioModule: any\n\nif (Platform.OS === 'web') {\n let instance: AudioStudioWeb | null = null\n\n AudioStudioModule = (webProps: AudioStudioWebProps) => {\n instance ??= new AudioStudioWeb({\n ...webProps,\n emitEvent: (eventName, params) => {\n AudioStudioModule.sendEvent(eventName, params)\n },\n })\n return instance\n }\n AudioStudioModule.requestPermissionsAsync = async () => {\n try {\n const stream = await navigator.mediaDevices.getUserMedia({\n audio: true,\n })\n stream.getTracks().forEach((track) => track.stop())\n return {\n status: 'granted',\n expires: 'never',\n canAskAgain: true,\n granted: true,\n }\n } catch {\n return {\n status: 'denied',\n expires: 'never',\n canAskAgain: true,\n granted: false,\n }\n }\n }\n AudioStudioModule.getPermissionsAsync = async () => {\n let maybeStatus: string | null = null\n\n if (navigator?.permissions?.query) {\n try {\n const { state } = await navigator.permissions.query({\n name: 'microphone' as PermissionName,\n })\n maybeStatus = state\n } catch {\n maybeStatus = null\n }\n }\n\n switch (maybeStatus) {\n case 'granted':\n return {\n status: 'granted',\n expires: 'never',\n canAskAgain: true,\n granted: true,\n }\n case 'denied':\n return {\n status: 'denied',\n expires: 'never',\n canAskAgain: true,\n granted: false,\n }\n default:\n return await AudioStudioModule.requestPermissionsAsync()\n }\n }\n // Add a sendEvent method for web\n AudioStudioModule.sendEvent = (eventName: string, params: any) => {\n // This will be picked up by the LegacyEventEmitter in trimAudio.ts\n AudioStudioModule.listeners?.[eventName]?.forEach(\n (listener: Function) => {\n listener(params)\n }\n )\n }\n\n // Initialize listeners object\n AudioStudioModule.listeners = {}\n\n // Add methods for event listeners that LegacyEventEmitter will use\n AudioStudioModule.addListener = (eventName: string, listener: Function) => {\n if (!AudioStudioModule.listeners[eventName]) {\n AudioStudioModule.listeners[eventName] = []\n }\n AudioStudioModule.listeners[eventName].push(listener)\n\n // Return an object with a remove method\n return {\n remove: () => {\n const index =\n AudioStudioModule.listeners[eventName].indexOf(listener)\n if (index !== -1) {\n AudioStudioModule.listeners[eventName].splice(index, 1)\n }\n },\n }\n }\n\n AudioStudioModule.removeAllListeners = (eventName: string) => {\n if (AudioStudioModule.listeners[eventName]) {\n delete AudioStudioModule.listeners[eventName]\n }\n }\n\n AudioStudioModule.prepareRecording = async (options: any) => {\n // For web platform, we'll implement a simplified version that just checks permissions\n // and does minimal setup. The actual recording setup will still happen in startRecording.\n try {\n // Check for microphone permissions\n const permissionsResult =\n await AudioStudioModule.getPermissionsAsync()\n if (!permissionsResult.granted) {\n throw new Error('Microphone permission not granted')\n }\n\n // If using a web instance, call its prepareRecording method\n if (instance) {\n return await instance.prepareRecording(options)\n }\n\n return true\n } catch (error) {\n console.error('Error preparing recording:', error)\n throw error\n }\n }\n}\n\nif (Platform.OS !== 'web') {\n AudioStudioModule = requireNativeModule('AudioStudio')\n}\n\nexport default AudioStudioModule\n"]}