我在上一篇文章中提到了这一点,但是由于它与原始问题不相关,因此我将其分开发布。我无法以与在媒体播放器中一样的方式通过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
您真的不能只这样调用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 }; }