AudioTrack lag: obtenhaBuffer excedeu o tempo limite
Estou reproduzindo WAVs no meu telefone Android carregando o arquivo e alimentando os bytes em AudioTrack.write () por meio do método FileInputStream> BufferedInputStream> DataInputStream. O áudio toca bem e, quando é, posso ajustar facilmente a taxa de amostragem, o volume etc. em tempo real com um bom desempenho. No entanto, leva cerca de dois segundos completos para uma faixa começar a tocar. Eu sei que o AudioTrack tem um atraso inevitável, mas isso é ridículo. Toda vez que toco uma faixa, recebo o seguinte:
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
Percebi que a contagem de gravações atrasadas aumenta em um toda vez que reproduzo uma faixa - mesmo em várias sessões - desde o momento em que o telefone foi ligado. O tempo de bloqueio é sempre de 230 a 240ms, o que faz sentido considerando um tamanho mínimo de buffer de 9600 neste dispositivo (9600/44100). Eu já vi essa mensagem em inúmeras pesquisas na Internet, mas geralmente parece estar relacionada a não reproduzir áudio ou ignorar o áudio. No meu caso, é apenas um início atrasado.
Estou executando todo o meu código em um thread de alta prioridade. Aqui está uma versão truncada e funcional do que estou fazendo. Este é o retorno de chamada do segmento na minha classe de reprodução. Novamente, isso funciona (apenas reproduzindo arquivos estéreo de 16 bits, 44,1kHz, no momento), leva apenas uma eternidade para iniciar e a obtenção de mensagem de buffer / gravação atrasada é sempre necessári
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
}
}
}
}
Se eu conseguir superar o atraso artificialmente longo, posso lidar facilmente com a latência herdada iniciando minha gravação em uma posição previsível mais tarde (ou seja, pule o tamanho mínimo do buffer ao iniciar a reprodução de um arquivo).