【问题标题】:Choppy/inaudible playback with chunked audio through Web Audio API通过 Web 音频 API 使用分块音频进行断断续续/听不见的播放
【发布时间】:2013-12-26 21:05:16
【问题描述】:

我在上一篇文章中提出了这个问题,但由于它与原始问题无关,因此我将其单独发布。我无法像在媒体播放器中一样通过网络音频播放传输的音频。我尝试了 2 种不同的传输协议,binaryjs 和 socketio,但在尝试通过 Web Audio 播放时都没有任何区别。为了排除音频数据的传输问题,我创建了一个示例,该示例在从客户端接收数据后将数据发送回服务器并将返回转储到标准输出。将其导入 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

【问题讨论】:

  • 这个问题有点老了,但是我在你的仓库上测试了代码没有成功,你有什么更新吗?

标签: html node.js audio-streaming web-audio-api


【解决方案1】:

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

setTimeout() 有一个很长且不精确的延迟 - 其他主线程的东西可能正在进行,所以你的 setTimeout() 调用可能会延迟几毫秒,甚至几十毫秒(通过垃圾收集、JS 执行、布局.. .) 您的代码正在尝试在具有数十毫秒不精确度的计时器上立即播放音频 - 需要在大约 0.02 毫秒的精度内启动才能不会出现故障。

网络音频系统的重点在于音频调度程序在单独的高优先级线程中工作,您可以以非常高的准确度预先调度音频(开始、停止和音频参数更改)。您应该将系统重写为:

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
    };
}

【讨论】:

  • 感谢 cwilso,但这段代码听起来也非常有问题。也许是我的浏览器导致了问题。我的来源也是一个连续的直播,所以我不确定这是否重要。我认为不会。
  • 所以我尝试了几种不同的设置,结果每次都一样。这是我使用示例源代码和此更新的客户端代码听到的音频 sn-p。这是一个 22 秒的 ogg 文件。 drive.google.com/file/d/0B8vThR7JhLk_R2owSWp4eVNwR1E/…
  • 这似乎没有什么问题 - 似乎您没有获得所有数据,或者它是在过去安排的,或者其他一些非常糟糕的事情。我会疯狂地开始 console.log() 诊断,确保你得到了所有的数据包,它们被按顺序安排,并检查 currentTime 以确保有足够的延迟。
  • 我发现了我遇到的问题。出于某种原因使用 decodeAudioData 时,我无法一次发送一个块进行播放。为了解决这个问题,我在服务器上一次连接 40 个块,然后再发送到客户端。
  • 布拉德,你能展示你的工作代码吗?我也有延迟问题。谢谢!
猜你喜欢
  • 1970-01-01
  • 2017-11-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-06
相关资源
最近更新 更多