javascript - 有没有在浏览器中播放原始 wav 数据的好方法?
问题描述
我正在尝试在浏览器中播放wav原始数据,这些数据是从nodejs服务器通过socket.io传输的,主要思想是尽快播放接收数据,所以我不需要等到接收数据完毕。我尝试在这种情况下使用 blob,但总是会发生下一件事:如果我有一大块原始数据并且我正在使用 blob 转换它以进行播放,那么当第二个块准备好并再次使用 blob 转换时,然后在播放音频时会中断一段时间。
我也尝试使用下面的代码并且它有效,但是在播放它时我可以听到很多噪音。谁能帮我解决这个问题并告诉我如何在没有噪音的情况下播放音频?
PS传输中的超时是主要思想的一部分,我尝试在没有它的情况下播放音乐,但仍然没有运气。
<html>
<head>
<script src="socket.io.js"></script>
<script src=" https://cdnjs.cloudflare.com/ajax/libs/socket.io-stream/0.9.1/socket.io-stream.js">
</script>
<script src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
</head>
<body>
<button id="start">Play music!</button>
<script>
$(function () {
var socket = io.connect("http://localhost:3000");
var stream = ss.createStream();
// receive data
window.AudioContext = window.AudioContext || window.webkitAudioContext;
var audioCtx = new AudioContext();
var audioBuffer = audioCtx.createBuffer(2, 22050, 44100);
var source = audioCtx.createBufferSource();
source.buffer = audioBuffer;
// source.connect(audioCtx.destination);
gainNode = audioCtx.createGain();
gainNode.gain.value = 0;
gainNode.connect(audioCtx.destination);
source.connect(gainNode);
source.start(0);
socket.on('chat message', function (msg) {
console.log(".");
console.log(msg);
playsound(msg)
});
function playsound(raw) {
var context = audioCtx;
var buffer = new Int16Array(raw);
console.log(buffer);
var channel0buffer = new Float32Array(buffer.length / 2);
var channel1buffer = new Float32Array(buffer.length / 2);
var j = 0;
for (var i = 0; i < buffer.length; i++) {
channel0buffer[j] = buffer[i];
i++;
channel1buffer[j] = buffer[i];
j++;
}
var src = context.createBufferSource(),
audioBuffer = context.createBuffer(2, buffer.length, context.sampleRate);
audioBuffer.getChannelData(0).set(channel1buffer);
audioBuffer.getChannelData(1).set(channel0buffer);
src.buffer = audioBuffer;
src.connect(gainNode);
src.start(0);
}
document.getElementById("start").addEventListener('click', function () {
audioCtx.resume().then(() => {
console.log('Playback resumed successfully');
});
});
});
</script>
<p>Volume</p>
<input id="volume" type="range" min="0" max="1" step="0.1" value="0.0" />
<script>
document.getElementById('volume').addEventListener('change', function () {
gainNode.gain.value = this.value;
});
function touchStarted() {
getAudioContext().resume();
}
</script>
</body>
</html>
我的服务器代码如下所示:
const fs = require("fs");
var app = require("express")();
var http = require("http").createServer(app);
var io = require("socket.io")(http);
app.get("/", (req, res) => {
res.sendFile(__dirname + "/index.html");
});
io.on("connection", (socket) => {
console.log("a user connected");
socket.on("disconnect", () => {
console.log("user disconnected");
});
socket.on("chat message", (msg) => {
console.log("message: " + msg);
io.emit("chat message", msg);
});
});
http.listen(3000, () => {
console.log("listening on *:3000");
});
const stream = fs.createReadStream("Original1.wav", {
highWaterMark: 640000, // internal buffer size
});
stream.on("data", async (chunk) => {
stream.pause();
let newChunk = new Int16Array(chunk);
await asyncHandle(chunk);
setTimeout(() => {
stream.resume();
}, 1000);
});
async function asyncHandle(chunk) {
console.log(chunk);
io.emit("chat message", chunk);
}
解决方案
下面有一个 WAV 示例。由于带宽和延迟优势,我强烈建议考虑将音频编码为 Opus 而不是 WAV。
推荐阅读
- wpf - WPF MVVM Stylet,如何在命令绑定中使用 s:Action,而不将 Bootstrapper 导入项目?
- reactjs - 条件渲染以选择显示设置
- javascript - 使用 jwt、node/express 验证令牌时请求返回 404
- python - 使用 Pyodbc 包从 sql 数据库中获取数据
- javascript - Javascript将变量视为字符串
- dax - 在 DAX 度量中计算当前日期减去 6 个月
- sql-server - 如何更新 SQL Server 项目中的数据库函数
- git - 我在 git config 中添加了错误的变量。如何删除它?
- c# - 幸运抽奖计划
- git - 我正在为存储库做出贡献,但在提交时显示“致命:不会添加文件别名”