@siteed/expo-audio-stream 1.5.2 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -36
- package/build/AudioAnalysis/AudioAnalysis.types.d.ts +74 -0
- package/build/AudioAnalysis/AudioAnalysis.types.d.ts.map +1 -0
- package/build/AudioAnalysis/AudioAnalysis.types.js +3 -0
- package/build/AudioAnalysis/AudioAnalysis.types.js.map +1 -0
- package/build/AudioAnalysis/extractAudioAnalysis.d.ts +22 -0
- package/build/AudioAnalysis/extractAudioAnalysis.d.ts.map +1 -0
- package/build/AudioAnalysis/extractAudioAnalysis.js +86 -0
- package/build/AudioAnalysis/extractAudioAnalysis.js.map +1 -0
- package/build/AudioAnalysis/extractWaveform.d.ts +8 -0
- package/build/AudioAnalysis/extractWaveform.d.ts.map +1 -0
- package/build/AudioAnalysis/extractWaveform.js +11 -0
- package/build/AudioAnalysis/extractWaveform.js.map +1 -0
- package/build/AudioRecorder.provider.d.ts +11 -0
- package/build/AudioRecorder.provider.d.ts.map +1 -0
- package/build/AudioRecorder.provider.js +36 -0
- package/build/AudioRecorder.provider.js.map +1 -0
- package/build/ExpoAudioStream.native.d.ts +3 -0
- package/build/ExpoAudioStream.native.d.ts.map +1 -0
- package/build/ExpoAudioStream.native.js +6 -0
- package/build/ExpoAudioStream.native.js.map +1 -0
- package/build/ExpoAudioStream.types.d.ts +127 -0
- package/build/ExpoAudioStream.types.d.ts.map +1 -0
- package/build/ExpoAudioStream.types.js +2 -0
- package/build/ExpoAudioStream.types.js.map +1 -0
- package/build/ExpoAudioStream.web.d.ts +44 -0
- package/build/ExpoAudioStream.web.d.ts.map +1 -0
- package/build/ExpoAudioStream.web.js +206 -0
- package/build/ExpoAudioStream.web.js.map +1 -0
- package/build/ExpoAudioStreamModule.d.ts +3 -0
- package/build/ExpoAudioStreamModule.d.ts.map +1 -0
- package/build/ExpoAudioStreamModule.js +35 -0
- package/build/ExpoAudioStreamModule.js.map +1 -0
- package/build/WebRecorder.web.d.ts +54 -0
- package/build/WebRecorder.web.d.ts.map +1 -0
- package/build/WebRecorder.web.js +336 -0
- package/build/WebRecorder.web.js.map +1 -0
- package/build/constants.d.ts +11 -0
- package/build/constants.d.ts.map +1 -0
- package/build/constants.js +14 -0
- package/build/constants.js.map +1 -0
- package/build/events.d.ts +18 -0
- package/build/events.d.ts.map +1 -0
- package/build/events.js +11 -0
- package/build/events.js.map +1 -0
- package/build/index.d.ts +11 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js.map +1 -0
- package/build/useAudioRecorder.d.ts +20 -0
- package/build/useAudioRecorder.d.ts.map +1 -0
- package/build/useAudioRecorder.js +311 -0
- package/build/useAudioRecorder.js.map +1 -0
- package/build/utils/BlobFix.d.ts +9 -0
- package/build/utils/BlobFix.d.ts.map +1 -0
- package/build/utils/BlobFix.js +498 -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 +13 -0
- package/build/utils/convertPCMToFloat32.d.ts.map +1 -0
- package/build/utils/convertPCMToFloat32.js +120 -0
- package/build/utils/convertPCMToFloat32.js.map +1 -0
- package/build/utils/encodingToBitDepth.d.ts +5 -0
- package/build/utils/encodingToBitDepth.d.ts.map +1 -0
- package/build/utils/encodingToBitDepth.js +13 -0
- package/build/utils/encodingToBitDepth.js.map +1 -0
- package/build/utils/getWavFileInfo.d.ts +26 -0
- package/build/utils/getWavFileInfo.d.ts.map +1 -0
- package/build/utils/getWavFileInfo.js +92 -0
- package/build/utils/getWavFileInfo.js.map +1 -0
- package/build/utils/writeWavHeader.d.ts +49 -0
- package/build/utils/writeWavHeader.d.ts.map +1 -0
- package/build/utils/writeWavHeader.js +91 -0
- package/build/utils/writeWavHeader.js.map +1 -0
- package/build/workers/InlineFeaturesExtractor.web.d.ts +2 -0
- package/build/workers/InlineFeaturesExtractor.web.d.ts.map +1 -0
- package/build/workers/InlineFeaturesExtractor.web.js +311 -0
- package/build/workers/InlineFeaturesExtractor.web.js.map +1 -0
- package/build/workers/inlineAudioWebWorker.web.d.ts +2 -0
- package/build/workers/inlineAudioWebWorker.web.d.ts.map +1 -0
- package/build/workers/inlineAudioWebWorker.web.js +251 -0
- package/build/workers/inlineAudioWebWorker.web.js.map +1 -0
- package/expo-module.config.json +9 -0
- package/package.json +6 -2
- package/plugin/build/index.d.ts +3 -0
- package/plugin/build/index.js +132 -0
- package/plugin/src/index.ts +176 -0
- package/plugin/tsconfig.json +10 -0
- package/plugin/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { LegacyEventEmitter } from 'expo-modules-core';
|
|
2
|
+
import { AudioAnalysis } from './AudioAnalysis/AudioAnalysis.types';
|
|
3
|
+
import { AudioRecording, AudioStreamStatus, BitDepth, ConsoleLike, RecordingConfig, StartRecordingResult } from './ExpoAudioStream.types';
|
|
4
|
+
import { WebRecorder } from './WebRecorder.web';
|
|
5
|
+
export interface EmitAudioEventProps {
|
|
6
|
+
data: Float32Array;
|
|
7
|
+
position: number;
|
|
8
|
+
}
|
|
9
|
+
export type EmitAudioEventFunction = (_: EmitAudioEventProps) => void;
|
|
10
|
+
export type EmitAudioAnalysisFunction = (_: AudioAnalysis) => void;
|
|
11
|
+
export interface ExpoAudioStreamWebProps {
|
|
12
|
+
logger?: ConsoleLike;
|
|
13
|
+
audioWorkletUrl: string;
|
|
14
|
+
featuresExtratorUrl: string;
|
|
15
|
+
}
|
|
16
|
+
export declare class ExpoAudioStreamWeb extends LegacyEventEmitter {
|
|
17
|
+
customRecorder: WebRecorder | null;
|
|
18
|
+
audioChunks: Float32Array[];
|
|
19
|
+
isRecording: boolean;
|
|
20
|
+
isPaused: boolean;
|
|
21
|
+
recordingStartTime: number;
|
|
22
|
+
pausedTime: number;
|
|
23
|
+
currentDurationMs: number;
|
|
24
|
+
currentSize: number;
|
|
25
|
+
currentInterval: number;
|
|
26
|
+
lastEmittedSize: number;
|
|
27
|
+
lastEmittedTime: number;
|
|
28
|
+
streamUuid: string | null;
|
|
29
|
+
extension: 'webm' | 'wav';
|
|
30
|
+
recordingConfig?: RecordingConfig;
|
|
31
|
+
bitDepth: BitDepth;
|
|
32
|
+
audioWorkletUrl: string;
|
|
33
|
+
featuresExtratorUrl: string;
|
|
34
|
+
logger?: ConsoleLike;
|
|
35
|
+
constructor({ audioWorkletUrl, featuresExtratorUrl, logger, }: ExpoAudioStreamWebProps);
|
|
36
|
+
getMediaStream(): Promise<MediaStream>;
|
|
37
|
+
startRecording(recordingConfig?: RecordingConfig): Promise<StartRecordingResult>;
|
|
38
|
+
emitAudioEvent({ data, position }: EmitAudioEventProps): void;
|
|
39
|
+
stopRecording(): Promise<AudioRecording>;
|
|
40
|
+
pauseRecording(): Promise<void>;
|
|
41
|
+
resumeRecording(): Promise<void>;
|
|
42
|
+
status(): AudioStreamStatus;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=ExpoAudioStream.web.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExpoAudioStream.web.d.ts","sourceRoot":"","sources":["../src/ExpoAudioStream.web.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAEtD,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAA;AACnE,OAAO,EACH,cAAc,EACd,iBAAiB,EACjB,QAAQ,EACR,WAAW,EACX,eAAe,EACf,oBAAoB,EACvB,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAK/C,MAAM,WAAW,mBAAmB;IAChC,IAAI,EAAE,YAAY,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;CACnB;AACD,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,EAAE,mBAAmB,KAAK,IAAI,CAAA;AACrE,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,EAAE,aAAa,KAAK,IAAI,CAAA;AAElE,MAAM,WAAW,uBAAuB;IACpC,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,eAAe,EAAE,MAAM,CAAA;IACvB,mBAAmB,EAAE,MAAM,CAAA;CAC9B;AAED,qBAAa,kBAAmB,SAAQ,kBAAkB;IACtD,cAAc,EAAE,WAAW,GAAG,IAAI,CAAA;IAClC,WAAW,EAAE,YAAY,EAAE,CAAA;IAC3B,WAAW,EAAE,OAAO,CAAA;IACpB,QAAQ,EAAE,OAAO,CAAA;IACjB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,UAAU,EAAE,MAAM,CAAA;IAClB,iBAAiB,EAAE,MAAM,CAAA;IACzB,WAAW,EAAE,MAAM,CAAA;IACnB,eAAe,EAAE,MAAM,CAAA;IACvB,eAAe,EAAE,MAAM,CAAA;IACvB,eAAe,EAAE,MAAM,CAAA;IACvB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,SAAS,EAAE,MAAM,GAAG,KAAK,CAAQ;IACjC,eAAe,CAAC,EAAE,eAAe,CAAA;IACjC,QAAQ,EAAE,QAAQ,CAAA;IAClB,eAAe,EAAE,MAAM,CAAA;IACvB,mBAAmB,EAAE,MAAM,CAAA;IAC3B,MAAM,CAAC,EAAE,WAAW,CAAA;gBAER,EACR,eAAe,EACf,mBAAmB,EACnB,MAAM,GACT,EAAE,uBAAuB;IA8BpB,cAAc;IAUd,cAAc,CAAC,eAAe,GAAE,eAAoB;IAkE1D,cAAc,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,mBAAmB;IAiBhD,aAAa,IAAI,OAAO,CAAC,cAAc,CAAC;IA6CxC,cAAc;IAad,eAAe;IAarB,MAAM;CAWT"}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
// src/ExpoAudioStreamModule.web.ts
|
|
2
|
+
import { LegacyEventEmitter } from 'expo-modules-core';
|
|
3
|
+
import { WebRecorder } from './WebRecorder.web';
|
|
4
|
+
import { encodingToBitDepth } from './utils/encodingToBitDepth';
|
|
5
|
+
import { writeWavHeader } from './utils/writeWavHeader';
|
|
6
|
+
export class ExpoAudioStreamWeb extends LegacyEventEmitter {
|
|
7
|
+
customRecorder;
|
|
8
|
+
audioChunks;
|
|
9
|
+
isRecording;
|
|
10
|
+
isPaused;
|
|
11
|
+
recordingStartTime;
|
|
12
|
+
pausedTime;
|
|
13
|
+
currentDurationMs;
|
|
14
|
+
currentSize;
|
|
15
|
+
currentInterval;
|
|
16
|
+
lastEmittedSize;
|
|
17
|
+
lastEmittedTime;
|
|
18
|
+
streamUuid;
|
|
19
|
+
extension = 'wav'; // Default extension is 'webm'
|
|
20
|
+
recordingConfig;
|
|
21
|
+
bitDepth; // Bit depth of the audio
|
|
22
|
+
audioWorkletUrl;
|
|
23
|
+
featuresExtratorUrl;
|
|
24
|
+
logger;
|
|
25
|
+
constructor({ audioWorkletUrl, featuresExtratorUrl, logger, }) {
|
|
26
|
+
const mockNativeModule = {
|
|
27
|
+
addListener: () => {
|
|
28
|
+
// Not used on web
|
|
29
|
+
},
|
|
30
|
+
removeListeners: () => {
|
|
31
|
+
// Not used on web
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
super(mockNativeModule); // Pass the mock native module to the parent class
|
|
35
|
+
this.logger = logger;
|
|
36
|
+
this.customRecorder = null;
|
|
37
|
+
this.audioChunks = [];
|
|
38
|
+
this.isRecording = false;
|
|
39
|
+
this.isPaused = false;
|
|
40
|
+
this.recordingStartTime = 0;
|
|
41
|
+
this.pausedTime = 0;
|
|
42
|
+
this.currentDurationMs = 0;
|
|
43
|
+
this.currentSize = 0;
|
|
44
|
+
this.bitDepth = 32; // Default
|
|
45
|
+
this.currentInterval = 1000; // Default interval in ms
|
|
46
|
+
this.lastEmittedSize = 0;
|
|
47
|
+
this.lastEmittedTime = 0;
|
|
48
|
+
this.streamUuid = null; // Initialize UUID on first recording start
|
|
49
|
+
this.audioWorkletUrl = audioWorkletUrl;
|
|
50
|
+
this.featuresExtratorUrl = featuresExtratorUrl;
|
|
51
|
+
}
|
|
52
|
+
// Utility to handle user media stream
|
|
53
|
+
async getMediaStream() {
|
|
54
|
+
try {
|
|
55
|
+
return await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
console.error('Failed to get media stream:', error);
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// Start recording with options
|
|
63
|
+
async startRecording(recordingConfig = {}) {
|
|
64
|
+
if (this.isRecording) {
|
|
65
|
+
throw new Error('Recording is already in progress');
|
|
66
|
+
}
|
|
67
|
+
this.bitDepth = encodingToBitDepth({
|
|
68
|
+
encoding: recordingConfig.encoding ?? 'pcm_32bit',
|
|
69
|
+
});
|
|
70
|
+
const audioContext = new (window.AudioContext ||
|
|
71
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
72
|
+
// @ts-ignore - Allow webkitAudioContext for Safari
|
|
73
|
+
window.webkitAudioContext)();
|
|
74
|
+
const stream = await this.getMediaStream();
|
|
75
|
+
const source = audioContext.createMediaStreamSource(stream);
|
|
76
|
+
this.customRecorder = new WebRecorder({
|
|
77
|
+
audioContext,
|
|
78
|
+
source,
|
|
79
|
+
recordingConfig,
|
|
80
|
+
audioWorkletUrl: this.audioWorkletUrl,
|
|
81
|
+
emitAudioEventCallback: ({ data, position, }) => {
|
|
82
|
+
this.audioChunks.push(new Float32Array(data));
|
|
83
|
+
this.currentSize += data.byteLength;
|
|
84
|
+
this.emitAudioEvent({ data, position });
|
|
85
|
+
this.lastEmittedTime = Date.now();
|
|
86
|
+
this.lastEmittedSize = this.currentSize;
|
|
87
|
+
},
|
|
88
|
+
emitAudioAnalysisCallback: (audioAnalysisData) => {
|
|
89
|
+
this.logger?.log(`Emitted AudioAnalysis:`, audioAnalysisData);
|
|
90
|
+
this.emit('AudioAnalysis', audioAnalysisData);
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
await this.customRecorder.init();
|
|
94
|
+
this.customRecorder.start();
|
|
95
|
+
// // Set a timer to stop recording after 5 seconds
|
|
96
|
+
// setTimeout(() => {
|
|
97
|
+
// logger.log("AUTO Stopping recording");
|
|
98
|
+
// this.customRecorder?.stopAndPlay();
|
|
99
|
+
// this.isRecording = false;
|
|
100
|
+
// }, 3000);
|
|
101
|
+
this.isRecording = true;
|
|
102
|
+
this.recordingConfig = recordingConfig;
|
|
103
|
+
this.recordingStartTime = Date.now();
|
|
104
|
+
this.pausedTime = 0;
|
|
105
|
+
this.isPaused = false;
|
|
106
|
+
this.lastEmittedSize = 0;
|
|
107
|
+
this.lastEmittedTime = 0;
|
|
108
|
+
this.streamUuid = Date.now().toString();
|
|
109
|
+
const fileUri = `${this.streamUuid}.${this.extension}`;
|
|
110
|
+
const streamConfig = {
|
|
111
|
+
fileUri,
|
|
112
|
+
mimeType: `audio/${this.extension}`,
|
|
113
|
+
bitDepth: this.bitDepth,
|
|
114
|
+
channels: recordingConfig.channels ?? 1,
|
|
115
|
+
sampleRate: recordingConfig.sampleRate ?? 44100,
|
|
116
|
+
};
|
|
117
|
+
return streamConfig;
|
|
118
|
+
}
|
|
119
|
+
emitAudioEvent({ data, position }) {
|
|
120
|
+
const fileUri = `${this.streamUuid}.${this.extension}`;
|
|
121
|
+
const audioEventPayload = {
|
|
122
|
+
fileUri,
|
|
123
|
+
mimeType: `audio/${this.extension}`,
|
|
124
|
+
lastEmittedSize: this.lastEmittedSize, // Since this might be continuously streaming, adjust accordingly
|
|
125
|
+
deltaSize: data.byteLength,
|
|
126
|
+
position,
|
|
127
|
+
totalSize: this.currentSize,
|
|
128
|
+
buffer: data,
|
|
129
|
+
streamUuid: this.streamUuid ?? '', // Generate or manage UUID for stream identification
|
|
130
|
+
};
|
|
131
|
+
this.emit('AudioData', audioEventPayload);
|
|
132
|
+
}
|
|
133
|
+
// Stop recording
|
|
134
|
+
async stopRecording() {
|
|
135
|
+
if (!this.customRecorder) {
|
|
136
|
+
throw new Error('Recorder is not initialized');
|
|
137
|
+
}
|
|
138
|
+
const fullPcmBufferArray = await this.customRecorder.stop();
|
|
139
|
+
// concat all audio chunks
|
|
140
|
+
this.logger?.debug(`Stopped recording`, fullPcmBufferArray);
|
|
141
|
+
this.isRecording = false;
|
|
142
|
+
this.isPaused = false;
|
|
143
|
+
this.currentDurationMs = Date.now() - this.recordingStartTime;
|
|
144
|
+
// Rewrite wav header with correct data size
|
|
145
|
+
const wavConfig = {
|
|
146
|
+
buffer: new ArrayBuffer(fullPcmBufferArray.buffer.byteLength),
|
|
147
|
+
sampleRate: this.recordingConfig?.sampleRate ?? 44100,
|
|
148
|
+
numChannels: this.recordingConfig?.channels ?? 1,
|
|
149
|
+
bitDepth: this.bitDepth,
|
|
150
|
+
};
|
|
151
|
+
this.logger?.debug(`Writing wav header`, wavConfig);
|
|
152
|
+
const wavBuffer = writeWavHeader(wavConfig).slice(0);
|
|
153
|
+
// Create blob fileUri from audio chunks
|
|
154
|
+
const blob = new Blob([wavBuffer], {
|
|
155
|
+
type: `audio/${this.extension}`,
|
|
156
|
+
});
|
|
157
|
+
const fileUri = URL.createObjectURL(blob);
|
|
158
|
+
const result = {
|
|
159
|
+
fileUri,
|
|
160
|
+
filename: `${this.streamUuid}.${this.extension}`,
|
|
161
|
+
wavPCMData: fullPcmBufferArray,
|
|
162
|
+
bitDepth: this.bitDepth,
|
|
163
|
+
channels: this.recordingConfig?.channels ?? 1,
|
|
164
|
+
sampleRate: this.recordingConfig?.sampleRate ?? 44100,
|
|
165
|
+
durationMs: this.currentDurationMs,
|
|
166
|
+
size: this.currentSize,
|
|
167
|
+
mimeType: `audio/${this.extension}`,
|
|
168
|
+
};
|
|
169
|
+
return result;
|
|
170
|
+
}
|
|
171
|
+
// Pause recording
|
|
172
|
+
async pauseRecording() {
|
|
173
|
+
if (!this.isRecording || this.isPaused) {
|
|
174
|
+
throw new Error('Recording is not active or already paused');
|
|
175
|
+
}
|
|
176
|
+
if (this.customRecorder) {
|
|
177
|
+
this.customRecorder.pause();
|
|
178
|
+
}
|
|
179
|
+
this.isPaused = true;
|
|
180
|
+
this.pausedTime = Date.now();
|
|
181
|
+
}
|
|
182
|
+
// Resume recording
|
|
183
|
+
async resumeRecording() {
|
|
184
|
+
if (!this.isPaused) {
|
|
185
|
+
throw new Error('Recording is not paused');
|
|
186
|
+
}
|
|
187
|
+
if (this.customRecorder) {
|
|
188
|
+
this.customRecorder.resume();
|
|
189
|
+
}
|
|
190
|
+
this.isPaused = false;
|
|
191
|
+
this.recordingStartTime += Date.now() - this.pausedTime;
|
|
192
|
+
}
|
|
193
|
+
// Get current status
|
|
194
|
+
status() {
|
|
195
|
+
const status = {
|
|
196
|
+
isRecording: this.isRecording,
|
|
197
|
+
isPaused: this.isPaused,
|
|
198
|
+
durationMs: Date.now() - this.recordingStartTime,
|
|
199
|
+
size: this.currentSize,
|
|
200
|
+
interval: this.currentInterval,
|
|
201
|
+
mimeType: `audio/${this.extension}`,
|
|
202
|
+
};
|
|
203
|
+
return status;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
//# sourceMappingURL=ExpoAudioStream.web.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExpoAudioStream.web.js","sourceRoot":"","sources":["../src/ExpoAudioStream.web.ts"],"names":[],"mappings":"AAAA,mCAAmC;AACnC,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAWtD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAE/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAA;AAC/D,OAAO,EAAoB,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAezE,MAAM,OAAO,kBAAmB,SAAQ,kBAAkB;IACtD,cAAc,CAAoB;IAClC,WAAW,CAAgB;IAC3B,WAAW,CAAS;IACpB,QAAQ,CAAS;IACjB,kBAAkB,CAAQ;IAC1B,UAAU,CAAQ;IAClB,iBAAiB,CAAQ;IACzB,WAAW,CAAQ;IACnB,eAAe,CAAQ;IACvB,eAAe,CAAQ;IACvB,eAAe,CAAQ;IACvB,UAAU,CAAe;IACzB,SAAS,GAAmB,KAAK,CAAA,CAAC,8BAA8B;IAChE,eAAe,CAAkB;IACjC,QAAQ,CAAU,CAAC,yBAAyB;IAC5C,eAAe,CAAQ;IACvB,mBAAmB,CAAQ;IAC3B,MAAM,CAAc;IAEpB,YAAY,EACR,eAAe,EACf,mBAAmB,EACnB,MAAM,GACgB;QACtB,MAAM,gBAAgB,GAAG;YACrB,WAAW,EAAE,GAAG,EAAE;gBACd,kBAAkB;YACtB,CAAC;YACD,eAAe,EAAE,GAAG,EAAE;gBAClB,kBAAkB;YACtB,CAAC;SACJ,CAAA;QACD,KAAK,CAAC,gBAAgB,CAAC,CAAA,CAAC,kDAAkD;QAE1E,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;QACpB,IAAI,CAAC,cAAc,GAAG,IAAI,CAAA;QAC1B,IAAI,CAAC,WAAW,GAAG,EAAE,CAAA;QACrB,IAAI,CAAC,WAAW,GAAG,KAAK,CAAA;QACxB,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAA;QACrB,IAAI,CAAC,kBAAkB,GAAG,CAAC,CAAA;QAC3B,IAAI,CAAC,UAAU,GAAG,CAAC,CAAA;QACnB,IAAI,CAAC,iBAAiB,GAAG,CAAC,CAAA;QAC1B,IAAI,CAAC,WAAW,GAAG,CAAC,CAAA;QACpB,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAA,CAAC,UAAU;QAC7B,IAAI,CAAC,eAAe,GAAG,IAAI,CAAA,CAAC,yBAAyB;QACrD,IAAI,CAAC,eAAe,GAAG,CAAC,CAAA;QACxB,IAAI,CAAC,eAAe,GAAG,CAAC,CAAA;QACxB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAA,CAAC,2CAA2C;QAClE,IAAI,CAAC,eAAe,GAAG,eAAe,CAAA;QACtC,IAAI,CAAC,mBAAmB,GAAG,mBAAmB,CAAA;IAClD,CAAC;IAED,sCAAsC;IACtC,KAAK,CAAC,cAAc;QAChB,IAAI,CAAC;YACD,OAAO,MAAM,SAAS,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;QACrE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,6BAA6B,EAAE,KAAK,CAAC,CAAA;YACnD,MAAM,KAAK,CAAA;QACf,CAAC;IACL,CAAC;IAED,+BAA+B;IAC/B,KAAK,CAAC,cAAc,CAAC,kBAAmC,EAAE;QACtD,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAA;QACvD,CAAC;QAED,IAAI,CAAC,QAAQ,GAAG,kBAAkB,CAAC;YAC/B,QAAQ,EAAE,eAAe,CAAC,QAAQ,IAAI,WAAW;SACpD,CAAC,CAAA;QAEF,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY;YACzC,6DAA6D;YAC7D,mDAAmD;YACnD,MAAM,CAAC,kBAAkB,CAAC,EAAE,CAAA;QAChC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,cAAc,EAAE,CAAA;QAE1C,MAAM,MAAM,GAAG,YAAY,CAAC,uBAAuB,CAAC,MAAM,CAAC,CAAA;QAE3D,IAAI,CAAC,cAAc,GAAG,IAAI,WAAW,CAAC;YAClC,YAAY;YACZ,MAAM;YACN,eAAe;YACf,eAAe,EAAE,IAAI,CAAC,eAAe;YACrC,sBAAsB,EAAE,CAAC,EACrB,IAAI,EACJ,QAAQ,GACU,EAAE,EAAE;gBACtB,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC,CAAA;gBAC7C,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,UAAU,CAAA;gBACnC,IAAI,CAAC,cAAc,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAA;gBACvC,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;gBACjC,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,WAAW,CAAA;YAC3C,CAAC;YACD,yBAAyB,EAAE,CAAC,iBAAgC,EAAE,EAAE;gBAC5D,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,wBAAwB,EAAE,iBAAiB,CAAC,CAAA;gBAC7D,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,iBAAiB,CAAC,CAAA;YACjD,CAAC;SACJ,CAAC,CAAA;QACF,MAAM,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,CAAA;QAChC,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAA;QAE3B,mDAAmD;QACnD,qBAAqB;QACrB,2CAA2C;QAC3C,wCAAwC;QACxC,8BAA8B;QAC9B,YAAY;QAEZ,IAAI,CAAC,WAAW,GAAG,IAAI,CAAA;QACvB,IAAI,CAAC,eAAe,GAAG,eAAe,CAAA;QACtC,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QACpC,IAAI,CAAC,UAAU,GAAG,CAAC,CAAA;QACnB,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAA;QACrB,IAAI,CAAC,eAAe,GAAG,CAAC,CAAA;QACxB,IAAI,CAAC,eAAe,GAAG,CAAC,CAAA;QACxB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAA;QACvC,MAAM,OAAO,GAAG,GAAG,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,SAAS,EAAE,CAAA;QACtD,MAAM,YAAY,GAAyB;YACvC,OAAO;YACP,QAAQ,EAAE,SAAS,IAAI,CAAC,SAAS,EAAE;YACnC,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,QAAQ,EAAE,eAAe,CAAC,QAAQ,IAAI,CAAC;YACvC,UAAU,EAAE,eAAe,CAAC,UAAU,IAAI,KAAK;SAClD,CAAA;QACD,OAAO,YAAY,CAAA;IACvB,CAAC;IAED,cAAc,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAuB;QAClD,MAAM,OAAO,GAAG,GAAG,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,SAAS,EAAE,CAAA;QACtD,MAAM,iBAAiB,GAAsB;YACzC,OAAO;YACP,QAAQ,EAAE,SAAS,IAAI,CAAC,SAAS,EAAE;YACnC,eAAe,EAAE,IAAI,CAAC,eAAe,EAAE,iEAAiE;YACxG,SAAS,EAAE,IAAI,CAAC,UAAU;YAC1B,QAAQ;YACR,SAAS,EAAE,IAAI,CAAC,WAAW;YAC3B,MAAM,EAAE,IAAI;YACZ,UAAU,EAAE,IAAI,CAAC,UAAU,IAAI,EAAE,EAAE,oDAAoD;SAC1F,CAAA;QAED,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAA;IAC7C,CAAC;IAED,iBAAiB;IACjB,KAAK,CAAC,aAAa;QACf,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAA;QAClD,CAAC;QAED,MAAM,kBAAkB,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,CAAA;QAE3D,0BAA0B;QAC1B,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,mBAAmB,EAAE,kBAAkB,CAAC,CAAA;QAC3D,IAAI,CAAC,WAAW,GAAG,KAAK,CAAA;QACxB,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAA;QACrB,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,kBAAkB,CAAA;QAE7D,4CAA4C;QAC5C,MAAM,SAAS,GAAqB;YAChC,MAAM,EAAE,IAAI,WAAW,CAAC,kBAAkB,CAAC,MAAM,CAAC,UAAU,CAAC;YAC7D,UAAU,EAAE,IAAI,CAAC,eAAe,EAAE,UAAU,IAAI,KAAK;YACrD,WAAW,EAAE,IAAI,CAAC,eAAe,EAAE,QAAQ,IAAI,CAAC;YAChD,QAAQ,EAAE,IAAI,CAAC,QAAQ;SAC1B,CAAA;QACD,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,oBAAoB,EAAE,SAAS,CAAC,CAAA;QACnD,MAAM,SAAS,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;QAEpD,wCAAwC;QACxC,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,SAAS,CAAC,EAAE;YAC/B,IAAI,EAAE,SAAS,IAAI,CAAC,SAAS,EAAE;SAClC,CAAC,CAAA;QACF,MAAM,OAAO,GAAG,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,CAAA;QAEzC,MAAM,MAAM,GAAmB;YAC3B,OAAO;YACP,QAAQ,EAAE,GAAG,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,SAAS,EAAE;YAChD,UAAU,EAAE,kBAAkB;YAC9B,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,QAAQ,EAAE,IAAI,CAAC,eAAe,EAAE,QAAQ,IAAI,CAAC;YAC7C,UAAU,EAAE,IAAI,CAAC,eAAe,EAAE,UAAU,IAAI,KAAK;YACrD,UAAU,EAAE,IAAI,CAAC,iBAAiB;YAClC,IAAI,EAAE,IAAI,CAAC,WAAW;YACtB,QAAQ,EAAE,SAAS,IAAI,CAAC,SAAS,EAAE;SACtC,CAAA;QAED,OAAO,MAAM,CAAA;IACjB,CAAC;IAED,kBAAkB;IAClB,KAAK,CAAC,cAAc;QAChB,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACrC,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAA;QAChE,CAAC;QAED,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACtB,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAA;QAC/B,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAA;QACpB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;IAChC,CAAC;IAED,mBAAmB;IACnB,KAAK,CAAC,eAAe;QACjB,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAA;QAC9C,CAAC;QAED,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACtB,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,CAAA;QAChC,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAA;QACrB,IAAI,CAAC,kBAAkB,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,UAAU,CAAA;IAC3D,CAAC;IAED,qBAAqB;IACrB,MAAM;QACF,MAAM,MAAM,GAAsB;YAC9B,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,kBAAkB;YAChD,IAAI,EAAE,IAAI,CAAC,WAAW;YACtB,QAAQ,EAAE,IAAI,CAAC,eAAe;YAC9B,QAAQ,EAAE,SAAS,IAAI,CAAC,SAAS,EAAE;SACtC,CAAA;QACD,OAAO,MAAM,CAAA;IACjB,CAAC;CACJ","sourcesContent":["// src/ExpoAudioStreamModule.web.ts\nimport { LegacyEventEmitter } from 'expo-modules-core'\n\nimport { AudioAnalysis } from './AudioAnalysis/AudioAnalysis.types'\nimport {\n AudioRecording,\n AudioStreamStatus,\n BitDepth,\n ConsoleLike,\n RecordingConfig,\n StartRecordingResult,\n} from './ExpoAudioStream.types'\nimport { WebRecorder } from './WebRecorder.web'\nimport { AudioEventPayload } from './events'\nimport { encodingToBitDepth } from './utils/encodingToBitDepth'\nimport { WavHeaderOptions, writeWavHeader } from './utils/writeWavHeader'\n\nexport interface EmitAudioEventProps {\n data: Float32Array\n position: number\n}\nexport type EmitAudioEventFunction = (_: EmitAudioEventProps) => void\nexport type EmitAudioAnalysisFunction = (_: AudioAnalysis) => void\n\nexport interface ExpoAudioStreamWebProps {\n logger?: ConsoleLike\n audioWorkletUrl: string\n featuresExtratorUrl: string\n}\n\nexport class ExpoAudioStreamWeb extends LegacyEventEmitter {\n customRecorder: WebRecorder | null\n audioChunks: Float32Array[]\n isRecording: boolean\n isPaused: boolean\n recordingStartTime: number\n pausedTime: number\n currentDurationMs: number\n currentSize: number\n currentInterval: number\n lastEmittedSize: number\n lastEmittedTime: number\n streamUuid: string | null\n extension: 'webm' | 'wav' = 'wav' // Default extension is 'webm'\n recordingConfig?: RecordingConfig\n bitDepth: BitDepth // Bit depth of the audio\n audioWorkletUrl: string\n featuresExtratorUrl: string\n logger?: ConsoleLike\n\n constructor({\n audioWorkletUrl,\n featuresExtratorUrl,\n logger,\n }: ExpoAudioStreamWebProps) {\n const mockNativeModule = {\n addListener: () => {\n // Not used on web\n },\n removeListeners: () => {\n // Not used on web\n },\n }\n super(mockNativeModule) // Pass the mock native module to the parent class\n\n this.logger = logger\n this.customRecorder = null\n this.audioChunks = []\n this.isRecording = false\n this.isPaused = false\n this.recordingStartTime = 0\n this.pausedTime = 0\n this.currentDurationMs = 0\n this.currentSize = 0\n this.bitDepth = 32 // Default\n this.currentInterval = 1000 // Default interval in ms\n this.lastEmittedSize = 0\n this.lastEmittedTime = 0\n this.streamUuid = null // Initialize UUID on first recording start\n this.audioWorkletUrl = audioWorkletUrl\n this.featuresExtratorUrl = featuresExtratorUrl\n }\n\n // Utility to handle user media stream\n async getMediaStream() {\n try {\n return await navigator.mediaDevices.getUserMedia({ audio: true })\n } catch (error) {\n console.error('Failed to get media stream:', error)\n throw error\n }\n }\n\n // Start recording with options\n async startRecording(recordingConfig: RecordingConfig = {}) {\n if (this.isRecording) {\n throw new Error('Recording is already in progress')\n }\n\n this.bitDepth = encodingToBitDepth({\n encoding: recordingConfig.encoding ?? 'pcm_32bit',\n })\n\n const audioContext = new (window.AudioContext ||\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore - Allow webkitAudioContext for Safari\n window.webkitAudioContext)()\n const stream = await this.getMediaStream()\n\n const source = audioContext.createMediaStreamSource(stream)\n\n this.customRecorder = new WebRecorder({\n audioContext,\n source,\n recordingConfig,\n audioWorkletUrl: this.audioWorkletUrl,\n emitAudioEventCallback: ({\n data,\n position,\n }: EmitAudioEventProps) => {\n this.audioChunks.push(new Float32Array(data))\n this.currentSize += data.byteLength\n this.emitAudioEvent({ data, position })\n this.lastEmittedTime = Date.now()\n this.lastEmittedSize = this.currentSize\n },\n emitAudioAnalysisCallback: (audioAnalysisData: AudioAnalysis) => {\n this.logger?.log(`Emitted AudioAnalysis:`, audioAnalysisData)\n this.emit('AudioAnalysis', audioAnalysisData)\n },\n })\n await this.customRecorder.init()\n this.customRecorder.start()\n\n // // Set a timer to stop recording after 5 seconds\n // setTimeout(() => {\n // logger.log(\"AUTO Stopping recording\");\n // this.customRecorder?.stopAndPlay();\n // this.isRecording = false;\n // }, 3000);\n\n this.isRecording = true\n this.recordingConfig = recordingConfig\n this.recordingStartTime = Date.now()\n this.pausedTime = 0\n this.isPaused = false\n this.lastEmittedSize = 0\n this.lastEmittedTime = 0\n this.streamUuid = Date.now().toString()\n const fileUri = `${this.streamUuid}.${this.extension}`\n const streamConfig: StartRecordingResult = {\n fileUri,\n mimeType: `audio/${this.extension}`,\n bitDepth: this.bitDepth,\n channels: recordingConfig.channels ?? 1,\n sampleRate: recordingConfig.sampleRate ?? 44100,\n }\n return streamConfig\n }\n\n emitAudioEvent({ data, position }: EmitAudioEventProps) {\n const fileUri = `${this.streamUuid}.${this.extension}`\n const audioEventPayload: AudioEventPayload = {\n fileUri,\n mimeType: `audio/${this.extension}`,\n lastEmittedSize: this.lastEmittedSize, // Since this might be continuously streaming, adjust accordingly\n deltaSize: data.byteLength,\n position,\n totalSize: this.currentSize,\n buffer: data,\n streamUuid: this.streamUuid ?? '', // Generate or manage UUID for stream identification\n }\n\n this.emit('AudioData', audioEventPayload)\n }\n\n // Stop recording\n async stopRecording(): Promise<AudioRecording> {\n if (!this.customRecorder) {\n throw new Error('Recorder is not initialized')\n }\n\n const fullPcmBufferArray = await this.customRecorder.stop()\n\n // concat all audio chunks\n this.logger?.debug(`Stopped recording`, fullPcmBufferArray)\n this.isRecording = false\n this.isPaused = false\n this.currentDurationMs = Date.now() - this.recordingStartTime\n\n // Rewrite wav header with correct data size\n const wavConfig: WavHeaderOptions = {\n buffer: new ArrayBuffer(fullPcmBufferArray.buffer.byteLength),\n sampleRate: this.recordingConfig?.sampleRate ?? 44100,\n numChannels: this.recordingConfig?.channels ?? 1,\n bitDepth: this.bitDepth,\n }\n this.logger?.debug(`Writing wav header`, wavConfig)\n const wavBuffer = writeWavHeader(wavConfig).slice(0)\n\n // Create blob fileUri from audio chunks\n const blob = new Blob([wavBuffer], {\n type: `audio/${this.extension}`,\n })\n const fileUri = URL.createObjectURL(blob)\n\n const result: AudioRecording = {\n fileUri,\n filename: `${this.streamUuid}.${this.extension}`,\n wavPCMData: fullPcmBufferArray,\n bitDepth: this.bitDepth,\n channels: this.recordingConfig?.channels ?? 1,\n sampleRate: this.recordingConfig?.sampleRate ?? 44100,\n durationMs: this.currentDurationMs,\n size: this.currentSize,\n mimeType: `audio/${this.extension}`,\n }\n\n return result\n }\n\n // Pause recording\n async pauseRecording() {\n if (!this.isRecording || this.isPaused) {\n throw new Error('Recording is not active or already paused')\n }\n\n if (this.customRecorder) {\n this.customRecorder.pause()\n }\n this.isPaused = true\n this.pausedTime = Date.now()\n }\n\n // Resume recording\n async resumeRecording() {\n if (!this.isPaused) {\n throw new Error('Recording is not paused')\n }\n\n if (this.customRecorder) {\n this.customRecorder.resume()\n }\n this.isPaused = false\n this.recordingStartTime += Date.now() - this.pausedTime\n }\n\n // Get current status\n status() {\n const status: AudioStreamStatus = {\n isRecording: this.isRecording,\n isPaused: this.isPaused,\n durationMs: Date.now() - this.recordingStartTime,\n size: this.currentSize,\n interval: this.currentInterval,\n mimeType: `audio/${this.extension}`,\n }\n return status\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExpoAudioStreamModule.d.ts","sourceRoot":"","sources":["../src/ExpoAudioStreamModule.ts"],"names":[],"mappings":"AASA,QAAA,IAAI,qBAAqB,EAAE,GAAG,CAAA;AA+B9B,eAAe,qBAAqB,CAAA"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { requireNativeModule } from 'expo-modules-core';
|
|
2
|
+
import { Platform } from 'react-native';
|
|
3
|
+
import { ExpoAudioStreamWeb, } from './ExpoAudioStream.web';
|
|
4
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5
|
+
let ExpoAudioStreamModule;
|
|
6
|
+
if (Platform.OS === 'web') {
|
|
7
|
+
let instance = null;
|
|
8
|
+
ExpoAudioStreamModule = (webProps) => {
|
|
9
|
+
if (!instance) {
|
|
10
|
+
instance = new ExpoAudioStreamWeb(webProps);
|
|
11
|
+
}
|
|
12
|
+
return instance;
|
|
13
|
+
};
|
|
14
|
+
ExpoAudioStreamModule.requestPermissionsAsync = async () => {
|
|
15
|
+
return {
|
|
16
|
+
status: 'granted',
|
|
17
|
+
granted: true,
|
|
18
|
+
expires: 'never',
|
|
19
|
+
canAskAgain: true,
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
ExpoAudioStreamModule.getPermissionsAsync = async () => {
|
|
23
|
+
return {
|
|
24
|
+
status: 'granted',
|
|
25
|
+
granted: true,
|
|
26
|
+
expires: 'never',
|
|
27
|
+
canAskAgain: true,
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
ExpoAudioStreamModule = requireNativeModule('ExpoAudioStream');
|
|
33
|
+
}
|
|
34
|
+
export default ExpoAudioStreamModule;
|
|
35
|
+
//# sourceMappingURL=ExpoAudioStreamModule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExpoAudioStreamModule.js","sourceRoot":"","sources":["../src/ExpoAudioStreamModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAEvC,OAAO,EACH,kBAAkB,GAErB,MAAM,uBAAuB,CAAA;AAE9B,8DAA8D;AAC9D,IAAI,qBAA0B,CAAA;AAE9B,IAAI,QAAQ,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;IACxB,IAAI,QAAQ,GAA8B,IAAI,CAAA;IAE9C,qBAAqB,GAAG,CAAC,QAAiC,EAAE,EAAE;QAC1D,IAAI,CAAC,QAAQ,EAAE,CAAC;YACZ,QAAQ,GAAG,IAAI,kBAAkB,CAAC,QAAQ,CAAC,CAAA;QAC/C,CAAC;QACD,OAAO,QAAQ,CAAA;IACnB,CAAC,CAAA;IACD,qBAAqB,CAAC,uBAAuB,GAAG,KAAK,IAAI,EAAE;QACvD,OAAO;YACH,MAAM,EAAE,SAAS;YACjB,OAAO,EAAE,IAAI;YACb,OAAO,EAAE,OAAO;YAChB,WAAW,EAAE,IAAI;SACpB,CAAA;IACL,CAAC,CAAA;IACD,qBAAqB,CAAC,mBAAmB,GAAG,KAAK,IAAI,EAAE;QACnD,OAAO;YACH,MAAM,EAAE,SAAS;YACjB,OAAO,EAAE,IAAI;YACb,OAAO,EAAE,OAAO;YAChB,WAAW,EAAE,IAAI;SACpB,CAAA;IACL,CAAC,CAAA;AACL,CAAC;KAAM,CAAC;IACJ,qBAAqB,GAAG,mBAAmB,CAAC,iBAAiB,CAAC,CAAA;AAClE,CAAC;AAED,eAAe,qBAAqB,CAAA","sourcesContent":["import { requireNativeModule } from 'expo-modules-core'\nimport { Platform } from 'react-native'\n\nimport {\n ExpoAudioStreamWeb,\n ExpoAudioStreamWebProps,\n} from './ExpoAudioStream.web'\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet ExpoAudioStreamModule: any\n\nif (Platform.OS === 'web') {\n let instance: ExpoAudioStreamWeb | null = null\n\n ExpoAudioStreamModule = (webProps: ExpoAudioStreamWebProps) => {\n if (!instance) {\n instance = new ExpoAudioStreamWeb(webProps)\n }\n return instance\n }\n ExpoAudioStreamModule.requestPermissionsAsync = async () => {\n return {\n status: 'granted',\n granted: true,\n expires: 'never',\n canAskAgain: true,\n }\n }\n ExpoAudioStreamModule.getPermissionsAsync = async () => {\n return {\n status: 'granted',\n granted: true,\n expires: 'never',\n canAskAgain: true,\n }\n }\n} else {\n ExpoAudioStreamModule = requireNativeModule('ExpoAudioStream')\n}\n\nexport default ExpoAudioStreamModule\n"]}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { AudioAnalysis } from './AudioAnalysis/AudioAnalysis.types';
|
|
2
|
+
import { ConsoleLike, RecordingConfig } from './ExpoAudioStream.types';
|
|
3
|
+
import { EmitAudioAnalysisFunction, EmitAudioEventFunction } from './ExpoAudioStream.web';
|
|
4
|
+
interface AudioFeaturesEvent {
|
|
5
|
+
data: {
|
|
6
|
+
command: string;
|
|
7
|
+
result: AudioAnalysis;
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
export declare class WebRecorder {
|
|
11
|
+
private audioContext;
|
|
12
|
+
private audioWorkletNode;
|
|
13
|
+
private featureExtractorWorker?;
|
|
14
|
+
private source;
|
|
15
|
+
private audioWorkletUrl;
|
|
16
|
+
private emitAudioEventCallback;
|
|
17
|
+
private emitAudioAnalysisCallback;
|
|
18
|
+
private config;
|
|
19
|
+
private position;
|
|
20
|
+
private numberOfChannels;
|
|
21
|
+
private bitDepth;
|
|
22
|
+
private exportBitDepth;
|
|
23
|
+
private audioBuffer;
|
|
24
|
+
private audioBufferSize;
|
|
25
|
+
private audioAnalysisData;
|
|
26
|
+
private packetCount;
|
|
27
|
+
private logger?;
|
|
28
|
+
constructor({ audioContext, source, recordingConfig, audioWorkletUrl, emitAudioEventCallback, emitAudioAnalysisCallback, logger, }: {
|
|
29
|
+
audioContext: AudioContext;
|
|
30
|
+
source: MediaStreamAudioSourceNode;
|
|
31
|
+
recordingConfig: RecordingConfig;
|
|
32
|
+
audioWorkletUrl: string;
|
|
33
|
+
emitAudioEventCallback: EmitAudioEventFunction;
|
|
34
|
+
emitAudioAnalysisCallback: EmitAudioAnalysisFunction;
|
|
35
|
+
logger?: ConsoleLike;
|
|
36
|
+
});
|
|
37
|
+
init(): Promise<void>;
|
|
38
|
+
initFeatureExtractorWorker(featuresExtratorUrl?: string): void;
|
|
39
|
+
initFallbackWorker(): void;
|
|
40
|
+
handleWorkerError(error: ErrorEvent): void;
|
|
41
|
+
handleFeatureExtractorMessage(event: AudioFeaturesEvent): void;
|
|
42
|
+
start(): void;
|
|
43
|
+
stop(): Promise<Float32Array>;
|
|
44
|
+
pause(): void;
|
|
45
|
+
stopMediaStreamTracks(): void;
|
|
46
|
+
playRecordedData({ recordedData, }: {
|
|
47
|
+
recordedData: ArrayBuffer;
|
|
48
|
+
mimeType?: string;
|
|
49
|
+
}): Promise<void>;
|
|
50
|
+
private checkAudioContextFormat;
|
|
51
|
+
resume(): void;
|
|
52
|
+
}
|
|
53
|
+
export {};
|
|
54
|
+
//# sourceMappingURL=WebRecorder.web.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WebRecorder.web.d.ts","sourceRoot":"","sources":["../src/WebRecorder.web.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAA;AACnE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AACtE,OAAO,EACH,yBAAyB,EACzB,sBAAsB,EACzB,MAAM,uBAAuB,CAAA;AAe9B,UAAU,kBAAkB;IACxB,IAAI,EAAE;QACF,OAAO,EAAE,MAAM,CAAA;QACf,MAAM,EAAE,aAAa,CAAA;KACxB,CAAA;CACJ;AAUD,qBAAa,WAAW;IACpB,OAAO,CAAC,YAAY,CAAc;IAClC,OAAO,CAAC,gBAAgB,CAAmB;IAC3C,OAAO,CAAC,sBAAsB,CAAC,CAAQ;IACvC,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,eAAe,CAAQ;IAC/B,OAAO,CAAC,sBAAsB,CAAwB;IACtD,OAAO,CAAC,yBAAyB,CAA2B;IAC5D,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,QAAQ,CAAQ;IACxB,OAAO,CAAC,gBAAgB,CAAQ;IAChC,OAAO,CAAC,QAAQ,CAAQ;IACxB,OAAO,CAAC,cAAc,CAAQ;IAC9B,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,eAAe,CAAQ;IAC/B,OAAO,CAAC,iBAAiB,CAAe;IACxC,OAAO,CAAC,WAAW,CAAY;IAC/B,OAAO,CAAC,MAAM,CAAC,CAAa;gBAEhB,EACR,YAAY,EACZ,MAAM,EACN,eAAe,EACf,eAAe,EACf,sBAAsB,EACtB,yBAAyB,EACzB,MAAM,GACT,EAAE;QACC,YAAY,EAAE,YAAY,CAAA;QAC1B,MAAM,EAAE,0BAA0B,CAAA;QAClC,eAAe,EAAE,eAAe,CAAA;QAChC,eAAe,EAAE,MAAM,CAAA;QACvB,sBAAsB,EAAE,sBAAsB,CAAA;QAC9C,yBAAyB,EAAE,yBAAyB,CAAA;QACpD,MAAM,CAAC,EAAE,WAAW,CAAA;KACvB;IAqDK,IAAI;IAyHV,0BAA0B,CAAC,mBAAmB,CAAC,EAAE,MAAM;IA0BvD,kBAAkB;IAqBlB,iBAAiB,CAAC,KAAK,EAAE,UAAU;IAInC,6BAA6B,CAAC,KAAK,EAAE,kBAAkB;IAgCvD,KAAK;IAML,IAAI,IAAI,OAAO,CAAC,YAAY,CAAC;IAmF7B,KAAK;IAML,qBAAqB;IAMf,gBAAgB,CAAC,EACnB,YAAY,GACf,EAAE;QACC,YAAY,EAAE,WAAW,CAAA;QACzB,QAAQ,CAAC,EAAE,MAAM,CAAA;KACpB;IAsBD,OAAO,CAAC,uBAAuB;IAoB/B,MAAM;CAKT"}
|