Temas de audio y video de Android (2) Utilice AudioRecord y AudioTrack API para recopilar y reproducir datos PCM de audio en la plataforma Android y realizar la lectura y escritura de archivos wav de audio

1. Uso básico de AudioTrack

La clase AudioTrack puede completar la tarea de generar datos de audio en la plataforma Android. AudioTrack tiene dos modos de carga de datos (MODE_STREAM y MODE_STATIC), correspondientes al modo de carga de datos y al tipo de flujo de audio, correspondientes a dos escenarios de uso completamente diferentes.

  • MODE_STREAM: En este modo, los datos de audio se escriben en AudioTrack mediante escritura una y otra vez. Esto suele ser similar a escribir datos en un archivo a través de la llamada al sistema de escritura, pero esta forma de trabajar requiere copiar los datos del Buffer proporcionado por el usuario al Buffer dentro de AudioTrack cada vez, lo que introducirá un retraso hasta cierto punto. . Para resolver este problema, AudioTrack introdujo el segundo modo.
  • MODE_STATIC: En este modo, solo necesita transferir todos los datos al búfer interno en AudioTrack a través de una llamada de escritura antes de reproducir, y no necesita transferir datos en la siguiente. Este modo es adecuado para archivos con poca memoria y requisitos de alta latencia como tonos de llamada. Pero también tiene una desventaja, es decir, no puede escribir demasiados datos a la vez, de lo contrario, el sistema no puede asignar suficiente memoria para almacenar todos los datos.

1.1 modo MODE_STATIC

La forma de emitir audio en el modo MODE_STATIC es la siguiente ( Nota: si usa el modo ESTÁTICO, primero debe llamar a escribir para escribir datos y luego llamar a reproducir ):

Copiar codigo

La clase pública AudioTrackPlayerDemoActivity amplía la actividad implementa 
        OnClickListener { 

    Cadena final estática privada TAG = "AudioTrackPlayerDemoActivity"; 
    botón de botón privado; 
    byte privado [] audioData; 
    audioTrack privado de AudioTrack; 

    @Override 
    public void onCreate (Bundle SavedInstanceState) { 
        super.onCreate (SavedInstanceState); 
        super.setContentView (R.layout.main); 
        this.button = (Botón) super.findViewById (R.id.play); 
        this.button.setOnClickListener (esto); 
        this.button.setEnabled (falso); 
        new AsyncTask <Vacío, Vacío, Vacío> () { 
            @Override
            protegido Void doInBackground (Void ... params) {
                    }
                intente { 
                    InputStream in = getResources (). openRawResource (R.raw.ding); 
                    intente { 
                        ByteArrayOutputStream out = new ByteArrayOutputStream ( 
                                264848); 
                        for (int b; (b = in.read ())! = -1;) { 
                            out.write (b); 
                        } 
                        Log.d (TAG, "Obtuve los datos"); 
                        audioData = out.toByteArray (); 
                    } finalmente { 
                        in.close (); 
                } catch (IOException e) { 
                    Log.wtf (TAG, "No se pudo leer", e); 
                } 
                devuelve nulo; 
            } 

            @Override 
            protected void onPostExecute (Void v) { 
                Log.d (TAG, "Creando pista ..."); 
                button.setEnabled (verdadero); 
                Log.d (TAG, "Botón habilitado"); 
            } 
        } .execute (); 
    } 

    public void onClick (Ver vista) { 
        this.button.setEnabled (false); 
        this.releaseAudioTrack (); 
        this.audioTrack = new AudioTrack (AudioManager.STREAM_MUSIC, 44100, 
                AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT,
                audioData.length, AudioTrack.MODE_STATIC); 
        Log.d (TAG, "Escribiendo datos de audio ...");
        this.audioTrack.write (audioData, 0, audioData.length); 
        Log.d (TAG, "Iniciar reproducción"); 
        audioTrack.play (); 
        Log.d (TAG, "Reproducción"); 
        this.button.setEnabled (verdadero); 
    } 

    private void releaseAudioTrack () { 
        if (this.audioTrack! = null) { 
            Log.d (TAG, "Deteniendo"); 
            audioTrack.stop (); 
            Log.d (TAG, "Liberación"); 
            audioTrack.release (); 
            Log.d (TAG, "Anulación"); 
        } 
    } 

    public void onPause () { 
        super.onPause ();
        this.releaseAudioTrack (); 
    } 
}

Copiar codigo

1.2 modo MODE_STREAM

La forma de emitir audio en el modo MODE_STREAM es la siguiente:

Copiar codigo

byte [] tempBuffer = nuevo byte [bufferSize]; 
int readCount = 0; 
while (dis.available ()> 0) { 
    readCount = dis.read (tempBuffer); 
    if (readCount == AudioTrack.ERROR_INVALID_OPERATION || readCount == AudioTrack.ERROR_BAD_VALUE) { 
        continuar; 
    } 
    if (readCount! = 0 && readCount! = -1) { 
        audioTrack.play (); 
        audioTrack.write (tempBuffer, 0, readCount); 
    } 

Copiar codigo

En segundo lugar, AudioTrack detallado

 2.1 Tipos de transmisiones de audio

En el constructor AudioTrack, se expondrá el parámetro AudioManager.STREAM_MUSIC. Su significado está relacionado con la gestión y clasificación de las transmisiones de audio por parte del sistema Android.

Android divide el sonido del sistema en varios tipos de transmisión, los siguientes son algunos de los más comunes:

· STREAM_ALARM: sonido de advertencia

· STREAM_MUSIC: sonidos musicales, como música, etc.

· STREAM_RING: tono de llamada

· STREAM_SYSTEM: sonidos del sistema, como el aviso de batería baja, el sonido de la pantalla de bloqueo, etc.

· STREAM_VOCIE_CALL: sonido de llamada

Nota: Los tipos de divisiones anteriores no tienen nada que ver con los datos de audio en sí. Por ejemplo, los tipos MUSIC y RING pueden ser una determinada canción MP3. Además, no existe un estándar fijo para la selección del tipo de flujo de sonido. Por ejemplo, el tono de llamada en la vista previa del tono de llamada se puede establecer en el tipo de MÚSICA. La división de los tipos de flujo de audio está relacionada con la estrategia de gestión de audio del sistema de audio.

 

2.2 Asignación de búfer y el concepto de marco

Al calcular el tamaño de la asignación de búfer, un método que usamos a menudo es: getMinBufferSize. Esta función determina la cantidad de búfer de datos que asigna la capa de aplicación.

AudioTrack.getMinBufferSize (8000, // 8K puntos de muestreo por segundo                               
        AudioFormat.CHANNEL_CONFIGURATION_STEREO, // AudioFormat.ENCODING_PCM_16BIT de doble canal                   
        );

A partir de AudioTrack.getMinBufferSize para rastrear el código, puede encontrar que hay un concepto muy importante en el código subyacente: Frame. El marco es una unidad que se utiliza para describir la cantidad de datos. Una unidad de trama es igual a la cantidad de bytes de un punto de muestra × la cantidad de canales (por ejemplo, PCM16, una trama de dos canales es igual a 2 × 2 = 4 bytes). Un punto de muestreo es solo para un canal, pero de hecho puede haber uno o más canales. Dado que no se puede utilizar una unidad independiente para representar la cantidad de datos muestreados a la vez para todos los canales, se introduce el concepto de trama. El tamaño de la trama es el número de bytes de un punto de muestreo × el número de canales. Además, en el controlador de la tarjeta de sonido actual, su búfer interno también se asigna y administra utilizando Frame como una unidad.

El siguiente es el método que se remonta a la capa nativa:

Copiar codigo

// minBufCount representa el número mínimo de búferes, usa Frame como unidad 
   uint32_t minBufCount = afLatency / ((1000 * afFrameCount) / afSamplingRate); 
    if (minBufCount <2) minBufCount = 2; // Se requieren al menos dos búferes 
 
   / / Calcular el número mínimo de fotogramas 
   uint32_tminFrameCount =                
         (afFrameCount * sampleRateInHertz * minBufCount) / afSamplingRate; 
  // A continuación se calcula el tamaño mínimo del búfer basado en el FrameCount más pequeño    
   intminBuffSize = minFrameCount // El método de cálculo está totalmente en línea con nuestra introducción anterior a Cuadro 
           * (audioFormat == javaAudioTrackFields .PCM16? 2: 1) 
           * nbChannels; 
 
    returnminBuffSize;

Copiar codigo

getMinBufSize considerará exhaustivamente la situación del hardware (por ejemplo, si la frecuencia de muestreo es compatible, el retraso del hardware en sí, etc.) para llegar a un tamaño de búfer mínimo. Generalmente, el tamaño del búfer que asignamos será un múltiplo entero.

2.3 Proceso de construcción de AudioTrack

Cada secuencia de audio corresponde a una instancia de la clase AudioTrack. Cada AudioTrack se registrará en AudioFlinger cuando se cree, y AudioFlinger mezclará todas las AudioTracks (Mixer) y luego las enviará a AudioHardware para su reproducción. En la actualidad, Android puede en la mayoría al mismo tiempo Cree 32 secuencias de audio, es decir, Mixer procesará hasta 32 secuencias de datos AudioTrack al mismo tiempo. 

3. Comparación entre AudioTrack y MediaPlayer

Para reproducir sonidos, puede utilizar MediaPlayer y AudioTrack, los cuales proporcionan la API de Java para que los utilicen los desarrolladores de aplicaciones. Aunque ambos pueden reproducir sonidos, todavía existe una gran diferencia entre los dos.

3.1 Diferencia

La mayor diferencia es que MediaPlayer puede reproducir archivos de sonido en múltiples formatos, como MP3, AAC, WAV, OGG, MIDI, etc. MediaPlayer creará el decodificador de audio correspondiente en la capa de marco. AudioTrack solo puede reproducir transmisiones PCM decodificadas. Si compara los formatos de archivo admitidos, AudioTrack solo admite archivos de audio en formato wav, porque la mayoría de los archivos de audio en formato wav son transmisiones PCM. AudioTrack no crea un decodificador, por lo que solo puede reproducir archivos wav que no necesitan ser decodificados.

3.2 Contacto

MediaPlayer seguirá creando AudioTrack en la capa de marco, pasará la secuencia PCM decodificada a AudioTrack y luego la pasará a AudioFlinger para su mezcla y luego la pasará al hardware para su reproducción, por lo que MediaPlayer incluye AudioTrack.

3.3 Piscina de sonido

Cuando me comuniqué con la API de reproducción de audio de Android, descubrí que SoundPool también se puede usar para reproducir audio. Los siguientes son los escenarios de uso de los tres: MediaPlayer es más adecuado para reproducir archivos de música locales o recursos de transmisión en línea durante mucho tiempo en segundo plano; SoundPool es adecuado para reproducir clips de audio relativamente cortos, como sonidos de juegos, sonidos de botones, tonos de llamada , etc., puede reproducir múltiples audios al mismo tiempo; AudioTrack está más cerca de la capa inferior, proporciona capacidades de control muy poderosas, admite reproducción de baja latencia y es adecuado para escenarios como transmisión de medios y llamadas de voz VoIP.

Cuarto, el código fuente 

https://github.com/renhui/AudioDemo 

Supongo que te gusta

Origin blog.csdn.net/xfb1989/article/details/113348396
Recomendado
Clasificación