@siteed/expo-audio-stream 2.1.0 → 2.2.1-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -260
- package/build/index.d.ts +11 -15
- package/build/index.js +54 -14
- package/build/src/index.d.ts +11 -0
- package/build/src/index.js +54 -0
- package/package.json +49 -110
- package/src/index.ts +18 -32
- package/CHANGELOG.md +0 -206
- package/android/build.gradle +0 -105
- package/android/src/main/AndroidManifest.xml +0 -27
- package/android/src/main/java/net/siteed/audiostream/AudioAnalysisData.kt +0 -166
- package/android/src/main/java/net/siteed/audiostream/AudioDataEncoder.kt +0 -9
- package/android/src/main/java/net/siteed/audiostream/AudioFileHandler.kt +0 -131
- package/android/src/main/java/net/siteed/audiostream/AudioFormatUtils.kt +0 -103
- package/android/src/main/java/net/siteed/audiostream/AudioNotificationsManager.kt +0 -435
- package/android/src/main/java/net/siteed/audiostream/AudioProcessor.kt +0 -2235
- package/android/src/main/java/net/siteed/audiostream/AudioRecorderManager.kt +0 -1437
- package/android/src/main/java/net/siteed/audiostream/AudioRecordingService.kt +0 -152
- package/android/src/main/java/net/siteed/audiostream/AudioTrimmer.kt +0 -1099
- package/android/src/main/java/net/siteed/audiostream/Constants.kt +0 -21
- package/android/src/main/java/net/siteed/audiostream/EventSender.kt +0 -7
- package/android/src/main/java/net/siteed/audiostream/ExpoAudioStreamModule.kt +0 -739
- package/android/src/main/java/net/siteed/audiostream/FFT.kt +0 -99
- package/android/src/main/java/net/siteed/audiostream/Features.kt +0 -98
- package/android/src/main/java/net/siteed/audiostream/NotificationConfig.kt +0 -70
- package/android/src/main/java/net/siteed/audiostream/PermissionUtils.kt +0 -59
- package/android/src/main/java/net/siteed/audiostream/RecordingActionReceiver.kt +0 -59
- package/android/src/main/java/net/siteed/audiostream/RecordingConfig.kt +0 -205
- package/android/src/main/java/net/siteed/audiostream/WaveformConfig.kt +0 -19
- package/android/src/main/java/net/siteed/audiostream/WaveformRenderer.kt +0 -159
- package/android/src/main/res/drawable/ic_default_action_icon.xml +0 -16
- package/android/src/main/res/drawable/ic_microphone.xml +0 -13
- package/android/src/main/res/drawable/ic_pause.xml +0 -10
- package/android/src/main/res/drawable/ic_play.xml +0 -10
- package/android/src/main/res/drawable/ic_stop.xml +0 -10
- package/android/src/main/res/layout/notification_recording.xml +0 -37
- package/android/src/main/test/java/net/siteed/audiostream/AudioProcessorTest.kt +0 -56
- package/app.plugin.js +0 -1
- package/build/AudioAnalysis/AudioAnalysis.types.d.ts +0 -179
- package/build/AudioAnalysis/AudioAnalysis.types.d.ts.map +0 -1
- package/build/AudioAnalysis/AudioAnalysis.types.js +0 -3
- package/build/AudioAnalysis/AudioAnalysis.types.js.map +0 -1
- package/build/AudioAnalysis/extractAudioAnalysis.d.ts +0 -68
- package/build/AudioAnalysis/extractAudioAnalysis.d.ts.map +0 -1
- package/build/AudioAnalysis/extractAudioAnalysis.js +0 -203
- package/build/AudioAnalysis/extractAudioAnalysis.js.map +0 -1
- package/build/AudioAnalysis/extractAudioData.d.ts +0 -3
- package/build/AudioAnalysis/extractAudioData.d.ts.map +0 -1
- package/build/AudioAnalysis/extractAudioData.js +0 -5
- package/build/AudioAnalysis/extractAudioData.js.map +0 -1
- package/build/AudioAnalysis/extractMelSpectrogram.d.ts +0 -14
- package/build/AudioAnalysis/extractMelSpectrogram.d.ts.map +0 -1
- package/build/AudioAnalysis/extractMelSpectrogram.js +0 -85
- package/build/AudioAnalysis/extractMelSpectrogram.js.map +0 -1
- package/build/AudioAnalysis/extractPreview.d.ts +0 -11
- package/build/AudioAnalysis/extractPreview.d.ts.map +0 -1
- package/build/AudioAnalysis/extractPreview.js +0 -25
- package/build/AudioAnalysis/extractPreview.js.map +0 -1
- package/build/AudioAnalysis/extractWaveform.d.ts +0 -8
- package/build/AudioAnalysis/extractWaveform.d.ts.map +0 -1
- package/build/AudioAnalysis/extractWaveform.js +0 -11
- package/build/AudioAnalysis/extractWaveform.js.map +0 -1
- package/build/AudioRecorder.provider.d.ts +0 -11
- package/build/AudioRecorder.provider.d.ts.map +0 -1
- package/build/AudioRecorder.provider.js +0 -37
- package/build/AudioRecorder.provider.js.map +0 -1
- package/build/ExpoAudioStream.native.d.ts +0 -3
- package/build/ExpoAudioStream.native.d.ts.map +0 -1
- package/build/ExpoAudioStream.native.js +0 -6
- package/build/ExpoAudioStream.native.js.map +0 -1
- package/build/ExpoAudioStream.types.d.ts +0 -532
- package/build/ExpoAudioStream.types.d.ts.map +0 -1
- package/build/ExpoAudioStream.types.js +0 -2
- package/build/ExpoAudioStream.types.js.map +0 -1
- package/build/ExpoAudioStream.web.d.ts +0 -59
- package/build/ExpoAudioStream.web.d.ts.map +0 -1
- package/build/ExpoAudioStream.web.js +0 -285
- package/build/ExpoAudioStream.web.js.map +0 -1
- package/build/ExpoAudioStreamModule.d.ts +0 -3
- package/build/ExpoAudioStreamModule.d.ts.map +0 -1
- package/build/ExpoAudioStreamModule.js +0 -693
- package/build/ExpoAudioStreamModule.js.map +0 -1
- package/build/WebRecorder.web.d.ts +0 -119
- package/build/WebRecorder.web.d.ts.map +0 -1
- package/build/WebRecorder.web.js +0 -436
- package/build/WebRecorder.web.js.map +0 -1
- package/build/constants.d.ts +0 -11
- package/build/constants.d.ts.map +0 -1
- package/build/constants.js +0 -14
- package/build/constants.js.map +0 -1
- package/build/events.d.ts +0 -26
- package/build/events.d.ts.map +0 -1
- package/build/events.js +0 -21
- package/build/events.js.map +0 -1
- package/build/index.d.ts.map +0 -1
- package/build/index.js.map +0 -1
- package/build/trimAudio.d.ts +0 -25
- package/build/trimAudio.d.ts.map +0 -1
- package/build/trimAudio.js +0 -67
- package/build/trimAudio.js.map +0 -1
- package/build/useAudioRecorder.d.ts +0 -21
- package/build/useAudioRecorder.d.ts.map +0 -1
- package/build/useAudioRecorder.js +0 -427
- package/build/useAudioRecorder.js.map +0 -1
- package/build/utils/BlobFix.d.ts +0 -9
- package/build/utils/BlobFix.d.ts.map +0 -1
- package/build/utils/BlobFix.js +0 -498
- package/build/utils/BlobFix.js.map +0 -1
- package/build/utils/audioProcessing.d.ts +0 -24
- package/build/utils/audioProcessing.d.ts.map +0 -1
- package/build/utils/audioProcessing.js +0 -133
- package/build/utils/audioProcessing.js.map +0 -1
- package/build/utils/concatenateBuffers.d.ts +0 -8
- package/build/utils/concatenateBuffers.d.ts.map +0 -1
- package/build/utils/concatenateBuffers.js +0 -21
- package/build/utils/concatenateBuffers.js.map +0 -1
- package/build/utils/convertPCMToFloat32.d.ts +0 -13
- package/build/utils/convertPCMToFloat32.d.ts.map +0 -1
- package/build/utils/convertPCMToFloat32.js +0 -120
- package/build/utils/convertPCMToFloat32.js.map +0 -1
- package/build/utils/encodingToBitDepth.d.ts +0 -5
- package/build/utils/encodingToBitDepth.d.ts.map +0 -1
- package/build/utils/encodingToBitDepth.js +0 -13
- package/build/utils/encodingToBitDepth.js.map +0 -1
- package/build/utils/getWavFileInfo.d.ts +0 -26
- package/build/utils/getWavFileInfo.d.ts.map +0 -1
- package/build/utils/getWavFileInfo.js +0 -92
- package/build/utils/getWavFileInfo.js.map +0 -1
- package/build/utils/writeWavHeader.d.ts +0 -49
- package/build/utils/writeWavHeader.d.ts.map +0 -1
- package/build/utils/writeWavHeader.js +0 -91
- package/build/utils/writeWavHeader.js.map +0 -1
- package/build/workers/InlineFeaturesExtractor.web.d.ts +0 -2
- package/build/workers/InlineFeaturesExtractor.web.d.ts.map +0 -1
- package/build/workers/InlineFeaturesExtractor.web.js +0 -828
- package/build/workers/InlineFeaturesExtractor.web.js.map +0 -1
- package/build/workers/inlineAudioWebWorker.web.d.ts +0 -2
- package/build/workers/inlineAudioWebWorker.web.d.ts.map +0 -1
- package/build/workers/inlineAudioWebWorker.web.js +0 -157
- package/build/workers/inlineAudioWebWorker.web.js.map +0 -1
- package/expo-module.config.json +0 -9
- package/ios/AudioAnalysisData.swift +0 -74
- package/ios/AudioNotificationManager.swift +0 -135
- package/ios/AudioProcessingHelpers.swift +0 -743
- package/ios/AudioProcessor.swift +0 -1313
- package/ios/AudioStreamError.swift +0 -7
- package/ios/AudioStreamManager.swift +0 -1708
- package/ios/AudioStreamManagerDelegate.swift +0 -16
- package/ios/DataPoint.swift +0 -54
- package/ios/DecodingConfig.swift +0 -47
- package/ios/ExpoAudioStream.podspec +0 -27
- package/ios/ExpoAudioStreamModule.swift +0 -805
- package/ios/FFT.swift +0 -62
- package/ios/Features.swift +0 -95
- package/ios/Logger.swift +0 -7
- package/ios/NotificationExtension.swift +0 -15
- package/ios/RecordingResult.swift +0 -22
- package/ios/RecordingSettings.swift +0 -265
- package/ios/WaveformExtractor.swift +0 -105
- package/plugin/build/index.d.ts +0 -21
- package/plugin/build/index.js +0 -191
- package/plugin/src/index.ts +0 -278
- package/plugin/tsconfig.json +0 -10
- package/plugin/tsconfig.tsbuildinfo +0 -1
- package/src/AudioAnalysis/AudioAnalysis.types.ts +0 -202
- package/src/AudioAnalysis/extractAudioAnalysis.ts +0 -333
- package/src/AudioAnalysis/extractAudioData.ts +0 -6
- package/src/AudioAnalysis/extractMelSpectrogram.ts +0 -144
- package/src/AudioAnalysis/extractPreview.ts +0 -34
- package/src/AudioAnalysis/extractWaveform.ts +0 -22
- package/src/AudioRecorder.provider.tsx +0 -54
- package/src/ExpoAudioStream.native.ts +0 -6
- package/src/ExpoAudioStream.types.ts +0 -641
- package/src/ExpoAudioStream.web.ts +0 -359
- package/src/ExpoAudioStreamModule.ts +0 -967
- package/src/WebRecorder.web.ts +0 -580
- package/src/constants.ts +0 -18
- package/src/events.ts +0 -60
- package/src/trimAudio.ts +0 -90
- package/src/useAudioRecorder.tsx +0 -620
- package/src/utils/BlobFix.ts +0 -559
- package/src/utils/audioProcessing.ts +0 -205
- package/src/utils/concatenateBuffers.ts +0 -24
- package/src/utils/convertPCMToFloat32.ts +0 -170
- package/src/utils/encodingToBitDepth.ts +0 -18
- package/src/utils/getWavFileInfo.ts +0 -132
- package/src/utils/writeWavHeader.ts +0 -114
- package/src/workers/InlineFeaturesExtractor.web.tsx +0 -827
- package/src/workers/inlineAudioWebWorker.web.tsx +0 -156
package/build/WebRecorder.web.js
DELETED
|
@@ -1,436 +0,0 @@
|
|
|
1
|
-
// packages/expo-audio-stream/src/WebRecorder.web.ts
|
|
2
|
-
import { encodingToBitDepth } from './utils/encodingToBitDepth';
|
|
3
|
-
import { InlineFeaturesExtractor } from './workers/InlineFeaturesExtractor.web';
|
|
4
|
-
import { InlineAudioWebWorker } from './workers/inlineAudioWebWorker.web';
|
|
5
|
-
const DEFAULT_WEB_BITDEPTH = 32;
|
|
6
|
-
const DEFAULT_SEGMENT_DURATION_MS = 100;
|
|
7
|
-
const DEFAULT_WEB_INTERVAL = 500;
|
|
8
|
-
const DEFAULT_WEB_NUMBER_OF_CHANNELS = 1;
|
|
9
|
-
const TAG = 'WebRecorder';
|
|
10
|
-
export class WebRecorder {
|
|
11
|
-
audioContext;
|
|
12
|
-
audioWorkletNode;
|
|
13
|
-
featureExtractorWorker;
|
|
14
|
-
source;
|
|
15
|
-
emitAudioEventCallback;
|
|
16
|
-
emitAudioAnalysisCallback;
|
|
17
|
-
config;
|
|
18
|
-
position = 0;
|
|
19
|
-
numberOfChannels; // Number of audio channels
|
|
20
|
-
bitDepth; // Bit depth of the audio
|
|
21
|
-
exportBitDepth; // Bit depth of the audio
|
|
22
|
-
audioAnalysisData; // Keep updating the full audio analysis data with latest events
|
|
23
|
-
packetCount = 0;
|
|
24
|
-
logger;
|
|
25
|
-
compressedMediaRecorder = null;
|
|
26
|
-
compressedChunks = [];
|
|
27
|
-
compressedSize = 0;
|
|
28
|
-
pendingCompressedChunk = null;
|
|
29
|
-
wavMimeType = 'audio/wav';
|
|
30
|
-
dataPointIdCounter = 0; // Add this property to track the counter
|
|
31
|
-
/**
|
|
32
|
-
* Initializes a new WebRecorder instance for audio recording and processing
|
|
33
|
-
* @param audioContext - The AudioContext to use for recording
|
|
34
|
-
* @param source - The MediaStreamAudioSourceNode providing the audio input
|
|
35
|
-
* @param recordingConfig - Configuration options for the recording
|
|
36
|
-
* @param emitAudioEventCallback - Callback function for audio data events
|
|
37
|
-
* @param emitAudioAnalysisCallback - Callback function for audio analysis events
|
|
38
|
-
* @param logger - Optional logger for debugging information
|
|
39
|
-
*/
|
|
40
|
-
constructor({ audioContext, source, recordingConfig, emitAudioEventCallback, emitAudioAnalysisCallback, logger, }) {
|
|
41
|
-
this.audioContext = audioContext;
|
|
42
|
-
this.source = source;
|
|
43
|
-
this.emitAudioEventCallback = emitAudioEventCallback;
|
|
44
|
-
this.emitAudioAnalysisCallback = emitAudioAnalysisCallback;
|
|
45
|
-
this.config = recordingConfig;
|
|
46
|
-
this.logger = logger;
|
|
47
|
-
const audioContextFormat = this.checkAudioContextFormat({
|
|
48
|
-
sampleRate: this.audioContext.sampleRate,
|
|
49
|
-
});
|
|
50
|
-
this.logger?.debug('Initialized WebRecorder with config:', {
|
|
51
|
-
sampleRate: audioContextFormat.sampleRate,
|
|
52
|
-
bitDepth: audioContextFormat.bitDepth,
|
|
53
|
-
numberOfChannels: audioContextFormat.numberOfChannels,
|
|
54
|
-
});
|
|
55
|
-
this.bitDepth = audioContextFormat.bitDepth;
|
|
56
|
-
this.numberOfChannels =
|
|
57
|
-
audioContextFormat.numberOfChannels ||
|
|
58
|
-
DEFAULT_WEB_NUMBER_OF_CHANNELS; // Default to 1 if not available
|
|
59
|
-
this.exportBitDepth =
|
|
60
|
-
encodingToBitDepth({
|
|
61
|
-
encoding: recordingConfig.encoding ?? 'pcm_32bit',
|
|
62
|
-
}) ||
|
|
63
|
-
audioContextFormat.bitDepth ||
|
|
64
|
-
DEFAULT_WEB_BITDEPTH;
|
|
65
|
-
this.audioAnalysisData = {
|
|
66
|
-
amplitudeRange: { min: 0, max: 0 },
|
|
67
|
-
rmsRange: { min: 0, max: 0 },
|
|
68
|
-
dataPoints: [],
|
|
69
|
-
durationMs: 0,
|
|
70
|
-
samples: 0,
|
|
71
|
-
bitDepth: this.bitDepth,
|
|
72
|
-
numberOfChannels: this.numberOfChannels,
|
|
73
|
-
sampleRate: this.config.sampleRate || this.audioContext.sampleRate,
|
|
74
|
-
segmentDurationMs: this.config.segmentDurationMs ?? DEFAULT_SEGMENT_DURATION_MS, // Default to 100ms segments
|
|
75
|
-
};
|
|
76
|
-
if (recordingConfig.enableProcessing) {
|
|
77
|
-
this.initFeatureExtractorWorker();
|
|
78
|
-
}
|
|
79
|
-
// Initialize compressed recording if enabled
|
|
80
|
-
if (recordingConfig.compression?.enabled) {
|
|
81
|
-
this.initializeCompressedRecorder();
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
/**
|
|
85
|
-
* Initializes the audio worklet using an inline script
|
|
86
|
-
* Creates and connects the audio processing pipeline
|
|
87
|
-
*/
|
|
88
|
-
async init() {
|
|
89
|
-
try {
|
|
90
|
-
// Create and use inline audio worklet
|
|
91
|
-
const blob = new Blob([InlineAudioWebWorker], {
|
|
92
|
-
type: 'application/javascript',
|
|
93
|
-
});
|
|
94
|
-
const url = URL.createObjectURL(blob);
|
|
95
|
-
await this.audioContext.audioWorklet.addModule(url);
|
|
96
|
-
this.audioWorkletNode = new AudioWorkletNode(this.audioContext, 'recorder-processor');
|
|
97
|
-
this.audioWorkletNode.port.onmessage = async (event) => {
|
|
98
|
-
const command = event.data.command;
|
|
99
|
-
if (command !== 'newData')
|
|
100
|
-
return;
|
|
101
|
-
const pcmBufferFloat = event.data.recordedData;
|
|
102
|
-
if (!pcmBufferFloat) {
|
|
103
|
-
this.logger?.warn('Received empty audio buffer', event);
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
// Process data in smaller chunks and emit immediately
|
|
107
|
-
const chunkSize = this.audioContext.sampleRate * 2; // Reduce to 2 seconds chunks
|
|
108
|
-
const sampleRate = event.data.sampleRate ?? this.audioContext.sampleRate;
|
|
109
|
-
const duration = pcmBufferFloat.length / sampleRate;
|
|
110
|
-
// Calculate bytes per sample based on bit depth
|
|
111
|
-
const bytesPerSample = this.bitDepth / 8;
|
|
112
|
-
// Emit chunks without storing them
|
|
113
|
-
for (let i = 0; i < pcmBufferFloat.length; i += chunkSize) {
|
|
114
|
-
const chunk = pcmBufferFloat.slice(i, i + chunkSize);
|
|
115
|
-
const chunkPosition = this.position + i / sampleRate;
|
|
116
|
-
// Calculate byte positions and samples
|
|
117
|
-
const startPosition = Math.floor(i * bytesPerSample);
|
|
118
|
-
const endPosition = Math.floor((i + chunk.length) * bytesPerSample);
|
|
119
|
-
const samples = chunk.length; // Number of samples in this chunk
|
|
120
|
-
// Process features if enabled
|
|
121
|
-
if (this.config.enableProcessing &&
|
|
122
|
-
this.featureExtractorWorker) {
|
|
123
|
-
this.featureExtractorWorker.postMessage({
|
|
124
|
-
command: 'process',
|
|
125
|
-
channelData: chunk,
|
|
126
|
-
sampleRate,
|
|
127
|
-
segmentDurationMs: this.config.segmentDurationMs ??
|
|
128
|
-
DEFAULT_SEGMENT_DURATION_MS, // Default to 100ms
|
|
129
|
-
bitDepth: this.bitDepth,
|
|
130
|
-
fullAudioDurationMs: chunkPosition * 1000,
|
|
131
|
-
numberOfChannels: this.numberOfChannels,
|
|
132
|
-
features: this.config.features,
|
|
133
|
-
intervalAnalysis: this.config.intervalAnalysis,
|
|
134
|
-
startPosition,
|
|
135
|
-
endPosition,
|
|
136
|
-
samples,
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
// Emit chunk immediately
|
|
140
|
-
this.emitAudioEventCallback({
|
|
141
|
-
data: chunk,
|
|
142
|
-
position: chunkPosition,
|
|
143
|
-
compression: this.pendingCompressedChunk
|
|
144
|
-
? {
|
|
145
|
-
data: this.pendingCompressedChunk,
|
|
146
|
-
size: this.pendingCompressedChunk.size,
|
|
147
|
-
totalSize: this.compressedSize,
|
|
148
|
-
mimeType: 'audio/webm',
|
|
149
|
-
format: 'opus',
|
|
150
|
-
bitrate: this.config.compression?.bitrate ??
|
|
151
|
-
128000,
|
|
152
|
-
}
|
|
153
|
-
: undefined,
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
this.position += duration;
|
|
157
|
-
this.pendingCompressedChunk = null;
|
|
158
|
-
};
|
|
159
|
-
this.logger?.debug(`WebRecorder initialized -- recordSampleRate=${this.audioContext.sampleRate}`, this.config);
|
|
160
|
-
this.audioWorkletNode.port.postMessage({
|
|
161
|
-
command: 'init',
|
|
162
|
-
recordSampleRate: this.audioContext.sampleRate,
|
|
163
|
-
exportSampleRate: this.config.sampleRate ?? this.audioContext.sampleRate,
|
|
164
|
-
bitDepth: this.bitDepth,
|
|
165
|
-
exportBitDepth: this.exportBitDepth,
|
|
166
|
-
channels: this.numberOfChannels,
|
|
167
|
-
interval: this.config.interval ?? DEFAULT_WEB_INTERVAL,
|
|
168
|
-
// enableLogging: !!this.logger,
|
|
169
|
-
});
|
|
170
|
-
// Connect the source to the AudioWorkletNode and start recording
|
|
171
|
-
this.source.connect(this.audioWorkletNode);
|
|
172
|
-
this.audioWorkletNode.connect(this.audioContext.destination);
|
|
173
|
-
}
|
|
174
|
-
catch (error) {
|
|
175
|
-
console.error(`[${TAG}] Failed to initialize WebRecorder`, error);
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
/**
|
|
179
|
-
* Initializes the feature extractor worker for audio analysis
|
|
180
|
-
* Creates an inline worker from a blob for audio feature extraction
|
|
181
|
-
*/
|
|
182
|
-
initFeatureExtractorWorker() {
|
|
183
|
-
try {
|
|
184
|
-
const blob = new Blob([InlineFeaturesExtractor], {
|
|
185
|
-
type: 'application/javascript',
|
|
186
|
-
});
|
|
187
|
-
const url = URL.createObjectURL(blob);
|
|
188
|
-
this.featureExtractorWorker = new Worker(url);
|
|
189
|
-
this.featureExtractorWorker.onmessage =
|
|
190
|
-
this.handleFeatureExtractorMessage.bind(this);
|
|
191
|
-
this.featureExtractorWorker.onerror = (error) => {
|
|
192
|
-
console.error(`[${TAG}] Feature extractor worker error:`, error);
|
|
193
|
-
};
|
|
194
|
-
this.logger?.log('Feature extractor worker initialized successfully');
|
|
195
|
-
}
|
|
196
|
-
catch (error) {
|
|
197
|
-
console.error(`[${TAG}] Failed to initialize feature extractor worker`, error);
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
/**
|
|
201
|
-
* Processes audio analysis results from the feature extractor worker
|
|
202
|
-
* Updates the audio analysis data and emits events
|
|
203
|
-
* @param event - The event containing audio analysis results
|
|
204
|
-
*/
|
|
205
|
-
handleFeatureExtractorMessage(event) {
|
|
206
|
-
if (event.data.command === 'features') {
|
|
207
|
-
const segmentResult = event.data.result;
|
|
208
|
-
// Update the dataPointIdCounter based on the last ID received
|
|
209
|
-
if (segmentResult.dataPoints &&
|
|
210
|
-
segmentResult.dataPoints.length > 0) {
|
|
211
|
-
const lastDataPoint = segmentResult.dataPoints[segmentResult.dataPoints.length - 1];
|
|
212
|
-
if (lastDataPoint && typeof lastDataPoint.id === 'number') {
|
|
213
|
-
this.dataPointIdCounter = Math.max(this.dataPointIdCounter, lastDataPoint.id + 1);
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
this.logger?.debug('[WebRecorder] Raw segment result:', {
|
|
217
|
-
dataPointsLength: segmentResult.dataPoints.length,
|
|
218
|
-
durationMs: segmentResult.durationMs,
|
|
219
|
-
sampleRate: segmentResult.sampleRate,
|
|
220
|
-
amplitudeRange: segmentResult.amplitudeRange,
|
|
221
|
-
});
|
|
222
|
-
// Ensure consistent sample rate in the result
|
|
223
|
-
segmentResult.sampleRate =
|
|
224
|
-
this.config.sampleRate || this.audioContext.sampleRate;
|
|
225
|
-
// Update the full audio analysis data with proper range merging
|
|
226
|
-
this.audioAnalysisData.dataPoints.push(...segmentResult.dataPoints);
|
|
227
|
-
this.audioAnalysisData.durationMs += segmentResult.durationMs;
|
|
228
|
-
// Make sure the sample rate is consistent
|
|
229
|
-
this.audioAnalysisData.sampleRate = segmentResult.sampleRate;
|
|
230
|
-
// Properly merge amplitude ranges
|
|
231
|
-
if (segmentResult.amplitudeRange) {
|
|
232
|
-
if (!this.audioAnalysisData.amplitudeRange) {
|
|
233
|
-
this.audioAnalysisData.amplitudeRange = {
|
|
234
|
-
...segmentResult.amplitudeRange,
|
|
235
|
-
};
|
|
236
|
-
}
|
|
237
|
-
else {
|
|
238
|
-
this.audioAnalysisData.amplitudeRange = {
|
|
239
|
-
min: Math.min(this.audioAnalysisData.amplitudeRange.min, segmentResult.amplitudeRange.min),
|
|
240
|
-
max: Math.max(this.audioAnalysisData.amplitudeRange.max, segmentResult.amplitudeRange.max),
|
|
241
|
-
};
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
// Properly merge RMS ranges
|
|
245
|
-
if (segmentResult.rmsRange) {
|
|
246
|
-
if (!this.audioAnalysisData.rmsRange) {
|
|
247
|
-
this.audioAnalysisData.rmsRange = {
|
|
248
|
-
...segmentResult.rmsRange,
|
|
249
|
-
};
|
|
250
|
-
}
|
|
251
|
-
else {
|
|
252
|
-
this.audioAnalysisData.rmsRange = {
|
|
253
|
-
min: Math.min(this.audioAnalysisData.rmsRange.min, segmentResult.rmsRange.min),
|
|
254
|
-
max: Math.max(this.audioAnalysisData.rmsRange.max, segmentResult.rmsRange.max),
|
|
255
|
-
};
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
this.logger?.debug('features event segmentResult', segmentResult);
|
|
259
|
-
this.logger?.debug(`features event audioAnalysisData duration=${this.audioAnalysisData.durationMs}`, this.audioAnalysisData);
|
|
260
|
-
this.emitAudioAnalysisCallback(segmentResult);
|
|
261
|
-
this.logger?.debug('[WebRecorder] Updated audioAnalysisData:', {
|
|
262
|
-
dataPointsLength: this.audioAnalysisData.dataPoints.length,
|
|
263
|
-
durationMs: this.audioAnalysisData.durationMs,
|
|
264
|
-
sampleRate: this.audioAnalysisData.sampleRate,
|
|
265
|
-
amplitudeRange: this.audioAnalysisData.amplitudeRange,
|
|
266
|
-
});
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
/**
|
|
270
|
-
* Resets the data point ID counter
|
|
271
|
-
* Used when starting a new recording
|
|
272
|
-
*/
|
|
273
|
-
resetDataPointCounter() {
|
|
274
|
-
this.dataPointIdCounter = 0;
|
|
275
|
-
// Reset the counter in the worker
|
|
276
|
-
if (this.featureExtractorWorker) {
|
|
277
|
-
this.featureExtractorWorker.postMessage({
|
|
278
|
-
command: 'resetCounter',
|
|
279
|
-
startCounterFrom: 0,
|
|
280
|
-
});
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
/**
|
|
284
|
-
* Starts the audio recording process
|
|
285
|
-
* Connects the audio nodes and begins capturing audio data
|
|
286
|
-
*/
|
|
287
|
-
start() {
|
|
288
|
-
this.source.connect(this.audioWorkletNode);
|
|
289
|
-
this.audioWorkletNode.connect(this.audioContext.destination);
|
|
290
|
-
this.packetCount = 0;
|
|
291
|
-
// Reset the counter when starting a new recording
|
|
292
|
-
this.resetDataPointCounter();
|
|
293
|
-
if (this.compressedMediaRecorder) {
|
|
294
|
-
this.compressedMediaRecorder.start(this.config.interval ?? 1000);
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
/**
|
|
298
|
-
* Stops the audio recording process and returns the recorded data
|
|
299
|
-
* @returns Promise resolving to an object containing PCM data and optional compressed blob
|
|
300
|
-
*/
|
|
301
|
-
async stop() {
|
|
302
|
-
try {
|
|
303
|
-
if (this.compressedMediaRecorder) {
|
|
304
|
-
this.compressedMediaRecorder.stop();
|
|
305
|
-
return {
|
|
306
|
-
pcmData: new Float32Array(), // Return empty array since we're streaming
|
|
307
|
-
compressedBlob: new Blob(this.compressedChunks, {
|
|
308
|
-
type: 'audio/webm;codecs=opus',
|
|
309
|
-
}),
|
|
310
|
-
};
|
|
311
|
-
}
|
|
312
|
-
return { pcmData: new Float32Array() };
|
|
313
|
-
}
|
|
314
|
-
finally {
|
|
315
|
-
this.cleanup();
|
|
316
|
-
// Reset the chunks array
|
|
317
|
-
this.compressedChunks = [];
|
|
318
|
-
this.compressedSize = 0;
|
|
319
|
-
this.pendingCompressedChunk = null;
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
/**
|
|
323
|
-
* Cleans up resources when recording is stopped
|
|
324
|
-
* Closes audio context and disconnects nodes
|
|
325
|
-
*/
|
|
326
|
-
cleanup() {
|
|
327
|
-
if (this.audioContext) {
|
|
328
|
-
this.audioContext.close();
|
|
329
|
-
}
|
|
330
|
-
if (this.audioWorkletNode) {
|
|
331
|
-
this.audioWorkletNode.disconnect();
|
|
332
|
-
}
|
|
333
|
-
if (this.source) {
|
|
334
|
-
this.source.disconnect();
|
|
335
|
-
}
|
|
336
|
-
this.stopMediaStreamTracks();
|
|
337
|
-
}
|
|
338
|
-
/**
|
|
339
|
-
* Pauses the audio recording process
|
|
340
|
-
* Disconnects audio nodes and pauses the media recorder
|
|
341
|
-
*/
|
|
342
|
-
pause() {
|
|
343
|
-
this.source.disconnect(this.audioWorkletNode); // Disconnect the source from the AudioWorkletNode
|
|
344
|
-
this.audioWorkletNode.disconnect(this.audioContext.destination); // Disconnect the AudioWorkletNode from the destination
|
|
345
|
-
this.audioWorkletNode.port.postMessage({ command: 'pause' });
|
|
346
|
-
this.compressedMediaRecorder?.pause();
|
|
347
|
-
}
|
|
348
|
-
/**
|
|
349
|
-
* Stops all media stream tracks to release hardware resources
|
|
350
|
-
* Ensures recording indicators (like microphone icon) are turned off
|
|
351
|
-
*/
|
|
352
|
-
stopMediaStreamTracks() {
|
|
353
|
-
// Stop all audio tracks to stop the recording icon
|
|
354
|
-
const tracks = this.source.mediaStream.getTracks();
|
|
355
|
-
tracks.forEach((track) => track.stop());
|
|
356
|
-
}
|
|
357
|
-
/**
|
|
358
|
-
* Determines the audio format capabilities of the current audio context
|
|
359
|
-
* @param sampleRate - The sample rate to check
|
|
360
|
-
* @returns Object containing format information (sample rate, bit depth, channels)
|
|
361
|
-
*/
|
|
362
|
-
checkAudioContextFormat({ sampleRate }) {
|
|
363
|
-
// Create a silent AudioBuffer
|
|
364
|
-
const frameCount = sampleRate * 1.0; // 1 second buffer
|
|
365
|
-
const audioBuffer = this.audioContext.createBuffer(1, frameCount, sampleRate);
|
|
366
|
-
// Check the format
|
|
367
|
-
const channelData = audioBuffer.getChannelData(0);
|
|
368
|
-
const bitDepth = channelData.BYTES_PER_ELEMENT * 8; // 4 bytes per element means 32-bit
|
|
369
|
-
return {
|
|
370
|
-
sampleRate: audioBuffer.sampleRate,
|
|
371
|
-
bitDepth,
|
|
372
|
-
numberOfChannels: audioBuffer.numberOfChannels,
|
|
373
|
-
};
|
|
374
|
-
}
|
|
375
|
-
/**
|
|
376
|
-
* Resumes a paused recording
|
|
377
|
-
* Reconnects audio nodes and resumes the media recorder
|
|
378
|
-
*/
|
|
379
|
-
resume() {
|
|
380
|
-
this.source.connect(this.audioWorkletNode);
|
|
381
|
-
this.audioWorkletNode.connect(this.audioContext.destination);
|
|
382
|
-
this.audioWorkletNode.port.postMessage({ command: 'resume' });
|
|
383
|
-
this.compressedMediaRecorder?.resume();
|
|
384
|
-
}
|
|
385
|
-
/**
|
|
386
|
-
* Initializes the compressed media recorder if compression is enabled
|
|
387
|
-
* Sets up event handlers for compressed audio data
|
|
388
|
-
*/
|
|
389
|
-
initializeCompressedRecorder() {
|
|
390
|
-
try {
|
|
391
|
-
const mimeType = 'audio/webm;codecs=opus';
|
|
392
|
-
if (!MediaRecorder.isTypeSupported(mimeType)) {
|
|
393
|
-
this.logger?.warn('Opus compression not supported in this browser');
|
|
394
|
-
return;
|
|
395
|
-
}
|
|
396
|
-
this.compressedMediaRecorder = new MediaRecorder(this.source.mediaStream, {
|
|
397
|
-
mimeType,
|
|
398
|
-
audioBitsPerSecond: this.config.compression?.bitrate ?? 128000,
|
|
399
|
-
});
|
|
400
|
-
this.compressedMediaRecorder.ondataavailable = (event) => {
|
|
401
|
-
if (event.data.size > 0) {
|
|
402
|
-
this.compressedChunks.push(event.data);
|
|
403
|
-
this.compressedSize += event.data.size;
|
|
404
|
-
this.pendingCompressedChunk = event.data;
|
|
405
|
-
}
|
|
406
|
-
};
|
|
407
|
-
}
|
|
408
|
-
catch (error) {
|
|
409
|
-
this.logger?.error('Failed to initialize compressed recorder:', error);
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
/**
|
|
413
|
-
* Processes features if enabled
|
|
414
|
-
*/
|
|
415
|
-
processFeatures(chunk, sampleRate, chunkPosition, startPosition, endPosition, samples) {
|
|
416
|
-
if (this.config.enableProcessing && this.featureExtractorWorker) {
|
|
417
|
-
this.featureExtractorWorker.postMessage({
|
|
418
|
-
command: 'process',
|
|
419
|
-
channelData: chunk,
|
|
420
|
-
sampleRate,
|
|
421
|
-
segmentDurationMs: this.config.segmentDurationMs ??
|
|
422
|
-
DEFAULT_SEGMENT_DURATION_MS, // Default to 100ms
|
|
423
|
-
bitDepth: this.bitDepth,
|
|
424
|
-
fullAudioDurationMs: chunkPosition * 1000,
|
|
425
|
-
numberOfChannels: this.numberOfChannels,
|
|
426
|
-
features: this.config.features,
|
|
427
|
-
intervalAnalysis: this.config.intervalAnalysis,
|
|
428
|
-
startPosition,
|
|
429
|
-
endPosition,
|
|
430
|
-
samples,
|
|
431
|
-
startCounterFrom: this.dataPointIdCounter, // Pass the current counter value
|
|
432
|
-
});
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
//# sourceMappingURL=WebRecorder.web.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"WebRecorder.web.js","sourceRoot":"","sources":["../src/WebRecorder.web.ts"],"names":[],"mappings":"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","sourcesContent":["// packages/expo-audio-stream/src/WebRecorder.web.ts\n\nimport { AudioAnalysis } from './AudioAnalysis/AudioAnalysis.types'\nimport { ConsoleLike, RecordingConfig } from './ExpoAudioStream.types'\nimport {\n EmitAudioAnalysisFunction,\n EmitAudioEventFunction,\n} from './ExpoAudioStream.web'\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_SEGMENT_DURATION_MS = 100\nconst DEFAULT_WEB_INTERVAL = 500\nconst DEFAULT_WEB_NUMBER_OF_CHANNELS = 1\n\nconst TAG = 'WebRecorder'\n\nexport class WebRecorder {\n private audioContext: AudioContext\n private audioWorkletNode!: AudioWorkletNode\n private featureExtractorWorker?: Worker\n private source: MediaStreamAudioSourceNode\n private emitAudioEventCallback: EmitAudioEventFunction\n private emitAudioAnalysisCallback: EmitAudioAnalysisFunction\n private config: RecordingConfig\n private position: number = 0\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 audioAnalysisData: AudioAnalysis // Keep updating the full audio analysis data with latest events\n private packetCount: number = 0\n private logger?: ConsoleLike\n private compressedMediaRecorder: MediaRecorder | null = null\n private compressedChunks: Blob[] = []\n private compressedSize: number = 0\n private pendingCompressedChunk: Blob | null = null\n private readonly wavMimeType = 'audio/wav'\n private dataPointIdCounter: number = 0 // Add this property to track the counter\n\n /**\n * Initializes a new WebRecorder instance for audio recording and processing\n * @param audioContext - The AudioContext to use for recording\n * @param source - The MediaStreamAudioSourceNode providing the audio input\n * @param recordingConfig - Configuration options for the recording\n * @param emitAudioEventCallback - Callback function for audio data events\n * @param emitAudioAnalysisCallback - Callback function for audio analysis events\n * @param logger - Optional logger for debugging information\n */\n constructor({\n audioContext,\n source,\n recordingConfig,\n emitAudioEventCallback,\n emitAudioAnalysisCallback,\n logger,\n }: {\n audioContext: AudioContext\n source: MediaStreamAudioSourceNode\n recordingConfig: RecordingConfig\n emitAudioEventCallback: EmitAudioEventFunction\n emitAudioAnalysisCallback: EmitAudioAnalysisFunction\n logger?: ConsoleLike\n }) {\n this.audioContext = audioContext\n this.source = source\n this.emitAudioEventCallback = emitAudioEventCallback\n this.emitAudioAnalysisCallback = emitAudioAnalysisCallback\n this.config = recordingConfig\n this.logger = logger\n\n const audioContextFormat = this.checkAudioContextFormat({\n sampleRate: this.audioContext.sampleRate,\n })\n this.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 rmsRange: { 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 segmentDurationMs:\n this.config.segmentDurationMs ?? DEFAULT_SEGMENT_DURATION_MS, // Default to 100ms segments\n }\n\n if (recordingConfig.enableProcessing) {\n this.initFeatureExtractorWorker()\n }\n\n // Initialize compressed recording if enabled\n if (recordingConfig.compression?.enabled) {\n this.initializeCompressedRecorder()\n }\n }\n\n /**\n * Initializes the audio worklet using an inline script\n * Creates and connects the audio processing pipeline\n */\n async init() {\n try {\n // Create and use inline audio worklet\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\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') return\n\n const pcmBufferFloat = event.data.recordedData\n if (!pcmBufferFloat) {\n this.logger?.warn('Received empty audio buffer', event)\n return\n }\n\n // Process data in smaller chunks and emit immediately\n const chunkSize = this.audioContext.sampleRate * 2 // Reduce to 2 seconds chunks\n const sampleRate =\n event.data.sampleRate ?? this.audioContext.sampleRate\n const duration = pcmBufferFloat.length / sampleRate\n\n // Calculate bytes per sample based on bit depth\n const bytesPerSample = this.bitDepth / 8\n\n // Emit chunks without storing them\n for (let i = 0; i < pcmBufferFloat.length; i += chunkSize) {\n const chunk = pcmBufferFloat.slice(i, i + chunkSize)\n const chunkPosition = this.position + i / sampleRate\n\n // Calculate byte positions and samples\n const startPosition = Math.floor(i * bytesPerSample)\n const endPosition = Math.floor(\n (i + chunk.length) * bytesPerSample\n )\n const samples = chunk.length // Number of samples in this chunk\n\n // Process features if enabled\n if (\n this.config.enableProcessing &&\n this.featureExtractorWorker\n ) {\n this.featureExtractorWorker.postMessage({\n command: 'process',\n channelData: chunk,\n sampleRate,\n segmentDurationMs:\n this.config.segmentDurationMs ??\n DEFAULT_SEGMENT_DURATION_MS, // Default to 100ms\n bitDepth: this.bitDepth,\n fullAudioDurationMs: chunkPosition * 1000,\n numberOfChannels: this.numberOfChannels,\n features: this.config.features,\n intervalAnalysis: this.config.intervalAnalysis,\n startPosition,\n endPosition,\n samples,\n })\n }\n\n // Emit chunk immediately\n this.emitAudioEventCallback({\n data: chunk,\n position: chunkPosition,\n compression: this.pendingCompressedChunk\n ? {\n data: this.pendingCompressedChunk,\n size: this.pendingCompressedChunk.size,\n totalSize: this.compressedSize,\n mimeType: 'audio/webm',\n format: 'opus',\n bitrate:\n this.config.compression?.bitrate ??\n 128000,\n }\n : undefined,\n })\n }\n\n this.position += duration\n this.pendingCompressedChunk = null\n }\n\n this.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,\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 // enableLogging: !!this.logger,\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 /**\n * Initializes the feature extractor worker for audio analysis\n * Creates an inline worker from a blob for audio feature extraction\n */\n initFeatureExtractorWorker() {\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}] Feature extractor worker error:`, error)\n }\n this.logger?.log(\n 'Feature extractor worker initialized successfully'\n )\n } catch (error) {\n console.error(\n `[${TAG}] Failed to initialize feature extractor worker`,\n error\n )\n }\n }\n\n /**\n * Processes audio analysis results from the feature extractor worker\n * Updates the audio analysis data and emits events\n * @param event - The event containing audio analysis results\n */\n handleFeatureExtractorMessage(event: AudioFeaturesEvent) {\n if (event.data.command === 'features') {\n const segmentResult = event.data.result\n\n // Update the dataPointIdCounter based on the last ID received\n if (\n segmentResult.dataPoints &&\n segmentResult.dataPoints.length > 0\n ) {\n const lastDataPoint =\n segmentResult.dataPoints[\n segmentResult.dataPoints.length - 1\n ]\n if (lastDataPoint && typeof lastDataPoint.id === 'number') {\n this.dataPointIdCounter = Math.max(\n this.dataPointIdCounter,\n lastDataPoint.id + 1\n )\n }\n }\n\n this.logger?.debug('[WebRecorder] Raw segment result:', {\n dataPointsLength: segmentResult.dataPoints.length,\n durationMs: segmentResult.durationMs,\n sampleRate: segmentResult.sampleRate,\n amplitudeRange: segmentResult.amplitudeRange,\n })\n\n // Ensure consistent sample rate in the result\n segmentResult.sampleRate =\n this.config.sampleRate || this.audioContext.sampleRate\n\n // Update the full audio analysis data with proper range merging\n this.audioAnalysisData.dataPoints.push(...segmentResult.dataPoints)\n this.audioAnalysisData.durationMs += segmentResult.durationMs\n\n // Make sure the sample rate is consistent\n this.audioAnalysisData.sampleRate = segmentResult.sampleRate\n\n // Properly merge amplitude ranges\n if (segmentResult.amplitudeRange) {\n if (!this.audioAnalysisData.amplitudeRange) {\n this.audioAnalysisData.amplitudeRange = {\n ...segmentResult.amplitudeRange,\n }\n } else {\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 }\n\n // Properly merge RMS ranges\n if (segmentResult.rmsRange) {\n if (!this.audioAnalysisData.rmsRange) {\n this.audioAnalysisData.rmsRange = {\n ...segmentResult.rmsRange,\n }\n } else {\n this.audioAnalysisData.rmsRange = {\n min: Math.min(\n this.audioAnalysisData.rmsRange.min,\n segmentResult.rmsRange.min\n ),\n max: Math.max(\n this.audioAnalysisData.rmsRange.max,\n segmentResult.rmsRange.max\n ),\n }\n }\n }\n\n this.logger?.debug('features event segmentResult', segmentResult)\n this.logger?.debug(\n `features event audioAnalysisData duration=${this.audioAnalysisData.durationMs}`,\n this.audioAnalysisData\n )\n this.emitAudioAnalysisCallback(segmentResult)\n\n this.logger?.debug('[WebRecorder] Updated audioAnalysisData:', {\n dataPointsLength: this.audioAnalysisData.dataPoints.length,\n durationMs: this.audioAnalysisData.durationMs,\n sampleRate: this.audioAnalysisData.sampleRate,\n amplitudeRange: this.audioAnalysisData.amplitudeRange,\n })\n }\n }\n\n /**\n * Resets the data point ID counter\n * Used when starting a new recording\n */\n resetDataPointCounter() {\n this.dataPointIdCounter = 0\n\n // Reset the counter in the worker\n if (this.featureExtractorWorker) {\n this.featureExtractorWorker.postMessage({\n command: 'resetCounter',\n startCounterFrom: 0,\n })\n }\n }\n\n /**\n * Starts the audio recording process\n * Connects the audio nodes and begins capturing audio data\n */\n start() {\n this.source.connect(this.audioWorkletNode)\n this.audioWorkletNode.connect(this.audioContext.destination)\n this.packetCount = 0\n\n // Reset the counter when starting a new recording\n this.resetDataPointCounter()\n\n if (this.compressedMediaRecorder) {\n this.compressedMediaRecorder.start(this.config.interval ?? 1000)\n }\n }\n\n /**\n * Stops the audio recording process and returns the recorded data\n * @returns Promise resolving to an object containing PCM data and optional compressed blob\n */\n async stop(): Promise<{ pcmData: Float32Array; compressedBlob?: Blob }> {\n try {\n if (this.compressedMediaRecorder) {\n this.compressedMediaRecorder.stop()\n return {\n pcmData: new Float32Array(), // Return empty array since we're streaming\n compressedBlob: new Blob(this.compressedChunks, {\n type: 'audio/webm;codecs=opus',\n }),\n }\n }\n return { pcmData: new Float32Array() }\n } finally {\n this.cleanup()\n // Reset the chunks array\n this.compressedChunks = []\n this.compressedSize = 0\n this.pendingCompressedChunk = null\n }\n }\n\n /**\n * Cleans up resources when recording is stopped\n * Closes audio context and disconnects nodes\n */\n private cleanup() {\n if (this.audioContext) {\n this.audioContext.close()\n }\n if (this.audioWorkletNode) {\n this.audioWorkletNode.disconnect()\n }\n if (this.source) {\n this.source.disconnect()\n }\n this.stopMediaStreamTracks()\n }\n\n /**\n * Pauses the audio recording process\n * Disconnects audio nodes and pauses the media recorder\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 this.compressedMediaRecorder?.pause()\n }\n\n /**\n * Stops all media stream tracks to release hardware resources\n * Ensures recording indicators (like microphone icon) are turned off\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 /**\n * Determines the audio format capabilities of the current audio context\n * @param sampleRate - The sample rate to check\n * @returns Object containing format information (sample rate, bit depth, channels)\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 /**\n * Resumes a paused recording\n * Reconnects audio nodes and resumes the media recorder\n */\n resume() {\n this.source.connect(this.audioWorkletNode)\n this.audioWorkletNode.connect(this.audioContext.destination)\n this.audioWorkletNode.port.postMessage({ command: 'resume' })\n this.compressedMediaRecorder?.resume()\n }\n\n /**\n * Initializes the compressed media recorder if compression is enabled\n * Sets up event handlers for compressed audio data\n */\n private initializeCompressedRecorder() {\n try {\n const mimeType = 'audio/webm;codecs=opus'\n if (!MediaRecorder.isTypeSupported(mimeType)) {\n this.logger?.warn(\n 'Opus compression not supported in this browser'\n )\n return\n }\n\n this.compressedMediaRecorder = new MediaRecorder(\n this.source.mediaStream,\n {\n mimeType,\n audioBitsPerSecond:\n this.config.compression?.bitrate ?? 128000,\n }\n )\n\n this.compressedMediaRecorder.ondataavailable = (event) => {\n if (event.data.size > 0) {\n this.compressedChunks.push(event.data)\n this.compressedSize += event.data.size\n this.pendingCompressedChunk = event.data\n }\n }\n } catch (error) {\n this.logger?.error(\n 'Failed to initialize compressed recorder:',\n error\n )\n }\n }\n\n /**\n * Processes features if enabled\n */\n processFeatures(\n chunk: Float32Array,\n sampleRate: number,\n chunkPosition: number,\n startPosition: number,\n endPosition: number,\n samples: number\n ) {\n if (this.config.enableProcessing && this.featureExtractorWorker) {\n this.featureExtractorWorker.postMessage({\n command: 'process',\n channelData: chunk,\n sampleRate,\n segmentDurationMs:\n this.config.segmentDurationMs ??\n DEFAULT_SEGMENT_DURATION_MS, // Default to 100ms\n bitDepth: this.bitDepth,\n fullAudioDurationMs: chunkPosition * 1000,\n numberOfChannels: this.numberOfChannels,\n features: this.config.features,\n intervalAnalysis: this.config.intervalAnalysis,\n startPosition,\n endPosition,\n samples,\n startCounterFrom: this.dataPointIdCounter, // Pass the current counter value\n })\n }\n }\n}\n"]}
|
package/build/constants.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { BitDepth, SampleRate } from './ExpoAudioStream.types';
|
|
2
|
-
export declare const isWeb: boolean;
|
|
3
|
-
export declare const DEBUG_NAMESPACE = "expo-audio-stream";
|
|
4
|
-
export declare const RIFF_HEADER = 1380533830;
|
|
5
|
-
export declare const WAVE_HEADER = 1463899717;
|
|
6
|
-
export declare const FMT_CHUNK_ID = 1718449184;
|
|
7
|
-
export declare const DATA_CHUNK_ID = 1684108385;
|
|
8
|
-
export declare const INFO_CHUNK_ID = 1229866575;
|
|
9
|
-
export declare const DEFAULT_SAMPLE_RATE: SampleRate;
|
|
10
|
-
export declare const DEFAULT_BIT_DEPTH: BitDepth;
|
|
11
|
-
//# sourceMappingURL=constants.d.ts.map
|
package/build/constants.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
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
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
// packages/expo-audio-stream/src/constants.ts
|
|
2
|
-
import { Platform } from 'react-native';
|
|
3
|
-
export const isWeb = Platform.OS === 'web';
|
|
4
|
-
export const DEBUG_NAMESPACE = 'expo-audio-stream';
|
|
5
|
-
// Constants for identifying chunks in a WAV file
|
|
6
|
-
export const RIFF_HEADER = 0x52494646; // "RIFF"
|
|
7
|
-
export const WAVE_HEADER = 0x57415645; // "WAVE"
|
|
8
|
-
export const FMT_CHUNK_ID = 0x666d7420; // "fmt "
|
|
9
|
-
export const DATA_CHUNK_ID = 0x64617461; // "data"
|
|
10
|
-
export const INFO_CHUNK_ID = 0x494e464f; // "INFO"
|
|
11
|
-
// Default values
|
|
12
|
-
export const DEFAULT_SAMPLE_RATE = 16000;
|
|
13
|
-
export const DEFAULT_BIT_DEPTH = 32;
|
|
14
|
-
//# sourceMappingURL=constants.js.map
|
package/build/constants.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
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
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { type EventSubscription } from 'expo-modules-core';
|
|
2
|
-
import { AudioAnalysis } from './AudioAnalysis/AudioAnalysis.types';
|
|
3
|
-
import { RecordingInterruptionEvent } from './ExpoAudioStream.types';
|
|
4
|
-
export interface AudioEventPayload {
|
|
5
|
-
encoded?: string;
|
|
6
|
-
buffer?: Float32Array;
|
|
7
|
-
fileUri: string;
|
|
8
|
-
lastEmittedSize: number;
|
|
9
|
-
position: number;
|
|
10
|
-
deltaSize: number;
|
|
11
|
-
totalSize: number;
|
|
12
|
-
mimeType: string;
|
|
13
|
-
streamUuid: string;
|
|
14
|
-
compression?: {
|
|
15
|
-
data?: string | Blob;
|
|
16
|
-
position: number;
|
|
17
|
-
eventDataSize: number;
|
|
18
|
-
totalSize: number;
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
export declare function addAudioEventListener(listener: (event: AudioEventPayload) => Promise<void>): EventSubscription;
|
|
22
|
-
export interface AudioAnalysisEvent extends AudioAnalysis {
|
|
23
|
-
}
|
|
24
|
-
export declare function addAudioAnalysisListener(listener: (event: AudioAnalysisEvent) => Promise<void>): EventSubscription;
|
|
25
|
-
export declare function addRecordingInterruptionListener(listener: (event: RecordingInterruptionEvent) => void): EventSubscription;
|
|
26
|
-
//# sourceMappingURL=events.d.ts.map
|
package/build/events.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAEA,OAAO,EAAsB,KAAK,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAE9E,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAA;AACnE,OAAO,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAA;AAMpE,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;IAClB,WAAW,CAAC,EAAE;QACV,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;QACpB,QAAQ,EAAE,MAAM,CAAA;QAChB,aAAa,EAAE,MAAM,CAAA;QACrB,SAAS,EAAE,MAAM,CAAA;KACpB,CAAA;CACJ;AAED,wBAAgB,qBAAqB,CACjC,QAAQ,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,OAAO,CAAC,IAAI,CAAC,GACtD,iBAAiB,CAEnB;AAGD,MAAM,WAAW,kBAAmB,SAAQ,aAAa;CAAG;AAE5D,wBAAgB,wBAAwB,CACpC,QAAQ,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,OAAO,CAAC,IAAI,CAAC,GACvD,iBAAiB,CAEnB;AAED,wBAAgB,gCAAgC,CAC5C,QAAQ,EAAE,CAAC,KAAK,EAAE,0BAA0B,KAAK,IAAI,GACtD,iBAAiB,CAanB"}
|
package/build/events.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
// packages/expo-audio-stream/src/events.ts
|
|
2
|
-
import { LegacyEventEmitter } from 'expo-modules-core';
|
|
3
|
-
import ExpoAudioStreamModule from './ExpoAudioStreamModule';
|
|
4
|
-
const emitter = new LegacyEventEmitter(ExpoAudioStreamModule);
|
|
5
|
-
export function addAudioEventListener(listener) {
|
|
6
|
-
return emitter.addListener('AudioData', listener);
|
|
7
|
-
}
|
|
8
|
-
export function addAudioAnalysisListener(listener) {
|
|
9
|
-
return emitter.addListener('AudioAnalysis', listener);
|
|
10
|
-
}
|
|
11
|
-
export function addRecordingInterruptionListener(listener) {
|
|
12
|
-
// Add debug logging
|
|
13
|
-
console.debug('Adding recording interruption listener');
|
|
14
|
-
const subscription = emitter.addListener('onRecordingInterrupted', // Make sure this matches the native event name
|
|
15
|
-
(event) => {
|
|
16
|
-
console.debug('Recording interruption event received:', event);
|
|
17
|
-
listener(event);
|
|
18
|
-
});
|
|
19
|
-
return subscription;
|
|
20
|
-
}
|
|
21
|
-
//# sourceMappingURL=events.js.map
|
package/build/events.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAE3C,OAAO,EAAE,kBAAkB,EAA0B,MAAM,mBAAmB,CAAA;AAI9E,OAAO,qBAAqB,MAAM,yBAAyB,CAAA;AAE3D,MAAM,OAAO,GAAG,IAAI,kBAAkB,CAAC,qBAAqB,CAAC,CAAA;AAqB7D,MAAM,UAAU,qBAAqB,CACjC,QAAqD;IAErD,OAAO,OAAO,CAAC,WAAW,CAAoB,WAAW,EAAE,QAAQ,CAAC,CAAA;AACxE,CAAC;AAKD,MAAM,UAAU,wBAAwB,CACpC,QAAsD;IAEtD,OAAO,OAAO,CAAC,WAAW,CAAqB,eAAe,EAAE,QAAQ,CAAC,CAAA;AAC7E,CAAC;AAED,MAAM,UAAU,gCAAgC,CAC5C,QAAqD;IAErD,oBAAoB;IACpB,OAAO,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAA;IAEvD,MAAM,YAAY,GAAG,OAAO,CAAC,WAAW,CACpC,wBAAwB,EAAE,+CAA+C;IACzE,CAAC,KAAK,EAAE,EAAE;QACN,OAAO,CAAC,KAAK,CAAC,wCAAwC,EAAE,KAAK,CAAC,CAAA;QAC9D,QAAQ,CAAC,KAAK,CAAC,CAAA;IACnB,CAAC,CACJ,CAAA;IAED,OAAO,YAAY,CAAA;AACvB,CAAC","sourcesContent":["// packages/expo-audio-stream/src/events.ts\n\nimport { LegacyEventEmitter, type EventSubscription } from 'expo-modules-core'\n\nimport { AudioAnalysis } from './AudioAnalysis/AudioAnalysis.types'\nimport { RecordingInterruptionEvent } from './ExpoAudioStream.types'\nimport ExpoAudioStreamModule from './ExpoAudioStreamModule'\n\nconst emitter = new LegacyEventEmitter(ExpoAudioStreamModule)\n\n// Internal event payload from native module\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 compression?: {\n data?: string | Blob // Base64 (native) or Float32Array (web) encoded compressed data chunk\n position: number\n eventDataSize: number\n totalSize: number\n }\n}\n\nexport function addAudioEventListener(\n listener: (event: AudioEventPayload) => Promise<void>\n): EventSubscription {\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): EventSubscription {\n return emitter.addListener<AudioAnalysisEvent>('AudioAnalysis', listener)\n}\n\nexport function addRecordingInterruptionListener(\n listener: (event: RecordingInterruptionEvent) => void\n): EventSubscription {\n // Add debug logging\n console.debug('Adding recording interruption listener')\n\n const subscription = emitter.addListener<RecordingInterruptionEvent>(\n 'onRecordingInterrupted', // Make sure this matches the native event name\n (event) => {\n console.debug('Recording interruption event received:', event)\n listener(event)\n }\n )\n\n return subscription\n}\n"]}
|
package/build/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACH,qBAAqB,EACrB,oBAAoB,EACvB,MAAM,sCAAsC,CAAA;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAA;AACnE,OAAO,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAA;AAC7E,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AAC/D,OAAO,EACH,qBAAqB,EACrB,sBAAsB,EACzB,MAAM,0BAA0B,CAAA;AACjC,OAAO,qBAAqB,MAAM,yBAAyB,CAAA;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAErD,cAAc,6BAA6B,CAAA;AAC3C,cAAc,wBAAwB,CAAA;AACtC,cAAc,wBAAwB,CAAA;AAEtC,OAAO,EACH,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,oBAAoB,EACpB,cAAc,EACd,SAAS,EACT,gBAAgB,EAChB,qBAAqB,EACrB,gBAAgB,EAChB,sBAAsB,GACzB,CAAA;AAED,mBAAmB,qCAAqC,CAAA;AACxD,mBAAmB,yBAAyB,CAAA"}
|
package/build/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,eAAe;AAEf,OAAO,EACH,qBAAqB,EACrB,oBAAoB,GACvB,MAAM,sCAAsC,CAAA;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAA;AACnE,OAAO,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAA;AAC7E,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AAC/D,OAAO,EACH,qBAAqB,EACrB,sBAAsB,GACzB,MAAM,0BAA0B,CAAA;AACjC,OAAO,qBAAqB,MAAM,yBAAyB,CAAA;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAErD,cAAc,6BAA6B,CAAA;AAC3C,cAAc,wBAAwB,CAAA;AACtC,cAAc,wBAAwB,CAAA;AAEtC,OAAO,EACH,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,oBAAoB,EACpB,cAAc,EACd,SAAS,EACT,gBAAgB,EAChB,qBAAqB,EACrB,gBAAgB,EAChB,sBAAsB,GACzB,CAAA","sourcesContent":["// src/index.ts\n\nimport {\n extractRawWavAnalysis,\n extractAudioAnalysis,\n} from './AudioAnalysis/extractAudioAnalysis'\nimport { extractAudioData } from './AudioAnalysis/extractAudioData'\nimport { extractMelSpectrogram } from './AudioAnalysis/extractMelSpectrogram'\nimport { extractPreview } from './AudioAnalysis/extractPreview'\nimport {\n AudioRecorderProvider,\n useSharedAudioRecorder,\n} from './AudioRecorder.provider'\nimport ExpoAudioStreamModule from './ExpoAudioStreamModule'\nimport { trimAudio } from './trimAudio'\nimport { useAudioRecorder } from './useAudioRecorder'\n\nexport * from './utils/convertPCMToFloat32'\nexport * from './utils/getWavFileInfo'\nexport * from './utils/writeWavHeader'\n\nexport {\n AudioRecorderProvider,\n ExpoAudioStreamModule,\n extractRawWavAnalysis,\n extractAudioAnalysis,\n extractPreview,\n trimAudio,\n extractAudioData,\n extractMelSpectrogram,\n useAudioRecorder,\n useSharedAudioRecorder,\n}\n\nexport type * from './AudioAnalysis/AudioAnalysis.types'\nexport type * from './ExpoAudioStream.types'\n"]}
|