有没有在浏览器中播放原始wav数据的好方法?

问题描述 投票:2回答:2

我正在尝试在浏览器中播放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);
}
javascript node.js socket.io blob web-audio-api
2个回答
1
投票

下面有一个WAV示例。我强烈建议您考虑将音频编码为Opus而不是WAV,因为它具有带宽和延迟优势。

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


0
投票

我自己找到了需要的解决方案。此代码可帮助您通过socket.io和Web Audio 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数据的更多信息,您可能会发现,这要感谢以下链接的注释部分的好心人,此处Play PCM with javascript

© www.soinside.com 2019 - 2024. All rights reserved.