Android实现通话自动录音

作者:程思阳 时间:2021-08-29 20:33:35 

最近需要做一个类似于电话客户的功能,要求拨打电话能自动录音。所以写了一个dome,希望能够帮到大家。

主要思路就是监听手机通话状态在监听到接听时开始录音,结束停止录音。

Android实现通话自动录音

AndroidManifest中配置


<!-- 权限 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.WRITE_CALL_LOG" />
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />

当然了还要在清单文件中注册service


public abstract class CommonAdapter<T> extends BaseAdapter{

protected Context mContext;
protected List<T> mList;
protected int mLayoutId;

public CommonAdapter(Context context, List<T> list, int layoutId) {
 mContext=context;
 mList=list;
 mLayoutId=layoutId;
}

//刷新数据
public void refresh(List<T> list){
 mList=list;
 notifyDataSetChanged();
}

@Override
public int getCount() {
 return mList.size();
}

@Override
public T getItem(int position) {
 return mList.get(position);
}

@Override
public long getItemId(int position) {
 return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
 ViewHolder holder = ViewHolder.getHolder(mContext, mLayoutId, convertView, parent);
 convertView(holder,mList.get(position));
 return holder.getConvertView();
}

public abstract void convertView(ViewHolder holder,T t);
}

public class RBOutPhoneCallState {

Context ctx;

public RBOutPhoneCallState(Context ctx) {
 this.ctx = ctx;
}

/**
 * 前台呼叫状态
 *
 */
public static final class ForeGroundCallState {
 public static final String DIALING =  
   "com.sdvdxl.phonerecorder.FORE_GROUND_DIALING";
 public static final String ALERTING =  
   "com.sdvdxl.phonerecorder.FORE_GROUND_ALERTING";
 public static final String ACTIVE =  
   "com.sdvdxl.phonerecorder.FORE_GROUND_ACTIVE";
 public static final String IDLE =  
   "com.sdvdxl.phonerecorder.FORE_GROUND_IDLE";
 public static final String DISCONNECTED =  
   "com.sdvdxl.phonerecorder.FORE_GROUND_DISCONNECTED";
}

/**
 * 开始监听呼出状态的转变,
 * 并在对应状态发送广播
 */
public void startListen() {
 new RBReadPhoneLog(ctx).start();
 Log.d("Recorder", "开始监听呼出状态的转变,并在对应状态发送广播");
}

}

public class RBPhoneListener extends PhoneStateListener {

public RBRecorder recorder;

@Override  
public void onCallStateChanged(int state, String incomingNumber) {  
 super.onCallStateChanged(state, incomingNumber);  

switch (state) {  
 case TelephonyManager.CALL_STATE_IDLE: // 空闲状态,即无来电也无去电  
  Log.i("TelephoneState", "IDLE");

//此处添加一系列功能代码
  if (recorder != null && !recorder.isCommingNumber() && recorder.isStarted()) {

Log.i("TelephoneState", "STOP RECORDER");
   recorder.stop();
  }

break;  
 case TelephonyManager.CALL_STATE_RINGING: // 来电响铃  
  Log.i("TelephoneState", "RINGING");  
  //此处添加一系列功能代码
  break;  
 case TelephonyManager.CALL_STATE_OFFHOOK: // 摘机,即接通
  Log.i("TelephoneState", "OFFHOOK");  
  //此处添加一系列功能代码

if (recorder == null) {
   recorder = new RBRecorder();
  }

if (!recorder.isStarted()) {
   Log.i("TelephoneState", "START RECORDER");
   if (incomingNumber != null && incomingNumber.length() >= 8) {
    //CALLID
    recorder.setPhoneNumber(String.valueOf(incomingNumber));
   }

if (!recorder.isCommingNumber() && !recorder.isStarted()) {
    recorder.start();
   }
  }

break;  
 }  

Log.i("TelephoneState", String.valueOf(incomingNumber));  
}  
}

public class RBReadPhoneLog extends Thread {
private Context ctx;
private int logCount;

private static final String TAG = "LogInfo OutGoing Call";

/**
 * 前后台电话
 *  
 */
private static class CallViewState {
 public static final String FORE_GROUND_CALL_STATE = "mForeground";
}

/**
 * 呼叫状态  
 *
 */
private static class CallState {
 public static final String DIALING = "DIALING";
 public static final String ALERTING = "ALERTING";
 public static final String ACTIVE = "ACTIVE";
 public static final String IDLE = "IDLE";
 public static final String DISCONNECTED = "DISCONNECTED";
}

public RBReadPhoneLog(Context ctx) {
 this.ctx = ctx;
}

/**
 * 读取Log流
 * 取得呼出状态的log
 * 从而得到转换状态
 */
@Override
public void run() {
 Log.d(TAG, "开始读取日志记录");

String[] catchParams = {"logcat", "InCallScreen *:s"};
 String[] clearParams = {"logcat", "-c"};

try {
  Process process=Runtime.getRuntime().exec(catchParams);
  InputStream is = process.getInputStream();
  BufferedReader reader = new BufferedReader(new InputStreamReader(is));

String line = null;
  while ((line=reader.readLine())!=null) {
   logCount++;
   //输出所有
  Log.v(TAG, line);

//日志超过512条就清理
   if (logCount>512) {
    //清理日志
    Runtime.getRuntime().exec(clearParams)
     .destroy();//销毁进程,释放资源
    logCount = 0;
    Log.v(TAG, "-----------清理日志---------------");
   }  

/*---------------------------------前台呼叫-----------------------*/
   //空闲
   if (line.contains(RBReadPhoneLog.CallViewState.FORE_GROUND_CALL_STATE)
     && line.contains(RBReadPhoneLog.CallState.IDLE)) {
    Log.d(TAG, RBReadPhoneLog.CallState.IDLE);
   }

//正在拨号,等待建立连接,即已拨号,但对方还没有响铃,
   if (line.contains(RBReadPhoneLog.CallViewState.FORE_GROUND_CALL_STATE)
     && line.contains(RBReadPhoneLog.CallState.DIALING)) {
    //发送广播
    Intent dialingIntent = new Intent();
    dialingIntent.setAction(RBOutPhoneCallState.ForeGroundCallState.DIALING);
    ctx.sendBroadcast(dialingIntent);

Log.d(TAG, RBReadPhoneLog.CallState.DIALING);
   }

//呼叫对方 正在响铃
   if (line.contains(RBReadPhoneLog.CallViewState.FORE_GROUND_CALL_STATE)
     && line.contains(RBReadPhoneLog.CallState.ALERTING)) {
    //发送广播
    Intent dialingIntent = new Intent();
    dialingIntent.setAction(RBOutPhoneCallState.ForeGroundCallState.ALERTING);
    ctx.sendBroadcast(dialingIntent);

Log.d(TAG, RBReadPhoneLog.CallState.ALERTING);
   }

//已接通,通话建立
   if (line.contains(RBReadPhoneLog.CallViewState.FORE_GROUND_CALL_STATE)
     && line.contains(RBReadPhoneLog.CallState.ACTIVE)) {
    //发送广播
    Intent dialingIntent = new Intent();
    dialingIntent.setAction(RBOutPhoneCallState.ForeGroundCallState.ACTIVE);
    ctx.sendBroadcast(dialingIntent);

Log.d(TAG, RBReadPhoneLog.CallState.ACTIVE);
   }

//断开连接,即挂机
   if (line.contains(RBReadPhoneLog.CallViewState.FORE_GROUND_CALL_STATE)
     && line.contains(RBReadPhoneLog.CallState.DISCONNECTED)) {
    //发送广播
    Intent dialingIntent = new Intent();
    dialingIntent.setAction(RBOutPhoneCallState.ForeGroundCallState.DISCONNECTED);
    ctx.sendBroadcast(dialingIntent);

Log.d(TAG, RBReadPhoneLog.CallState.DISCONNECTED);
   }

}

} catch (IOException e) {
  e.printStackTrace();
 }  
}

public class RBRecorder {
private String phoneNumber;
private MediaRecorder mrecorder;
private boolean started = false; // 录音机是否启动
private boolean isCommingNumber = false;// 是否是来电
private String TAG = "Recorder";

public RBRecorder(String phoneNumber) {
 this.setPhoneNumber(phoneNumber);
}

public RBRecorder() {
}

public void start() {
 started = true;
 mrecorder = new MediaRecorder();

String fileName = new SimpleDateFormat("yy-MM-dd_HH-mm-ss")
   .format(new Date(System.currentTimeMillis())) + ".mp3";

String fileSavePath = getFilePath(fileName);

File recordName = new File(fileSavePath);

try {
  recordName.createNewFile();
  Log.d("recorder", "创建文件" + recordName.getName());
 } catch (IOException e) {
  e.printStackTrace();
 }

mrecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
 mrecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
 mrecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);

mrecorder.setOutputFile(recordName.getAbsolutePath());

try {
  mrecorder.prepare();
 } catch (IllegalStateException e) {
  e.printStackTrace();
 } catch (IOException e) {
  e.printStackTrace();
 }
 mrecorder.start();
 started = true;
 Log.d(TAG, "录音开始");
}

public void stop() {
 try {
  if (mrecorder != null) {
   mrecorder.stop();
   // reset
   mrecorder.release();
   mrecorder = null;
  }
  started = false;
 } catch (IllegalStateException e) {
  e.printStackTrace();
 }

Log.d(TAG, "录音结束");
}

public void pause() {

}

public String getPhoneNumber() {
 return phoneNumber;
}

public void setPhoneNumber(String phoneNumber) {
 this.phoneNumber = phoneNumber;
}

public boolean isStarted() {
 return started;
}

public void setStarted(boolean hasStarted) {
 this.started = hasStarted;
}

public boolean isCommingNumber() {
 return isCommingNumber;
}

public void setIsCommingNumber(boolean isCommingNumber) {
 this.isCommingNumber = isCommingNumber;
}

private String getFilePath(String fileName) {
 File sdcardDir = null;
 boolean sdcardExist = Environment.getExternalStorageState().equals(
   android.os.Environment.MEDIA_MOUNTED);
 if (sdcardExist) {
  sdcardDir = Environment.getExternalStorageDirectory();
 }
 String filePath = sdcardDir.toString() + "/Recorder/Recorder";
 File file = new File(filePath);
 if (!file.exists()) {
  file.mkdirs();
 }
 return filePath + "/" + fileName;
}

}

来源:https://blog.csdn.net/qq_25749749/article/details/102558479

标签:Android,录音
0
投稿

猜你喜欢

  • c# 调用Surfer软件,添加引用的具体操作方法

    2023-12-06 17:05:37
  • Java操作Mongodb数据库实现数据的增删查改功能示例

    2023-11-25 00:02:05
  • java为何不能多继承的原因详解

    2023-10-12 04:45:00
  • Java实现经典游戏黄金矿工的示例代码

    2022-01-09 16:35:41
  • Java 实现分布式服务的调用链跟踪

    2023-11-25 10:24:55
  • Mybatis中连接查询和嵌套查询实例代码

    2021-08-23 13:24:31
  • jdk-logging log4j logback日志系统实现机制原理介绍

    2022-03-22 11:45:28
  • java使用FileVisitor遍历文件和目录

    2021-07-17 13:25:21
  • C#线程同步的几种方法总结

    2022-01-31 19:49:06
  • c#多线程之间的排他锁的实现

    2022-06-11 12:31:53
  • Junit测试多线程无法得到结果的问题解决

    2023-01-01 22:12:52
  • C# datagrid非常规方法实现添加合并列

    2023-02-08 07:31:00
  • SpringBoot自定义starter实例代码

    2021-09-04 14:28:06
  • Maven项目修改JDK版本全过程

    2021-07-19 12:13:29
  • C#实现集合转换成json格式数据的方法

    2022-03-18 03:28:50
  • Java解除文件占用即Dom4j操作后实现xml关流

    2022-07-05 19:18:35
  • SpringBoot实现文件上传与下载功能的示例代码

    2021-11-10 09:15:32
  • Spring boot 整合Logback过程示例解析

    2021-12-06 04:05:52
  • C#中CheckedListBox控件的用法实例

    2021-08-05 06:03:29
  • 详解Springboot分布式限流实践

    2021-07-12 14:29:18
  • asp之家 软件编程 m.aspxhome.com