@siteed/expo-audio-stream 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.size-limit.json +4 -4
- package/README.md +18 -176
- package/android/src/main/java/net/siteed/audiostream/AudioRecorderManager.kt +1 -0
- package/app.plugin.js +1 -1
- package/build/AudioAnalysis/AudioAnalysis.types.d.ts +3 -5
- package/build/AudioAnalysis/AudioAnalysis.types.d.ts.map +1 -1
- package/build/AudioAnalysis/AudioAnalysis.types.js.map +1 -1
- package/build/AudioAnalysis/extractAudioAnalysis.d.ts +19 -3
- package/build/AudioAnalysis/extractAudioAnalysis.d.ts.map +1 -1
- package/build/AudioAnalysis/extractAudioAnalysis.js +14 -27
- package/build/AudioAnalysis/extractAudioAnalysis.js.map +1 -1
- package/build/AudioAnalysis/extractWaveform.d.ts.map +1 -1
- package/build/AudioAnalysis/extractWaveform.js +3 -3
- package/build/AudioAnalysis/extractWaveform.js.map +1 -1
- package/build/AudioRecorder.provider.d.ts +6 -6
- package/build/AudioRecorder.provider.d.ts.map +1 -1
- package/build/AudioRecorder.provider.js +9 -9
- package/build/AudioRecorder.provider.js.map +1 -1
- package/build/ExpoAudioStream.native.d.ts.map +1 -1
- package/build/ExpoAudioStream.native.js +2 -2
- package/build/ExpoAudioStream.native.js.map +1 -1
- package/build/ExpoAudioStream.types.d.ts +20 -18
- package/build/ExpoAudioStream.types.d.ts.map +1 -1
- package/build/ExpoAudioStream.types.js.map +1 -1
- package/build/ExpoAudioStream.web.d.ts +8 -8
- package/build/ExpoAudioStream.web.d.ts.map +1 -1
- package/build/ExpoAudioStream.web.js +40 -22
- package/build/ExpoAudioStream.web.js.map +1 -1
- package/build/ExpoAudioStreamModule.d.ts.map +1 -1
- package/build/ExpoAudioStreamModule.js +8 -7
- package/build/ExpoAudioStreamModule.js.map +1 -1
- package/build/WebRecorder.web.d.ts +8 -8
- package/build/WebRecorder.web.d.ts.map +1 -1
- package/build/WebRecorder.web.js +60 -50
- package/build/WebRecorder.web.js.map +1 -1
- package/build/constants.d.ts +1 -1
- package/build/constants.d.ts.map +1 -1
- package/build/constants.js +3 -3
- package/build/constants.js.map +1 -1
- package/build/events.d.ts +16 -4
- package/build/events.d.ts.map +1 -1
- package/build/events.js +8 -8
- package/build/events.js.map +1 -1
- package/build/index.d.ts +8 -8
- package/build/index.d.ts.map +1 -1
- package/build/index.js +6 -6
- package/build/index.js.map +1 -1
- package/build/logger.d.ts +2 -2
- package/build/logger.d.ts.map +1 -1
- package/build/logger.js +7 -11
- package/build/logger.js.map +1 -1
- package/build/useAudioRecorder.d.ts +4 -21
- package/build/useAudioRecorder.d.ts.map +1 -1
- package/build/useAudioRecorder.js +33 -33
- package/build/useAudioRecorder.js.map +1 -1
- package/build/utils/BlobFix.d.ts +9 -0
- package/build/utils/BlobFix.d.ts.map +1 -0
- package/build/utils/BlobFix.js +494 -0
- package/build/utils/BlobFix.js.map +1 -0
- package/build/utils/concatenateBuffers.d.ts +8 -0
- package/build/utils/concatenateBuffers.d.ts.map +1 -0
- package/build/utils/concatenateBuffers.js +21 -0
- package/build/utils/concatenateBuffers.js.map +1 -0
- package/build/utils/convertPCMToFloat32.d.ts +2 -2
- package/build/utils/convertPCMToFloat32.d.ts.map +1 -1
- package/build/utils/convertPCMToFloat32.js +49 -36
- package/build/utils/convertPCMToFloat32.js.map +1 -1
- package/build/utils/encodingToBitDepth.d.ts +1 -1
- package/build/utils/encodingToBitDepth.d.ts.map +1 -1
- package/build/utils/encodingToBitDepth.js +3 -3
- package/build/utils/encodingToBitDepth.js.map +1 -1
- package/build/utils/getWavFileInfo.d.ts +4 -3
- package/build/utils/getWavFileInfo.d.ts.map +1 -1
- package/build/utils/getWavFileInfo.js +18 -15
- package/build/utils/getWavFileInfo.js.map +1 -1
- package/build/utils/writeWavHeader.d.ts.map +1 -1
- package/build/utils/writeWavHeader.js +4 -4
- package/build/utils/writeWavHeader.js.map +1 -1
- package/build/workers/InlineFeaturesExtractor.web.d.ts.map +1 -1
- package/build/workers/InlineFeaturesExtractor.web.js.map +1 -1
- package/build/workers/inlineAudioWebWorker.web.d.ts.map +1 -1
- package/build/workers/inlineAudioWebWorker.web.js.map +1 -1
- package/expo-module.config.json +8 -17
- package/ios/AudioStreamManager.swift +1 -0
- package/ios/ExpoAudioStreamModule.swift +1 -0
- package/ios/RecordingResult.swift +1 -0
- package/package.json +72 -65
- package/plugin/build/index.d.ts +1 -1
- package/plugin/build/index.js +7 -7
- package/plugin/src/index.ts +47 -47
- package/plugin/tsconfig.json +8 -13
- package/src/AudioAnalysis/AudioAnalysis.types.ts +59 -60
- package/src/AudioAnalysis/extractAudioAnalysis.ts +132 -121
- package/src/AudioAnalysis/extractWaveform.ts +18 -18
- package/src/AudioRecorder.provider.tsx +53 -53
- package/src/ExpoAudioStream.native.ts +2 -2
- package/src/ExpoAudioStream.types.ts +56 -53
- package/src/ExpoAudioStream.web.ts +232 -205
- package/src/ExpoAudioStreamModule.ts +17 -16
- package/src/WebRecorder.web.ts +407 -390
- package/src/constants.ts +11 -11
- package/src/events.ts +27 -13
- package/src/index.ts +15 -15
- package/src/logger.ts +15 -18
- package/src/useAudioRecorder.tsx +394 -389
- package/src/utils/BlobFix.ts +550 -0
- package/src/utils/concatenateBuffers.ts +24 -0
- package/src/utils/convertPCMToFloat32.ts +72 -45
- package/src/utils/encodingToBitDepth.ts +14 -14
- package/src/utils/getWavFileInfo.ts +106 -99
- package/src/utils/writeWavHeader.ts +45 -45
- package/src/workers/InlineFeaturesExtractor.web.tsx +1 -1
- package/src/workers/inlineAudioWebWorker.web.tsx +1 -1
- package/tsconfig.json +12 -7
|
@@ -1,136 +1,147 @@
|
|
|
1
1
|
// packages/expo-audio-stream/src/AudioAnalysis/extractAudioAnalysis.ts
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
AmplitudeAlgorithm,
|
|
4
|
+
AudioAnalysis,
|
|
5
|
+
AudioFeaturesOptions,
|
|
6
|
+
} from './AudioAnalysis.types'
|
|
7
|
+
import ExpoAudioStreamModule from '../ExpoAudioStreamModule'
|
|
8
|
+
import { isWeb } from '../constants'
|
|
9
|
+
import { getLogger } from '../logger'
|
|
10
|
+
import { convertPCMToFloat32 } from '../utils/convertPCMToFloat32'
|
|
11
|
+
import { getWavFileInfo, WavFileInfo } from '../utils/getWavFileInfo'
|
|
12
|
+
import { InlineFeaturesExtractor } from '../workers/InlineFeaturesExtractor.web'
|
|
10
13
|
|
|
11
|
-
const logger = getLogger(
|
|
14
|
+
const logger = getLogger('extractAudioAnalysis')
|
|
15
|
+
|
|
16
|
+
export interface ExtractAudioAnalysisProps {
|
|
17
|
+
fileUri?: string // should provide either fileUri or arrayBuffer
|
|
18
|
+
wavMetadata?: WavFileInfo
|
|
19
|
+
arrayBuffer?: ArrayBuffer
|
|
20
|
+
bitDepth?: number
|
|
21
|
+
skipWavHeader?: boolean
|
|
22
|
+
durationMs?: number
|
|
23
|
+
sampleRate?: number
|
|
24
|
+
numberOfChannels?: number
|
|
25
|
+
algorithm?: AmplitudeAlgorithm
|
|
26
|
+
position?: number // Optional number of bytes to skip. Default is 0
|
|
27
|
+
length?: number // Optional number of bytes to read.
|
|
28
|
+
pointsPerSecond?: number // Optional number of points per second. Use to reduce the number of points and compute the number of datapoints to return.
|
|
29
|
+
features?: AudioFeaturesOptions
|
|
30
|
+
featuresExtratorUrl?: string
|
|
31
|
+
}
|
|
12
32
|
|
|
13
33
|
export const extractAudioAnalysis = async ({
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}:
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
34
|
+
fileUri,
|
|
35
|
+
pointsPerSecond = 20,
|
|
36
|
+
arrayBuffer,
|
|
37
|
+
bitDepth,
|
|
38
|
+
skipWavHeader = true,
|
|
39
|
+
durationMs,
|
|
40
|
+
sampleRate,
|
|
41
|
+
numberOfChannels,
|
|
42
|
+
algorithm = 'rms',
|
|
43
|
+
features,
|
|
44
|
+
featuresExtratorUrl,
|
|
45
|
+
}: ExtractAudioAnalysisProps): Promise<AudioAnalysis> => {
|
|
46
|
+
if (isWeb) {
|
|
47
|
+
if (!arrayBuffer && !fileUri) {
|
|
48
|
+
throw new Error('Either arrayBuffer or fileUri must be provided')
|
|
49
|
+
}
|
|
30
50
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
51
|
+
if (!arrayBuffer) {
|
|
52
|
+
logger.log(`fetching fileUri`, fileUri)
|
|
53
|
+
const response = await fetch(fileUri!)
|
|
34
54
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
55
|
+
if (!response.ok) {
|
|
56
|
+
throw new Error(
|
|
57
|
+
`Failed to fetch fileUri: ${response.statusText}`
|
|
58
|
+
)
|
|
59
|
+
}
|
|
38
60
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
61
|
+
arrayBuffer = await response.arrayBuffer()
|
|
62
|
+
logger.log(`fetched fileUri`, arrayBuffer.byteLength, arrayBuffer)
|
|
63
|
+
}
|
|
42
64
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
65
|
+
// Create a new copy of the ArrayBuffer to avoid detachment issues
|
|
66
|
+
const bufferCopy = arrayBuffer.slice(0)
|
|
67
|
+
logger.log(
|
|
68
|
+
`extractAudioAnalysis skipWavHeader=${skipWavHeader} bitDepth=${bitDepth} len=${bufferCopy.byteLength}`,
|
|
69
|
+
bufferCopy.slice(0, 100)
|
|
70
|
+
)
|
|
49
71
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
// let copyChannelData: Float32Array;
|
|
60
|
-
// try {
|
|
61
|
-
// const audioContext = new (window.AudioContext ||
|
|
62
|
-
// // @ts-ignore
|
|
63
|
-
// window.webkitAudioContext)();
|
|
64
|
-
// const audioBuffer = await audioContext.decodeAudioData(bufferCopy);
|
|
65
|
-
// const channelData = audioBuffer.getChannelData(0); // Use only the first channel
|
|
66
|
-
// copyChannelData = new Float32Array(channelData); // Create a new Float32Array
|
|
67
|
-
// } catch (error) {
|
|
68
|
-
// console.warn("Failed to decode audio data:", error);
|
|
69
|
-
// // Fall back to creating a new Float32Array from the ArrayBuffer if decoding fails
|
|
70
|
-
// copyChannelData = new Float32Array(arrayBuffer);
|
|
71
|
-
// }
|
|
72
|
+
let actualBitDepth = bitDepth
|
|
73
|
+
if (!actualBitDepth) {
|
|
74
|
+
logger.log(
|
|
75
|
+
`extractAudioAnalysis bitDepth not provided -- getting wav file info`
|
|
76
|
+
)
|
|
77
|
+
const fileInfo = await getWavFileInfo(bufferCopy)
|
|
78
|
+
actualBitDepth = fileInfo.bitDepth
|
|
79
|
+
}
|
|
80
|
+
logger.log(`extractAudioAnalysis actualBitDepth=${actualBitDepth}`)
|
|
72
81
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
82
|
+
const {
|
|
83
|
+
pcmValues: channelData,
|
|
84
|
+
min,
|
|
85
|
+
max,
|
|
86
|
+
} = await convertPCMToFloat32({
|
|
87
|
+
buffer: arrayBuffer,
|
|
88
|
+
bitDepth: actualBitDepth,
|
|
89
|
+
skipWavHeader,
|
|
90
|
+
})
|
|
91
|
+
logger.log(
|
|
92
|
+
`extractAudioAnalysis skipWaveHeader=${skipWavHeader} convertPCMToFloat32 length=${channelData.length} range: [ ${min} :: ${max} ]`
|
|
93
|
+
)
|
|
85
94
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
95
|
+
return new Promise((resolve, reject) => {
|
|
96
|
+
let worker: Worker
|
|
97
|
+
if (featuresExtratorUrl) {
|
|
98
|
+
worker = new Worker(
|
|
99
|
+
new URL(featuresExtratorUrl, window.location.href)
|
|
100
|
+
)
|
|
101
|
+
} else {
|
|
102
|
+
const blob = new Blob([InlineFeaturesExtractor], {
|
|
103
|
+
type: 'application/javascript',
|
|
104
|
+
})
|
|
105
|
+
const url = URL.createObjectURL(blob)
|
|
106
|
+
worker = new Worker(url)
|
|
107
|
+
}
|
|
97
108
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
109
|
+
worker.onmessage = (event) => {
|
|
110
|
+
resolve(event.data.result)
|
|
111
|
+
}
|
|
101
112
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
113
|
+
worker.onerror = (error) => {
|
|
114
|
+
reject(error)
|
|
115
|
+
}
|
|
105
116
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
117
|
+
worker.postMessage({
|
|
118
|
+
command: 'process',
|
|
119
|
+
channelData,
|
|
120
|
+
sampleRate,
|
|
121
|
+
pointsPerSecond,
|
|
122
|
+
algorithm,
|
|
123
|
+
bitDepth,
|
|
124
|
+
fullAudioDurationMs: durationMs,
|
|
125
|
+
numberOfChannels,
|
|
126
|
+
})
|
|
127
|
+
})
|
|
128
|
+
} else {
|
|
129
|
+
if (!fileUri) {
|
|
130
|
+
throw new Error('fileUri is required')
|
|
131
|
+
}
|
|
132
|
+
logger.log(`extractAudioAnalysis`, {
|
|
133
|
+
fileUri,
|
|
134
|
+
pointsPerSecond,
|
|
135
|
+
algorithm,
|
|
136
|
+
})
|
|
137
|
+
const res = await ExpoAudioStreamModule.extractAudioAnalysis({
|
|
138
|
+
fileUri,
|
|
139
|
+
pointsPerSecond,
|
|
140
|
+
skipWavHeader,
|
|
141
|
+
algorithm,
|
|
142
|
+
features,
|
|
143
|
+
})
|
|
144
|
+
logger.log(`extractAudioAnalysis`, res)
|
|
145
|
+
return res
|
|
120
146
|
}
|
|
121
|
-
|
|
122
|
-
fileUri,
|
|
123
|
-
pointsPerSecond,
|
|
124
|
-
algorithm,
|
|
125
|
-
});
|
|
126
|
-
const res = await ExpoAudioStreamModule.extractAudioAnalysis({
|
|
127
|
-
fileUri,
|
|
128
|
-
pointsPerSecond,
|
|
129
|
-
skipWavHeader,
|
|
130
|
-
algorithm,
|
|
131
|
-
features,
|
|
132
|
-
});
|
|
133
|
-
logger.log(`extractAudioAnalysis`, res);
|
|
134
|
-
return res;
|
|
135
|
-
}
|
|
136
|
-
};
|
|
147
|
+
}
|
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
import ExpoAudioStreamModule from
|
|
2
|
-
import { getLogger } from
|
|
1
|
+
import ExpoAudioStreamModule from '../ExpoAudioStreamModule'
|
|
2
|
+
import { getLogger } from '../logger'
|
|
3
3
|
|
|
4
|
-
const logger = getLogger(
|
|
4
|
+
const logger = getLogger('extractWaveform')
|
|
5
5
|
export interface ExtractWaveformProps {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
fileUri: string
|
|
7
|
+
numberOfSamples: number
|
|
8
|
+
offset?: number
|
|
9
|
+
length?: number
|
|
10
10
|
}
|
|
11
11
|
export const extractWaveform = async ({
|
|
12
|
-
fileUri,
|
|
13
|
-
numberOfSamples,
|
|
14
|
-
offset = 0,
|
|
15
|
-
length,
|
|
16
|
-
}: ExtractWaveformProps): Promise<unknown> => {
|
|
17
|
-
const res = await ExpoAudioStreamModule.extractAudioAnalysis({
|
|
18
12
|
fileUri,
|
|
19
13
|
numberOfSamples,
|
|
20
|
-
offset,
|
|
14
|
+
offset = 0,
|
|
21
15
|
length,
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
16
|
+
}: ExtractWaveformProps): Promise<unknown> => {
|
|
17
|
+
const res = await ExpoAudioStreamModule.extractAudioAnalysis({
|
|
18
|
+
fileUri,
|
|
19
|
+
numberOfSamples,
|
|
20
|
+
offset,
|
|
21
|
+
length,
|
|
22
|
+
})
|
|
23
|
+
logger.log(`extractWaveform`, res)
|
|
24
|
+
return res
|
|
25
|
+
}
|
|
@@ -1,70 +1,70 @@
|
|
|
1
1
|
// packages/expo-audio-stream/src/AudioRecorder.provider.tsx
|
|
2
|
-
import React, { createContext, useContext } from
|
|
2
|
+
import React, { createContext, useContext } from 'react'
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { AudioAnalysis } from './AudioAnalysis/AudioAnalysis.types'
|
|
5
5
|
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
} from
|
|
10
|
-
import { UseAudioRecorderProps, useAudioRecorder } from
|
|
6
|
+
AudioRecording,
|
|
7
|
+
RecordingConfig,
|
|
8
|
+
StartRecordingResult,
|
|
9
|
+
} from './ExpoAudioStream.types'
|
|
10
|
+
import { UseAudioRecorderProps, useAudioRecorder } from './useAudioRecorder'
|
|
11
11
|
|
|
12
12
|
export interface UseAudioRecorderState {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
13
|
+
startRecording: (_: RecordingConfig) => Promise<StartRecordingResult>
|
|
14
|
+
stopRecording: () => Promise<AudioRecording | null>
|
|
15
|
+
pauseRecording: () => void
|
|
16
|
+
resumeRecording: () => void
|
|
17
|
+
isRecording: boolean
|
|
18
|
+
isPaused: boolean
|
|
19
|
+
durationMs: number // Duration of the recording
|
|
20
|
+
size: number // Size in bytes of the recorded audio
|
|
21
|
+
analysisData?: AudioAnalysis // Analysis data for the recording depending on enableProcessing flag
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
const initContext: UseAudioRecorderState = {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
25
|
+
isRecording: false,
|
|
26
|
+
isPaused: false,
|
|
27
|
+
durationMs: 0,
|
|
28
|
+
size: 0,
|
|
29
|
+
startRecording: async () => {
|
|
30
|
+
throw new Error('AudioRecorderProvider not found')
|
|
31
|
+
},
|
|
32
|
+
stopRecording: async () => {
|
|
33
|
+
throw new Error('AudioRecorderProvider not found')
|
|
34
|
+
},
|
|
35
|
+
pauseRecording: () => {
|
|
36
|
+
throw new Error('AudioRecorderProvider not found')
|
|
37
|
+
},
|
|
38
|
+
resumeRecording: () => {
|
|
39
|
+
throw new Error('AudioRecorderProvider not found')
|
|
40
|
+
},
|
|
41
|
+
}
|
|
42
42
|
|
|
43
|
-
const AudioRecorderContext = createContext<UseAudioRecorderState>(initContext)
|
|
43
|
+
const AudioRecorderContext = createContext<UseAudioRecorderState>(initContext)
|
|
44
44
|
|
|
45
45
|
interface AudioRecorderProviderProps {
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
children: React.ReactNode
|
|
47
|
+
config?: UseAudioRecorderProps
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
export const AudioRecorderProvider: React.FC<AudioRecorderProviderProps> = ({
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
children,
|
|
52
|
+
config = {},
|
|
53
53
|
}) => {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
54
|
+
const audioRecorder = useAudioRecorder(config)
|
|
55
|
+
return (
|
|
56
|
+
<AudioRecorderContext.Provider value={audioRecorder}>
|
|
57
|
+
{children}
|
|
58
|
+
</AudioRecorderContext.Provider>
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
61
|
|
|
62
62
|
export const useSharedAudioRecorder = () => {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
63
|
+
const context = useContext(AudioRecorderContext)
|
|
64
|
+
if (!context) {
|
|
65
|
+
throw new Error(
|
|
66
|
+
'useSharedAudioRecorder must be used within an AudioRecorderProvider'
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
return context
|
|
70
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/ExpoAudioStreamModule.ts
|
|
2
|
-
import { requireNativeModule } from
|
|
2
|
+
import { requireNativeModule } from 'expo-modules-core'
|
|
3
3
|
|
|
4
4
|
// It loads the native module object from the JSI or falls back to
|
|
5
5
|
// the bridge module (from NativeModulesProxy) if the remote debugger is on.
|
|
6
|
-
export default requireNativeModule(
|
|
6
|
+
export default requireNativeModule('ExpoAudioStream')
|
|
@@ -1,74 +1,77 @@
|
|
|
1
1
|
// packages/expo-audio-stream/src/ExpoAudioStream.types.ts
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
AmplitudeAlgorithm,
|
|
4
|
+
AudioAnalysis,
|
|
5
|
+
AudioFeaturesOptions,
|
|
6
|
+
} from './AudioAnalysis/AudioAnalysis.types'
|
|
7
|
+
import { AudioAnalysisEvent } from './events'
|
|
6
8
|
|
|
7
9
|
export interface AudioStreamStatus {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
isRecording: boolean
|
|
11
|
+
isPaused: boolean
|
|
12
|
+
durationMs: number
|
|
13
|
+
size: number
|
|
14
|
+
interval: number
|
|
15
|
+
mimeType: string
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
export interface AudioDataEvent {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
data: string | Float32Array
|
|
20
|
+
position: number
|
|
21
|
+
fileUri: string
|
|
22
|
+
eventDataSize: number
|
|
23
|
+
totalSize: number
|
|
22
24
|
}
|
|
23
25
|
|
|
24
|
-
export
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
totalSize: number;
|
|
32
|
-
mimeType: string;
|
|
33
|
-
streamUuid: string;
|
|
26
|
+
export type EncodingType = 'pcm_32bit' | 'pcm_16bit' | 'pcm_8bit'
|
|
27
|
+
export type SampleRate = 16000 | 44100 | 48000
|
|
28
|
+
export type BitDepth = 8 | 16 | 32
|
|
29
|
+
|
|
30
|
+
export interface Chunk {
|
|
31
|
+
text: string
|
|
32
|
+
timestamp: [number, number | null]
|
|
34
33
|
}
|
|
35
34
|
|
|
36
|
-
export
|
|
37
|
-
|
|
38
|
-
|
|
35
|
+
export interface TranscriberData {
|
|
36
|
+
isBusy: boolean
|
|
37
|
+
text: string
|
|
38
|
+
chunks: Chunk[]
|
|
39
|
+
}
|
|
39
40
|
|
|
40
|
-
export interface
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
41
|
+
export interface AudioRecording {
|
|
42
|
+
fileUri: string
|
|
43
|
+
filename: string
|
|
44
|
+
durationMs: number
|
|
45
|
+
size: number
|
|
46
|
+
mimeType: string
|
|
47
|
+
channels: number
|
|
48
|
+
bitDepth: BitDepth
|
|
49
|
+
sampleRate: SampleRate
|
|
50
|
+
transcripts?: TranscriberData[]
|
|
51
|
+
wavPCMData?: Float32Array // Full PCM data for the recording in WAV format (only on web, for native use the fileUri)
|
|
52
|
+
analysisData?: AudioAnalysis // Analysis data for the recording depending on enableProcessing flag
|
|
49
53
|
}
|
|
50
54
|
|
|
51
55
|
export interface StartRecordingResult {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
56
|
+
fileUri: string
|
|
57
|
+
mimeType: string
|
|
58
|
+
channels?: number
|
|
59
|
+
bitDepth?: BitDepth
|
|
60
|
+
sampleRate?: SampleRate
|
|
57
61
|
}
|
|
58
62
|
|
|
59
63
|
export interface RecordingConfig {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
+
sampleRate?: SampleRate // Sample rate for recording
|
|
65
|
+
channels?: 1 | 2 // 1 or 2 (MONO or STEREO)
|
|
66
|
+
encoding?: EncodingType // Encoding type for the recording
|
|
67
|
+
interval?: number // Interval in milliseconds at which to emit recording data
|
|
64
68
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
69
|
+
// Optional parameters for audio processing
|
|
70
|
+
enableProcessing?: boolean // Boolean to enable/disable audio processing (default is false)
|
|
71
|
+
pointsPerSecond?: number // Number of data points to extract per second of audio (default is 1000)
|
|
72
|
+
algorithm?: AmplitudeAlgorithm // Algorithm to use for amplitude computation (default is "rms")
|
|
73
|
+
features?: AudioFeaturesOptions // Feature options to extract (default is empty)
|
|
70
74
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
onProcessingResult?: (_: AudioAnalysisData) => Promise<void>; // Callback function to handle processing results
|
|
75
|
+
onAudioStream?: (_: AudioDataEvent) => Promise<void> // Callback function to handle audio stream
|
|
76
|
+
onAudioAnalysis?: (_: AudioAnalysisEvent) => Promise<void> // Callback function to handle audio features extraction results
|
|
74
77
|
}
|