Node.js 如何从客户端录制麦克风,然后发送到服务器

Node.js 如何从客户端录制麦克风,然后发送到服务器,node.js,xmlhttprequest,fetch,recording,mediastream,Node.js,Xmlhttprequest,Fetch,Recording,Mediastream,我想录制来自客户端的麦克风输入,然后当客户端停止时,将数据发送到服务器,然后将录制的音频输出到特定文件夹 到目前为止,我已经为我跟踪的客户的录音做好了准备 客户端上的console.log(blob)返回一个对象 Blob { size: 35412, type: "audio/ogg; codecs=opus" } 在服务器端,我使用Node.js app.post("/notes",function(req,res){ console.log(r

我想录制来自客户端的麦克风输入,然后当客户端停止时,将数据发送到服务器,然后将录制的音频输出到特定文件夹

到目前为止,我已经为我跟踪的客户的录音做好了准备

客户端上的console.log(blob)返回一个对象

Blob { size: 35412, type: "audio/ogg; codecs=opus" }
在服务器端,我使用Node.js

app.post("/notes",function(req,res){
  console.log(req);
});
服务器接收formData,但正文为空{}


我也尝试过XMLHttpRequest,得到了同样的结果。

我以前也参与过这种类型的项目。我创建了一个简单的表单,允许您从麦克风录制,然后上传到服务器

声音文件将保存在./Sound\u文件中

只需像这样运行节点服务器

node server.js

然后转到localhost:3000查看页面

节点代码(server.js)

index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Speech to text test</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" type="text/css" href="https://bootswatch.com/4/cerulean/bootstrap.min.css">
</head>
<body style="padding:50px;">
    <h1>Speech to text test</h1>
    <div id="controls">
    <button id="recordButton">Record</button>
    <button id="transcribeButton" disabled>Stop and upload to server</button>
    </div>
    <div id="output"></div>
    <script src="https://cdn.rawgit.com/mattdiamond/Recorderjs/08e7abd9/dist/recorder.js"></script>
    <script>
                
        let rec = null;
        let audioStream = null;

        const recordButton = document.getElementById("recordButton");
        const transcribeButton = document.getElementById("transcribeButton");

        recordButton.addEventListener("click", startRecording);
        transcribeButton.addEventListener("click", transcribeText);

        function startRecording() {

            let constraints = { audio: true, video:false }

            recordButton.disabled = true;
            transcribeButton.disabled = false;

            navigator.mediaDevices.getUserMedia(constraints).then(function(stream) {
                const audioContext = new window.AudioContext();
                audioStream = stream;
                const input = audioContext.createMediaStreamSource(stream);
                rec = new Recorder(input, { numChannels: 1 })
                rec.record()
                document.getElementById("output").innerHTML = "Recording started..."
            }).catch(function(err) {
                recordButton.disabled = false;
                transcribeButton.disabled = true;
            });
        }

        function transcribeText() {
            document.getElementById("output").innerHTML = "Converting audio to text..."
            transcribeButton.disabled = true;
            recordButton.disabled = false;
            rec.stop();
            audioStream.getAudioTracks()[0].stop();
            rec.exportWAV(uploadSoundData);
        }

        function uploadSoundData(blob) {
            const filename = "sound-file-" + new Date().getTime() + ".wav";
            const formData = new FormData();
            formData.append("audio_data", blob, filename);
            
            fetch('http://localhost:3000/notes', {
                method: 'POST',
                body: formData
            }).then(async result => { 
                document.getElementById("output").innerHTML = await result.text();
            }).catch(error => { 
                document.getElementById("output").innerHTML = "An error occurred: " + error;
            })
        }

    </script>
</body>
</html>

语篇转换测试
语篇转换测试
记录
停止并上传到服务器
设rec=null;
设audioStream=null;
const recordButton=document.getElementById(“recordButton”);
const transcribeButton=document.getElementById(“transcribeButton”);
recordButton.addEventListener(“单击”,开始录制);
transcribeButton.addEventListener(“单击”,转录文本);
函数startRecording(){
let约束={audio:true,video:false}
recordButton.disabled=true;
transcribeButton.disabled=false;
navigator.mediaDevices.getUserMedia(约束)。然后(函数(流){
const audioContext=new window.audioContext();
音频流=音频流;
常量输入=audioContext.createMediaStreamSource(流);
rec=新记录器(输入,{numChannels:1})
记录
document.getElementById(“输出”).innerHTML=“录制已开始…”
}).catch(函数(err){
recordButton.disabled=false;
transcribeButton.disabled=true;
});
}
函数transcribeText(){
document.getElementById(“输出”).innerHTML=“将音频转换为文本…”
transcribeButton.disabled=true;
recordButton.disabled=false;
建议停止();
audioStream.getAudioTracks()[0]。停止();
rec.exportWAV(上传声音数据);
}
函数上传声音数据(blob){
const filename=“声音文件-”+新日期().getTime()+“.wav”;
const formData=new formData();
追加(“音频数据”,blob,文件名);
取('http://localhost:3000/notes', {
方法:“POST”,
正文:formData
}).then(异步结果=>{
document.getElementById(“输出”).innerHTML=wait result.text();
}).catch(错误=>{
document.getElementById(“输出”).innerHTML=“发生错误:”+错误;
})
}
const express = require('express');
const multer = require('multer');
    
const storage = multer.diskStorage(
    {
        destination: './sound_files/',
        filename: function (req, file, cb ) {
            cb( null, file.originalname);
        }
    }
);

const upload = multer( { storage: storage } );

const app = express();
const port = 3000;

app.use(express.static('./'));

app.post("/notes", upload.single("audio_data"), function(req,res){
    res.status(200).send("ok");
});

app.listen(port, () => {
    console.log(`Express server listening on port: ${port}...`);
});
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Speech to text test</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" type="text/css" href="https://bootswatch.com/4/cerulean/bootstrap.min.css">
</head>
<body style="padding:50px;">
    <h1>Speech to text test</h1>
    <div id="controls">
    <button id="recordButton">Record</button>
    <button id="transcribeButton" disabled>Stop and upload to server</button>
    </div>
    <div id="output"></div>
    <script src="https://cdn.rawgit.com/mattdiamond/Recorderjs/08e7abd9/dist/recorder.js"></script>
    <script>
                
        let rec = null;
        let audioStream = null;

        const recordButton = document.getElementById("recordButton");
        const transcribeButton = document.getElementById("transcribeButton");

        recordButton.addEventListener("click", startRecording);
        transcribeButton.addEventListener("click", transcribeText);

        function startRecording() {

            let constraints = { audio: true, video:false }

            recordButton.disabled = true;
            transcribeButton.disabled = false;

            navigator.mediaDevices.getUserMedia(constraints).then(function(stream) {
                const audioContext = new window.AudioContext();
                audioStream = stream;
                const input = audioContext.createMediaStreamSource(stream);
                rec = new Recorder(input, { numChannels: 1 })
                rec.record()
                document.getElementById("output").innerHTML = "Recording started..."
            }).catch(function(err) {
                recordButton.disabled = false;
                transcribeButton.disabled = true;
            });
        }

        function transcribeText() {
            document.getElementById("output").innerHTML = "Converting audio to text..."
            transcribeButton.disabled = true;
            recordButton.disabled = false;
            rec.stop();
            audioStream.getAudioTracks()[0].stop();
            rec.exportWAV(uploadSoundData);
        }

        function uploadSoundData(blob) {
            const filename = "sound-file-" + new Date().getTime() + ".wav";
            const formData = new FormData();
            formData.append("audio_data", blob, filename);
            
            fetch('http://localhost:3000/notes', {
                method: 'POST',
                body: formData
            }).then(async result => { 
                document.getElementById("output").innerHTML = await result.text();
            }).catch(error => { 
                document.getElementById("output").innerHTML = "An error occurred: " + error;
            })
        }

    </script>
</body>
</html>