PDM Avanzado Captura de Audio

De MediaWiki
Saltar a: navegación, buscar

Introducion

Nesta parte imos aprender como capturar audio dende Android.

A clase que imos utilizar é a Clase MediaRecorder.

Podedes ver os formatos de audio soportados en: http://developer.android.com/guide/appendix/media-formats.html

Nota: Poderíamos usar a clase AudioRecord pero como non imos procesar e analizar o audio capturado e polo tanto non a usaremos.


Para facelo necesitaremos engadir unha serie de permisos ao arquivo AndroidManifiest.xml.

  • Permiso para capturar audio.
  1.     <uses-permission android:name="android.permission.RECORD_AUDIO"/>


  • Permiso para gardar o audio capturado na tarxeta SD.
  1.     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>


IMPORTANTE: A partires da API 23 (Android 6), Android incorpora outro nivel de seguridade, de tal forma que agora, a maiores, teremos que solicitar dito permiso a nivel de programación. Máis información de como facelo neste enlace.

Clase MediaRecorder

Os pasos que temos que dar para capturar audio son os seguintes:

  • Crear un obxecto da clase MediaRecorder.
  1.  private MediaRecorder mediaRecorder;
  2.  ...........
  3.  mediaRecorder = new MediaRecorder();
  • Establecer de onde vén a fonte de audio. O normal é que sexa do MIC da cámara web. Isto se fai chamando ó método setAudioSource(fonte) onde fonte é unha constante que atopades en MediaRecorder.AudioSource.XXXXX.
  1. mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
  • Establecer o formato de saída, chamando ó método setOutputFormat(formato) onde formato é unha constante que se atopa en MediaRecorder.OutputFormat.XXX
  1. mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
PDM Avanzada Multimedia Reprod 10.jpg
Imaxe obtida de http://developer.android.com/guide/appendix/media-formats.html

A columna de Supported File Type indica o formato de saída. No noso caso usaremos MediaRecorder.OutputFormat.TREE_GPP.


  • Optativo: Establecer o tempo máximo de gravación chamando o método setMaxDuration(int mseg) do obxecto MediaRecorder.

Nos imos poñer 10000 (10 segundos).

  1. mediaRecorder.setMaxDuration(10000);
  • Optativo: Indicar a tasa de bit´s, chamando ó método setAudioEncodingBitRate(int valor).

Os permitidos o tedes no na imaxe anterior.

Nota: A cantidade de bit´s vai establecer a calidade do audio capturado.

Algúns valores típicos:

  • Tasas de bits de compresión a MP3:
4 kbit/s Mínimo para recoñecer a fala.
8 kbit/s Calidade telefónica convencional
32 kbit/s Radio AM
96 kbit/s Radio FM
128 kbit/s Son calidade semi CD, muy común en MP3
192 kbit/s Son calidade CD en formato MP3
320 kbit/s Máxima calidade para formato MP3

Nos imos probar con 32 * 1024 = 32768

  1. mediaRecorder.setAudioEncodingBitRate(32768);
  • Optativo: Indicar a frecuencia de muestreo, chamando ó método setAudioSamplingRate(int valor).

ATENCION: No emulador este valor non pode ser superior a 8000.

PDM Avanzada Multimedia Reprod 11.jpg

Máis información: http://es.wikipedia.org/wiki/Frecuencia_de_muestreo

Un exemplo, no caso de calidade CD o simplerate é de 44,1Khz. No noso caso o valor estará limitado pola táboa de formatos de audio. Por exemplo AAC está limitado entre 8Khz e 96Khz, AMR_NB só a 8Khz e AMR_WB a 16Khz.

Nos imos probar con 8000 (8Khz) pola limitación do emulador.

  1. mediaRecorder.setAudioSamplingRate(8000); // No emulador só 8000


  • Indicar a codificación de audio utilizada chamando ó método setAudioEncoder(método) onde método é unha constante que se atopa en MediaRecorder.AudioEncoder.XXX.

No noso caso imos utilizar MediaRecorder.AudioEncoder.AAC.

  1. mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
  • Indicar o arquivo a gravar, indicando a ruta nome e extensión do arquivo, chamando ó método setOutputFile(arquivogravar).

Aquí temos varias posibilidades. Unha delas é darlle coma valor un String no que vai a ruta e o nome de arquivo e extensión. A ruta será algún cartafol da SDCARD. Para obter esa ruta faremos uso da clase Environment.

Para saber onde gardar o arquivo tedes que facer uso da clase Environment: http://developer.android.com/reference/android/os/Environment.html

Exemplos:

  1. Environment.getExternalStorageDirectory().getAbsolutePath()
Con isto obtemos a ruta a SDCARD (raíz).
  1. String state = Environment.getExternalStorageState();
  2. if(!state.equals(Environment.MEDIA_MOUNTED)){
  3. // A TARXETA NON ESTA MONTADA
  4. }
Con isto sabemos se a tarxeta SD está montada.


Nota: Tamén podemos crear a ruta na SDCARD, facendo uso de obxectos da clase File, ou comprobando se existe o cartafol. O veremos máis adiante.

  1. private String arquivoGravar;
  2. ................
  3. String timeStamp = DateFormat.getDateTimeInstance().format(new Date()).replaceAll(":", "").replaceAll("/", "_") .replaceAll(" ", "_");
  4.  
  5. arquivoGravar = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC) + timeStamp + ".3gp";
  6.  
  7. mediaRecorder.setOutputFile(arquivoGravar);

Neste exemplo creamos un nome para o arquivo gravado baseado na data-hora e o vai gardar no cartafol da SD Externa que o S.O. reserva para gardar música.


  • Chamar ó método prepare(). Pode producir excepcións (debe ir con try...catch).
  1. mediaRecorder.prepare();


  • Chamar ó método start().
  1. mediaRecorder.start();


Neste intre se procede a gravar no cartafol indicado. A gravación non parará ata que chamemos ó método stop do MediaRecorder ou se acade o tempo máximo de gravación.


É importante seguir a orden, xa que por exemplo, a chamada a setAudioEncoder non pode ir antes de setOutputFormat (mirade o diagrama de estados seguinte). Ó igual que o MediaPlayer, o MediaRecorder ten un diagrama de estados que xa non debería ter dificultade en entenderse:

PDM Avanzada Multimedia Reprod 12.jpg
Imaxe obtido de http://developer.android.com/reference/android/media/MediaRecorder.html


Cando rematemos de gravar (por tempo) ou se paramos nos premendo o botón correspondente se recomenda liberar os recursos do MediaRecorder.

O faremos así:

  • Chamando o método stop.
  • Chamando o método release.
  • Igualando a null o obxecto da clase MediaRecorder.

Tamén deberemos liberar os recursos se cambiamos de aplicación ou se a pechamos.

Caso práctico

O obxectivo desta práctica é gravar un arquivo de audio no cartafol da SD Externa reservado á música. Ó premer o botón Gravar amosaremos unha caixa de diálogo indicando que se está a gravar e o saír de dita caixa pararemos de gravar. Ó premer o botón Reproducir reproduciremos o arquivo gardado.

PDM Avanzada Multimedia Reprod 13.jpg

Creamos a Activity

  • Nome do proxecto: UD6_03_MultimediaGravador
  • Nome da activity: UD6_03_MultimediaGravador.java


Código do layout xml
Nota: Por motivos de tempo para o alumnado o deseño non fai uso de constantes externas definidas no cartafol values. Queda claro que esta debería ser a opción escollida para o deseño das Interfaces de Usuario.

  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2.    xmlns:tools="http://schemas.android.com/tools"
  3.    android:layout_width="match_parent"
  4.    android:layout_height="match_parent"
  5.    tools:context="${relativePackage}.${activityClass}" >
  6.  
  7.     <Button
  8.        android:id="@+id/UD6_03_btnGravar"
  9.        android:layout_width="wrap_content"
  10.        android:layout_height="wrap_content"
  11.        android:layout_alignParentTop="true"
  12.        android:layout_centerHorizontal="true"
  13.        android:text="GRAVAR AUDIO" />
  14.  
  15.     <Button
  16.        android:id="@+id/UD6_03_btnReproducir"
  17.        android:layout_width="wrap_content"
  18.        android:layout_height="wrap_content"
  19.        android:layout_below="@+id/UD6_03_btnGravar"
  20.        android:layout_centerHorizontal="true"
  21.        android:layout_marginTop="26dp"
  22.        android:text="REPRODUCIR AUDIO" />
  23. </RelativeLayout>


Código da clase UD6_03_MultimediaGravador
Obxectivo: Amosar como gravar un arquivo de audio.

  1. import java.io.File;
  2. import java.text.DateFormat;
  3. import java.util.Date;
  4.  
  5. import android.app.Activity;
  6. import android.app.AlertDialog;
  7. import android.content.DialogInterface;
  8. import android.media.AudioManager;
  9. import android.media.MediaPlayer;
  10. import android.media.MediaRecorder;
  11. import android.os.Bundle;
  12. import android.os.Environment;
  13. import android.view.View;
  14. import android.view.View.OnClickListener;
  15. import android.widget.Button;
  16. import android.widget.Toast;
  17.  
  18. public class UD6_03_MultimediaGravador extends Activity {
  19.  
  20.         private MediaRecorder mediaRecorder;
  21.         private String arquivoGravar;
  22.        
  23.        
  24.         private void abrirDialogo(String tipo){
  25.                 if (tipo == "GRAVAR") {
  26.                         AlertDialog.Builder dialog = new AlertDialog.Builder(this)
  27.                                         .setMessage("GRAVANDO").setPositiveButton(
  28.                                                         "PREME PARA PARAR",
  29.                                                         new DialogInterface.OnClickListener() {
  30.  
  31.                                                                 @Override
  32.                                                                 public void onClick(DialogInterface dialog,
  33.                                                                                 int which) {
  34.                                                                         // TODO Auto-generated method stub
  35.                                                                         mediaRecorder.stop();
  36.                                                                         mediaRecorder.release();
  37.                                                                         mediaRecorder = null;
  38.                                                                 }
  39.                                                         });
  40.                         dialog.show();
  41.                 }              
  42.                
  43.                 if (tipo == "REPRODUCIR") {
  44.  
  45.                         if ((arquivoGravar==null) | arquivoGravar=="") return;
  46.                         File arquivo = new File(arquivoGravar);
  47.                         if (!arquivo.exists()) return;
  48.                        
  49.                         final MediaPlayer mediaPlayer = new MediaPlayer();
  50.                         try {
  51.                                 mediaPlayer.setDataSource(arquivoGravar);
  52.                                 mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
  53.                                 mediaPlayer.prepare();
  54.                                 mediaPlayer.start();
  55.                         } catch (Exception e) {
  56.                                 Toast.makeText(getApplicationContext(),
  57.                                                 "ERRO:" + e.getMessage(), Toast.LENGTH_LONG).show();
  58.                         }
  59.  
  60.                         AlertDialog.Builder dialog = new AlertDialog.Builder(this)
  61.                                         .setMessage("REPRODUCINDO").setPositiveButton(
  62.                                                         "PREME PARA PARAR",
  63.                                                         new DialogInterface.OnClickListener() {
  64.  
  65.                                                                 @Override
  66.                                                                 public void onClick(DialogInterface dialog,
  67.                                                                                 int which) {
  68.                                                                         // TODO Auto-generated method stub
  69.                                                                         mediaPlayer.stop();
  70.                                                                         mediaPlayer.release();
  71.                                                                 }
  72.                                                         });
  73.                         dialog.show();
  74.  
  75.                 }
  76.  
  77.         }
  78.        
  79.         private void xestionarEventos(){
  80.                
  81.                 Button btnGravar = (Button)findViewById(R.id.UD6_03_btnGravar);
  82.                 btnGravar.setOnClickListener(new OnClickListener() {
  83.                        
  84.                         @Override
  85.                         public void onClick(View v) {
  86.                                 // TODO Auto-generated method stub
  87.                                 String timeStamp = DateFormat.getDateTimeInstance().format(
  88.                                                 new Date()).replaceAll(":", "").replaceAll("/", "_")
  89.                                                 .replaceAll(" ", "_");
  90.  
  91.                                 mediaRecorder = new MediaRecorder();
  92.                                 arquivoGravar = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC) + timeStamp + ".3gp";
  93.                                 mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
  94.                                 mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
  95.                                 mediaRecorder.setMaxDuration(10000);
  96.                                 mediaRecorder.setAudioEncodingBitRate(32768);
  97.                                 mediaRecorder.setAudioSamplingRate(8000); // No emulador só 8000 coma
  98.                                 mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
  99.                                 mediaRecorder.setOutputFile(arquivoGravar);
  100.                                 try {
  101.                                         mediaRecorder.prepare();
  102.                                 } catch (Exception e) {
  103.                                 // TODO Auto-generated catch block
  104.                                         mediaRecorder.reset();
  105.                                 }
  106.                                 mediaRecorder.start();
  107.                                 abrirDialogo("GRAVAR");
  108.                        
  109.                                
  110.                         }
  111.                 });
  112.                
  113.                 Button btnReproducir = (Button)findViewById(R.id.UD6_03_btnReproducir);
  114.                 btnReproducir.setOnClickListener(new OnClickListener() {
  115.                        
  116.                         @Override
  117.                         public void onClick(View v) {
  118.                                 // TODO Auto-generated method stub
  119.                                 abrirDialogo("REPRODUCIR");
  120.                         }
  121.                 });
  122.                
  123.                
  124.         }
  125.        
  126.         @Override
  127.         protected void onCreate(Bundle savedInstanceState) {
  128.                 super.onCreate(savedInstanceState);
  129.                 setContentView(R.layout.activity_ud6_03__multimedia_gravador);
  130.                
  131.                 xestionarEventos();
  132.                
  133.         }
  134. }
  • Liña 20: Definimos o MediaRecorder.
  • Liña 21: Propiedade que garda o nome e ruta do arquivo gravado. Necesario para cando prememos o botón de reproducir.
  • Liñas 25-41: Diálogo que aparece cando prememos sobre o botón de Gravar. Se prememos o botón de Aceptar dentro do diálogo paramos de gravar e liberamos o MediaRecorder.
  • Liñas 43-75: Diálogo que aparece cando prememos sobre o botón de Reproducir. Xa visto no punto anterior desta Unidade Didáctica.
  • Liñas 91-107: Xestión do evento click sobre o botón de gravar. Preparamos o MediaRecorder e chamamos a abrir o diálogo de gravación.
  • Liñas 117-120: Xestión do evento click sobre o botón de reproducir. Abrimos o diálogo de Reproducir.





-- Ángel D. Fernández González e Carlos Carrión Álvarez -- (2014).