PDM Avanzado Captura de Audio
Introducion
Con esta clase podemos capturar audio ou vídeo.
Nesta sección imos aprender como capturar audio dende Android.
Se queredes saber como capturar vídeo accedendo ao hardware (a cámara) directamente, tedes que seguir a guía de Android onde se explica os pasos a seguir.
Lembrar que podemos facer a captura moito máis facilmente chamando cun Intent a aplicación da cámara do S.O. como veremos na seguinte sección da Wiki.
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);
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.
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:
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.
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.
Enlace a la página principal de la UD7
Enlace a la página principal del curso
-- Ángel D. Fernández González e Carlos Carrión Álvarez -- (2014).