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