@siteed/expo-audio-stream 0.5.2 → 0.7.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/android/src/main/java/net/siteed/audiostream/AudioDataEncoder.kt +9 -0
- package/android/src/main/java/net/siteed/audiostream/AudioFileHandler.kt +62 -0
- package/android/src/main/java/net/siteed/audiostream/AudioFormatUtils.kt +4 -0
- package/android/src/main/java/net/siteed/audiostream/AudioRecorderManager.kt +445 -0
- package/android/src/main/java/net/siteed/audiostream/Constants.kt +12 -0
- package/android/src/main/java/net/siteed/audiostream/EventSender.kt +7 -0
- package/android/src/main/java/net/siteed/audiostream/ExpoAudioStreamModule.kt +39 -430
- package/android/src/main/java/net/siteed/audiostream/PermissionUtils.kt +16 -0
- package/build/ExpoAudioStream.types.d.ts +5 -1
- package/build/ExpoAudioStream.types.d.ts.map +1 -1
- package/build/ExpoAudioStream.types.js.map +1 -1
- package/build/ExpoAudioStreamModule.web.d.ts +2 -2
- package/build/ExpoAudioStreamModule.web.d.ts.map +1 -1
- package/build/ExpoAudioStreamModule.web.js.map +1 -1
- package/build/index.d.ts +1 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +3 -0
- package/build/index.js.map +1 -1
- package/build/useAudioRecording.d.ts +4 -2
- package/build/useAudioRecording.d.ts.map +1 -1
- package/build/useAudioRecording.js +18 -13
- package/build/useAudioRecording.js.map +1 -1
- package/ios/AudioStreamManager.swift +26 -21
- package/ios/ExpoAudioStreamModule.swift +12 -6
- package/package.json +1 -1
- package/src/ExpoAudioStream.types.ts +6 -5
- package/src/ExpoAudioStreamModule.web.ts +2 -2
- package/src/index.ts +4 -0
- package/src/useAudioRecording.ts +25 -18
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,kBAAkB,GAEnB,MAAM,mBAAmB,CAAC;AAK3B,OAAO,qBAAqB,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EACL,gBAAgB,GAGjB,MAAM,qBAAqB,CAAC;AAE7B,MAAM,OAAO,GAAG,IAAI,YAAY,CAC9B,qBAAqB,IAAI,kBAAkB,CAAC,eAAe,CAC5D,CAAC;AAEF,MAAM,UAAU,cAAc;IAC5B,OAAO,qBAAqB,CAAC,cAAc,EAAE,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,OAAO,qBAAqB,CAAC,eAAe,EAAE,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,QAAqD;IAErD,OAAO,CAAC,GAAG,CAAC,uBAAuB,EAAE,QAAQ,CAAC,CAAC;IAC/C,OAAO,OAAO,CAAC,WAAW,CAAoB,WAAW,EAAE,QAAQ,CAAC,CAAC;AACvE,CAAC;AAGD,OAAO,EAAE,gBAAgB,EAAE,CAAC","sourcesContent":["import {\n EventEmitter,\n NativeModulesProxy,\n type Subscription,\n} from \"expo-modules-core\";\n\n// Import the native module. On web, it will be resolved to ExpoAudioStream.web.ts\n// and on native platforms to ExpoAudioStream.ts\nimport { AudioEventPayload } from \"./ExpoAudioStream.types\";\nimport ExpoAudioStreamModule from \"./ExpoAudioStreamModule\";\nimport {\n useAudioRecorder,\n UseAudioRecorderState,\n AudioDataEvent,\n} from \"./useAudioRecording\";\n\nconst emitter = new EventEmitter(\n ExpoAudioStreamModule ?? NativeModulesProxy.ExpoAudioStream,\n);\n\nexport function listAudioFiles(): Promise<string[]> {\n return ExpoAudioStreamModule.listAudioFiles();\n}\n\nexport function clearAudioFiles(): Promise<void> {\n return ExpoAudioStreamModule.clearAudioFiles();\n}\n\nexport function addAudioEventListener(\n listener: (event: AudioEventPayload) => Promise<void>,\n): Subscription {\n console.log(`addAudioEventListener`, listener);\n return emitter.addListener<AudioEventPayload>(\"AudioData\", listener);\n}\n\nexport type { AudioEventPayload, UseAudioRecorderState, AudioDataEvent };\nexport { useAudioRecorder };\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,kBAAkB,GAEnB,MAAM,mBAAmB,CAAC;AAK3B,OAAO,qBAAqB,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EACL,gBAAgB,GAGjB,MAAM,qBAAqB,CAAC;AAE7B,MAAM,OAAO,GAAG,IAAI,YAAY,CAC9B,qBAAqB,IAAI,kBAAkB,CAAC,eAAe,CAC5D,CAAC;AAEF,MAAM,UAAU,cAAc;IAC5B,OAAO,qBAAqB,CAAC,cAAc,EAAE,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,OAAO,qBAAqB,CAAC,eAAe,EAAE,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,IAAI;IAClB,OAAO,qBAAqB,CAAC,IAAI,EAAE,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,QAAqD;IAErD,OAAO,CAAC,GAAG,CAAC,uBAAuB,EAAE,QAAQ,CAAC,CAAC;IAC/C,OAAO,OAAO,CAAC,WAAW,CAAoB,WAAW,EAAE,QAAQ,CAAC,CAAC;AACvE,CAAC;AAGD,OAAO,EAAE,gBAAgB,EAAE,CAAC","sourcesContent":["import {\n EventEmitter,\n NativeModulesProxy,\n type Subscription,\n} from \"expo-modules-core\";\n\n// Import the native module. On web, it will be resolved to ExpoAudioStream.web.ts\n// and on native platforms to ExpoAudioStream.ts\nimport { AudioEventPayload } from \"./ExpoAudioStream.types\";\nimport ExpoAudioStreamModule from \"./ExpoAudioStreamModule\";\nimport {\n useAudioRecorder,\n UseAudioRecorderState,\n AudioDataEvent,\n} from \"./useAudioRecording\";\n\nconst emitter = new EventEmitter(\n ExpoAudioStreamModule ?? NativeModulesProxy.ExpoAudioStream,\n);\n\nexport function listAudioFiles(): Promise<string[]> {\n return ExpoAudioStreamModule.listAudioFiles();\n}\n\nexport function clearAudioFiles(): Promise<void> {\n return ExpoAudioStreamModule.clearAudioFiles();\n}\n\nexport function test(): void {\n return ExpoAudioStreamModule.test();\n}\n\nexport function addAudioEventListener(\n listener: (event: AudioEventPayload) => Promise<void>,\n): Subscription {\n console.log(`addAudioEventListener`, listener);\n return emitter.addListener<AudioEventPayload>(\"AudioData\", listener);\n}\n\nexport type { AudioEventPayload, UseAudioRecorderState, AudioDataEvent };\nexport { useAudioRecorder };\n"]}
|
|
@@ -1,14 +1,16 @@
|
|
|
1
|
-
import { AudioStreamResult,
|
|
1
|
+
import { AudioStreamResult, RecordingConfig, StartAudioStreamResult } from "./ExpoAudioStream.types";
|
|
2
2
|
export interface AudioDataEvent {
|
|
3
3
|
data: string | Blob;
|
|
4
4
|
position: number;
|
|
5
|
+
fileUri: string;
|
|
5
6
|
eventDataSize: number;
|
|
6
7
|
totalSize: number;
|
|
7
8
|
}
|
|
8
9
|
export interface UseAudioRecorderState {
|
|
9
|
-
startRecording: (_:
|
|
10
|
+
startRecording: (_: RecordingConfig) => Promise<StartAudioStreamResult>;
|
|
10
11
|
stopRecording: () => Promise<AudioStreamResult | null>;
|
|
11
12
|
pauseRecording: () => void;
|
|
13
|
+
resumeRecording: () => void;
|
|
12
14
|
isRecording: boolean;
|
|
13
15
|
isPaused: boolean;
|
|
14
16
|
duration: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAudioRecording.d.ts","sourceRoot":"","sources":["../src/useAudioRecording.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,iBAAiB,EAEjB,
|
|
1
|
+
{"version":3,"file":"useAudioRecording.d.ts","sourceRoot":"","sources":["../src/useAudioRecording.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,iBAAiB,EAEjB,eAAe,EACf,sBAAsB,EACvB,MAAM,yBAAyB,CAAC;AAGjC,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB;AACD,MAAM,WAAW,qBAAqB;IACpC,cAAc,EAAE,CAAC,CAAC,EAAE,eAAe,KAAK,OAAO,CAAC,sBAAsB,CAAC,CAAC;IACxE,aAAa,EAAE,MAAM,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;IACvD,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,WAAW,EAAE,OAAO,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,aAAa,EACb,KAAa,GACd,EAAE;IACD,aAAa,CAAC,EAAE,CAAC,CAAC,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,GAAG,qBAAqB,CA+MxB"}
|
|
@@ -73,6 +73,7 @@ export function useAudioRecorder({ onAudioStream, debug = false, }) {
|
|
|
73
73
|
onAudioStream?.({
|
|
74
74
|
data: encoded,
|
|
75
75
|
position,
|
|
76
|
+
fileUri,
|
|
76
77
|
eventDataSize: deltaSize,
|
|
77
78
|
totalSize,
|
|
78
79
|
});
|
|
@@ -101,6 +102,7 @@ export function useAudioRecorder({ onAudioStream, debug = false, }) {
|
|
|
101
102
|
onAudioStream?.({
|
|
102
103
|
data: buffer,
|
|
103
104
|
position,
|
|
105
|
+
fileUri,
|
|
104
106
|
eventDataSize: deltaSize,
|
|
105
107
|
totalSize,
|
|
106
108
|
});
|
|
@@ -126,29 +128,31 @@ export function useAudioRecorder({ onAudioStream, debug = false, }) {
|
|
|
126
128
|
setIsPaused(false);
|
|
127
129
|
setSize(0);
|
|
128
130
|
setDuration(0);
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
console.log(`[useAudioRecorder] start recoding`, recordingOptions);
|
|
132
|
-
}
|
|
133
|
-
const fileUrl = await ExpoAudioStreamModule.startRecording(recordingOptions);
|
|
134
|
-
return fileUrl;
|
|
135
|
-
}
|
|
136
|
-
catch (error) {
|
|
137
|
-
console.error("[useAudioRecorder] Error starting recording:", error);
|
|
138
|
-
setIsRecording(false);
|
|
131
|
+
if (debug) {
|
|
132
|
+
console.log(`[useAudioRecorder] start recoding`, recordingOptions);
|
|
139
133
|
}
|
|
134
|
+
const result = await ExpoAudioStreamModule.startRecording(recordingOptions);
|
|
135
|
+
return result;
|
|
140
136
|
}, [debug]);
|
|
141
137
|
const stopRecording = useCallback(async () => {
|
|
142
|
-
console.log(`STOOOOOP NOW`);
|
|
143
138
|
const result = await ExpoAudioStreamModule.stopRecording();
|
|
144
|
-
console.log(`STOOOOOP NOW 2`);
|
|
145
139
|
setIsRecording(false);
|
|
146
140
|
setIsPaused(false);
|
|
147
141
|
return result;
|
|
148
142
|
}, []);
|
|
149
143
|
const pauseRecording = useCallback(async () => {
|
|
150
144
|
try {
|
|
151
|
-
await ExpoAudioStreamModule.
|
|
145
|
+
await ExpoAudioStreamModule.pauseRecording();
|
|
146
|
+
setIsPaused(true);
|
|
147
|
+
setIsRecording(false);
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
console.error("[useAudioRecorder] Error pausing recording:", error);
|
|
151
|
+
}
|
|
152
|
+
}, [debug]);
|
|
153
|
+
const resumeRecording = useCallback(async () => {
|
|
154
|
+
try {
|
|
155
|
+
await ExpoAudioStreamModule.resumeRecording();
|
|
152
156
|
setIsPaused(true);
|
|
153
157
|
setIsRecording(false);
|
|
154
158
|
}
|
|
@@ -160,6 +164,7 @@ export function useAudioRecorder({ onAudioStream, debug = false, }) {
|
|
|
160
164
|
startRecording,
|
|
161
165
|
stopRecording,
|
|
162
166
|
pauseRecording,
|
|
167
|
+
resumeRecording,
|
|
163
168
|
isPaused,
|
|
164
169
|
isRecording,
|
|
165
170
|
duration,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAudioRecording.js","sourceRoot":"","sources":["../src/useAudioRecording.ts"],"names":[],"mappings":"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","sourcesContent":["import { Platform } from \"expo-modules-core\";\nimport { useCallback, useEffect, useState } from \"react\";\n\nimport { addAudioEventListener } from \".\";\nimport {\n AudioStreamResult,\n AudioStreamStatus,\n RecordingOptions,\n StartAudioStreamResult,\n} from \"./ExpoAudioStream.types\";\nimport ExpoAudioStreamModule from \"./ExpoAudioStreamModule\";\n\nexport interface AudioDataEvent {\n data: string | Blob;\n position: number;\n eventDataSize: number;\n totalSize: number;\n}\nexport interface UseAudioRecorderState {\n startRecording: (_: RecordingOptions) => Promise<StartAudioStreamResult>;\n stopRecording: () => Promise<AudioStreamResult | null>;\n pauseRecording: () => void;\n isRecording: boolean;\n isPaused: boolean;\n duration: number; // Duration of the recording\n size: number; // Size in bytes of the recorded audio\n}\n\nexport function useAudioRecorder({\n onAudioStream,\n debug = false,\n}: {\n onAudioStream?: (_: AudioDataEvent) => Promise<void>;\n debug?: boolean;\n}): UseAudioRecorderState {\n const [isRecording, setIsRecording] = useState(false);\n const [isPaused, setIsPaused] = useState(false);\n const [duration, setDuration] = useState(0);\n const [size, setSize] = useState(0);\n\n const checkStatus = useCallback(async () => {\n try {\n if (!isRecording) {\n return;\n }\n\n const status: AudioStreamStatus = ExpoAudioStreamModule.status();\n if (debug) {\n console.log(`[useAudioRecorder] Status:`, status);\n }\n\n if (!status.isRecording) {\n // Don't update if recording stopped.\n return;\n }\n // Extract matching file from filesystem\n setDuration(status.duration);\n setSize(status.size);\n } catch (error) {\n console.error(`[useAudioRecorder] Error getting status:`, error);\n }\n }, [isRecording]);\n\n useEffect(() => {\n const interval = setInterval(checkStatus, 1000);\n return () => clearInterval(interval);\n }, [checkStatus]);\n\n useEffect(() => {\n if (debug) {\n console.log(\n `[useAudioRecorder] Registering audio event listener`,\n onAudioStream,\n );\n }\n const subscribe = addAudioEventListener(\n async ({\n fileUri,\n deltaSize,\n totalSize,\n lastEmittedSize,\n position,\n streamUuid,\n encoded,\n mimeType,\n buffer,\n }) => {\n try {\n if (debug) {\n console.log(`[useAudioRecorder] Received audio event:`, {\n fileUri,\n deltaSize,\n totalSize,\n position,\n mimeType,\n lastEmittedSize,\n streamUuid,\n encodedLength: encoded?.length,\n });\n }\n if (deltaSize > 0) {\n // Coming from native ( ios / android ) otherwise buffer is set\n if (Platform.OS !== \"web\") {\n // Read the audio file as a base64 string for comparison\n try {\n if (!encoded) {\n console.error(\n \"[useAudioRecorder] Encoded audio data is missing\",\n );\n throw new Error(\"Encoded audio data is missing\");\n }\n // const binaryData = atob(encoded);\n // const bytes = new Uint8Array(binaryData.length);\n // for (let i = 0; i < binaryData.length; i++) {\n // bytes[i] = binaryData.charCodeAt(i) & 0xff; // Mask to 8 bits\n // }\n // const arrayBuffer = bytes.buffer;\n\n // if (debug) {\n // console.log(\n // `[useAudioRecorder] Read audio file position=${position} deltaSize: ${deltaSize} vs encoded.length: ${encoded.length}`,\n // );\n // }\n\n onAudioStream?.({\n data: encoded,\n position,\n eventDataSize: deltaSize,\n totalSize,\n });\n\n // Below code is optional, used to compare encoded data to audio on file system\n // Fetch the audio data from the fileUri\n // const options = {\n // encoding: FileSystem.EncodingType.Base64,\n // position: lastEmittedSize,\n // length: deltaSize,\n // };\n // const base64Content = await FileSystem.readAsStringAsync(fileUri, options);\n // const binaryData = atob(base64Content);\n // const content = new Uint8Array(binaryData.length);\n // for (let i = 0; i < binaryData.length; i++) {\n // content[i] = binaryData.charCodeAt(i);\n // }\n // const audioBlob = new Blob([content], { type: 'application/octet-stream' }); // Create a Blob from the byte array\n // console.debug(`Read audio file (len: ${content.length}) vs ${deltaSize}`)\n } catch (error) {\n console.error(\n \"[useAudioRecorder] Error reading audio file:\",\n error,\n );\n }\n } else if (buffer) {\n // Coming from web\n onAudioStream?.({\n data: buffer,\n position,\n eventDataSize: deltaSize,\n totalSize,\n });\n }\n }\n } catch (error) {\n console.error(\n \"[useAudioRecorder] Error processing audio event:\",\n error,\n );\n }\n },\n );\n if (debug) {\n console.log(\n `[useAudioRecorder] Subscribed to audio event listener`,\n subscribe,\n );\n }\n return () => {\n if (debug) {\n console.log(`[useAudioRecorder] Removing audio event listener`);\n }\n subscribe.remove();\n };\n }, []);\n\n const startRecording = useCallback(\n async (recordingOptions: RecordingOptions) => {\n setIsRecording(true);\n setIsPaused(false);\n setSize(0);\n setDuration(0);\n try {\n if (debug) {\n console.log(`[useAudioRecorder] start recoding`, recordingOptions);\n }\n\n const fileUrl =\n await ExpoAudioStreamModule.startRecording(recordingOptions);\n\n return fileUrl;\n } catch (error) {\n console.error(\"[useAudioRecorder] Error starting recording:\", error);\n setIsRecording(false);\n }\n },\n [debug],\n );\n\n const stopRecording = useCallback(async () => {\n console.log(`STOOOOOP NOW`);\n const result: AudioStreamResult =\n await ExpoAudioStreamModule.stopRecording();\n console.log(`STOOOOOP NOW 2`);\n setIsRecording(false);\n setIsPaused(false);\n return result;\n }, []);\n\n const pauseRecording = useCallback(async () => {\n try {\n await ExpoAudioStreamModule.stopRecording();\n setIsPaused(true);\n setIsRecording(false);\n } catch (error) {\n console.error(\"[useAudioRecorder] Error pausing recording:\", error);\n }\n }, [debug]);\n\n return {\n startRecording,\n stopRecording,\n pauseRecording,\n isPaused,\n isRecording,\n duration,\n size,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"useAudioRecording.js","sourceRoot":"","sources":["../src/useAudioRecording.ts"],"names":[],"mappings":"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","sourcesContent":["import { Platform } from \"expo-modules-core\";\nimport { useCallback, useEffect, useState } from \"react\";\n\nimport { addAudioEventListener } from \".\";\nimport {\n AudioStreamResult,\n AudioStreamStatus,\n RecordingConfig,\n StartAudioStreamResult,\n} from \"./ExpoAudioStream.types\";\nimport ExpoAudioStreamModule from \"./ExpoAudioStreamModule\";\n\nexport interface AudioDataEvent {\n data: string | Blob;\n position: number;\n fileUri: string;\n eventDataSize: number;\n totalSize: number;\n}\nexport interface UseAudioRecorderState {\n startRecording: (_: RecordingConfig) => Promise<StartAudioStreamResult>;\n stopRecording: () => Promise<AudioStreamResult | null>;\n pauseRecording: () => void;\n resumeRecording: () => void;\n isRecording: boolean;\n isPaused: boolean;\n duration: number; // Duration of the recording\n size: number; // Size in bytes of the recorded audio\n}\n\nexport function useAudioRecorder({\n onAudioStream,\n debug = false,\n}: {\n onAudioStream?: (_: AudioDataEvent) => Promise<void>;\n debug?: boolean;\n}): UseAudioRecorderState {\n const [isRecording, setIsRecording] = useState(false);\n const [isPaused, setIsPaused] = useState(false);\n const [duration, setDuration] = useState(0);\n const [size, setSize] = useState(0);\n\n const checkStatus = useCallback(async () => {\n try {\n if (!isRecording) {\n return;\n }\n\n const status: AudioStreamStatus = ExpoAudioStreamModule.status();\n if (debug) {\n console.log(`[useAudioRecorder] Status:`, status);\n }\n\n if (!status.isRecording) {\n // Don't update if recording stopped.\n return;\n }\n // Extract matching file from filesystem\n setDuration(status.duration);\n setSize(status.size);\n } catch (error) {\n console.error(`[useAudioRecorder] Error getting status:`, error);\n }\n }, [isRecording]);\n\n useEffect(() => {\n const interval = setInterval(checkStatus, 1000);\n return () => clearInterval(interval);\n }, [checkStatus]);\n\n useEffect(() => {\n if (debug) {\n console.log(\n `[useAudioRecorder] Registering audio event listener`,\n onAudioStream,\n );\n }\n const subscribe = addAudioEventListener(\n async ({\n fileUri,\n deltaSize,\n totalSize,\n lastEmittedSize,\n position,\n streamUuid,\n encoded,\n mimeType,\n buffer,\n }) => {\n try {\n if (debug) {\n console.log(`[useAudioRecorder] Received audio event:`, {\n fileUri,\n deltaSize,\n totalSize,\n position,\n mimeType,\n lastEmittedSize,\n streamUuid,\n encodedLength: encoded?.length,\n });\n }\n if (deltaSize > 0) {\n // Coming from native ( ios / android ) otherwise buffer is set\n if (Platform.OS !== \"web\") {\n // Read the audio file as a base64 string for comparison\n try {\n if (!encoded) {\n console.error(\n \"[useAudioRecorder] Encoded audio data is missing\",\n );\n throw new Error(\"Encoded audio data is missing\");\n }\n // const binaryData = atob(encoded);\n // const bytes = new Uint8Array(binaryData.length);\n // for (let i = 0; i < binaryData.length; i++) {\n // bytes[i] = binaryData.charCodeAt(i) & 0xff; // Mask to 8 bits\n // }\n // const arrayBuffer = bytes.buffer;\n\n // if (debug) {\n // console.log(\n // `[useAudioRecorder] Read audio file position=${position} deltaSize: ${deltaSize} vs encoded.length: ${encoded.length}`,\n // );\n // }\n\n onAudioStream?.({\n data: encoded,\n position,\n fileUri,\n eventDataSize: deltaSize,\n totalSize,\n });\n\n // Below code is optional, used to compare encoded data to audio on file system\n // Fetch the audio data from the fileUri\n // const options = {\n // encoding: FileSystem.EncodingType.Base64,\n // position: lastEmittedSize,\n // length: deltaSize,\n // };\n // const base64Content = await FileSystem.readAsStringAsync(fileUri, options);\n // const binaryData = atob(base64Content);\n // const content = new Uint8Array(binaryData.length);\n // for (let i = 0; i < binaryData.length; i++) {\n // content[i] = binaryData.charCodeAt(i);\n // }\n // const audioBlob = new Blob([content], { type: 'application/octet-stream' }); // Create a Blob from the byte array\n // console.debug(`Read audio file (len: ${content.length}) vs ${deltaSize}`)\n } catch (error) {\n console.error(\n \"[useAudioRecorder] Error reading audio file:\",\n error,\n );\n }\n } else if (buffer) {\n // Coming from web\n onAudioStream?.({\n data: buffer,\n position,\n fileUri,\n eventDataSize: deltaSize,\n totalSize,\n });\n }\n }\n } catch (error) {\n console.error(\n \"[useAudioRecorder] Error processing audio event:\",\n error,\n );\n }\n },\n );\n if (debug) {\n console.log(\n `[useAudioRecorder] Subscribed to audio event listener`,\n subscribe,\n );\n }\n return () => {\n if (debug) {\n console.log(`[useAudioRecorder] Removing audio event listener`);\n }\n subscribe.remove();\n };\n }, []);\n\n const startRecording = useCallback(\n async (recordingOptions: RecordingConfig) => {\n setIsRecording(true);\n setIsPaused(false);\n setSize(0);\n setDuration(0);\n if (debug) {\n console.log(`[useAudioRecorder] start recoding`, recordingOptions);\n }\n\n const result: StartAudioStreamResult =\n await ExpoAudioStreamModule.startRecording(recordingOptions);\n return result;\n },\n [debug],\n );\n\n const stopRecording = useCallback(async () => {\n const result: AudioStreamResult =\n await ExpoAudioStreamModule.stopRecording();\n setIsRecording(false);\n setIsPaused(false);\n return result;\n }, []);\n\n const pauseRecording = useCallback(async () => {\n try {\n await ExpoAudioStreamModule.pauseRecording();\n setIsPaused(true);\n setIsRecording(false);\n } catch (error) {\n console.error(\"[useAudioRecorder] Error pausing recording:\", error);\n }\n }, [debug]);\n\n const resumeRecording = useCallback(async () => {\n try {\n await ExpoAudioStreamModule.resumeRecording();\n setIsPaused(true);\n setIsRecording(false);\n } catch (error) {\n console.error(\"[useAudioRecorder] Error pausing recording:\", error);\n }\n }, [debug]);\n\n return {\n startRecording,\n stopRecording,\n pauseRecording,\n resumeRecording,\n isPaused,\n isRecording,\n duration,\n size,\n };\n}\n"]}
|
|
@@ -76,9 +76,9 @@ class AudioStreamManager: NSObject {
|
|
|
76
76
|
internal var recordingSettings: RecordingSettings?
|
|
77
77
|
internal var recordingUUID: UUID?
|
|
78
78
|
internal var mimeType: String = "audio/wav"
|
|
79
|
-
private var lastBuffer: AVAudioPCMBuffer?
|
|
80
79
|
private var lastBufferTime: AVAudioTime?
|
|
81
|
-
|
|
80
|
+
private var accumulatedData = Data()
|
|
81
|
+
|
|
82
82
|
weak var delegate: AudioStreamManagerDelegate? // Define the delegate here
|
|
83
83
|
|
|
84
84
|
override init() {
|
|
@@ -113,16 +113,9 @@ class AudioStreamManager: NSObject {
|
|
|
113
113
|
let fileName = "\(recordingUUID!.uuidString).wav"
|
|
114
114
|
let fileURL = documentsDirectory.appendingPathComponent(fileName)
|
|
115
115
|
|
|
116
|
-
if fileManager.createFile(atPath: fileURL.path, contents: nil, attributes: nil) {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
let wavHeader = createWavHeader(dataSize: 0) // Initially set data size to 0
|
|
120
|
-
fileHandle.write(wavHeader)
|
|
121
|
-
fileHandle.closeFile()
|
|
122
|
-
} catch {
|
|
123
|
-
Logger.debug("Failed to write WAV header: \(error.localizedDescription)")
|
|
124
|
-
return nil
|
|
125
|
-
}
|
|
116
|
+
if !fileManager.createFile(atPath: fileURL.path, contents: nil, attributes: nil) {
|
|
117
|
+
Logger.debug("Failed to create file at: \(fileURL.path)")
|
|
118
|
+
return nil
|
|
126
119
|
}
|
|
127
120
|
return fileURL
|
|
128
121
|
}
|
|
@@ -215,6 +208,8 @@ class AudioStreamManager: NSObject {
|
|
|
215
208
|
|
|
216
209
|
emissionInterval = max(100.0, Double(intervalMilliseconds)) / 1000.0
|
|
217
210
|
lastEmissionTime = Date()
|
|
211
|
+
accumulatedData.removeAll()
|
|
212
|
+
totalDataSize = 0
|
|
218
213
|
|
|
219
214
|
let session = AVAudioSession.sharedInstance()
|
|
220
215
|
do {
|
|
@@ -247,9 +242,6 @@ class AudioStreamManager: NSObject {
|
|
|
247
242
|
|
|
248
243
|
// Processing the current buffer
|
|
249
244
|
self.processAudioBuffer(buffer, fileURL: self.recordingFileURL!)
|
|
250
|
-
|
|
251
|
-
// Store the buffer and time as the last buffer and time
|
|
252
|
-
self.lastBuffer = buffer
|
|
253
245
|
self.lastBufferTime = time
|
|
254
246
|
}
|
|
255
247
|
|
|
@@ -309,9 +301,12 @@ class AudioStreamManager: NSObject {
|
|
|
309
301
|
return nil
|
|
310
302
|
}
|
|
311
303
|
|
|
312
|
-
//
|
|
313
|
-
if
|
|
314
|
-
|
|
304
|
+
// Emit any remaining accumulated data
|
|
305
|
+
if !accumulatedData.isEmpty {
|
|
306
|
+
let currentTime = Date()
|
|
307
|
+
let recordingTime = currentTime.timeIntervalSince(startTime)
|
|
308
|
+
delegate?.audioStreamManager(self, didReceiveAudioData: accumulatedData, recordingTime: recordingTime, totalDataSize: totalDataSize)
|
|
309
|
+
accumulatedData.removeAll()
|
|
315
310
|
}
|
|
316
311
|
|
|
317
312
|
let endTime = Date()
|
|
@@ -336,7 +331,6 @@ class AudioStreamManager: NSObject {
|
|
|
336
331
|
sampleRate: settings.sampleRate
|
|
337
332
|
)
|
|
338
333
|
recordingFileURL = nil // Reset for next recording
|
|
339
|
-
lastBuffer = nil // Reset last buffer
|
|
340
334
|
lastBufferTime = nil // Reset last buffer time
|
|
341
335
|
|
|
342
336
|
return result
|
|
@@ -381,7 +375,17 @@ class AudioStreamManager: NSObject {
|
|
|
381
375
|
print("Buffer data is nil.")
|
|
382
376
|
return
|
|
383
377
|
}
|
|
384
|
-
|
|
378
|
+
var data = Data(bytes: bufferData, count: Int(audioData.mDataByteSize))
|
|
379
|
+
|
|
380
|
+
// Check if this is the first buffer to process and totalDataSize is 0
|
|
381
|
+
if totalDataSize == 0 {
|
|
382
|
+
// Since it's the first buffer, prepend the WAV header
|
|
383
|
+
let header = createWavHeader(dataSize: 0) // Set initial dataSize to 0, update later
|
|
384
|
+
data.insert(contentsOf: header, at: 0)
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// Accumulate new data
|
|
388
|
+
accumulatedData.append(data)
|
|
385
389
|
|
|
386
390
|
// print("Writing data size: \(data.count) bytes") // Debug: Check the size of data being written
|
|
387
391
|
fileHandle.seekToEndOfFile()
|
|
@@ -396,9 +400,10 @@ class AudioStreamManager: NSObject {
|
|
|
396
400
|
if let startTime = startTime {
|
|
397
401
|
let recordingTime = currentTime.timeIntervalSince(startTime)
|
|
398
402
|
// print("Emitting data: Recording time \(recordingTime) seconds, Data size \(totalDataSize) bytes")
|
|
399
|
-
self.delegate?.audioStreamManager(self, didReceiveAudioData:
|
|
403
|
+
self.delegate?.audioStreamManager(self, didReceiveAudioData: accumulatedData, recordingTime: recordingTime, totalDataSize: totalDataSize)
|
|
400
404
|
self.lastEmissionTime = currentTime // Update last emission time
|
|
401
405
|
self.lastEmittedSize = totalDataSize
|
|
406
|
+
accumulatedData.removeAll() // Reset accumulated data after emission
|
|
402
407
|
}
|
|
403
408
|
}
|
|
404
409
|
}
|
|
@@ -31,9 +31,18 @@ public class ExpoAudioStreamModule: Module, AudioStreamManagerDelegate {
|
|
|
31
31
|
let interval = options["interval"] as? Int ?? 1000
|
|
32
32
|
|
|
33
33
|
let settings = RecordingSettings(sampleRate: sampleRate, numberOfChannels: numberOfChannels, bitDepth: bitDepth)
|
|
34
|
-
let result = self.streamManager.startRecording(settings: settings, intervalMilliseconds: interval)
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
if let result = self.streamManager.startRecording(settings: settings, intervalMilliseconds: interval) {
|
|
35
|
+
let resultDict: [String: Any] = [
|
|
36
|
+
"fileUri": result.fileUri,
|
|
37
|
+
"channels": result.channels,
|
|
38
|
+
"bitDepth": result.bitDepth,
|
|
39
|
+
"sampleRate": result.sampleRate,
|
|
40
|
+
"mimeType": result.mimeType,
|
|
41
|
+
]
|
|
42
|
+
promise.resolve(resultDict)
|
|
43
|
+
} else {
|
|
44
|
+
promise.reject("ERROR", "Failed to start recording.")
|
|
45
|
+
}
|
|
37
46
|
}
|
|
38
47
|
}
|
|
39
48
|
|
|
@@ -97,9 +106,6 @@ public class ExpoAudioStreamModule: Module, AudioStreamManagerDelegate {
|
|
|
97
106
|
"streamUuid": manager.recordingUUID?.uuidString ?? UUID().uuidString
|
|
98
107
|
]
|
|
99
108
|
|
|
100
|
-
// Update the last emitted size for the next calculation
|
|
101
|
-
manager.lastEmittedSize += Int64(deltaSize)
|
|
102
|
-
|
|
103
109
|
// Emit the event to JavaScript
|
|
104
110
|
sendEvent(audioDataEvent, eventBody)
|
|
105
111
|
}
|
package/package.json
CHANGED
|
@@ -37,10 +37,11 @@ export interface AudioStreamStatus {
|
|
|
37
37
|
mimeType: string;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
export
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
export type EncodingType = "pcm_16bit" | "pcm_8bit";
|
|
41
|
+
|
|
42
|
+
export interface RecordingConfig {
|
|
43
|
+
sampleRate?: 16000 | 44100 | 48000;
|
|
44
|
+
channels?: 1 | 2; // 1 or 2 MONO or STEREO
|
|
45
|
+
encoding?: EncodingType;
|
|
45
46
|
interval?: number;
|
|
46
47
|
}
|
|
@@ -4,7 +4,7 @@ import { EventEmitter } from "expo-modules-core";
|
|
|
4
4
|
import {
|
|
5
5
|
AudioEventPayload,
|
|
6
6
|
AudioStreamResult,
|
|
7
|
-
|
|
7
|
+
RecordingConfig,
|
|
8
8
|
StartAudioStreamResult,
|
|
9
9
|
} from "./ExpoAudioStream.types";
|
|
10
10
|
|
|
@@ -59,7 +59,7 @@ class ExpoAudioStreamWeb extends EventEmitter {
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
// Start recording with options
|
|
62
|
-
async startRecording(options:
|
|
62
|
+
async startRecording(options: RecordingConfig = {}) {
|
|
63
63
|
if (this.isRecording) {
|
|
64
64
|
throw new Error("Recording is already in progress");
|
|
65
65
|
}
|
package/src/index.ts
CHANGED
|
@@ -26,6 +26,10 @@ export function clearAudioFiles(): Promise<void> {
|
|
|
26
26
|
return ExpoAudioStreamModule.clearAudioFiles();
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
export function test(): void {
|
|
30
|
+
return ExpoAudioStreamModule.test();
|
|
31
|
+
}
|
|
32
|
+
|
|
29
33
|
export function addAudioEventListener(
|
|
30
34
|
listener: (event: AudioEventPayload) => Promise<void>,
|
|
31
35
|
): Subscription {
|
package/src/useAudioRecording.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { addAudioEventListener } from ".";
|
|
|
5
5
|
import {
|
|
6
6
|
AudioStreamResult,
|
|
7
7
|
AudioStreamStatus,
|
|
8
|
-
|
|
8
|
+
RecordingConfig,
|
|
9
9
|
StartAudioStreamResult,
|
|
10
10
|
} from "./ExpoAudioStream.types";
|
|
11
11
|
import ExpoAudioStreamModule from "./ExpoAudioStreamModule";
|
|
@@ -13,13 +13,15 @@ import ExpoAudioStreamModule from "./ExpoAudioStreamModule";
|
|
|
13
13
|
export interface AudioDataEvent {
|
|
14
14
|
data: string | Blob;
|
|
15
15
|
position: number;
|
|
16
|
+
fileUri: string;
|
|
16
17
|
eventDataSize: number;
|
|
17
18
|
totalSize: number;
|
|
18
19
|
}
|
|
19
20
|
export interface UseAudioRecorderState {
|
|
20
|
-
startRecording: (_:
|
|
21
|
+
startRecording: (_: RecordingConfig) => Promise<StartAudioStreamResult>;
|
|
21
22
|
stopRecording: () => Promise<AudioStreamResult | null>;
|
|
22
23
|
pauseRecording: () => void;
|
|
24
|
+
resumeRecording: () => void;
|
|
23
25
|
isRecording: boolean;
|
|
24
26
|
isPaused: boolean;
|
|
25
27
|
duration: number; // Duration of the recording
|
|
@@ -125,6 +127,7 @@ export function useAudioRecorder({
|
|
|
125
127
|
onAudioStream?.({
|
|
126
128
|
data: encoded,
|
|
127
129
|
position,
|
|
130
|
+
fileUri,
|
|
128
131
|
eventDataSize: deltaSize,
|
|
129
132
|
totalSize,
|
|
130
133
|
});
|
|
@@ -155,6 +158,7 @@ export function useAudioRecorder({
|
|
|
155
158
|
onAudioStream?.({
|
|
156
159
|
data: buffer,
|
|
157
160
|
position,
|
|
161
|
+
fileUri,
|
|
158
162
|
eventDataSize: deltaSize,
|
|
159
163
|
totalSize,
|
|
160
164
|
});
|
|
@@ -183,33 +187,25 @@ export function useAudioRecorder({
|
|
|
183
187
|
}, []);
|
|
184
188
|
|
|
185
189
|
const startRecording = useCallback(
|
|
186
|
-
async (recordingOptions:
|
|
190
|
+
async (recordingOptions: RecordingConfig) => {
|
|
187
191
|
setIsRecording(true);
|
|
188
192
|
setIsPaused(false);
|
|
189
193
|
setSize(0);
|
|
190
194
|
setDuration(0);
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
console.log(`[useAudioRecorder] start recoding`, recordingOptions);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
const fileUrl =
|
|
197
|
-
await ExpoAudioStreamModule.startRecording(recordingOptions);
|
|
198
|
-
|
|
199
|
-
return fileUrl;
|
|
200
|
-
} catch (error) {
|
|
201
|
-
console.error("[useAudioRecorder] Error starting recording:", error);
|
|
202
|
-
setIsRecording(false);
|
|
195
|
+
if (debug) {
|
|
196
|
+
console.log(`[useAudioRecorder] start recoding`, recordingOptions);
|
|
203
197
|
}
|
|
198
|
+
|
|
199
|
+
const result: StartAudioStreamResult =
|
|
200
|
+
await ExpoAudioStreamModule.startRecording(recordingOptions);
|
|
201
|
+
return result;
|
|
204
202
|
},
|
|
205
203
|
[debug],
|
|
206
204
|
);
|
|
207
205
|
|
|
208
206
|
const stopRecording = useCallback(async () => {
|
|
209
|
-
console.log(`STOOOOOP NOW`);
|
|
210
207
|
const result: AudioStreamResult =
|
|
211
208
|
await ExpoAudioStreamModule.stopRecording();
|
|
212
|
-
console.log(`STOOOOOP NOW 2`);
|
|
213
209
|
setIsRecording(false);
|
|
214
210
|
setIsPaused(false);
|
|
215
211
|
return result;
|
|
@@ -217,7 +213,17 @@ export function useAudioRecorder({
|
|
|
217
213
|
|
|
218
214
|
const pauseRecording = useCallback(async () => {
|
|
219
215
|
try {
|
|
220
|
-
await ExpoAudioStreamModule.
|
|
216
|
+
await ExpoAudioStreamModule.pauseRecording();
|
|
217
|
+
setIsPaused(true);
|
|
218
|
+
setIsRecording(false);
|
|
219
|
+
} catch (error) {
|
|
220
|
+
console.error("[useAudioRecorder] Error pausing recording:", error);
|
|
221
|
+
}
|
|
222
|
+
}, [debug]);
|
|
223
|
+
|
|
224
|
+
const resumeRecording = useCallback(async () => {
|
|
225
|
+
try {
|
|
226
|
+
await ExpoAudioStreamModule.resumeRecording();
|
|
221
227
|
setIsPaused(true);
|
|
222
228
|
setIsRecording(false);
|
|
223
229
|
} catch (error) {
|
|
@@ -229,6 +235,7 @@ export function useAudioRecorder({
|
|
|
229
235
|
startRecording,
|
|
230
236
|
stopRecording,
|
|
231
237
|
pauseRecording,
|
|
238
|
+
resumeRecording,
|
|
232
239
|
isPaused,
|
|
233
240
|
isRecording,
|
|
234
241
|
duration,
|