PDM Avanzado Captura de Audio

De MediaWiki
Ir a la navegación Ir a la búsqueda

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).