array(2) { ["docs"]=> array(10) { [0]=> array(10) { ["id"]=> string(3) "428" ["text"]=> string(77) "Visual Studio 2017 单独启动MSDN帮助(Microsoft Help Viewer)的方法" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(8) "DonetRen" ["tagsname"]=> string(55) "Visual Studio 2017|MSDN帮助|C#程序|.NET|Help Viewer" ["tagsid"]=> string(23) "[401,402,403,"300",404]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400964" ["_id"]=> string(3) "428" } [1]=> array(10) { ["id"]=> string(3) "427" ["text"]=> string(42) "npm -v;报错 cannot find module "wrapp"" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "zzty" ["tagsname"]=> string(50) "node.js|npm|cannot find module "wrapp“|node" ["tagsid"]=> string(19) "[398,"239",399,400]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400760" ["_id"]=> string(3) "427" } [2]=> array(10) { ["id"]=> string(3) "426" ["text"]=> string(54) "说说css中pt、px、em、rem都扮演了什么角色" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(12) "zhengqiaoyin" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400640" ["_id"]=> string(3) "426" } [3]=> array(10) { ["id"]=> string(3) "425" ["text"]=> string(83) "深入学习JS执行--创建执行上下文(变量对象,作用域链,this)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "Ry-yuan" ["tagsname"]=> string(33) "Javascript|Javascript执行过程" ["tagsid"]=> string(13) "["169","191"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511399901" ["_id"]=> string(3) "425" } [4]=> array(10) { ["id"]=> string(3) "424" ["text"]=> string(30) "C# 排序技术研究与对比" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "vveiliang" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(8) ".Net Dev" ["catesid"]=> string(5) "[199]" ["createtime"]=> string(10) "1511399150" ["_id"]=> string(3) "424" } [5]=> array(10) { ["id"]=> string(3) "423" ["text"]=> string(72) "【算法】小白的算法笔记:快速排序算法的编码和优化" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "penghuwan" ["tagsname"]=> string(6) "算法" ["tagsid"]=> string(7) "["344"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511398109" ["_id"]=> string(3) "423" } [6]=> array(10) { ["id"]=> string(3) "422" ["text"]=> string(64) "JavaScript数据可视化编程学习(二)Flotr2,雷达图" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "chengxs" ["tagsname"]=> string(28) "数据可视化|前端学习" ["tagsid"]=> string(9) "[396,397]" ["catesname"]=> string(18) "前端基本知识" ["catesid"]=> string(5) "[198]" ["createtime"]=> string(10) "1511397800" ["_id"]=> string(3) "422" } [7]=> array(10) { ["id"]=> string(3) "421" ["text"]=> string(36) "C#表达式目录树(Expression)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "wwym" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(4) ".NET" ["catesid"]=> string(7) "["119"]" ["createtime"]=> string(10) "1511397474" ["_id"]=> string(3) "421" } [8]=> array(10) { ["id"]=> string(3) "420" ["text"]=> string(47) "数据结构 队列_队列实例:事件处理" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "idreamo" ["tagsname"]=> string(40) "C语言|数据结构|队列|事件处理" ["tagsid"]=> string(23) "["246","247","248",395]" ["catesname"]=> string(12) "数据结构" ["catesid"]=> string(7) "["133"]" ["createtime"]=> string(10) "1511397279" ["_id"]=> string(3) "420" } [9]=> array(10) { ["id"]=> string(3) "419" ["text"]=> string(47) "久等了,博客园官方Android客户端发布" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(3) "cmt" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511396549" ["_id"]=> string(3) "419" } } ["count"]=> int(200) } 222 【Android】录音暂停和继续 - 爱码网

Android自带的录音类MediaRecorder只有start和stop功能,既没有pause功能也没有seekto函数,所以我们要实现暂停功能需要自己动手。而暂停这个功能在很多地方是需要的,假设一个应用中有录音这个功能,那么当电话打来的时候就需要使用暂停功能,并且在打完电话之后恢复录音。(小米手机的原生录音功能是在打进来电话的时候停止录音)。

基本思想是,基于它只能开始和暂停(也有reset重置功能),那么我们只能在打进电话的同时调用stop方法,这个别无它法,然后我们要做的就是在电话打完恢复应用的时候就去重新开始一段录音,等用户点击保存的时候,合并所有的录音文件,这样就可以实现暂停和继续录音的功能。借鉴以下两篇博客以及自己的经验做出阐述如下:

博客一:AMR文件格式分析

博客二:Android MediaRecorder实现暂停断点录音功能

前一篇博客描述了AMR文件的格式,我们可以确定,AMR文件的前6个字节(也就是文件头)是一定一样的。

【Android】录音暂停和继续

这幅图最前面的额框就是文件头"#!AMR\n"的ASCII字符码,我在MAC上使用Vim命令同样可以看到该效果(包括换行),截图如下:

【Android】录音暂停和继续

左上角就是"#!AMR\n"的文件头,这里换行了。

到这里就很简单了,AMR文件的文件头很简单,什么都没有,而我们要做的就是读一个文件头,将所有文件的音频帧拼凑到一起,OK,继续。

 1     /** 合并所有的音频文件 */
 2     public void mergeAllAmrFiles(){ 
 3             // 创建音频文件,合并的文件放这里
 4               File tempFile = new File(recordingFiles.get(0));
 5               File mergeFile = new File(tempFile.getParent() + File.separator + Utils.QIDUO_AMR + ".amr");
 6               Log.d("RECORD", "MERGE : " + mergeFile.getAbsolutePath());
 7               FileOutputStream fileOutputStream = null;  
 8          
 9               if(!mergeFile.exists()){  
10                   try {  
11                       mergeFile.createNewFile();  
12                   } catch (IOException e){  
13                       // TODO Auto-generated catch block  
14                       e.printStackTrace();  
15                   }  
16               }
17       
18               try {  
19                   fileOutputStream=new FileOutputStream(mergeFile);  
20               } catch (IOException e) {  
21                   // TODO Auto-generated catch block  
22                   e.printStackTrace();  
23               } 
24               
25               //list里面为暂停录音 所产生的几段录音文件的名字,中间几段文件的减去前面的6个字节头文件  
26               for(int index = 0; index < recordingFiles.size(); index++){  
27                   File file=new File(recordingFiles.get(index));
28                   Log.d("RECORD-PATH", recordingFiles.get(index) + file.length());
29                   try {  
30                       FileInputStream fileInputStream=new FileInputStream(file);  
31                       byte  []myByte = new byte[fileInputStream.available()];
32                       //文件长度  
33                       int length = myByte.length;
34                       Log.d("RECORD-LENGTH", length  + "");
35         
36                       //头文件  
37                       if(index == 0){  
38                           while(fileInputStream.read(myByte) != -1){ 
39                               fileOutputStream.write(myByte);
40                               //fileOutputStream.write(myByte, 0,length);
41                           }
42                       }
43                       
44                       //之后的文件,去掉前面6个字节(头文件) 
45                       else{  
46                           while(fileInputStream.read(myByte) != -1){            
47                               fileOutputStream.write(myByte, 6, length - 6);  
48                           }
49                       }
50                 
51                       fileOutputStream.flush();
52                       fileInputStream.close();
53                       //合并之后删除文件
54                       //file.delete();
55                   } catch (Exception e) {  
56                       // TODO Auto-generated catch block  
57                       e.printStackTrace();  
58                   }  
59               }  
60               
61               //结束后关闭流 
62               try {
63                   fileOutputStream.flush();
64                   fileOutputStream.close();  
65               } catch (IOException e) {  
66                   // TODO Auto-generated catch block  
67                   e.printStackTrace();  
68               }
69               
70               mSampleFile = mergeFile;//指向它,以便获取地址
71         }

如上代码,我们将除第一个文件的其余amr文件的文件头全部去掉,拼凑在一起即可实现需要的功能。

注意点:

1   mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
2   mRecorder.setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR);//
3   mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);

OutputStream一定要设置为"RAW_AMR"类型,THREE_GPP是一定不可以的!(文件格式完全不一样,需要重新考察文件头)

相关文章: