虽然在Android5.0之前在AudioRecord开放给第三方的初始化方法中VOICE_CALL音频源是可以使用的,但是在厂商的适配过程中很多还是不能用,因此在低版本中一直是通过AudioRecord读取MIC录音源实现。
很多厂商在做系统优化时,使用MIC仍然无法通话录音,所以要完美实现可以通过读取其他软件甚至是使用系统自带的拨号软件进行全局通话录音后再读取上传。
首先对几种录音方案进行分析:
1.软件集成录音:
一般是使用AudioRecord读取MIC或者VOICE_CALL音频源进行录音
缺点:
- 受安卓版本影响较大
- 需要保证软件正常运行
优点:
- MP3格式,1分钟60KB
2.ACR
ACR时谷歌商店最好的通话录音软件,在低版本中它也是使用以上方式录音,在大部分Android5.0+手机上仍能录音的方式不得而知
缺点:
- 受安卓版本影响较大
- 需要附加安装应用
- 需要保证软件在通话时正常运行
- 无法直接录制MP3格式音频文件大,1分钟200KB
- 无法剪切拨号时未接通的空白音
- 需要间接读取录音文件
优点:
- 在某些高版本可用
3.MIUI拨号自带录音
系统自带,只需要打开全局录音开发开关即可
缺点:
- 需要打开全局录音开关
- 需要销售拨打电话时不关闭录音
- 需要间接读取录音文件
优点:
- 所有MIUI手机都可用
- mp3格式,1分钟60KB
- 系统应用,不受CRM是否运行影响
针对以上分析,对三种方案都做了集成,对使用第三方录音的代码分享如下:
ACR录音读取分析:
ACR录音文件存放于sdcard/ACRCalls目录,文件格式如下:
1d20170330120101p10010.m4a
录音类型d录音开始时间p录音号码.录音文件格式
相应正则:
^(\d)d(\d{14})p(\d*)\.\w+$
上代码:
/**
* 查找由ACR录音软件录制的通话录音,并继续流程
*
* @param isOutCall 是否为呼出电话
* @param phoneNumber 通话对方号码
* @param startTime 开始时间
* @param stopTime 结束时间
* @return 查找到的录音文件
*/
private static File findAcrRecordFile(boolean isOutCall, String phoneNumber, long startTime, long stopTime) {
String callType = isOutCall ? "1" : "0";
//时间容错范围
startTime = startTime - 1000;
stopTime = stopTime + 1000;
//acr默认录音目录
File fileDir = new File(Environment.getExternalStorageDirectory(), "ACRCalls");
if (fileDir.exists() && fileDir.isDirectory()) {
//筛选出指定号码,指定时间段内的录音
File[] records = fileDir.listFiles();
if (records.length <= 0) {
return null;
}
//先判断最后一个文件是否符合
File acrRecordFile = records[records.length - 1];
if (checkACRRecordFile(acrRecordFile, callType, phoneNumber, startTime, stopTime)) {
return acrRecordFile;
}
//不符合时遍历寻找
for (int i = 0; i < records.length; i++) {
acrRecordFile = records[i];
if (checkACRRecordFile(acrRecordFile, callType, phoneNumber, startTime, stopTime)) {
return acrRecordFile;
}
}
}
LogUtils.w(TAG, "未找到ACR录音文件");
return null;
}
private static boolean checkACRRecordFile(File srcFile, String callType, String phoneNumber, long startTime, long stopTime) {
if (srcFile == null || !srcFile.isFile()) {
return false;
}
//文件时间提取格式化
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA);
//判断文件是否为指定文件
String name = srcFile.getName();
String recordType = name.replaceAll("^(\\d)d(\\d{14})p(\\d*)\\.\\w+$", "$1");//通话类型(0:呼入;1:呼出)
String recordDate = name.replaceAll("^(\\d)d(\\d{14})p(\\d*)\\.\\w+$", "$2");//录音开始时间
String recordPhone = name.replaceAll("^(\\d)d(\\d{14})p(\\d*)\\.\\w+$", "$3");//录音号码
long recordTime = sdf.parse(recordDate, new ParsePosition(0)).getTime();
return (callType.equals(recordType) && recordTime > startTime && recordTime < stopTime && phoneNumber.equals(recordPhone));
}
读取MIUI通话录音
录音文件路径:sdcard/MIUI/sound_recorder/call_rec
通话录音@中国联通(10010)_20170330120101.mp3
相应正则:
^通话录音@[^()]+\((\d+)\)_(\d{14})\.mp3$
代码:
/**
* 查找由MIUI自带录音软件录制的通话录音,并继续流程
*
* @param phoneNumber 通话对方号码
* @param startTime 开始时间
* @param stopTime 结束时间
* @return 查找到的录音文件
*/
private static File findMIUIRecordFile(String phoneNumber, long startTime, long stopTime) {
//时间容错范围
startTime = startTime - 1000;
stopTime = stopTime + 1000;
//acr默认录音目录
File fileDir = new File(Environment.getExternalStorageDirectory(), "MIUI/sound_recorder/call_rec");
//筛选出指定号码,指定时间段内的录音
if (fileDir.exists() && fileDir.isDirectory()) {
File[] records = fileDir.listFiles();
LogUtils.e(TAG, records.toString());
if (records.length <= 0) {
return null;
}
//先判断最后一个文件是否符合
File acrRecordFile = records[records.length - 1];
if (checkMIUIRecordFile(acrRecordFile, phoneNumber, startTime, stopTime)) {
return acrRecordFile;
}
//不符合时遍历寻找
for (int i = 0; i < records.length; i++) {
acrRecordFile = records[i];
if (checkMIUIRecordFile(acrRecordFile, phoneNumber, startTime, stopTime)) {
return acrRecordFile;
}
}
}
LogUtils.w(TAG, "未找到MIUI录音文件");
return null;
}
private static boolean checkMIUIRecordFile(File srcFile, String phoneNumber, long startTime, long stopTime) {
if (srcFile == null || !srcFile.isFile()) {
return false;
}
//文件时间提取格式化
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA);
String name = srcFile.getName();
String recordDate = "";
String recordPhone = "";
if (name.matches("^通话录音@[^()]+\\((\\d+)\\)_(\\d{14})\\.mp3$")) {
recordDate = name.replaceAll("^通话录音@[^()]+\\((\\d+)\\)_(\\d{14})\\.mp3$", "$2");//录音开始时间
recordPhone = name.replaceAll("^通话录音@[^()]+\\((\\d+)\\)_(\\d{14})\\.mp3$", "$1");//录音号码
} else if (name.matches("^通话录音@(\\d+)_(\\d{14})\\.mp3$")) {
recordDate = name.replaceAll("^通话录音@(\\d+)_(\\d{14})\\.mp3$", "$2");//录音开始时间
recordPhone = name.replaceAll("^通话录音@(\\d+)_(\\d{14})\\.mp3$", "$1");//录音号码
}
long recordTime = sdf.parse(recordDate, new ParsePosition(0)).getTime();
return recordTime > startTime && recordTime < stopTime && phoneNumber.equals(recordPhone);
}