@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.
- package/CHANGELOG.md +12 -1
- package/README.md +41 -1
- package/android/src/main/java/net/siteed/audiostudio/AudioRecorderManager.kt +130 -0
- package/android/src/main/java/net/siteed/audiostudio/AudioStudioModule.kt +1 -0
- package/android/src/main/java/net/siteed/audiostudio/Constants.kt +2 -1
- package/android/src/main/java/net/siteed/audiostudio/RecordingConfig.kt +5 -1
- package/build/cjs/AudioStudio.types.js.map +1 -1
- package/build/cjs/AudioStudio.web.js +125 -13
- package/build/cjs/AudioStudio.web.js.map +1 -1
- package/build/cjs/AudioStudioModule.js +6 -1
- package/build/cjs/AudioStudioModule.js.map +1 -1
- package/build/cjs/events.js +4 -0
- package/build/cjs/events.js.map +1 -1
- package/build/cjs/index.js +3 -1
- package/build/cjs/index.js.map +1 -1
- package/build/cjs/useAudioRecorder.js +187 -30
- package/build/cjs/useAudioRecorder.js.map +1 -1
- package/build/cjs/utils/nativeRecordingOptions.js +13 -0
- package/build/cjs/utils/nativeRecordingOptions.js.map +1 -0
- package/build/cjs/utils/nativeRecordingOptions.test.js +30 -0
- package/build/cjs/utils/nativeRecordingOptions.test.js.map +1 -0
- package/build/esm/AudioStudio.types.js.map +1 -1
- package/build/esm/AudioStudio.web.js +125 -13
- package/build/esm/AudioStudio.web.js.map +1 -1
- package/build/esm/AudioStudioModule.js +6 -1
- package/build/esm/AudioStudioModule.js.map +1 -1
- package/build/esm/events.js +3 -0
- package/build/esm/events.js.map +1 -1
- package/build/esm/index.js +1 -0
- package/build/esm/index.js.map +1 -1
- package/build/esm/useAudioRecorder.js +188 -31
- package/build/esm/useAudioRecorder.js.map +1 -1
- package/build/esm/utils/nativeRecordingOptions.js +10 -0
- package/build/esm/utils/nativeRecordingOptions.js.map +1 -0
- package/build/esm/utils/nativeRecordingOptions.test.js +28 -0
- package/build/esm/utils/nativeRecordingOptions.test.js.map +1 -0
- package/build/types/AudioStudio.types.d.ts +58 -1
- package/build/types/AudioStudio.types.d.ts.map +1 -1
- package/build/types/AudioStudio.web.d.ts +17 -1
- package/build/types/AudioStudio.web.d.ts.map +1 -1
- package/build/types/AudioStudioModule.d.ts.map +1 -1
- package/build/types/events.d.ts +2 -1
- package/build/types/events.d.ts.map +1 -1
- package/build/types/index.d.ts +1 -0
- package/build/types/index.d.ts.map +1 -1
- package/build/types/useAudioRecorder.d.ts +4 -1
- package/build/types/useAudioRecorder.d.ts.map +1 -1
- package/build/types/utils/nativeRecordingOptions.d.ts +28 -0
- package/build/types/utils/nativeRecordingOptions.d.ts.map +1 -0
- package/build/types/utils/nativeRecordingOptions.test.d.ts +2 -0
- package/build/types/utils/nativeRecordingOptions.test.d.ts.map +1 -0
- package/ios/AudioStreamManager.swift +103 -9
- package/ios/AudioStreamManagerDelegate.swift +1 -0
- package/ios/AudioStudioModule.swift +6 -0
- package/ios/RecordingSettings.swift +48 -43
- package/package.json +1 -1
- package/src/AudioStudio.types.ts +70 -1
- package/src/AudioStudio.web.ts +152 -13
- package/src/AudioStudioModule.ts +6 -1
- package/src/events.ts +13 -1
- package/src/index.ts +1 -0
- package/src/useAudioRecorder.tsx +260 -45
- package/src/utils/nativeRecordingOptions.test.ts +29 -0
- package/src/utils/nativeRecordingOptions.ts +20 -0
package/src/AudioStudio.web.ts
CHANGED
|
@@ -52,6 +52,7 @@ export interface AudioStudioWebProps {
|
|
|
52
52
|
audioWorkletUrl: string
|
|
53
53
|
featuresExtratorUrl: string
|
|
54
54
|
maxBufferSize?: number // Maximum number of chunks to keep in memory
|
|
55
|
+
emitEvent?: (eventName: string, params: unknown) => void
|
|
55
56
|
}
|
|
56
57
|
|
|
57
58
|
export class AudioStudioWeb extends LegacyEventEmitter {
|
|
@@ -80,12 +81,19 @@ export class AudioStudioWeb extends LegacyEventEmitter {
|
|
|
80
81
|
totalCompressedSize: number = 0
|
|
81
82
|
private readonly maxBufferSize: number
|
|
82
83
|
private eventCallback?: (event: AudioStreamEvent) => void
|
|
84
|
+
private readonly moduleEventEmitter?: (eventName: string, params: unknown) => void
|
|
85
|
+
private maxDurationTimer?: ReturnType<typeof setTimeout>
|
|
86
|
+
private maxDurationTargetMs = 0
|
|
87
|
+
private maxDurationAccumulatedActiveMs = 0
|
|
88
|
+
private maxDurationSegmentStartMs = 0
|
|
89
|
+
private maxDurationReached = false
|
|
83
90
|
|
|
84
91
|
constructor({
|
|
85
92
|
audioWorkletUrl,
|
|
86
93
|
featuresExtratorUrl,
|
|
87
94
|
logger,
|
|
88
95
|
maxBufferSize = DEFAULT_MAX_BUFFER_SIZE,
|
|
96
|
+
emitEvent,
|
|
89
97
|
}: AudioStudioWebProps) {
|
|
90
98
|
const mockNativeModule = {
|
|
91
99
|
addListener: () => {},
|
|
@@ -114,6 +122,125 @@ export class AudioStudioWeb extends LegacyEventEmitter {
|
|
|
114
122
|
this.audioWorkletUrl = audioWorkletUrl
|
|
115
123
|
this.featuresExtratorUrl = featuresExtratorUrl
|
|
116
124
|
this.maxBufferSize = maxBufferSize
|
|
125
|
+
this.moduleEventEmitter = emitEvent
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
private emitModuleEvent(eventName: string, params: unknown) {
|
|
129
|
+
this.emit(eventName, params)
|
|
130
|
+
this.moduleEventEmitter?.(eventName, params)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
private resetMaxDurationState(preserveReached = false) {
|
|
134
|
+
if (this.maxDurationTimer) {
|
|
135
|
+
clearTimeout(this.maxDurationTimer)
|
|
136
|
+
this.maxDurationTimer = undefined
|
|
137
|
+
}
|
|
138
|
+
this.maxDurationSegmentStartMs = 0
|
|
139
|
+
if (!preserveReached || !this.maxDurationReached) {
|
|
140
|
+
this.maxDurationTargetMs = 0
|
|
141
|
+
this.maxDurationAccumulatedActiveMs = 0
|
|
142
|
+
this.maxDurationReached = false
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
private getMaxDurationActiveMs(now = performance.now()) {
|
|
147
|
+
if (this.maxDurationSegmentStartMs <= 0) {
|
|
148
|
+
return this.maxDurationAccumulatedActiveMs
|
|
149
|
+
}
|
|
150
|
+
return (
|
|
151
|
+
this.maxDurationAccumulatedActiveMs +
|
|
152
|
+
(now - this.maxDurationSegmentStartMs)
|
|
153
|
+
)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
private scheduleMaxDurationTimer() {
|
|
157
|
+
if (
|
|
158
|
+
this.maxDurationTargetMs <= 0 ||
|
|
159
|
+
this.maxDurationReached ||
|
|
160
|
+
!this.isRecording ||
|
|
161
|
+
this.isPaused
|
|
162
|
+
) {
|
|
163
|
+
return
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (this.maxDurationTimer) {
|
|
167
|
+
clearTimeout(this.maxDurationTimer)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const remainingMs = Math.max(
|
|
171
|
+
0,
|
|
172
|
+
this.maxDurationTargetMs - this.getMaxDurationActiveMs()
|
|
173
|
+
)
|
|
174
|
+
this.maxDurationTimer = setTimeout(() => {
|
|
175
|
+
this.maxDurationTimer = undefined
|
|
176
|
+
this.emitMaxDurationReached()
|
|
177
|
+
}, remainingMs)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
private startMaxDurationTimer(recordingConfig: RecordingConfig) {
|
|
181
|
+
this.resetMaxDurationState()
|
|
182
|
+
const targetMs = Number(recordingConfig.maxDurationMs ?? 0)
|
|
183
|
+
if (!Number.isFinite(targetMs) || targetMs <= 0) {
|
|
184
|
+
return
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
this.maxDurationTargetMs = targetMs
|
|
188
|
+
this.maxDurationSegmentStartMs = performance.now()
|
|
189
|
+
this.scheduleMaxDurationTimer()
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
private pauseMaxDurationTimer() {
|
|
193
|
+
if (this.maxDurationTimer) {
|
|
194
|
+
clearTimeout(this.maxDurationTimer)
|
|
195
|
+
this.maxDurationTimer = undefined
|
|
196
|
+
}
|
|
197
|
+
if (this.maxDurationSegmentStartMs > 0) {
|
|
198
|
+
this.maxDurationAccumulatedActiveMs = this.getMaxDurationActiveMs()
|
|
199
|
+
this.maxDurationSegmentStartMs = 0
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
private resumeMaxDurationTimer() {
|
|
204
|
+
if (this.maxDurationTargetMs <= 0 || this.maxDurationReached) {
|
|
205
|
+
return
|
|
206
|
+
}
|
|
207
|
+
this.maxDurationSegmentStartMs = performance.now()
|
|
208
|
+
this.scheduleMaxDurationTimer()
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
private emitMaxDurationReached() {
|
|
212
|
+
if (this.maxDurationTargetMs <= 0 || this.maxDurationReached) {
|
|
213
|
+
return
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const durationMs = Math.round(this.getMaxDurationActiveMs())
|
|
217
|
+
this.maxDurationReached = true
|
|
218
|
+
const autoStopped = !!this.recordingConfig?.autoStopOnMaxDuration
|
|
219
|
+
this.emitModuleEvent('MaxDurationReached', {
|
|
220
|
+
durationMs,
|
|
221
|
+
maxDurationMs: this.maxDurationTargetMs,
|
|
222
|
+
overrunMs: Math.max(0, durationMs - this.maxDurationTargetMs),
|
|
223
|
+
streamUuid: this.streamUuid ?? undefined,
|
|
224
|
+
autoStopped,
|
|
225
|
+
})
|
|
226
|
+
if (autoStopped) {
|
|
227
|
+
this.stopRecording().catch((error) => {
|
|
228
|
+
this.logger?.error(
|
|
229
|
+
'Error auto-stopping on max duration:',
|
|
230
|
+
error
|
|
231
|
+
)
|
|
232
|
+
})
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
private flushExpiredMaxDuration() {
|
|
237
|
+
if (
|
|
238
|
+
this.maxDurationTargetMs > 0 &&
|
|
239
|
+
!this.maxDurationReached &&
|
|
240
|
+
this.getMaxDurationActiveMs() >= this.maxDurationTargetMs
|
|
241
|
+
) {
|
|
242
|
+
this.emitMaxDurationReached()
|
|
243
|
+
}
|
|
117
244
|
}
|
|
118
245
|
|
|
119
246
|
// Utility to handle user media stream
|
|
@@ -275,6 +402,7 @@ export class AudioStudioWeb extends LegacyEventEmitter {
|
|
|
275
402
|
this.currentInterval = recordingConfig.interval ?? 1000
|
|
276
403
|
this.currentIntervalAnalysis = recordingConfig.intervalAnalysis ?? 500
|
|
277
404
|
this.lastEmittedAnalysisTime = Date.now()
|
|
405
|
+
this.startMaxDurationTimer(recordingConfig)
|
|
278
406
|
|
|
279
407
|
// Use custom filename if provided, otherwise fallback to timestamp
|
|
280
408
|
if (recordingConfig.filename) {
|
|
@@ -321,11 +449,11 @@ export class AudioStudioWeb extends LegacyEventEmitter {
|
|
|
321
449
|
// Update local state if the interruption should pause recording
|
|
322
450
|
if (event.isPaused) {
|
|
323
451
|
this.isPaused = true
|
|
452
|
+
this.pausedTime = Date.now()
|
|
453
|
+
this.pauseMaxDurationTimer()
|
|
324
454
|
|
|
325
455
|
// If this is a device disconnection, handle according to behavior setting
|
|
326
456
|
if (event.reason === 'deviceDisconnected') {
|
|
327
|
-
this.pausedTime = Date.now()
|
|
328
|
-
|
|
329
457
|
// Check if we should try fallback to another device
|
|
330
458
|
if (
|
|
331
459
|
this.recordingConfig?.deviceDisconnectionBehavior ===
|
|
@@ -339,7 +467,7 @@ export class AudioStudioWeb extends LegacyEventEmitter {
|
|
|
339
467
|
this.handleDeviceFallback().catch((error) => {
|
|
340
468
|
// If fallback fails, emit warning
|
|
341
469
|
this.logger?.error('Device fallback failed:', error)
|
|
342
|
-
this.
|
|
470
|
+
this.emitModuleEvent('onRecordingInterrupted', {
|
|
343
471
|
reason: 'deviceSwitchFailed',
|
|
344
472
|
isPaused: true,
|
|
345
473
|
timestamp: Date.now(),
|
|
@@ -352,15 +480,15 @@ export class AudioStudioWeb extends LegacyEventEmitter {
|
|
|
352
480
|
this.logger?.warn(
|
|
353
481
|
'Device disconnected - recording paused automatically'
|
|
354
482
|
)
|
|
355
|
-
this.
|
|
483
|
+
this.emitModuleEvent('onRecordingInterrupted', event)
|
|
356
484
|
}
|
|
357
485
|
} else {
|
|
358
486
|
// For other interruption types, just emit the event
|
|
359
|
-
this.
|
|
487
|
+
this.emitModuleEvent('onRecordingInterrupted', event)
|
|
360
488
|
}
|
|
361
489
|
} else {
|
|
362
490
|
// If not causing a pause, just forward the event
|
|
363
|
-
this.
|
|
491
|
+
this.emitModuleEvent('onRecordingInterrupted', event)
|
|
364
492
|
}
|
|
365
493
|
}
|
|
366
494
|
|
|
@@ -390,7 +518,7 @@ export class AudioStudioWeb extends LegacyEventEmitter {
|
|
|
390
518
|
private customRecorderAnalysisCallback(
|
|
391
519
|
audioAnalysisData: AudioAnalysis
|
|
392
520
|
): void {
|
|
393
|
-
this.
|
|
521
|
+
this.emitModuleEvent('AudioAnalysis', audioAnalysisData)
|
|
394
522
|
}
|
|
395
523
|
|
|
396
524
|
// Get recording duration
|
|
@@ -425,6 +553,7 @@ export class AudioStudioWeb extends LegacyEventEmitter {
|
|
|
425
553
|
} else {
|
|
426
554
|
this.currentDurationMs += chunkDurationMs
|
|
427
555
|
}
|
|
556
|
+
this.flushExpiredMaxDuration()
|
|
428
557
|
|
|
429
558
|
const audioEventPayload: AudioEventPayload = {
|
|
430
559
|
fileUri,
|
|
@@ -445,7 +574,7 @@ export class AudioStudioWeb extends LegacyEventEmitter {
|
|
|
445
574
|
: undefined,
|
|
446
575
|
}
|
|
447
576
|
|
|
448
|
-
this.
|
|
577
|
+
this.emitModuleEvent('AudioData', audioEventPayload)
|
|
449
578
|
}
|
|
450
579
|
|
|
451
580
|
// Stop recording
|
|
@@ -457,6 +586,7 @@ export class AudioStudioWeb extends LegacyEventEmitter {
|
|
|
457
586
|
this.logger?.debug('Starting stop process')
|
|
458
587
|
|
|
459
588
|
try {
|
|
589
|
+
this.pauseMaxDurationTimer()
|
|
460
590
|
const { compressedBlob, uncompressedBlob } =
|
|
461
591
|
await this.customRecorder.stop()
|
|
462
592
|
|
|
@@ -540,6 +670,7 @@ export class AudioStudioWeb extends LegacyEventEmitter {
|
|
|
540
670
|
this.totalCompressedSize = 0
|
|
541
671
|
this.lastEmittedCompressionSize = 0
|
|
542
672
|
this.audioChunks = []
|
|
673
|
+
this.resetMaxDurationState(true)
|
|
543
674
|
|
|
544
675
|
return result
|
|
545
676
|
} catch (error) {
|
|
@@ -565,11 +696,13 @@ export class AudioStudioWeb extends LegacyEventEmitter {
|
|
|
565
696
|
}
|
|
566
697
|
this.isPaused = true
|
|
567
698
|
this.pausedTime = Date.now()
|
|
699
|
+
this.pauseMaxDurationTimer()
|
|
568
700
|
} catch (error) {
|
|
569
701
|
this.logger?.error('Error in pauseRecording', error)
|
|
570
702
|
// Even if the pause operation failed, make sure our state is consistent
|
|
571
703
|
this.isPaused = true
|
|
572
704
|
this.pausedTime = Date.now()
|
|
705
|
+
this.pauseMaxDurationTimer()
|
|
573
706
|
}
|
|
574
707
|
}
|
|
575
708
|
|
|
@@ -607,8 +740,9 @@ export class AudioStudioWeb extends LegacyEventEmitter {
|
|
|
607
740
|
const pauseDuration = Date.now() - this.pausedTime
|
|
608
741
|
this.recordingStartTime += pauseDuration
|
|
609
742
|
this.pausedTime = 0
|
|
743
|
+
this.resumeMaxDurationTimer()
|
|
610
744
|
|
|
611
|
-
this.
|
|
745
|
+
this.emitModuleEvent('onRecordingInterrupted', {
|
|
612
746
|
reason: 'userResumed',
|
|
613
747
|
isPaused: false,
|
|
614
748
|
timestamp: Date.now(),
|
|
@@ -616,7 +750,7 @@ export class AudioStudioWeb extends LegacyEventEmitter {
|
|
|
616
750
|
} catch (error) {
|
|
617
751
|
this.logger?.error('Resume failed:', error)
|
|
618
752
|
// Fallback to emitting a general failure if resume fails unexpectedly
|
|
619
|
-
this.
|
|
753
|
+
this.emitModuleEvent('onRecordingInterrupted', {
|
|
620
754
|
reason: 'resumeFailed', // Use a more specific reason
|
|
621
755
|
isPaused: true, // Remain paused if resume fails
|
|
622
756
|
timestamp: Date.now(),
|
|
@@ -628,6 +762,7 @@ export class AudioStudioWeb extends LegacyEventEmitter {
|
|
|
628
762
|
|
|
629
763
|
// Get current status
|
|
630
764
|
status() {
|
|
765
|
+
this.flushExpiredMaxDuration()
|
|
631
766
|
const durationMs = this.getRecordingDuration()
|
|
632
767
|
|
|
633
768
|
const status: AudioStreamStatus = {
|
|
@@ -651,6 +786,9 @@ export class AudioStudioWeb extends LegacyEventEmitter {
|
|
|
651
786
|
compressedFileUri: `${this.streamUuid}.webm`,
|
|
652
787
|
}
|
|
653
788
|
: undefined,
|
|
789
|
+
maxDurationMs:
|
|
790
|
+
this.maxDurationTargetMs > 0 ? this.maxDurationTargetMs : undefined,
|
|
791
|
+
maxDurationReached: this.maxDurationReached,
|
|
654
792
|
}
|
|
655
793
|
return status
|
|
656
794
|
}
|
|
@@ -708,7 +846,7 @@ export class AudioStudioWeb extends LegacyEventEmitter {
|
|
|
708
846
|
// Try to get a fallback device
|
|
709
847
|
const fallbackDeviceInfo = await this.getFallbackDevice()
|
|
710
848
|
if (!fallbackDeviceInfo) {
|
|
711
|
-
this.
|
|
849
|
+
this.emitModuleEvent('onRecordingInterrupted', {
|
|
712
850
|
reason: 'deviceSwitchFailed',
|
|
713
851
|
isPaused: true,
|
|
714
852
|
timestamp: Date.now(),
|
|
@@ -774,6 +912,7 @@ export class AudioStudioWeb extends LegacyEventEmitter {
|
|
|
774
912
|
// Update recording state
|
|
775
913
|
this.isPaused = false
|
|
776
914
|
this.recordingStartTime = Date.now()
|
|
915
|
+
this.resumeMaxDurationTimer()
|
|
777
916
|
|
|
778
917
|
// Restore size counters to maintain continuity
|
|
779
918
|
this.currentSize = previousTotalSize
|
|
@@ -795,7 +934,7 @@ export class AudioStudioWeb extends LegacyEventEmitter {
|
|
|
795
934
|
error
|
|
796
935
|
)
|
|
797
936
|
this.isPaused = true
|
|
798
|
-
this.
|
|
937
|
+
this.emitModuleEvent('onRecordingInterrupted', {
|
|
799
938
|
reason: 'deviceSwitchFailed',
|
|
800
939
|
isPaused: true,
|
|
801
940
|
timestamp: Date.now(),
|
|
@@ -807,7 +946,7 @@ export class AudioStudioWeb extends LegacyEventEmitter {
|
|
|
807
946
|
} catch (error) {
|
|
808
947
|
this.logger?.error('Failed to use fallback device', error)
|
|
809
948
|
this.isPaused = true
|
|
810
|
-
this.
|
|
949
|
+
this.emitModuleEvent('onRecordingInterrupted', {
|
|
811
950
|
reason: 'deviceSwitchFailed',
|
|
812
951
|
isPaused: true,
|
|
813
952
|
timestamp: Date.now(),
|
package/src/AudioStudioModule.ts
CHANGED
|
@@ -10,7 +10,12 @@ if (Platform.OS === 'web') {
|
|
|
10
10
|
let instance: AudioStudioWeb | null = null
|
|
11
11
|
|
|
12
12
|
AudioStudioModule = (webProps: AudioStudioWebProps) => {
|
|
13
|
-
instance ??= new AudioStudioWeb(
|
|
13
|
+
instance ??= new AudioStudioWeb({
|
|
14
|
+
...webProps,
|
|
15
|
+
emitEvent: (eventName, params) => {
|
|
16
|
+
AudioStudioModule.sendEvent(eventName, params)
|
|
17
|
+
},
|
|
18
|
+
})
|
|
14
19
|
return instance
|
|
15
20
|
}
|
|
16
21
|
AudioStudioModule.requestPermissionsAsync = async () => {
|
package/src/events.ts
CHANGED
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
import { LegacyEventEmitter, type EventSubscription } from 'expo-modules-core'
|
|
4
4
|
|
|
5
5
|
import { AudioAnalysis } from './AudioAnalysis/AudioAnalysis.types'
|
|
6
|
-
import {
|
|
6
|
+
import type {
|
|
7
|
+
MaxDurationReachedEvent,
|
|
8
|
+
RecordingInterruptionEvent,
|
|
9
|
+
} from './AudioStudio.types'
|
|
7
10
|
import AudioStudioModule from './AudioStudioModule'
|
|
8
11
|
|
|
9
12
|
const emitter = new LegacyEventEmitter(AudioStudioModule)
|
|
@@ -61,3 +64,12 @@ export function addRecordingInterruptionListener(
|
|
|
61
64
|
|
|
62
65
|
return subscription
|
|
63
66
|
}
|
|
67
|
+
|
|
68
|
+
export function addMaxDurationReachedListener(
|
|
69
|
+
listener: (event: MaxDurationReachedEvent) => void
|
|
70
|
+
): EventSubscription {
|
|
71
|
+
return emitter.addListener<MaxDurationReachedEvent>(
|
|
72
|
+
'MaxDurationReached',
|
|
73
|
+
listener
|
|
74
|
+
)
|
|
75
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
} from './streamAudioData'
|
|
26
26
|
import { trimAudio } from './trimAudio'
|
|
27
27
|
import { useAudioRecorder } from './useAudioRecorder'
|
|
28
|
+
export { addMaxDurationReachedListener } from './events'
|
|
28
29
|
|
|
29
30
|
export * from './utils/convertPCMToFloat32'
|
|
30
31
|
export * from './utils/getWavFileInfo'
|