1

免責事項:nodeJSとオーディオ解析の初心者

node-icecastの助けを借りて、expressJS アプリを介してデジタル ラジオ ストリームをプロキシしようとしています。私はラジオのmp3ストリームを取得しており、ノードラメを介してmp3をPCMにデコードし、スピーカーに送信しています。これらはすべて、github プロジェクトの readme の例からそのまま機能します。

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 に変換すると思っていたので、質問を変更しました ;-) 逆にしました。ここで、ストリームがまだスピーカーにフィードしている間に、ストリームの一部を切り取りたいだけです。

4

2 に答える 2

2

そんなに簡単ではありませんが、今週末はなんとかやり遂げました。このコードを改善する方法さえ指摘していただければ幸いです。ストリームの「終わり」をシミュレートするアプローチはあまり好きではありません。ノード内のストリームのパイプ配線の一部を「切り離す」または「再配線」するようなものはありますか?

まず、自分自身の Writable 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')
    );
};

これで、次のように、デコードされたストリームを SliceStream クラスのインスタンスにパイプできます (他のパイプに追加)。

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*/)
});
于 2015-03-24T14:28:03.097 に答える