一尘不染

通过Web Audio API通过分块音频进行断断续续的/听不清的播放

node.js

我在上一篇文章中提到了这一点,但是由于它与原始问题不相关,因此我将其分开发布。我无法以与在媒体播放器中一样的方式通过Web
Audio播放传输的音频。我尝试了2种不同的传输协议,binaryjs和socketio,并且在尝试通过Web
Audio播放时都没有区别。为了排除音频数据的传输问题,我创建了一个示例,该示例在从客户端接收数据后将数据发送回服务器,并将返回的数据转储到stdout。将其插入VLC可带来您希望听到的聆听体验。

要在通过vlc播放时听到结果(听起来应该是这样),使用以下命令在https://github.com/grkblood13/web-audio-
stream/tree/master/vlc上运行示例:

$ node webaudio_vlc_svr.js | vlc -

无论出于何种原因,当我尝试通过Web Audio播放相同的音频数据时,它都会失败。结果是随机噪声之间存在较大的静默间隙。

以下代码使播放声音变得如此糟糕,这是怎么回事?

window.AudioContext = window.AudioContext || window.webkitAudioContext;
var context = new AudioContext();
var delayTime = 0;
var init = 0;
var audioStack = [];

client.on('stream', function(stream, meta){
    stream.on('data', function(data) {
        context.decodeAudioData(data, function(buffer) {
            audioStack.push(buffer);
            if (audioStack.length > 10 && init == 0) { init++; playBuffer(); }
        }, function(err) {
            console.log("err(decodeAudioData): "+err);
        });
    });
});

function playBuffer() {
    var buffer = audioStack.shift();
    setTimeout( function() {
            var source    = context.createBufferSource();
            source.buffer = buffer;
            source.connect(context.destination);
            source.start(context.currentTime);
            delayTime=source.buffer.duration*1000; // Make the next buffer wait the length of the last buffer before being played
            playBuffer();
    }, delayTime);
}

全文:https : //github.com/grkblood13/web-audio-
stream/tree/master/binaryjs


阅读 282

收藏
2020-07-07

共1个答案

一尘不染

您真的不能只这样调用source.start(audioContext.currentTime)。

setTimeout()的延迟时间长且不精确-
其他主线程可能会继续运行,因此setTimeout()调用可能会延迟几毫秒,甚至数十毫秒(通过垃圾回收,JS执行,布局…)。代码正试图在具有数十毫秒不精确度的计时器上立即播放音频-
该音频必须在大约0.02ms的精度内启动而不出现毛刺-。

Web音频系统的全部要点是音频调度程序在单独的高优先级线程中工作,并且您可以以非常高的精度预先调度音频(开始,停止和audioparam更改)。您应该将系统重写为:

1)跟踪在音频上下文时间安排第一个块的时间-不要立即安排第一个块,给它们一些延迟,以便您的网络有望跟上进度。

2)基于其“下一块”定时安排将来接收的每个连续块。

例如(请注意,我尚未测试此代码,这超出了我的头脑):

window.AudioContext = window.AudioContext || window.webkitAudioContext;
var context = new AudioContext();
var delayTime = 0;
var init = 0;
var audioStack = [];
var nextTime = 0;

client.on('stream', function(stream, meta){
    stream.on('data', function(data) {
        context.decodeAudioData(data, function(buffer) {
            audioStack.push(buffer);
            if ((init!=0) || (audioStack.length > 10)) { // make sure we put at least 10 chunks in the buffer before starting
                init++;
                scheduleBuffers();
            }
        }, function(err) {
            console.log("err(decodeAudioData): "+err);
        });
    });
});

function scheduleBuffers() {
    while ( audioStack.length) {
        var buffer = audioStack.shift();
        var source    = context.createBufferSource();
        source.buffer = buffer;
        source.connect(context.destination);
        if (nextTime == 0)
            nextTime = context.currentTime + 0.05;  /// add 50ms latency to work well across systems - tune this if you like
        source.start(nextTime);
        nextTime+=source.buffer.duration; // Make the next buffer wait the length of the last buffer before being played
    };
}
2020-07-07