2011-03-13 17 views
10

Estoy reproduciendo WAV en mi teléfono Android cargando el archivo y alimentando los bytes en AudioTrack.write() a través del método FileInputStream> BufferedInputStream> DataInputStream. El audio funciona bien y, cuando lo hace, puedo ajustar fácilmente la frecuencia de muestreo, el volumen, etc. sobre la marcha con un buen rendimiento. Sin embargo, tomará unos dos segundos completos para que una pista comience a reproducirse. Sé que AudioTrack tiene un retraso ineludible, pero esto es ridículo. Cada vez que juego una pista, me sale esto:Retraso de audio: obtener el tiempo de espera agotado

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 

me he dado cuenta que el recuento de escritura demorada se incrementa en uno cada vez que juegan una pista - incluso a través de múltiples sesiones - desde el momento en que el teléfono tiene encendido. El tiempo de bloqueo siempre es de 230 a 240 ms, lo cual tiene sentido considerando un tamaño mínimo de buffer de 9600 en este dispositivo (9600/44100). He visto este mensaje en innumerables búsquedas en Internet, pero por lo general parece estar relacionado con la falta de reproducción del audio o la omisión del audio. En mi caso, es solo un comienzo retrasado.

Estoy ejecutando todo mi código con un hilo de alta prioridad. Aquí hay una versión truncada pero funcional de lo que estoy haciendo. Esta es la devolución de llamada del hilo en mi clase de reproducción. De nuevo, esto funciona (solo reproduce archivos estéreo de 16 bits, 44.1kHz en este momento), solo toma una eternidad comenzar y tiene ese mensaje getBuffer/demora de escritura cada vez.

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 
      }     
     } 
    } 
} 

Si puedo conseguir más allá del artificialmente largo intervalo, puedo tratar fácilmente con la latencia hereda iniciando mi escritura en una posición más tarde, predecible (es decir, pasar de largo la longitud del búfer mínimo cuando empieza a reproducir un archivo)

+1

Tengo un problema similar en el momento. ¿Encontraste alguna solución? – sunside

+1

todavía no, lamentablemente. :/ – BTR

Respuesta

2

Me encontré con un problema similar, aunque estaba usando un RandomAccessFile, en lugar de un BufferedInputStream, para leer los datos de PCM. El problema era que el archivo de E/S era demasiado lento. Sospecho que tendrá este problema incluso con una transmisión en búfer, porque la E/S todavía se está llevando a cabo en el mismo hilo que el procesamiento de audio.

La solución es tener dos hilos: un hilo que lee los búferes de un archivo y los pone en cola en la memoria, y otro hilo que lee de esta cola y escribe en el hardware de audio. Usé una ConcurrentLinkedQueue para lograr esto.

Utilicé la misma técnica para grabar, usando AudioRecord, pero en la dirección inversa. La clave es colocar el archivo de E/S en un hilo separado.

+0

¡Gracias! Este proyecto ha estado en pausa esperando una solución. Voy a probar esto. – BTR

1

Llegué un poco tarde a la fiesta respondiendo esto, pero en caso de que ayude a alguien en el futuro, encontré este problema exacto con un código bastante similar al código en la pregunta, donde AudioTrack se creó y se configuró para reproducir, pero no escrito de inmediato.

Descubrí que la creación del AudioTrack inmediatamente antes de comenzar a escribir hacía que la demora desapareciera. Por alguna razón, a AudioTrack no parece gustarle sentarse con un búfer vacío.

En términos del código anterior, que querría hacer algo así

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; 
} 
Cuestiones relacionadas