转自:http://www.cnblogs.com/Amandaliu/archive/2013/02/04/2891604.html

Android提供了两个API用于实现录音功能:android.media.AudioRecord、android.media.MediaRecorder。

    网上有很多谈论这两个类的资料。现在大致总结下:

1、AudioRecord

主要是实现边录边播(AudioRecord+AudioTrack)以及对音频的实时处理(如会说话的汤姆猫、语音)

优点:语音的实时处理,可以用代码实现各种音频的封装

缺点:输出是PCM语音数据,如果保存成音频文件,是不能够被播放器播放的,所以必须先写代码实现数据编码以及压缩

示例:

使用AudioRecord类录音,并实现WAV格式封装。录音20s,输出的音频文件大概为3.5M左右(已写测试代码)

2、MediaRecorder

已经集成了录音、编码、压缩等,支持少量的录音音频格式,大概有.aac(API = 16) .amr .3gp

优点:大部分以及集成,直接调用相关接口即可,代码量小

缺点:无法实时处理音频;输出的音频格式不是很多,例如没有输出mp3格式文件

示例:

使用MediaRecorder类录音,输出amr格式文件。录音20s,输出的音频文件大概为33K(已写测试代码)

3、音频格式比较

WAV格式:录音质量高,但是压缩率小,文件大

AAC格式:相对于mp3,AAC格式的音质更佳,文件更小;有损压缩;一般苹果或者Android SDK4.1.2(API 16)及以上版本支持播放

AMR格式:压缩比比较大,但相对其他的压缩格式质量比较差,多用于人声,通话录音

至于常用的mp3格式,使用MediaRecorder没有该视频格式输出。一些人的做法是使用AudioRecord录音,然后编码成wav格式,再转换成mp3格式

 

    再贴上一些测试工程。

功能描述:

1、点击“录音WAV文件”,开始录音。录音完成后,生成文件/sdcard/FinalAudio.wav

2、点击“录音AMR文件”,开始录音。录音完成后,生成文件/sdcard/FinalAudio.amr

3、点击“停止录音”,停止录音,并显示录音输出文件以及该文件大小。

 

大致代码如下:

1、AudioRecord录音,封装成WAV格式

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 package  com.example.audiorecordtest;   import  java.io.File; import  java.io.FileInputStream; import  java.io.FileNotFoundException; import  java.io.FileOutputStream; import  java.io.IOException;   import  android.media.AudioFormat; import  android.media.AudioRecord;   public  class  AudioRecordFunc {      // 缓冲区字节大小       private  int  bufferSizeInBytes = 0 ;            //AudioName裸音频数据文件 ,麦克风      private  String AudioName = ""            //NewAudioName可播放的音频文件       private  String NewAudioName = "" ;            private  AudioRecord audioRecord;       private  boolean  isRecord = false ; // 设置正在录制的状态                   private  static  AudioRecordFunc mInstance;                 private  AudioRecordFunc(){                }              public  synchronized  static  AudioRecordFunc getInstance()      {          if (mInstance == null )              mInstance = new  AudioRecordFunc();          return  mInstance;      }            public  int  startRecordAndFile() {          //判断是否有外部存储设备sdcard          if (AudioFileFunc.isSdcardExit())          {              if (isRecord)              {                  return  ErrorCode.E_STATE_RECODING;              }              else              {                  if (audioRecord == null )                      creatAudioRecord();                                    audioRecord.startRecording();                   // 让录制状态为true                   isRecord = true                  // 开启音频文件写入线程                   new  Thread( new  AudioRecordThread()).start();                                     return  ErrorCode.SUCCESS;              }                        }                else          {              return  ErrorCode.E_NOSDCARD;                     }                       public  void  stopRecordAndFile() {           close();       }                  public  long  getRecordFileSize(){          return  AudioFileFunc.getFileSize(NewAudioName);      }                private  void  close() {           if  (audioRecord != null ) {               System.out.println( "stopRecord" );               isRecord = false ; //停止文件写入               audioRecord.stop();               audioRecord.release(); //释放资源               audioRecord = null               }                  private  void  creatAudioRecord() {           // 获取音频文件路径          AudioName = AudioFileFunc.getRawFilePath();          NewAudioName = AudioFileFunc.getWavFilePath();                    // 获得缓冲区字节大小           bufferSizeInBytes = AudioRecord.getMinBufferSize(AudioFileFunc.AUDIO_SAMPLE_RATE,                   AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_PCM_16BIT);                     // 创建AudioRecord对象           audioRecord = new  AudioRecord(AudioFileFunc.AUDIO_INPUT, AudioFileFunc.AUDIO_SAMPLE_RATE,                   AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_PCM_16BIT, bufferSizeInBytes);       }                  class  AudioRecordThread implements  Runnable {           @Override           public  void  run() {               writeDateTOFile(); //往文件中写入裸数据               copyWaveFile(AudioName, NewAudioName); //给裸数据加上头文件                         /**       * 这里将数据写入文件,但是并不能播放,因为AudioRecord获得的音频是原始的裸音频,       * 如果需要播放就必须加入一些格式或者编码的头信息。但是这样的好处就是你可以对音频的 裸数据进行处理,比如你要做一个爱说话的TOM       * 猫在这里就进行音频的处理,然后重新封装 所以说这样得到的音频比较容易做一些音频的处理。       */       private  void  writeDateTOFile() {           // new一个byte数组用来存一些字节数据,大小为缓冲区大小           byte [] audiodata = new  byte [bufferSizeInBytes];           FileOutputStream fos = null          int  readsize = 0          try               File file = new  File(AudioName);               if  (file.exists()) {                   file.delete();                            fos = new  FileOutputStream(file); // 建立一个可存取字节的文件           } catch  (Exception e) {               e.printStackTrace();                    while  (isRecord == true ) {               readsize = audioRecord.read(audiodata, 0 , bufferSizeInBytes);               if  (AudioRecord.ERROR_INVALID_OPERATION != readsize && fos!= null ) {                   try                       fos.write(audiodata);                   } catch  (IOException e) {                       e.printStackTrace();                                                  try  {              if (fos != null )                  fos.close(); // 关闭写入流           } catch  (IOException e) {               e.printStackTrace();                         // 这里得到可播放的音频文件       private  void  copyWaveFile(String inFilename, String outFilename) {           FileInputStream in = null          FileOutputStream out = null          long  totalAudioLen = 0          long  totalDataLen = totalAudioLen + 36          long  longSampleRate = AudioFileFunc.AUDIO_SAMPLE_RATE;           int  channels = 2          long  byteRate = 16  * AudioFileFunc.AUDIO_SAMPLE_RATE * channels / 8          byte [] data = new  byte [bufferSizeInBytes];           try               in = new  FileInputStream(inFilename);               out = new  FileOutputStream(outFilename);               totalAudioLen = in.getChannel().size();               totalDataLen = totalAudioLen + 36              WriteWaveFileHeader(out, totalAudioLen, totalDataLen,                       longSampleRate, channels, byteRate);               while  (in.read(data) != - 1 ) {                   out.write(data);                            in.close();               out.close();           } catch  (FileNotFoundException e) {               e.printStackTrace();           } catch  (IOException e) {               e.printStackTrace();                         /**       * 这里提供一个头信息。插入这些信息就可以得到可以播放的文件。       * 为我为啥插入这44个字节,这个还真没深入研究,不过你随便打开一个wav       * 音频的文件,可以发现前面的头文件可以说基本一样哦。每种格式的文件都有       * 自己特有的头文件。       */       private  void  WriteWaveFileHeader(FileOutputStream out, long  totalAudioLen,               long  totalDataLen, long  longSampleRate, int  channels, long  byteRate)               throws  IOException {           byte [] header = new  byte [ 44 ];           header[ 0 ] = 'R' ; // RIFF/WAVE header           header[ 1 ] = 'I'          header[ 2 ] = 'F'          header[ 3 ] = 'F'          header[ 4 ] = ( byte ) (totalDataLen & 0xff );           header[ 5 ] = ( byte ) ((totalDataLen >> 8 ) & 0xff );           header[ 6 ] = ( byte ) ((totalDataLen >> 16 ) & 0xff );           header[ 7 ] = ( byte ) ((totalDataLen >> 24 ) & 0xff );           header[ 8 ] = 'W'          header[ 9 ] = 'A'          header[ 10 ] = 'V'          header[ 11 ] = 'E'          header[ 12 ] = 'f' ; // 'fmt ' chunk           header[ 13 ] = 'm'          header[ 14 ] = 't'          header[ 15 ] = ' '          header[ 16 ] = 16 ; // 4 bytes: size of 'fmt ' chunk           header[ 17 ] = 0          header[ 18 ] = 0          header[ 19 ] = 0          header[ 20 ] = 1 ; // format = 1           header[ 21 ] = 0          header[ 22 ] = ( byte ) channels;           header[ 23 ] = 0          header[ 24 ] = ( byte ) (longSampleRate & 0xff );           header[ 25 ] = ( byte ) ((longSampleRate >> 8 ) & 0xff );           header[ 26 ] = ( byte ) ((longSampleRate >> 16 ) & 0xff );           header[ 27 ] = ( byte ) ((longSampleRate >> 24 ) & 0xff );           header[ 28 ] = ( byte ) (byteRate & 0xff );           header[ 29 ] = ( byte ) ((byteRate >> 8 ) & 0xff );           header[ 30 ] = ( byte ) ((byteRate >> 16 ) & 0xff );           header[ 31 ] = ( byte ) ((byteRate >> 24 ) & 0xff );           header[ 32 ] = ( byte ) ( 2  * 16  / 8 ); // block align           header[ 33 ] = 0          header[ 34 ] = 16 ; // bits per sample           header[ 35 ] = 0          header[ 36 ] = 'd'          header[ 37 ] = 'a'          header[ 38 ] = 't'          header[ 39 ] = 'a'          header[ 40 ] = ( byte ) (totalAudioLen & 0xff );           header[ 41 ] = ( byte ) ((totalAudioLen >> 8 ) & 0xff );           header[ 42 ] = ( byte ) ((totalAudioLen >> 16 ) & 0xff );           header[ 43 ] = ( byte ) ((totalAudioLen >> 24 ) & 0xff );           out.write(header, 0 , 44 );       }

 

2、MediaRecorder录音,输出amr格式音频

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 package  com.example.audiorecordtest;   import  java.io.File; import  java.io.IOException;   import  android.media.MediaRecorder;   public  class  MediaRecordFunc {       private  boolean  isRecord = false ;            private  MediaRecorder mMediaRecorder;      private  MediaRecordFunc(){      }            private  static  MediaRecordFunc mInstance;      public  synchronized  static  MediaRecordFunc getInstance(){          if (mInstance == null )              mInstance = new  MediaRecordFunc();          return  mInstance;      }            public  int  startRecordAndFile(){          //判断是否有外部存储设备sdcard          if (AudioFileFunc.isSdcardExit())          {              if (isRecord)              {                  return  ErrorCode.E_STATE_RECODING;              }              else              {                 

更多相关文章

  1. Windows平台上编译OpenCV的Android版本
  2. Android(安卓)Studio获取SHA1值
  3. 基于Android(安卓)tess-two工程的数字识别
  4. Android(安卓)SAX解析xml文件
  5. android学习笔记(不断更新...)
  6. 烽火学习笔记1
  7. android读取plist文件
  8. android Multiple markers at this line - The type java.lang.C
  9. NPM 和webpack 的基础使用

随机推荐

  1. android 安全讲座第四层 手机Root授权原
  2. Android按钮的点击效果的总结
  3. android ant 打包遇到[aapt] invalid res
  4. Android(安卓)集成海康威视监控 SDK,实现
  5. Android Wear:创建可穿戴应用 - 概述
  6. Android Scroll分析
  7. Android覆盖升级以及apk签名
  8. 使用ant让Android自动打包的build.xml,自
  9. Android实用视图动画及工具系列之四:多状
  10. Nexus 6P 外媒评测:华为造出了最好的 Andr