Android录音--AudioRecord、MediaRecorder

Android实现边录边播(MediaRecorder和AudioRecord) Android可以通过MediaRecorder和AudioRecord这两个工具来实现录音,MediaRecorder直接把麦克风的数据存到文件,并且能够直接进行编码(如AMR,MP3等),而AudioRecord则是读取麦克风的音频流。本文使用AudioRecord读取音频流,使用AudioTrack播放音频流,通过“边读边播放”以及增大音量的方式来实现一个简单的助听器程序。 PS:由于目前的Android模拟器还不支持AudioRecord,因此本程序需要编译之后放到真机运行。 Activity_ 阅读详情

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
             {
                 if (mMediaRecorder == null )
                     createMediaRecord();
                 
                 try {
                     mMediaRecorder.prepare();
                     mMediaRecorder.start();
                     // 让录制状态为true 
                     isRecord = true ;
                     return  ErrorCode.SUCCESS;
                 } catch (IOException ex){
                     ex.printStackTrace();
                     return  ErrorCode.E_UNKOWN;
                 }
             }
             
         }      
         else
         {
             return  ErrorCode.E_NOSDCARD;           
         }      
     }
     
     
     public  void  stopRecordAndFile(){
          close();
     }
     
     public  long  getRecordFileSize(){
         return  AudioFileFunc.getFileSize(AudioFileFunc.getAMRFilePath());
     }
     
     
     private  void  createMediaRecord(){
          /* ①Initial:实例化MediaRecorder对象 */
         mMediaRecorder = new  MediaRecorder();
         
         /* setAudioSource/setVedioSource*/
         mMediaRecorder.setAudioSource(AudioFileFunc.AUDIO_INPUT); //设置麦克风
         
         /* 设置输出文件的格式:THREE_GPP/MPEG-4/RAW_AMR/Default
          * THREE_GPP(3gp格式,H263视频/ARM音频编码)、MPEG-4、RAW_AMR(只支持音频且音频编码要求为AMR_NB)
          */
          mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
          
          /* 设置音频文件的编码:AAC/AMR_NB/AMR_MB/Default */
          mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
          
          /* 设置输出文件的路径 */
          File file = new  File(AudioFileFunc.getAMRFilePath());
          if  (file.exists()) { 
              file.delete(); 
          }
          mMediaRecorder.setOutputFile(AudioFileFunc.getAMRFilePath());
     }
     
     
     private  void  close(){
         if  (mMediaRecorder != null ) { 
             System.out.println( "stopRecord" ); 
             isRecord = false ;
             mMediaRecorder.stop(); 
             mMediaRecorder.release(); 
             mMediaRecorder = null ;
         } 
     }
}
1
  

3、其他文件

AudioFileFunc.java

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
package  com.example.audiorecordtest;
 
import  java.io.File;
 
import  android.media.MediaRecorder;
import  android.os.Environment;
 
public  class  AudioFileFunc {
     //音频输入-麦克风
     public  final  static  int  AUDIO_INPUT = MediaRecorder.AudioSource.MIC;
     
     //采用频率
     //44100是目前的标准,但是某些设备仍然支持22050,16000,11025
     public  final  static  int  AUDIO_SAMPLE_RATE = 44100 ;  //44.1KHz,普遍使用的频率  
     //录音输出文件
     private  final  static  String AUDIO_RAW_FILENAME = "RawAudio.raw" ;
     private  final  static  String AUDIO_WAV_FILENAME = "FinalAudio.wav" ;
     public  final  static  String AUDIO_AMR_FILENAME = "FinalAudio.amr" ;
     
     /**
      * 判断是否有外部存储设备sdcard
      * @return true | false
      */
     public  static  boolean  isSdcardExit(){      
         if  (Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED))
             return  true ;
         else
             return  false ;
     }
         
     /**
      * 获取麦克风输入的原始音频流文件路径
      * @return
      */
     public  static  String getRawFilePath(){
         String mAudioRawPath = "" ;
         if (isSdcardExit()){
             String fileBasePath = Environment.getExternalStorageDirectory().getAbsolutePath();
             mAudioRawPath = fileBasePath+ "/" +AUDIO_RAW_FILENAME;
         }  
         
         return  mAudioRawPath;
     }
     
     /**
      * 获取编码后的WAV格式音频文件路径
      * @return
      */
     public  static  String getWavFilePath(){
         String mAudioWavPath = "" ;
         if (isSdcardExit()){
             String fileBasePath = Environment.getExternalStorageDirectory().getAbsolutePath();
             mAudioWavPath = fileBasePath+ "/" +AUDIO_WAV_FILENAME;
         }
         return  mAudioWavPath;
     }
     
     
     /**
      * 获取编码后的AMR格式音频文件路径
      * @return
      */
     public  static  String getAMRFilePath(){
         String mAudioAMRPath = "" ;
         if (isSdcardExit()){
             String fileBasePath = Environment.getExternalStorageDirectory().getAbsolutePath();
             mAudioAMRPath = fileBasePath+ "/" +AUDIO_AMR_FILENAME;
         }
         return  mAudioAMRPath;
     }  
     
     
     /**
      * 获取文件大小
      * @param path,文件的绝对路径
      * @return
      */
     public  static  long  getFileSize(String path){
         File mFile = new  File(path);
         if (!mFile.exists())
             return  - 1 ;
         return  mFile.length();
     }
 
}

 

4、其他文件

ErrorCode.java

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
package  com.example.audiorecordtest;
 
import  android.content.Context;
import  android.content.res.Resources.NotFoundException;
 
public  class  ErrorCode {
     public  final  static  int  SUCCESS = 1000 ;
     public  final  static  int  E_NOSDCARD = 1001 ;
     public  final  static  int  E_STATE_RECODING = 1002 ;
     public  final  static  int  E_UNKOWN = 1003 ;
     
     
     public  static  String getErrorInfo(Context vContext, int  vType) throws  NotFoundException
     {
         switch (vType)
         {
         case  SUCCESS:
             return  "success" ;
         case  E_NOSDCARD:
             return  vContext.getResources().getString(R.string.error_no_sdcard);
         case  E_STATE_RECODING:
             return  vContext.getResources().getString(R.string.error_state_record); 
         case  E_UNKOWN:
         default :
             return  vContext.getResources().getString(R.string.error_unknown);          
             
         }
     }
 
}

 

5、string.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<? xml  version="1.0" encoding="utf-8"?>
< resources >
 
     < string  name="app_name">AudioRecordTest</ string >
     < string  name="hello_world">测试AudioRecord,实现录音功能</ string >
     < string  name="menu_settings">Settings</ string >
     < string  name="view_record_wav">录音WAV文件</ string >
     < string  name="view_record_amr">录音AMR文件</ string >
     < string  name="view_stop">停止录音</ string >
     
     < string  name="error_no_sdcard">没有SD卡,无法存储录音数据</ string >
     < string  name="error_state_record">正在录音中,请先停止录音</ string >
     < string  name="error_unknown">无法识别的错误</ string >
 
</ resources >

 

6、主程序MainActivity

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
package com.example.audiorecordtest;
 
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
 
public class MainActivity extends Activity {
     private final static int FLAG_WAV = 0;
     private final static int FLAG_AMR = 1;
     private int mState = -1;    //-1:没再录制,0:录制wav,1:录制amr
     private Button btn_record_wav;
     private Button btn_record_amr;
     private Button btn_stop;
     private TextView txt;
     private UIHandler uiHandler;
     private UIThread uiThread;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);
         findViewByIds();
         setListeners();
         init();
     }
 
     @Override
     public boolean onCreateOptionsMenu(Menu menu) {
         // Inflate the menu; this adds items to the action bar if it is present.
         getMenuInflater().inflate(R.menu.activity_main, menu);
         return true;
     }
     private void findViewByIds(){
         btn_record_wav = (Button)this.findViewById(R.id.btn_record_wav);
         btn_record_amr = (Button)this.findViewById(R.id.btn_record_amr);
         btn_stop = (Button)this.findViewById(R.id.btn_stop);
         txt = (TextView)this.findViewById(R.id.text);
     }
     private void setListeners(){
         btn_record_wav.setOnClickListener(btn_record_wav_clickListener);
         btn_record_amr.setOnClickListener(btn_record_amr_clickListener);
         btn_stop.setOnClickListener(btn_stop_clickListener);
     }
     private void init(){
         uiHandler = new UIHandler();       
     }
     private Button.OnClickListener btn_record_wav_clickListener = new Button.OnClickListener(){
         public void onClick(View v){
             record(FLAG_WAV);
         }
     };
     private Button.OnClickListener btn_record_amr_clickListener = new Button.OnClickListener(){
         public void onClick(View v){
             record(FLAG_AMR);
         }
     };
     private Button.OnClickListener btn_stop_clickListener = new Button.OnClickListener(){
         public void onClick(View v){
             stop();    
         }
     };
     /**
      * 开始录音
      * @param mFlag,0:录制wav格式,1:录音amr格式
      */
     private void record(int mFlag){
         if(mState != -1){
             Message msg = new Message();
             Bundle b = new Bundle();// 存放数据
             b.putInt("cmd",CMD_RECORDFAIL);
             b.putInt("msg", ErrorCode.E_STATE_RECODING);
             msg.setData(b);
 
             uiHandler.sendMessage(msg); // 向Handler发送消息,更新UI
             return;
         }
         int mResult = -1;
         switch(mFlag){       
         case FLAG_WAV:
             AudioRecordFunc mRecord_1 = AudioRecordFunc.getInstance();
             mResult = mRecord_1.startRecordAndFile();           
             break;
         case FLAG_AMR:
             MediaRecordFunc mRecord_2 = MediaRecordFunc.getInstance();
             mResult = mRecord_2.startRecordAndFile();
             break;
         }
         if(mResult == ErrorCode.SUCCESS){
             uiThread = new UIThread();
             new Thread(uiThread).start();
             mState = mFlag;
         }else{
             Message msg = new Message();
             Bundle b = new Bundle();// 存放数据
             b.putInt("cmd",CMD_RECORDFAIL);
             b.putInt("msg", mResult);
             msg.setData(b);
 
             uiHandler.sendMessage(msg); // 向Handler发送消息,更新UI
         }
     }
     /**
      * 停止录音
      */
     private void stop(){
         if(mState != -1){
             switch(mState){
             case FLAG_WAV:
                 AudioRecordFunc mRecord_1 = AudioRecordFunc.getInstance();
                 mRecord_1.stopRecordAndFile();
                 break;
             case FLAG_AMR:
                 MediaRecordFunc mRecord_2 = MediaRecordFunc.getInstance();
                 mRecord_2.stopRecordAndFile();
                 break;
             }           
             if(uiThread != null){
                 uiThread.stopThread();
             }
             if(uiHandler != null)
                 uiHandler.removeCallbacks(uiThread);
             Message msg = new Message();
             Bundle b = new Bundle();// 存放数据
             b.putInt("cmd",CMD_STOP);
             b.putInt("msg", mState);
             msg.setData(b);
             uiHandler.sendMessageDelayed(msg,1000); // 向Handler发送消息,更新UI
             mState = -1;
         }
     }   
     private final static int CMD_RECORDING_TIME = 2000;
     private final static int CMD_RECORDFAIL = 2001;
     private final static int CMD_STOP = 2002;
     class UIHandler extends Handler{
         public UIHandler() {
         }
         @Override
         public void handleMessage(Message msg) {
             // TODO Auto-generated method stub
             Log.d("MyHandler", "handleMessage......");
             super.handleMessage(msg);
             Bundle b = msg.getData();
             int vCmd = b.getInt("cmd");
             switch(vCmd)
             {
             case CMD_RECORDING_TIME:
                 int vTime = b.getInt("msg");
                 MainActivity.this.txt.setText("正在录音中,已录制:"+vTime+" s");
                 break;
             case CMD_RECORDFAIL:
                 int vErrorCode = b.getInt("msg");
                 String vMsg = ErrorCode.getErrorInfo(MainActivity.this, vErrorCode);
                 MainActivity.this.txt.setText("录音失败:"+vMsg);
                 break;
             case CMD_STOP:               
                 int vFileType = b.getInt("msg");
                 switch(vFileType){
                 case FLAG_WAV:
                     AudioRecordFunc mRecord_1 = AudioRecordFunc.getInstance();
                     long mSize = mRecord_1.getRecordFileSize();
                     MainActivity.this.txt.setText("录音已停止.录音文件:"+AudioFileFunc.getWavFilePath()+"\n文件大小:"+mSize);
                     break;
                 case FLAG_AMR:                   
                     MediaRecordFunc mRecord_2 = MediaRecordFunc.getInstance();
                     mSize = mRecord_2.getRecordFileSize();
                     MainActivity.this.txt.setText("录音已停止.录音文件:"+AudioFileFunc.getAMRFilePath()+"\n文件大小:"+mSize);
                     break;
                 }
                 break;
             default:
                 break;
             }
         }
     };
     class UIThread implements Runnable {       
         int mTimeMill = 0;
         boolean vRun = true;
         public void stopThread(){
             vRun = false;
         }
         public void run() {
             while(vRun){
                 try {
                     Thread.sleep(1000);
                 } catch (InterruptedException e) {
                     // TODO Auto-generated catch block
                     e.printStackTrace();
                 }
                 mTimeMill ++;
                 Log.d("thread", "mThread........"+mTimeMill);
                 Message msg = new Message();
                 Bundle b = new Bundle();// 存放数据
                 b.putInt("cmd",CMD_RECORDING_TIME);
                 b.putInt("msg", mTimeMill);
                 msg.setData(b);
 
                 MainActivity.this.uiHandler.sendMessage(msg); // 向Handler发送消息,更新UI
             }
 
         }
     }
 
}
原文链接:http://www.cnblogs.com/Amandaliu/archive/2013/02/04/2891604.html

Android AudioRecord 的使用 AudioRecord 本工程实现pcm多配置(采样率、文件格式可选)的录音和播放工具,可用户音频的录制。 工程代码:https://github.com/worson/AudioRecord.git [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2Hvl37yP-1580284239332)(img/picture_2020_01_29_14___52_41.pn... 阅读详情

相关推荐

音视频基础能力之 Android 音频篇 (一):音频采集

本人比较详细的讲解了 AudioRecord 的运行机制以及使用方面的介绍,下面是 github 上的示例代码链接。如果您觉得以上内容对您有所帮助的话,可以关注下我们运营的公众号,会定期的推送 音视频技术、移动端技术 为主轴的 科普类、基础知识类、行业资讯类等相关文章。在这里插入图片描述AudioRecord 状态。

AVExplorer的博客 1634

html5录音功能实战

缘起 由于项目需要,我们要在web端实现录音功能。一开始,找到的方案有两个,一个是通过iframe,一个是html5的getUserMedia api。由于我们的录音功能不需要兼容IE浏览器,所以毫不犹豫的选择了html5提供的getUserMedia去实现。基本思路是参考了官方的api文档以及网上查找的一些方案做结合做出了适合项目需要的方案。但由于我们必须保证这个录音功能能够同时在pad端、pc端都可以打开,所以其中也踩了一些坑。以下为过程还原。 步骤1 由于新的api是通过navigator.me

Within的博客 2368

android 录音原始文件_Android录音--AudioRecord、MediaRecorder (音频文件格式处理)

Android提供了两个API用于实现录音功能:android.media.AudioRecord、android.media.MediaRecorder。网上有很多谈论这两个类的资料。现在大致总结下:1、AudioRecord主要是实现边录边播(AudioRecord+AudioTrack)以及对音频的实时处理(如会说话的汤姆猫、语音)优点:语音的实时处理,可以用代码实现各种音频的封装缺点:输出...

weixin_29672983的博客 1034

android中AudioRecord使用详解

摘要 本文介绍了android中AudioRecord的一些基本使用,主要参考官方文档,本文不讲过多理论知识,主要介绍在实际开发中的使用方法。 类概述   AudioRecord类在Java应用程序中管理音频资源,用来记录从平台音频输入设备产生的数据。 通过AudioRecord对象来完成”pulling”(读取)数据。 应用通过以下几个方法负责立即从AudioRecord对象读取: ...

ai-exception的博客 3万+

Android之录音--AudioRecord、MediaRecorder

Android提供了两个API用于实现录音功能:android.media.AudioRecord、android.media.MediaRecorder。     网上有很多谈论这两个类的资料。现在大致总结下: 1、AudioRecord 主要是实现边录边播(AudioRecord+AudioTrack)以及对音频的实时处理(如会说话的汤姆猫、语音) 优点:语音的实时处理

码莎拉蒂 4540

【MediaPipe实战】从零构建实时人脸关键点检测与表情分析系统

本文详细介绍了如何使用MediaPipe框架从零构建实时人脸关键点检测与表情分析系统。通过Python代码实现,系统能够精准检测468个3D人脸关键点,并实时分析用户表情,适用于智能交互应用。文章包含环境配置、核心实现、可视化技巧及性能优化等实战内容,帮助开发者快速掌握深度学习在计算机视觉中的应用。

weixin_30836759的博客 73

【Android】【录音】Android录音--AudioRecord MediaRecorder

【Android】【录音】Android录音--AudioRecord MediaRecorder

gfuugff的博客 756

浮点数运算的陷阱与启示:FP16加法器/乘法器开发中的常见误区

本文深入探讨FP16加法器和乘法器开发中的常见误区,包括FP16格式解析、阶码对齐陷阱、尾数运算风险及规格化处理。通过Verilog实战代码展示防御性编程技巧,帮助开发者避免边界条件处理和异常状态管理中的错误,提升硬件设计的可靠性和效率。

dell8的博客 250

android 录音原始文件_Android录音--AudioRecord、MediaRecorder的使用

Android提供了两个API用于实现录音功能:android.media.AudioRecord、android.media.MediaRecorder。网上有很多谈论这两个类的资料。现在大致总结下:1、AudioRecord主要是实现边录边播(AudioRecord+AudioTrack)以及对音频的实时处理(如会说话的汤姆猫、语音)优点:语音的实时处理,可以用代码实现各种音频的封装缺点:输出...

weixin_32642653的博客 807

从Unitree B2W到四足机器人:用Isaac Lab构建强化学习奖励函数的5个实战技巧

本文分享了在Isaac Lab仿真环境中,为Unitree B2W等四足机器人设计强化学习奖励函数的5个核心实战技巧。内容涵盖奖励函数的结构化组合、轮腿混合机器人的适配策略、课程学习的动态调整、域随机化增强鲁棒性以及高效的调试可视化方法,旨在帮助开发者构建更稳定、高效的机器人运动策略。

lg888的博客 1066

RAID 0/1/5/10 性能实测:4块 SATA SSD 组阵列,顺序读写速度对比

本文通过实测对比了RAID 0/1/5/10在4块SATA SSD上的顺序读写性能,详细展示了不同RAID级别的配置方法、理论性能与实际测试数据。测试结果显示,RAID 0在顺序读写速度上表现最佳,而RAID 10则在性能与数据安全之间取得了平衡,适合数据库服务器等关键应用场景。

weixin_33462167的博客 424

aac mediarecorder录制_Android录音--AudioRecord、MediaRecorder

Android提供了两个API用于实现录音功能:android.media.AudioRecord、android.media.MediaRecorder。网上有很多谈论这两个类的资料。现在大致总结下:1、AudioRecord主要是实现边录边播(AudioRecord+AudioTrack)以及对音频的实时处理(如会说话的汤姆猫、语音)优点:语音的实时处理,可以用代码实现各种音频的封装缺点:输出...

weixin_39878646的博客 211

蓝鸟四轴飞控系统C程序V3.0(基础版本)深度解读

2. 解析遥控通道数据(油门 / 横滚 / 俯仰 / 偏航),转换为标准化值(-1000~+1000);3. 封装PID初始化(PID_Init,配置KP/KI/KD、输出限幅、积分限幅);,包含姿态角(Attitude_Data.Roll/Pitch/Yaw)、角速度(Gyro_Data.X/Y/Z)、遥控值(RC_Data[0~5])、电池电压(Bat_Volt)、电机PWM值(Motor_PWM[0~3])、系统状态(Sys_State),校验和通过Check_Sum()函数计算;

搏博的专栏 343

【Android】【录音】Android录音--AudioRecord、MediaRecorder

Android提供了两个API用于实现录音功能:android.media.AudioRecord、android.media.MediaRecorder。     网上有很多谈论这两个类的资料。现在大致总结下: 1、AudioRecord 主要是实现边录边播(AudioRecord+AudioTrack)以及对音频的实时处理(如会说话的汤姆猫、语音) 优点:语音的实时处理,可以用代码

进击的小黑哥 1002

28、数字电路测试与半导体内存测试全解析

本文全面解析了数字电路中的顺序电路测试生成方法与半导体内存测试技术。内容涵盖顺序电路中的故障检测、多重观察测试、可驱动性分析、伪组合电路测试及初始化问题,并深入探讨了内存技术发展、故障模型、测试流程与未来趋势。重点介绍了DRAM、SRAM等主流内存类型的特点,以及制造和使用过程中面临的永久性与非永久性故障挑战,提出了基于故障模型的高效测试策略与优化方案。

go5gopher的博客 122

Unity-RetargetPro3-动画插件试用

一个名气大于实战的插件。

大话程序员 711

Android 调用系统api录音的两种方式(MediaRecorder、AudioRecord)

废话 权限、权限、权限,必须要先获取了录音权限,其他的事情晚点再说。 另外,新版本的Android 10系统会对录音有调整,引入了一个录音焦点的概念,也就是说以前的麦克风只能一个APP使用,必须要等它断开了别人才能用,现在换成可以抢的形式,也就是如果没有音焦,代码有可能不会报错,但是是录不进声音的。 Android系统API提供的录音方式就两种:MediaRecorder、AudioReco...

qq_33601179的博客 4822

Qualcomm Camera 启动优化实战:Preview、Snapshot、ZSL 路径控制与时延剖析

在移动终端上,Camera 的“启动速度”与“抓拍响应”是决定用户体验的关键指标。以 Qualcomm Snapdragon 平台为代表,Camera Stack 涉及 HAL 初始化、Session 配置、ISP 路径激活、Buffer 分配、图像流启动等多个异步流程,稍有设计不当将导致 Preview 启动缓慢或抓拍延迟明显。本文基于高通平台架构与 CamX 实战经验,详细剖析 Preview 与 Snapshot 启动路径,重点分析 ZSL 模式下的全链路优化策略,给出具体时延测量方法与调试参数建议。

努力分享一些人工智能、计算机视觉、影像等相关的知识干货! 1582

android 录音原始文件_Android 录音详解(一)—— MediaRecorder、AudioRecord、生成wav格式、边录边播...

Android 录音详解(一)—— MediaRecorder、AudioRecord、生成wav格式、边录边播越来越多的 APP 都用到了手机的录音功能,比如搜索、聊天、输入、K歌等...本系列详细介绍 Android 中录音功能的实现,包括:Android 录音详解(四)—— 录音添加背景音乐Android 中的录音主要有两种方式 MediaRecorder 和 AudioRecord,下面分...

weixin_39915078的博客 2101

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

Android录音--AudioRecord、MediaRecorder (音频文件格式处理)

Android提供了两个API用于实现录音功能:android.media.AudioRecord、android.media.MediaRecorder。 网上有很多谈论这两个类的资料。现在大致总结下: 1、AudioRecord 主要是实现边录边播(AudioRecord+AudioTrack)以及对音频的实时处理(如会说话的汤姆猫、语音) 优点:语音的实时处理...

FLY_THINK2012的博客 962

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

android 读取音频音量,Android AudioRecord和MediaRecorder录音并实现了实时获取音量大小...

【实例简介】Android AudioRecord和MediaRecorder录音并实现了实时获取音量大小看代码就知道了【实例截图】【核心代码】MediaRecorer和AudioRecore└── MediaRecorer和AudioRecore├── MyAudioRecorder│ ├── AndroidManifest.xml│ ├── bin│ │ ├── Android...

weixin_31752923的博客 928

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

上一篇: android动画(一)Interpolator
hookfeng
博客等级 码龄12年 4粉丝 5原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值