如何捕获通过 HTTP 流式传输的 mp3 的前 10 秒
How to capture the first 10 seconds of an mp3 being streamed over HTTP
免责声明:nodeJS 和音频解析新手
我正在尝试借助 expressJS 应用程序代理数字广播流 node-icecast which works great. I am getting the radio's mp3 stream, and via node-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 识别音乐。问题是我正在使用一个流,但没有文件(而且我对可读和可写流的了解还不够,而且学习速度很慢)。我一直在四处寻找一段时间,试图写入流(最好写入内存),直到我有大约 10 秒的时间。然后我会将那部分音频传递给我的 API,但是我不知道这是否可行,也不知道从哪里开始切割 10 秒的流。我想可能会尝试将流传递给 ffmpeg,因为它有一个持续时间的 -t 选项,也许这会限制它,但我还没有让它工作。
任何将流缩短到 10 秒的建议都很棒。谢谢!
已更新:更改了我的问题,因为我最初认为我正在获取 PCM 并转换为 mp3 ;-) 我倒退了。现在我只想切掉一部分流,同时流仍然为扬声器供电。
没那么容易..但我这个周末做到了。如果你们能指出如何改进这段代码,我会很高兴。我不太喜欢模拟流的 "end" 的方法。节点中的流管道布线是否有类似 "detaching" 或 "rewiring" 的部分?
首先,您应该创建自己的可写流 class,它本身会创建一个蹩脚的编码实例。这个可写流将接收解码后的 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')
);
};
现在您可以将 解码的 流通过管道传输到您的 SliceStream class 实例中,像这样(除了其他管道之外):
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*/)
});
我可以建议在 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);
免责声明:nodeJS 和音频解析新手
我正在尝试借助 expressJS 应用程序代理数字广播流 node-icecast which works great. I am getting the radio's mp3 stream, and via node-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 识别音乐。问题是我正在使用一个流,但没有文件(而且我对可读和可写流的了解还不够,而且学习速度很慢)。我一直在四处寻找一段时间,试图写入流(最好写入内存),直到我有大约 10 秒的时间。然后我会将那部分音频传递给我的 API,但是我不知道这是否可行,也不知道从哪里开始切割 10 秒的流。我想可能会尝试将流传递给 ffmpeg,因为它有一个持续时间的 -t 选项,也许这会限制它,但我还没有让它工作。
任何将流缩短到 10 秒的建议都很棒。谢谢!
已更新:更改了我的问题,因为我最初认为我正在获取 PCM 并转换为 mp3 ;-) 我倒退了。现在我只想切掉一部分流,同时流仍然为扬声器供电。
没那么容易..但我这个周末做到了。如果你们能指出如何改进这段代码,我会很高兴。我不太喜欢模拟流的 "end" 的方法。节点中的流管道布线是否有类似 "detaching" 或 "rewiring" 的部分?
首先,您应该创建自己的可写流 class,它本身会创建一个蹩脚的编码实例。这个可写流将接收解码后的 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')
);
};
现在您可以将 解码的 流通过管道传输到您的 SliceStream class 实例中,像这样(除了其他管道之外):
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*/)
});
我可以建议在 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);