我在使用node.js和socket.io通过WebSocket流式传输MP3数据时遇到问题。一切似乎都正常,但decodeAudioData对我来说不公平。
这是我的玩具服务器:
var app = require('http').createServer(handler)
, io = require('socket.io').listen(app)
, fs = require('fs')
app.listen(8081);
function handler (req, res) {
res.writeHead(200, {
'Content-Type': 'text/html',
});
res.end('Hello, world!');
}
io.configure('development', function() {
io.set('log level', 1);
io.set('transports', [ 'websocket' ]);
});
io.sockets.on('connection', function (socket) {
console.log('connection established');
var readStream = fs.createReadStream("test.mp3",
{'flags': 'r',
'encoding': 'binary',
'mode': 0666,
'bufferSize': 64 * 1024});
readStream.on('data', function(data) {
console.log(typeof data);
console.log('sending chunk of data')
socket.send(data);
});
socket.on('disconnect', function () {
console.log('connection droped');
});
});
console.log('Server running at http://127.0.0.1:8081/');
客户端以字符串类型接收数据,但我想将数据提供给decodeAudioData,它似乎不喜欢字符串。调用decodeAudioData会导致以下错误消息:
Uncaught Error: SYNTAX_ERR: DOM Exception 12
我认为decodeAudioData需要存储在ArrayBuffer中的数据。有没有转换数据的方法?
这是客户端代码:
<script src="http://127.0.0.1:8081/socket.io/socket.io.js"></script>
<script>
var audioBuffer = null;
var context = null;
window.addEventListener('load', init, false);
function init() {
try {
context = new webkitAudioContext();
} catch(e) {
alert('Web Audio API is not supported in this browser');
}
}
function decodeHandler(buffer) {
console.log(data);
}
var socket = io.connect('http://127.0.0.1:8081');
socket.on('message', function (data) {
// HERE IS THE PROBLEM
context.decodeAudioData(data, decodeHandler, function(e) { console.log(e); });
});
</script>
我自己找到了一种通过Websockets流式传输MP3数据的方法。
一个问题是MP3数据的块大小。似乎Web Audio API需要提供有效的MP3块才能解码数据。也许并不奇怪。在我的演示应用程序中,我提供了一组MP3块文件。
此外,音频的质量也不完美。我有一些小故障。我能够通过发送更大的MP3数据块来改进这一点,但仍然存在微小的裂纹。
编辑:我设法提高了音频质量。似乎Web Audio方法解码AudioData并不是真正设计用于解码连续的MP3数据块。
在您的情况下,context.decodeAudioData需要一个二进制数据的ArrayBuffer,我建议将您的区块转换为base64字符串,然后转换为ArrayBuff客户端,以获得最可预测的结果。这个脚本应该是从base64对分块数据进行客户端解码的一个很好的起点。
在获得数据(base-64编码字符串)后立即添加一行data = Base64Binary.decodeArrayBuffer(data);
就可以了。。。
socket.io似乎仍然不支持二进制传输。所以websocket.io可以在这里使用。
- https://github.com/LearnBoost/socket.io/issues/511#issuecomment-2370129
- https://github.com/LearnBoost/socket.io/issues/680#issuecomment-3083490