javascript - 如何使用 Express.js 在有效负载中重新组装带有 MP3 blob 的分块 POST 请求?
问题描述
我正在构建一个语音到音频的网络应用程序,它接受麦克风输入,将录音转换为 MP3(使用 mic-recorder-to-mp3 NPM 包),然后将其发送到 node.js/express 服务器-用于存储并作为后续 POST 请求传递给语音到文本 API(rev.ai)。
UI 上的录音功能很好,我在标签中播放了录音,听起来不错,是全长录音:
stopBtn.addEventListener("click", () => {
recorder
.stop()
.getMp3().then(([buffer, blob]) => {
let newBlob = new Blob(buffer);
recordedAudio.src = URL.createObjectURL(blob);
recordedAudio.controls=true;
sendData(blob);
}).catch((e) => {
console.log(e);
});
});
function sendData(blob) {
let fd = new FormData();
fd.append('audio', blob);
fetch('/audio', {
headers: { Accept: "application/json", "Transfer-Encoding": "chunked" },
method: "POST", body: fd
});
}
现在,起初在我的服务器端快速路由中,我看到每个记录都有多个请求,并认为这是一个我可以稍后解决的错误,所以我进行了快速布尔检查以查看请求是否已经被处理并且如果是这样,只需 res.end() 回到 UI。
这一切都很好,直到我意识到只有前 4 秒的录音被保存了。这 4 秒的重新编码在服务器端保存为 MP3,并且在音乐应用程序中打开时也可以正常播放,并且在 rev.ai 中也可以正确转录,但仍然只有 4 秒。
我意识到音频 blob 正在以块的形式发送到 UI,每个块都是我看到的多个请求的一部分。因此,我开始研究如何将这些块重新组合到可以保存为 MP3 并在 rev.ai 上正确解析为音频的音频 blob 中,但到目前为止我没有尝试过任何工作。这是我最近的尝试:
app.post("/audio", async (req, res) => {
let audioBlobs = [];
let audioContent;
let filename = `narr-${Date.now()}.mp3`;
//let processed = false;
req.on('readable', async () => {
//if(!processed){
//processed = true;
//let audioChunk = await req.read();
//}
while(null !== (audioChunk = await req.read())) {
console.log("adding chunk")
audioBlobs.push(audioChunk);
}
});
req.on("end", () => {
audioContent = audioBlobs.join('');
fs.writeFile(`./audio/${filename}`, audioContent, async function(err) {
if (err) {
console.log("an error occurred");
console.error(err);
res.end();
}
const stream = fs.createReadStream(`./audio/${filename}`);
let job = await client.submitJobAudioData(stream, filename, {}).then(data => {
waitForRevProcessing(data.id);
}).catch(e => {
console.log("caught an error");
console.log(e);
});
res.end();
})
});
});
该 blob 使用此代码保存在服务器端,但无法在音乐应用程序中播放,并且 rev.ai 拒绝录制,因为它不会将 blob 解释为音频文件。
我重新组装块的方式正在破坏 MP3 格式的完整性。
我认为这可能有几个原因:
- 这些块可能会乱序进入服务器端,尽管考虑到当我进行布尔检查时,它似乎在保存第一个块而不是中间块,但这并没有多大意义
- 最后一个块被“打开”,或者有一些元数据丢失或填充与编码混淆
- 这些可能不是用于启动/结束程序集的正确事件
我希望 Express/http 节点模块有内置的东西来自动处理这个问题,而我正在不必要地进行这个手动重组——我很惊讶 Express 中没有现成的东西来处理这个问题,但也许它不像我想象的那么普遍?
任何可以提供的帮助将不胜感激。
解决方案
推荐阅读
- javascript - 从 javascript 发送数据以查看和返回修改后的数据
- java - 当我按下微调器时,我看到了我的数据,但是当我尝试选择它时,它没有设置数据?
- java - 发生异常时未调用@ExceptionHandler 方法
- woocommerce - Woocommerce 插件扩展优惠券
- javascript - Javascript 中较短的 if 语句
- python - 如何使用单个 init 调用初始化链表节点?
- vue.js - 使用 vue-pdf 时出现空白
- c# - 如何强制孩子在 Xamarin 中具有方形尺寸?
- html - 不使用 HTML 和 CSS 的复选框显示内容(无 JS)
- ruby-on-rails - 使用 ActiveRecord 查询接口进行分组和排序