android实现通话录音获取上传实现过程记录。_android软电话实现通话录音-程序员宅基地

技术标签: android通话录音  android录音  

项目里提了一个需求,需要通话录音功能(录制双方的声音),并上传到后台。(软件是内部人员工作使用不涉及个人隐私)

首先想到的肯定是用APP来进行录音,可控性比较高,测试了android自带的MediaRecorder与AudioRecord结果发现都只能录到呼叫方的声音,查找资料发现录音的来源中有一个MediaRecorder.AudioSource.VOICE_CALL可以录制双方声音,不过5.1以后已经被修改为系统应用才可以使用。

嗯....爆炸

然后发现一款叫ec的软件号称可以实现双方录音并上传。(拥有企鹅投资的公司应该比较牛)

赶紧下载下来体验一下,发现第一次在软件内拨打电话会提示去开启通话录音功能,点击去开启的话就会跳转到拨号界面。

然后我没开 直接测试打电话,挂断,在列表里查看,没有发现录音文件,然后问客服,客服说要手动打开手机的通话的自动录音功能。

emmm 这这这 好吧 手动去打开了通话自动录音功能,再测试,确实会有录音文件出现在列表。

分析一下这个实现原理,录音是靠手机自动的通话录音,然后找到这个录音文件上传。(这也太敷衍了,不过既然这大公司也只能用这种方案,估计就没有其他好的方案了。)

那我们也按照他的实现方式来做。

首先想到有没有系统api可以检测通话录音功能是否打开呢?

emmm 这个目前网上也没找到有相关文章介绍可以通过系统的api去检测的,所以走系统api检查的方案不可行。

既然没有api可以检测那只能找其它途径了,突然想到是否可以从有录音文件这个方向入手呢,嗯 好像还不错,如果通话结束后有录音文件那就是开了通话录音功能,没有就是没开。

那么问题又来了,这个录音文件该怎么找它的路径呢?

因为不会逆向没办法看ec的实现方案,那就自己想,是不是可以通过固定的文件目录来找到这个文件呢?

开始测试

第一次用华为的nova3 开了通话录音然后去查看文件的目录发现是在根目录/Sounds/CallRecord/目录下

第二次用华为的荣耀畅玩6开了通话录音然后去查看文件的目录发现是在根目录/record/目录下

emmm 同一个厂家不同型号的存储位置都不一样 那不得一台一台去判断了?而且一台台适配的话,手机资源也没这么多(没钱)。这个方案不行。(当然ec是可以做到的,毕竟有企鹅投资,资金不是问题)

那继续观察,咦 发现一个点 录音文件名后面都会包含一个日期 格式年月日时分秒(yyyyMMddHHmmss)

这样是不是肯定可以这个去适配呢?

但是又有一个问题怎么让这个文件名的时间跟这通电话关联起来呢?

发现通话记录表有个CallLog.Calls.DATE字段是long类型。那这个时间是不是跟文件名有关联呢?

继续测试

拿华为的nova3与荣耀畅玩6 读取拨打结束对应号码的date字段转换成yyyyMMddHHmmss格式与录音文件对比发现

竟然是一致的,那不就可以拿这个时间去匹配对应的文件了?(高兴了一波,事实证明没这么简单)

然后我又拿了一台vivo手机去测试,结果发现录音文件名后面的日期格式变成了(yyyy-MM-dd HH-mm-ss) 

而且读取的通话记录里的data字段转换过来跟录音文件名后面的日期也对应不上。FU

emmm,方案又失败了(跟前面一样需要一台台适配)

极端方案(目前项目里使用的能比较大程度上保证获取准确的录音文件,目前不能说100%吧)

首先知道录音文件的后缀名,一般是.amr .wav .aac .mp3 当然这些只是主流的 不排除一些特别的,所以最好做成后台配置规则的方式去处理。

然后去扫描SD卡所有文件,由于全部扫描非常耗时,所以目录也做了相应的匹配规则(例如包含RECORD,SOUND,录音),也做成后台配置。

public static List<File> searchFiles(File folder) {
    List<File> result = new ArrayList<>();
    if (folder.isFile())
        result.add(folder);
    File[] subFolders = folder.listFiles(new FileFilter() {
        @Override
        public boolean accept(File file) {
            if (file.isDirectory()&&checkFileName(file.getName())) {
                return true;
            }
            if (checkFileNameEnd(file.getName())) {
                return true;
            }
            return false;
        }
    });
    if (subFolders != null) {
        for (File file : subFolders) {
            if (file.isFile()) {
                // 如果是文件则将文件添加到结果列表中
                result.add(file);
            } else {
                // 如果是文件夹,则递归调用本方法,然后把所有的文件加到结果列表中
                result.addAll(searchFiles(file));
            }
        }
    }
    return result;
}
//匹配目录规则
private static boolean checkFileName(String name){
    String[] rule=App.getApp().getFileNameRule().split(",");
    for (String string:rule){
        if(name.toUpperCase().contains(string)){
            return true;
        }
    }
   return false;
}
//匹配后缀规则
private static boolean checkFileNameEnd(String name){
    String[] rule=App.getApp().getFileNameEndRule().split(",");
    for (String string:rule){
        if(name.toLowerCase().contains(string)){
            return true;
        }
    }
    return false;
}

从上面的函数中获取到了符合规则的文件列表然后,获取修改时间是最新的文件。

//获取修改时间是最新的文件
public static File getLastFile(List<File> files){
    File myfile=null;
    long fileTime=0;
    for (File file:files){
        if(file.lastModified()>fileTime){
            myfile=file;
            fileTime=file.lastModified();
        }
    }
    return myfile;
}

然后还要检测这个文件跟目前这个通话的时间上不能差距太大,我发现vivo的通话记录的date跟录音文件名后面的日期大概差了0-20s左右不固定,所以写了个一分钟的区间。当然你可以根据更多的测试去把这个区间调的更加准确。

然后在项目中监听通话状态挂断的时候可以保存一个时间戳,用保存的时间戳与前面获取到的文件的最后修改时间进行比较,测试发现误差在1秒左右,为了防止可能卡顿的情况所以给个5秒应该算是比较精确的了。

//检测这个文件是否符合要求
//time是从监听通话挂断时记录的时间戳。
public static boolean checkFile(File file,long time){
    return Math.abs(time-file.lastModified())<5*1000;
}

这样大部分都可以兼容了,目录与后缀名规则可以在测试过程中通过后台不断添加完善。

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/zpswz/article/details/97141010

智能推荐

linux下编译GDAL外加扩展格式支持(五)--完-程序员宅基地

文章浏览阅读229次。接1、2、3、4篇。10、安装mysql支持安装fedora15或者16系统时若选择安装mysql数据库,则必须自行安装mysql开发包。因为自带默认数据库不会安装这个包。否则会遇到mysql错误:ogr_mysql.h:34:23: fatal error: my_global.h: No such file or directory#问题原因:找不到mysql头文件..._linux gdal netcdf5

Linux tc qdisc 模拟网络丢包延时-程序员宅基地

文章浏览阅读1.2k次。Linux tc qdisc 模拟网络丢包延时_tc qdisc

linux64bit 安装 jdk 1.7-程序员宅基地

文章浏览阅读336次。linux64bit 安装 jdk 1.7下载地址 : https://edelivery.oracle.com/otn-pub/java/jdk/7u21-b11/jdk-7u21-linux-x64.rpm0. 卸载rpm版的jdk: #rpm -qa|grep jdk 显示:jdk-1.6.0_10-fcs 卸载:#rpm -e --nodep..._liunx64位得jdk1.7

【Linux笔记】-----Nginx/LVS/HAProxy负载均衡的优缺点_中间件应用场景nginx lvs proxy-程序员宅基地

文章浏览阅读552次。开始听到负载均衡的时候,我第一反应想到的是链路负载均衡,在此之前主要是在学习网络方面知识,像在NA、NP阶段实验做链路负载均衡时常会遇到,后来还接触到SLB负载分担技术,这都是在链路基础上实现的。 其实负载均衡可以分为硬件实现负载均衡和软件实现负载均衡。 硬件实现负载均衡:常见F5和Array负载均衡器,配套专业维护服务,但是成本昂贵。 软件实现负载均衡:常见开源免费的负载均衡软件有Ngin..._中间件应用场景nginx lvs proxy

多维时序 | MATLAB实现CNN-LSTM多变量时序预测_cnn可以进行多步预测-程序员宅基地

文章浏览阅读4.7k次。多维时序 | MATLAB实现CNN-LSTM多变量时序预测目录多维时序 | MATLAB实现CNN-LSTM多变量多步预测基本介绍模型特点程序设计学习总结参考资料基本介绍本次运行测试环境MATLAB2020b,MATLAB实现CNN-LSTM多变量多步预测。模型特点深度学习使用分布式的分层特征表示方法自动提取数据中的从最低层到最高层固有的抽象特征和隐藏不变结构. 为了充分利用单个模型的优点并提高预测性能, 现已提出了许多组合模型。CNN 是多层前馈神经网络, 已被证明在提取隐藏_cnn可以进行多步预测

随便推点

【9.3】用户和组的管理、密码_polkitd:input 用户和组-程序员宅基地

文章浏览阅读219次。3.1 用户配置文件和密码配置文件3.2 用户组管理3.3 用户管理3.4 usermod命令3.5 用户密码管理3.6 mkpasswd命令_polkitd:input 用户和组

pca算法python代码_三种方法实现PCA算法(Python)-程序员宅基地

文章浏览阅读670次。主成分分析,即Principal Component Analysis(PCA),是多元统计中的重要内容,也广泛应用于机器学习和其它领域。它的主要作用是对高维数据进行降维。PCA把原先的n个特征用数目更少的k个特征取代,新特征是旧特征的线性组合,这些线性组合最大化样本方差,尽量使新的k个特征互不相关。关于PCA的更多介绍,请参考:https://en.wikipedia.org/wiki/Prin..._inprementation python code of pca

内存地址Linux下内存分配与映射之一-程序员宅基地

文章浏览阅读35次。发一下牢骚和主题无关:地址类型:32位的cpu,共4G间空,其中0-3G属于用户间空地址,3G-4G是内核间空地址。用户虚拟地址:用户间空程序的地址物理地址:cpu与内存之间的用使地址总线地址:外围总线和内存之间的用使地址内核逻辑地址:内存的分部或全体射映,大多数情况下,它与物理地址仅差一个偏移量。如Kmalloc分..._linux 内存条与内存地址

自动化测试介绍_自动化测试中baw库指的什么-程序员宅基地

文章浏览阅读1.3k次,点赞2次,收藏16次。什么是自动化测试?   做测试好几年了,真正学习和实践自动化测试一年,自我感觉这一个年中收获许多。一直想动笔写一篇文章分享自动化测试实践中的一些经验。终于决定花点时间来做这件事儿。  首先理清自动化测试的概念,广义上来讲,自动化包括一切通过工具(程序)的方式来代替或辅助手工测试的行为都可以看做自动化,包括性能测试工具(loadrunner、jmeter),或自己所写的一段程序,用于_自动化测试中baw库指的什么

a0图框标题栏尺寸_a0图纸尺寸(a0图纸标题栏尺寸标准国标)-程序员宅基地

文章浏览阅读1.6w次。A0纸指的是一平方米大小的白银比例长方形纸(长为1189mm宽为841mm)。A0=1189mm*841mm A1=841mm*594mm 相当于1/2张A0纸 A2=594mm*420mm 相当于1/4.A1图纸大小尺寸:841mm*594mm 即长为841mm,宽为594mm 过去是以多少"开"(例如8开或16开等)来表示纸张的大小,我国采用国际标准,规定以 A0、A1、A2、.GB/T 14..._a0图纸尺寸

TreeTable的简单实现_treetable canvas-程序员宅基地

文章浏览阅读966次。最终效果图:UI说明:针对table本身进行增强的tree table组件。 tree的数据来源是单元格内a元素的自定义属性:level和type。具体代码如下:Java代码 DepartmentEmployeeIDposi_treetable canvas