失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 通话录音自动上传功能

通话录音自动上传功能

时间:2018-12-13 01:17:51

相关推荐

通话录音自动上传功能

需求:项目中有一期需要做通话录音自动上传功能需求。订单详情页面,用户拨打电话以后,自动将通话录音上传到云端服务器。原来的方式是通话完成,用户从本地文件夹中选择对应的录音文件,然后上传云端。因为业务人员感觉这个操作比较麻烦,因此希望能够自动上传通话录音。

调研: 自动上传通话录音功能包括两个方面:

1)通话录音的采集:用户拨打电话时,采集通话录音。这需要监听用户拨打订单电话的状态,包括电话的接通和挂断;

2)通话录音自动上传:通话结束后,将采集到的订单通话录音文件上传服务器。

这通话录音的采集有两种方案:

1)应用自身采集,这样能够无差错的建立起订单和通话录音文件的映射关系。

2)系统采集,然后抓取对应的通话录音文件。因为录音文件的生成是有系统负责,应用本身并不能进行控制。 这有一个问题:不同的系统,通话录音的保存路径不一样,录音文件的命名规则也不相同,不能够针对所有类型的设备进行处理,可以对一些特殊的设备进行处理。当然还存在安全性问题,不能准确无误的建立起订单和录音文件的映射关系。

实现:

因为方案一是一个通用方案,因此采用方案一方式实现。

1)监听用户的通话

/*** 启动通话监听*/private void startCallListener() {if (isRooted || isMIUI) {//获得电话管理器manager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);//为管理器设置监听器,监听电话的呼叫状态phoneListener = new MyPhoneListener();manager.listen(phoneListener, PhoneStateListener.LISTEN_CALL_STATE);}}

通话监听器:

/*** 电话监听器* 说明: 监听双向通话*/private class MyPhoneListener extends PhoneStateListener {public void onCallStateChanged(int state, String incomingNumber) {if(TextUtils.isEmpty(incomingNumber)) {return;}switch (state) {case TelephonyManager.CALL_STATE_RINGING://来电振动LogUtils.d(TAG, "CALL_STATE_RINGING:" + incomingNumber);break;case TelephonyManager.CALL_STATE_OFFHOOK:LogUtils.d(TAG, "CALL_STATE_OFFHOOK:" + incomingNumber); // 当接通电话开始通话时 可以进行录音if (null != callRecordEvent&& Utils.GetStringNoNil(callRecordEvent.phone).equals(incomingNumber)) {//检查是否需要进行通话录音(只有订单通话才记录通话录音)recordStartTime = System.currentTimeMillis();phoneNumber = incomingNumber.replace(" ", "");LogUtils.d(TAG, "onCallStateChanged recordStartTime:" + TimeUtil.format(TimeUtil.FORMAT_YYYY_MM_DD_HH_MM_SS, recordStartTime) + " phoneNumber: " + phoneNumber);handler.sendEmptyMessage(MSG_START_CALL_RECORD);}break;case TelephonyManager.CALL_STATE_IDLE:LogUtils.d(TAG, "CALL_STATE_IDLE:" + incomingNumber);//挂断电话时停止录音handler.sendEmptyMessage(MSG_STOP_CALL_RECORD);if (null != callRecordEvent && !TextUtils.isEmpty(incomingNumber)) {recordStopTime = System.currentTimeMillis();//录音文件事件复位等待下一次操作callRecordEvent.phone = "";//记录通话结束的手机号phoneNumber = incomingNumber.replace(" ", "");LogUtils.d(TAG, "onCallStateChanged recordStopTime:" + TimeUtil.format(TimeUtil.FORMAT_YYYY_MM_DD_HH_MM_SS, recordStopTime) + " phoneNumber: " + phoneNumber);}break;}}}

2)监听到用户启动通话接通时,开始启动通话录音:

/*** 启动通话录音* 说明: 只有Root设备才能启动通话录音功能*/private void startCallRecord() {if (isRooted && !startFlag) {// 创建录音器createMediaRecorder();// 开始记录录音startRecording();}}

创建录音器:

/*** 创建录音器对象*/private void createMediaRecorder() {//1) Create MediaRecordermRecorder = new MediaRecorder();// Set audio and video source and encodertry { //1代表单声道,2代表双声道(立体声)mRecorder.setAudioChannels(2); //2) 这两项需要放在setOutputFormat之前mRecorder.setAudioSource(MediaRecorder.AudioSource.VOICE_CALL);} catch (Exception e) {e.printStackTrace();}try { //3) Set output file format(mp4格式)mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);} catch (Exception e) {e.printStackTrace();}try { //4) 这两项需要放在setOutputFormat之后mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);} catch (Exception e) {e.printStackTrace();}// Set output file path //初始化缓存目录createOutputFile();try { //设置输出文件路径mRecorder.setOutputFile(audioPath);} catch (Exception e) {e.printStackTrace();}}

开始通话录音

/*** 开始录音*/private void startRecording() {LogUtils.d(TAG, "bf mRecorder.prepare()");try {mRecorder.prepare();} catch (Exception e) {e.printStackTrace();}LogUtils.d(TAG, "af mRecorder.prepare()");try {LogUtils.d(TAG, "bf mRecorder.start()");mRecorder.start(); // Recording is now started} catch (Exception e) {e.printStackTrace();//启动出错if(!isMIUI){//MIUI支持录音文件抓取ToastUtils.showToast(this, R.string.audio_start_failed, Toast.LENGTH_SHORT);}handler.sendEmptyMessage(MSG_START_CALL_RECORD_FAILED);return;}//设置标签: 已经启动通话录音startFlag = true;LogUtils.d(TAG, "af mRecorder.start()");LogUtils.d(TAG, "Start recording ...");}

3)通话结束时停止通话录音开始上传

/*** 结束通话录音* 说明: 如果自动录音成功优先使用自动录音;* 如果自动录音启动失败,且是小米系统,可以尝试抓取录音文件进行上传* (1、有些手机未Root权限判断为已经Root;2、系统自身已经开启通话录音导致自动录音失败)。*/private void stopCallRecord() {if (isRooted && startFlag) { //如果是Root设备查找自我录音的文件// (通话录音开启成功时使用自动录音的文件;否则使用小米手机的通话录音)//停止录音设备stopMediaRecorder();//录音文件是非空的录音文件if (FileHelper.getFileSize(audioPath) > 0) { //录音结束开始启动通话录音文件上传handler.sendEmptyMessage(MSG_UPLOAD_CALL_RECORD);} else {//空文件删除FileHelper.deleteFile(audioPath);}// Set button status flagstartFlag = false;} else if (isMIUI) { //MIUI系统设备有自动通话录音功能抓取对应的通话录音文件if(null != callRecordEvent) {//只有在贷后自动录音处理才抓取录音文件startFilterAudioFile(phoneNumber, recordStartTime,callRecordEvent.son_order_id);}}}

产生问题:程序安装后,发现有的手机运行没有问题,有的手机运行录音一直不成功,录音文件大小为0。是什么原因导致录音不成功呢?

通话录音是一种比较危险权限,系统未Root时,除了系统自身授权,其他的应用是无法获取到这种权限的。

因此即使看到应用已经授权录音权限,如果手机未Root,自己采集通话录音不能成功。红米Note4是稳定版的系统,

因此应用不能采集到通话录音。

出现这种情况,有两种解决方案:

方式一:将手机Root。这是一种比较危险的操作。

方式二:应用不进行录音,有系统录音,应用抓取系统的录音文件进行上传。

对于未Root的手机,采用方式二进行处理。工作人员使用的手机是红米手机。小米手机的通话录音文件,

保存在一个固定的目录:

内存目录/MIUI/sound_recorder/call_rec,可以从目录中抓取通话录音文件。

小米手机通话录音文件的保存的文件名也很有特征:通话录音@手机号xxx_时间串.mp3,

我们可以根据手机号+时间串来抓取对应的通话录音文件。

/*** 从小米文件夹中抓取对应的录音文件** @param phoneNumber: 手机号* @param recordStartTime : 录音文件开始时间* @param son_order_id : 订单ID*/private void startFilterAudioFile(final String phoneNumber, final long recordStartTime,String son_order_id) {if (TextUtils.isEmpty(phoneNumber) || TextUtils.isEmpty(son_order_id)) {//手机号或者订单号不存在不需要上传return;}//首先检查录音文件保存目录是否存在if (!FileHelper.fileIsExists(Config.callRecordDir)) {//对应的录音文件夹不存在return;}//抓取对应的录音文件(手机号+通话开始时间)File dir = new File(Config.callRecordDir);if (!dir.isDirectory()) {return;}//获取其中的子文件列表File[] files = dir.listFiles(new FileFilter() {@Overridepublic boolean accept(File pathname) {if (pathname.isDirectory()) {//子文件夹不处理return false;}//检测录音文件有效性if (pathname.length() <= 0) {//删除空白文件FileHelper.deleteFile(pathname.getPath());return false;}//过滤文件名日志String simpleName = pathname.getName();//去掉所有的空格字符simpleName = simpleName.replace(" ", "");if (!simpleName.contains(phoneNumber)) {return false;}//过滤文件名中的时间String dateStr = parseDate(simpleName);if(TextUtils.isEmpty(dateStr)) {return false;}//最早的时间Date fileDate = DateUtils.strToDate(dateStr, TimeUtil.FORMAT_NO_SPLIT_YYYY_MM_DD_CHS_HH_MM_SS);//录音文件时间一定在录音开始时间和录音结束时间的监听范围内long fileTime = fileDate.getTime();return fileTime >= 0 && fileTime >= recordStartTime && fileTime <= recordStopTime;}});if (null == files || files.length <= 0) {//未找到符合条件的文件return;}//有多个文件符合条件时优先查找文件名刚好一致的文件File destFile = null;if(files.length > 1) {//如果有多个文件符合条件优先获取时间刚好相同的文件String str = TimeUtil.format(TimeUtil.FORMAT_NO_SPLIT_YYYY_MM_DD_CHS_HH_MM_SS, recordStartTime);for (File file : files) {if(file.getName().contains(str)) {//找到一个完全匹配的文件destFile = file;break;}}} //如果没有找到完全匹配的文件默认采用过滤文件列表中第一个if(null == destFile) {destFile = files[0];} //开始上传录音文件startUploadFile(destFile.getPath(), son_order_id);}

这样,对于未Root的小米手机,也能够实现自动抓取通话录音文件了。

总结:对于功能开发,首先需要从安全型方面考虑,权限方面需要优先考虑。

如果觉得《通话录音自动上传功能》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。