有没有什么好的方法可以在浏览器中播放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。

https://fetch-stream-audio.anthum.com  ::  (GitHub)

我自己找到了我需要的解决方案。 此代码可帮助您通过 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 评论部分的好心人,此处