返回顶部
首页 > 资讯 > 精选 >Android6.0如何实现双向通话自动录音功能
  • 361
分享到

Android6.0如何实现双向通话自动录音功能

2023-05-31 00:05:42 361人浏览 泡泡鱼
摘要

这篇文章主要为大家展示了“Android6.0如何实现双向通话自动录音功能”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Android6.0如何实现双向通话自动录音功能”这篇文章吧。具体如下:项

这篇文章主要为大家展示了“Android6.0如何实现双向通话自动录音功能”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Android6.0如何实现双向通话自动录音功能”这篇文章吧。

具体如下:

项目中需要实现基于Android 6.0 的双向通话自动录音功能,在查阅相关android电话状态监听文章以及git上的开源录音项目后,整理出此文

首先,实现android 电话状态的监听(来电和去电)

实现手机电话状态的监听,主要依靠两个类:

TelephoneManger和PhoneStateListener

TelephonseManger提供了取得手机基本服务的信息的一种方式。因此应用程序可以使用TelephonyManager来探测手机基本服务的情况。应用程序可以注册listener来监听电话状态的改变。

我们不能对TelephonyManager进行实例化,只能通过获取服务的形式:

Context.getSystemService(Context.TELEPHONY_SERVICE);

注意:对手机的某些信息进行读取是需要一定许可(permission)的。
主要静态成员常量:(它们对应PhoneStateListener.LISTEN_CALL_STATE所监听到的内容)

int CALL_STATE_IDLE  //空闲状态,没有任何活动。int CALL_STATE_OFFHOOK //摘机状态,至少有个电话活动。该活动或是拨打(dialing)或是通话,或是 on hold。并且没有电话是ringing or waitingint CALL_STATE_RINGING //来电状态,电话铃声响起的那段时间或正在通话又来新电,新来电话不得不等待的那段时间。

项目中使用服务来监听通话状态,所以需要弄清楚手机通话状态在广播中的对应值:

EXTRA_STATE_IDLE //它在手机通话状态改变的广播中,用于表示CALL_STATE_IDLE状态,即空闲状态。EXTRA_STATE_OFFHOOK //它在手机通话状态改变的广播中,用于表示CALL_STATE_OFFHOOK状态,即摘机状态。EXTRA_STATE_RINGING //它在手机通话状态改变的广播中,用于表示CALL_STATE_RINGING状态,即来电状态ACTION_PHONE_STATE_CHANGED //在广播中用ACTION_PHONE_STATE_CHANGED这个Action来标示通话状态改变的广播(intent)。//注:需要许可READ_PHONE_STATE。String EXTRA_INCOMING_NUMBER //在手机通话状态改变的广播,用于从extra取来电号码。String EXTRA_STATE //在通话状态改变的广播,用于从extra取来通话状态。

如何实现电话监听呢?

Android在电话状态改变是会发送action为android.intent.action.PHONE_STATE的广播,而拨打电话时会发送action为

public static final String ACTION_NEW_OUTGoING_CALL =      "android.intent.action.NEW_OUTGOING_CALL";

的广播。通过自定义广播接收器,接受上述两个广播便可。

下面给出Java代码:(其中的Toast均为方便测试而添加)

package com.example.hgx.phoneinfo60.Recording;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.telephony.TelephonyManager;import android.widget.Toast;public class PhoneCallReceiver extends BroadcastReceiver {  private int lastCallState = TelephonyManager.CALL_STATE_IDLE;  private boolean isIncoming = false;  private static String contactNum;  Intent audioRecorderService;  public PhoneCallReceiver() {  }  @Override  public void onReceive(Context context, Intent intent) {    //如果是去电    if (intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)){      contactNum = intent.getExtras().getString(Intent.EXTRA_PHONE_NUMBER);    }else //android.intent.action.PHONE_STATE.查了下android文档,貌似没有专门用于接收来电的action,所以,非去电即来电.    {      String state = intent.getExtras().getString(TelephonyManager.EXTRA_STATE);      String phoneNumber = intent.getExtras().getString(TelephonyManager.EXTRA_INCOMING_NUMBER);      int stateChange = 0;      if (state.equals(TelephonyManager.EXTRA_STATE_IDLE)){        //空闲状态        stateChange =TelephonyManager.CALL_STATE_IDLE;        if (isIncoming){          onIncominGCallEnded(context,phoneNumber);        }else {          onOutgoingCallEnded(context,phoneNumber);        }      }else if (state.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)){        //摘机状态        stateChange = TelephonyManager.CALL_STATE_OFFHOOK;        if (lastCallState != TelephonyManager.CALL_STATE_RINGING){          //如果最近的状态不是来电响铃的话,意味着本次通话是去电          isIncoming =false;          onOutgoingCallStarted(context,phoneNumber);        }else {          //否则本次通话是来电          isIncoming = true;          onIncomingCallAnswered(context, phoneNumber);        }      }else if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)){        //来电响铃状态        stateChange = TelephonyManager.CALL_STATE_RINGING;        lastCallState = stateChange;        onIncomingCallReceived(context,contactNum);      }    }  }  protected void onIncomingCallStarted(Context context,String number){    Toast.makeText(context,"Incoming call is started",Toast.LENGTH_LONG).show();    context.startService(new Intent(context,AudioRecorderService.class));  }  protected void onOutgoingCallStarted(Context context,String number){    Toast.makeText(context, "Outgoing call is started", Toast.LENGTH_LONG).show();    context.startService(new Intent(context, AudioRecorderService.class));  }  protected void onIncomingCallEnded(Context context,String number){    Toast.makeText(context, "Incoming call is ended", Toast.LENGTH_LONG).show();    context.startService(new Intent(context, AudioRecorderService.class));  }  protected void onOutgoingCallEnded(Context context,String number){    Toast.makeText(context, "Outgoing call is ended", Toast.LENGTH_LONG).show();    context.startService(new Intent(context, AudioRecorderService.class));  }  protected void onIncomingCallReceived(Context context,String number){    Toast.makeText(context, "Incoming call is received", Toast.LENGTH_LONG).show();  }  protected void onIncomingCallAnswered(Context context, String number) {    Toast.makeText(context, "Incoming call is answered", Toast.LENGTH_LONG).show();  }}

下面是AudioRecorderService的java实现:

package com.example.hgx.phoneinfo60.Recording;import android.app.Service;import android.content.Intent;import android.media.AudioFORMat;import android.media.AudioRecord;import android.media.MediaRecorder;import android.os.AsyncTask;import android.os.Environment;import android.os.IBinder;import android.provider.MediaStore;import android.util.Log;import android.widget.Toast;import com.example.hgx.phoneinfo60.MyApplication;import java.io.DataOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.net.HttpURLConnection;import java.net.URL;public class AudioRecorderService extends Service {  private static int RECORD_RATE = 0;  private static int RECORD_BPP = 32;  private static int RECORD_CHANNEL = AudioFormat.CHANNEL_IN_MONO;  private static int RECORD_ENCODER = AudioFormat.ENcoding_PCM_16BIT;  private AudioRecord audioRecorder = null;  private Thread recordT = null;  private Boolean isRecording = false;  private int bufferEle = 1024, bytesPerEle = 2;// want to play 2048 (2K) since 2 bytes we use only 1024 2 bytes in 16bit format  private static int[] recordRate ={44100 , 22050 , 11025 , 8000};  int bufferSize = 0;  File uploadFile;  @Override  public IBinder onBind(Intent intent) {    // TODO: Return the communication channel to the service.    //maintain the relationship between the caller activity and the callee service, currently useless here    return null;  }  @Override  public void onDestroy() {    if (isRecording){      stopRecord();    }else{      Toast.makeText(MyApplication.getContext(), "Recording is already stopped",Toast.LENGTH_SHORT).show();    }    super.onDestroy();  }  @Override  public int onStartCommand(Intent intent, int flags, int startId) {    if (!isRecording){      startRecord();    }else {      Toast.makeText(MyApplication.getContext(), "Recording is already started",Toast.LENGTH_SHORT).show();    }    return 1;  }  private void startRecord(){    audioRecorder = initializeRecord();    if (audioRecorder != null){      Toast.makeText(MyApplication.getContext(), "Recording is started",Toast.LENGTH_SHORT).show();      audioRecorder.startRecording();    }else      return;    isRecording = true;    recordT = new Thread(new Runnable() {      @Override      public void run() {        writeToFile();      }    },"Recording Thread");    recordT.start();  }  private void writeToFile(){    byte bDate[] = new byte[bufferEle];    FileOutputStream fos =null;    File recordFile = createTempFile();    try {      fos = new FileOutputStream(recordFile);    } catch (FileNotFoundException e) {      e.printStackTrace();    }    while (isRecording){      audioRecorder.read(bDate,0,bufferEle);    }    try {      fos.write(bDate);    } catch (IOException e) {      e.printStackTrace();    }    try {      fos.close();    } catch (IOException e) {      e.printStackTrace();    }  }  //Following function converts short data to byte data  private byte[] writeShortToByte(short[] sData) {    int size = sData.length;    byte[] byteArrayData = new byte[size * 2];    for (int i = 0; i < size; i++) {      byteArrayData[i * 2] = (byte) (sData[i] & 0x00FF);      byteArrayData[(i * 2) + 1] = (byte) (sData[i] >> 8);      sData[i] = 0;    }    return byteArrayData;  }  //Creates temporary .raw file for recording  private File createTempFile() {    File tempFile = new File(Environment.getExternalStorageDirectory(), "aditi.raw");    return tempFile;  }  //Create file to convert to .wav format  private File createWavFile() {    File wavFile = new File(Environment.getExternalStorageDirectory(), "aditi_" + System.currentTimeMillis() + ".wav");    return wavFile;  }    private void convertRawToWavFile(File tempFile, File wavFile) {    FileInputStream fin = null;    FileOutputStream fos = null;    long audioLength = 0;    long dataLength = audioLength + 36;    long sampleRate = RECORD_RATE;    int channel = 1;    long byteRate = RECORD_BPP * RECORD_RATE * channel / 8;    String fileName = null;    byte[] data = new byte[bufferSize];    try {      fin = new FileInputStream(tempFile);      fos = new FileOutputStream(wavFile);      audioLength = fin.getChannel().size();      dataLength = audioLength + 36;      createWaveFileHeader(fos, audioLength, dataLength, sampleRate, channel, byteRate);      while (fin.read(data) != -1) {        fos.write(data);      }      uploadFile = wavFile.getAbsoluteFile();    } catch (FileNotFoundException e) {      //Log.e("MainActivity:convertRawToWavFile",e.getMessage());    } catch (IOException e) {      //Log.e("MainActivity:convertRawToWavFile",e.getMessage());    } catch (Exception e) {      //Log.e("MainActivity:convertRawToWavFile",e.getMessage());    }  }    private void createWaveFileHeader(FileOutputStream fos, long audioLength, long dataLength, long sampleRate, int channel, long byteRate) {    byte[] header = new byte[44];    header[0] = 'R'; // RIFF/WAVE header    header[1] = 'I';    header[2] = 'F';    header[3] = 'F';    header[4] = (byte) (dataLength & 0xff);    header[5] = (byte) ((dataLength >> 8) & 0xff);    header[6] = (byte) ((dataLength >> 16) & 0xff);    header[7] = (byte) ((dataLength >> 24) & 0xff);    header[8] = 'W';    header[9] = 'A';    header[10] = 'V';    header[11] = 'E';    header[12] = 'f'; // 'fmt ' chunk    header[13] = 'm';    header[14] = 't';    header[15] = ' ';    header[16] = 16; // 4 bytes: size of 'fmt ' chunk    header[17] = 0;    header[18] = 0;    header[19] = 0;    header[20] = 1; // format = 1    header[21] = 0;    header[22] = (byte) channel;    header[23] = 0;    header[24] = (byte) (sampleRate & 0xff);    header[25] = (byte) ((sampleRate >> 8) & 0xff);    header[26] = (byte) ((sampleRate >> 16) & 0xff);    header[27] = (byte) ((sampleRate >> 24) & 0xff);    header[28] = (byte) (byteRate & 0xff);    header[29] = (byte) ((byteRate >> 8) & 0xff);    header[30] = (byte) ((byteRate >> 16) & 0xff);    header[31] = (byte) ((byteRate >> 24) & 0xff);    header[32] = (byte) (2 * 16 / 8); // block align    header[33] = 0;    header[34] = 16; // bits per sample    header[35] = 0;    header[36] = 'd';    header[37] = 'a';    header[38] = 't';    header[39] = 'a';    header[40] = (byte) (audioLength & 0xff);    header[41] = (byte) ((audioLength >> 8) & 0xff);    header[42] = (byte) ((audioLength >> 16) & 0xff);    header[43] = (byte) ((audioLength >> 24) & 0xff);    try {      fos.write(header, 0, 44);    } catch (IOException e) {      // TODO Auto-generated catch block      //Log.e("MainActivity:createWavFileHeader()",e.getMessage());    }  }    private void deletTempFile() {    File file = createTempFile();    file.delete();  }    private AudioRecord initializeRecord() {    short[] audioFormat = new short[]{AudioFormat.ENCODING_PCM_16BIT, AudioFormat.ENCODING_PCM_8BIT};    short[] channelConfiguration = new short[]{AudioFormat.CHANNEL_IN_MONO, AudioFormat.CHANNEL_IN_STEREO};    for (int rate : recordRate) {      for (short aFormat : audioFormat) {        for (short cConf : channelConfiguration) {          //Log.d("MainActivity:initializeRecord()","Rate"+rate+"AudioFormat"+aFormat+"Channel Configuration"+cConf);          try {            int buffSize = AudioRecord.getMinBufferSize(rate, cConf, aFormat);            bufferSize = buffSize;            if (buffSize != AudioRecord.ERROR_BAD_VALUE) {              AudioRecord aRecorder = new AudioRecord(MediaRecorder.AudiOSource.DEFAULT, rate, cConf, aFormat, buffSize);              if (aRecorder.getState() == AudioRecord.STATE_INITIALIZED) {                RECORD_RATE = rate;                //Log.d("MainActivity:InitializeRecord - AudioFormat",String.valueOf(aFormat));                //Log.d("MainActivity:InitializeRecord - Channel",String.valueOf(cConf));                //Log.d("MainActivity:InitialoizeRecord - rceordRate", String.valueOf(rate));                return aRecorder;              }            }          } catch (Exception e) {            //Log.e("MainActivity:initializeRecord()",e.getMessage());          }        }      }    }    return null;  }    private void stopRecord() {    if (null != audioRecorder) {      isRecording = false;      audioRecorder.stop();      audioRecorder.release();      audioRecorder = null;      recordT = null;      Toast.makeText(getApplicationContext(), "Recording is stopped", Toast.LENGTH_LONG).show();    }    convertRawToWavFile(createTempFile(), createWavFile());    if (uploadFile.exists()) {      //Log.d("AudioRecorderService:stopRecord()", "UploadFile exists");    }    new UploadFile().execute(uploadFile);    deletTempFile();  }}

以上是“Android6.0如何实现双向通话自动录音功能”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注编程网精选频道!

--结束END--

本文标题: Android6.0如何实现双向通话自动录音功能

本文链接: https://lsjlt.com/news/222329.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Android6.0如何实现双向通话自动录音功能
    这篇文章主要为大家展示了“Android6.0如何实现双向通话自动录音功能”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Android6.0如何实现双向通话自动录音功能”这篇文章吧。具体如下:项...
    99+
    2023-05-31
  • Android 实现电话来去自动录音的功能
    我们在使用Android手机打电话时,有时可能会需要对来去电通话自动录音,本文就详细讲解实现Android来去电通话自动录音的方法,大家按照文中的方法编写程序就可以完成此功能。...
    99+
    2022-06-06
    自动 电话 Android
  • Android应用中怎么实现一个通话录音功能
    这期内容当中小编将会给大家带来有关Android应用中怎么实现一个通话录音功能,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。服务代码:package com.eboy.phoneListener;impo...
    99+
    2023-05-31
    android roi
  • Vue如何实现悬浮框自由移动+录音功能
    本篇内容介绍了“Vue如何实现悬浮框自由移动+录音功能”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!效果如下主要功能一个漂浮的球,在全屏幕中...
    99+
    2023-07-02
  • HTML5如何实现录音功能
    这篇文章主要介绍了HTML5如何实现录音功能,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。获取 PCM 数据处理 PCM 数据Float32 转 Int16ArrayBuff...
    99+
    2023-06-09
  • Android如何实现录音功能
    这篇文章给大家分享的是有关Android如何实现录音功能的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。本文介绍了Android实现录音的实例代码(MediaRecorder),分享给大家,具体如下:Android...
    99+
    2023-05-30
    android
  • 实例详解uniapp如何实现电话录音功能(附代码)
    本篇文章给大家带来了关于uniapp的相关知识,其中主要介绍了怎么用uniapp实现拨打电话并且还能同步录音的功能,感兴趣的朋友一起来看一下吧,希望对大家有帮助。uniapp 实现打电话录音功能最近需要实现一个通过 uniapp 调用手机拨...
    99+
    2023-05-14
    uni-app
  • Java如何实现双向链表功能
    双向链表实现 双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继...
    99+
    2024-04-02
  • java web如何实现自动登录功能
    这篇文章主要介绍java web如何实现自动登录功能,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!具体内容如下主要思路就是:当用户访问网站的首页时,浏览器端会先检擦浏览器中存在的cookie中是否又登录的用户的用户名...
    99+
    2023-05-31
    java web
  • Qt C++如何实现录屏录音功能
    这篇文章主要介绍了Qt C++如何实现录屏录音功能的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Qt C++如何实现录屏录音功能文章都会有所收获,下面我们一起来看看吧。录屏部分录屏的主要思路...
    99+
    2023-07-05
  • WCF如何实现双向通信
    这篇文章主要介绍“WCF如何实现双向通信”,在日常操作中,相信很多人在WCF如何实现双向通信问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”WCF如何实现双向通信”的疑惑有所帮助!接下来,请跟着小编一起来学习吧...
    99+
    2023-06-30
  • C++用winapi socket实现局域网语音通话功能
    目录一、socket通信二、waveIn和WaveOut的Win32API1.音频设备的的信息获取2.音频设备的初始化3.输入输出设备缓冲区的准备和添加4.播放和录音的开始和终止5....
    99+
    2024-04-02
  • JavaWeb实现自动登录功能
    本文实例为大家分享了JavaWeb实现自动登录功能的具体代码,供大家参考,具体内容如下 自动登录是通过存储cookie值来实现的。 工程目录如下: login.jsp: <...
    99+
    2024-04-02
  • C++如何实现通讯录功能
    这篇文章主要介绍“C++如何实现通讯录功能”,在日常操作中,相信很多人在C++如何实现通讯录功能问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C++如何实现通讯录功能”的疑惑有所帮助!接下来,请跟着小编一起来...
    99+
    2023-07-02
  • 如何通过Oracle实现自动发邮件功能
    在内网项目、外网项目中多有 需要自动监控发邮件提醒的功能,因为邮件功能最便捷、便宜、不用开接口,不用接口费用。现 提供 我在一个内网项目中的使用案例: 案例背景: 在有限的资源下,能够自动给下级单位发布 数据考核评分(自动评分)和...
    99+
    2019-09-17
    如何通过Oracle实现自动发邮件功能
  • HTML5中如何实现背景音乐自动播放功能
    小编给大家分享一下HTML5中如何实现背景音乐自动播放功能,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!音乐的自动播放属性,这里...
    99+
    2024-04-02
  • recorder.js如何实现基于Html5录音功能
    这篇文章将为大家详细讲解有关recorder.js如何实现基于Html5录音功能,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。recorder.jsmicrophone基于HTML5的录音功能,输出格式为...
    99+
    2023-06-09
  • JS如何实现两周内自动登录功能
    这篇文章将为大家详细讲解有关JS如何实现两周内自动登录功能,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。具体内容如下<!DOCTYPE html> ...
    99+
    2024-04-02
  • shell脚本如何通过expect实现自动单边无密登录功能
    这篇文章主要介绍了shell脚本如何通过expect实现自动单边无密登录功能,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。代码如下:EXPECT=/usr/bin/expec...
    99+
    2023-06-09
  • C++怎么用winapi socket实现局域网语音通话功能
    本篇内容主要讲解“C++怎么用winapi socket实现局域网语音通话功能”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C++怎么用winapi socket实现局域网语...
    99+
    2023-07-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作