Android多媒体学习七:调用Android自带的音频录制程序,实现录制

Android中有自带的音频录制程序,我们可以通过指定一个Action为MediaStore.Audio.Media.RECORD_SOUND_ACTION的Intent来

启动它就可以了。然后在onActivityResult()方法中,获取Intent的Data,就是录制的音频对应的URI。

 

代码:

 

  1. package demo.camera;  
  2. import android.app.Activity;  
  3. import android.content.Intent;  
  4. import android.net.Uri;  
  5. import android.os.Bundle;  
  6. import android.provider.MediaStore;  
  7. import android.view.View;  
  8. import android.widget.Toast;  
  9. /** 
  10.  * 被实例演示如何调用Android自带的应用来完成Audio的录入 
  11.  * 其实很简单,我们需要指定一个MediaStore.Audio.Media.RECORD_SOUND_ACTION的Action来启动就可以 
  12.  * 返回的Data数据就是我们录制的音频的URI了 
  13.  *  
  14.  * 通过上面这种方式,灵活性不够高,我们可以利用MediaRecorder类来实现自己的音频录制程序 
  15.  * MediaRecorder既可以用来录制音频,也可以用来录制视频 
  16.  * 创建了一个MediaRecorder实例后,需要调用setAudioSource和setAudioEncoder来初始化 
  17.  * 通常情况下,在准备录制前,我们还需要调用setOutputFormat()方法来决定使用的音频格式,同时调用 
  18.  * setOutputFile()来指定存放录制内容的文件 
  19.  *  
  20.  * 这几个方法的调用顺序是:setAudioSource,setOutputFormat,setAudioEncoder,setOutputFile 
  21.  *  
  22.  *  
  23.  *  
  24.  * @author Administrator 
  25.  * 
  26.  */  
  27. public class AudioRecordDemo extends Activity {  
  28.       
  29.       
  30.     public void onCreate(Bundle savedInstanceState){  
  31.         super.onCreate(savedInstanceState);  
  32.         setContentView(R.layout.audio_record);  
  33.     }  
  34.       
  35.     public void onActivityResult(int requestCode, int resultCode, Intent data){  
  36.         //super.onActivityResult(requestCode, resultCode, data);  
  37.         //这里我们就可以获取到刚刚录制的音频的Uri,可以进行播放等操作,这里显示返回的Uri  
  38.         if(resultCode == RESULT_OK){  
  39.             Uri audioPath = data.getData();  
  40.             Toast.makeText(this, audioPath.toString(), Toast.LENGTH_LONG).show();  
  41.         }  
  42.     }  
  43.       
  44.     public void onClick(View v){  
  45.         int id = v.getId();  
  46.         switch(id){  
  47.         case R.id.btn1:  
  48.             //调用Android自带的音频录制应用  
  49.             Intent intent = new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION);  
  50.             startActivityForResult(intent, 0);  
  51.             break;  
  52.         case R.id.btn2:  
  53.             //通过MediaRecorder类来实现自己的音频录制程序  
  54.             Intent intent2 = new Intent();  
  55.             intent2.setClass(this, MyAudioRecord.class);  
  56.             startActivityForResult(intent2, 1);  
  57.             break;  
  58.         case R.id.btn3:  
  59.             //通过AudioRecord类实现自己的音频录制程序  
  60.             Intent intent3 = new Intent();  
  61.             intent3.setClass(this, MyAudioRecord2.class);  
  62.             startActivityForResult(intent3, 2);  
  63.             break;  
  64.         }  
  65.     }  

  1. package demo.camera;  
  2. import java.io.File;  
  3. import java.io.IOException;  
  4. import android.app.Activity;  
  5. import android.content.ContentValues;  
  6. import android.content.Intent;  
  7. import android.media.MediaPlayer;  
  8. import android.media.MediaRecorder;  
  9. import android.net.Uri;  
  10. import android.os.Bundle;  
  11. import android.os.Environment;  
  12. import android.provider.MediaStore;  
  13. import android.view.View;  
  14. import android.widget.Button;  
  15. import android.widget.TextView;  
  16. /** 
  17.  * 这个是利用MediaRecorder类来实现自己的音频录制程序 
  18.  *  
  19.  * 为了可以录制音频我们需要RECORD_AUDIO权限 
  20.  * 为了可以写入SDCard,我们需要WRITE_EXTERNAL_STORAGE权限 
  21.  * @author Administrator 
  22.  * 
  23.  */  
  24. public class MyAudioRecord extends Activity {  
  25.       
  26.     private TextView stateView;  
  27.       
  28.     private Button btnStart,btnStop,btnPlay,btnFinish;  
  29.       
  30.     private MediaRecorder recorder;  
  31.       
  32.     private MediaPlayer player;  
  33.       
  34.     private File audioFile;  
  35.       
  36.     private Uri fileUri;  
  37.       
  38.     public void onCreate(Bundle savedInstanceState){  
  39.         super.onCreate(savedInstanceState);  
  40.         setContentView(R.layout.my_audio_record);  
  41.           
  42.         stateView = (TextView)this.findViewById(R.id.view_state);  
  43.         stateView.setText("准备开始");  
  44.         btnStart = (Button)this.findViewById(R.id.btn_start);  
  45.         btnStop = (Button)this.findViewById(R.id.btn_stop);  
  46.         btnPlay = (Button)this.findViewById(R.id.btn_play);  
  47.         btnFinish = (Button)this.findViewById(R.id.btn_finish);  
  48.           
  49.         btnStop.setEnabled(false);  
  50.         btnPlay.setEnabled(false);  
  51.           
  52.     }  
  53.       
  54.       
  55.     public void onClick(View v){  
  56.         int id = v.getId();  
  57.         switch(id){  
  58.         case R.id.btn_start:  
  59.             //开始录制  
  60.             //我们需要实例化一个MediaRecorder对象,然后进行相应的设置  
  61.             recorder = new MediaRecorder();  
  62.             //指定AudioSource 为MIC(Microphone audio source ),这是最长用的  
  63.             recorder.setAudioSource(MediaRecorder.AudioSource.MIC);  
  64.             //指定OutputFormat,我们选择3gp格式  
  65.             //其他格式,MPEG-4:这将指定录制的文件为mpeg-4格式,可以保护Audio和Video  
  66.             //RAW_AMR:录制原始文件,这只支持音频录制,同时要求音频编码为AMR_NB  
  67.             //THREE_GPP:录制后文件是一个3gp文件,支持音频和视频录制  
  68.             recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);  
  69.             //指定Audio编码方式,目前只有AMR_NB格式  
  70.             recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);  
  71.             //接下来我们需要指定录制后文件的存储路径  
  72.             File fpath = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/data/files/");  
  73.             fpath.mkdirs();//创建文件夹  
  74.             try {  
  75.                 //创建临时文件  
  76.                 audioFile = File.createTempFile("recording"".3gp", fpath);  
  77.             } catch (IOException e) {  
  78.                 // TODO Auto-generated catch block  
  79.                 e.printStackTrace();  
  80.             }  
  81.               
  82.             recorder.setOutputFile(audioFile.getAbsolutePath());  
  83.               
  84.             //下面就开始录制了  
  85.             try {  
  86.                 recorder.prepare();  
  87.             } catch (IllegalStateException e) {  
  88.                 // TODO Auto-generated catch block  
  89.                 e.printStackTrace();  
  90.             } catch (IOException e) {  
  91.                 // TODO Auto-generated catch block  
  92.                 e.printStackTrace();  
  93.             }  
  94.               
  95.             recorder.start();  
  96.               
  97.             stateView.setText("正在录制");  
  98.             btnStart.setEnabled(false);  
  99.             btnPlay.setEnabled(false);  
  100.             btnStop.setEnabled(true);  
  101.               
  102.             break;  
  103.         case R.id.btn_stop:  
  104.             recorder.stop();  
  105.             recorder.release();  
  106.               
  107.             //然后我们可以将我们的录制文件存储到MediaStore中  
  108.             ContentValues values = new ContentValues();  
  109.             values.put(MediaStore.Audio.Media.TITLE, "this is my first record-audio");  
  110.             values.put(MediaStore.Audio.Media.DATE_ADDED, System.currentTimeMillis());  
  111.             values.put(MediaStore.Audio.Media.DATA, audioFile.getAbsolutePath());  
  112.             fileUri = this.getContentResolver().insert(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, values);  
  113.             //录制结束后,我们实例化一个MediaPlayer对象,然后准备播放  
  114.             player = new MediaPlayer();  
  115.             player.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {  
  116.                   
  117.                 @Override  
  118.                 public void onCompletion(MediaPlayer arg0) {  
  119.                     //更新状态  
  120.                     stateView.setText("准备录制");  
  121.                     btnPlay.setEnabled(true);  
  122.                     btnStart.setEnabled(true);  
  123.                     btnStop.setEnabled(false);  
  124.                 }  
  125.             });  
  126.               
  127.             //准备播放  
  128.             try {  
  129.                 player.setDataSource(audioFile.getAbsolutePath());  
  130.                 player.prepare();  
  131.             } catch (IllegalArgumentException e) {  
  132.                 // TODO Auto-generated catch block  
  133.                 e.printStackTrace();  
  134.             } catch (IllegalStateException e) {  
  135.                 // TODO Auto-generated catch block  
  136.                 e.printStackTrace();  
  137.             } catch (IOException e) {  
  138.                 // TODO Auto-generated catch block  
  139.                 e.printStackTrace();  
  140.             }  
  141.               
  142.             //更新状态  
  143.             stateView.setText("准备播放");  
  144.             btnPlay.setEnabled(true);  
  145.             btnStart.setEnabled(true);  
  146.             btnStop.setEnabled(false);  
  147.             break;  
  148.         case R.id.btn_play:  
  149.             //播放录音  
  150.             //注意,我们在录音结束的时候,已经实例化了MediaPlayer,做好了播放的准备  
  151.             player.start();  
  152.             //更新状态  
  153.             stateView.setText("正在播放");  
  154.             btnStart.setEnabled(false);  
  155.             btnStop.setEnabled(false);  
  156.             btnPlay.setEnabled(false);  
  157.               
  158.             //在播放结束的时候也要更新状态  
  159.             break;  
  160.         case R.id.btn_finish:  
  161.             //完成录制,返回录制的音频的Uri  
  162.             Intent intent = new Intent();  
  163.             intent.setData(fileUri);  
  164.             this.setResult(RESULT_OK, intent);  
  165.             this.finish();  
  166.             break;  
  167.               
  168.         }  
  169.     }  

AudioRecord类相对于MediaRecorder来说,更加接近底层,为我们封装的方法也更少。然而实现一个AudioRecord的音频录制程序也很

简单。本实例代码如下:

 

可惜,本实例测试时有个问题,在录制的时候,会出现buffer over。缓存泄露,待解决。

 

 

  1. package demo.camera;  
  2. import java.io.BufferedInputStream;  
  3. import java.io.BufferedOutputStream;  
  4. import java.io.DataInputStream;  
  5. import java.io.DataOutputStream;  
  6. import java.io.File;  
  7. import java.io.FileInputStream;  
  8. import java.io.FileOutputStream;  
  9. import java.io.IOException;  
  10. import android.app.Activity;  
  11. import android.content.ContentValues;  
  12. import android.content.Intent;  
  13. import android.hardware.Camera.AutoFocusCallback;  
  14. import android.media.AudioFormat;  
  15. import android.media.AudioManager;  
  16. import android.media.AudioRecord;  
  17. import android.media.AudioTrack;  
  18. import android.media.MediaPlayer;  
  19. import android.media.MediaRecorder;  
  20. import android.net.Uri;  
  21. import android.os.AsyncTask;  
  22. import android.os.Bundle;  
  23. import android.os.Environment;  
  24. import android.provider.MediaStore;  
  25. import android.util.Log;  
  26. import android.view.View;  
  27. import android.widget.Button;  
  28. import android.widget.TextView;  
  29. /** 
  30.  * 该实例中,我们使用AudioRecord类来完成我们的音频录制程序 
  31.  * AudioRecord类,我们可以使用三种不同的read方法来完成录制工作, 
  32.  * 每种方法都有其实用的场合 
  33.  * 一、实例化一个AudioRecord类我们需要传入几种参数 
  34.  * 1、AudioSource:这里可以是MediaRecorder.AudioSource.MIC 
  35.  * 2、SampleRateInHz:录制频率,可以为8000hz或者11025hz等,不同的硬件设备这个值不同 
  36.  * 3、ChannelConfig:录制通道,可以为AudioFormat.CHANNEL_CONFIGURATION_MONO和AudioFormat.CHANNEL_CONFIGURATION_STEREO 
  37.  * 4、AudioFormat:录制编码格式,可以为AudioFormat.ENCODING_16BIT和8BIT,其中16BIT的仿真性比8BIT好,但是需要消耗更多的电量和存储空间 
  38.  * 5、BufferSize:录制缓冲大小:可以通过getMinBufferSize来获取 
  39.  * 这样我们就可以实例化一个AudioRecord对象了 
  40.  * 二、创建一个文件,用于保存录制的内容 
  41.  * 同上篇 
  42.  * 三、打开一个输出流,指向创建的文件 
  43.  * DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file))) 
  44.  * 四、现在就可以开始录制了,我们需要创建一个字节数组来存储从AudioRecorder中返回的音频数据,但是 
  45.  * 注意,我们定义的数组要小于定义AudioRecord时指定的那个BufferSize 
  46.  * short[]buffer = new short[BufferSize/4]; 
  47.  * startRecording(); 
  48.  * 然后一个循环,调用AudioRecord的read方法实现读取 
  49.  * 另外使用MediaPlayer是无法播放使用AudioRecord录制的音频的,为了实现播放,我们需要 
  50.  * 使用AudioTrack类来实现 
  51.  * AudioTrack类允许我们播放原始的音频数据 
  52.  *  
  53.  *  
  54.  * 一、实例化一个AudioTrack同样要传入几个参数 
  55.  * 1、StreamType:在AudioManager中有几个常量,其中一个是STREAM_MUSIC; 
  56.  * 2、SampleRateInHz:最好和AudioRecord使用的是同一个值 
  57.  * 3、ChannelConfig:同上 
  58.  * 4、AudioFormat:同上 
  59.  * 5、BufferSize:通过AudioTrack的静态方法getMinBufferSize来获取 
  60.  * 6、Mode:可以是AudioTrack.MODE_STREAM和MODE_STATIC,关于这两种不同之处,可以查阅文档 
  61.  * 二、打开一个输入流,指向刚刚录制内容保存的文件,然后开始播放,边读取边播放 
  62.  *  
  63.  * 实现时,音频的录制和播放分别使用两个AsyncTask来完成  
  64.  */  
  65. public class MyAudioRecord2 extends Activity{  
  66.       
  67.     private TextView stateView;  
  68.       
  69.     private Button btnStart,btnStop,btnPlay,btnFinish;  
  70.       
  71.     private RecordTask recorder;  
  72.     private PlayTask player;  
  73.       
  74.     private File audioFile;  
  75.       
  76.     private boolean isRecording=true, isPlaying=false//标记  
  77.       
  78.     private int frequence = 8000//录制频率,单位hz.这里的值注意了,写的不好,可能实例化AudioRecord对象的时候,会出错。我开始写成11025就不行。这取决于硬件设备  
  79.     private int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;  
  80.     private int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;  
  81.       
  82.       
  83.     public void onCreate(Bundle savedInstanceState){  
  84.         super.onCreate(savedInstanceState);  
  85.         setContentView(R.layout.my_audio_record);  
  86.           
  87.         stateView = (TextView)this.findViewById(R.id.view_state);  
  88.         stateView.setText("准备开始");  
  89.         btnStart = (Button)this.findViewById(R.id.btn_start);  
  90.         btnStop = (Button)this.findViewById(R.id.btn_stop);  
  91.         btnPlay = (Button)this.findViewById(R.id.btn_play);  
  92.         btnFinish = (Button)this.findViewById(R.id.btn_finish);  
  93.         btnFinish.setText("停止播放");  
  94.         btnStop.setEnabled(false);  
  95.         btnPlay.setEnabled(false);  
  96.         btnFinish.setEnabled(false);  
  97.           
  98.         //在这里我们创建一个文件,用于保存录制内容  
  99.         File fpath = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/data/files/");  
  100.         fpath.mkdirs();//创建文件夹  
  101.         try {  
  102.             //创建临时文件,注意这里的格式为.pcm  
  103.             audioFile = File.createTempFile("recording"".pcm", fpath);  
  104.         } catch (IOException e) {  
  105.             // TODO Auto-generated catch block  
  106.             e.printStackTrace();  
  107.         }         
  108.     }  
  109.       
  110.       
  111.     public void onClick(View v){  
  112.         int id = v.getId();  
  113.         switch(id){  
  114.         case R.id.btn_start:  
  115.             //开始录制  
  116.               
  117.             //这里启动录制任务  
  118.             recorder = new RecordTask();  
  119.             recorder.execute();  
  120.               
  121.             break;  
  122.         case R.id.btn_stop:  
  123.             //停止录制  
  124.             this.isRecording = false;  
  125.             //更新状态  
  126.             //在录制完成时设置,在RecordTask的onPostExecute中完成  
  127.             break;  
  128.         case R.id.btn_play:  
  129.               
  130.             player = new PlayTask();  
  131.             player.execute();  
  132.             break;  
  133.         case R.id.btn_finish:  
  134.             //完成播放  
  135.             this.isPlaying = false;  
  136.             break;  
  137.               
  138.         }  
  139.     }  
  140.       
  141.     class RecordTask extends AsyncTask<Void, Integer, Void>{  
  142.         @Override  
  143.         protected Void doInBackground(Void... arg0) {  
  144.             isRecording = true;  
  145.             try {  
  146.                 //开通输出流到指定的文件  
  147.                 DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(audioFile)));  
  148.                 //根据定义好的几个配置,来获取合适的缓冲大小  
  149.                 int bufferSize = AudioRecord.getMinBufferSize(frequence, channelConfig, audioEncoding);  
  150.                 //实例化AudioRecord  
  151.                 AudioRecord record = new AudioRecord(MediaRecorder.AudioSource.MIC, frequence, channelConfig, audioEncoding, bufferSize);  
  152.                 //定义缓冲  
  153.                 short[] buffer = new short[bufferSize/4];  
  154.                   
  155.                 //开始录制  
  156.                 record.startRecording();  
  157.                   
  158.                 int r = 0//存储录制进度  
  159.                 //定义循环,根据isRecording的值来判断是否继续录制  
  160.                 while(isRecording){  
  161.                     //从bufferSize中读取字节,返回读取的short个数  
  162.                     //这里老是出现buffer overflow,不知道是什么原因,试了好几个值,都没用,TODO:待解决  
  163.                     int bufferReadResult = record.read(buffer, 0, buffer.length);  
  164.                     //循环将buffer中的音频数据写入到OutputStream中  
  165.                     for(int i=0; i<bufferReadResult; i++){  
  166.                         dos.writeShort(buffer[i]);  
  167.                     }  
  168.                     publishProgress(new Integer(r)); //向UI线程报告当前进度  
  169.                     r++; //自增进度值  
  170.                 }  
  171.                 //录制结束  
  172.                 record.stop();  
  173.                 Log.v("The DOS available:""::"+audioFile.length());  
  174.                 dos.close();  
  175.             } catch (Exception e) {  
  176.                 // TODO: handle exception  
  177.             }  
  178.             return null;  
  179.         }  
  180.           
  181.         //当在上面方法中调用publishProgress时,该方法触发,该方法在UI线程中被执行  
  182.         protected void onProgressUpdate(Integer...progress){  
  183.             stateView.setText(progress[0].toString());  
  184.         }  
  185.           
  186.         protected void onPostExecute(Void result){  
  187.             btnStop.setEnabled(false);  
  188.             btnStart.setEnabled(true);  
  189.             btnPlay.setEnabled(true);  
  190.             btnFinish.setEnabled(false);  
  191.         }  
  192.           
  193.         protected void onPreExecute(){  
  194.             //stateView.setText("正在录制");  
  195.             btnStart.setEnabled(false);  
  196.             btnPlay.setEnabled(false);  
  197.             btnFinish.setEnabled(false);  
  198.             btnStop.setEnabled(true);         
  199.         }  
  200.           
  201.     }  
  202.       
  203.     class PlayTask extends AsyncTask<Void, Integer, Void>{  
  204.         @Override  
  205.         protected Void doInBackground(Void... arg0) {  
  206.             isPlaying = true;  
  207.             int bufferSize = AudioTrack.getMinBufferSize(frequence, channelConfig, audioEncoding);  
  208.             short[] buffer = new short[bufferSize/4];  
  209.             try {  
  210.                 //定义输入流,将音频写入到AudioTrack类中,实现播放  
  211.                 DataInputStream dis = new DataInputStream(new BufferedInputStream(new FileInputStream(audioFile)));  
  212.                 //实例AudioTrack  
  213.                 AudioTrack track = new AudioTrack(AudioManager.STREAM_MUSIC, frequence, channelConfig, audioEncoding, bufferSize, AudioTrack.MODE_STREAM);  
  214.                 //开始播放  
  215.                 track.play();  
  216.                 //由于AudioTrack播放的是流,所以,我们需要一边播放一边读取  
  217.                 while(isPlaying && dis.available()>0){  
  218.                     int i = 0;  
  219.                     while(dis.available()>0 && i<buffer.length){  
  220.                         buffer[i] = dis.readShort();  
  221.                         i++;  
  222.                     }  
  223.                     //然后将数据写入到AudioTrack中  
  224.                     track.write(buffer, 0, buffer.length);  
  225.                       
  226.                 }  
  227.                   
  228.                 //播放结束  
  229.                 track.stop();  
  230.                 dis.close();  
  231.             } catch (Exception e) {  
  232.                 // TODO: handle exception  
  233.             }  
  234.             return null;  
  235.         }  
  236.           
  237.         protected void onPostExecute(Void result){  
  238.             btnPlay.setEnabled(true);  
  239.             btnFinish.setEnabled(false);  
  240.             btnStart.setEnabled(true);  
  241.             btnStop.setEnabled(false);  
  242.         }  
  243.           
  244.         protected void onPreExecute(){    
  245.               
  246.             //stateView.setText("正在播放");  
  247.             btnStart.setEnabled(false);  
  248.             btnStop.setEnabled(false);  
  249.             btnPlay.setEnabled(false);  
  250.             btnFinish.setEnabled(true);           
  251.         }  
  252.           
  253.     }  


发布了6 篇原创文章 · 获赞 6 · 访问量 12万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览