link-stack/apps/metamigo-frontend/components/voice/voicelines/MicInput.tsx

148 lines
4 KiB
TypeScript
Raw Normal View History

2023-02-13 12:41:30 +00:00
import { useInput } from "react-admin";
import React, { useState } from "react";
import dynamic from "next/dynamic";
import MicIcon from "@material-ui/icons/Mic";
import StopIcon from "@material-ui/icons/Stop";
import Button from "@material-ui/core/Button";
import { makeStyles, useTheme } from "@material-ui/core/styles";
import AudioPlayer from "material-ui-audio-player";
import { useStopwatch } from "react-timer-hook";
import style from "./MicInput.module.css";
//import type { ReactMicProps } from "react-mic";
2023-02-13 12:41:30 +00:00
const ReactMic = dynamic<ReactMicProps>(
// eslint-disable-next-line promise/prefer-await-to-then
() => { throw new Error("MIC INPUT FEATURE IS DISABLED"); /*return import("react-mic").then((mod) => mod.ReactMic);*/ } ,
2023-02-13 12:41:30 +00:00
{ ssr: false }
);
const blobToDataUri = (blob) => {
const reader = new FileReader();
reader.readAsDataURL(blob);
return new Promise((resolve) => {
reader.onloadend = () => {
resolve(reader.result);
};
});
};
const dataUriToObj = (dataUri) => {
const [prefix, base64] = dataUri.split(",");
const mime = prefix.slice(5, prefix.indexOf(";"));
const result = {};
result[mime] = base64;
return result;
};
const blobToResult = async (blob) => {
const result = dataUriToObj(await blobToDataUri(blob));
return result;
};
const resultToDataUri = (result): string => {
if (!result || !result["audio/webm"]) return "";
const base64 = result["audio/webm"];
const r = `data:audio/webm;base64,${base64}`;
return r;
};
const MicInput = (props) => {
const { seconds, minutes, hours, start, reset, pause } = useStopwatch();
const theme = useTheme();
const {
input: { value, onChange },
} = useInput(props);
let [record, setRecorder] = useState({ record: false });
const decodedValue = resultToDataUri(value);
const startRecording = () => {
setRecorder({ record: true });
reset();
start();
};
const stopRecording = () => {
setRecorder({ record: false });
pause();
};
async function onData(recordedBlob) {}
async function onStop(recordedBlob) {
const result = await blobToResult(recordedBlob.blob);
onChange(result);
}
const isRecording = record.record;
const canPlay = !isRecording && decodedValue;
const duration = `${hours
.toString()
.padStart(2, "0")}:${minutes
.toString()
.padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`;
const useStyles = makeStyles((theme) => {
return {
volumeIcon: {
display: "none",
},
mainSlider: {
display: "none",
},
};
});
return (
<div className="MuiFormControl-marginDense RaFormInput-input-40">
<div className={style.content}>
<div className={style.voiceWaveWrapper}>
<ReactMic
record={record.record}
className={isRecording ? style.visible : style.hidden}
onStop={onStop}
onData={onData}
strokeColor={theme.palette.primary.main}
backgroundColor="white"
mimeType="audio/webm"
visualSetting="frequencyBars"
/>
</div>
<div>{isRecording ? <p>Recording... {duration}</p> : ""}</div>
<div className={style.buttonWrapper}>
{isRecording ? (
<Button variant="contained" color="primary" onClick={stopRecording}>
<StopIcon />
Stop
</Button>
) : (
<Button
variant="contained"
color="primary"
onClick={startRecording}
style={{ marginRight: "20px" }}
>
<MicIcon />
Record
</Button>
)}
</div>
<div className={style.playerWrapper}>
{canPlay && (
<AudioPlayer
elevation={0}
src={decodedValue}
variation="secondary"
volume={false}
useStyles={useStyles}
/>
)}
</div>
</div>
</div>
);
};
export default MicInput;