Android项目中媒体是很多人头疼的一个问题,不仅仅因为处理起来很麻烦,而且不同的手机差别很大(和硬件,系统都有关系),今天就总结一下Android中的录音和播放,可保存成mp3或amr格式。

小米1s,三星,酷派8721移动版 测试通过

1、首先说一下amr格式和mp3格式的区别

----------------------------------------------------------------------------------------------

amr由欧洲通信标准化委员会提出,是在移动通信系统中使用最广泛的语音标准。它是被各大手机厂商认可的一种保存手机录音的格式。由于amr文件容量很小,因此即便是长达一分钟的音频文件,也能符合中国移动现行的彩信不超过50KB容量的技术规范,所以amr也是实现在彩信中加载人声的唯一格式。但是受体积所限,amr在音质方面不太乐观。


mp3是一个实用的有损音频压缩编码,以此获得较高的压缩和较小的体积。


所以录音优先选择amr格式,微信生成的语音文件就是amr格式的。


2、录音播放的步骤

---------------------------------------------------------------------------------------

Android api中可以录音并播放的类主要有2个,一个是AudioRecord,另一个是MediaRecorder,这篇文章我们用AudioRecord,至于他们的区别,在什么情况下用那个,大家可以自行百度。

  1)实例化一个AudioRecord

  2)设置录音频率,录制通道,编码格式等参数

  3)设置录制缓存区大小

  4)创建一个文件,用于保存录制的内容

  5)打开一个流,指向创建的文件

  6)开始录制


先定义一些音频录制的参数

private boolean isRecording = true, isPlaying = false; // 标记private int frequence = 16000;// 8000;private int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;private int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;
在录制之前,先要判断一个sd卡是否存在:

if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))// 手机有SD卡的情况{// 在这里我们创建一个文件,用于保存录制内容fpath = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/test_record/");fpath.mkdirs();// 创建文件夹} else// 手机无SD卡的情况{//返回在文件系统上应用程序特定的缓存目录的绝对路径fpath = this.getCacheDir();}try {// 创建临时文件,注意这里的格式为.pcm  .amr  .mp3audioFile = File.createTempFile("recording", ".amr", fpath);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}


这儿我们将事先定义好的参数作为AudioRecord的构造方法的参数传递进去,你也可以先new一个AudioRecord对象,然后设置它的录制参数。

class RecordTask extends AsyncTask {@Overrideprotected Void doInBackground(Void... arg0) {isRecording = true;try {// 开通输出流到指定的文件DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(audioFile)));// 根据定义好的几个配置,来获取合适的缓冲大小int bufferSize = AudioRecord.getMinBufferSize(frequence,channelConfig, audioEncoding);// 实例化AudioRecordAudioRecord record = new AudioRecord(MediaRecorder.AudioSource.MIC, frequence,channelConfig, audioEncoding, bufferSize);// 定义缓冲short[] buffer = new short[bufferSize];// 开始录制record.startRecording();int r = 0; // 存储录制进度// 定义循环,根据isRecording的值来判断是否继续录制while (isRecording) {// 从bufferSize中读取字节,返回读取的short个数// 这里老是出现buffer overflow,不知道是什么原因,试了好几个值,都没用,TODO:待解决int bufferReadResult = record.read(buffer, 0, buffer.length);// 循环将buffer中的音频数据写入到OutputStream中for (int i = 0; i < bufferReadResult; i++) {dos.writeShort(buffer[i]);}publishProgress(new Integer(r)); // 向UI线程报告当前进度r++; // 自增进度值}// 录制结束record.stop();Log.v("The DOS available:", "::" + audioFile.length());dos.close();} catch (Exception e) {// TODO: handle exception}return null;}// 当在上面方法中调用publishProgress时,该方法触发,该方法在I线程中被执行protected void onProgressUpdate(Integer... progress) {stateView.setText(progress[0].toString());}protected void onPostExecute(Void result) {btnStop.setEnabled(false);btnStart.setEnabled(true);btnPlay.setEnabled(true);btnFinish.setEnabled(false);}protected void onPreExecute() {// stateView.setText("正在录制");btnStart.setEnabled(false);btnPlay.setEnabled(false);btnFinish.setEnabled(false);btnStop.setEnabled(true);}}

将音频录制的过程放到线程中取执行,然后更新ui给用户。接下来就是播放了,仍然在线程中播放

class PlayTask extends AsyncTask {@Overrideprotected Void doInBackground(Void... arg0) {isPlaying = true;int bufferSize = AudioTrack.getMinBufferSize(frequence,channelConfig, audioEncoding);short[] buffer = new short[bufferSize / 4];try {// 定义输入流,将音频写入到AudioTrack类中,实现播放DataInputStream dis = new DataInputStream(new BufferedInputStream(new FileInputStream(audioFile)));// 实例AudioTrackAudioTrack track = new AudioTrack(AudioManager.STREAM_MUSIC,frequence, channelConfig, audioEncoding, bufferSize,AudioTrack.MODE_STREAM);// 开始播放track.play();// 由于AudioTrack播放的是流,所以,我们需要一边播放一边读取while (isPlaying && dis.available() > 0) {int i = 0;while (dis.available() > 0 && i < buffer.length) {buffer[i] = dis.readShort();i++;}// 然后将数据写入到AudioTrack中track.write(buffer, 0, buffer.length);}// 播放结束track.stop();dis.close();} catch (Exception e) {// TODO: handle exception}return null;}protected void onPostExecute(Void result) {btnPlay.setEnabled(true);btnFinish.setEnabled(false);btnStart.setEnabled(true);btnStop.setEnabled(false);}protected void onPreExecute() {btnStart.setEnabled(false);btnStop.setEnabled(false);btnPlay.setEnabled(false);btnFinish.setEnabled(true);}}

到此一个音频录制,播放的demo就完成了,在对amr和mp3的格式进行比较时,分别录制了2段10分钟的视频,但是发现他们的大小是一样的?这就和我们上面说的矛盾了?其实不是,检查整个过程发现,生成音频文件的代码都是一样的,只是最终保存的格式不一样,它的大小肯定是一样的了,至于amr的文件的生成规则,没有做进一步的研究,但是肯定的是用它独特的方法生成的音频文件肯定要小,不然微信的录音也不会用amr的格式了。如果有人知道的话可以贴出来给大家分享。

更多相关文章

  1. 类加载器
  2. Android中Activity的初步接触(一)
  3. 如何在Android(安卓)Studio和eclipse中查看File Explorer视图(设
  4. android r cannot be resolved to a variable 错误以及 所有的文
  5. Android(安卓)Studio导入SlidingMenu类库的方法(其他类库应该也适
  6. Android中自动朗读(TTS)的简单使用
  7. 深入理解Android音频框架AudioTrack到AudioFlinger及Mix过程
  8. AndroidManifest.xml文件剖析
  9. Android(安卓)SDK作用和结构

随机推荐

  1. Android调用系统相册和相机选择图片并显
  2. 如何在Android上快速集成微信和QQ的分享(S
  3. 关于android双卡手机sim卡信息采集适配的
  4. Android版本适配(基于 6.0 ~ 9.0)
  5. Android有毒,三星或将打造独立生态圈
  6. android 6.0的DozeMode低功耗模式 及 引
  7. 调用Android原生裁剪方式裁剪图片并保存
  8. Android开发工程师:都想要进大厂,那么大公
  9. Android应用程序资源的查找过程分析
  10. 面试多家大厂被拒后,危险拿到网易offer,分