88 lines
2.5 KiB
TypeScript
88 lines
2.5 KiB
TypeScript
import { useEffect, useRef, useState } from "react";
|
||
import reactLogo from "./assets/react.svg";
|
||
import viteLogo from "/vite.svg";
|
||
import "./App.css";
|
||
import { client, start } from "./utils/mqtt";
|
||
import { startAudio, stopAudio, context } from "./utils/microphone";
|
||
import { arrayBufferToBase64, downSampleAudioFrame, floatTo16BitPCM, getMergedPCMData } from "./utils/audio";
|
||
|
||
let mqttData;
|
||
|
||
let buffers: Float32Array[] = [];
|
||
|
||
const getAudio = () => {
|
||
buffers = [];
|
||
|
||
startAudio((float32Arr) => {
|
||
// 降比特率到 16000
|
||
const downedFloat32Arr = downSampleAudioFrame(float32Arr, context.sampleRate, 16000);
|
||
// 转 base64 打包给后端
|
||
const sendItem = arrayBufferToBase64(floatTo16BitPCM(downedFloat32Arr));
|
||
// 存储一遍压缩后的音频
|
||
buffers.push(downedFloat32Arr);
|
||
|
||
client.publish(mqttData.recognition_topic, sendItem);
|
||
});
|
||
};
|
||
|
||
const onDownload = () => {
|
||
if (buffers.length === 0) {
|
||
return;
|
||
}
|
||
|
||
const data = getMergedPCMData(buffers);
|
||
const blob = new Blob([floatTo16BitPCM(data)], { type: 'audio/wave' });
|
||
|
||
const a = document.createElement('a');
|
||
a.href = URL.createObjectURL(blob);
|
||
a.download = 'merged_audio.pcm';
|
||
a.click();
|
||
};
|
||
|
||
function App() {
|
||
const loaded = useRef(false);
|
||
const [mqttStatus, setMqttStatus] = useState(false);
|
||
|
||
useEffect(() => {
|
||
if (loaded.current) {
|
||
return;
|
||
}
|
||
|
||
loaded.current = true;
|
||
|
||
// 启用 MQTT 并连接
|
||
start().then(([client, data]) => {
|
||
console.log("mqtt connected");
|
||
|
||
mqttData = data;
|
||
|
||
setMqttStatus(true);
|
||
});
|
||
}, []);
|
||
|
||
return (
|
||
<>
|
||
<div>
|
||
<a href="https://vitejs.dev" target="_blank">
|
||
<img src={viteLogo} className="logo" alt="Vite logo" />
|
||
</a>
|
||
<a href="https://react.dev" target="_blank">
|
||
<img src={reactLogo} className="logo react" alt="React logo" />
|
||
</a>
|
||
</div>
|
||
<p>确保 MQTT 已连接,再点击 getAudio 开始录音,stopAudio 结束</p>
|
||
<p>点击 download 下载音频原始数据(Float32Array 拼接的),用 Audacity 音频软件可加载。</p>
|
||
<p>MQTT 连接状态:{String(mqttStatus)}</p>
|
||
<p>当前输入设备比特率:{context.sampleRate}hz</p>
|
||
<p>当前输出音频比特率:16000hz</p>
|
||
<div className="card">
|
||
<button onClick={getAudio}>getAudio</button>
|
||
<button onClick={stopAudio}>stopAudio</button>
|
||
<button onClick={onDownload}>download</button>
|
||
</div>
|
||
</>
|
||
);
|
||
}
|
||
|
||
export default App;
|