11

ファイルをロードし、FileInputStream > BufferedInputStream > DataInputStream メソッドを介してバイトを AudioTrack.write() にフィードすることにより、Android フォンで WAV を再生しています。オーディオは問題なく再生され、その場合は、サンプル レート、ボリュームなどをオンザフライで簡単に調整でき、優れたパフォーマンスが得られます。ただし、トラックの再生が始まるまでに約 2 秒かかります。AudioTrack には避けられない遅延があることは知っていますが、これはばかげています。トラックを再生するたびに、次のようになります。

03-13 14:55:57.100: WARN/AudioTrack(3454): obtainBuffer timed out (is the CPU pegged?) 0x2e9348 user=00000960,     server=00000000
03-13 14:55:57.340: WARN/AudioFlinger(72): write blocked for 233 msecs, 9 delayed writes, thread 0xba28

電話の電源を入れてから、トラックを再生するたびに、複数のセッションにまたがっても、遅延書き込みカウントが 1 ずつ増加することに気付きました。ブロック時間は常に 230 ~ 240 ミリ秒です。これは、このデバイスの最小バッファー サイズが 9600 (9600 / 44100) であることを考慮すると理にかなっています。インターネットで数え切れないほどの検索でこのメッセージを見てきましたが、通常は、オーディオがまったく再生されないか、オーディオがスキップされることに関連しているようです。私の場合は、開始が遅れただけです。

すべてのコードを優先度の高いスレッドで実行しています。これは、私がやっていることの切り詰められたまだ機能的なバージョンです。これは、再生クラスのスレッド コールバックです。繰り返しますが、これは機能します (現在は 16 ビット、44.1kHz、ステレオ ファイルのみを再生しています)。起動するのに永遠に時間がかかり、毎回その getsBuffer/delayed write メッセージを持っています。

public void run() {

    // Load file
    FileInputStream mFileInputStream;
    try {
        // mFile is instance of custom file class -- this is correct, 
        // so don't sweat this line
        mFileInputStream = new FileInputStream(mFile.path());
    } catch (FileNotFoundException e) {
        // log
    }

    BufferedInputStream mBufferedInputStream = new BufferedInputStream(mFileInputStream, mBufferLength);
    DataInputStream mDataInputStream = new DataInputStream(mBufferedInputStream);

    // Skip header
    try {
        if (mDataInputStream.available() > 44) {
            mDataInputStream.skipBytes(44);
        }
    } catch (IOException e) {
        // log
    }

    // Initialize device
    mAudioTrack = new AudioTrack(
        AudioManager.STREAM_MUSIC, 
        ConfigManager.SAMPLE_RATE, 
        AudioFormat.CHANNEL_CONFIGURATION_STEREO, 
        AudioFormat.ENCODING_PCM_16BIT, 
        ConfigManager.AUDIO_BUFFER_LENGTH,
        AudioTrack.MODE_STREAM
    );
    mAudioTrack.play();

    // Initialize buffer
    byte[] mByteArray = new byte[mBufferLength];
    int mBytesToWrite = 0;
    int mBytesWritten = 0;

    // Loop to keep thread running
    while (mRun) {

        // This flag is turned on when the user presses "play"
        while (mPlaying) {

            try {
                // Check if data is available
                if (mDataInputStream.available() > 0) {

                    // Read data from file and write to audio device
                    mBytesToWrite = mDataInputStream.read(mByteArray, 0, mBufferLength);
                    mBytesWritten += mAudioTrack.write(mByteArray, 0, mBytesToWrite);

                }
            }
            catch (IOException e){
                // log
            }                
        }   
    }
}

人為的に長いラグを乗り越えることができれば、後で予測可能な位置で書き込みを開始することで、継承レイテンシーに簡単に対処できます (つまり、ファイルの再生を開始するときに最小バッファー長をスキップします)。

4

2 に答える 2

2

PCM データを読み取るために、BufferedInputStream の代わりに RandomAccessFile を使用していましたが、同様の問題に遭遇しました。問題は、ファイル I/O が遅すぎることでした。オーディオ処理と同じスレッドで I/O が行われているため、バッファリングされたストリームでもこの問題が発生すると思われます。

解決策は、2 つのスレッドを用意することです。1 つはファイルからバッファを読み取ってメモリにキューに入れるスレッドで、もう 1 つはこのキューから読み取ってオーディオ ハードウェアに書き込むスレッドです。これを実現するために ConcurrentLinkedQueue を使用しました。

AudioRecord を使用して録音にも同じ手法を使用しましたが、逆方向に使用しました。重要なのは、ファイル I/O を別のスレッドに配置することです。

于 2011-08-22T16:16:30.810 に答える
1

これに答えるパーティーに少し遅れましたが、将来誰かに役立つ場合に備えて、AudioTrackが作成されて再生されるように設定されているが、すぐに。

書き込みを開始する直前にAudioTrackを作成すると、遅延がなくなることがわかりました。何らかの理由で、AudioTrackは空のバッファを持って座っているのが好きではないようです。

上記のコードに関して、あなたは次のようなことをしたいと思うでしょう

mAudioTrack=null;
while (mRun) 
{ 

    // This flag is turned on when the user presses "play" 
    while (mPlaying) 
    { 

        try 
        { 
            if (mAudioTrack==null) {   
                mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, ConfigManager.SAMPLE_RATE,AudioFormat.CHANNEL_CONFIGURATION_STEREO, AudioFormat.ENCODING_PCM_16BIT,ConfigManager.AUDIO_BUFFER_LENGTH,AudioTrack.MODE_STREAM);   
                mAudioTrack.play();   
            }
            // Rest of the playback code here
        }
    }
    mAudioTrack=null;
}
于 2012-06-06T07:27:41.903 に答える