我正在尝试使用节点js和socket io实时缓冲MP3歌曲。我基本上将MP3分成几段字节并将其发送到客户端,网络音频API将接收它,解码并开始播放。这里的问题是声音不能连续播放,每个缓冲段之间有0.5秒的差距。我该如何解决这个问题
// buffer is a 2 seconds decoded audio ready to be played
// the function is called when a new buffer is recieved
function stream(buffer)
{
// creates a new buffer source and connects it to the Audio context
var source = context.createBufferSource();
source.buffer = buffer;
source.connect(context.destination);
source.loop = false;
// sets it and updates the time
source.start(time + context.currentTime);
time += buffer.duration; // time is global variable initially set to zero
}
称为流的部分
// where stream bufferQ is an array of decoded MP3 data
// so the stream function is called after every 3 segments that are recieved
// the Web audio Api plays it with gaps between the sound
if(bufferQ.length == 3)
{
for(var i = 0, n = bufferQ.length ; i < n; i++)
{
stream(bufferQ.splice(0,1)[0]);
}
}
我应该使用除了网络音频API之外的其他API,还是有办法安排我的缓冲区以便连续播放?
答案 0 :(得分:0)
这是mp3文件的问题,每个mp3文件在开始和结束时都有几帧静音。 如果你使用wav文件或正确计时每个文件的开始和停止,你可以修复它
答案 1 :(得分:0)
context.currentTime将根据评估时间的不同而有所不同,并且由于四舍五入到最接近的2ms左右,因此每次读取都有隐式的误差(请参见Firefox BaseAudioContext/currentTime#Reduced time precision)。考虑:
function stream(buffer)
{
...
source.start(time + context.currentTime);
time += buffer.duration; // time is global variable initially set to zero
为每个PCM数据块调用source.start(time + context.currentTime)
总是将在当前时间(四舍五入到2ms)加上{{1} }偏移量。
要播放背对背PCM块,请在流的开头读取一次currentTime,然后在安排播放后将每个持续时间添加到该时间。例如,PCMPlayer执行以下操作:
time
注意PCMPlayer.prototype.flush = function() {
...
if (this.startTime < this.audioCtx.currentTime) {
this.startTime = this.audioCtx.currentTime;
}
...
bufferSource.start(this.startTime);
this.startTime += audioBuffer.duration;
};
仅在它代表过去的时间时才被重置-对于连续缓冲的流,它不会被重置,因为它将在将来的某个时间值。在每次刷新调用中,startTime
用于安排回放,并且仅随着每个PCM数据持续时间而增加,而与currentTime无关。
另一个潜在的问题是,您正在解码的PCM缓冲区的采样率可能与AudioContext的采样率不匹配。在这种情况下,浏览器将分别对每个PCM缓冲区重新采样,从而导致块边界不连续。参见Clicking sounds in Stream played with Web Audio Api。