网络音频 API - 块之间的直播流 'clicks'。
Web Audio API - Live Stream 'clicks' between chunks.
我正在尝试通过 node.js(快速)服务器上的网络套接字将音频流式传输到网络浏览器。音频来自 iOS 设备,以 4k(每秒 4000 个样本)采样的 16 位单声道 wav 文件。
这是我的代码:
服务器代码:
webSocketServer.on('connection', function connection(client) {
client.on('message', function(message) {
webSocketServer.clients.forEach(function each(connection) {
connection.send(message, { binary: true }
);
});
});
客户代码:
webSocket = new WebSocket('ws://' + window.location.hostname + ':8080/');
webSocket.binaryType = 'arraybuffer'
webSocket.onmessage = function(message) {
var arrayBuffer = message.data // wav from server, as arraybuffer
var source = audioContext.createBufferSource();
audioContext.decodeAudioData(arrayBuffer, function(buffer){
source.buffer = buffer
source.connect(audioContext.destination)
source.start(time);
time += source.buffer.duration
}, function(){
console.log('error')
})
};
decodeAudioData()
似乎可以正常工作,但是它 returns 的音频缓冲区长度只有我预期的一半。 (例如 4000 个样本只会给我 0.5 秒的音频。我最初认为这是因为 wav 是 16 位而不是 32,但是切换到 32 导致 decodeAudioData()
触发它的错误回调。
我认为可以将此解决方法添加到成功回调中:
source.playbackRate.value = 0.5 // play at half speed
time += source.buffer.duration * 2 // double duration
这让计时完美,但我遇到了一个问题:音频块之间有一个可听见的'click'或'pop'。将块间隔一秒 (time += (source.buffer.duration * 2) + 1
) 后,我发现点击发生在每个块的最开头。
所以我最头疼的两个问题是:
1) 为什么解码后的音频播放速度是我预期的两倍?我的 4k 采样率对于 Web Audio API 来说太低了吗?为什么我不能解码 32 位 wav?
2) 我对数字音频工作站(ableton、logic)有一些经验,我知道如果波 'jumps' 从样本回落到零或反之亦然(即:starting/ending一个相位中间的正弦波)。这就是这里发生的事情吗?有办法解决这个问题吗?交叉淡入淡出每个单独的样本似乎很愚蠢。为什么每个块都不会从最后一个停止的地方拾取?
1) 我收到的音频实际上是 2k 的错误,但是 wav header 仍然说 4k,因此双倍速错误。
2) 见Chris Wilsons answer here最后一段:
Finally - this is not going to work well if the sound stream does not match the default audio device's sample rate; there are always going to be clicks, because decodeAudioData will resample to the device rate, which will not have a perfect duration. It will work, but there will likely be artifacts like clicks at the boundaries of chunks. You need a feature that's not yet spec'ed or implemented - selectable AudioContext sample rates - in order to fix this.
Brion Vibbers AudioFeeder.js works great without any clicks but requires raw 32bit pcm data. Also be wary of upsampling artifacts!
另一种选择:
您可以使用 MediaSource API 来克服音频之间的这些故障。
如果您需要对此进行全面研究,请使用:MSE for Audio
我正在尝试通过 node.js(快速)服务器上的网络套接字将音频流式传输到网络浏览器。音频来自 iOS 设备,以 4k(每秒 4000 个样本)采样的 16 位单声道 wav 文件。
这是我的代码:
服务器代码:
webSocketServer.on('connection', function connection(client) {
client.on('message', function(message) {
webSocketServer.clients.forEach(function each(connection) {
connection.send(message, { binary: true }
);
});
});
客户代码:
webSocket = new WebSocket('ws://' + window.location.hostname + ':8080/');
webSocket.binaryType = 'arraybuffer'
webSocket.onmessage = function(message) {
var arrayBuffer = message.data // wav from server, as arraybuffer
var source = audioContext.createBufferSource();
audioContext.decodeAudioData(arrayBuffer, function(buffer){
source.buffer = buffer
source.connect(audioContext.destination)
source.start(time);
time += source.buffer.duration
}, function(){
console.log('error')
})
};
decodeAudioData()
似乎可以正常工作,但是它 returns 的音频缓冲区长度只有我预期的一半。 (例如 4000 个样本只会给我 0.5 秒的音频。我最初认为这是因为 wav 是 16 位而不是 32,但是切换到 32 导致 decodeAudioData()
触发它的错误回调。
我认为可以将此解决方法添加到成功回调中:
source.playbackRate.value = 0.5 // play at half speed
time += source.buffer.duration * 2 // double duration
这让计时完美,但我遇到了一个问题:音频块之间有一个可听见的'click'或'pop'。将块间隔一秒 (time += (source.buffer.duration * 2) + 1
) 后,我发现点击发生在每个块的最开头。
所以我最头疼的两个问题是:
1) 为什么解码后的音频播放速度是我预期的两倍?我的 4k 采样率对于 Web Audio API 来说太低了吗?为什么我不能解码 32 位 wav?
2) 我对数字音频工作站(ableton、logic)有一些经验,我知道如果波 'jumps' 从样本回落到零或反之亦然(即:starting/ending一个相位中间的正弦波)。这就是这里发生的事情吗?有办法解决这个问题吗?交叉淡入淡出每个单独的样本似乎很愚蠢。为什么每个块都不会从最后一个停止的地方拾取?
1) 我收到的音频实际上是 2k 的错误,但是 wav header 仍然说 4k,因此双倍速错误。
2) 见Chris Wilsons answer here最后一段:
Finally - this is not going to work well if the sound stream does not match the default audio device's sample rate; there are always going to be clicks, because decodeAudioData will resample to the device rate, which will not have a perfect duration. It will work, but there will likely be artifacts like clicks at the boundaries of chunks. You need a feature that's not yet spec'ed or implemented - selectable AudioContext sample rates - in order to fix this.
Brion Vibbers AudioFeeder.js works great without any clicks but requires raw 32bit pcm data. Also be wary of upsampling artifacts!
另一种选择: 您可以使用 MediaSource API 来克服音频之间的这些故障。
如果您需要对此进行全面研究,请使用:MSE for Audio