有没有什么好的方法可以在浏览器中播放raw wav数据?
Is there a good way to play raw wav data in the browser?
我正在尝试在浏览器中播放wav原始数据,它是通过socket.io从nodejs服务器传输过来的,主要思想是尽快播放接收数据,所以我没有需要等到接收数据完成。我尝试在这种情况下使用 blob,但接下来总是会发生:如果我有一大块原始数据并且我正在使用 blob 将其转换为播放,然后当第二个数据块准备好并再次使用 blob 进行转换时,然后播放音频时断断续续
另外,我尝试使用下面的代码并且成功了,但是我在播放时听到了很多噪音。任何人都可以帮我解决这个问题并告诉我如何无噪音地播放音频吗?
P.S。传输中的超时是主要思想的一部分,我尝试在没有它的情况下播放音乐,但仍然没有成功。
<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。
我自己找到了我需要的解决方案。
此代码可帮助您通过 socket.io 和网络音频 Api 播放每个 wav 文件而不会出现任何问题。
客户端:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Test</title>
<script src="socket.io.js"></script>
<script src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
<script type="text/javascript">
var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
var socket = io.connect("http://localhost:3000");
var channels = 1;
let subcounter = 0;
let audiobuffer = [];
socket.on('chat message', function (msg) {
audiobuffer.push(new Uint16Array(msg));
console.log(".");
console.log(msg);
});
function play(soundName) {
var frameCount = audiobuffer[subcounter].length;
var myAudioBuffer = audioCtx.createBuffer(channels, frameCount, 22050);
for (var channel = 0; channel < channels; channel++) {
var nowBuffering = myAudioBuffer.getChannelData(channel);
for (var i = 0; i < frameCount; i++) {
// audio needs to be in [-1.0; 1.0]
var word = audiobuffer[subcounter][i];
nowBuffering[i] = ((word + 32768) % 65536 - 32768) / 32768.0;
}
}
subcounter += 1;
var source = audioCtx.createBufferSource();
source.buffer = myAudioBuffer;
source.connect(audioCtx.destination);
source.onended = play;
source.start();
}
</script>
</head>
<div>
<button id="play-sinewave" type="button" onclick="play('sinewave')">Play sound 'sinewave'</button>
</div>
</body>
</html>
服务器端:
const fs = require("fs");
var app = require("express")();
var http = require("http").createServer(app);
var io = require("socket.io")(http);
var cors = require("cors");
app.use(cors());
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("Original122050.wav", {
highWaterMark: 128000, // internal buffer size
});
let flag = true;
stream.on("data", async (chunk) => {
stream.pause();
setTimeout(async () => {
await asyncHandle(chunk);
flag = false;
stream.resume();
}, 1000); // I need this timeout because of my reasons, if u don't need it, just remove.
});
async function asyncHandle(chunk) {
if (flag) {
//U may have another header size.
chunk = chunk.slice(206); // Because I don't wanna play header as music!
}
console.log(chunk);
io.emit("chat message", chunk);
}
希望对大家有所帮助!
您可能会找到有关流式传输 pcm 数据的更多信息,感谢来自以下 link 评论部分的好心人,此处
我正在尝试在浏览器中播放wav原始数据,它是通过socket.io从nodejs服务器传输过来的,主要思想是尽快播放接收数据,所以我没有需要等到接收数据完成。我尝试在这种情况下使用 blob,但接下来总是会发生:如果我有一大块原始数据并且我正在使用 blob 将其转换为播放,然后当第二个数据块准备好并再次使用 blob 进行转换时,然后播放音频时断断续续
另外,我尝试使用下面的代码并且成功了,但是我在播放时听到了很多噪音。任何人都可以帮我解决这个问题并告诉我如何无噪音地播放音频吗?
P.S。传输中的超时是主要思想的一部分,我尝试在没有它的情况下播放音乐,但仍然没有成功。
<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。
我自己找到了我需要的解决方案。 此代码可帮助您通过 socket.io 和网络音频 Api 播放每个 wav 文件而不会出现任何问题。
客户端:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Test</title>
<script src="socket.io.js"></script>
<script src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
<script type="text/javascript">
var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
var socket = io.connect("http://localhost:3000");
var channels = 1;
let subcounter = 0;
let audiobuffer = [];
socket.on('chat message', function (msg) {
audiobuffer.push(new Uint16Array(msg));
console.log(".");
console.log(msg);
});
function play(soundName) {
var frameCount = audiobuffer[subcounter].length;
var myAudioBuffer = audioCtx.createBuffer(channels, frameCount, 22050);
for (var channel = 0; channel < channels; channel++) {
var nowBuffering = myAudioBuffer.getChannelData(channel);
for (var i = 0; i < frameCount; i++) {
// audio needs to be in [-1.0; 1.0]
var word = audiobuffer[subcounter][i];
nowBuffering[i] = ((word + 32768) % 65536 - 32768) / 32768.0;
}
}
subcounter += 1;
var source = audioCtx.createBufferSource();
source.buffer = myAudioBuffer;
source.connect(audioCtx.destination);
source.onended = play;
source.start();
}
</script>
</head>
<div>
<button id="play-sinewave" type="button" onclick="play('sinewave')">Play sound 'sinewave'</button>
</div>
</body>
</html>
服务器端:
const fs = require("fs");
var app = require("express")();
var http = require("http").createServer(app);
var io = require("socket.io")(http);
var cors = require("cors");
app.use(cors());
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("Original122050.wav", {
highWaterMark: 128000, // internal buffer size
});
let flag = true;
stream.on("data", async (chunk) => {
stream.pause();
setTimeout(async () => {
await asyncHandle(chunk);
flag = false;
stream.resume();
}, 1000); // I need this timeout because of my reasons, if u don't need it, just remove.
});
async function asyncHandle(chunk) {
if (flag) {
//U may have another header size.
chunk = chunk.slice(206); // Because I don't wanna play header as music!
}
console.log(chunk);
io.emit("chat message", chunk);
}
希望对大家有所帮助!
您可能会找到有关流式传输 pcm 数据的更多信息,感谢来自以下 link 评论部分的好心人,此处