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; /**
* Created by hgx on 2016/6/13.
*/
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;
/**
* Created by hgx on 2016/6/13.
*/ 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;
} /*
* Convert raw to wav file
* @param java.io.File temporay raw file
* @param java.io.File destination wav file
* @return void
*
* */
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());
}
} /*
* To create wav file need to create header for the same
*
* @param java.io.FileOutputStream
* @param long
* @param long
* @param long
* @param int
* @param long
* @return void
*/
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());
} } /*
* delete created temperory file
* @param
* @return void
*/
private void deletTempFile() {
File file = createTempFile();
file.delete();
} /*
* Initialize audio record
*
* @param
* @return android.media.AudioRecord
*/
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;
} /*
* Method to stop and release audio record
*
* @param
* @return void
*/
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();
} /*
* Asynchronous task to upload audio file in background
*
*
*/
private class UploadFile extends AsyncTask<File, Void, Void> {
protected Void doInBackground(File... files) { if (files[0] == null)
return null;
try {
File fileToUpload = files[0];
String boundary = "*****";
String lineEnd = "\r\n";
String twoHyphens = "--";
int maxBufferSize = 1 * 1024 * 1024;
String fileName = fileToUpload.getAbsolutePath();
FileInputStream fis = new FileInputStream(new File(fileName));
URL serverUrl = new URL("http://192.168.78.128/UploadToServer.php");
HttpURLConnection connection = (HttpURLConnection) serverUrl.openConnection();
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setUseCaches(false);
connection.setRequestMethod("POST");
connection.setRequestProperty("Connection", "Keep-Alive");
connection.setRequestProperty("ENCTYPE", "multipart/form-data");
connection.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
connection.setRequestProperty("uploaded_file", fileName);
DataOutputStream dos = new DataOutputStream(connection.getOutputStream()); dos.writeBytes(twoHyphens + boundary + lineEnd);
dos.writeBytes("Content-Disposition: form-data; name=\"uploadedfile\";filename=\"" + fileName + "\"" + lineEnd);
dos.writeBytes(lineEnd); // create a buffer of maximum size
int bytesAvailable = fis.available();
int bufferSize = Math.min(bytesAvailable, maxBufferSize);
byte[] buffer = new byte[bufferSize]; // read file and write it into form...
int bytesRead = fis.read(buffer, 0, bufferSize); while (bytesRead > 0) { dos.write(buffer, 0, bufferSize);
bytesAvailable = fis.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fis.read(buffer, 0, bufferSize); } dos.writeBytes(lineEnd);
dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
// Responses from the server (code and message)
int serverResponseCode = connection.getResponseCode();
String serverResponseMessage = connection.getResponseMessage(); // /Log.d("AudioRecorderService:AsyncTask",String.valueOf(serverResponseCode));
// /Log.d("AudioRecorderService:AsyncTask",serverResponseMessage); if (serverResponseCode == 200) { Toast.makeText(getApplicationContext(), "File is uploaded successfully", Toast.LENGTH_SHORT).show(); } //close the streams //
fis.close();
dos.flush();
dos.close(); } catch (Exception e) {
Log.e("AudioRecorder:Asynctask", e.getMessage());
} return null; }
}
}

  原文地址:http://blog.csdn.net/gyhgx/article/details/51669892

Android 6.0 双向通话自动录音的更多相关文章

  1. 手把手教你Android来去电通话自动录音的方法

    我们在使用Android手机打电话时,有时可能会需要对来去电通话自动录音,本文就详细讲解实现Android来去电通话自动录音的方法,大家按照文中的方法编写程序就可以完成此功能. 来去电自动录音的关键在 ...

  2. Android 8.0 功能和 API

    Android 8.0 为用户和开发者引入多种新功能.本文重点介绍面向开发者的新功能. 用户体验 通知 在 Android 8.0 中,我们已重新设计通知,以便为管理通知行为和设置提供更轻松和更统一的 ...

  3. Android 8.0/9.0 wifi 自动连接评分机制

    前言 Android N wifi auto connect流程分析 Android N selectQualifiedNetwork分析 Wifi自动连接时的评分机制 今天了解了一下Wifi自动连接 ...

  4. Android 6.0(棉花糖)新特性

    1.支持4K显示 Android 6.0本身已经支持4K显示,会通过一定优化形式使4K内容更加清晰. 2. 启动验证 (更完整的应用权限管理) Android 6.0在开机时会自动运行验证代码,检测设 ...

  5. Android 6.0 新功能及主要 API 变更

    运行时权限 这个版本中引入了新的权限模型,现在用户可以在运行时直接管理应用程序的权限.这个模型基于用户对权限控制的更多可见性,同时为应用程序的开发者提供更流畅的应用安装和自动升级.用户可以为已安装的每 ...

  6. Android 4.0源码目录结构

    转:http://blog.csdn.net/xiangjai/article/details/9012387 在学习Android的过程中,学习写应用还好,一开始不用管太多代码,直接调用函数就可以了 ...

  7. Android 6.0 Changes

    原文链接:http://developer.android.com/about/versions/marshmallow/android-6.0-changes.html 伴随着新特性和功能,Andr ...

  8. Android 6.0 动态权限申请注意事项

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/uana_777/article/details/54136255 Part One 权限区分 And ...

  9. Android 6.0 变更

    Android 6.0(API 级别 23)除了提供诸多新特性和功能外,还对系统和 API 行为做出了各种变更.本文重点介绍您应该了解并在开发应用时加以考虑的一些主要变更. 如果您之前发布过 Andr ...

随机推荐

  1. 201521123105 第11周Java学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多线程相关内容. 2. 书面作业 本次PTA作业题集多线程 1. 互斥访问与同步访问 完成题集4-4(互斥访问)与4-5(同步访问) ...

  2. 201521123011《Java程序设计》第10周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常与多线程相关内容. 2. 书面作业 本次PTA作业题集异常.多线程 1.finally 题目4-2 1.1 截图你的提交结果(出 ...

  3. 201521123012 《Java程序设计》第九周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常相关内容. 2. 书面作业 1.本次PTA作业题集异常 常用异常 题目5-1 1.1 截图你的提交结果(出现学号) 1.2 自己 ...

  4. logback:用slf4j+logback实现多功能日志解决方案

    slf4j是原来log4j的作者写的一个新的日志组件,意思是简单日志门面接口,可以跟其他日志组件配合使用,常用的配合是slf4j+logback,无论从功能上还是从性能上都较之log4j有了很大的提升 ...

  5. linux加载与使用ko驱动

    linux驱动和有两种形式: 1:编译到内核 2:编译为ko模块 这里记录下ko模块使用方法. 首先cd到/var/lib/(内核版本)/drivers/ 在这里面找到要装载的模块ko文件 modpr ...

  6. sql server 把数据 复制成脚本文件

    问题描述:想把一个数据库里的表和字段复制到另一个数据库里: 方法一:a.生成脚本文件 选择数据库右键->任务->生成脚本: b. 选择特定的数据库对象->下一步: c.高级-> ...

  7. MySQL_日期函数汇总

              如果转载,请注明博文来源: www.cnblogs.com/xinysu/   ,版权归 博客园 苏家小萝卜 所有.望各位支持!         关于MySQL日期时间函数,每回总 ...

  8. 1.在CentOS 6.4安装python3

    CentOS安装Python3.X 1.系统环境说明 [root@Python ~]# uname -r 2.6.32-431.el6.i686 [root@Python ~]# uname -m i ...

  9. Nginx学习——Nginx启动、停止、重启和信号控制以及平滑升级

    1.Nginx 启动与停止 (1)启动方式 启动格式:Nginx可执行文件地址 -c Nginx配置文件地址 /etc/local/nginx/sbin/nginx -c /root/dufy/ngi ...

  10. 无向图广度优先遍历及其matlab实现

    广度优先遍历(breadth-first traverse,bfts),称作广度优先搜索(breath first search)是连通图的一种遍历策略.之所以称作广度优先遍历是因为他的思想是从一个顶 ...