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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +30 -1
  2. package/android/src/main/java/net/siteed/audiostudio/AudioRecorderManager.kt +130 -0
  3. package/android/src/main/java/net/siteed/audiostudio/AudioStudioModule.kt +1 -0
  4. package/android/src/main/java/net/siteed/audiostudio/Constants.kt +2 -1
  5. package/android/src/main/java/net/siteed/audiostudio/RecordingConfig.kt +5 -1
  6. package/build/cjs/AudioStudio.types.js.map +1 -1
  7. package/build/cjs/AudioStudio.web.js +125 -13
  8. package/build/cjs/AudioStudio.web.js.map +1 -1
  9. package/build/cjs/AudioStudioModule.js +6 -1
  10. package/build/cjs/AudioStudioModule.js.map +1 -1
  11. package/build/cjs/events.js +4 -0
  12. package/build/cjs/events.js.map +1 -1
  13. package/build/cjs/index.js +3 -1
  14. package/build/cjs/index.js.map +1 -1
  15. package/build/cjs/useAudioRecorder.js +139 -4
  16. package/build/cjs/useAudioRecorder.js.map +1 -1
  17. package/build/esm/AudioStudio.types.js.map +1 -1
  18. package/build/esm/AudioStudio.web.js +125 -13
  19. package/build/esm/AudioStudio.web.js.map +1 -1
  20. package/build/esm/AudioStudioModule.js +6 -1
  21. package/build/esm/AudioStudioModule.js.map +1 -1
  22. package/build/esm/events.js +3 -0
  23. package/build/esm/events.js.map +1 -1
  24. package/build/esm/index.js +1 -0
  25. package/build/esm/index.js.map +1 -1
  26. package/build/esm/useAudioRecorder.js +140 -5
  27. package/build/esm/useAudioRecorder.js.map +1 -1
  28. package/build/types/AudioStudio.types.d.ts +44 -1
  29. package/build/types/AudioStudio.types.d.ts.map +1 -1
  30. package/build/types/AudioStudio.web.d.ts +17 -1
  31. package/build/types/AudioStudio.web.d.ts.map +1 -1
  32. package/build/types/AudioStudioModule.d.ts.map +1 -1
  33. package/build/types/events.d.ts +2 -1
  34. package/build/types/events.d.ts.map +1 -1
  35. package/build/types/index.d.ts +1 -0
  36. package/build/types/index.d.ts.map +1 -1
  37. package/build/types/useAudioRecorder.d.ts +2 -0
  38. package/build/types/useAudioRecorder.d.ts.map +1 -1
  39. package/ios/AudioStreamManager.swift +103 -9
  40. package/ios/AudioStreamManagerDelegate.swift +1 -0
  41. package/ios/AudioStudioModule.swift +6 -0
  42. package/ios/RecordingSettings.swift +48 -43
  43. package/package.json +1 -1
  44. package/src/AudioStudio.types.ts +48 -1
  45. package/src/AudioStudio.web.ts +152 -13
  46. package/src/AudioStudioModule.ts +6 -1
  47. package/src/events.ts +13 -1
  48. package/src/index.ts +1 -0
  49. package/src/useAudioRecorder.tsx +182 -2
package/README.md CHANGED
@@ -36,7 +36,7 @@ Cross-platform audio recording, analysis, and processing for React Native and Ex
36
36
 
37
37
  ## Features
38
38
 
39
- - **Recording** — real-time streaming, dual-stream (raw PCM + compressed), background recording, zero-latency start via `prepareRecording`
39
+ - **Recording** — real-time streaming, dual-stream (raw PCM + compressed), max active duration limits, background recording, zero-latency start via `prepareRecording`
40
40
  - **Device management** — list/select input devices (Bluetooth, USB, wired), automatic fallback
41
41
  - **Interruption handling** — auto pause/resume during phone calls
42
42
  - **Audio analysis** — MFCC, spectral features, mel spectrogram, tempo, pitch, waveform preview
@@ -116,6 +116,35 @@ await startRecording({
116
116
  })
117
117
  ```
118
118
 
119
+ ### Max Active Recording Duration
120
+
121
+ Use `maxDurationMs` to cap cumulative active recording time. Paused time does
122
+ not count toward the limit. By default, the recorder emits
123
+ `onMaxDurationReached` and continues recording so your app can decide what to
124
+ do next. Set `autoStopOnMaxDuration: true` to stop automatically.
125
+
126
+ ```typescript
127
+ const {
128
+ startRecording,
129
+ maxDurationMs,
130
+ maxDurationReached,
131
+ } = useAudioRecorder()
132
+
133
+ await startRecording({
134
+ sampleRate: 16000,
135
+ channels: 1,
136
+ maxDurationMs: 60_000,
137
+ autoStopOnMaxDuration: true,
138
+ onMaxDurationReached: (event) => {
139
+ console.log('Reached recording limit:', event.maxDurationMs)
140
+ },
141
+ })
142
+ ```
143
+
144
+ When auto-stop is enabled, the max-duration event is emitted before the stop
145
+ finishes. Use the event and stream callbacks for immediate UI updates, then use
146
+ normal recording state to observe that the recorder has stopped.
147
+
119
148
  ## Audio Analysis
120
149
 
121
150
  For live analysis during recording, `useAudioRecorder` keeps a recent analysis
@@ -92,6 +92,12 @@ class AudioRecorderManager(
92
92
  private var lastEmitTime = SystemClock.elapsedRealtime()
93
93
  private var lastPauseTime = 0L
94
94
  private var pausedDuration = 0L
95
+ private val maxDurationLock = Any()
96
+ private var maxDurationRunnable: Runnable? = null
97
+ private var maxDurationTargetMs = 0L
98
+ private var maxDurationAccumulatedActiveMs = 0L
99
+ private var maxDurationSegmentStartElapsed = 0L
100
+ private var maxDurationReached = false
95
101
  private var lastEmittedSize = 0L
96
102
  private var lastEmittedCompressedSize = 0L
97
103
  private var streamPosition = 0L // Track total bytes processed in the stream
@@ -650,6 +656,7 @@ class AudioRecorderManager(
650
656
  "compressedFileUri" to compressedFile?.toURI().toString()
651
657
  ) else null
652
658
  )
659
+ startMaxDurationTimer()
653
660
  promise.resolve(result)
654
661
 
655
662
  } catch (e: Exception) {
@@ -695,6 +702,123 @@ class AudioRecorderManager(
695
702
  return isSupported
696
703
  }
697
704
 
705
+ private fun getMaxDurationActiveMs(now: Long = SystemClock.elapsedRealtime()): Long {
706
+ return synchronized(maxDurationLock) {
707
+ if (maxDurationSegmentStartElapsed <= 0L) {
708
+ maxDurationAccumulatedActiveMs
709
+ } else {
710
+ maxDurationAccumulatedActiveMs + (now - maxDurationSegmentStartElapsed)
711
+ }
712
+ }
713
+ }
714
+
715
+ private fun startMaxDurationTimer() {
716
+ synchronized(maxDurationLock) {
717
+ maxDurationRunnable?.let { mainHandler.removeCallbacks(it) }
718
+ maxDurationRunnable = null
719
+ maxDurationTargetMs = recordingConfig.maxDurationMs
720
+ maxDurationAccumulatedActiveMs = 0L
721
+ maxDurationSegmentStartElapsed = 0L
722
+ maxDurationReached = false
723
+
724
+ if (maxDurationTargetMs <= 0L) {
725
+ return
726
+ }
727
+
728
+ maxDurationSegmentStartElapsed = SystemClock.elapsedRealtime()
729
+ }
730
+ scheduleMaxDurationTimer()
731
+ }
732
+
733
+ private fun scheduleMaxDurationTimer() {
734
+ val remainingMs = synchronized(maxDurationLock) {
735
+ if (
736
+ maxDurationTargetMs <= 0L ||
737
+ maxDurationReached ||
738
+ !_isRecording.get() ||
739
+ isPaused.get()
740
+ ) {
741
+ return
742
+ }
743
+
744
+ maxDurationRunnable?.let { mainHandler.removeCallbacks(it) }
745
+ (maxDurationTargetMs - getMaxDurationActiveMs()).coerceAtLeast(0L)
746
+ }
747
+
748
+ val runnable = Runnable { emitMaxDurationReached() }
749
+ synchronized(maxDurationLock) {
750
+ maxDurationRunnable = runnable
751
+ }
752
+ mainHandler.postDelayed(runnable, remainingMs)
753
+ }
754
+
755
+ private fun pauseMaxDurationTimer() {
756
+ synchronized(maxDurationLock) {
757
+ maxDurationRunnable?.let { mainHandler.removeCallbacks(it) }
758
+ maxDurationRunnable = null
759
+ if (maxDurationSegmentStartElapsed > 0L) {
760
+ maxDurationAccumulatedActiveMs = getMaxDurationActiveMs()
761
+ maxDurationSegmentStartElapsed = 0L
762
+ }
763
+ }
764
+ }
765
+
766
+ private fun resumeMaxDurationTimer() {
767
+ synchronized(maxDurationLock) {
768
+ if (maxDurationTargetMs <= 0L || maxDurationReached) {
769
+ return
770
+ }
771
+ maxDurationSegmentStartElapsed = SystemClock.elapsedRealtime()
772
+ }
773
+ scheduleMaxDurationTimer()
774
+ }
775
+
776
+ private fun cancelMaxDurationTimer() {
777
+ synchronized(maxDurationLock) {
778
+ maxDurationRunnable?.let { mainHandler.removeCallbacks(it) }
779
+ maxDurationRunnable = null
780
+ maxDurationSegmentStartElapsed = 0L
781
+ if (!maxDurationReached) {
782
+ maxDurationTargetMs = 0L
783
+ maxDurationAccumulatedActiveMs = 0L
784
+ }
785
+ }
786
+ }
787
+
788
+ private fun emitMaxDurationReached() {
789
+ val event = synchronized(maxDurationLock) {
790
+ if (maxDurationTargetMs <= 0L || maxDurationReached) {
791
+ return
792
+ }
793
+ if (!_isRecording.get() || isPaused.get()) {
794
+ return
795
+ }
796
+
797
+ val durationMs = getMaxDurationActiveMs()
798
+ maxDurationReached = true
799
+ maxDurationRunnable = null
800
+ bundleOf(
801
+ "durationMs" to durationMs,
802
+ "maxDurationMs" to maxDurationTargetMs,
803
+ "overrunMs" to (durationMs - maxDurationTargetMs).coerceAtLeast(0L),
804
+ "streamUuid" to streamUuid,
805
+ "autoStopped" to recordingConfig.autoStopOnMaxDuration,
806
+ )
807
+ }
808
+
809
+ eventSender.sendExpoEvent(Constants.MAX_DURATION_REACHED_EVENT_NAME, event)
810
+ if (recordingConfig.autoStopOnMaxDuration) {
811
+ stopRecording(object : Promise {
812
+ override fun resolve(value: Any?) {
813
+ LogUtils.d(CLASS_NAME, "Auto-stopped recording after maxDurationMs")
814
+ }
815
+ override fun reject(code: String?, message: String?, cause: Throwable?) {
816
+ LogUtils.e(CLASS_NAME, "Failed to auto-stop recording after maxDurationMs: $message")
817
+ }
818
+ })
819
+ }
820
+ }
821
+
698
822
  private fun checkPermissions(options: Map<String, Any?>, promise: Promise): Boolean {
699
823
  if (!permissionUtils.checkRecordingPermission(enableBackgroundAudio)) {
700
824
  promise.reject(
@@ -996,6 +1120,7 @@ class AudioRecorderManager(
996
1120
 
997
1121
  fun stopRecording(promise: Promise) {
998
1122
  val stopStartTime = System.currentTimeMillis()
1123
+ cancelMaxDurationTimer()
999
1124
 
1000
1125
  synchronized(audioRecordLock) {
1001
1126
  if (!_isRecording.get()) {
@@ -1246,6 +1371,7 @@ class AudioRecorderManager(
1246
1371
  acquireWakeLock()
1247
1372
  pausedDuration += System.currentTimeMillis() - lastPauseTime
1248
1373
  isPaused.set(false)
1374
+ resumeMaxDurationTimer()
1249
1375
 
1250
1376
  synchronized(audioRecordLock) {
1251
1377
  // Double-check audioRecord is valid after potential reinitialization
@@ -1292,6 +1418,7 @@ class AudioRecorderManager(
1292
1418
  lastPauseTime = System.currentTimeMillis()
1293
1419
  isPaused.set(true)
1294
1420
  pausedBySystemInterruption.set(isSystemInterruption)
1421
+ pauseMaxDurationTimer()
1295
1422
 
1296
1423
  if (recordingConfig.showNotification) {
1297
1424
  notificationManager.pauseUpdates()
@@ -1381,6 +1508,8 @@ class AudioRecorderManager(
1381
1508
  "mimeType" to mimeType,
1382
1509
  "size" to totalDataSize,
1383
1510
  "interval" to recordingConfig.interval,
1511
+ "maxDurationMs" to if (recordingConfig.maxDurationMs > 0) recordingConfig.maxDurationMs else null,
1512
+ "maxDurationReached" to maxDurationReached,
1384
1513
  "compression" to compressionBundle
1385
1514
  )
1386
1515
  }
@@ -1756,6 +1885,7 @@ class AudioRecorderManager(
1756
1885
  }
1757
1886
 
1758
1887
  fun cleanup() {
1888
+ cancelMaxDurationTimer()
1759
1889
  synchronized(audioRecordLock) {
1760
1890
  try {
1761
1891
  if (_isRecording.get()) {
@@ -90,6 +90,7 @@ class AudioStudioModule : Module(), EventSender, AudioStreamDecoderDelegate {
90
90
  Constants.AUDIO_EVENT_NAME,
91
91
  Constants.AUDIO_ANALYSIS_EVENT_NAME,
92
92
  Constants.RECORDING_INTERRUPTED_EVENT_NAME,
93
+ Constants.MAX_DURATION_REACHED_EVENT_NAME,
93
94
  Constants.TRIM_PROGRESS_EVENT,
94
95
  Constants.DEVICE_CHANGED_EVENT, // Add device changed event name
95
96
  Constants.AUDIO_STREAM_CHUNK_EVENT,
@@ -9,6 +9,7 @@ object Constants {
9
9
  const val AUDIO_EVENT_NAME = "AudioData"
10
10
  const val AUDIO_ANALYSIS_EVENT_NAME = "AudioAnalysis"
11
11
  const val RECORDING_INTERRUPTED_EVENT_NAME = "onRecordingInterrupted"
12
+ const val MAX_DURATION_REACHED_EVENT_NAME = "MaxDurationReached"
12
13
  const val TRIM_PROGRESS_EVENT = "TrimProgress"
13
14
  const val DEVICE_CHANGED_EVENT = "deviceChangedEvent"
14
15
  const val AUDIO_STREAM_CHUNK_EVENT = "AudioDataStreamChunk"
@@ -38,4 +39,4 @@ object Constants {
38
39
  const val DEVICE_TYPE_WIRED_HEADPHONES = "wired_headphones"
39
40
  const val DEVICE_TYPE_SPEAKER = "speaker"
40
41
  const val DEVICE_TYPE_UNKNOWN = "unknown"
41
- }
42
+ }
@@ -67,6 +67,8 @@ data class RecordingConfig(
67
67
  val audioFocusStrategy: String? = null,
68
68
  val bufferDurationSeconds: Double? = null,
69
69
  val streamFormat: String = "raw",
70
+ val maxDurationMs: Long = 0L,
71
+ val autoStopOnMaxDuration: Boolean = false,
70
72
  ) {
71
73
  companion object {
72
74
  fun fromMap(options: Map<String, Any?>?): Result<Pair<RecordingConfig, AudioFormatInfo>> {
@@ -160,6 +162,8 @@ data class RecordingConfig(
160
162
  audioFocusStrategy = audioFocusStrategy,
161
163
  bufferDurationSeconds = (options["bufferDurationSeconds"] as? Number)?.toDouble(),
162
164
  streamFormat = options.getStringOrDefault("streamFormat", "raw"),
165
+ maxDurationMs = options.getNumberOrDefault("maxDurationMs", 0L),
166
+ autoStopOnMaxDuration = options.getBooleanOrDefault("autoStopOnMaxDuration", false),
163
167
  )
164
168
 
165
169
  // Validate sample rate and channels
@@ -256,4 +260,4 @@ data class AudioFormatInfo(
256
260
  val format: Int,
257
261
  val mimeType: String,
258
262
  val fileExtension: String
259
- )
263
+ )
@@ -1 +1 @@
1
- {"version":3,"file":"AudioStudio.types.js","sourceRoot":"","sources":["../../src/AudioStudio.types.ts"],"names":[],"mappings":";;;AA8UA,4EAA4E;AAC/D,QAAA,2BAA2B,GAAG;IACvC,8CAA8C;IAC9C,KAAK,EAAE,OAAO;IACd,sDAAsD;IACtD,QAAQ,EAAE,UAAU;CACd,CAAA","sourcesContent":["// packages/audio-studio/src/AudioStudio.types.ts\nimport {\n AudioAnalysis,\n AudioFeaturesOptions,\n DecodingConfig,\n} from './AudioAnalysis/AudioAnalysis.types'\nimport { AudioAnalysisEvent } from './events'\n\nexport interface CompressionInfo {\n /** Size of the compressed audio data in bytes */\n size: number\n /** MIME type of the compressed audio (e.g., 'audio/aac', 'audio/opus') */\n mimeType: string\n /** Bitrate of the compressed audio in bits per second */\n bitrate: number\n /** Format of the compression (e.g., 'aac', 'opus') */\n format: string\n /** URI to the compressed audio file if available */\n compressedFileUri?: string\n}\n\nexport interface AudioStreamStatus {\n /** Indicates whether audio recording is currently active */\n isRecording: boolean\n /** Indicates whether recording is in a paused state */\n isPaused: boolean\n /** Duration of the current recording in milliseconds */\n durationMs: number\n /** Size of the recorded audio data in bytes */\n size: number\n /** Interval in milliseconds at which recording data is emitted */\n interval: number\n /** Interval in milliseconds at which analysis data is emitted */\n intervalAnalysis: number\n /** MIME type of the recorded audio (e.g., 'audio/wav') */\n mimeType: string\n /** Information about audio compression if enabled */\n compression?: CompressionInfo\n}\n\ninterface AudioDataEventBase {\n /** Current position in the audio stream in bytes */\n position: number\n /** URI to the file being recorded */\n fileUri: string\n /** Size of the current data chunk in bytes */\n eventDataSize: number\n /** Total size of the recording so far in bytes */\n totalSize: number\n /** Information about compression if enabled, including the compressed data chunk */\n compression?: CompressionInfo & {\n /** Base64 (native) or Blob (web) encoded compressed data chunk */\n data?: string | Blob\n }\n}\n\nexport interface AudioDataEventRaw extends AudioDataEventBase {\n /** Audio data as base64 string (native), Float32Array (web), or Int16Array (web) */\n data: string | Float32Array | Int16Array\n streamFormat?: undefined | 'raw'\n}\n\nexport interface AudioDataEventFloat32 extends AudioDataEventBase {\n /** Audio data as Float32Array with samples in [-1, 1] range */\n data: Float32Array\n streamFormat: 'float32'\n}\n\nexport type AudioDataEvent = AudioDataEventRaw | AudioDataEventFloat32\n\n/**\n * Audio encoding types supported by the library.\n *\n * Platform support:\n * - `pcm_8bit`: Android only (iOS/Web will fallback to 16-bit)\n * - `pcm_16bit`: All platforms\n * - `pcm_32bit`: All platforms\n *\n * @see {@link https://github.com/deeeed/audiolab/blob/main/packages/audio-studio/docs/PLATFORM_LIMITATIONS.md | Platform Limitations}\n */\nexport type EncodingType = 'pcm_32bit' | 'pcm_16bit' | 'pcm_8bit'\n\n/**\n * Supported audio sample rates in Hz.\n * All platforms support these standard rates.\n */\nexport type SampleRate = 16000 | 44100 | 48000\n\n/**\n * Audio bit depth (bits per sample).\n *\n * Platform support:\n * - `8`: Android only (iOS/Web will fallback to 16)\n * - `16`: All platforms (recommended for compatibility)\n * - `32`: All platforms\n *\n * @see {@link https://github.com/deeeed/audiolab/blob/main/packages/audio-studio/docs/PLATFORM_LIMITATIONS.md | Platform Limitations}\n */\nexport type BitDepth = 8 | 16 | 32\n\n/**\n * PCM format string representation.\n * @deprecated Use `EncodingType` directly\n */\nexport type PCMFormat = `pcm_${BitDepth}bit`\n\nexport type ConsoleLike = {\n /** Logs a message with optional arguments */\n log: (message: string, ...args: unknown[]) => void\n /** Logs a debug message with optional arguments */\n debug: (message: string, ...args: unknown[]) => void\n /** Logs an info message with optional arguments */\n info: (message: string, ...args: unknown[]) => void\n /** Logs a warning message with optional arguments */\n warn: (message: string, ...args: unknown[]) => void\n /** Logs an error message with optional arguments */\n error: (message: string, ...args: unknown[]) => void\n}\n\nexport interface Chunk {\n /** Transcribed text content */\n text: string\n /** Start and end timestamp in seconds [start, end] where end can be null if ongoing */\n timestamp: [number, number | null]\n}\n\nexport interface TranscriberData {\n /** Unique identifier for the transcription */\n id: string\n /** Indicates if the transcriber is currently processing */\n isBusy: boolean\n /** Complete transcribed text */\n text: string\n /** Start time of the transcription in milliseconds */\n startTime: number\n /** End time of the transcription in milliseconds */\n endTime: number\n /** Array of transcribed text chunks with timestamps */\n chunks: Chunk[]\n}\n\nexport interface AudioRecording {\n /** URI to the recorded audio file */\n fileUri: string\n /** Filename of the recorded audio */\n filename: string\n /** Duration of the recording in milliseconds */\n durationMs: number\n /** Size of the recording in bytes */\n size: number\n /** MIME type of the recorded audio */\n mimeType: string\n /** Number of audio channels (1 for mono, 2 for stereo) */\n channels: number\n /** Bit depth of the audio (8, 16, or 32 bits) */\n bitDepth: BitDepth\n /** Sample rate of the audio in Hz */\n sampleRate: SampleRate\n /** Timestamp when the recording was created */\n createdAt?: number\n /** Array of transcription data if available */\n transcripts?: TranscriberData[]\n /**\n * Full analysis data for the recording if processing was enabled and\n * `keepFullAnalysis` was not set to `false`.\n */\n analysisData?: AudioAnalysis\n /** Information about compression if enabled, including the URI to the compressed file */\n compression?: CompressionInfo & {\n /** URI to the compressed audio file */\n compressedFileUri: string\n }\n}\n\nexport interface StartRecordingResult {\n /** URI to the file being recorded */\n fileUri: string\n /** MIME type of the recording */\n mimeType: string\n /** Number of audio channels (1 for mono, 2 for stereo) */\n channels?: number\n /** Bit depth of the audio (8, 16, or 32 bits) */\n bitDepth?: BitDepth\n /** Sample rate of the audio in Hz */\n sampleRate?: SampleRate\n /** Information about compression if enabled, including the URI to the compressed file */\n compression?: CompressionInfo & {\n /** URI to the compressed audio file */\n compressedFileUri: string\n }\n}\n\nexport interface AudioSessionConfig {\n /**\n * Audio session category that defines the audio behavior\n * - 'Ambient': Audio continues with silent switch, mixes with other audio\n * - 'SoloAmbient': Audio continues with silent switch, interrupts other audio\n * - 'Playback': Audio continues in background, interrupts other audio\n * - 'Record': Optimized for recording, interrupts other audio\n * - 'PlayAndRecord': Allows simultaneous playback and recording\n * - 'MultiRoute': Routes audio to multiple outputs simultaneously\n */\n category?:\n | 'Ambient'\n | 'SoloAmbient'\n | 'Playback'\n | 'Record'\n | 'PlayAndRecord'\n | 'MultiRoute'\n /**\n * Audio session mode that defines the behavior for specific use cases\n * - 'Default': Standard audio behavior\n * - 'VoiceChat': Optimized for voice chat applications\n * - 'VideoChat': Optimized for video chat applications\n * - 'GameChat': Optimized for in-game chat\n * - 'VideoRecording': Optimized for video recording\n * - 'Measurement': Optimized for audio measurement\n * - 'MoviePlayback': Optimized for movie playback\n * - 'SpokenAudio': Optimized for spoken audio content\n */\n mode?:\n | 'Default'\n | 'VoiceChat'\n | 'VideoChat'\n | 'GameChat'\n | 'VideoRecording'\n | 'Measurement'\n | 'MoviePlayback'\n | 'SpokenAudio'\n /**\n * Options that modify the behavior of the audio session category\n * - 'MixWithOthers': Allows mixing with other active audio sessions\n * - 'DuckOthers': Reduces the volume of other audio sessions\n * - 'InterruptSpokenAudioAndMixWithOthers': Interrupts spoken audio and mixes with others\n * - 'AllowBluetooth': Allows audio routing to Bluetooth devices\n * - 'AllowBluetoothA2DP': Allows audio routing to Bluetooth A2DP devices\n * - 'AllowAirPlay': Allows audio routing to AirPlay devices\n * - 'DefaultToSpeaker': Routes audio to the speaker by default\n */\n categoryOptions?: (\n | 'MixWithOthers'\n | 'DuckOthers'\n | 'InterruptSpokenAudioAndMixWithOthers'\n | 'AllowBluetooth'\n | 'AllowBluetoothA2DP'\n | 'AllowAirPlay'\n | 'DefaultToSpeaker'\n )[]\n}\n\nexport interface IOSConfig {\n /** Configuration for the iOS audio session */\n audioSession?: AudioSessionConfig\n}\n\n/** Android platform specific configuration options */\nexport interface AndroidConfig {\n /**\n * Audio focus strategy for handling interruptions and background behavior\n *\n * - `'background'`: Continue recording when app loses focus (voice recorders, transcription apps)\n * - `'interactive'`: Pause when losing focus, resume when gaining (music apps, games)\n * - `'communication'`: Maintain priority for real-time communication (video calls, voice chat)\n * - `'none'`: No automatic audio focus management (custom handling)\n *\n * @default 'background' when keepAwake=true, 'interactive' otherwise\n */\n audioFocusStrategy?: 'background' | 'interactive' | 'communication' | 'none'\n}\n\n/** Web platform specific configuration options */\nexport interface WebConfig {\n // Reserved for future web-specific options\n}\n\n// Add new type for interruption reasons\nexport type RecordingInterruptionReason =\n /** Audio focus was lost to another app */\n | 'audioFocusLoss'\n /** Audio focus was regained */\n | 'audioFocusGain'\n /** Recording was interrupted by a phone call */\n | 'phoneCall'\n /** Phone call that interrupted recording has ended */\n | 'phoneCallEnded'\n /** Recording was stopped by the system or another app */\n | 'recordingStopped'\n /** Recording device was disconnected */\n | 'deviceDisconnected'\n /** Recording switched to default device after disconnection */\n | 'deviceFallback'\n /** A new audio device was connected */\n | 'deviceConnected'\n /** Device switching failed */\n | 'deviceSwitchFailed'\n\n// Add new interface for interruption events\nexport interface RecordingInterruptionEvent {\n /** The reason for the recording interruption */\n reason: RecordingInterruptionReason\n /** Indicates whether the recording is paused due to the interruption */\n isPaused: boolean\n}\n\nexport interface AudioDeviceCapabilities {\n /** Supported sample rates for the device */\n sampleRates: number[]\n /** Supported channel counts for the device */\n channelCounts: number[]\n /** Supported bit depths for the device */\n bitDepths: number[]\n /** Whether the device supports echo cancellation */\n hasEchoCancellation?: boolean\n /** Whether the device supports noise suppression */\n hasNoiseSuppression?: boolean\n /** Whether the device supports automatic gain control */\n hasAutomaticGainControl?: boolean\n}\n\nexport interface AudioDevice {\n /** Unique identifier for the device */\n id: string\n /** Human-readable name of the device */\n name: string\n /** Device type (builtin_mic, bluetooth, etc.) */\n type: string\n /** Whether this is the system default device */\n isDefault: boolean\n /** Audio capabilities for the device */\n capabilities: AudioDeviceCapabilities\n /** Whether the device is currently available */\n isAvailable: boolean\n}\n\n/** Defines how recording should behave when a device becomes unavailable */\nexport const DeviceDisconnectionBehavior = {\n /** Pause recording when device disconnects */\n PAUSE: 'pause',\n /** Switch to default device and continue recording */\n FALLBACK: 'fallback',\n} as const\n\n/** Type for DeviceDisconnectionBehavior values */\nexport type DeviceDisconnectionBehaviorType =\n (typeof DeviceDisconnectionBehavior)[keyof typeof DeviceDisconnectionBehavior]\n\n/**\n * Configuration for audio output files during recording\n */\nexport interface OutputConfig {\n /**\n * Configuration for the primary (uncompressed) output file\n */\n primary?: {\n /** Whether to create the primary output file (default: true) */\n enabled?: boolean\n /** Format for the primary output (currently only 'wav' is supported) */\n format?: 'wav'\n }\n\n /**\n * Configuration for the compressed output file\n */\n compressed?: {\n /** Whether to create a compressed output file (default: false) */\n enabled?: boolean\n /**\n * Format for compression\n * - 'aac': Advanced Audio Coding - supported on all platforms\n * - 'opus': Opus encoding - supported on Android and Web; on iOS will automatically fall back to AAC\n */\n format?: 'aac' | 'opus'\n /** Bitrate for compression in bits per second (default: 128000) */\n bitrate?: number\n /**\n * Prefer raw stream over container format (Android only)\n * - true: Use raw AAC stream (.aac files) like in v2.10.6\n * - false/undefined: Use M4A container (.m4a files) for better seeking support\n * Note: iOS always produces M4A containers and ignores this flag\n */\n preferRawStream?: boolean\n }\n\n // Future enhancement: Post-processing pipeline\n // postProcessing?: {\n // normalize?: boolean\n // trimSilence?: boolean\n // noiseReduction?: boolean\n // customProcessors?: AudioProcessor[]\n // }\n}\n\nexport interface RecordingConfig {\n /** Sample rate for recording in Hz (16000, 44100, or 48000) */\n sampleRate?: SampleRate\n\n /** Number of audio channels (1 for mono, 2 for stereo) */\n channels?: 1 | 2\n\n /**\n * Encoding type for the recording.\n *\n * Platform limitations:\n * - `pcm_8bit`: Android only (iOS/Web will fallback to `pcm_16bit` with warning)\n * - `pcm_16bit`: All platforms (recommended for cross-platform compatibility)\n * - `pcm_32bit`: All platforms\n *\n * The library will automatically validate and adjust the encoding based on\n * platform capabilities. A warning will be logged if fallback is required.\n *\n * @default 'pcm_16bit'\n * @see {@link EncodingType}\n * @see {@link https://github.com/deeeed/audiolab/blob/main/packages/audio-studio/docs/PLATFORM_LIMITATIONS.md | Platform Limitations}\n */\n encoding?: EncodingType\n\n /** Interval in milliseconds at which to emit recording data (minimum: 10ms) */\n interval?: number\n\n /** Interval in milliseconds at which to emit analysis data (minimum: 10ms) */\n intervalAnalysis?: number\n\n /** Keep the device awake while recording (default is false) */\n keepAwake?: boolean\n\n /** Show a notification during recording (default is false) */\n showNotification?: boolean\n\n /** Show waveform in the notification (Android only, when showNotification is true) */\n showWaveformInNotification?: boolean\n\n /** Configuration for the notification */\n notification?: NotificationConfig\n\n /** Enable audio processing (default is false) */\n enableProcessing?: boolean\n\n /**\n * Whether `useAudioRecorder` should retain every audio-analysis data point\n * and attach the full history to `stopRecording().analysisData`.\n *\n * Defaults to `true` for backwards compatibility. Set to `false` for\n * long-running recordings when you only need live `analysisData` state or\n * per-callback `onAudioAnalysis` chunks; this avoids unbounded JS memory\n * growth in the hook without disabling native analysis processing.\n */\n keepFullAnalysis?: boolean\n\n /** iOS-specific configuration */\n ios?: IOSConfig\n\n /** Android-specific configuration */\n android?: AndroidConfig\n\n /** Web-specific configuration options */\n web?: WebConfig\n\n /** Duration of each segment in milliseconds for analysis (default: 100) */\n segmentDurationMs?: number\n\n /** Feature options to extract during audio processing */\n features?: AudioFeaturesOptions\n\n /** Callback function to handle audio stream data */\n onAudioStream?: (_: AudioDataEvent) => Promise<void>\n\n /** Callback function to handle audio features extraction results */\n onAudioAnalysis?: (_: AudioAnalysisEvent) => Promise<void>\n\n /**\n * Configuration for audio output files\n *\n * Examples:\n * - Primary only (default): `{ primary: { enabled: true } }`\n * - Compressed only: `{ primary: { enabled: false }, compressed: { enabled: true, format: 'aac' } }`\n * - Both outputs: `{ compressed: { enabled: true } }`\n * - Streaming only: `{ primary: { enabled: false } }`\n */\n output?: OutputConfig\n\n /** Whether to automatically resume recording after an interruption (default is false) */\n autoResumeAfterInterruption?: boolean\n\n /** Optional callback to handle recording interruptions */\n onRecordingInterrupted?: (_: RecordingInterruptionEvent) => void\n\n /** Optional directory path where output files will be saved */\n outputDirectory?: string // If not provided, uses default app directory\n /** Optional filename for the recording (uses UUID if not provided) */\n filename?: string // If not provided, uses UUID\n\n /** ID of the device to use for recording (if not specified, uses default) */\n deviceId?: string\n\n /** How to handle device disconnection during recording */\n deviceDisconnectionBehavior?: DeviceDisconnectionBehaviorType\n\n /**\n * Buffer duration in seconds. Controls the size of audio buffers\n * used during recording. Smaller values reduce latency but increase\n * CPU usage. Larger values improve efficiency but increase latency.\n *\n * Platform Notes:\n * - iOS/macOS: Minimum effective 0.1s, uses accumulation below\n * - Android: Respects all sizes within hardware limits\n * - Web: Fully configurable\n *\n * Default: undefined (uses platform default ~23ms at 44.1kHz)\n * Recommended: 0.01 - 0.5 seconds\n * Optimal iOS: >= 0.1 seconds\n */\n bufferDurationSeconds?: number\n\n /**\n * Format for the audio stream data delivered to `onAudioStream`.\n *\n * - `'raw'` (default): base64-encoded PCM bytes on native, Float32Array on web\n * - `'float32'`: Float32Array with samples in [-1, 1] on all platforms.\n * Eliminates base64 encode/decode overhead on the native bridge.\n * Android (new arch): delivered as Float32Array via JSI.\n * iOS: delivered as regular Array<number>, normalized to Float32Array in JS.\n *\n * @default 'raw'\n */\n streamFormat?: 'float32' | 'raw'\n}\n\nexport interface NotificationConfig {\n /** Title of the notification */\n title?: string\n\n /** Main text content of the notification */\n text?: string\n\n /** Icon to be displayed in the notification (resource name or URI) */\n icon?: string\n\n /** Android-specific notification configuration */\n android?: {\n /** Unique identifier for the notification channel */\n channelId?: string\n\n /** User-visible name of the notification channel */\n channelName?: string\n\n /** User-visible description of the notification channel */\n channelDescription?: string\n\n /** Unique identifier for this notification */\n notificationId?: number\n\n /** List of actions that can be performed from the notification */\n actions?: NotificationAction[]\n\n /** Configuration for the waveform visualization in the notification */\n waveform?: WaveformConfig\n\n /** Color of the notification LED (if device supports it) */\n lightColor?: string\n\n /** Priority of the notification (affects how it's displayed) */\n priority?: 'min' | 'low' | 'default' | 'high' | 'max'\n\n /** Accent color for the notification (used for the app icon and buttons) */\n accentColor?: string\n\n /** Whether to show pause/resume actions in the notification (default: true) */\n showPauseResumeActions?: boolean\n }\n\n /** iOS-specific notification configuration */\n ios?: {\n /** Identifier for the notification category (used for grouping similar notifications) */\n categoryIdentifier?: string\n }\n}\n\nexport interface NotificationAction {\n /** Display title for the action */\n title: string\n\n /** Unique identifier for the action */\n identifier: string\n\n /** Icon to be displayed for the action (Android only) */\n icon?: string\n}\n\nexport interface WaveformConfig {\n /** The color of the waveform (e.g., \"#FFFFFF\" for white) */\n color?: string // The color of the waveform (e.g., \"#FFFFFF\" for white)\n /** Opacity of the waveform (0.0 - 1.0) */\n opacity?: number // Opacity of the waveform (0.0 - 1.0)\n /** Width of the waveform line (default: 1.5) */\n strokeWidth?: number // Width of the waveform line (default: 1.5)\n /** Drawing style: \"stroke\" for outline, \"fill\" for solid */\n style?: 'stroke' | 'fill' // Drawing style: \"stroke\" for outline, \"fill\" for solid\n /** Whether to mirror the waveform (symmetrical display) */\n mirror?: boolean // Whether to mirror the waveform (symmetrical display)\n /** Height of the waveform view in dp (default: 64) */\n height?: number // Height of the waveform view in dp (default: 64)\n}\n\nexport interface ExtractAudioDataOptions {\n /** URI of the audio file to extract data from */\n fileUri: string\n /** Start time in milliseconds (for time-based range) */\n startTimeMs?: number\n /** End time in milliseconds (for time-based range) */\n endTimeMs?: number\n /** Start position in bytes (for byte-based range) */\n position?: number\n /** Length in bytes to extract (for byte-based range) */\n length?: number\n /** Include normalized audio data in [-1, 1] range */\n includeNormalizedData?: boolean\n /** Include base64 encoded string representation of the audio data */\n includeBase64Data?: boolean\n /** Include WAV header in the PCM data (makes it a valid WAV file) */\n includeWavHeader?: boolean\n /** Logger for debugging - can pass console directly. */\n logger?: ConsoleLike\n /** Compute the checksum of the PCM data */\n computeChecksum?: boolean\n /** Target config for the normalized audio (Android and Web) */\n decodingOptions?: DecodingConfig\n}\n\nexport interface ExtractedAudioData {\n /** Raw PCM audio data */\n pcmData: Uint8Array\n /** Normalized audio data in [-1, 1] range (when includeNormalizedData is true) */\n normalizedData?: Float32Array\n /** Base64 encoded string representation of the audio data (when includeBase64Data is true) */\n base64Data?: string\n /** Sample rate in Hz (e.g., 44100, 48000) */\n sampleRate: number\n /** Number of audio channels (1 for mono, 2 for stereo) */\n channels: number\n /** Bits per sample (8, 16, or 32) */\n bitDepth: BitDepth\n /** Duration of the audio in milliseconds */\n durationMs: number\n /** PCM format identifier (e.g., \"pcm_16bit\") */\n format: PCMFormat\n /** Total number of audio samples per channel */\n samples: number\n /** Whether the pcmData includes a WAV header */\n hasWavHeader?: boolean\n /** CRC32 Checksum of PCM data */\n checksum?: number\n}\n\nexport interface UseAudioRecorderState {\n /**\n * Prepares recording with the specified configuration without starting it.\n *\n * This method eliminates the latency between calling startRecording and the actual recording beginning.\n * It pre-initializes all audio resources, requests permissions, and sets up audio sessions in advance,\n * allowing for true zero-latency recording start when startRecording is called later.\n *\n * Technical benefits:\n * - Eliminates audio pipeline initialization delay (50-300ms depending on platform)\n * - Pre-allocates audio buffers to avoid memory allocation during recording start\n * - Initializes audio hardware in advance (particularly important on iOS)\n * - Requests and verifies permissions before the critical recording moment\n *\n * Use this method when:\n * - You need zero-latency recording start (e.g., voice commands, musical applications)\n * - You're building time-sensitive applications where missing initial audio would be problematic\n * - You want to prepare resources during app initialization, screen loading, or preceding user interaction\n * - You need to ensure recording starts reliably and instantly on all platforms\n *\n * @param config - The recording configuration, identical to what you would pass to startRecording\n * @returns A promise that resolves when preparation is complete\n *\n * @example\n * // Prepare during component mounting\n * useEffect(() => {\n * prepareRecording({\n * sampleRate: 44100,\n * channels: 1,\n * encoding: 'pcm_16bit',\n * });\n * }, []);\n *\n * // Later when user taps record button, it starts with zero latency\n * const handleRecordPress = () => startRecording({\n * sampleRate: 44100,\n * channels: 1,\n * encoding: 'pcm_16bit',\n * });\n */\n prepareRecording: (_: RecordingConfig) => Promise<void>\n /** Starts recording with the specified configuration */\n startRecording: (_: RecordingConfig) => Promise<StartRecordingResult>\n /** Stops the current recording and returns the recording data */\n stopRecording: () => Promise<AudioRecording | null>\n /** Pauses the current recording */\n pauseRecording: () => Promise<void>\n /** Resumes a paused recording */\n resumeRecording: () => Promise<void>\n /** Indicates whether recording is currently active */\n isRecording: boolean\n /** Indicates whether recording is in a paused state */\n isPaused: boolean\n /** Duration of the current recording in milliseconds */\n durationMs: number // Duration of the recording\n /** Size of the recorded audio in bytes */\n size: number // Size in bytes of the recorded audio\n /** Information about compression if enabled */\n compression?: CompressionInfo\n /** Analysis data for the recording if processing was enabled */\n analysisData?: AudioAnalysis // Analysis data for the recording depending on enableProcessing flag\n /** Optional callback to handle recording interruptions */\n onRecordingInterrupted?: (_: RecordingInterruptionEvent) => void\n}\n\n/**\n * Represents an event emitted during the trimming process to report progress.\n */\nexport interface TrimProgressEvent {\n /**\n * The percentage of the trimming process that has been completed, ranging from 0 to 100.\n */\n progress: number\n\n /**\n * The number of bytes that have been processed so far. This is optional and may not be provided in all implementations.\n */\n bytesProcessed?: number\n\n /**\n * The total number of bytes to process. This is optional and may not be provided in all implementations.\n */\n totalBytes?: number\n}\n\n/**\n * Defines a time range in milliseconds for trimming operations.\n */\nexport interface TimeRange {\n /**\n * The start time of the range in milliseconds.\n */\n startTimeMs: number\n\n /**\n * The end time of the range in milliseconds.\n */\n endTimeMs: number\n}\n\n/**\n * Options for configuring the audio trimming operation.\n */\nexport interface TrimAudioOptions {\n /**\n * The URI of the audio file to trim.\n */\n fileUri: string\n\n /**\n * The mode of trimming to apply.\n * - `'single'`: Trims the audio to a single range defined by `startTimeMs` and `endTimeMs`.\n * - `'keep'`: Keeps the specified `ranges` and removes all other portions of the audio.\n * - `'remove'`: Removes the specified `ranges` and keeps the remaining portions of the audio.\n * @default 'single'\n */\n mode?: 'single' | 'keep' | 'remove'\n\n /**\n * An array of time ranges to keep or remove, depending on the `mode`.\n * - Required for `'keep'` and `'remove'` modes.\n * - Ignored when `mode` is `'single'`.\n */\n ranges?: TimeRange[]\n\n /**\n * The start time in milliseconds for the `'single'` mode.\n * - If not provided, trimming starts from the beginning of the audio (0 ms).\n */\n startTimeMs?: number\n\n /**\n * The end time in milliseconds for the `'single'` mode.\n * - If not provided, trimming extends to the end of the audio.\n */\n endTimeMs?: number\n\n /**\n * The name of the output file. If not provided, a default name will be generated.\n */\n outputFileName?: string\n\n /**\n * Configuration for the output audio format.\n */\n outputFormat?: {\n /**\n * The format of the output audio file.\n * - `'wav'`: Waveform Audio File Format (uncompressed).\n * - `'aac'`: Advanced Audio Coding (compressed). Not supported on web platforms.\n * - `'opus'`: Opus Interactive Audio Codec (compressed).\n */\n format: 'wav' | 'aac' | 'opus'\n\n /**\n * The sample rate of the output audio in Hertz (Hz).\n * - If not provided, the input audio's sample rate is used.\n */\n sampleRate?: number\n\n /**\n * The number of channels in the output audio (e.g., 1 for mono, 2 for stereo).\n * - If not provided, the input audio's channel count is used.\n */\n channels?: number\n\n /**\n * The bit depth of the output audio, applicable to PCM formats like `'wav'`.\n * - If not provided, the input audio's bit depth is used.\n */\n bitDepth?: number\n\n /**\n * The bitrate of the output audio in bits per second, applicable to compressed formats like `'aac'`.\n * - If not provided, a default bitrate is used based on the format.\n */\n bitrate?: number\n }\n\n /**\n * Options for decoding the input audio file.\n * - See `DecodingConfig` for details.\n */\n decodingOptions?: DecodingConfig\n}\n\n/**\n * Result of the audio trimming operation.\n */\nexport interface TrimAudioResult {\n /**\n * The URI of the trimmed audio file.\n */\n uri: string\n\n /**\n * The filename of the trimmed audio file.\n */\n filename: string\n\n /**\n * The duration of the trimmed audio in milliseconds.\n */\n durationMs: number\n\n /**\n * The size of the trimmed audio file in bytes.\n */\n size: number\n\n /**\n * The sample rate of the trimmed audio in Hertz (Hz).\n */\n sampleRate: number\n\n /**\n * The number of channels in the trimmed audio (e.g., 1 for mono, 2 for stereo).\n */\n channels: number\n\n /**\n * The bit depth of the trimmed audio, applicable to PCM formats like `'wav'`.\n */\n bitDepth: number\n\n /**\n * The MIME type of the trimmed audio file (e.g., `'audio/wav'`, `'audio/mpeg'`).\n */\n mimeType: string\n\n /**\n * Information about compression if the output format is compressed.\n */\n compression?: {\n /**\n * The format of the compression (e.g., `'aac'`, `'mp3'`, `'opus'`).\n */\n format: string\n\n /**\n * The bitrate of the compressed audio in bits per second.\n */\n bitrate: number\n\n /**\n * The size of the compressed audio file in bytes.\n */\n size: number\n }\n\n /**\n * Information about the processing time.\n */\n processingInfo?: {\n /**\n * The time it took to process the audio in milliseconds.\n */\n durationMs: number\n }\n}\n"]}
1
+ {"version":3,"file":"AudioStudio.types.js","sourceRoot":"","sources":["../../src/AudioStudio.types.ts"],"names":[],"mappings":";;;AA+VA,4EAA4E;AAC/D,QAAA,2BAA2B,GAAG;IACvC,8CAA8C;IAC9C,KAAK,EAAE,OAAO;IACd,sDAAsD;IACtD,QAAQ,EAAE,UAAU;CACd,CAAA","sourcesContent":["// packages/audio-studio/src/AudioStudio.types.ts\nimport {\n AudioAnalysis,\n AudioFeaturesOptions,\n DecodingConfig,\n} from './AudioAnalysis/AudioAnalysis.types'\nimport type { AudioAnalysisEvent } from './events'\n\nexport interface CompressionInfo {\n /** Size of the compressed audio data in bytes */\n size: number\n /** MIME type of the compressed audio (e.g., 'audio/aac', 'audio/opus') */\n mimeType: string\n /** Bitrate of the compressed audio in bits per second */\n bitrate: number\n /** Format of the compression (e.g., 'aac', 'opus') */\n format: string\n /** URI to the compressed audio file if available */\n compressedFileUri?: string\n}\n\nexport interface AudioStreamStatus {\n /** Indicates whether audio recording is currently active */\n isRecording: boolean\n /** Indicates whether recording is in a paused state */\n isPaused: boolean\n /** Duration of the current recording in milliseconds */\n durationMs: number\n /** Size of the recorded audio data in bytes */\n size: number\n /** Interval in milliseconds at which recording data is emitted */\n interval: number\n /** Interval in milliseconds at which analysis data is emitted */\n intervalAnalysis: number\n /** MIME type of the recorded audio (e.g., 'audio/wav') */\n mimeType: string\n /** Information about audio compression if enabled */\n compression?: CompressionInfo\n /** Configured maximum active recording duration in milliseconds, if enabled */\n maxDurationMs?: number\n /** Whether the current recording session has reached the configured maximum duration */\n maxDurationReached?: boolean\n}\n\ninterface AudioDataEventBase {\n /** Current position in the audio stream in bytes */\n position: number\n /** URI to the file being recorded */\n fileUri: string\n /** Size of the current data chunk in bytes */\n eventDataSize: number\n /** Total size of the recording so far in bytes */\n totalSize: number\n /** Information about compression if enabled, including the compressed data chunk */\n compression?: CompressionInfo & {\n /** Base64 (native) or Blob (web) encoded compressed data chunk */\n data?: string | Blob\n }\n}\n\nexport interface AudioDataEventRaw extends AudioDataEventBase {\n /** Audio data as base64 string (native), Float32Array (web), or Int16Array (web) */\n data: string | Float32Array | Int16Array\n streamFormat?: undefined | 'raw'\n}\n\nexport interface AudioDataEventFloat32 extends AudioDataEventBase {\n /** Audio data as Float32Array with samples in [-1, 1] range */\n data: Float32Array\n streamFormat: 'float32'\n}\n\nexport type AudioDataEvent = AudioDataEventRaw | AudioDataEventFloat32\n\n/**\n * Audio encoding types supported by the library.\n *\n * Platform support:\n * - `pcm_8bit`: Android only (iOS/Web will fallback to 16-bit)\n * - `pcm_16bit`: All platforms\n * - `pcm_32bit`: All platforms\n *\n * @see {@link https://github.com/deeeed/audiolab/blob/main/packages/audio-studio/docs/PLATFORM_LIMITATIONS.md | Platform Limitations}\n */\nexport type EncodingType = 'pcm_32bit' | 'pcm_16bit' | 'pcm_8bit'\n\n/**\n * Supported audio sample rates in Hz.\n * All platforms support these standard rates.\n */\nexport type SampleRate = 16000 | 44100 | 48000\n\n/**\n * Audio bit depth (bits per sample).\n *\n * Platform support:\n * - `8`: Android only (iOS/Web will fallback to 16)\n * - `16`: All platforms (recommended for compatibility)\n * - `32`: All platforms\n *\n * @see {@link https://github.com/deeeed/audiolab/blob/main/packages/audio-studio/docs/PLATFORM_LIMITATIONS.md | Platform Limitations}\n */\nexport type BitDepth = 8 | 16 | 32\n\n/**\n * PCM format string representation.\n * @deprecated Use `EncodingType` directly\n */\nexport type PCMFormat = `pcm_${BitDepth}bit`\n\nexport type ConsoleLike = {\n /** Logs a message with optional arguments */\n log: (message: string, ...args: unknown[]) => void\n /** Logs a debug message with optional arguments */\n debug: (message: string, ...args: unknown[]) => void\n /** Logs an info message with optional arguments */\n info: (message: string, ...args: unknown[]) => void\n /** Logs a warning message with optional arguments */\n warn: (message: string, ...args: unknown[]) => void\n /** Logs an error message with optional arguments */\n error: (message: string, ...args: unknown[]) => void\n}\n\nexport interface Chunk {\n /** Transcribed text content */\n text: string\n /** Start and end timestamp in seconds [start, end] where end can be null if ongoing */\n timestamp: [number, number | null]\n}\n\nexport interface TranscriberData {\n /** Unique identifier for the transcription */\n id: string\n /** Indicates if the transcriber is currently processing */\n isBusy: boolean\n /** Complete transcribed text */\n text: string\n /** Start time of the transcription in milliseconds */\n startTime: number\n /** End time of the transcription in milliseconds */\n endTime: number\n /** Array of transcribed text chunks with timestamps */\n chunks: Chunk[]\n}\n\nexport interface AudioRecording {\n /** URI to the recorded audio file */\n fileUri: string\n /** Filename of the recorded audio */\n filename: string\n /** Duration of the recording in milliseconds */\n durationMs: number\n /** Size of the recording in bytes */\n size: number\n /** MIME type of the recorded audio */\n mimeType: string\n /** Number of audio channels (1 for mono, 2 for stereo) */\n channels: number\n /** Bit depth of the audio (8, 16, or 32 bits) */\n bitDepth: BitDepth\n /** Sample rate of the audio in Hz */\n sampleRate: SampleRate\n /** Timestamp when the recording was created */\n createdAt?: number\n /** Array of transcription data if available */\n transcripts?: TranscriberData[]\n /**\n * Full analysis data for the recording if processing was enabled and\n * `keepFullAnalysis` was not set to `false`.\n */\n analysisData?: AudioAnalysis\n /** Information about compression if enabled, including the URI to the compressed file */\n compression?: CompressionInfo & {\n /** URI to the compressed audio file */\n compressedFileUri: string\n }\n}\n\nexport interface StartRecordingResult {\n /** URI to the file being recorded */\n fileUri: string\n /** MIME type of the recording */\n mimeType: string\n /** Number of audio channels (1 for mono, 2 for stereo) */\n channels?: number\n /** Bit depth of the audio (8, 16, or 32 bits) */\n bitDepth?: BitDepth\n /** Sample rate of the audio in Hz */\n sampleRate?: SampleRate\n /** Information about compression if enabled, including the URI to the compressed file */\n compression?: CompressionInfo & {\n /** URI to the compressed audio file */\n compressedFileUri: string\n }\n}\n\nexport interface MaxDurationReachedEvent {\n /** Active recording duration that triggered the event, in milliseconds */\n durationMs: number\n /** Configured active recording duration limit, in milliseconds */\n maxDurationMs: number\n /** Amount by which timer delivery exceeded the limit, in milliseconds */\n overrunMs: number\n /** Active stream identifier when available */\n streamUuid?: string\n /** Whether the recorder was configured to stop automatically after this event */\n autoStopped: boolean\n}\n\nexport interface AudioSessionConfig {\n /**\n * Audio session category that defines the audio behavior\n * - 'Ambient': Audio continues with silent switch, mixes with other audio\n * - 'SoloAmbient': Audio continues with silent switch, interrupts other audio\n * - 'Playback': Audio continues in background, interrupts other audio\n * - 'Record': Optimized for recording, interrupts other audio\n * - 'PlayAndRecord': Allows simultaneous playback and recording\n * - 'MultiRoute': Routes audio to multiple outputs simultaneously\n */\n category?:\n | 'Ambient'\n | 'SoloAmbient'\n | 'Playback'\n | 'Record'\n | 'PlayAndRecord'\n | 'MultiRoute'\n /**\n * Audio session mode that defines the behavior for specific use cases\n * - 'Default': Standard audio behavior\n * - 'VoiceChat': Optimized for voice chat applications\n * - 'VideoChat': Optimized for video chat applications\n * - 'GameChat': Optimized for in-game chat\n * - 'VideoRecording': Optimized for video recording\n * - 'Measurement': Optimized for audio measurement\n * - 'MoviePlayback': Optimized for movie playback\n * - 'SpokenAudio': Optimized for spoken audio content\n */\n mode?:\n | 'Default'\n | 'VoiceChat'\n | 'VideoChat'\n | 'GameChat'\n | 'VideoRecording'\n | 'Measurement'\n | 'MoviePlayback'\n | 'SpokenAudio'\n /**\n * Options that modify the behavior of the audio session category\n * - 'MixWithOthers': Allows mixing with other active audio sessions\n * - 'DuckOthers': Reduces the volume of other audio sessions\n * - 'InterruptSpokenAudioAndMixWithOthers': Interrupts spoken audio and mixes with others\n * - 'AllowBluetooth': Allows audio routing to Bluetooth devices\n * - 'AllowBluetoothA2DP': Allows audio routing to Bluetooth A2DP devices\n * - 'AllowAirPlay': Allows audio routing to AirPlay devices\n * - 'DefaultToSpeaker': Routes audio to the speaker by default\n */\n categoryOptions?: (\n | 'MixWithOthers'\n | 'DuckOthers'\n | 'InterruptSpokenAudioAndMixWithOthers'\n | 'AllowBluetooth'\n | 'AllowBluetoothA2DP'\n | 'AllowAirPlay'\n | 'DefaultToSpeaker'\n )[]\n}\n\nexport interface IOSConfig {\n /** Configuration for the iOS audio session */\n audioSession?: AudioSessionConfig\n}\n\n/** Android platform specific configuration options */\nexport interface AndroidConfig {\n /**\n * Audio focus strategy for handling interruptions and background behavior\n *\n * - `'background'`: Continue recording when app loses focus (voice recorders, transcription apps)\n * - `'interactive'`: Pause when losing focus, resume when gaining (music apps, games)\n * - `'communication'`: Maintain priority for real-time communication (video calls, voice chat)\n * - `'none'`: No automatic audio focus management (custom handling)\n *\n * @default 'background' when keepAwake=true, 'interactive' otherwise\n */\n audioFocusStrategy?: 'background' | 'interactive' | 'communication' | 'none'\n}\n\n/** Web platform specific configuration options */\nexport interface WebConfig {\n // Reserved for future web-specific options\n}\n\n// Add new type for interruption reasons\nexport type RecordingInterruptionReason =\n /** Audio focus was lost to another app */\n | 'audioFocusLoss'\n /** Audio focus was regained */\n | 'audioFocusGain'\n /** Recording was interrupted by a phone call */\n | 'phoneCall'\n /** Phone call that interrupted recording has ended */\n | 'phoneCallEnded'\n /** Recording was stopped by the system or another app */\n | 'recordingStopped'\n /** Recording device was disconnected */\n | 'deviceDisconnected'\n /** Recording switched to default device after disconnection */\n | 'deviceFallback'\n /** A new audio device was connected */\n | 'deviceConnected'\n /** Device switching failed */\n | 'deviceSwitchFailed'\n\n// Add new interface for interruption events\nexport interface RecordingInterruptionEvent {\n /** The reason for the recording interruption */\n reason: RecordingInterruptionReason\n /** Indicates whether the recording is paused due to the interruption */\n isPaused: boolean\n}\n\nexport interface AudioDeviceCapabilities {\n /** Supported sample rates for the device */\n sampleRates: number[]\n /** Supported channel counts for the device */\n channelCounts: number[]\n /** Supported bit depths for the device */\n bitDepths: number[]\n /** Whether the device supports echo cancellation */\n hasEchoCancellation?: boolean\n /** Whether the device supports noise suppression */\n hasNoiseSuppression?: boolean\n /** Whether the device supports automatic gain control */\n hasAutomaticGainControl?: boolean\n}\n\nexport interface AudioDevice {\n /** Unique identifier for the device */\n id: string\n /** Human-readable name of the device */\n name: string\n /** Device type (builtin_mic, bluetooth, etc.) */\n type: string\n /** Whether this is the system default device */\n isDefault: boolean\n /** Audio capabilities for the device */\n capabilities: AudioDeviceCapabilities\n /** Whether the device is currently available */\n isAvailable: boolean\n}\n\n/** Defines how recording should behave when a device becomes unavailable */\nexport const DeviceDisconnectionBehavior = {\n /** Pause recording when device disconnects */\n PAUSE: 'pause',\n /** Switch to default device and continue recording */\n FALLBACK: 'fallback',\n} as const\n\n/** Type for DeviceDisconnectionBehavior values */\nexport type DeviceDisconnectionBehaviorType =\n (typeof DeviceDisconnectionBehavior)[keyof typeof DeviceDisconnectionBehavior]\n\n/**\n * Configuration for audio output files during recording\n */\nexport interface OutputConfig {\n /**\n * Configuration for the primary (uncompressed) output file\n */\n primary?: {\n /** Whether to create the primary output file (default: true) */\n enabled?: boolean\n /** Format for the primary output (currently only 'wav' is supported) */\n format?: 'wav'\n }\n\n /**\n * Configuration for the compressed output file\n */\n compressed?: {\n /** Whether to create a compressed output file (default: false) */\n enabled?: boolean\n /**\n * Format for compression\n * - 'aac': Advanced Audio Coding - supported on all platforms\n * - 'opus': Opus encoding - supported on Android and Web; on iOS will automatically fall back to AAC\n */\n format?: 'aac' | 'opus'\n /** Bitrate for compression in bits per second (default: 128000) */\n bitrate?: number\n /**\n * Prefer raw stream over container format (Android only)\n * - true: Use raw AAC stream (.aac files) like in v2.10.6\n * - false/undefined: Use M4A container (.m4a files) for better seeking support\n * Note: iOS always produces M4A containers and ignores this flag\n */\n preferRawStream?: boolean\n }\n\n // Future enhancement: Post-processing pipeline\n // postProcessing?: {\n // normalize?: boolean\n // trimSilence?: boolean\n // noiseReduction?: boolean\n // customProcessors?: AudioProcessor[]\n // }\n}\n\nexport interface RecordingConfig {\n /** Sample rate for recording in Hz (16000, 44100, or 48000) */\n sampleRate?: SampleRate\n\n /** Number of audio channels (1 for mono, 2 for stereo) */\n channels?: 1 | 2\n\n /**\n * Encoding type for the recording.\n *\n * Platform limitations:\n * - `pcm_8bit`: Android only (iOS/Web will fallback to `pcm_16bit` with warning)\n * - `pcm_16bit`: All platforms (recommended for cross-platform compatibility)\n * - `pcm_32bit`: All platforms\n *\n * The library will automatically validate and adjust the encoding based on\n * platform capabilities. A warning will be logged if fallback is required.\n *\n * @default 'pcm_16bit'\n * @see {@link EncodingType}\n * @see {@link https://github.com/deeeed/audiolab/blob/main/packages/audio-studio/docs/PLATFORM_LIMITATIONS.md | Platform Limitations}\n */\n encoding?: EncodingType\n\n /** Interval in milliseconds at which to emit recording data (minimum: 10ms) */\n interval?: number\n\n /** Interval in milliseconds at which to emit analysis data (minimum: 10ms) */\n intervalAnalysis?: number\n\n /** Keep the device awake while recording (default is false) */\n keepAwake?: boolean\n\n /** Show a notification during recording (default is false) */\n showNotification?: boolean\n\n /** Show waveform in the notification (Android only, when showNotification is true) */\n showWaveformInNotification?: boolean\n\n /** Configuration for the notification */\n notification?: NotificationConfig\n\n /** Enable audio processing (default is false) */\n enableProcessing?: boolean\n\n /**\n * Whether `useAudioRecorder` should retain every audio-analysis data point\n * and attach the full history to `stopRecording().analysisData`.\n *\n * Defaults to `true` for backwards compatibility. Set to `false` for\n * long-running recordings when you only need live `analysisData` state or\n * per-callback `onAudioAnalysis` chunks; this avoids unbounded JS memory\n * growth in the hook without disabling native analysis processing.\n */\n keepFullAnalysis?: boolean\n\n /** iOS-specific configuration */\n ios?: IOSConfig\n\n /** Android-specific configuration */\n android?: AndroidConfig\n\n /** Web-specific configuration options */\n web?: WebConfig\n\n /** Duration of each segment in milliseconds for analysis (default: 100) */\n segmentDurationMs?: number\n\n /** Feature options to extract during audio processing */\n features?: AudioFeaturesOptions\n\n /** Callback function to handle audio stream data */\n onAudioStream?: (_: AudioDataEvent) => Promise<void>\n\n /** Callback function to handle audio features extraction results */\n onAudioAnalysis?: (_: AudioAnalysisEvent) => Promise<void>\n\n /**\n * Configuration for audio output files\n *\n * Examples:\n * - Primary only (default): `{ primary: { enabled: true } }`\n * - Compressed only: `{ primary: { enabled: false }, compressed: { enabled: true, format: 'aac' } }`\n * - Both outputs: `{ compressed: { enabled: true } }`\n * - Streaming only: `{ primary: { enabled: false } }`\n */\n output?: OutputConfig\n\n /** Whether to automatically resume recording after an interruption (default is false) */\n autoResumeAfterInterruption?: boolean\n\n /** Optional callback to handle recording interruptions */\n onRecordingInterrupted?: (_: RecordingInterruptionEvent) => void\n\n /**\n * Maximum cumulative active recording duration, in milliseconds.\n *\n * Paused time does not count. Set to undefined, 0, or a negative value to disable.\n */\n maxDurationMs?: number\n\n /**\n * Stop recording automatically when maxDurationMs is reached.\n *\n * Defaults to false. The MaxDurationReached event is emitted before the stop request.\n * The automatic stop result is not returned to onMaxDurationReached; use the\n * event and stream callbacks for immediate UI updates.\n */\n autoStopOnMaxDuration?: boolean\n\n /**\n * Optional callback invoked when maxDurationMs is reached.\n *\n * If autoStopOnMaxDuration is true, this callback is invoked before the\n * recorder finishes stopping. The final stop result is not passed here.\n */\n onMaxDurationReached?: (_: MaxDurationReachedEvent) => void\n\n /** Optional directory path where output files will be saved */\n outputDirectory?: string // If not provided, uses default app directory\n /** Optional filename for the recording (uses UUID if not provided) */\n filename?: string // If not provided, uses UUID\n\n /** ID of the device to use for recording (if not specified, uses default) */\n deviceId?: string\n\n /** How to handle device disconnection during recording */\n deviceDisconnectionBehavior?: DeviceDisconnectionBehaviorType\n\n /**\n * Buffer duration in seconds. Controls the size of audio buffers\n * used during recording. Smaller values reduce latency but increase\n * CPU usage. Larger values improve efficiency but increase latency.\n *\n * Platform Notes:\n * - iOS/macOS: Minimum effective 0.1s, uses accumulation below\n * - Android: Respects all sizes within hardware limits\n * - Web: Fully configurable\n *\n * Default: undefined (uses platform default ~23ms at 44.1kHz)\n * Recommended: 0.01 - 0.5 seconds\n * Optimal iOS: >= 0.1 seconds\n */\n bufferDurationSeconds?: number\n\n /**\n * Format for the audio stream data delivered to `onAudioStream`.\n *\n * - `'raw'` (default): base64-encoded PCM bytes on native, Float32Array on web\n * - `'float32'`: Float32Array with samples in [-1, 1] on all platforms.\n * Eliminates base64 encode/decode overhead on the native bridge.\n * Android (new arch): delivered as Float32Array via JSI.\n * iOS: delivered as regular Array<number>, normalized to Float32Array in JS.\n *\n * @default 'raw'\n */\n streamFormat?: 'float32' | 'raw'\n}\n\nexport interface NotificationConfig {\n /** Title of the notification */\n title?: string\n\n /** Main text content of the notification */\n text?: string\n\n /** Icon to be displayed in the notification (resource name or URI) */\n icon?: string\n\n /** Android-specific notification configuration */\n android?: {\n /** Unique identifier for the notification channel */\n channelId?: string\n\n /** User-visible name of the notification channel */\n channelName?: string\n\n /** User-visible description of the notification channel */\n channelDescription?: string\n\n /** Unique identifier for this notification */\n notificationId?: number\n\n /** List of actions that can be performed from the notification */\n actions?: NotificationAction[]\n\n /** Configuration for the waveform visualization in the notification */\n waveform?: WaveformConfig\n\n /** Color of the notification LED (if device supports it) */\n lightColor?: string\n\n /** Priority of the notification (affects how it's displayed) */\n priority?: 'min' | 'low' | 'default' | 'high' | 'max'\n\n /** Accent color for the notification (used for the app icon and buttons) */\n accentColor?: string\n\n /** Whether to show pause/resume actions in the notification (default: true) */\n showPauseResumeActions?: boolean\n }\n\n /** iOS-specific notification configuration */\n ios?: {\n /** Identifier for the notification category (used for grouping similar notifications) */\n categoryIdentifier?: string\n }\n}\n\nexport interface NotificationAction {\n /** Display title for the action */\n title: string\n\n /** Unique identifier for the action */\n identifier: string\n\n /** Icon to be displayed for the action (Android only) */\n icon?: string\n}\n\nexport interface WaveformConfig {\n /** The color of the waveform (e.g., \"#FFFFFF\" for white) */\n color?: string // The color of the waveform (e.g., \"#FFFFFF\" for white)\n /** Opacity of the waveform (0.0 - 1.0) */\n opacity?: number // Opacity of the waveform (0.0 - 1.0)\n /** Width of the waveform line (default: 1.5) */\n strokeWidth?: number // Width of the waveform line (default: 1.5)\n /** Drawing style: \"stroke\" for outline, \"fill\" for solid */\n style?: 'stroke' | 'fill' // Drawing style: \"stroke\" for outline, \"fill\" for solid\n /** Whether to mirror the waveform (symmetrical display) */\n mirror?: boolean // Whether to mirror the waveform (symmetrical display)\n /** Height of the waveform view in dp (default: 64) */\n height?: number // Height of the waveform view in dp (default: 64)\n}\n\nexport interface ExtractAudioDataOptions {\n /** URI of the audio file to extract data from */\n fileUri: string\n /** Start time in milliseconds (for time-based range) */\n startTimeMs?: number\n /** End time in milliseconds (for time-based range) */\n endTimeMs?: number\n /** Start position in bytes (for byte-based range) */\n position?: number\n /** Length in bytes to extract (for byte-based range) */\n length?: number\n /** Include normalized audio data in [-1, 1] range */\n includeNormalizedData?: boolean\n /** Include base64 encoded string representation of the audio data */\n includeBase64Data?: boolean\n /** Include WAV header in the PCM data (makes it a valid WAV file) */\n includeWavHeader?: boolean\n /** Logger for debugging - can pass console directly. */\n logger?: ConsoleLike\n /** Compute the checksum of the PCM data */\n computeChecksum?: boolean\n /** Target config for the normalized audio (Android and Web) */\n decodingOptions?: DecodingConfig\n}\n\nexport interface ExtractedAudioData {\n /** Raw PCM audio data */\n pcmData: Uint8Array\n /** Normalized audio data in [-1, 1] range (when includeNormalizedData is true) */\n normalizedData?: Float32Array\n /** Base64 encoded string representation of the audio data (when includeBase64Data is true) */\n base64Data?: string\n /** Sample rate in Hz (e.g., 44100, 48000) */\n sampleRate: number\n /** Number of audio channels (1 for mono, 2 for stereo) */\n channels: number\n /** Bits per sample (8, 16, or 32) */\n bitDepth: BitDepth\n /** Duration of the audio in milliseconds */\n durationMs: number\n /** PCM format identifier (e.g., \"pcm_16bit\") */\n format: PCMFormat\n /** Total number of audio samples per channel */\n samples: number\n /** Whether the pcmData includes a WAV header */\n hasWavHeader?: boolean\n /** CRC32 Checksum of PCM data */\n checksum?: number\n}\n\nexport interface UseAudioRecorderState {\n /**\n * Prepares recording with the specified configuration without starting it.\n *\n * This method eliminates the latency between calling startRecording and the actual recording beginning.\n * It pre-initializes all audio resources, requests permissions, and sets up audio sessions in advance,\n * allowing for true zero-latency recording start when startRecording is called later.\n *\n * Technical benefits:\n * - Eliminates audio pipeline initialization delay (50-300ms depending on platform)\n * - Pre-allocates audio buffers to avoid memory allocation during recording start\n * - Initializes audio hardware in advance (particularly important on iOS)\n * - Requests and verifies permissions before the critical recording moment\n *\n * Use this method when:\n * - You need zero-latency recording start (e.g., voice commands, musical applications)\n * - You're building time-sensitive applications where missing initial audio would be problematic\n * - You want to prepare resources during app initialization, screen loading, or preceding user interaction\n * - You need to ensure recording starts reliably and instantly on all platforms\n *\n * @param config - The recording configuration, identical to what you would pass to startRecording\n * @returns A promise that resolves when preparation is complete\n *\n * @example\n * // Prepare during component mounting\n * useEffect(() => {\n * prepareRecording({\n * sampleRate: 44100,\n * channels: 1,\n * encoding: 'pcm_16bit',\n * });\n * }, []);\n *\n * // Later when user taps record button, it starts with zero latency\n * const handleRecordPress = () => startRecording({\n * sampleRate: 44100,\n * channels: 1,\n * encoding: 'pcm_16bit',\n * });\n */\n prepareRecording: (_: RecordingConfig) => Promise<void>\n /** Starts recording with the specified configuration */\n startRecording: (_: RecordingConfig) => Promise<StartRecordingResult>\n /** Stops the current recording and returns the recording data */\n stopRecording: () => Promise<AudioRecording | null>\n /** Pauses the current recording */\n pauseRecording: () => Promise<void>\n /** Resumes a paused recording */\n resumeRecording: () => Promise<void>\n /** Indicates whether recording is currently active */\n isRecording: boolean\n /** Indicates whether recording is in a paused state */\n isPaused: boolean\n /** Duration of the current recording in milliseconds */\n durationMs: number // Duration of the recording\n /** Size of the recorded audio in bytes */\n size: number // Size in bytes of the recorded audio\n /** Information about compression if enabled */\n compression?: CompressionInfo\n /** Configured maximum active recording duration in milliseconds, if enabled */\n maxDurationMs?: number\n /** Whether the current recording session has reached the configured maximum duration */\n maxDurationReached?: boolean\n /** Analysis data for the recording if processing was enabled */\n analysisData?: AudioAnalysis // Analysis data for the recording depending on enableProcessing flag\n /** Optional callback to handle recording interruptions */\n onRecordingInterrupted?: (_: RecordingInterruptionEvent) => void\n /** Optional callback invoked when maxDurationMs is reached */\n onMaxDurationReached?: (_: MaxDurationReachedEvent) => void\n}\n\n/**\n * Represents an event emitted during the trimming process to report progress.\n */\nexport interface TrimProgressEvent {\n /**\n * The percentage of the trimming process that has been completed, ranging from 0 to 100.\n */\n progress: number\n\n /**\n * The number of bytes that have been processed so far. This is optional and may not be provided in all implementations.\n */\n bytesProcessed?: number\n\n /**\n * The total number of bytes to process. This is optional and may not be provided in all implementations.\n */\n totalBytes?: number\n}\n\n/**\n * Defines a time range in milliseconds for trimming operations.\n */\nexport interface TimeRange {\n /**\n * The start time of the range in milliseconds.\n */\n startTimeMs: number\n\n /**\n * The end time of the range in milliseconds.\n */\n endTimeMs: number\n}\n\n/**\n * Options for configuring the audio trimming operation.\n */\nexport interface TrimAudioOptions {\n /**\n * The URI of the audio file to trim.\n */\n fileUri: string\n\n /**\n * The mode of trimming to apply.\n * - `'single'`: Trims the audio to a single range defined by `startTimeMs` and `endTimeMs`.\n * - `'keep'`: Keeps the specified `ranges` and removes all other portions of the audio.\n * - `'remove'`: Removes the specified `ranges` and keeps the remaining portions of the audio.\n * @default 'single'\n */\n mode?: 'single' | 'keep' | 'remove'\n\n /**\n * An array of time ranges to keep or remove, depending on the `mode`.\n * - Required for `'keep'` and `'remove'` modes.\n * - Ignored when `mode` is `'single'`.\n */\n ranges?: TimeRange[]\n\n /**\n * The start time in milliseconds for the `'single'` mode.\n * - If not provided, trimming starts from the beginning of the audio (0 ms).\n */\n startTimeMs?: number\n\n /**\n * The end time in milliseconds for the `'single'` mode.\n * - If not provided, trimming extends to the end of the audio.\n */\n endTimeMs?: number\n\n /**\n * The name of the output file. If not provided, a default name will be generated.\n */\n outputFileName?: string\n\n /**\n * Configuration for the output audio format.\n */\n outputFormat?: {\n /**\n * The format of the output audio file.\n * - `'wav'`: Waveform Audio File Format (uncompressed).\n * - `'aac'`: Advanced Audio Coding (compressed). Not supported on web platforms.\n * - `'opus'`: Opus Interactive Audio Codec (compressed).\n */\n format: 'wav' | 'aac' | 'opus'\n\n /**\n * The sample rate of the output audio in Hertz (Hz).\n * - If not provided, the input audio's sample rate is used.\n */\n sampleRate?: number\n\n /**\n * The number of channels in the output audio (e.g., 1 for mono, 2 for stereo).\n * - If not provided, the input audio's channel count is used.\n */\n channels?: number\n\n /**\n * The bit depth of the output audio, applicable to PCM formats like `'wav'`.\n * - If not provided, the input audio's bit depth is used.\n */\n bitDepth?: number\n\n /**\n * The bitrate of the output audio in bits per second, applicable to compressed formats like `'aac'`.\n * - If not provided, a default bitrate is used based on the format.\n */\n bitrate?: number\n }\n\n /**\n * Options for decoding the input audio file.\n * - See `DecodingConfig` for details.\n */\n decodingOptions?: DecodingConfig\n}\n\n/**\n * Result of the audio trimming operation.\n */\nexport interface TrimAudioResult {\n /**\n * The URI of the trimmed audio file.\n */\n uri: string\n\n /**\n * The filename of the trimmed audio file.\n */\n filename: string\n\n /**\n * The duration of the trimmed audio in milliseconds.\n */\n durationMs: number\n\n /**\n * The size of the trimmed audio file in bytes.\n */\n size: number\n\n /**\n * The sample rate of the trimmed audio in Hertz (Hz).\n */\n sampleRate: number\n\n /**\n * The number of channels in the trimmed audio (e.g., 1 for mono, 2 for stereo).\n */\n channels: number\n\n /**\n * The bit depth of the trimmed audio, applicable to PCM formats like `'wav'`.\n */\n bitDepth: number\n\n /**\n * The MIME type of the trimmed audio file (e.g., `'audio/wav'`, `'audio/mpeg'`).\n */\n mimeType: string\n\n /**\n * Information about compression if the output format is compressed.\n */\n compression?: {\n /**\n * The format of the compression (e.g., `'aac'`, `'mp3'`, `'opus'`).\n */\n format: string\n\n /**\n * The bitrate of the compressed audio in bits per second.\n */\n bitrate: number\n\n /**\n * The size of the compressed audio file in bytes.\n */\n size: number\n }\n\n /**\n * Information about the processing time.\n */\n processingInfo?: {\n /**\n * The time it took to process the audio in milliseconds.\n */\n durationMs: number\n }\n}\n"]}