【问题标题】:decodeAudioData failing with null errors on continuous streamdecodeAudioData 在连续流上失败并出现空错误
【发布时间】:2013-12-03 19:53:43
【问题描述】:

在我的以下代码中,ffmpeg 正在对输入流进行转码,并成功地将块发送到客户端。在客户端,客户端正在解码来自 socket.io 的 base64 响应,并将响应转换为数组缓冲区。从那时起,decodeAudioData 无法处理数组缓冲区并返回空错误。有谁知道为什么 decodeAudioData 不起作用?

./webaudio_svr.js:

var express = require('/usr/local/lib/node_modules/express');
var http = require('http');
var spawn = require('child_process').spawn;
var util = require('util');
var fs = require('fs');

var app       = express();
var webServer = http.createServer(app);
var audServer = http.createServer(app);
var io        = require('/usr/local/lib/node_modules/socket.io').listen(webServer, {log: false, });

app.use(express.static(__dirname + '/public'));

app.get('/', function(req, res){
    res.send(
    "<script src='/socket.io/socket.io.js'></script>\n"+
    "<script>var socket=io.connect('http://127.0.0.1:3000');</script>\n"+
    "<script src='/webaudio_cli.js'></script>"
    );
});
webServer.listen(3000);

var inputStream = spawn('/usr/bin/wget', ['-O','-','http://nprdmp.ic.llnwd.net/stream/nprdmp_live01_mp3']);

var ffmpeg = spawn('ffmpeg', [
    '-i', 'pipe:0', // Input on stdin
    '-ar', '44100', // Sampling rate
    '-ac', 2, // Stereo
    '-f', 'mp3',
    'pipe:1' // Output on stdout
]);

io.sockets.on('connection', function(webSocket) {
    var disconnect = '0';

    if (disconnect == '0') {
        inputStream.stdout.pipe(ffmpeg.stdin);
        ffmpeg.stdout.on('data', function(data) {
            var data64 = data.toString('base64');
            webSocket.emit('stream',data64);
        });
    }

    webSocket.on('disconnect', function() {
        disconnect=1;
    });
});

./public/webaudio_cli.js:

function str2ab(str) {
    var buf = new ArrayBuffer(str.length*2); // 2 bytes for each char
    var bufView = new Uint16Array(buf);
    for (var i=0, strLen=str.length; i<strLen; i++) {
        bufView[i] = str.charCodeAt(i);
    }
    return buf;
}

window.AudioContext = window.AudioContext || window.webkitAudioContext;
var context = new AudioContext();
var source = context.createBufferSource();

socket.on('stream', function(data) {
        var data=str2ab(atob(data));
        context.decodeAudioData(data, function(buffer) {
            source.connect(context.destination);
            source.buffer = buffer;
            source.start(0);
        }, function(err) {
            console.log("err(decodeAudioData): "+err);
        });
});

【问题讨论】:

  • 如果您的音频只是原始的 16 位 PCM,我很确定 decodeAudioData 不知道如何处理它。
  • 不是原始 PCM,ffmpeg 正在将其转码为 mp3。我实际上想使用来自 ffmpeg 的 speex 编码的 ogg 流,但我在这个主题上看到的所有帖子都涉及 mp3,所以我想我会这样做以增加获得答案的机会。
  • var sourceload 回调函数中声明。 decodeAudioData如何访问它?
  • 只是为了缩小范围,您是否尝试过转储 base64 数据、对其进行解码并使用 VLC 或其他方式进行回放?让我们将其缩小到客户端问题,然后是是否存在编解码器支持问题。
  • @Brad.Smith,这不是内置的 DOM 方法——他们实际上已经在页面上写出了函数。

标签: html node.js google-chrome ffmpeg web-audio-api


【解决方案1】:

如果您阅读原始帖子的注释部分,您会发现我最终使用 binaryjs 进行了此操作,但在 Kevin 的帮助下,我能够使其与 socket.io 一起使用。请注意,这仍然是播放不连贯的一个巨大问题。如果有人可以帮助清理音频,请这样做。除非音频按预期工作,否则这个解决方案真的毫无意义,所以我需要弄清楚这一点。

问题与浏览器如何编码/解码您的 base64 字符串有关。在此更改之前,您必须从 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Base64_encoding_and_decoding 提供您自己的函数。

webaudio_svr.js:

var express = require('/usr/local/lib/node_modules/express');
var http = require('http');
var spawn = require('child_process').spawn;
var util = require('util');
var fs = require('fs');

var app       = express();
var webServer = http.createServer(app);
var io        = require('/usr/local/lib/node_modules/socket.io').listen(webServer, {log: false, });

app.use(express.static(__dirname + '/public'));

app.get('/', function(req, res){
    res.send(
    "<script src='/socket.io/socket.io.js'></script>\n"+
    "<script>var socket=io.connect('http://127.0.0.1:3000');</script>\n"+
    "<script src='/base64.js'></script>\n"+
    "<script src='/webaudio_cli.js'></script>"
    );
});
webServer.listen(3000);

var inputStream = spawn('/usr/bin/wget', ['-O','-','http://nprdmp.ic.llnwd.net/stream/nprdmp_live01_mp3']);

var ffmpeg = spawn('ffmpeg', [
    '-i', 'pipe:0', // Input on stdin
    '-ar', '44100', // Sampling rate
    '-ac', 2, // Stereo
    '-f', 'mp3',
    'pipe:1' // Output on stdout
]);

io.sockets.on('connection', function(webSocket) {
    var disconnect = '0';

    if (disconnect == '0') {
        inputStream.stdout.pipe(ffmpeg.stdin);
        ffmpeg.stdout.on('data', function(data) {
            var data64 = data.toString('base64');
            webSocket.emit('stream',data64);
        });
    }

    webSocket.on('disconnect', function() {
        disconnect=1;
    });
});

公共/webaudio_cli.js:

window.AudioContext = window.AudioContext || window.webkitAudioContext;
var context = new AudioContext();
var startTime = context.currentTime;

// buffer to arraybuffer
function toArrayBuffer(buffer) {
    var ab = new ArrayBuffer(buffer.length);
    var view = new Uint8Array(ab);
    for (var i = 0; i < buffer.length; ++i) {
    view[i] = buffer[i];
    }
    return ab;
}
socket.on('stream', function(data) {
        var data=toArrayBuffer(base64DecToArr(data));
        context.decodeAudioData(data, function(buffer) {
            playBuffer(buffer);
        }, function(err) {
            console.log("decodeAudioData err: "+err);
        });
});

function playBuffer(buf) {
    var source    = context.createBufferSource();
    source.buffer = buf;
    source.connect(context.destination);
    source.start(startTime);
    startTime = startTime+source.buffer.duration;
}

public/base64.js:

【讨论】:

  • 一些事情:首先,在你准备好播放第一个缓冲区之前,不要给startTime赋值。照原样,startTime 将在您实际获得第一个块时成为过去 - 这意味着您的所有时间都将关闭,并且事情将在不应该的时候立即开始播放。其次,您可能希望将缓冲区存储在一个数组中,并且在将其中一些缓冲区排队之前不要开始尝试播放它们。这将为您提供一些针对网络问题的保护。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-17
  • 2018-02-24
  • 1970-01-01
  • 1970-01-01
  • 2021-06-01
  • 2012-09-24
相关资源
最近更新 更多