Android中有自带的音频录制程序,我们可以通过指定一个Action为MediaStore.Audio.Media.RECORD_SOUND_ACTION的Intent来
启动它就可以了。然后在onActivityResult()方法中,获取Intent的Data,就是录制的音频对应的URI。
代码:
1. package
2. import
3. import
4. import
5. import
6. import
7. import
8. import
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
28.
29.
30. public void
31. super.onCreate(savedInstanceState);
32. setContentView(R.layout.audio_record);
33. }
34.
35. public void onActivityResult(int requestCode, int
36. //super.onActivityResult(requestCode, resultCode, data);
37. //这里我们就可以获取到刚刚录制的音频的Uri,可以进行播放等操作,这里显示返回的Uri
38. if(resultCode == RESULT_OK){
39. Uri audioPath = data.getData();
40. this, audioPath.toString(), Toast.LENGTH_LONG).show();
41. }
42. }
43.
44. public void
45. int
46. switch(id){
47. case
48. //调用Android自带的音频录制应用
49. new
50. 0);
51. break;
52. case
53. //通过MediaRecorder类来实现自己的音频录制程序
54. new
55. this, MyAudioRecord.class);
56. 1);
57. break;
58. case
59. //通过AudioRecord类实现自己的音频录制程序
60. new
61. this, MyAudioRecord2.class);
62. 2);
63. break;
64. }
65. }
66. }
67. package
68. import
69. import
70. import
71. import
72. import
73. import
74. import
75. import
76. import
77. import
78. import
79. import
80. import
81. import
82. /**
83. * 这个是利用MediaRecorder类来实现自己的音频录制程序
84. *
85. * 为了可以录制音频我们需要RECORD_AUDIO权限
86. * 为了可以写入SDCard,我们需要WRITE_EXTERNAL_STORAGE权限
87. * @author Administrator
88. *
89. */
90. public class MyAudioRecord extends
91.
92. private
93.
94. private
95.
96. private
97.
98. private
99.
100. private
101.
102. private
103.
104. public void
105. super.onCreate(savedInstanceState);
106. setContentView(R.layout.my_audio_record);
107.
108. this.findViewById(R.id.view_state);
109. "准备开始");
110. this.findViewById(R.id.btn_start);
111. this.findViewById(R.id.btn_stop);
112. this.findViewById(R.id.btn_play);
113. this.findViewById(R.id.btn_finish);
114.
115. false);
116. false);
117.
118. }
119.
120.
121. public void
122. int
123. switch(id){
124. case
125. //开始录制
126. //我们需要实例化一个MediaRecorder对象,然后进行相应的设置
127. new
128. //指定AudioSource 为MIC(Microphone audio source ),这是最长用的
129. recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
130. //指定OutputFormat,我们选择3gp格式
131. //其他格式,MPEG-4:这将指定录制的文件为mpeg-4格式,可以保护Audio和Video
132. //RAW_AMR:录制原始文件,这只支持音频录制,同时要求音频编码为AMR_NB
133. //THREE_GPP:录制后文件是一个3gp文件,支持音频和视频录制
134. recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
135. //指定Audio编码方式,目前只有AMR_NB格式
136. recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
137. //接下来我们需要指定录制后文件的存储路径
138. new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/data/files/");
139. //创建文件夹
140. try
141. //创建临时文件
142. "recording", ".3gp", fpath);
143. catch
144. // TODO Auto-generated catch block
145. e.printStackTrace();
146. }
147.
148. recorder.setOutputFile(audioFile.getAbsolutePath());
149.
150. //下面就开始录制了
151. try
152. recorder.prepare();
153. catch
154. // TODO Auto-generated catch block
155. e.printStackTrace();
156. catch
157. // TODO Auto-generated catch block
158. e.printStackTrace();
159. }
160.
161. recorder.start();
162.
163. "正在录制");
164. false);
165. false);
166. true);
167.
168. break;
169. case
170. recorder.stop();
171. recorder.release();
172.
173. //然后我们可以将我们的录制文件存储到MediaStore中
174. new
175. "this is my first record-audio");
176. values.put(MediaStore.Audio.Media.DATE_ADDED, System.currentTimeMillis());
177. values.put(MediaStore.Audio.Media.DATA, audioFile.getAbsolutePath());
178. this.getContentResolver().insert(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, values);
179. //录制结束后,我们实例化一个MediaPlayer对象,然后准备播放
180. new
181. new
182.
183. @Override
184. public void
185. //更新状态
186. "准备录制");
187. true);
188. true);
189. false);
190. }
191. });
192.
193. //准备播放
194. try
195. player.setDataSource(audioFile.getAbsolutePath());
196. player.prepare();
197. catch
198. // TODO Auto-generated catch block
199. e.printStackTrace();
200. catch
201. // TODO Auto-generated catch block
202. e.printStackTrace();
203. catch
204. // TODO Auto-generated catch block
205. e.printStackTrace();
206. }
207.
208. //更新状态
209. "准备播放");
210. true);
211. true);
212. false);
213. break;
214. case
215. //播放录音
216. //注意,我们在录音结束的时候,已经实例化了MediaPlayer,做好了播放的准备
217. player.start();
218. //更新状态
219. "正在播放");
220. false);
221. false);
222. false);
223.
224. //在播放结束的时候也要更新状态
225. break;
226. case
227. //完成录制,返回录制的音频的Uri
228. new
229. intent.setData(fileUri);
230. this.setResult(RESULT_OK, intent);
231. this.finish();
232. break;
233.
234. }
235. }
236. }
AudioRecord类相对于MediaRecorder来说,更加接近底层,为我们封装的方法也更少。然而实现一个AudioRecord的音频录制程序也很
简单。本实例代码如下:
可惜,本实例测试时有个问题,在录制的时候,会出现buffer over。缓存泄露,待解决。
1. package
2. import
3. import
4. import
5. import
6. import
7. import
8. import
9. import
10. import
11. import
12. import
13. import
14. import
15. import
16. import
17. import
18. import
19. import
20. import
21. import
22. import
23. import
24. import
25. import
26. import
27. import
28. import
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
66.
67. private
68.
69. private
70.
71. private
72. private
73.
74. private
75.
76. private boolean isRecording=true, isPlaying=false; //标记
77.
78. private int frequence = 8000; //录制频率,单位hz.这里的值注意了,写的不好,可能实例化AudioRecord对象的时候,会出错。我开始写成11025就不行。这取决于硬件设备
79. private int
80. private int
81.
82.
83. public void
84. super.onCreate(savedInstanceState);
85. setContentView(R.layout.my_audio_record);
86.
87. this.findViewById(R.id.view_state);
88. "准备开始");
89. this.findViewById(R.id.btn_start);
90. this.findViewById(R.id.btn_stop);
91. this.findViewById(R.id.btn_play);
92. this.findViewById(R.id.btn_finish);
93. "停止播放");
94. false);
95. false);
96. false);
97.
98. //在这里我们创建一个文件,用于保存录制内容
99. new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/data/files/");
100. //创建文件夹
101. try
102. //创建临时文件,注意这里的格式为.pcm
103. "recording", ".pcm", fpath);
104. catch
105. // TODO Auto-generated catch block
106. e.printStackTrace();
107. }
108. }
109.
110.
111. public void
112. int
113. switch(id){
114. case
115. //开始录制
116.
117. //这里启动录制任务
118. new
119. recorder.execute();
120.
121. break;
122. case
123. //停止录制
124. this.isRecording = false;
125. //更新状态
126. //在录制完成时设置,在RecordTask的onPostExecute中完成
127. break;
128. case
129.
130. new
131. player.execute();
132. break;
133. case
134. //完成播放
135. this.isPlaying = false;
136. break;
137.
138. }
139. }
140.
141. class RecordTask extends
142. @Override
143. protected
144. true;
145. try
146. //开通输出流到指定的文件
147. new DataOutputStream(new BufferedOutputStream(new
148. //根据定义好的几个配置,来获取合适的缓冲大小
149. int
150. //实例化AudioRecord
151. new
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. new Integer(r)); //向UI线程报告当前进度
169. //自增进度值
170. }
171. //录制结束
172. record.stop();
173. "The DOS available:", "::"+audioFile.length());
174. dos.close();
175. catch
176. // TODO: handle exception
177. }
178. return null;
179. }
180.
181. //当在上面方法中调用publishProgress时,该方法触发,该方法在UI线程中被执行
182. protected void
183. 0].toString());
184. }
185.
186. protected void
187. false);
188. true);
189. true);
190. false);
191. }
192.
193. protected void
194. //stateView.setText("正在录制");
195. false);
196. false);
197. false);
198. true);
199. }
200.
201. }
202.
203. class PlayTask extends
204. @Override
205. protected
206. true;
207. int
208. short[] buffer = new short[bufferSize/4];
209. try
210. //定义输入流,将音频写入到AudioTrack类中,实现播放
211. new DataInputStream(new BufferedInputStream(new
212. //实例AudioTrack
213. new
214. //开始播放
215. track.play();
216. //由于AudioTrack播放的是流,所以,我们需要一边播放一边读取
217. while(isPlaying && dis.available()>0){
218. int i = 0;
219. while(dis.available()>0
220. buffer[i] = dis.readShort();
221. i++;
222. }
223. //然后将数据写入到AudioTrack中
224. 0, buffer.length);
225.
226. }
227.
228. //播放结束
229. track.stop();
230. dis.close();
231. catch
232. // TODO: handle exception
233. }
234. return null;
235. }
236.
237. protected void
238. true);
239. false);
240. true);
241. false);
242. }
243.
244. protected void
245.
246. //stateView.setText("正在播放");
247. false);
248. false);
249. false);
250. true);
251. }
252.
253. }
254. }