我在上一篇文章中提到了这一点,但由于它是原始问题的主题,我将单独发布.我无法通过Web Audio播放传输的音频,就像在媒体播放器中播放的那样.我尝试过两种不同的传输协议,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
解决方法
你真的不能像这样调用source.start(audioContext.currentTime).
setTimeout()有一个漫长且不精确的延迟 – 其他主线程的东西可以继续,所以你的setTimeout()调用可以延迟毫秒,甚至几十毫秒(通过垃圾收集,JS执行,布局…)你的代码试图立即播放音频 – 需要在大约0.02ms精度内启动而不会出现故障 – 在具有数十毫秒不精确度的定时器上.
Web音频系统的重点是音频调度程序在一个单独的高优先级线程中工作,您可以非常高的准确度预先安排音频(开始,停止和audioparam更改).您应该将系统重写为:
1)跟踪第一个块是在audiocontext时间安排的时间 – 并且不要立即安排第一个块,给出一些延迟,以便您的网络可以跟上.
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(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 }; }