|
|
@ -1,7 +1,8 @@
|
|
|
|
import React, { useState, useEffect } from "react";
|
|
|
|
import React, { useState, useEffect, useCallback } from "react";
|
|
|
|
import { View, Text, TouchableOpacity, StyleSheet } from "react-native";
|
|
|
|
import { View, Text, TouchableOpacity, StyleSheet } from "react-native";
|
|
|
|
import * as FileSystem from 'expo-file-system';
|
|
|
|
import * as FileSystem from 'expo-file-system';
|
|
|
|
import { AVPlaybackStatus, AVPlaybackStatusSuccess, Audio } from "expo-av";
|
|
|
|
import { AVPlaybackStatus, AVPlaybackStatusSuccess, Audio } from "expo-av";
|
|
|
|
|
|
|
|
import { polyfill as polyfillEncoding } from 'react-native-polyfill-globals/src/encoding';
|
|
|
|
|
|
|
|
|
|
|
|
interface MainProps {
|
|
|
|
interface MainProps {
|
|
|
|
route: {
|
|
|
|
route: {
|
|
|
@ -19,11 +20,15 @@ const Main: React.FC<MainProps> = ({ route }) => {
|
|
|
|
const [audioQueue, setAudioQueue] = useState<string[]>([]);
|
|
|
|
const [audioQueue, setAudioQueue] = useState<string[]>([]);
|
|
|
|
const [sound, setSound] = useState<Audio.Sound | null>();
|
|
|
|
const [sound, setSound] = useState<Audio.Sound | null>();
|
|
|
|
const audioDir = FileSystem.documentDirectory + '01/audio/';
|
|
|
|
const audioDir = FileSystem.documentDirectory + '01/audio/';
|
|
|
|
|
|
|
|
const [permissionResponse, requestPermission] = Audio.usePermissions();
|
|
|
|
|
|
|
|
polyfillEncoding();
|
|
|
|
|
|
|
|
const reader = new FileReader();
|
|
|
|
|
|
|
|
|
|
|
|
const constructTempFilePath = async (buffer: string) => {
|
|
|
|
const constructTempFilePath = async (buffer: string) => {
|
|
|
|
await dirExists();
|
|
|
|
await dirExists();
|
|
|
|
|
|
|
|
|
|
|
|
const tempFilePath = `${audioDir}${Date.now()}.wav`;
|
|
|
|
const tempFilePath = `${audioDir}${Date.now()}.wav`;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
await FileSystem.writeAsStringAsync(
|
|
|
|
await FileSystem.writeAsStringAsync(
|
|
|
|
tempFilePath,
|
|
|
|
tempFilePath,
|
|
|
|
buffer,
|
|
|
|
buffer,
|
|
|
@ -32,6 +37,7 @@ const Main: React.FC<MainProps> = ({ route }) => {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return tempFilePath;
|
|
|
|
return tempFilePath;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
@ -111,9 +117,9 @@ const Main: React.FC<MainProps> = ({ route }) => {
|
|
|
|
websocket.onmessage = async (e) => {
|
|
|
|
websocket.onmessage = async (e) => {
|
|
|
|
|
|
|
|
|
|
|
|
const message = JSON.parse(e.data);
|
|
|
|
const message = JSON.parse(e.data);
|
|
|
|
console.log(message.content);
|
|
|
|
console.log(message.content.slice(0, 50));
|
|
|
|
|
|
|
|
|
|
|
|
const buffer = await message.content;
|
|
|
|
const buffer = await message.content as string;
|
|
|
|
const filePath = await constructTempFilePath(buffer);
|
|
|
|
const filePath = await constructTempFilePath(buffer);
|
|
|
|
setAudioQueue((prevQueue) => [...prevQueue, filePath]);
|
|
|
|
setAudioQueue((prevQueue) => [...prevQueue, filePath]);
|
|
|
|
console.log("audio file written to", filePath);
|
|
|
|
console.log("audio file written to", filePath);
|
|
|
@ -122,26 +128,6 @@ const Main: React.FC<MainProps> = ({ route }) => {
|
|
|
|
console.log("calling playNextAudio");
|
|
|
|
console.log("calling playNextAudio");
|
|
|
|
playNextAudio();
|
|
|
|
playNextAudio();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
const message = JSON.parse(e.data);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (message.content) {
|
|
|
|
|
|
|
|
const parsedMessage = message.content.replace(/^b'|['"]|['"]$/g, "");
|
|
|
|
|
|
|
|
console.log("parsedMessage", parsedMessage.slice(0, 30));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const filePath = await constructFilePath(parsedMessage);
|
|
|
|
|
|
|
|
setAudioQueue((prevQueue) => [...prevQueue, filePath]);
|
|
|
|
|
|
|
|
console.log("audio file written to", filePath);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (message.format === "bytes.raw" && message.end && audioQueue.length > 1) {
|
|
|
|
|
|
|
|
console.log("calling playNextAudio");
|
|
|
|
|
|
|
|
playNextAudio();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
websocket.onerror = (error) => {
|
|
|
|
websocket.onerror = (error) => {
|
|
|
@ -167,56 +153,76 @@ const Main: React.FC<MainProps> = ({ route }) => {
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}, [scannedData]);
|
|
|
|
}, [scannedData]);
|
|
|
|
|
|
|
|
|
|
|
|
const startRecording = async () => {
|
|
|
|
const startRecording = useCallback(async () => {
|
|
|
|
if (recording) {
|
|
|
|
if (recording) {
|
|
|
|
console.log("A recording is already in progress.");
|
|
|
|
console.log("A recording is already in progress.");
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
console.log("Requesting permissions..");
|
|
|
|
if (permissionResponse !== null && permissionResponse.status !== `granted`) {
|
|
|
|
await Audio.requestPermissionsAsync();
|
|
|
|
console.log("Requesting permission..");
|
|
|
|
|
|
|
|
await requestPermission();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
await Audio.setAudioModeAsync({
|
|
|
|
await Audio.setAudioModeAsync({
|
|
|
|
allowsRecordingIOS: true,
|
|
|
|
allowsRecordingIOS: true,
|
|
|
|
playsInSilentModeIOS: true,
|
|
|
|
playsInSilentModeIOS: true,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
console.log("Starting recording..");
|
|
|
|
console.log("Starting recording..");
|
|
|
|
const { recording: newRecording } = await Audio.Recording.createAsync(
|
|
|
|
const newRecording = new Audio.Recording();
|
|
|
|
Audio.RecordingOptionsPresets.HIGH_QUALITY
|
|
|
|
await newRecording.prepareToRecordAsync(Audio.RecordingOptionsPresets.HIGH_QUALITY);
|
|
|
|
);
|
|
|
|
await newRecording.startAsync();
|
|
|
|
|
|
|
|
|
|
|
|
setRecording(newRecording);
|
|
|
|
setRecording(newRecording);
|
|
|
|
console.log("Recording started");
|
|
|
|
|
|
|
|
} catch (err) {
|
|
|
|
} catch (err) {
|
|
|
|
console.error("Failed to start recording", err);
|
|
|
|
console.error("Failed to start recording", err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
|
|
const stopRecording = async () => {
|
|
|
|
const stopRecording = useCallback(async () => {
|
|
|
|
console.log("Stopping recording..");
|
|
|
|
console.log("Stopping recording..");
|
|
|
|
setRecording(null);
|
|
|
|
|
|
|
|
if (recording) {
|
|
|
|
if (recording) {
|
|
|
|
await recording.stopAndUnloadAsync();
|
|
|
|
await recording.stopAndUnloadAsync();
|
|
|
|
await Audio.setAudioModeAsync({
|
|
|
|
await Audio.setAudioModeAsync({
|
|
|
|
allowsRecordingIOS: false,
|
|
|
|
allowsRecordingIOS: false,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
const uri = recording.getURI();
|
|
|
|
const uri = recording.getURI();
|
|
|
|
console.log("Recording stopped and stored at", uri);
|
|
|
|
console.log("recording uri at ", uri);
|
|
|
|
|
|
|
|
setRecording(null);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// sanity check play the audio recording locally
|
|
|
|
|
|
|
|
// recording is working fine; is the server caching the audio file somewhere?
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
if (uri) {
|
|
|
|
|
|
|
|
const { sound } = await Audio.Sound.createAsync({ uri });
|
|
|
|
|
|
|
|
sound.playAsync();
|
|
|
|
|
|
|
|
console.log("playing audio recording from", uri);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (ws && uri) {
|
|
|
|
if (ws && uri) {
|
|
|
|
const response = await fetch(uri);
|
|
|
|
const response = await fetch(uri);
|
|
|
|
|
|
|
|
console.log("fetched audio file", response);
|
|
|
|
const blob = await response.blob();
|
|
|
|
const blob = await response.blob();
|
|
|
|
const reader = new FileReader();
|
|
|
|
|
|
|
|
reader.readAsArrayBuffer(blob);
|
|
|
|
reader.readAsArrayBuffer(blob);
|
|
|
|
reader.onloadend = () => {
|
|
|
|
reader.onloadend = () => {
|
|
|
|
const audioBytes = reader.result;
|
|
|
|
const audioBytes = reader.result;
|
|
|
|
if (audioBytes) {
|
|
|
|
if (audioBytes) {
|
|
|
|
ws.send(audioBytes);
|
|
|
|
ws.send(audioBytes);
|
|
|
|
console.log("sent audio bytes to WebSocket");
|
|
|
|
const audioArray = new Uint8Array(audioBytes as ArrayBuffer);
|
|
|
|
|
|
|
|
const decoder = new TextDecoder("utf-8");
|
|
|
|
|
|
|
|
console.log("sent audio bytes to WebSocket", decoder.decode(audioArray).slice(0, 50));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}, [recording]);
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
return (
|
|
|
|
<View style={styles.container}>
|
|
|
|
<View style={styles.container}>
|
|
|
|