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 searchFiles(File folder) {
    List 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 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;
}

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

 

你可能感兴趣的:(android通话录音,android录音)