29 - Captura de audio mediante la clase MediaRecorder

Otra forma de grabar audio en Android es el empleo de la clase MediaRecorder. Esta clase nos da más libertades a la hora de construir una aplicación que requiere grabar audio.

Problema:

Crear un proyecto (Proyecto032)Disponer tres objetos de la clase Button con las etiquetas "Grabar", "Detener Grabación" y "Reproducir Grabación". Disponer además un TextView para informar del estado actual.

Cuando se presione el botón "Grabar" permitir registrar todos los sonidos hasta que se presione el botón "Detener Grabación". Cuando se presione el botón "Reproducir Grabación" emitir el archivo de audio previamente generado.

La interfaz visual a implementar es la siguiente:

grabar audio android MediaRecorder

También debemos modificar el archivo AndroidManifest.xml donde debemos indicar que nuestra aplicación accederá a la grabadora de sonido y a la tarjeta SD donde se almacenará el archivo de sonido.

Esto lo hacemos seleccionando el archivo AndroidManifest.xml y escribiendo los permisos respectivos:

grabar audio android MediaRecorder

El código fuente en Kotlin es:

package com.tutorialesprogramacionya.proyecto032

import android.media.MediaPlayer
import android.media.MediaRecorder
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.os.Environment
import kotlinx.android.synthetic.main.activity_main.*
import java.io.File
import java.io.IOException

class MainActivity : AppCompatActivity(), MediaPlayer.OnCompletionListener {
    lateinit var recorder: MediaRecorder
    lateinit var player: MediaPlayer
    lateinit var archivo: File

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        boton1.setOnClickListener {
            recorder = MediaRecorder()
            recorder.setAudioSource(MediaRecorder.AudioSource.MIC)
            recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP)
            recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB)
            val path = File(Environment.getExternalStorageDirectory()
                    .getPath())
            try {
                archivo = File.createTempFile("temporal", ".3gp", path)
            } catch (e: IOException) {
            }

            recorder.setOutputFile(archivo.absolutePath)
            try {
                recorder.prepare()
            } catch (e: IOException) {
            }

            recorder.start()
            tv1.text ="Grabando"
            boton1.setEnabled(false)
            boton2.setEnabled(true)
        }

        boton2.setOnClickListener {
            recorder.stop()
            recorder.release()
            player = MediaPlayer()
            player.setOnCompletionListener(this)
            try {
                player.setDataSource(archivo.absolutePath)
            } catch (e: IOException) {
            }

            try {
                player.prepare()
            } catch (e: IOException) {
            }

            boton1.setEnabled(true)
            boton2.setEnabled(false)
            boton3.setEnabled(true)
            tv1.text = "Listo para reproducir"
        }

        boton3.setOnClickListener {
            player.start();
            boton1.setEnabled(false);
            boton2.setEnabled(false);
            boton3.setEnabled(false);
            tv1.setText("Reproduciendo");
        }
    }

    override fun onCompletion(mp: MediaPlayer) {
        boton1.setEnabled(true)
        boton2.setEnabled(true)
        boton3.setEnabled(true)
        tv1.setText("Listo")
    }
}

Declaramos un objeto de la clase MediaRecorder para grabar audio:

    lateinit var recorder: MediaRecorder

Declaramos un objeto de la clase MediaPlayer para reproducir el archivo de sonido generado:

    lateinit var player: MediaPlayer

Declaramos un objeto de la clase File que hace referencia al archivo que se creará:

    lateinit var archivo: File

El método más importante de este concepto es el grabar:

        boton1.setOnClickListener {
            recorder = MediaRecorder()
            recorder.setAudioSource(MediaRecorder.AudioSource.MIC)
            recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP)
            recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB)
            val path = File(Environment.getExternalStorageDirectory()
                    .getPath())
            try {
                archivo = File.createTempFile("temporal", ".3gp", path)
            } catch (e: IOException) {
            }

            recorder.setOutputFile(archivo.absolutePath)
            try {
                recorder.prepare()
            } catch (e: IOException) {
            }

            recorder.start()
            tv1.text ="Grabando"
            boton1.setEnabled(false)
            boton2.setEnabled(true)
        }

Creamos un objeto de la clase MediaRecorder:

            recorder = MediaRecorder()

Seguidamente definimos el micrófono como fuente de audio:

            recorder.setAudioSource(MediaRecorder.AudioSource.MIC)

Luego llamamos al método setOutputFormat especificando que el archivo será almacenado con la especificación 3GPP y con extensión .3gp

            recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP)

Especificamos el codec a emplear llamando al método setAudioEncoder:

            recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB)

Obtenemos el path de la tarjeta SD y creamos un archivo temporal con extensión 3gp:

            val path = File(Environment.getExternalStorageDirectory()
                    .getPath())
            try {
                archivo = File.createTempFile("temporal", ".3gp", path)
            } catch (e: IOException) {
            }

Con el método setOutputFile de la clase MediaRecorder le indicamos el archivo donde debe almacenarse la grabación:

            recorder.setOutputFile(archivo.absolutePath)

Llamamos al método prepare y finalmente al método start para comenzar la grabación:

            recorder.setOutputFile(archivo.absolutePath)
            try {
                recorder.prepare()
            } catch (e: IOException) {
            }

La función lambda del segundo botón detiene la grabación:

        boton2.setOnClickListener {
            recorder.stop()
            recorder.release()
            player = MediaPlayer()
            player.setOnCompletionListener(this)
            try {
                player.setDataSource(archivo.absolutePath)
            } catch (e: IOException) {
            }

            try {
                player.prepare()
            } catch (e: IOException) {
            }

            boton1.setEnabled(true)
            boton2.setEnabled(false)
            boton3.setEnabled(true)
            tv1.text = "Listo para reproducir"
        }

Llamamos primero al método stop de la clase MediaRecorder y liberamos los recursos consumidos llamando a release:

            recorder.stop()
            recorder.release()

Creamos un objeto de la clase MediaPlayer para poder reproducir el archivo de audio que acabamos de grabar. Indicamos mediante el método setOnCompletionListener la referencia de la clase que será informada cuando el audio finalice:

            player = MediaPlayer()
            player.setOnCompletionListener(this)

Referenciamos el archivo a que debe reproducir:

            try {
                player.setDataSource(archivo.absolutePath)
            } catch (e: IOException) {
            }

Finalmente llamamos al método prepare de la clase MediaPlayer:

            try {
                player.prepare()
            } catch (e: IOException) {
            }

La función lambda para reproducir simplemente llama al método start de la clase MediaPlayer para iniciar la reproducción del archivo previamente grabado:

        boton3.setOnClickListener {
            player.start();
            boton1.setEnabled(false);
            boton2.setEnabled(false);
            boton3.setEnabled(false);
            tv1.setText("Reproduciendo");
        }

El método onCompletion se ejecuta cuando termina de reproducirse el archivo de audio:

    override fun onCompletion(mp: MediaPlayer) {
        boton1.setEnabled(true)
        boton2.setEnabled(true)
        boton3.setEnabled(true)
        tv1.setText("Listo")
    }

Este proyecto lo puede descargar en un zip desde este enlace: proyecto032.zip