@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/WebRecorder.web.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { getLogger } from
|
|
2
|
-
import { encodingToBitDepth } from
|
|
3
|
-
import { InlineFeaturesExtractor } from
|
|
4
|
-
import { InlineAudioWebWorker } from
|
|
1
|
+
import { getLogger } from './logger';
|
|
2
|
+
import { encodingToBitDepth } from './utils/encodingToBitDepth';
|
|
3
|
+
import { InlineFeaturesExtractor } from './workers/InlineFeaturesExtractor.web';
|
|
4
|
+
import { InlineAudioWebWorker } from './workers/inlineAudioWebWorker.web';
|
|
5
5
|
const DEFAULT_WEB_BITDEPTH = 32;
|
|
6
6
|
const DEFAULT_WEB_POINTS_PER_SECOND = 10;
|
|
7
7
|
const DEFAULT_WEB_INTERVAL = 500;
|
|
8
8
|
const DEFAULT_WEB_NUMBER_OF_CHANNELS = 1;
|
|
9
|
-
const
|
|
9
|
+
const DEFAULT_ALGORITHM = 'rms';
|
|
10
|
+
const TAG = 'WebRecorder';
|
|
10
11
|
const logger = getLogger(TAG);
|
|
11
12
|
export class WebRecorder {
|
|
12
13
|
audioContext;
|
|
@@ -21,9 +22,10 @@ export class WebRecorder {
|
|
|
21
22
|
numberOfChannels; // Number of audio channels
|
|
22
23
|
bitDepth; // Bit depth of the audio
|
|
23
24
|
exportBitDepth; // Bit depth of the audio
|
|
24
|
-
|
|
25
|
+
buffer; // Single buffer to store the audio data
|
|
26
|
+
bufferSize; // Keep track of the buffer size
|
|
25
27
|
audioAnalysisData; // Keep updating the full audio analysis data with latest events
|
|
26
|
-
constructor({ audioContext, source, recordingConfig,
|
|
28
|
+
constructor({ audioContext, source, recordingConfig, audioWorkletUrl, emitAudioEventCallback, emitAudioAnalysisCallback, }) {
|
|
27
29
|
this.audioContext = audioContext;
|
|
28
30
|
this.source = source;
|
|
29
31
|
this.audioWorkletUrl = audioWorkletUrl;
|
|
@@ -31,21 +33,23 @@ export class WebRecorder {
|
|
|
31
33
|
this.emitAudioAnalysisCallback = emitAudioAnalysisCallback;
|
|
32
34
|
this.config = recordingConfig;
|
|
33
35
|
this.position = 0;
|
|
34
|
-
this.
|
|
36
|
+
this.bufferSize = 0;
|
|
37
|
+
this.buffer = new Float32Array(0); // Initialize the buffer
|
|
35
38
|
const audioContextFormat = this.checkAudioContextFormat({
|
|
36
39
|
sampleRate: this.audioContext.sampleRate,
|
|
37
40
|
});
|
|
38
|
-
logger.debug(
|
|
41
|
+
logger.debug('Initialized WebRecorder with config:', {
|
|
39
42
|
sampleRate: audioContextFormat.sampleRate,
|
|
40
43
|
bitDepth: audioContextFormat.bitDepth,
|
|
41
44
|
numberOfChannels: audioContextFormat.numberOfChannels,
|
|
42
45
|
});
|
|
43
46
|
this.bitDepth = audioContextFormat.bitDepth;
|
|
44
47
|
this.numberOfChannels =
|
|
45
|
-
audioContextFormat.numberOfChannels ||
|
|
48
|
+
audioContextFormat.numberOfChannels ||
|
|
49
|
+
DEFAULT_WEB_NUMBER_OF_CHANNELS; // Default to 1 if not available
|
|
46
50
|
this.exportBitDepth =
|
|
47
51
|
encodingToBitDepth({
|
|
48
|
-
encoding: recordingConfig.encoding ??
|
|
52
|
+
encoding: recordingConfig.encoding ?? 'pcm_32bit',
|
|
49
53
|
}) ||
|
|
50
54
|
audioContextFormat.bitDepth ||
|
|
51
55
|
DEFAULT_WEB_BITDEPTH;
|
|
@@ -54,6 +58,7 @@ export class WebRecorder {
|
|
|
54
58
|
dataPoints: [],
|
|
55
59
|
durationMs: 0,
|
|
56
60
|
samples: 0,
|
|
61
|
+
amplitudeAlgorithm: recordingConfig.algorithm || DEFAULT_ALGORITHM,
|
|
57
62
|
bitDepth: this.bitDepth,
|
|
58
63
|
numberOfChannels: this.numberOfChannels,
|
|
59
64
|
sampleRate: this.config.sampleRate || this.audioContext.sampleRate,
|
|
@@ -68,7 +73,7 @@ export class WebRecorder {
|
|
|
68
73
|
try {
|
|
69
74
|
if (!this.audioWorkletUrl) {
|
|
70
75
|
const blob = new Blob([InlineAudioWebWorker], {
|
|
71
|
-
type:
|
|
76
|
+
type: 'application/javascript',
|
|
72
77
|
});
|
|
73
78
|
const url = URL.createObjectURL(blob);
|
|
74
79
|
await this.audioContext.audioWorklet.addModule(url);
|
|
@@ -76,39 +81,38 @@ export class WebRecorder {
|
|
|
76
81
|
else {
|
|
77
82
|
await this.audioContext.audioWorklet.addModule(this.audioWorkletUrl);
|
|
78
83
|
}
|
|
79
|
-
this.audioWorkletNode = new AudioWorkletNode(this.audioContext,
|
|
84
|
+
this.audioWorkletNode = new AudioWorkletNode(this.audioContext, 'recorder-processor');
|
|
80
85
|
this.audioWorkletNode.port.onmessage = async (event) => {
|
|
81
86
|
const command = event.data.command;
|
|
82
|
-
if (command !==
|
|
87
|
+
if (command !== 'newData') {
|
|
83
88
|
return;
|
|
84
89
|
}
|
|
85
90
|
// Handle the audio blob (e.g., send it to the server or process it further)
|
|
86
|
-
logger.debug(
|
|
87
|
-
const
|
|
88
|
-
if (!
|
|
91
|
+
logger.debug('Received audio blob from processor', event);
|
|
92
|
+
const pcmBufferFloat = event.data.recordedData;
|
|
93
|
+
if (!pcmBufferFloat) {
|
|
89
94
|
return;
|
|
90
95
|
}
|
|
91
|
-
|
|
96
|
+
// Concatenate the incoming Float32Array to the existing buffer
|
|
97
|
+
const newBuffer = new Float32Array(this.bufferSize + pcmBufferFloat.length);
|
|
98
|
+
newBuffer.set(this.buffer, 0);
|
|
99
|
+
newBuffer.set(pcmBufferFloat, this.bufferSize);
|
|
100
|
+
this.buffer = newBuffer;
|
|
101
|
+
this.bufferSize += pcmBufferFloat.length;
|
|
92
102
|
const sampleRate = event.data.sampleRate ?? this.audioContext.sampleRate;
|
|
93
|
-
const
|
|
94
|
-
// Pass the intermediary buffer to the feature extractor worker
|
|
95
|
-
const pcmBufferCopy = pcmBuffer.slice(0);
|
|
96
|
-
const channelData = new Float32Array(pcmBufferCopy);
|
|
97
|
-
const duration = channelData.length / sampleRate; // Calculate duration of the current buffer
|
|
98
|
-
const otherDuration = pcmBuffer.byteLength /
|
|
99
|
-
(otherSampleRate * (this.exportBitDepth / this.numberOfChannels)); // Calculate duration of the current buffer
|
|
100
|
-
logger.debug(`sampleRate=${sampleRate} Duration: ${duration} -- otherSampleRate=${otherSampleRate} Other duration: ${otherDuration}`);
|
|
103
|
+
const duration = pcmBufferFloat.length / sampleRate; // Calculate duration of the current buffer
|
|
101
104
|
this.emitAudioEventCallback({
|
|
102
|
-
data:
|
|
105
|
+
data: pcmBufferFloat,
|
|
103
106
|
position: this.position,
|
|
104
107
|
});
|
|
105
108
|
this.position += duration; // Update position
|
|
106
109
|
this.featureExtractorWorker?.postMessage({
|
|
107
|
-
command:
|
|
108
|
-
channelData,
|
|
109
|
-
sampleRate
|
|
110
|
-
pointsPerSecond: this.config.pointsPerSecond ||
|
|
111
|
-
|
|
110
|
+
command: 'process',
|
|
111
|
+
channelData: pcmBufferFloat,
|
|
112
|
+
sampleRate,
|
|
113
|
+
pointsPerSecond: this.config.pointsPerSecond ||
|
|
114
|
+
DEFAULT_WEB_POINTS_PER_SECOND,
|
|
115
|
+
algorithm: this.config.algorithm || 'rms',
|
|
112
116
|
bitDepth: this.bitDepth,
|
|
113
117
|
fullAudioDurationMs: this.position * 1000,
|
|
114
118
|
numberOfChannels: this.numberOfChannels,
|
|
@@ -117,7 +121,7 @@ export class WebRecorder {
|
|
|
117
121
|
};
|
|
118
122
|
logger.debug(`WebRecorder initialized -- recordSampleRate=${this.audioContext.sampleRate}`, this.config);
|
|
119
123
|
this.audioWorkletNode.port.postMessage({
|
|
120
|
-
command:
|
|
124
|
+
command: 'init',
|
|
121
125
|
recordSampleRate: this.audioContext.sampleRate, // Pass the original sample rate
|
|
122
126
|
exportSampleRate: this.config.sampleRate ?? this.audioContext.sampleRate,
|
|
123
127
|
bitDepth: this.bitDepth,
|
|
@@ -142,7 +146,8 @@ export class WebRecorder {
|
|
|
142
146
|
this.featureExtractorWorker = new Worker(new URL(featuresExtratorUrl, window.location.href));
|
|
143
147
|
this.featureExtractorWorker.onmessage =
|
|
144
148
|
this.handleFeatureExtractorMessage.bind(this);
|
|
145
|
-
this.featureExtractorWorker.onerror =
|
|
149
|
+
this.featureExtractorWorker.onerror =
|
|
150
|
+
this.handleWorkerError.bind(this);
|
|
146
151
|
}
|
|
147
152
|
else {
|
|
148
153
|
// Fallback to the inline worker if the URL is not provided
|
|
@@ -157,7 +162,7 @@ export class WebRecorder {
|
|
|
157
162
|
initFallbackWorker() {
|
|
158
163
|
try {
|
|
159
164
|
const blob = new Blob([InlineFeaturesExtractor], {
|
|
160
|
-
type:
|
|
165
|
+
type: 'application/javascript',
|
|
161
166
|
});
|
|
162
167
|
const url = URL.createObjectURL(blob);
|
|
163
168
|
this.featureExtractorWorker = new Worker(url);
|
|
@@ -166,7 +171,7 @@ export class WebRecorder {
|
|
|
166
171
|
this.featureExtractorWorker.onerror = (error) => {
|
|
167
172
|
console.error(`[${TAG}] Default Inline worker failed`, error);
|
|
168
173
|
};
|
|
169
|
-
logger.log(
|
|
174
|
+
logger.log('Inline worker initialized successfully');
|
|
170
175
|
}
|
|
171
176
|
catch (error) {
|
|
172
177
|
console.error(`[${TAG}] Failed to initialize Inline Feature Extractor worker`, error);
|
|
@@ -176,7 +181,7 @@ export class WebRecorder {
|
|
|
176
181
|
console.error(`[${TAG}] Feature extractor worker error:`, error);
|
|
177
182
|
}
|
|
178
183
|
handleFeatureExtractorMessage(event) {
|
|
179
|
-
if (event.data.command ===
|
|
184
|
+
if (event.data.command === 'features') {
|
|
180
185
|
const segmentResult = event.data.result;
|
|
181
186
|
// Merge the segment result with the full audio analysis data
|
|
182
187
|
this.audioAnalysisData.dataPoints.push(...segmentResult.dataPoints);
|
|
@@ -189,8 +194,8 @@ export class WebRecorder {
|
|
|
189
194
|
};
|
|
190
195
|
}
|
|
191
196
|
// Handle the extracted features (e.g., emit an event or log them)
|
|
192
|
-
logger.debug(
|
|
193
|
-
logger.debug(
|
|
197
|
+
logger.debug('features event segmentResult', segmentResult);
|
|
198
|
+
logger.debug('features event audioAnalysisData', this.audioAnalysisData);
|
|
194
199
|
this.emitAudioAnalysisCallback(segmentResult);
|
|
195
200
|
}
|
|
196
201
|
}
|
|
@@ -204,30 +209,35 @@ export class WebRecorder {
|
|
|
204
209
|
if (this.audioWorkletNode) {
|
|
205
210
|
// this.source.disconnect(this.audioWorkletNode);
|
|
206
211
|
// this.audioWorkletNode.disconnect(this.audioContext.destination);
|
|
207
|
-
this.audioWorkletNode.port.postMessage({ command:
|
|
212
|
+
this.audioWorkletNode.port.postMessage({ command: 'stop' });
|
|
208
213
|
// Set a timeout to reject the promise if no message is received within 5 seconds
|
|
209
214
|
const timeout = setTimeout(() => {
|
|
210
|
-
this.audioWorkletNode.port.removeEventListener(
|
|
215
|
+
this.audioWorkletNode.port.removeEventListener('message', onMessage);
|
|
211
216
|
reject(new Error("Timeout error, audioWorkletNode didn't complete."));
|
|
212
217
|
}, 5000);
|
|
213
218
|
// Listen for the recordedData message to confirm stopping
|
|
214
219
|
const onMessage = async (event) => {
|
|
215
220
|
const command = event.data.command;
|
|
216
|
-
if (command ===
|
|
221
|
+
if (command === 'recordedData') {
|
|
217
222
|
clearTimeout(timeout); // Clear the timeout
|
|
218
223
|
const rawPCMDataFull = event.data.recordedData?.slice(0);
|
|
224
|
+
if (!rawPCMDataFull) {
|
|
225
|
+
reject(new Error('Failed to get recorded data'));
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
219
228
|
// Compute duration of the recorded data
|
|
220
229
|
const duration = rawPCMDataFull.byteLength /
|
|
221
230
|
(this.audioContext.sampleRate *
|
|
222
|
-
(this.exportBitDepth /
|
|
231
|
+
(this.exportBitDepth /
|
|
232
|
+
this.numberOfChannels));
|
|
223
233
|
logger.debug(`Received recorded data -- Duration: ${duration} vs ${rawPCMDataFull.byteLength / this.audioContext.sampleRate} seconds`);
|
|
224
|
-
logger.debug(`recordedData.length=${rawPCMDataFull.byteLength} vs transmittedData.length=${this.
|
|
234
|
+
logger.debug(`recordedData.length=${rawPCMDataFull.byteLength} vs transmittedData.length=${this.bufferSize}`);
|
|
225
235
|
// Remove the event listener after receiving the final data
|
|
226
|
-
this.audioWorkletNode.port.removeEventListener(
|
|
227
|
-
resolve(this.
|
|
236
|
+
this.audioWorkletNode.port.removeEventListener('message', onMessage);
|
|
237
|
+
resolve(this.buffer); // Resolve the promise with the collected buffers
|
|
228
238
|
}
|
|
229
239
|
};
|
|
230
|
-
this.audioWorkletNode.port.addEventListener(
|
|
240
|
+
this.audioWorkletNode.port.addEventListener('message', onMessage);
|
|
231
241
|
}
|
|
232
242
|
// Stop all media stream tracks to stop the browser recording
|
|
233
243
|
this.stopMediaStreamTracks();
|
|
@@ -240,7 +250,7 @@ export class WebRecorder {
|
|
|
240
250
|
pause() {
|
|
241
251
|
this.source.disconnect(this.audioWorkletNode); // Disconnect the source from the AudioWorkletNode
|
|
242
252
|
this.audioWorkletNode.disconnect(this.audioContext.destination); // Disconnect the AudioWorkletNode from the destination
|
|
243
|
-
this.audioWorkletNode.port.postMessage({ command:
|
|
253
|
+
this.audioWorkletNode.port.postMessage({ command: 'pause' });
|
|
244
254
|
}
|
|
245
255
|
stopMediaStreamTracks() {
|
|
246
256
|
// Stop all audio tracks to stop the recording icon
|
|
@@ -260,7 +270,7 @@ export class WebRecorder {
|
|
|
260
270
|
bufferSource.buffer = audioBuffer;
|
|
261
271
|
bufferSource.connect(this.audioContext.destination);
|
|
262
272
|
bufferSource.start();
|
|
263
|
-
logger.debug(
|
|
273
|
+
logger.debug('Playing recorded data', recordedData);
|
|
264
274
|
}
|
|
265
275
|
catch (error) {
|
|
266
276
|
console.error(`[${TAG}] Failed to play recorded data:`, error);
|
|
@@ -282,7 +292,7 @@ export class WebRecorder {
|
|
|
282
292
|
resume() {
|
|
283
293
|
this.source.connect(this.audioWorkletNode);
|
|
284
294
|
this.audioWorkletNode.connect(this.audioContext.destination);
|
|
285
|
-
this.audioWorkletNode.port.postMessage({ command:
|
|
295
|
+
this.audioWorkletNode.port.postMessage({ command: 'resume' });
|
|
286
296
|
}
|
|
287
297
|
}
|
|
288
298
|
//# sourceMappingURL=WebRecorder.web.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WebRecorder.web.js","sourceRoot":"","sources":["../src/WebRecorder.web.ts"],"names":[],"mappings":"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","sourcesContent":["// src/WebRecorder.ts\nimport { AudioAnalysisData } from \"./AudioAnalysis/AudioAnalysis.types\";\nimport { RecordingConfig } from \"./ExpoAudioStream.types\";\nimport {\n EmitAudioAnalysisFunction,\n EmitAudioEventFunction,\n} from \"./ExpoAudioStream.web\";\nimport { getLogger } from \"./logger\";\nimport { encodingToBitDepth } from \"./utils/encodingToBitDepth\";\nimport { InlineFeaturesExtractor } from \"./workers/InlineFeaturesExtractor.web\";\nimport { InlineAudioWebWorker } from \"./workers/inlineAudioWebWorker.web\";\n\ninterface AudioWorkletEvent {\n data: {\n command: string;\n recordedData?: ArrayBuffer;\n sampleRate?: number;\n };\n}\n\ninterface AudioFeaturesEvent {\n data: {\n command: string;\n result: AudioAnalysisData;\n };\n}\n\nconst DEFAULT_WEB_BITDEPTH = 32;\nconst DEFAULT_WEB_POINTS_PER_SECOND = 10;\nconst DEFAULT_WEB_INTERVAL = 500;\nconst DEFAULT_WEB_NUMBER_OF_CHANNELS = 1;\n\nconst TAG = \"WebRecorder\";\nconst logger = getLogger(TAG);\n\nexport class WebRecorder {\n private audioContext: AudioContext;\n private audioWorkletNode!: AudioWorkletNode;\n private featureExtractorWorker?: Worker;\n private source: MediaStreamAudioSourceNode;\n private audioWorkletUrl: string;\n private emitAudioEventCallback: EmitAudioEventFunction;\n private emitAudioAnalysisCallback: EmitAudioAnalysisFunction;\n private config: RecordingConfig;\n private position: number; // Track the cumulative position\n private numberOfChannels: number; // Number of audio channels\n private bitDepth: number; // Bit depth of the audio\n private exportBitDepth: number; // Bit depth of the audio\n private buffers: ArrayBuffer[]; // Array to store the buffers\n private audioAnalysisData: AudioAnalysisData; // Keep updating the full audio analysis data with latest events\n\n constructor({\n audioContext,\n source,\n recordingConfig,\n featuresExtratorUrl,\n audioWorkletUrl,\n emitAudioEventCallback,\n emitAudioAnalysisCallback,\n }: {\n audioContext: AudioContext;\n source: MediaStreamAudioSourceNode;\n recordingConfig: RecordingConfig;\n featuresExtratorUrl: string;\n audioWorkletUrl: string;\n emitAudioEventCallback: EmitAudioEventFunction;\n emitAudioAnalysisCallback: EmitAudioAnalysisFunction;\n }) {\n this.audioContext = audioContext;\n this.source = source;\n this.audioWorkletUrl = audioWorkletUrl;\n this.emitAudioEventCallback = emitAudioEventCallback;\n this.emitAudioAnalysisCallback = emitAudioAnalysisCallback;\n this.config = recordingConfig;\n this.position = 0;\n this.buffers = []; // Initialize the buffers array\n\n const audioContextFormat = this.checkAudioContextFormat({\n sampleRate: this.audioContext.sampleRate,\n });\n logger.debug(\"Initialized WebRecorder with config:\", {\n sampleRate: audioContextFormat.sampleRate,\n bitDepth: audioContextFormat.bitDepth,\n numberOfChannels: audioContextFormat.numberOfChannels,\n });\n\n this.bitDepth = audioContextFormat.bitDepth;\n this.numberOfChannels =\n audioContextFormat.numberOfChannels || DEFAULT_WEB_NUMBER_OF_CHANNELS; // Default to 1 if not available\n this.exportBitDepth =\n encodingToBitDepth({\n encoding: recordingConfig.encoding ?? \"pcm_32bit\",\n }) ||\n audioContextFormat.bitDepth ||\n DEFAULT_WEB_BITDEPTH;\n\n this.audioAnalysisData = {\n amplitudeRange: { min: 0, max: 0 },\n dataPoints: [],\n durationMs: 0,\n samples: 0,\n bitDepth: this.bitDepth,\n numberOfChannels: this.numberOfChannels,\n sampleRate: this.config.sampleRate || this.audioContext.sampleRate,\n pointsPerSecond:\n this.config.pointsPerSecond || DEFAULT_WEB_POINTS_PER_SECOND,\n speakerChanges: [],\n };\n\n if (recordingConfig.enableProcessing) {\n this.initFeatureExtractorWorker();\n }\n }\n\n async init() {\n try {\n if (!this.audioWorkletUrl) {\n const blob = new Blob([InlineAudioWebWorker], {\n type: \"application/javascript\",\n });\n const url = URL.createObjectURL(blob);\n await this.audioContext.audioWorklet.addModule(url);\n } else {\n await this.audioContext.audioWorklet.addModule(this.audioWorkletUrl);\n }\n this.audioWorkletNode = new AudioWorkletNode(\n this.audioContext,\n \"recorder-processor\",\n );\n\n this.audioWorkletNode.port.onmessage = async (\n event: AudioWorkletEvent,\n ) => {\n const command = event.data.command;\n if (command !== \"newData\") {\n return;\n }\n // Handle the audio blob (e.g., send it to the server or process it further)\n logger.debug(\"Received audio blob from processor\", event);\n const pcmBuffer = event.data.recordedData;\n\n if (!pcmBuffer) {\n return;\n }\n\n this.buffers.push(pcmBuffer); // Store the buffer\n const sampleRate =\n event.data.sampleRate ?? this.audioContext.sampleRate;\n const otherSampleRate = this.audioContext.sampleRate;\n\n // Pass the intermediary buffer to the feature extractor worker\n const pcmBufferCopy = pcmBuffer.slice(0);\n const channelData = new Float32Array(pcmBufferCopy);\n\n const duration = channelData.length / sampleRate; // Calculate duration of the current buffer\n const otherDuration =\n pcmBuffer.byteLength /\n (otherSampleRate * (this.exportBitDepth / this.numberOfChannels)); // Calculate duration of the current buffer\n logger.debug(\n `sampleRate=${sampleRate} Duration: ${duration} -- otherSampleRate=${otherSampleRate} Other duration: ${otherDuration}`,\n );\n\n this.emitAudioEventCallback({\n data: pcmBuffer,\n position: this.position,\n });\n this.position += duration; // Update position\n\n this.featureExtractorWorker?.postMessage(\n {\n command: \"process\",\n channelData,\n sampleRate: this.audioContext.sampleRate,\n pointsPerSecond:\n this.config.pointsPerSecond || DEFAULT_WEB_POINTS_PER_SECOND,\n algorithm: this.config.algorithm || \"rms\",\n bitDepth: this.bitDepth,\n fullAudioDurationMs: this.position * 1000,\n numberOfChannels: this.numberOfChannels,\n features: this.config.features,\n },\n [],\n );\n };\n\n logger.debug(\n `WebRecorder initialized -- recordSampleRate=${this.audioContext.sampleRate}`,\n this.config,\n );\n this.audioWorkletNode.port.postMessage({\n command: \"init\",\n recordSampleRate: this.audioContext.sampleRate, // Pass the original sample rate\n exportSampleRate:\n this.config.sampleRate ?? this.audioContext.sampleRate,\n bitDepth: this.bitDepth,\n exportBitDepth: this.exportBitDepth,\n channels: this.numberOfChannels,\n interval: this.config.interval ?? DEFAULT_WEB_INTERVAL,\n });\n\n // Connect the source to the AudioWorkletNode and start recording\n this.source.connect(this.audioWorkletNode);\n this.audioWorkletNode.connect(this.audioContext.destination);\n } catch (error) {\n console.error(`[${TAG}] Failed to initialize WebRecorder`, error);\n }\n }\n\n initFeatureExtractorWorker(featuresExtratorUrl?: string) {\n try {\n if (featuresExtratorUrl) {\n // Initialize the feature extractor worker\n //TODO: create audio feature extractor from a Blob instead of url since we cannot include the url directly in the library\n // We keep the url during dev and use the blob in production.\n this.featureExtractorWorker = new Worker(\n new URL(featuresExtratorUrl, window.location.href),\n );\n this.featureExtractorWorker.onmessage =\n this.handleFeatureExtractorMessage.bind(this);\n this.featureExtractorWorker.onerror = this.handleWorkerError.bind(this);\n } else {\n // Fallback to the inline worker if the URL is not provided\n this.initFallbackWorker();\n }\n } catch (error) {\n console.error(\n `[${TAG}] Failed to initialize feature extractor worker`,\n error,\n );\n this.initFallbackWorker();\n }\n }\n\n initFallbackWorker() {\n try {\n const blob = new Blob([InlineFeaturesExtractor], {\n type: \"application/javascript\",\n });\n const url = URL.createObjectURL(blob);\n this.featureExtractorWorker = new Worker(url);\n this.featureExtractorWorker.onmessage =\n this.handleFeatureExtractorMessage.bind(this);\n this.featureExtractorWorker.onerror = (error) => {\n console.error(`[${TAG}] Default Inline worker failed`, error);\n };\n logger.log(\"Inline worker initialized successfully\");\n } catch (error) {\n console.error(\n `[${TAG}] Failed to initialize Inline Feature Extractor worker`,\n error,\n );\n }\n }\n\n handleWorkerError(error: ErrorEvent) {\n console.error(`[${TAG}] Feature extractor worker error:`, error);\n }\n\n handleFeatureExtractorMessage(event: AudioFeaturesEvent) {\n if (event.data.command === \"features\") {\n const segmentResult = event.data.result;\n\n // Merge the segment result with the full audio analysis data\n this.audioAnalysisData.dataPoints.push(...segmentResult.dataPoints);\n this.audioAnalysisData.speakerChanges?.push(\n ...(segmentResult.speakerChanges ?? []),\n );\n this.audioAnalysisData.durationMs = segmentResult.durationMs;\n if (segmentResult.amplitudeRange) {\n this.audioAnalysisData.amplitudeRange = {\n min: Math.min(\n this.audioAnalysisData.amplitudeRange.min,\n segmentResult.amplitudeRange.min,\n ),\n max: Math.max(\n this.audioAnalysisData.amplitudeRange.max,\n segmentResult.amplitudeRange.max,\n ),\n };\n }\n // Handle the extracted features (e.g., emit an event or log them)\n logger.debug(\"features event segmentResult\", segmentResult);\n logger.debug(\"features event audioAnalysisData\", this.audioAnalysisData);\n this.emitAudioAnalysisCallback(segmentResult);\n }\n }\n\n start() {\n this.source.connect(this.audioWorkletNode);\n this.audioWorkletNode.connect(this.audioContext.destination);\n }\n\n stop() {\n return new Promise((resolve, reject) => {\n try {\n if (this.audioWorkletNode) {\n // this.source.disconnect(this.audioWorkletNode);\n // this.audioWorkletNode.disconnect(this.audioContext.destination);\n this.audioWorkletNode.port.postMessage({ command: \"stop\" });\n\n // Set a timeout to reject the promise if no message is received within 5 seconds\n const timeout = setTimeout(() => {\n this.audioWorkletNode.port.removeEventListener(\n \"message\",\n onMessage,\n );\n reject(\n new Error(\"Timeout error, audioWorkletNode didn't complete.\"),\n );\n }, 5000);\n\n // Listen for the recordedData message to confirm stopping\n const onMessage = async (event: AudioWorkletEvent) => {\n const command = event.data.command;\n if (command === \"recordedData\") {\n clearTimeout(timeout); // Clear the timeout\n\n const rawPCMDataFull = event.data.recordedData?.slice(\n 0,\n ) as ArrayBuffer;\n\n // Compute duration of the recorded data\n const duration =\n rawPCMDataFull.byteLength /\n (this.audioContext.sampleRate *\n (this.exportBitDepth / this.numberOfChannels));\n logger.debug(\n `Received recorded data -- Duration: ${duration} vs ${rawPCMDataFull.byteLength / this.audioContext.sampleRate} seconds`,\n );\n logger.debug(\n `recordedData.length=${rawPCMDataFull.byteLength} vs transmittedData.length=${this.buffers[0].byteLength}`,\n );\n\n // Remove the event listener after receiving the final data\n this.audioWorkletNode.port.removeEventListener(\n \"message\",\n onMessage,\n );\n resolve(this.buffers); // Resolve the promise with the collected buffers\n }\n };\n this.audioWorkletNode.port.addEventListener(\"message\", onMessage);\n }\n\n // Stop all media stream tracks to stop the browser recording\n this.stopMediaStreamTracks();\n } catch (error) {\n reject(error);\n }\n });\n }\n\n pause() {\n this.source.disconnect(this.audioWorkletNode); // Disconnect the source from the AudioWorkletNode\n this.audioWorkletNode.disconnect(this.audioContext.destination); // Disconnect the AudioWorkletNode from the destination\n this.audioWorkletNode.port.postMessage({ command: \"pause\" });\n }\n\n stopMediaStreamTracks() {\n // Stop all audio tracks to stop the recording icon\n const tracks = this.source.mediaStream.getTracks();\n tracks.forEach((track) => track.stop());\n }\n\n async playRecordedData({\n recordedData,\n }: {\n recordedData: ArrayBuffer;\n mimeType?: string;\n }) {\n try {\n const blob = new Blob([recordedData]);\n const url = URL.createObjectURL(blob);\n const response = await fetch(url);\n const arrayBuffer = await response.arrayBuffer();\n\n // Decode the audio data\n const audioBuffer = await this.audioContext.decodeAudioData(arrayBuffer);\n\n // Create a buffer source node and play the audio\n const bufferSource = this.audioContext.createBufferSource();\n bufferSource.buffer = audioBuffer;\n bufferSource.connect(this.audioContext.destination);\n bufferSource.start();\n logger.debug(\"Playing recorded data\", recordedData);\n } catch (error) {\n console.error(`[${TAG}] Failed to play recorded data:`, error);\n }\n }\n\n private checkAudioContextFormat({ sampleRate }: { sampleRate: number }) {\n // Create a silent AudioBuffer\n const frameCount = sampleRate * 1.0; // 1 second buffer\n const audioBuffer = this.audioContext.createBuffer(\n 1,\n frameCount,\n sampleRate,\n );\n\n // Check the format\n const channelData = audioBuffer.getChannelData(0);\n const bitDepth = channelData.BYTES_PER_ELEMENT * 8; // 4 bytes per element means 32-bit\n\n return {\n sampleRate: audioBuffer.sampleRate,\n bitDepth,\n numberOfChannels: audioBuffer.numberOfChannels,\n };\n }\n\n resume() {\n this.source.connect(this.audioWorkletNode);\n this.audioWorkletNode.connect(this.audioContext.destination);\n this.audioWorkletNode.port.postMessage({ command: \"resume\" });\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"WebRecorder.web.js","sourceRoot":"","sources":["../src/WebRecorder.web.ts"],"names":[],"mappings":"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","sourcesContent":["// src/WebRecorder.ts\nimport { AudioAnalysis } from './AudioAnalysis/AudioAnalysis.types'\nimport { RecordingConfig } from './ExpoAudioStream.types'\nimport {\n EmitAudioAnalysisFunction,\n EmitAudioEventFunction,\n} from './ExpoAudioStream.web'\nimport { getLogger } from './logger'\nimport { encodingToBitDepth } from './utils/encodingToBitDepth'\nimport { InlineFeaturesExtractor } from './workers/InlineFeaturesExtractor.web'\nimport { InlineAudioWebWorker } from './workers/inlineAudioWebWorker.web'\n\ninterface AudioWorkletEvent {\n data: {\n command: string\n recordedData?: Float32Array\n sampleRate?: number\n }\n}\n\ninterface AudioFeaturesEvent {\n data: {\n command: string\n result: AudioAnalysis\n }\n}\n\nconst DEFAULT_WEB_BITDEPTH = 32\nconst DEFAULT_WEB_POINTS_PER_SECOND = 10\nconst DEFAULT_WEB_INTERVAL = 500\nconst DEFAULT_WEB_NUMBER_OF_CHANNELS = 1\nconst DEFAULT_ALGORITHM = 'rms'\n\nconst TAG = 'WebRecorder'\nconst logger = getLogger(TAG)\n\nexport class WebRecorder {\n private audioContext: AudioContext\n private audioWorkletNode!: AudioWorkletNode\n private featureExtractorWorker?: Worker\n private source: MediaStreamAudioSourceNode\n private audioWorkletUrl: string\n private emitAudioEventCallback: EmitAudioEventFunction\n private emitAudioAnalysisCallback: EmitAudioAnalysisFunction\n private config: RecordingConfig\n private position: number // Track the cumulative position\n private numberOfChannels: number // Number of audio channels\n private bitDepth: number // Bit depth of the audio\n private exportBitDepth: number // Bit depth of the audio\n private buffer: Float32Array // Single buffer to store the audio data\n private bufferSize: number // Keep track of the buffer size\n private audioAnalysisData: AudioAnalysis // Keep updating the full audio analysis data with latest events\n\n constructor({\n audioContext,\n source,\n recordingConfig,\n audioWorkletUrl,\n emitAudioEventCallback,\n emitAudioAnalysisCallback,\n }: {\n audioContext: AudioContext\n source: MediaStreamAudioSourceNode\n recordingConfig: RecordingConfig\n audioWorkletUrl: string\n emitAudioEventCallback: EmitAudioEventFunction\n emitAudioAnalysisCallback: EmitAudioAnalysisFunction\n }) {\n this.audioContext = audioContext\n this.source = source\n this.audioWorkletUrl = audioWorkletUrl\n this.emitAudioEventCallback = emitAudioEventCallback\n this.emitAudioAnalysisCallback = emitAudioAnalysisCallback\n this.config = recordingConfig\n this.position = 0\n this.bufferSize = 0\n this.buffer = new Float32Array(0) // Initialize the buffer\n\n const audioContextFormat = this.checkAudioContextFormat({\n sampleRate: this.audioContext.sampleRate,\n })\n logger.debug('Initialized WebRecorder with config:', {\n sampleRate: audioContextFormat.sampleRate,\n bitDepth: audioContextFormat.bitDepth,\n numberOfChannels: audioContextFormat.numberOfChannels,\n })\n\n this.bitDepth = audioContextFormat.bitDepth\n this.numberOfChannels =\n audioContextFormat.numberOfChannels ||\n DEFAULT_WEB_NUMBER_OF_CHANNELS // Default to 1 if not available\n this.exportBitDepth =\n encodingToBitDepth({\n encoding: recordingConfig.encoding ?? 'pcm_32bit',\n }) ||\n audioContextFormat.bitDepth ||\n DEFAULT_WEB_BITDEPTH\n\n this.audioAnalysisData = {\n amplitudeRange: { min: 0, max: 0 },\n dataPoints: [],\n durationMs: 0,\n samples: 0,\n amplitudeAlgorithm: recordingConfig.algorithm || DEFAULT_ALGORITHM,\n bitDepth: this.bitDepth,\n numberOfChannels: this.numberOfChannels,\n sampleRate: this.config.sampleRate || this.audioContext.sampleRate,\n pointsPerSecond:\n this.config.pointsPerSecond || DEFAULT_WEB_POINTS_PER_SECOND,\n speakerChanges: [],\n }\n\n if (recordingConfig.enableProcessing) {\n this.initFeatureExtractorWorker()\n }\n }\n\n async init() {\n try {\n if (!this.audioWorkletUrl) {\n const blob = new Blob([InlineAudioWebWorker], {\n type: 'application/javascript',\n })\n const url = URL.createObjectURL(blob)\n await this.audioContext.audioWorklet.addModule(url)\n } else {\n await this.audioContext.audioWorklet.addModule(\n this.audioWorkletUrl\n )\n }\n this.audioWorkletNode = new AudioWorkletNode(\n this.audioContext,\n 'recorder-processor'\n )\n\n this.audioWorkletNode.port.onmessage = async (\n event: AudioWorkletEvent\n ) => {\n const command = event.data.command\n if (command !== 'newData') {\n return\n }\n // Handle the audio blob (e.g., send it to the server or process it further)\n logger.debug('Received audio blob from processor', event)\n const pcmBufferFloat = event.data.recordedData\n\n if (!pcmBufferFloat) {\n return\n }\n\n // Concatenate the incoming Float32Array to the existing buffer\n const newBuffer = new Float32Array(\n this.bufferSize + pcmBufferFloat.length\n )\n newBuffer.set(this.buffer, 0)\n newBuffer.set(pcmBufferFloat, this.bufferSize)\n this.buffer = newBuffer\n this.bufferSize += pcmBufferFloat.length\n\n const sampleRate =\n event.data.sampleRate ?? this.audioContext.sampleRate\n const duration = pcmBufferFloat.length / sampleRate // Calculate duration of the current buffer\n\n this.emitAudioEventCallback({\n data: pcmBufferFloat,\n position: this.position,\n })\n this.position += duration // Update position\n\n this.featureExtractorWorker?.postMessage(\n {\n command: 'process',\n channelData: pcmBufferFloat,\n sampleRate,\n pointsPerSecond:\n this.config.pointsPerSecond ||\n DEFAULT_WEB_POINTS_PER_SECOND,\n algorithm: this.config.algorithm || 'rms',\n bitDepth: this.bitDepth,\n fullAudioDurationMs: this.position * 1000,\n numberOfChannels: this.numberOfChannels,\n features: this.config.features,\n },\n []\n )\n }\n\n logger.debug(\n `WebRecorder initialized -- recordSampleRate=${this.audioContext.sampleRate}`,\n this.config\n )\n this.audioWorkletNode.port.postMessage({\n command: 'init',\n recordSampleRate: this.audioContext.sampleRate, // Pass the original sample rate\n exportSampleRate:\n this.config.sampleRate ?? this.audioContext.sampleRate,\n bitDepth: this.bitDepth,\n exportBitDepth: this.exportBitDepth,\n channels: this.numberOfChannels,\n interval: this.config.interval ?? DEFAULT_WEB_INTERVAL,\n })\n\n // Connect the source to the AudioWorkletNode and start recording\n this.source.connect(this.audioWorkletNode)\n this.audioWorkletNode.connect(this.audioContext.destination)\n } catch (error) {\n console.error(`[${TAG}] Failed to initialize WebRecorder`, error)\n }\n }\n\n initFeatureExtractorWorker(featuresExtratorUrl?: string) {\n try {\n if (featuresExtratorUrl) {\n // Initialize the feature extractor worker\n //TODO: create audio feature extractor from a Blob instead of url since we cannot include the url directly in the library\n // We keep the url during dev and use the blob in production.\n this.featureExtractorWorker = new Worker(\n new URL(featuresExtratorUrl, window.location.href)\n )\n this.featureExtractorWorker.onmessage =\n this.handleFeatureExtractorMessage.bind(this)\n this.featureExtractorWorker.onerror =\n this.handleWorkerError.bind(this)\n } else {\n // Fallback to the inline worker if the URL is not provided\n this.initFallbackWorker()\n }\n } catch (error) {\n console.error(\n `[${TAG}] Failed to initialize feature extractor worker`,\n error\n )\n this.initFallbackWorker()\n }\n }\n\n initFallbackWorker() {\n try {\n const blob = new Blob([InlineFeaturesExtractor], {\n type: 'application/javascript',\n })\n const url = URL.createObjectURL(blob)\n this.featureExtractorWorker = new Worker(url)\n this.featureExtractorWorker.onmessage =\n this.handleFeatureExtractorMessage.bind(this)\n this.featureExtractorWorker.onerror = (error) => {\n console.error(`[${TAG}] Default Inline worker failed`, error)\n }\n logger.log('Inline worker initialized successfully')\n } catch (error) {\n console.error(\n `[${TAG}] Failed to initialize Inline Feature Extractor worker`,\n error\n )\n }\n }\n\n handleWorkerError(error: ErrorEvent) {\n console.error(`[${TAG}] Feature extractor worker error:`, error)\n }\n\n handleFeatureExtractorMessage(event: AudioFeaturesEvent) {\n if (event.data.command === 'features') {\n const segmentResult = event.data.result\n\n // Merge the segment result with the full audio analysis data\n this.audioAnalysisData.dataPoints.push(...segmentResult.dataPoints)\n this.audioAnalysisData.speakerChanges?.push(\n ...(segmentResult.speakerChanges ?? [])\n )\n this.audioAnalysisData.durationMs = segmentResult.durationMs\n if (segmentResult.amplitudeRange) {\n this.audioAnalysisData.amplitudeRange = {\n min: Math.min(\n this.audioAnalysisData.amplitudeRange.min,\n segmentResult.amplitudeRange.min\n ),\n max: Math.max(\n this.audioAnalysisData.amplitudeRange.max,\n segmentResult.amplitudeRange.max\n ),\n }\n }\n // Handle the extracted features (e.g., emit an event or log them)\n logger.debug('features event segmentResult', segmentResult)\n logger.debug(\n 'features event audioAnalysisData',\n this.audioAnalysisData\n )\n this.emitAudioAnalysisCallback(segmentResult)\n }\n }\n\n start() {\n this.source.connect(this.audioWorkletNode)\n this.audioWorkletNode.connect(this.audioContext.destination)\n }\n\n stop(): Promise<Float32Array> {\n return new Promise((resolve, reject) => {\n try {\n if (this.audioWorkletNode) {\n // this.source.disconnect(this.audioWorkletNode);\n // this.audioWorkletNode.disconnect(this.audioContext.destination);\n this.audioWorkletNode.port.postMessage({ command: 'stop' })\n\n // Set a timeout to reject the promise if no message is received within 5 seconds\n const timeout = setTimeout(() => {\n this.audioWorkletNode.port.removeEventListener(\n 'message',\n onMessage\n )\n reject(\n new Error(\n \"Timeout error, audioWorkletNode didn't complete.\"\n )\n )\n }, 5000)\n\n // Listen for the recordedData message to confirm stopping\n const onMessage = async (event: AudioWorkletEvent) => {\n const command = event.data.command\n if (command === 'recordedData') {\n clearTimeout(timeout) // Clear the timeout\n\n const rawPCMDataFull =\n event.data.recordedData?.slice(0)\n\n if (!rawPCMDataFull) {\n reject(new Error('Failed to get recorded data'))\n return\n }\n\n // Compute duration of the recorded data\n const duration =\n rawPCMDataFull.byteLength /\n (this.audioContext.sampleRate *\n (this.exportBitDepth /\n this.numberOfChannels))\n logger.debug(\n `Received recorded data -- Duration: ${duration} vs ${rawPCMDataFull.byteLength / this.audioContext.sampleRate} seconds`\n )\n logger.debug(\n `recordedData.length=${rawPCMDataFull.byteLength} vs transmittedData.length=${this.bufferSize}`\n )\n\n // Remove the event listener after receiving the final data\n this.audioWorkletNode.port.removeEventListener(\n 'message',\n onMessage\n )\n resolve(this.buffer) // Resolve the promise with the collected buffers\n }\n }\n this.audioWorkletNode.port.addEventListener(\n 'message',\n onMessage\n )\n }\n\n // Stop all media stream tracks to stop the browser recording\n this.stopMediaStreamTracks()\n } catch (error) {\n reject(error)\n }\n })\n }\n\n pause() {\n this.source.disconnect(this.audioWorkletNode) // Disconnect the source from the AudioWorkletNode\n this.audioWorkletNode.disconnect(this.audioContext.destination) // Disconnect the AudioWorkletNode from the destination\n this.audioWorkletNode.port.postMessage({ command: 'pause' })\n }\n\n stopMediaStreamTracks() {\n // Stop all audio tracks to stop the recording icon\n const tracks = this.source.mediaStream.getTracks()\n tracks.forEach((track) => track.stop())\n }\n\n async playRecordedData({\n recordedData,\n }: {\n recordedData: ArrayBuffer\n mimeType?: string\n }) {\n try {\n const blob = new Blob([recordedData])\n const url = URL.createObjectURL(blob)\n const response = await fetch(url)\n const arrayBuffer = await response.arrayBuffer()\n\n // Decode the audio data\n const audioBuffer =\n await this.audioContext.decodeAudioData(arrayBuffer)\n\n // Create a buffer source node and play the audio\n const bufferSource = this.audioContext.createBufferSource()\n bufferSource.buffer = audioBuffer\n bufferSource.connect(this.audioContext.destination)\n bufferSource.start()\n logger.debug('Playing recorded data', recordedData)\n } catch (error) {\n console.error(`[${TAG}] Failed to play recorded data:`, error)\n }\n }\n\n private checkAudioContextFormat({ sampleRate }: { sampleRate: number }) {\n // Create a silent AudioBuffer\n const frameCount = sampleRate * 1.0 // 1 second buffer\n const audioBuffer = this.audioContext.createBuffer(\n 1,\n frameCount,\n sampleRate\n )\n\n // Check the format\n const channelData = audioBuffer.getChannelData(0)\n const bitDepth = channelData.BYTES_PER_ELEMENT * 8 // 4 bytes per element means 32-bit\n\n return {\n sampleRate: audioBuffer.sampleRate,\n bitDepth,\n numberOfChannels: audioBuffer.numberOfChannels,\n }\n }\n\n resume() {\n this.source.connect(this.audioWorkletNode)\n this.audioWorkletNode.connect(this.audioContext.destination)\n this.audioWorkletNode.port.postMessage({ command: 'resume' })\n }\n}\n"]}
|
package/build/constants.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BitDepth, SampleRate } from
|
|
1
|
+
import { BitDepth, SampleRate } from './ExpoAudioStream.types';
|
|
2
2
|
export declare const isWeb: boolean;
|
|
3
3
|
export declare const DEBUG_NAMESPACE = "expo-audio-stream";
|
|
4
4
|
export declare const RIFF_HEADER = 1380533830;
|
package/build/constants.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,yBAAyB,
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AAE9D,eAAO,MAAM,KAAK,SAAwB,CAAA;AAC1C,eAAO,MAAM,eAAe,sBAAsB,CAAA;AAGlD,eAAO,MAAM,WAAW,aAAa,CAAA;AACrC,eAAO,MAAM,WAAW,aAAa,CAAA;AACrC,eAAO,MAAM,YAAY,aAAa,CAAA;AACtC,eAAO,MAAM,aAAa,aAAa,CAAA;AACvC,eAAO,MAAM,aAAa,aAAa,CAAA;AAGvC,eAAO,MAAM,mBAAmB,EAAE,UAAkB,CAAA;AACpD,eAAO,MAAM,iBAAiB,EAAE,QAAa,CAAA"}
|
package/build/constants.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// packages/expo-audio-stream/src/constants.ts
|
|
2
|
-
import { Platform } from
|
|
3
|
-
export const isWeb = Platform.OS ===
|
|
4
|
-
export const DEBUG_NAMESPACE =
|
|
2
|
+
import { Platform } from 'react-native';
|
|
3
|
+
export const isWeb = Platform.OS === 'web';
|
|
4
|
+
export const DEBUG_NAMESPACE = 'expo-audio-stream';
|
|
5
5
|
// Constants for identifying chunks in a WAV file
|
|
6
6
|
export const RIFF_HEADER = 0x52494646; // "RIFF"
|
|
7
7
|
export const WAVE_HEADER = 0x57415645; // "WAVE"
|
package/build/constants.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAIvC,MAAM,CAAC,MAAM,KAAK,GAAG,QAAQ,CAAC,EAAE,KAAK,KAAK,CAAA;AAC1C,MAAM,CAAC,MAAM,eAAe,GAAG,mBAAmB,CAAA;AAElD,iDAAiD;AACjD,MAAM,CAAC,MAAM,WAAW,GAAG,UAAU,CAAA,CAAC,SAAS;AAC/C,MAAM,CAAC,MAAM,WAAW,GAAG,UAAU,CAAA,CAAC,SAAS;AAC/C,MAAM,CAAC,MAAM,YAAY,GAAG,UAAU,CAAA,CAAC,SAAS;AAChD,MAAM,CAAC,MAAM,aAAa,GAAG,UAAU,CAAA,CAAC,SAAS;AACjD,MAAM,CAAC,MAAM,aAAa,GAAG,UAAU,CAAA,CAAC,SAAS;AAEjD,iBAAiB;AACjB,MAAM,CAAC,MAAM,mBAAmB,GAAe,KAAK,CAAA;AACpD,MAAM,CAAC,MAAM,iBAAiB,GAAa,EAAE,CAAA","sourcesContent":["// packages/expo-audio-stream/src/constants.ts\nimport { Platform } from 'react-native'\n\nimport { BitDepth, SampleRate } from './ExpoAudioStream.types'\n\nexport const isWeb = Platform.OS === 'web'\nexport const DEBUG_NAMESPACE = 'expo-audio-stream'\n\n// Constants for identifying chunks in a WAV file\nexport const RIFF_HEADER = 0x52494646 // \"RIFF\"\nexport const WAVE_HEADER = 0x57415645 // \"WAVE\"\nexport const FMT_CHUNK_ID = 0x666d7420 // \"fmt \"\nexport const DATA_CHUNK_ID = 0x64617461 // \"data\"\nexport const INFO_CHUNK_ID = 0x494e464f // \"INFO\"\n\n// Default values\nexport const DEFAULT_SAMPLE_RATE: SampleRate = 16000\nexport const DEFAULT_BIT_DEPTH: BitDepth = 32\n"]}
|
package/build/events.d.ts
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
|
-
import { type Subscription } from
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import { type Subscription } from 'expo-modules-core';
|
|
2
|
+
import { AudioAnalysis } from './AudioAnalysis/AudioAnalysis.types';
|
|
3
|
+
export interface AudioEventPayload {
|
|
4
|
+
encoded?: string;
|
|
5
|
+
buffer?: Float32Array;
|
|
6
|
+
fileUri: string;
|
|
7
|
+
lastEmittedSize: number;
|
|
8
|
+
position: number;
|
|
9
|
+
deltaSize: number;
|
|
10
|
+
totalSize: number;
|
|
11
|
+
mimeType: string;
|
|
12
|
+
streamUuid: string;
|
|
13
|
+
}
|
|
4
14
|
export declare function addAudioEventListener(listener: (event: AudioEventPayload) => Promise<void>): Subscription;
|
|
5
|
-
export
|
|
15
|
+
export interface AudioAnalysisEvent extends AudioAnalysis {
|
|
16
|
+
}
|
|
17
|
+
export declare function addAudioAnalysisListener(listener: (event: AudioAnalysisEvent) => Promise<void>): Subscription;
|
|
6
18
|
//# sourceMappingURL=events.d.ts.map
|
package/build/events.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAEA,OAAO,EAAgB,KAAK,YAAY,EAAE,MAAM,mBAAmB,
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAEA,OAAO,EAAgB,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAEnE,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAA;AAOnE,MAAM,WAAW,iBAAiB;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,YAAY,CAAA;IACrB,OAAO,EAAE,MAAM,CAAA;IACf,eAAe,EAAE,MAAM,CAAA;IACvB,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;CACrB;AAED,wBAAgB,qBAAqB,CACjC,QAAQ,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,OAAO,CAAC,IAAI,CAAC,GACtD,YAAY,CAGd;AAGD,MAAM,WAAW,kBAAmB,SAAQ,aAAa;CAAG;AAE5D,wBAAgB,wBAAwB,CACpC,QAAQ,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,OAAO,CAAC,IAAI,CAAC,GACvD,YAAY,CAGd"}
|
package/build/events.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
// packages/expo-audio-stream/src/events.ts
|
|
2
|
-
import { EventEmitter } from
|
|
3
|
-
import ExpoAudioStreamModule from
|
|
4
|
-
import { getLogger } from
|
|
2
|
+
import { EventEmitter } from 'expo-modules-core';
|
|
3
|
+
import ExpoAudioStreamModule from './ExpoAudioStreamModule';
|
|
4
|
+
import { getLogger } from './logger';
|
|
5
5
|
const emitter = new EventEmitter(ExpoAudioStreamModule);
|
|
6
|
-
const logger = getLogger(
|
|
6
|
+
const logger = getLogger('events');
|
|
7
7
|
export function addAudioEventListener(listener) {
|
|
8
|
-
logger.log(
|
|
9
|
-
return emitter.addListener(
|
|
8
|
+
logger.log('Adding listener for AudioData event');
|
|
9
|
+
return emitter.addListener('AudioData', listener);
|
|
10
10
|
}
|
|
11
11
|
export function addAudioAnalysisListener(listener) {
|
|
12
|
-
logger.log(
|
|
13
|
-
return emitter.addListener(
|
|
12
|
+
logger.log('Adding listener for AudioAnalysis event');
|
|
13
|
+
return emitter.addListener('AudioAnalysis', listener);
|
|
14
14
|
}
|
|
15
15
|
//# sourceMappingURL=events.js.map
|
package/build/events.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAE3C,OAAO,EAAE,YAAY,EAAqB,MAAM,mBAAmB,
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAE3C,OAAO,EAAE,YAAY,EAAqB,MAAM,mBAAmB,CAAA;AAGnE,OAAO,qBAAqB,MAAM,yBAAyB,CAAA;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAEpC,MAAM,OAAO,GAAG,IAAI,YAAY,CAAC,qBAAqB,CAAC,CAAA;AACvD,MAAM,MAAM,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAA;AAclC,MAAM,UAAU,qBAAqB,CACjC,QAAqD;IAErD,MAAM,CAAC,GAAG,CAAC,qCAAqC,CAAC,CAAA;IACjD,OAAO,OAAO,CAAC,WAAW,CAAoB,WAAW,EAAE,QAAQ,CAAC,CAAA;AACxE,CAAC;AAKD,MAAM,UAAU,wBAAwB,CACpC,QAAsD;IAEtD,MAAM,CAAC,GAAG,CAAC,yCAAyC,CAAC,CAAA;IACrD,OAAO,OAAO,CAAC,WAAW,CAAqB,eAAe,EAAE,QAAQ,CAAC,CAAA;AAC7E,CAAC","sourcesContent":["// packages/expo-audio-stream/src/events.ts\n\nimport { EventEmitter, type Subscription } from 'expo-modules-core'\n\nimport { AudioAnalysis } from './AudioAnalysis/AudioAnalysis.types'\nimport ExpoAudioStreamModule from './ExpoAudioStreamModule'\nimport { getLogger } from './logger'\n\nconst emitter = new EventEmitter(ExpoAudioStreamModule)\nconst logger = getLogger('events')\n\nexport interface AudioEventPayload {\n encoded?: string\n buffer?: Float32Array\n fileUri: string\n lastEmittedSize: number\n position: number\n deltaSize: number\n totalSize: number\n mimeType: string\n streamUuid: string\n}\n\nexport function addAudioEventListener(\n listener: (event: AudioEventPayload) => Promise<void>\n): Subscription {\n logger.log('Adding listener for AudioData event')\n return emitter.addListener<AudioEventPayload>('AudioData', listener)\n}\n\n// Only aliasing the AudioAnalysis type for the event payload\nexport interface AudioAnalysisEvent extends AudioAnalysis {}\n\nexport function addAudioAnalysisListener(\n listener: (event: AudioAnalysisEvent) => Promise<void>\n): Subscription {\n logger.log('Adding listener for AudioAnalysis event')\n return emitter.addListener<AudioAnalysisEvent>('AudioAnalysis', listener)\n}\n"]}
|
package/build/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { extractAudioAnalysis } from
|
|
2
|
-
import { AudioRecorderProvider, useSharedAudioRecorder } from
|
|
3
|
-
import { useAudioRecorder } from
|
|
4
|
-
export * from
|
|
5
|
-
export * from
|
|
6
|
-
export * from
|
|
1
|
+
import { extractAudioAnalysis } from './AudioAnalysis/extractAudioAnalysis';
|
|
2
|
+
import { AudioRecorderProvider, useSharedAudioRecorder } from './AudioRecorder.provider';
|
|
3
|
+
import { useAudioRecorder } from './useAudioRecorder';
|
|
4
|
+
export * from './utils/getWavFileInfo';
|
|
5
|
+
export * from './utils/convertPCMToFloat32';
|
|
6
|
+
export * from './utils/writeWavHeader';
|
|
7
7
|
export { AudioRecorderProvider, extractAudioAnalysis, useAudioRecorder, useSharedAudioRecorder, };
|
|
8
|
-
export type * from
|
|
9
|
-
export type * from
|
|
8
|
+
export type * from './AudioAnalysis/AudioAnalysis.types';
|
|
9
|
+
export type * from './ExpoAudioStream.types';
|
|
10
10
|
//# sourceMappingURL=index.d.ts.map
|
package/build/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAA;AAC3E,OAAO,EACH,qBAAqB,EACrB,sBAAsB,EACzB,MAAM,0BAA0B,CAAA;AACjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAErD,cAAc,wBAAwB,CAAA;AACtC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,wBAAwB,CAAA;AAEtC,OAAO,EACH,qBAAqB,EACrB,oBAAoB,EACpB,gBAAgB,EAChB,sBAAsB,GACzB,CAAA;AAED,mBAAmB,qCAAqC,CAAA;AACxD,mBAAmB,yBAAyB,CAAA"}
|
package/build/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
-
import { extractAudioAnalysis } from
|
|
3
|
-
import { AudioRecorderProvider, useSharedAudioRecorder, } from
|
|
4
|
-
import { useAudioRecorder } from
|
|
5
|
-
export * from
|
|
6
|
-
export * from
|
|
7
|
-
export * from
|
|
2
|
+
import { extractAudioAnalysis } from './AudioAnalysis/extractAudioAnalysis';
|
|
3
|
+
import { AudioRecorderProvider, useSharedAudioRecorder, } from './AudioRecorder.provider';
|
|
4
|
+
import { useAudioRecorder } from './useAudioRecorder';
|
|
5
|
+
export * from './utils/getWavFileInfo';
|
|
6
|
+
export * from './utils/convertPCMToFloat32';
|
|
7
|
+
export * from './utils/writeWavHeader';
|
|
8
8
|
export { AudioRecorderProvider, extractAudioAnalysis, useAudioRecorder, useSharedAudioRecorder, };
|
|
9
9
|
//# sourceMappingURL=index.js.map
|
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,eAAe;AAEf,OAAO,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,eAAe;AAEf,OAAO,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAA;AAC3E,OAAO,EACH,qBAAqB,EACrB,sBAAsB,GACzB,MAAM,0BAA0B,CAAA;AACjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAErD,cAAc,wBAAwB,CAAA;AACtC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,wBAAwB,CAAA;AAEtC,OAAO,EACH,qBAAqB,EACrB,oBAAoB,EACpB,gBAAgB,EAChB,sBAAsB,GACzB,CAAA","sourcesContent":["// src/index.ts\n\nimport { extractAudioAnalysis } from './AudioAnalysis/extractAudioAnalysis'\nimport {\n AudioRecorderProvider,\n useSharedAudioRecorder,\n} from './AudioRecorder.provider'\nimport { useAudioRecorder } from './useAudioRecorder'\n\nexport * from './utils/getWavFileInfo'\nexport * from './utils/convertPCMToFloat32'\nexport * from './utils/writeWavHeader'\n\nexport {\n AudioRecorderProvider,\n extractAudioAnalysis,\n useAudioRecorder,\n useSharedAudioRecorder,\n}\n\nexport type * from './AudioAnalysis/AudioAnalysis.types'\nexport type * from './ExpoAudioStream.types'\n"]}
|
package/build/logger.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
type ConsoleLike = {
|
|
2
2
|
log: (message: string, ...args: unknown[]) => void;
|
|
3
3
|
debug: (message: string, ...args: unknown[]) => void;
|
|
4
|
+
warn: (message: string, ...args: unknown[]) => void;
|
|
5
|
+
error: (message: string, ...args: unknown[]) => void;
|
|
4
6
|
};
|
|
5
7
|
export declare const getLogger: (tag: string) => ConsoleLike;
|
|
6
|
-
export declare const enableAllLoggers: () => void;
|
|
7
|
-
export declare const disableAllLoggers: () => void;
|
|
8
8
|
export {};
|
|
9
9
|
//# sourceMappingURL=logger.d.ts.map
|
package/build/logger.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAKA,KAAK,WAAW,GAAG;
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAKA,KAAK,WAAW,GAAG;IACf,GAAG,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;IAClD,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;IACpD,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;IACnD,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;CACvD,CAAA;AAED,eAAO,MAAM,SAAS,QAAS,MAAM,KAAG,WASvC,CAAA"}
|
package/build/logger.js
CHANGED
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
// packages/expo-audio-stream/src/logger.ts
|
|
2
|
-
import
|
|
3
|
-
import { DEBUG_NAMESPACE } from
|
|
2
|
+
import { getLogger as siteedGetLogger } from '@siteed/react-native-logger';
|
|
3
|
+
import { DEBUG_NAMESPACE } from './constants';
|
|
4
4
|
export const getLogger = (tag) => {
|
|
5
|
-
const baseLogger =
|
|
5
|
+
const baseLogger = siteedGetLogger(`${DEBUG_NAMESPACE}:${tag}`);
|
|
6
6
|
return {
|
|
7
|
-
log: (...args) => baseLogger(...args),
|
|
8
|
-
debug: (...args) => baseLogger(...args),
|
|
7
|
+
log: (...args) => baseLogger.log(...args),
|
|
8
|
+
debug: (...args) => baseLogger.debug(...args),
|
|
9
|
+
error: (...args) => baseLogger.error(...args),
|
|
10
|
+
warn: (...args) => baseLogger.warn(...args),
|
|
9
11
|
};
|
|
10
12
|
};
|
|
11
|
-
export const enableAllLoggers = () => {
|
|
12
|
-
createDebug.enable(`${DEBUG_NAMESPACE}:*`);
|
|
13
|
-
};
|
|
14
|
-
export const disableAllLoggers = () => {
|
|
15
|
-
createDebug.disable();
|
|
16
|
-
};
|
|
17
13
|
//# sourceMappingURL=logger.js.map
|