4

48 KHz でサウンドカードからデータをキャプチャし、収集のためにバッファに書き込むスレッドを作成するプログラムがあります。スレッドコードの核心は次のとおりです..

    public void run()   {
    // Run continously
    for (;;)    {
        // get data from the audio device.
        getSample();
    }
}

// Read in 2 bytes from the audio source combine them together into a single integer
// then write that into the sound buffer
private void getSample ()   {
    int sample,count,total=0,fsample;
    byte buffer[]=new byte[2];
    try {
            while (total<1) {
                count=Line.read(buffer,0,2);
                total=total+count;
                }
            } catch (Exception e)   {
                String err=e.getMessage();
            }
    sample=(buffer[0]<<8)+buffer[1];

            etc etc etc 
}

プロセスが CPU 時間の 100% を使用しているように見えることを除いて、プログラムは機能します。これは、スレッドが Line.Read 行にデータが到着するのを待っているためだと思います。スレッドのさまざまなポイントで Thread.yield() を挿入しようとしましたが、違いはないようです。

このスレッドにかかる CPU 時間を短縮する方法を提案できる人はいますか?

御時間ありがとうございます

イアン

4

3 に答える 3

3

スレッドが入力をブロックしていることを確認してください。

ブロックしない場合、スレッドは CPU 時間の 100% を占有します。ブロックすると、スレッドを起動するための外部刺激が発生するまで、スレッドがスリープ状態になります。入力を処理するための専用スレッドがある場合は常に、そのスレッドがループで CPU 時間を 100% 占有するのを避けるために、このようにスリープするようにその入力をブロックしていることを確認する必要があります。

この特定のケースでは、 ifLineが の場合javax.sound.sampled.TargetDataLineread()メソッドはブロッキングを行うべき場所です。APIによると、「このメソッドは、要求された量のデータが読み取られるまでブロックされます」が、「要求された量が読み取られる前にデータラインが閉じられ、停止され、排出され、またはフラッシュされた場合、メソッドはブロックされなくなりますが、これまでに読み取ったバイト数を返します。」

したがって、いくつかの可能性があります。の定義が表示Lineされないため、含まれていないコードの行をフラッシュまたはドレインしている可能性があります。それを行った場合は、それらのメソッドを使用しないようにソリューションをリファクタリングする必要があります。

もう 1 つの可能性は、常に一度に 2 バイトしか読み取っていないため、ブロックするほど十分に読み取っていないことです。基本的に、読み取った 2 バイトを処理するのに時間がかかりすぎるため、常に 2 バイトが使用可能であり、常に別の 2 バイトが使用可能です。バッファのサイズを増やして、一度に 4kb 程度を読み取ってみてください。これにより、ループの実行頻度が低下し、ブロックの頻度が高くなるかどうかを確認してください。

于 2010-10-25T13:48:42.273 に答える
1

サイズ 2 よりもはるかに大きな read-buffer を使用する必要があります。ほとんどの場合、適度に大きなバッファー サイズを使用することをお勧めしますが、小さなバッファー サイズを使用する場合、何らかの理由で javax.sound は特に非効率的です。これは、Java ベースの VU メーターを実装したときに学びました。

于 2010-11-20T22:40:47.743 に答える
0

Thread.sleep(a few ms);aを無限ループに入れるか、 a を使用しjava.util.Timerて数ミリ秒ごとに getSample() を呼び出します。

于 2010-10-25T13:23:58.537 に答える