如何捕捉通过HTTP传输的MP3的前10秒

免责声明:新手到nodeJS和audioparsing

我试图通过一个expressJS应用程序代理一个数字广播stream,在节点icecast的帮助下,这非常有效。 我收到广播的MP3stream,并通过节点lame解码MP3到PCM,然后发送到扬声器。 所有这些只是从github项目的自述例子直接工作:

var lame = require('lame'); var icecast = require('icecast'); var Speaker = require('speaker'); // URL to a known Icecast stream var url = 'http://firewall.pulsradio.com'; // connect to the remote stream icecast.get(url, function (res) { // log the HTTP response headers console.error(res.headers); // log any "metadata" events that happen res.on('metadata', function (metadata) { var parsed = icecast.parse(metadata); console.error(parsed); }); // Let's play the music (assuming MP3 data). // lame decodes and Speaker sends to speakers! res.pipe(new lame.Decoder()) .pipe(new Speaker()); }); 

我现在正在尝试使用Doreso API设置一个服务来识别音乐。 问题是我正在处理一个stream,没有这个文件(而且我还不够了解可读写stream,而且学习速度慢)。 我一直在寻找一段时间,试图写stream(理想的记忆),直到我有大约10秒的价值。 然后我会将这部分audio传递给我的API,但是我不知道这是可能的还是知道从哪里开始切片10秒的stream。 我想可能试图通过streamffmpeg,因为它有一个-t选项持续时间,也许这可能会限制它,但我还没有得到这个工作。

任何build议削减stream到10秒将是真棒。 谢谢!

更新 :改变我的问题,因为我原来以为我得到PCM和转换为MP3 ;-)我倒过来。 现在我只想在stream仍然供给扬声器的时候切掉一部分stream。

这不是那么容易,但我已经在这个周末处理了。 我会很高兴,如果你们可以指出如何甚至改善这个代码。 我不太喜欢模拟stream的“结束”的方法。 是否有像节点中的stream的pipe道布线的“分离”或“重新布线”部分?

首先,你应该创build你自己的Writable Stream类,它自己创build一个lame编码实例。 这个可写入的stream将接收解码后的PCM数据。

它是这样工作的:

 var stream = require('stream'); var util = require('util'); var fs = require('fs'); var lame = require('lame'); var streamifier = require('streamifier'); var WritableStreamBuffer = require("stream-buffers").WritableStreamBuffer; var SliceStream = function(lameConfig) { stream.Writable.call(this); this.encoder = new lame.Encoder(lameConfig); // we need a stream buffer to buffer the PCM data this.buffer = new WritableStreamBuffer({ initialSize: (1000 * 1024), // start as 1 MiB. incrementAmount: (150 * 1024) // grow by 150 KiB each time buffer overflows. }); }; util.inherits(SliceStream, stream.Writable); // some attributes, initialization SliceStream.prototype.writable = true; SliceStream.prototype.encoder = null; SliceStream.prototype.buffer = null; // will be called each time the decoded steam emits "data" // together with a bunch of binary data as Buffer SliceStream.prototype.write = function(buf) { //console.log('bytes recv: ', buf.length); this.buffer.write(buf); //console.log('buffer size: ', this.buffer.size()); }; // this method will invoke when the setTimeout function // emits the simulated "end" event. Lets encode to MP3 again... SliceStream.prototype.end = function(buf) { if (arguments.length) { this.buffer.write(buf); } this.writable = false; //console.log('buffer size: ' + this.buffer.size()); // fetch binary data from buffer var PCMBuffer = this.buffer.getContents(); // create a stream out of the binary buffer data streamifier.createReadStream(PCMBuffer).pipe( // and pipe it right into the MP3 encoder... this.encoder ); // but dont forget to pipe the encoders output // into a writable file stream this.encoder.pipe( fs.createWriteStream('./fooBar.mp3') ); }; 

现在,您可以将解码后的stream传送到SliceStream类的实例中,如下所示(其他pipe道附加):

 icecast.get(streamUrl, function(res) { var lameEncoderConfig = { // input channels: 2, // 2 channels (left and right) bitDepth: 16, // 16-bit samples sampleRate: 44100, // 44,100 Hz sample rate // output bitRate: 320, outSampleRate: 44100, mode: lame.STEREO // STEREO (default), JOINTSTEREO, DUALCHANNEL or MONO }; var decodedStream = res.pipe(new lame.Decoder()); // pipe decoded PCM stream into a SliceStream instance decodedStream.pipe(new SliceStream(lameEncoderConfig)); // now play it... decodedStream.pipe(new Speaker()); setTimeout(function() { // after 10 seconds, emulate an end of the stream. res.emit('end'); }, 10 * 1000 /*milliseconds*/) }); 

我可以build议10秒后使用removeListener吗? 这将阻止未来的事件通过听众传送。

 var request = require('request'), fs = require('fs'), masterStream = request('-- mp3 stream --') var writeStream = fs.createWriteStream('recording.mp3'), handler = function(bit){ writeStream.write(bit); } masterStream.on('data', handler); setTimeout(function(){ masterStream.removeListener('data', handler); writeStream.end(); }, 1000 * 10);