@siteed/expo-audio-studio 2.4.1 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/CHANGELOG.md +14 -1
  2. package/README.md +25 -0
  3. package/android/src/main/java/net/siteed/audiostream/AudioAnalysisData.kt +22 -0
  4. package/android/src/main/java/net/siteed/audiostream/AudioDeviceManager.kt +1501 -0
  5. package/android/src/main/java/net/siteed/audiostream/AudioFileHandler.kt +10 -5
  6. package/android/src/main/java/net/siteed/audiostream/AudioNotificationsManager.kt +27 -25
  7. package/android/src/main/java/net/siteed/audiostream/AudioProcessor.kt +73 -71
  8. package/android/src/main/java/net/siteed/audiostream/AudioRecorderManager.kt +576 -252
  9. package/android/src/main/java/net/siteed/audiostream/Constants.kt +17 -1
  10. package/android/src/main/java/net/siteed/audiostream/ExpoAudioStreamModule.kt +419 -155
  11. package/android/src/main/java/net/siteed/audiostream/LogUtils.kt +65 -0
  12. package/android/src/main/java/net/siteed/audiostream/RecordingConfig.kt +9 -1
  13. package/build/AudioAnalysis/AudioAnalysis.types.js.map +1 -1
  14. package/build/AudioDeviceManager.d.ts +107 -0
  15. package/build/AudioDeviceManager.d.ts.map +1 -0
  16. package/build/AudioDeviceManager.js +493 -0
  17. package/build/AudioDeviceManager.js.map +1 -0
  18. package/build/AudioRecorder.provider.d.ts.map +1 -1
  19. package/build/AudioRecorder.provider.js +3 -0
  20. package/build/AudioRecorder.provider.js.map +1 -1
  21. package/build/ExpoAudioStream.types.d.ts +104 -1
  22. package/build/ExpoAudioStream.types.d.ts.map +1 -1
  23. package/build/ExpoAudioStream.types.js +7 -1
  24. package/build/ExpoAudioStream.types.js.map +1 -1
  25. package/build/ExpoAudioStream.web.d.ts +37 -0
  26. package/build/ExpoAudioStream.web.d.ts.map +1 -1
  27. package/build/ExpoAudioStream.web.js +478 -62
  28. package/build/ExpoAudioStream.web.js.map +1 -1
  29. package/build/ExpoAudioStreamModule.d.ts.map +1 -1
  30. package/build/ExpoAudioStreamModule.js +20 -0
  31. package/build/ExpoAudioStreamModule.js.map +1 -1
  32. package/build/WebRecorder.web.d.ts +74 -11
  33. package/build/WebRecorder.web.d.ts.map +1 -1
  34. package/build/WebRecorder.web.js +390 -74
  35. package/build/WebRecorder.web.js.map +1 -1
  36. package/build/hooks/useAudioDevices.d.ts +14 -0
  37. package/build/hooks/useAudioDevices.d.ts.map +1 -0
  38. package/build/hooks/useAudioDevices.js +151 -0
  39. package/build/hooks/useAudioDevices.js.map +1 -0
  40. package/build/index.d.ts +2 -0
  41. package/build/index.d.ts.map +1 -1
  42. package/build/index.js +4 -0
  43. package/build/index.js.map +1 -1
  44. package/build/useAudioRecorder.d.ts +1 -0
  45. package/build/useAudioRecorder.d.ts.map +1 -1
  46. package/build/useAudioRecorder.js +20 -1
  47. package/build/useAudioRecorder.js.map +1 -1
  48. package/build/utils/BlobFix.d.ts.map +1 -1
  49. package/build/utils/BlobFix.js +2 -2
  50. package/build/utils/BlobFix.js.map +1 -1
  51. package/build/utils/writeWavHeader.d.ts +3 -18
  52. package/build/utils/writeWavHeader.d.ts.map +1 -1
  53. package/build/utils/writeWavHeader.js +19 -26
  54. package/build/utils/writeWavHeader.js.map +1 -1
  55. package/build/workers/InlineFeaturesExtractor.web.d.ts +1 -1
  56. package/build/workers/InlineFeaturesExtractor.web.d.ts.map +1 -1
  57. package/build/workers/InlineFeaturesExtractor.web.js +27 -26
  58. package/build/workers/InlineFeaturesExtractor.web.js.map +1 -1
  59. package/build/workers/inlineAudioWebWorker.web.d.ts +1 -1
  60. package/build/workers/inlineAudioWebWorker.web.d.ts.map +1 -1
  61. package/build/workers/inlineAudioWebWorker.web.js +25 -1
  62. package/build/workers/inlineAudioWebWorker.web.js.map +1 -1
  63. package/ios/AudioDeviceManager.swift +654 -0
  64. package/ios/AudioStreamManager.swift +964 -760
  65. package/ios/ExpoAudioStreamModule.swift +174 -19
  66. package/ios/Features.swift +1 -1
  67. package/ios/ISSUE_IOS.md +45 -0
  68. package/ios/Logger.swift +13 -1
  69. package/ios/RecordingSettings.swift +12 -0
  70. package/package.json +2 -2
  71. package/src/AudioAnalysis/AudioAnalysis.types.ts +2 -2
  72. package/src/AudioDeviceManager.ts +571 -0
  73. package/src/AudioRecorder.provider.tsx +3 -0
  74. package/src/ExpoAudioStream.types.ts +113 -1
  75. package/src/ExpoAudioStream.web.ts +609 -69
  76. package/src/ExpoAudioStreamModule.ts +23 -0
  77. package/src/WebRecorder.web.ts +482 -92
  78. package/src/hooks/useAudioDevices.ts +180 -0
  79. package/src/index.ts +6 -0
  80. package/src/types/crc-32.d.ts +6 -6
  81. package/src/useAudioRecorder.tsx +27 -1
  82. package/src/utils/BlobFix.ts +6 -4
  83. package/src/utils/writeWavHeader.ts +26 -25
  84. package/src/workers/InlineFeaturesExtractor.web.tsx +27 -26
  85. package/src/workers/inlineAudioWebWorker.web.tsx +25 -1
@@ -145,7 +145,7 @@ export interface StartRecordingResult {
145
145
  }
146
146
 
147
147
  export interface AudioSessionConfig {
148
- /**
148
+ /**
149
149
  * Audio session category that defines the audio behavior
150
150
  * - 'Ambient': Audio continues with silent switch, mixes with other audio
151
151
  * - 'SoloAmbient': Audio continues with silent switch, interrupts other audio
@@ -207,6 +207,19 @@ export interface IOSConfig {
207
207
  audioSession?: AudioSessionConfig
208
208
  }
209
209
 
210
+ /** Web platform specific configuration options */
211
+ export interface WebConfig {
212
+ /**
213
+ * Whether to store uncompressed audio data for WAV generation
214
+ *
215
+ * When true, all PCM chunks are stored in memory to create a WAV file when compression is disabled
216
+ * When false, uncompressed audio won't be available, but memory usage will be lower
217
+ *
218
+ * Default: true (for backward compatibility)
219
+ */
220
+ storeUncompressedAudio?: boolean
221
+ }
222
+
210
223
  // Add new type for interruption reasons
211
224
  export type RecordingInterruptionReason =
212
225
  /** Audio focus was lost to another app */
@@ -219,6 +232,14 @@ export type RecordingInterruptionReason =
219
232
  | 'phoneCallEnded'
220
233
  /** Recording was stopped by the system or another app */
221
234
  | 'recordingStopped'
235
+ /** Recording device was disconnected */
236
+ | 'deviceDisconnected'
237
+ /** Recording switched to default device after disconnection */
238
+ | 'deviceFallback'
239
+ /** A new audio device was connected */
240
+ | 'deviceConnected'
241
+ /** Device switching failed */
242
+ | 'deviceSwitchFailed'
222
243
 
223
244
  // Add new interface for interruption events
224
245
  export interface RecordingInterruptionEvent {
@@ -228,6 +249,48 @@ export interface RecordingInterruptionEvent {
228
249
  isPaused: boolean
229
250
  }
230
251
 
252
+ export interface AudioDeviceCapabilities {
253
+ /** Supported sample rates for the device */
254
+ sampleRates: number[]
255
+ /** Supported channel counts for the device */
256
+ channelCounts: number[]
257
+ /** Supported bit depths for the device */
258
+ bitDepths: number[]
259
+ /** Whether the device supports echo cancellation */
260
+ hasEchoCancellation?: boolean
261
+ /** Whether the device supports noise suppression */
262
+ hasNoiseSuppression?: boolean
263
+ /** Whether the device supports automatic gain control */
264
+ hasAutomaticGainControl?: boolean
265
+ }
266
+
267
+ export interface AudioDevice {
268
+ /** Unique identifier for the device */
269
+ id: string
270
+ /** Human-readable name of the device */
271
+ name: string
272
+ /** Device type (builtin_mic, bluetooth, etc.) */
273
+ type: string
274
+ /** Whether this is the system default device */
275
+ isDefault: boolean
276
+ /** Audio capabilities for the device */
277
+ capabilities: AudioDeviceCapabilities
278
+ /** Whether the device is currently available */
279
+ isAvailable: boolean
280
+ }
281
+
282
+ /** Defines how recording should behave when a device becomes unavailable */
283
+ export const DeviceDisconnectionBehavior = {
284
+ /** Pause recording when device disconnects */
285
+ PAUSE: 'pause',
286
+ /** Switch to default device and continue recording */
287
+ FALLBACK: 'fallback',
288
+ } as const
289
+
290
+ /** Type for DeviceDisconnectionBehavior values */
291
+ export type DeviceDisconnectionBehaviorType =
292
+ (typeof DeviceDisconnectionBehavior)[keyof typeof DeviceDisconnectionBehavior]
293
+
231
294
  export interface RecordingConfig {
232
295
  /** Sample rate for recording in Hz (16000, 44100, or 48000) */
233
296
  sampleRate?: SampleRate
@@ -262,6 +325,9 @@ export interface RecordingConfig {
262
325
  /** iOS-specific configuration */
263
326
  ios?: IOSConfig
264
327
 
328
+ /** Web-specific configuration options */
329
+ web?: WebConfig
330
+
265
331
  /** Duration of each segment in milliseconds for analysis (default: 100) */
266
332
  segmentDurationMs?: number
267
333
 
@@ -294,6 +360,12 @@ export interface RecordingConfig {
294
360
  outputDirectory?: string // If not provided, uses default app directory
295
361
  /** Optional filename for the recording (uses UUID if not provided) */
296
362
  filename?: string // If not provided, uses UUID
363
+
364
+ /** ID of the device to use for recording (if not specified, uses default) */
365
+ deviceId?: string
366
+
367
+ /** How to handle device disconnection during recording */
368
+ deviceDisconnectionBehavior?: DeviceDisconnectionBehaviorType
297
369
  }
298
370
 
299
371
  export interface NotificationConfig {
@@ -420,6 +492,46 @@ export interface ExtractedAudioData {
420
492
  }
421
493
 
422
494
  export interface UseAudioRecorderState {
495
+ /**
496
+ * Prepares recording with the specified configuration without starting it.
497
+ *
498
+ * This method eliminates the latency between calling startRecording and the actual recording beginning.
499
+ * It pre-initializes all audio resources, requests permissions, and sets up audio sessions in advance,
500
+ * allowing for true zero-latency recording start when startRecording is called later.
501
+ *
502
+ * Technical benefits:
503
+ * - Eliminates audio pipeline initialization delay (50-300ms depending on platform)
504
+ * - Pre-allocates audio buffers to avoid memory allocation during recording start
505
+ * - Initializes audio hardware in advance (particularly important on iOS)
506
+ * - Requests and verifies permissions before the critical recording moment
507
+ *
508
+ * Use this method when:
509
+ * - You need zero-latency recording start (e.g., voice commands, musical applications)
510
+ * - You're building time-sensitive applications where missing initial audio would be problematic
511
+ * - You want to prepare resources during app initialization, screen loading, or preceding user interaction
512
+ * - You need to ensure recording starts reliably and instantly on all platforms
513
+ *
514
+ * @param config - The recording configuration, identical to what you would pass to startRecording
515
+ * @returns A promise that resolves when preparation is complete
516
+ *
517
+ * @example
518
+ * // Prepare during component mounting
519
+ * useEffect(() => {
520
+ * prepareRecording({
521
+ * sampleRate: 44100,
522
+ * channels: 1,
523
+ * encoding: 'pcm_16bit',
524
+ * });
525
+ * }, []);
526
+ *
527
+ * // Later when user taps record button, it starts with zero latency
528
+ * const handleRecordPress = () => startRecording({
529
+ * sampleRate: 44100,
530
+ * channels: 1,
531
+ * encoding: 'pcm_16bit',
532
+ * });
533
+ */
534
+ prepareRecording: (_: RecordingConfig) => Promise<void>
423
535
  /** Starts recording with the specified configuration */
424
536
  startRecording: (_: RecordingConfig) => Promise<StartRecordingResult>
425
537
  /** Stops the current recording and returns the recording data */