@siteed/expo-audio-stream 1.0.3 → 1.0.5
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/.size-limit.json +4 -4
- package/README.md +18 -176
- package/android/src/main/java/net/siteed/audiostream/AudioRecorderManager.kt +1 -0
- package/app.plugin.js +1 -1
- package/build/AudioAnalysis/AudioAnalysis.types.d.ts +3 -5
- package/build/AudioAnalysis/AudioAnalysis.types.d.ts.map +1 -1
- package/build/AudioAnalysis/AudioAnalysis.types.js.map +1 -1
- package/build/AudioAnalysis/extractAudioAnalysis.d.ts +19 -3
- package/build/AudioAnalysis/extractAudioAnalysis.d.ts.map +1 -1
- package/build/AudioAnalysis/extractAudioAnalysis.js +14 -27
- package/build/AudioAnalysis/extractAudioAnalysis.js.map +1 -1
- package/build/AudioAnalysis/extractWaveform.d.ts.map +1 -1
- package/build/AudioAnalysis/extractWaveform.js +3 -3
- package/build/AudioAnalysis/extractWaveform.js.map +1 -1
- package/build/AudioRecorder.provider.d.ts +6 -6
- package/build/AudioRecorder.provider.d.ts.map +1 -1
- package/build/AudioRecorder.provider.js +9 -9
- package/build/AudioRecorder.provider.js.map +1 -1
- package/build/ExpoAudioStream.native.d.ts.map +1 -1
- package/build/ExpoAudioStream.native.js +2 -2
- package/build/ExpoAudioStream.native.js.map +1 -1
- package/build/ExpoAudioStream.types.d.ts +20 -18
- package/build/ExpoAudioStream.types.d.ts.map +1 -1
- package/build/ExpoAudioStream.types.js.map +1 -1
- package/build/ExpoAudioStream.web.d.ts +8 -8
- package/build/ExpoAudioStream.web.d.ts.map +1 -1
- package/build/ExpoAudioStream.web.js +40 -22
- package/build/ExpoAudioStream.web.js.map +1 -1
- package/build/ExpoAudioStreamModule.d.ts.map +1 -1
- package/build/ExpoAudioStreamModule.js +8 -7
- package/build/ExpoAudioStreamModule.js.map +1 -1
- package/build/WebRecorder.web.d.ts +8 -8
- package/build/WebRecorder.web.d.ts.map +1 -1
- package/build/WebRecorder.web.js +60 -50
- package/build/WebRecorder.web.js.map +1 -1
- package/build/constants.d.ts +1 -1
- package/build/constants.d.ts.map +1 -1
- package/build/constants.js +3 -3
- package/build/constants.js.map +1 -1
- package/build/events.d.ts +16 -4
- package/build/events.d.ts.map +1 -1
- package/build/events.js +8 -8
- package/build/events.js.map +1 -1
- package/build/index.d.ts +8 -8
- package/build/index.d.ts.map +1 -1
- package/build/index.js +6 -6
- package/build/index.js.map +1 -1
- package/build/logger.d.ts +2 -2
- package/build/logger.d.ts.map +1 -1
- package/build/logger.js +7 -11
- package/build/logger.js.map +1 -1
- package/build/useAudioRecorder.d.ts +4 -21
- package/build/useAudioRecorder.d.ts.map +1 -1
- package/build/useAudioRecorder.js +33 -33
- package/build/useAudioRecorder.js.map +1 -1
- package/build/utils/BlobFix.d.ts +9 -0
- package/build/utils/BlobFix.d.ts.map +1 -0
- package/build/utils/BlobFix.js +494 -0
- package/build/utils/BlobFix.js.map +1 -0
- package/build/utils/concatenateBuffers.d.ts +8 -0
- package/build/utils/concatenateBuffers.d.ts.map +1 -0
- package/build/utils/concatenateBuffers.js +21 -0
- package/build/utils/concatenateBuffers.js.map +1 -0
- package/build/utils/convertPCMToFloat32.d.ts +2 -2
- package/build/utils/convertPCMToFloat32.d.ts.map +1 -1
- package/build/utils/convertPCMToFloat32.js +49 -36
- package/build/utils/convertPCMToFloat32.js.map +1 -1
- package/build/utils/encodingToBitDepth.d.ts +1 -1
- package/build/utils/encodingToBitDepth.d.ts.map +1 -1
- package/build/utils/encodingToBitDepth.js +3 -3
- package/build/utils/encodingToBitDepth.js.map +1 -1
- package/build/utils/getWavFileInfo.d.ts +4 -3
- package/build/utils/getWavFileInfo.d.ts.map +1 -1
- package/build/utils/getWavFileInfo.js +18 -15
- package/build/utils/getWavFileInfo.js.map +1 -1
- package/build/utils/writeWavHeader.d.ts.map +1 -1
- package/build/utils/writeWavHeader.js +4 -4
- package/build/utils/writeWavHeader.js.map +1 -1
- package/build/workers/InlineFeaturesExtractor.web.d.ts.map +1 -1
- package/build/workers/InlineFeaturesExtractor.web.js.map +1 -1
- package/build/workers/inlineAudioWebWorker.web.d.ts.map +1 -1
- package/build/workers/inlineAudioWebWorker.web.js.map +1 -1
- package/expo-module.config.json +8 -17
- package/ios/AudioStreamManager.swift +1 -0
- package/ios/ExpoAudioStreamModule.swift +1 -0
- package/ios/RecordingResult.swift +1 -0
- package/package.json +72 -65
- package/plugin/build/index.d.ts +1 -1
- package/plugin/build/index.js +7 -7
- package/plugin/src/index.ts +47 -47
- package/plugin/tsconfig.json +8 -13
- package/src/AudioAnalysis/AudioAnalysis.types.ts +59 -60
- package/src/AudioAnalysis/extractAudioAnalysis.ts +132 -121
- package/src/AudioAnalysis/extractWaveform.ts +18 -18
- package/src/AudioRecorder.provider.tsx +53 -53
- package/src/ExpoAudioStream.native.ts +2 -2
- package/src/ExpoAudioStream.types.ts +56 -53
- package/src/ExpoAudioStream.web.ts +232 -205
- package/src/ExpoAudioStreamModule.ts +17 -16
- package/src/WebRecorder.web.ts +407 -390
- package/src/constants.ts +11 -11
- package/src/events.ts +27 -13
- package/src/index.ts +15 -15
- package/src/logger.ts +15 -18
- package/src/useAudioRecorder.tsx +394 -389
- package/src/utils/BlobFix.ts +550 -0
- package/src/utils/concatenateBuffers.ts +24 -0
- package/src/utils/convertPCMToFloat32.ts +72 -45
- package/src/utils/encodingToBitDepth.ts +14 -14
- package/src/utils/getWavFileInfo.ts +106 -99
- package/src/utils/writeWavHeader.ts +45 -45
- package/src/workers/InlineFeaturesExtractor.web.tsx +1 -1
- package/src/workers/inlineAudioWebWorker.web.tsx +1 -1
- package/tsconfig.json +12 -7
package/build/logger.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,OAAO,
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,OAAO,EAAE,SAAS,IAAI,eAAe,EAAE,MAAM,6BAA6B,CAAA;AAE1E,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAS7C,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,GAAW,EAAe,EAAE;IAClD,MAAM,UAAU,GAAG,eAAe,CAAC,GAAG,eAAe,IAAI,GAAG,EAAE,CAAC,CAAA;IAE/D,OAAO;QACH,GAAG,EAAE,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAI,IAAkB,CAAC;QACnE,KAAK,EAAE,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,GAAI,IAAkB,CAAC;QACvE,KAAK,EAAE,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,GAAI,IAAkB,CAAC;QACvE,IAAI,EAAE,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,GAAI,IAAkB,CAAC;KACxE,CAAA;AACL,CAAC,CAAA","sourcesContent":["// packages/expo-audio-stream/src/logger.ts\nimport { getLogger as siteedGetLogger } from '@siteed/react-native-logger'\n\nimport { DEBUG_NAMESPACE } from './constants'\n\ntype ConsoleLike = {\n log: (message: string, ...args: unknown[]) => void\n debug: (message: string, ...args: unknown[]) => void\n warn: (message: string, ...args: unknown[]) => void\n error: (message: string, ...args: unknown[]) => void\n}\n\nexport const getLogger = (tag: string): ConsoleLike => {\n const baseLogger = siteedGetLogger(`${DEBUG_NAMESPACE}:${tag}`)\n\n return {\n log: (...args: unknown[]) => baseLogger.log(...(args as [unknown])),\n debug: (...args: unknown[]) => baseLogger.debug(...(args as [unknown])),\n error: (...args: unknown[]) => baseLogger.error(...(args as [unknown])),\n warn: (...args: unknown[]) => baseLogger.warn(...(args as [unknown])),\n }\n}\n\n"]}
|
|
@@ -1,22 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { WavFileInfo } from "./utils/getWavFileInfo";
|
|
4
|
-
export interface ExtractMetadataProps {
|
|
5
|
-
fileUri?: string;
|
|
6
|
-
wavMetadata?: WavFileInfo;
|
|
7
|
-
arrayBuffer?: ArrayBuffer;
|
|
8
|
-
bitDepth?: number;
|
|
9
|
-
skipWavHeader?: boolean;
|
|
10
|
-
durationMs?: number;
|
|
11
|
-
sampleRate?: number;
|
|
12
|
-
numberOfChannels?: number;
|
|
13
|
-
algorithm?: "peak" | "rms";
|
|
14
|
-
position?: number;
|
|
15
|
-
length?: number;
|
|
16
|
-
pointsPerSecond?: number;
|
|
17
|
-
features?: AudioFeaturesOptions;
|
|
18
|
-
featuresExtratorUrl?: string;
|
|
19
|
-
}
|
|
1
|
+
import { AudioAnalysis } from './AudioAnalysis/AudioAnalysis.types';
|
|
2
|
+
import { AudioRecording, RecordingConfig, StartRecordingResult } from './ExpoAudioStream.types';
|
|
20
3
|
export interface UseAudioRecorderProps {
|
|
21
4
|
debug?: boolean;
|
|
22
5
|
audioWorkletUrl?: string;
|
|
@@ -24,14 +7,14 @@ export interface UseAudioRecorderProps {
|
|
|
24
7
|
}
|
|
25
8
|
export interface UseAudioRecorderState {
|
|
26
9
|
startRecording: (_: RecordingConfig) => Promise<StartRecordingResult>;
|
|
27
|
-
stopRecording: () => Promise<
|
|
10
|
+
stopRecording: () => Promise<AudioRecording>;
|
|
28
11
|
pauseRecording: () => void;
|
|
29
12
|
resumeRecording: () => void;
|
|
30
13
|
isRecording: boolean;
|
|
31
14
|
isPaused: boolean;
|
|
32
15
|
durationMs: number;
|
|
33
16
|
size: number;
|
|
34
|
-
analysisData?:
|
|
17
|
+
analysisData?: AudioAnalysis;
|
|
35
18
|
}
|
|
36
19
|
export declare function useAudioRecorder({ debug, audioWorkletUrl, featuresExtratorUrl, }?: UseAudioRecorderProps): UseAudioRecorderState;
|
|
37
20
|
//# sourceMappingURL=useAudioRecorder.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAudioRecorder.d.ts","sourceRoot":"","sources":["../src/useAudioRecorder.tsx"],"names":[],"mappings":"AAIA,OAAO,
|
|
1
|
+
{"version":3,"file":"useAudioRecorder.d.ts","sourceRoot":"","sources":["../src/useAudioRecorder.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAA;AACnE,OAAO,EAEH,cAAc,EAEd,eAAe,EACf,oBAAoB,EACvB,MAAM,yBAAyB,CAAA;AAWhC,MAAM,WAAW,qBAAqB;IAClC,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAC/B;AAED,MAAM,WAAW,qBAAqB;IAClC,cAAc,EAAE,CAAC,CAAC,EAAE,eAAe,KAAK,OAAO,CAAC,oBAAoB,CAAC,CAAA;IACrE,aAAa,EAAE,MAAM,OAAO,CAAC,cAAc,CAAC,CAAA;IAC5C,cAAc,EAAE,MAAM,IAAI,CAAA;IAC1B,eAAe,EAAE,MAAM,IAAI,CAAA;IAC3B,WAAW,EAAE,OAAO,CAAA;IACpB,QAAQ,EAAE,OAAO,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,MAAM,CAAA;IACZ,YAAY,CAAC,EAAE,aAAa,CAAA;CAC/B;AAwED,wBAAgB,gBAAgB,CAAC,EAC7B,KAAa,EACb,eAAe,EACf,mBAAmB,GACtB,GAAE,qBAA0B,GAAG,qBAAqB,CAiTpD"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// src/useAudioRecorder.ts
|
|
2
|
-
import { Platform } from
|
|
3
|
-
import { useCallback, useEffect, useReducer, useRef } from
|
|
4
|
-
import ExpoAudioStreamModule from
|
|
5
|
-
import { addAudioAnalysisListener, addAudioEventListener } from
|
|
6
|
-
import {
|
|
7
|
-
const TAG =
|
|
2
|
+
import { Platform } from 'expo-modules-core';
|
|
3
|
+
import { useCallback, useEffect, useReducer, useRef } from 'react';
|
|
4
|
+
import ExpoAudioStreamModule from './ExpoAudioStreamModule';
|
|
5
|
+
import { addAudioAnalysisListener, addAudioEventListener, } from './events';
|
|
6
|
+
import { getLogger } from './logger';
|
|
7
|
+
const TAG = 'useAudioRecorder';
|
|
8
8
|
const logger = getLogger(TAG);
|
|
9
9
|
const defaultAnalysis = {
|
|
10
10
|
pointsPerSecond: 10,
|
|
@@ -14,6 +14,8 @@ const defaultAnalysis = {
|
|
|
14
14
|
sampleRate: 44100,
|
|
15
15
|
samples: 0,
|
|
16
16
|
dataPoints: [],
|
|
17
|
+
amplitudeAlgorithm: 'rms',
|
|
18
|
+
speakerChanges: [],
|
|
17
19
|
amplitudeRange: {
|
|
18
20
|
min: Number.POSITIVE_INFINITY,
|
|
19
21
|
max: Number.NEGATIVE_INFINITY,
|
|
@@ -21,7 +23,7 @@ const defaultAnalysis = {
|
|
|
21
23
|
};
|
|
22
24
|
function audioRecorderReducer(state, action) {
|
|
23
25
|
switch (action.type) {
|
|
24
|
-
case
|
|
26
|
+
case 'START':
|
|
25
27
|
return {
|
|
26
28
|
...state,
|
|
27
29
|
isRecording: true,
|
|
@@ -30,19 +32,19 @@ function audioRecorderReducer(state, action) {
|
|
|
30
32
|
size: 0,
|
|
31
33
|
analysisData: defaultAnalysis, // Reset analysis data
|
|
32
34
|
};
|
|
33
|
-
case
|
|
35
|
+
case 'STOP':
|
|
34
36
|
return { ...state, isRecording: false, isPaused: false };
|
|
35
|
-
case
|
|
37
|
+
case 'PAUSE':
|
|
36
38
|
return { ...state, isPaused: true, isRecording: false };
|
|
37
|
-
case
|
|
39
|
+
case 'RESUME':
|
|
38
40
|
return { ...state, isPaused: false, isRecording: true };
|
|
39
|
-
case
|
|
41
|
+
case 'UPDATE_STATUS':
|
|
40
42
|
return {
|
|
41
43
|
...state,
|
|
42
44
|
durationMs: action.payload.durationMs,
|
|
43
45
|
size: action.payload.size,
|
|
44
46
|
};
|
|
45
|
-
case
|
|
47
|
+
case 'UPDATE_ANALYSIS':
|
|
46
48
|
return {
|
|
47
49
|
...state,
|
|
48
50
|
analysisData: action.payload,
|
|
@@ -62,12 +64,14 @@ export function useAudioRecorder({ debug = false, audioWorkletUrl, featuresExtra
|
|
|
62
64
|
const analysisListenerRef = useRef(null);
|
|
63
65
|
const analysisRef = useRef({ ...defaultAnalysis });
|
|
64
66
|
// Instantiate the module for web with URLs
|
|
65
|
-
const ExpoAudioStream = Platform.OS ===
|
|
67
|
+
const ExpoAudioStream = Platform.OS === 'web'
|
|
66
68
|
? ExpoAudioStreamModule({ audioWorkletUrl, featuresExtratorUrl })
|
|
67
69
|
: ExpoAudioStreamModule;
|
|
68
70
|
const onAudioStreamRef = useRef(null);
|
|
69
|
-
const handleAudioAnalysis = useCallback(async ({ analysis, visualizationDuration }) => {
|
|
70
|
-
const savedAnalysisData = analysisRef.current || {
|
|
71
|
+
const handleAudioAnalysis = useCallback(async ({ analysis, visualizationDuration, }) => {
|
|
72
|
+
const savedAnalysisData = analysisRef.current || {
|
|
73
|
+
...defaultAnalysis,
|
|
74
|
+
};
|
|
71
75
|
const maxDuration = visualizationDuration;
|
|
72
76
|
logger.debug(`[handleAudioAnalysis] Received audio analysis: maxDuration=${maxDuration} analysis.dataPoints=${analysis.dataPoints.length} analysisData.dataPoints=${savedAnalysisData.dataPoints.length}`, analysis);
|
|
73
77
|
// Combine data points
|
|
@@ -100,7 +104,10 @@ export function useAudioRecorder({ debug = false, audioWorkletUrl, featuresExtra
|
|
|
100
104
|
analysisRef.current = savedAnalysisData;
|
|
101
105
|
// Dispatch the updated analysis data to state to trigger re-render
|
|
102
106
|
// need to use spread operator otherwise it doesnt trigger update.
|
|
103
|
-
dispatch({
|
|
107
|
+
dispatch({
|
|
108
|
+
type: 'UPDATE_ANALYSIS',
|
|
109
|
+
payload: { ...savedAnalysisData },
|
|
110
|
+
});
|
|
104
111
|
}, [dispatch]);
|
|
105
112
|
const handleAudioEvent = useCallback(async (eventData) => {
|
|
106
113
|
const { fileUri, deltaSize, totalSize, lastEmittedSize, position, streamUuid, encoded, mimeType, buffer, } = eventData;
|
|
@@ -120,11 +127,11 @@ export function useAudioRecorder({ debug = false, audioWorkletUrl, featuresExtra
|
|
|
120
127
|
}
|
|
121
128
|
try {
|
|
122
129
|
// Coming from native ( ios / android ) otherwise buffer is set
|
|
123
|
-
if (Platform.OS !==
|
|
130
|
+
if (Platform.OS !== 'web') {
|
|
124
131
|
// Read the audio file as a base64 string for comparison
|
|
125
132
|
if (!encoded) {
|
|
126
133
|
console.error(`${TAG} Encoded audio data is missing`);
|
|
127
|
-
throw new Error(
|
|
134
|
+
throw new Error('Encoded audio data is missing');
|
|
128
135
|
}
|
|
129
136
|
onAudioStreamRef.current?.({
|
|
130
137
|
data: encoded,
|
|
@@ -162,7 +169,7 @@ export function useAudioRecorder({ debug = false, audioWorkletUrl, featuresExtra
|
|
|
162
169
|
logger.debug(`Status:`, status);
|
|
163
170
|
}
|
|
164
171
|
dispatch({
|
|
165
|
-
type:
|
|
172
|
+
type: 'UPDATE_STATUS',
|
|
166
173
|
payload: { durationMs: status.durationMs, size: status.size },
|
|
167
174
|
});
|
|
168
175
|
}
|
|
@@ -176,7 +183,7 @@ export function useAudioRecorder({ debug = false, audioWorkletUrl, featuresExtra
|
|
|
176
183
|
const { onAudioStream, ...options } = recordingOptions;
|
|
177
184
|
const { enableProcessing } = options;
|
|
178
185
|
const maxRecentDataDuration = 10000; // TODO compute maxRecentDataDuration based on screen dimensions
|
|
179
|
-
if (typeof onAudioStream ===
|
|
186
|
+
if (typeof onAudioStream === 'function') {
|
|
180
187
|
onAudioStreamRef.current = onAudioStream;
|
|
181
188
|
}
|
|
182
189
|
else {
|
|
@@ -184,7 +191,7 @@ export function useAudioRecorder({ debug = false, audioWorkletUrl, featuresExtra
|
|
|
184
191
|
onAudioStreamRef.current = null;
|
|
185
192
|
}
|
|
186
193
|
const startResult = await ExpoAudioStream.startRecording(options);
|
|
187
|
-
dispatch({ type:
|
|
194
|
+
dispatch({ type: 'START' });
|
|
188
195
|
if (enableProcessing) {
|
|
189
196
|
logger.debug(`Enabling audio analysis listener`);
|
|
190
197
|
const listener = addAudioAnalysisListener(async (analysisData) => {
|
|
@@ -204,26 +211,27 @@ export function useAudioRecorder({ debug = false, audioWorkletUrl, featuresExtra
|
|
|
204
211
|
}, [handleAudioAnalysis, dispatch]);
|
|
205
212
|
const stopRecording = useCallback(async () => {
|
|
206
213
|
logger.debug(`stoping recording`);
|
|
214
|
+
const stopResult = await ExpoAudioStream.stopRecording();
|
|
215
|
+
stopResult.analysisData = analysisRef.current;
|
|
207
216
|
if (analysisListenerRef.current) {
|
|
208
217
|
analysisListenerRef.current.remove();
|
|
209
218
|
analysisListenerRef.current = null;
|
|
210
219
|
}
|
|
211
|
-
const stopResult = await ExpoAudioStream.stopRecording();
|
|
212
220
|
onAudioStreamRef.current = null;
|
|
213
221
|
logger.debug(`recording stopped`, stopResult);
|
|
214
|
-
dispatch({ type:
|
|
222
|
+
dispatch({ type: 'STOP' });
|
|
215
223
|
return stopResult;
|
|
216
224
|
}, [dispatch]);
|
|
217
225
|
const pauseRecording = useCallback(async () => {
|
|
218
226
|
logger.debug(`pause recording`);
|
|
219
227
|
const pauseResult = await ExpoAudioStream.pauseRecording();
|
|
220
|
-
dispatch({ type:
|
|
228
|
+
dispatch({ type: 'PAUSE' });
|
|
221
229
|
return pauseResult;
|
|
222
230
|
}, [dispatch]);
|
|
223
231
|
const resumeRecording = useCallback(async () => {
|
|
224
232
|
logger.debug(`resume recording`);
|
|
225
233
|
const resumeResult = await ExpoAudioStream.resumeRecording();
|
|
226
|
-
dispatch({ type:
|
|
234
|
+
dispatch({ type: 'RESUME' });
|
|
227
235
|
return resumeResult;
|
|
228
236
|
}, [dispatch]);
|
|
229
237
|
useEffect(() => {
|
|
@@ -248,14 +256,6 @@ export function useAudioRecorder({ debug = false, audioWorkletUrl, featuresExtra
|
|
|
248
256
|
subscribeAudio.remove();
|
|
249
257
|
};
|
|
250
258
|
}, [handleAudioEvent, handleAudioAnalysis]);
|
|
251
|
-
useEffect(() => {
|
|
252
|
-
if (debug) {
|
|
253
|
-
enableAllLoggers();
|
|
254
|
-
}
|
|
255
|
-
else {
|
|
256
|
-
disableAllLoggers();
|
|
257
|
-
}
|
|
258
|
-
}, [debug]);
|
|
259
259
|
return {
|
|
260
260
|
startRecording,
|
|
261
261
|
stopRecording,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAudioRecorder.js","sourceRoot":"","sources":["../src/useAudioRecorder.tsx"],"names":[],"mappings":"AAAA,0BAA0B;AAC1B,OAAO,EAAE,QAAQ,EAAgB,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAenE,OAAO,qBAAqB,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAC3E,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAG1E,MAAM,GAAG,GAAG,kBAAkB,CAAC;AAC/B,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;AAkD9B,MAAM,eAAe,GAAsB;IACzC,eAAe,EAAE,EAAE;IACnB,QAAQ,EAAE,EAAE;IACZ,gBAAgB,EAAE,CAAC;IACnB,UAAU,EAAE,CAAC;IACb,UAAU,EAAE,KAAK;IACjB,OAAO,EAAE,CAAC;IACV,UAAU,EAAE,EAAE;IACd,cAAc,EAAE;QACd,GAAG,EAAE,MAAM,CAAC,iBAAiB;QAC7B,GAAG,EAAE,MAAM,CAAC,iBAAiB;KAC9B;CACF,CAAC;AAEF,SAAS,oBAAoB,CAC3B,KAA2B,EAC3B,MAAsB;IAEtB,QAAQ,MAAM,CAAC,IAAI,EAAE,CAAC;QACpB,KAAK,OAAO;YACV,OAAO;gBACL,GAAG,KAAK;gBACR,WAAW,EAAE,IAAI;gBACjB,QAAQ,EAAE,KAAK;gBACf,UAAU,EAAE,CAAC;gBACb,IAAI,EAAE,CAAC;gBACP,YAAY,EAAE,eAAe,EAAE,sBAAsB;aACtD,CAAC;QACJ,KAAK,MAAM;YACT,OAAO,EAAE,GAAG,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;QAC3D,KAAK,OAAO;YACV,OAAO,EAAE,GAAG,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC;QAC1D,KAAK,QAAQ;YACX,OAAO,EAAE,GAAG,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;QAC1D,KAAK,eAAe;YAClB,OAAO;gBACL,GAAG,KAAK;gBACR,UAAU,EAAE,MAAM,CAAC,OAAO,CAAC,UAAU;gBACrC,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI;aAC1B,CAAC;QACJ,KAAK,iBAAiB;YACpB,OAAO;gBACL,GAAG,KAAK;gBACR,YAAY,EAAE,MAAM,CAAC,OAAO;aAC7B,CAAC;QACJ;YACE,OAAO,KAAK,CAAC;IACjB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,EAC/B,KAAK,GAAG,KAAK,EACb,eAAe,EACf,mBAAmB,MACM,EAAE;IAC3B,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,UAAU,CAAC,oBAAoB,EAAE;QACzD,WAAW,EAAE,KAAK;QAClB,QAAQ,EAAE,KAAK;QACf,UAAU,EAAE,CAAC;QACb,IAAI,EAAE,CAAC;QACP,YAAY,EAAE,SAAS;KACxB,CAAC,CAAC;IAEH,MAAM,mBAAmB,GAAG,MAAM,CAAsB,IAAI,CAAC,CAAC;IAC9D,MAAM,WAAW,GAAG,MAAM,CAAoB,EAAE,GAAG,eAAe,EAAE,CAAC,CAAC;IAEtE,2CAA2C;IAC3C,MAAM,eAAe,GACnB,QAAQ,CAAC,EAAE,KAAK,KAAK;QACnB,CAAC,CAAC,qBAAqB,CAAC,EAAE,eAAe,EAAE,mBAAmB,EAAE,CAAC;QACjE,CAAC,CAAC,qBAAqB,CAAC;IAE5B,MAAM,gBAAgB,GAAG,MAAM,CAE7B,IAAI,CAAC,CAAC;IAER,MAAM,mBAAmB,GAAG,WAAW,CACrC,KAAK,EAAE,EAAE,QAAQ,EAAE,qBAAqB,EAA6B,EAAE,EAAE;QACvE,MAAM,iBAAiB,GAAG,WAAW,CAAC,OAAO,IAAI,EAAE,GAAG,eAAe,EAAE,CAAC;QAExE,MAAM,WAAW,GAAG,qBAAqB,CAAC;QAE1C,MAAM,CAAC,KAAK,CACV,8DAA8D,WAAW,wBAAwB,QAAQ,CAAC,UAAU,CAAC,MAAM,4BAA4B,iBAAiB,CAAC,UAAU,CAAC,MAAM,EAAE,EAC5L,QAAQ,CACT,CAAC;QAEF,sBAAsB;QACtB,MAAM,kBAAkB,GAAG;YACzB,GAAG,iBAAiB,CAAC,UAAU;YAC/B,GAAG,QAAQ,CAAC,UAAU;SACvB,CAAC;QAEF,6BAA6B;QAC7B,MAAM,eAAe,GACnB,QAAQ,CAAC,eAAe,IAAI,iBAAiB,CAAC,eAAe,CAAC;QAChE,MAAM,aAAa,GAAG,CAAC,eAAe,GAAG,qBAAqB,CAAC,GAAG,IAAI,CAAC;QAEvE,MAAM,CAAC,KAAK,CACV,+EAA+E,eAAe,0BAA0B,qBAAqB,6BAA6B,kBAAkB,CAAC,MAAM,qBAAqB,aAAa,EAAE,CACxO,CAAC;QAEF,oEAAoE;QACpE,IAAI,kBAAkB,CAAC,MAAM,GAAG,aAAa,EAAE,CAAC;YAC9C,kBAAkB,CAAC,MAAM,CAAC,CAAC,EAAE,kBAAkB,CAAC,MAAM,GAAG,aAAa,CAAC,CAAC;QAC1E,CAAC;QAED,iBAAiB,CAAC,UAAU,GAAG,kBAAkB,CAAC;QAClD,iBAAiB,CAAC,QAAQ;YACxB,QAAQ,CAAC,QAAQ,IAAI,iBAAiB,CAAC,QAAQ,CAAC;QAClD,iBAAiB,CAAC,UAAU;YAC1B,kBAAkB,CAAC,MAAM,GAAG,CAAC,IAAI,GAAG,eAAe,CAAC,CAAC;QAEvD,yBAAyB;QACzB,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CACrB,iBAAiB,CAAC,cAAc,CAAC,GAAG,EACpC,QAAQ,CAAC,cAAc,CAAC,GAAG,CAC5B,CAAC;QACF,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CACrB,iBAAiB,CAAC,cAAc,CAAC,GAAG,EACpC,QAAQ,CAAC,cAAc,CAAC,GAAG,CAC5B,CAAC;QAEF,iBAAiB,CAAC,cAAc,GAAG;YACjC,GAAG,EAAE,MAAM;YACX,GAAG,EAAE,MAAM;SACZ,CAAC;QAEF,MAAM,CAAC,KAAK,CACV,2DAA2D,iBAAiB,CAAC,UAAU,EAAE,EACzF,iBAAiB,CAClB,CAAC;QAEF,iBAAiB;QACjB,WAAW,CAAC,OAAO,GAAG,iBAAiB,CAAC;QAExC,mEAAmE;QACnE,kEAAkE;QAClE,QAAQ,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,EAAE,GAAG,iBAAiB,EAAE,EAAE,CAAC,CAAC;IAC3E,CAAC,EACD,CAAC,QAAQ,CAAC,CACX,CAAC;IAEF,MAAM,gBAAgB,GAAG,WAAW,CAAC,KAAK,EAAE,SAA4B,EAAE,EAAE;QAC1E,MAAM,EACJ,OAAO,EACP,SAAS,EACT,SAAS,EACT,eAAe,EACf,QAAQ,EACR,UAAU,EACV,OAAO,EACP,QAAQ,EACR,MAAM,GACP,GAAG,SAAS,CAAC;QACd,MAAM,CAAC,KAAK,CAAC,0CAA0C,EAAE;YACvD,OAAO;YACP,SAAS;YACT,SAAS;YACT,QAAQ;YACR,QAAQ;YACR,eAAe;YACf,UAAU;YACV,aAAa,EAAE,OAAO,EAAE,MAAM;SAC/B,CAAC,CAAC;QACH,IAAI,SAAS,KAAK,CAAC,EAAE,CAAC;YACpB,6BAA6B;YAC7B,OAAO;QACT,CAAC;QACD,IAAI,CAAC;YACH,+DAA+D;YAC/D,IAAI,QAAQ,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;gBAC1B,wDAAwD;gBACxD,IAAI,CAAC,OAAO,EAAE,CAAC;oBACb,OAAO,CAAC,KAAK,CAAC,GAAG,GAAG,gCAAgC,CAAC,CAAC;oBACtD,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;gBACnD,CAAC;gBACD,gBAAgB,CAAC,OAAO,EAAE,CAAC;oBACzB,IAAI,EAAE,OAAO;oBACb,QAAQ;oBACR,OAAO;oBACP,aAAa,EAAE,SAAS;oBACxB,SAAS;iBACV,CAAC,CAAC;YACL,CAAC;iBAAM,IAAI,MAAM,EAAE,CAAC;gBAClB,kBAAkB;gBAClB,MAAM,QAAQ,GAAmB;oBAC/B,IAAI,EAAE,MAAM;oBACZ,QAAQ;oBACR,OAAO;oBACP,aAAa,EAAE,SAAS;oBACxB,SAAS;iBACV,CAAC;gBACF,gBAAgB,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAC;gBACrC,MAAM,CAAC,KAAK,CACV,qDAAqD,EACrD,QAAQ,CACT,CAAC;YACJ,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,GAAG,GAAG,gCAAgC,EAAE,KAAK,CAAC,CAAC;QAC/D,CAAC;IACH,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,WAAW,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;QACzC,IAAI,CAAC;YACH,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;gBACvB,MAAM,CAAC,KAAK,CAAC,sCAAsC,CAAC,CAAC;gBACrD,OAAO;YACT,CAAC;YAED,MAAM,MAAM,GAAsB,eAAe,CAAC,MAAM,EAAE,CAAC;YAC3D,IAAI,KAAK,EAAE,CAAC;gBACV,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;YAClC,CAAC;YAED,QAAQ,CAAC;gBACP,IAAI,EAAE,eAAe;gBACrB,OAAO,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE;aAC9D,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,GAAG,GAAG,wBAAwB,EAAE,KAAK,CAAC,CAAC;QACvD,CAAC;IACH,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC;IAExB,MAAM,cAAc,GAAG,WAAW,CAChC,KAAK,EAAE,gBAAiC,EAAE,EAAE;QAC1C,MAAM,CAAC,KAAK,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,CAAC;QAEjD,WAAW,CAAC,OAAO,GAAG,EAAE,GAAG,eAAe,EAAE,CAAC,CAAC,sBAAsB;QAEpE,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,EAAE,GAAG,gBAAgB,CAAC;QACvD,MAAM,EAAE,gBAAgB,EAAE,GAAG,OAAO,CAAC;QAErC,MAAM,qBAAqB,GAAG,KAAK,CAAC,CAAC,gEAAgE;QACrG,IAAI,OAAO,aAAa,KAAK,UAAU,EAAE,CAAC;YACxC,gBAAgB,CAAC,OAAO,GAAG,aAAa,CAAC;QAC3C,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,IAAI,CAAC,GAAG,GAAG,kCAAkC,EAAE,aAAa,CAAC,CAAC;YACtE,gBAAgB,CAAC,OAAO,GAAG,IAAI,CAAC;QAClC,CAAC;QACD,MAAM,WAAW,GACf,MAAM,eAAe,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QAChD,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QAE5B,IAAI,gBAAgB,EAAE,CAAC;YACrB,MAAM,CAAC,KAAK,CAAC,kCAAkC,CAAC,CAAC;YACjD,MAAM,QAAQ,GAAG,wBAAwB,CAAC,KAAK,EAAE,YAAY,EAAE,EAAE;gBAC/D,IAAI,CAAC;oBACH,MAAM,mBAAmB,CAAC;wBACxB,QAAQ,EAAE,YAAY;wBACtB,qBAAqB,EAAE,qBAAqB;qBAC7C,CAAC,CAAC;gBACL,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,OAAO,CAAC,IAAI,CAAC,GAAG,GAAG,mCAAmC,EAAE,KAAK,CAAC,CAAC;gBACjE,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,mBAAmB,CAAC,OAAO,GAAG,QAAQ,CAAC;QACzC,CAAC;QAED,OAAO,WAAW,CAAC;IACrB,CAAC,EACD,CAAC,mBAAmB,EAAE,QAAQ,CAAC,CAChC,CAAC;IAEF,MAAM,aAAa,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;QAC3C,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;QAElC,IAAI,mBAAmB,CAAC,OAAO,EAAE,CAAC;YAChC,mBAAmB,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YACrC,mBAAmB,CAAC,OAAO,GAAG,IAAI,CAAC;QACrC,CAAC;QAED,MAAM,UAAU,GACd,MAAM,eAAe,CAAC,aAAa,EAAE,CAAC;QACxC,gBAAgB,CAAC,OAAO,GAAG,IAAI,CAAC;QAChC,MAAM,CAAC,KAAK,CAAC,mBAAmB,EAAE,UAAU,CAAC,CAAC;QAC9C,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;QAC3B,OAAO,UAAU,CAAC;IACpB,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;IAEf,MAAM,cAAc,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;QAC5C,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;QAChC,MAAM,WAAW,GAAG,MAAM,eAAe,CAAC,cAAc,EAAE,CAAC;QAC3D,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QAC5B,OAAO,WAAW,CAAC;IACrB,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;IAEf,MAAM,eAAe,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;QAC7C,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;QACjC,MAAM,YAAY,GAAG,MAAM,eAAe,CAAC,eAAe,EAAE,CAAC;QAC7D,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC7B,OAAO,YAAY,CAAC;IACtB,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;IAEf,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,QAAuC,CAAC;QAC5C,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;YACtB,QAAQ,GAAG,WAAW,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;QAC5C,CAAC;QACD,OAAO,GAAG,EAAE;YACV,IAAI,QAAQ,EAAE,CAAC;gBACb,aAAa,CAAC,QAAQ,CAAC,CAAC;YAC1B,CAAC;QACH,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,WAAW,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC;IAErC,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,CAAC,KAAK,CAAC,kCAAkC,CAAC,CAAC;QACjD,MAAM,cAAc,GAAG,qBAAqB,CAAC,gBAAgB,CAAC,CAAC;QAE/D,MAAM,CAAC,KAAK,CAAC,0DAA0D,EAAE;YACvE,cAAc;SACf,CAAC,CAAC;QAEH,OAAO,GAAG,EAAE;YACV,MAAM,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC;YAC9C,cAAc,CAAC,MAAM,EAAE,CAAC;QAC1B,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,CAAC,CAAC;IAE5C,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,KAAK,EAAE,CAAC;YACV,gBAAgB,EAAE,CAAC;QACrB,CAAC;aAAM,CAAC;YACN,iBAAiB,EAAE,CAAC;QACtB,CAAC;IACH,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IAEZ,OAAO;QACL,cAAc;QACd,aAAa;QACb,cAAc;QACd,eAAe;QACf,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,YAAY,EAAE,KAAK,CAAC,YAAY;KACjC,CAAC;AACJ,CAAC","sourcesContent":["// src/useAudioRecorder.ts\nimport { Platform, Subscription } from \"expo-modules-core\";\nimport { useCallback, useEffect, useReducer, useRef } from \"react\";\n\nimport {\n AudioAnalysisData,\n AudioAnalysisEventPayload,\n AudioFeaturesOptions,\n} from \"./AudioAnalysis/AudioAnalysis.types\";\nimport {\n AudioDataEvent,\n AudioEventPayload,\n AudioRecordingResult,\n AudioStreamStatus,\n RecordingConfig,\n StartRecordingResult,\n} from \"./ExpoAudioStream.types\";\nimport ExpoAudioStreamModule from \"./ExpoAudioStreamModule\";\nimport { addAudioAnalysisListener, addAudioEventListener } from \"./events\";\nimport { disableAllLoggers, enableAllLoggers, getLogger } from \"./logger\";\nimport { WavFileInfo } from \"./utils/getWavFileInfo\";\n\nconst TAG = \"useAudioRecorder\";\nconst logger = getLogger(TAG);\n\nexport interface ExtractMetadataProps {\n fileUri?: string; // should provide either fileUri or arrayBuffer\n wavMetadata?: WavFileInfo;\n arrayBuffer?: ArrayBuffer;\n bitDepth?: number;\n skipWavHeader?: boolean;\n durationMs?: number;\n sampleRate?: number;\n numberOfChannels?: number;\n algorithm?: \"peak\" | \"rms\";\n position?: number; // Optional number of bytes to skip. Default is 0\n length?: number; // Optional number of bytes to read.\n pointsPerSecond?: number; // Optional number of points per second. Use to reduce the number of points and compute the number of datapoints to return.\n features?: AudioFeaturesOptions;\n featuresExtratorUrl?: string;\n}\n\nexport interface UseAudioRecorderProps {\n debug?: boolean;\n audioWorkletUrl?: string;\n featuresExtratorUrl?: string;\n}\n\nexport interface UseAudioRecorderState {\n startRecording: (_: RecordingConfig) => Promise<StartRecordingResult>;\n stopRecording: () => Promise<AudioRecordingResult | null>;\n pauseRecording: () => void;\n resumeRecording: () => void;\n isRecording: boolean;\n isPaused: boolean;\n durationMs: number; // Duration of the recording\n size: number; // Size in bytes of the recorded audio\n analysisData?: AudioAnalysisData;\n}\n\ninterface RecorderReducerState {\n isRecording: boolean;\n isPaused: boolean;\n durationMs: number;\n size: number;\n analysisData?: AudioAnalysisData;\n}\n\ntype RecorderAction =\n | { type: \"START\" | \"STOP\" | \"PAUSE\" | \"RESUME\" }\n | { type: \"UPDATE_STATUS\"; payload: { durationMs: number; size: number } }\n | { type: \"UPDATE_ANALYSIS\"; payload: AudioAnalysisData };\n\nconst defaultAnalysis: AudioAnalysisData = {\n pointsPerSecond: 10,\n bitDepth: 32,\n numberOfChannels: 1,\n durationMs: 0,\n sampleRate: 44100,\n samples: 0,\n dataPoints: [],\n amplitudeRange: {\n min: Number.POSITIVE_INFINITY,\n max: Number.NEGATIVE_INFINITY,\n },\n};\n\nfunction audioRecorderReducer(\n state: RecorderReducerState,\n action: RecorderAction,\n): RecorderReducerState {\n switch (action.type) {\n case \"START\":\n return {\n ...state,\n isRecording: true,\n isPaused: false,\n durationMs: 0,\n size: 0,\n analysisData: defaultAnalysis, // Reset analysis data\n };\n case \"STOP\":\n return { ...state, isRecording: false, isPaused: false };\n case \"PAUSE\":\n return { ...state, isPaused: true, isRecording: false };\n case \"RESUME\":\n return { ...state, isPaused: false, isRecording: true };\n case \"UPDATE_STATUS\":\n return {\n ...state,\n durationMs: action.payload.durationMs,\n size: action.payload.size,\n };\n case \"UPDATE_ANALYSIS\":\n return {\n ...state,\n analysisData: action.payload,\n };\n default:\n return state;\n }\n}\n\nexport function useAudioRecorder({\n debug = false,\n audioWorkletUrl,\n featuresExtratorUrl,\n}: UseAudioRecorderProps = {}): UseAudioRecorderState {\n const [state, dispatch] = useReducer(audioRecorderReducer, {\n isRecording: false,\n isPaused: false,\n durationMs: 0,\n size: 0,\n analysisData: undefined,\n });\n\n const analysisListenerRef = useRef<Subscription | null>(null);\n const analysisRef = useRef<AudioAnalysisData>({ ...defaultAnalysis });\n\n // Instantiate the module for web with URLs\n const ExpoAudioStream =\n Platform.OS === \"web\"\n ? ExpoAudioStreamModule({ audioWorkletUrl, featuresExtratorUrl })\n : ExpoAudioStreamModule;\n\n const onAudioStreamRef = useRef<\n ((_: AudioDataEvent) => Promise<void>) | null\n >(null);\n\n const handleAudioAnalysis = useCallback(\n async ({ analysis, visualizationDuration }: AudioAnalysisEventPayload) => {\n const savedAnalysisData = analysisRef.current || { ...defaultAnalysis };\n\n const maxDuration = visualizationDuration;\n\n logger.debug(\n `[handleAudioAnalysis] Received audio analysis: maxDuration=${maxDuration} analysis.dataPoints=${analysis.dataPoints.length} analysisData.dataPoints=${savedAnalysisData.dataPoints.length}`,\n analysis,\n );\n\n // Combine data points\n const combinedDataPoints = [\n ...savedAnalysisData.dataPoints,\n ...analysis.dataPoints,\n ];\n\n // Calculate the new duration\n const pointsPerSecond =\n analysis.pointsPerSecond || savedAnalysisData.pointsPerSecond;\n const maxDataPoints = (pointsPerSecond * visualizationDuration) / 1000;\n\n logger.debug(\n `[handleAudioAnalysis] Combined data points before trimming: pointsPerSecond=${pointsPerSecond} visualizationDuration=${visualizationDuration} combinedDataPointsLength=${combinedDataPoints.length} vs maxDataPoints=${maxDataPoints}`,\n );\n\n // Trim data points to keep within the maximum number of data points\n if (combinedDataPoints.length > maxDataPoints) {\n combinedDataPoints.splice(0, combinedDataPoints.length - maxDataPoints);\n }\n\n savedAnalysisData.dataPoints = combinedDataPoints;\n savedAnalysisData.bitDepth =\n analysis.bitDepth || savedAnalysisData.bitDepth;\n savedAnalysisData.durationMs =\n combinedDataPoints.length * (1000 / pointsPerSecond);\n\n // Update amplitude range\n const newMin = Math.min(\n savedAnalysisData.amplitudeRange.min,\n analysis.amplitudeRange.min,\n );\n const newMax = Math.max(\n savedAnalysisData.amplitudeRange.max,\n analysis.amplitudeRange.max,\n );\n\n savedAnalysisData.amplitudeRange = {\n min: newMin,\n max: newMax,\n };\n\n logger.debug(\n `[handleAudioAnalysis] Updated analysis data: durationMs=${savedAnalysisData.durationMs}`,\n savedAnalysisData,\n );\n\n // Update the ref\n analysisRef.current = savedAnalysisData;\n\n // Dispatch the updated analysis data to state to trigger re-render\n // need to use spread operator otherwise it doesnt trigger update.\n dispatch({ type: \"UPDATE_ANALYSIS\", payload: { ...savedAnalysisData } });\n },\n [dispatch],\n );\n\n const handleAudioEvent = useCallback(async (eventData: AudioEventPayload) => {\n const {\n fileUri,\n deltaSize,\n totalSize,\n lastEmittedSize,\n position,\n streamUuid,\n encoded,\n mimeType,\n buffer,\n } = eventData;\n logger.debug(`[handleAudioEvent] Received audio event:`, {\n fileUri,\n deltaSize,\n totalSize,\n position,\n mimeType,\n lastEmittedSize,\n streamUuid,\n encodedLength: encoded?.length,\n });\n if (deltaSize === 0) {\n // Ignore packet with no data\n return;\n }\n try {\n // Coming from native ( ios / android ) otherwise buffer is set\n if (Platform.OS !== \"web\") {\n // Read the audio file as a base64 string for comparison\n if (!encoded) {\n console.error(`${TAG} Encoded audio data is missing`);\n throw new Error(\"Encoded audio data is missing\");\n }\n onAudioStreamRef.current?.({\n data: encoded,\n position,\n fileUri,\n eventDataSize: deltaSize,\n totalSize,\n });\n } else if (buffer) {\n // Coming from web\n const webEvent: AudioDataEvent = {\n data: buffer,\n position,\n fileUri,\n eventDataSize: deltaSize,\n totalSize,\n };\n onAudioStreamRef.current?.(webEvent);\n logger.debug(\n `[handleAudioEvent] Audio data sent to onAudioStream`,\n webEvent,\n );\n }\n } catch (error) {\n console.error(`${TAG} Error processing audio event:`, error);\n }\n }, []);\n\n const checkStatus = useCallback(async () => {\n try {\n if (!state.isRecording) {\n logger.debug(`Not recording, exiting status check.`);\n return;\n }\n\n const status: AudioStreamStatus = ExpoAudioStream.status();\n if (debug) {\n logger.debug(`Status:`, status);\n }\n\n dispatch({\n type: \"UPDATE_STATUS\",\n payload: { durationMs: status.durationMs, size: status.size },\n });\n } catch (error) {\n console.error(`${TAG} Error getting status:`, error);\n }\n }, [state.isRecording]);\n\n const startRecording = useCallback(\n async (recordingOptions: RecordingConfig) => {\n logger.debug(`start recoding`, recordingOptions);\n\n analysisRef.current = { ...defaultAnalysis }; // Reset analysis data\n\n const { onAudioStream, ...options } = recordingOptions;\n const { enableProcessing } = options;\n\n const maxRecentDataDuration = 10000; // TODO compute maxRecentDataDuration based on screen dimensions\n if (typeof onAudioStream === \"function\") {\n onAudioStreamRef.current = onAudioStream;\n } else {\n console.warn(`${TAG} onAudioStream is not a function`, onAudioStream);\n onAudioStreamRef.current = null;\n }\n const startResult: StartRecordingResult =\n await ExpoAudioStream.startRecording(options);\n dispatch({ type: \"START\" });\n\n if (enableProcessing) {\n logger.debug(`Enabling audio analysis listener`);\n const listener = addAudioAnalysisListener(async (analysisData) => {\n try {\n await handleAudioAnalysis({\n analysis: analysisData,\n visualizationDuration: maxRecentDataDuration,\n });\n } catch (error) {\n console.warn(`${TAG} Error processing audio analysis:`, error);\n }\n });\n\n analysisListenerRef.current = listener;\n }\n\n return startResult;\n },\n [handleAudioAnalysis, dispatch],\n );\n\n const stopRecording = useCallback(async () => {\n logger.debug(`stoping recording`);\n\n if (analysisListenerRef.current) {\n analysisListenerRef.current.remove();\n analysisListenerRef.current = null;\n }\n\n const stopResult: AudioRecordingResult =\n await ExpoAudioStream.stopRecording();\n onAudioStreamRef.current = null;\n logger.debug(`recording stopped`, stopResult);\n dispatch({ type: \"STOP\" });\n return stopResult;\n }, [dispatch]);\n\n const pauseRecording = useCallback(async () => {\n logger.debug(`pause recording`);\n const pauseResult = await ExpoAudioStream.pauseRecording();\n dispatch({ type: \"PAUSE\" });\n return pauseResult;\n }, [dispatch]);\n\n const resumeRecording = useCallback(async () => {\n logger.debug(`resume recording`);\n const resumeResult = await ExpoAudioStream.resumeRecording();\n dispatch({ type: \"RESUME\" });\n return resumeResult;\n }, [dispatch]);\n\n useEffect(() => {\n let interval: ReturnType<typeof setTimeout>;\n if (state.isRecording) {\n interval = setInterval(checkStatus, 1000);\n }\n return () => {\n if (interval) {\n clearInterval(interval);\n }\n };\n }, [checkStatus, state.isRecording]);\n\n useEffect(() => {\n logger.debug(`Registering audio event listener`);\n const subscribeAudio = addAudioEventListener(handleAudioEvent);\n\n logger.debug(`Subscribed to audio event listener and analysis listener`, {\n subscribeAudio,\n });\n\n return () => {\n logger.debug(`Removing audio event listener`);\n subscribeAudio.remove();\n };\n }, [handleAudioEvent, handleAudioAnalysis]);\n\n useEffect(() => {\n if (debug) {\n enableAllLoggers();\n } else {\n disableAllLoggers();\n }\n }, [debug]);\n\n return {\n startRecording,\n stopRecording,\n pauseRecording,\n resumeRecording,\n isPaused: state.isPaused,\n isRecording: state.isRecording,\n durationMs: state.durationMs,\n size: state.size,\n analysisData: state.analysisData,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"useAudioRecorder.js","sourceRoot":"","sources":["../src/useAudioRecorder.tsx"],"names":[],"mappings":"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","sourcesContent":["// src/useAudioRecorder.ts\nimport { Platform, Subscription } from 'expo-modules-core'\nimport { useCallback, useEffect, useReducer, useRef } from 'react'\n\nimport { AudioAnalysis } from './AudioAnalysis/AudioAnalysis.types'\nimport {\n AudioDataEvent,\n AudioRecording,\n AudioStreamStatus,\n RecordingConfig,\n StartRecordingResult,\n} from './ExpoAudioStream.types'\nimport ExpoAudioStreamModule from './ExpoAudioStreamModule'\nimport {\n addAudioAnalysisListener,\n addAudioEventListener,\n AudioEventPayload,\n} from './events'\nimport { getLogger } from './logger'\n\nconst TAG = 'useAudioRecorder'\nconst logger = getLogger(TAG)\nexport interface UseAudioRecorderProps {\n debug?: boolean\n audioWorkletUrl?: string\n featuresExtratorUrl?: string\n}\n\nexport interface UseAudioRecorderState {\n startRecording: (_: RecordingConfig) => Promise<StartRecordingResult>\n stopRecording: () => Promise<AudioRecording>\n pauseRecording: () => void\n resumeRecording: () => void\n isRecording: boolean\n isPaused: boolean\n durationMs: number // Duration of the recording\n size: number // Size in bytes of the recorded audio\n analysisData?: AudioAnalysis\n}\n\ninterface RecorderReducerState {\n isRecording: boolean\n isPaused: boolean\n durationMs: number\n size: number\n analysisData?: AudioAnalysis\n}\n\ntype RecorderAction =\n | { type: 'START' | 'STOP' | 'PAUSE' | 'RESUME' }\n | { type: 'UPDATE_STATUS'; payload: { durationMs: number; size: number } }\n | { type: 'UPDATE_ANALYSIS'; payload: AudioAnalysis }\n\nconst defaultAnalysis: AudioAnalysis = {\n pointsPerSecond: 10,\n bitDepth: 32,\n numberOfChannels: 1,\n durationMs: 0,\n sampleRate: 44100,\n samples: 0,\n dataPoints: [],\n amplitudeAlgorithm: 'rms',\n speakerChanges: [],\n amplitudeRange: {\n min: Number.POSITIVE_INFINITY,\n max: Number.NEGATIVE_INFINITY,\n },\n}\n\nfunction audioRecorderReducer(\n state: RecorderReducerState,\n action: RecorderAction\n): RecorderReducerState {\n switch (action.type) {\n case 'START':\n return {\n ...state,\n isRecording: true,\n isPaused: false,\n durationMs: 0,\n size: 0,\n analysisData: defaultAnalysis, // Reset analysis data\n }\n case 'STOP':\n return { ...state, isRecording: false, isPaused: false }\n case 'PAUSE':\n return { ...state, isPaused: true, isRecording: false }\n case 'RESUME':\n return { ...state, isPaused: false, isRecording: true }\n case 'UPDATE_STATUS':\n return {\n ...state,\n durationMs: action.payload.durationMs,\n size: action.payload.size,\n }\n case 'UPDATE_ANALYSIS':\n return {\n ...state,\n analysisData: action.payload,\n }\n default:\n return state\n }\n}\n\ninterface HandleAudioAnalysisProps {\n analysis: AudioAnalysis\n visualizationDuration: number\n}\n\nexport function useAudioRecorder({\n debug = false,\n audioWorkletUrl,\n featuresExtratorUrl,\n}: UseAudioRecorderProps = {}): UseAudioRecorderState {\n const [state, dispatch] = useReducer(audioRecorderReducer, {\n isRecording: false,\n isPaused: false,\n durationMs: 0,\n size: 0,\n analysisData: undefined,\n })\n\n const analysisListenerRef = useRef<Subscription | null>(null)\n const analysisRef = useRef<AudioAnalysis>({ ...defaultAnalysis })\n\n // Instantiate the module for web with URLs\n const ExpoAudioStream =\n Platform.OS === 'web'\n ? ExpoAudioStreamModule({ audioWorkletUrl, featuresExtratorUrl })\n : ExpoAudioStreamModule\n\n const onAudioStreamRef = useRef<\n ((_: AudioDataEvent) => Promise<void>) | null\n >(null)\n\n const handleAudioAnalysis = useCallback(\n async ({\n analysis,\n visualizationDuration,\n }: HandleAudioAnalysisProps) => {\n const savedAnalysisData = analysisRef.current || {\n ...defaultAnalysis,\n }\n\n const maxDuration = visualizationDuration\n\n logger.debug(\n `[handleAudioAnalysis] Received audio analysis: maxDuration=${maxDuration} analysis.dataPoints=${analysis.dataPoints.length} analysisData.dataPoints=${savedAnalysisData.dataPoints.length}`,\n analysis\n )\n\n // Combine data points\n const combinedDataPoints = [\n ...savedAnalysisData.dataPoints,\n ...analysis.dataPoints,\n ]\n\n // Calculate the new duration\n const pointsPerSecond =\n analysis.pointsPerSecond || savedAnalysisData.pointsPerSecond\n const maxDataPoints =\n (pointsPerSecond * visualizationDuration) / 1000\n\n logger.debug(\n `[handleAudioAnalysis] Combined data points before trimming: pointsPerSecond=${pointsPerSecond} visualizationDuration=${visualizationDuration} combinedDataPointsLength=${combinedDataPoints.length} vs maxDataPoints=${maxDataPoints}`\n )\n\n // Trim data points to keep within the maximum number of data points\n if (combinedDataPoints.length > maxDataPoints) {\n combinedDataPoints.splice(\n 0,\n combinedDataPoints.length - maxDataPoints\n )\n }\n\n savedAnalysisData.dataPoints = combinedDataPoints\n savedAnalysisData.bitDepth =\n analysis.bitDepth || savedAnalysisData.bitDepth\n savedAnalysisData.durationMs =\n combinedDataPoints.length * (1000 / pointsPerSecond)\n\n // Update amplitude range\n const newMin = Math.min(\n savedAnalysisData.amplitudeRange.min,\n analysis.amplitudeRange.min\n )\n const newMax = Math.max(\n savedAnalysisData.amplitudeRange.max,\n analysis.amplitudeRange.max\n )\n\n savedAnalysisData.amplitudeRange = {\n min: newMin,\n max: newMax,\n }\n\n logger.debug(\n `[handleAudioAnalysis] Updated analysis data: durationMs=${savedAnalysisData.durationMs}`,\n savedAnalysisData\n )\n\n // Update the ref\n analysisRef.current = savedAnalysisData\n\n // Dispatch the updated analysis data to state to trigger re-render\n // need to use spread operator otherwise it doesnt trigger update.\n dispatch({\n type: 'UPDATE_ANALYSIS',\n payload: { ...savedAnalysisData },\n })\n },\n [dispatch]\n )\n\n const handleAudioEvent = useCallback(\n async (eventData: AudioEventPayload) => {\n const {\n fileUri,\n deltaSize,\n totalSize,\n lastEmittedSize,\n position,\n streamUuid,\n encoded,\n mimeType,\n buffer,\n } = eventData\n logger.debug(`[handleAudioEvent] Received audio event:`, {\n fileUri,\n deltaSize,\n totalSize,\n position,\n mimeType,\n lastEmittedSize,\n streamUuid,\n encodedLength: encoded?.length,\n })\n if (deltaSize === 0) {\n // Ignore packet with no data\n return\n }\n try {\n // Coming from native ( ios / android ) otherwise buffer is set\n if (Platform.OS !== 'web') {\n // Read the audio file as a base64 string for comparison\n if (!encoded) {\n console.error(`${TAG} Encoded audio data is missing`)\n throw new Error('Encoded audio data is missing')\n }\n onAudioStreamRef.current?.({\n data: encoded,\n position,\n fileUri,\n eventDataSize: deltaSize,\n totalSize,\n })\n } else if (buffer) {\n // Coming from web\n const webEvent: AudioDataEvent = {\n data: buffer,\n position,\n fileUri,\n eventDataSize: deltaSize,\n totalSize,\n }\n onAudioStreamRef.current?.(webEvent)\n logger.debug(\n `[handleAudioEvent] Audio data sent to onAudioStream`,\n webEvent\n )\n }\n } catch (error) {\n console.error(`${TAG} Error processing audio event:`, error)\n }\n },\n []\n )\n\n const checkStatus = useCallback(async () => {\n try {\n if (!state.isRecording) {\n logger.debug(`Not recording, exiting status check.`)\n return\n }\n\n const status: AudioStreamStatus = ExpoAudioStream.status()\n if (debug) {\n logger.debug(`Status:`, status)\n }\n\n dispatch({\n type: 'UPDATE_STATUS',\n payload: { durationMs: status.durationMs, size: status.size },\n })\n } catch (error) {\n console.error(`${TAG} Error getting status:`, error)\n }\n }, [state.isRecording])\n\n const startRecording = useCallback(\n async (recordingOptions: RecordingConfig) => {\n logger.debug(`start recoding`, recordingOptions)\n\n analysisRef.current = { ...defaultAnalysis } // Reset analysis data\n\n const { onAudioStream, ...options } = recordingOptions\n const { enableProcessing } = options\n\n const maxRecentDataDuration = 10000 // TODO compute maxRecentDataDuration based on screen dimensions\n if (typeof onAudioStream === 'function') {\n onAudioStreamRef.current = onAudioStream\n } else {\n console.warn(\n `${TAG} onAudioStream is not a function`,\n onAudioStream\n )\n onAudioStreamRef.current = null\n }\n const startResult: StartRecordingResult =\n await ExpoAudioStream.startRecording(options)\n dispatch({ type: 'START' })\n\n if (enableProcessing) {\n logger.debug(`Enabling audio analysis listener`)\n const listener = addAudioAnalysisListener(\n async (analysisData) => {\n try {\n await handleAudioAnalysis({\n analysis: analysisData,\n visualizationDuration: maxRecentDataDuration,\n })\n } catch (error) {\n console.warn(\n `${TAG} Error processing audio analysis:`,\n error\n )\n }\n }\n )\n\n analysisListenerRef.current = listener\n }\n\n return startResult\n },\n [handleAudioAnalysis, dispatch]\n )\n\n const stopRecording = useCallback(async () => {\n logger.debug(`stoping recording`)\n\n const stopResult: AudioRecording = await ExpoAudioStream.stopRecording()\n stopResult.analysisData = analysisRef.current\n\n if (analysisListenerRef.current) {\n analysisListenerRef.current.remove()\n analysisListenerRef.current = null\n }\n onAudioStreamRef.current = null\n logger.debug(`recording stopped`, stopResult)\n dispatch({ type: 'STOP' })\n return stopResult\n }, [dispatch])\n\n const pauseRecording = useCallback(async () => {\n logger.debug(`pause recording`)\n const pauseResult = await ExpoAudioStream.pauseRecording()\n dispatch({ type: 'PAUSE' })\n return pauseResult\n }, [dispatch])\n\n const resumeRecording = useCallback(async () => {\n logger.debug(`resume recording`)\n const resumeResult = await ExpoAudioStream.resumeRecording()\n dispatch({ type: 'RESUME' })\n return resumeResult\n }, [dispatch])\n\n useEffect(() => {\n let interval: ReturnType<typeof setTimeout>\n if (state.isRecording) {\n interval = setInterval(checkStatus, 1000)\n }\n return () => {\n if (interval) {\n clearInterval(interval)\n }\n }\n }, [checkStatus, state.isRecording])\n\n useEffect(() => {\n logger.debug(`Registering audio event listener`)\n const subscribeAudio = addAudioEventListener(handleAudioEvent)\n\n logger.debug(\n `Subscribed to audio event listener and analysis listener`,\n {\n subscribeAudio,\n }\n )\n\n return () => {\n logger.debug(`Removing audio event listener`)\n subscribeAudio.remove()\n }\n }, [handleAudioEvent, handleAudioAnalysis])\n\n return {\n startRecording,\n stopRecording,\n pauseRecording,\n resumeRecording,\n isPaused: state.isPaused,\n isRecording: state.isRecording,\n durationMs: state.durationMs,\n size: state.size,\n analysisData: state.analysisData,\n }\n}\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fixes duration on MediaRecorder output.
|
|
3
|
+
* @param blob Input Blob with incorrect duration.
|
|
4
|
+
* @param duration Correct duration (in milliseconds).
|
|
5
|
+
* @param type Output blob mimetype (default: video/webm).
|
|
6
|
+
* @returns
|
|
7
|
+
*/
|
|
8
|
+
export declare const webmFixDuration: (blob: Blob, duration: number, type?: string) => Promise<Blob>;
|
|
9
|
+
//# sourceMappingURL=BlobFix.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BlobFix.d.ts","sourceRoot":"","sources":["../../src/utils/BlobFix.ts"],"names":[],"mappings":"AAggBA;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,SAClB,IAAI,YACA,MAAM,oBAEjB,OAAO,CAAC,IAAI,CA0Bd,CAAC"}
|