这是本文档旧的修订版!
1对1音视频通话
1对1实时音视频通话分为视频通话和音频通话,与普通电话不同,它是基于网络的。
实时通话的数据流量
实时语音和实时视频的数据流量如下:
实时语音:
- 双向 170k bytes/minute
实时视频(单路):
- 240p: 0.75M ~ 3M
- 480p: 2.2M ~ 7.5M
- 720p: 6.5M ~ 18.5M
- 1080p: 15M ~ 37.5M
监听呼入通话
通过注册相应 action 的 BroadcastReceiver 来监听呼叫过来的通话,接到广播后开发者可以调起 APP 里的通话 Activity。
IntentFilter callFilter = new IntentFilter(EMClient.getInstance().callManager().getIncomingCallBroadcastAction());
registerReceiver(new CallReceiver(), callFilter);
private class CallReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// 拨打方username
String from = intent.getStringExtra("from");
// call type
String type = intent.getStringExtra("type");
//跳转到通话页面
}
}
监听通话状态
通过 addCallStateChangeListener 监听通话状态。
注意:在收到 DISCONNECTED 回调时才能 finish 当前页面(保证通话所占用的资源都释放完),然后开始下一个通话。
EMClient.getInstance().callManager().addCallStateChangeListener(new EMCallStateChangeListener() {
@Override
public void onCallStateChanged(CallState callState, CallError error) {
switch (callState) {
case CONNECTING: // 正在连接对方
break;
case CONNECTED: // 双方已经建立连接
break;
case ACCEPTED: // 电话接通成功
break;
case DISCONNECTED: // 电话断了
if(error == CallError.ERROR_UNAVAILABLE){
// 对方不在线
}
break;
case NETWORK_UNSTABLE: //网络不稳定
if(error == CallError.ERROR_NO_DATA){
//无通话数据
}else{
}
break;
case NETWORK_NORMAL: //网络恢复正常
break;
case NETWORK_DISCONNECTED: //通话中对方断网会执行
break;
default:
break;
}
}
});
详细回调请参考API Doc。
拨打语音通话
/**
* 拨打语音通话
* @param to
* @throws EMServiceNotReadyException
*/
try {//单参数
EMClient.getInstance().callManager().makeVoiceCall(username);
} catch (EMServiceNotReadyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {//多参数
EMClient.getInstance().callManager().makeVoiceCall(username,"ext 扩展内容");
} catch (EMServiceNotReadyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {//多参数, recordOnServer:是否在服务器端录制该通话, mergeStream:服务器端录制时是否合并流
EMClient.getInstance().callManager().makeVoiceCall(username,"ext 扩展内容", recordOnServer, mergeStream);
} catch (EMServiceNotReadyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//获取扩展内容
String callExt = EMClient.getInstance().callManager().getCurrentCallSession().getExt();
拨打视频通话
/**
* 拨打视频通话
* @param to
* @throws EMServiceNotReadyException
*/
try {//单参数
EMClient.getInstance().callManager().makeVideoCall(username);
} catch (EMServiceNotReadyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {//多参数
EMClient.getInstance().callManager().makeVideoCall(username,"ext 扩展内容");
} catch (EMServiceNotReadyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {//多参数, recordOnServer:是否在服务器端录制该通话, mergeStream:服务器端录制时是否合并流
EMClient.getInstance().callManager().makeVideoCall(username,"ext 扩展内容", recordOnServer, mergeStream);
} catch (EMServiceNotReadyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//获取扩展内容
String callExt = EMClient.getInstance().callManager().getCurrentCallSession().getExt();
视频通话需要显示自己和对方的图像,需要设置相应 surfaceview。
接听通话
/**
* 接听通话
* @throws EMNoActiveCallException
* @throws EMNetworkUnconnectedException
*/
try {
EMClient.getInstance().callManager().answerCall();
} catch (EMNoActiveCallException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (EMNetworkUnconnectedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
拒绝接听
/**
* 拒绝接听
* @throws EMNoActiveCallException
*/
try {
EMClient.getInstance().callManager().rejectCall();
} catch (EMNoActiveCallException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
挂断通话
/**
* 挂断通话
*/
EMClient.getInstance().callManager().endCall();
暂停和恢复语音或视频数据传输
暂停语音数据传输:
EMClient.getInstance().callManager().pauseVoiceTransfer()
恢复语音数据传输:
EMClient.getInstance().callManager().resumeVoiceTransfer()
暂停视频(图像)数据传输:
EMClient.getInstance().callManager().pauseVideoTransfer()
恢复视频(图像)数据传输:
EMClient.getInstance().callManager().resumeVideoTransfer()
调用后对方会收到相应VOICE_PAUSE、VOICE_RESUME、VIDEO_PAUSE、VIDEO_RESUME的callstate的变动通知。
视频通话设置显示自己和对方图像的 surfaceView
视频通话需要预先设置 localSurfaceView、oppositeSurfaceView,
而且必须在Activity.onCreate(Context context)
方法中设置,之后才能正确捕捉 Surface 的变化。
EMClient.getInstance().callManager().setSurfaceView(localSurface, oppositeSurface);
用户自定义数据采集及数据处理
如果用户需要自己采集特定的数据或者对于数据需要先进行一些处理,可以使用SDK的外部输入数据的方法进行。
例如如果想要使用美颜或者变音等功能,需要用户使用系统的摄像头或者麦克风,然后启动监听系统设备,获取到数据后进行处理,处理后再调用我们输入数据的api发布出去。
使用方式:
/**
* 首先在初始化音视频部分设置外部输入视频数据
* 设置是否启用外部输入视频数据,默认 false,如果设置为 true,需要自己调用
* {@link EMCallManager#inputExternalVideoData(byte[], int, int, int)}输入视频数据
*/
EMClient.getInstance().callManager().getCallOptions().setEnableExternalVideoData(true);
...
/**
* 然后就是自己获取视频数据,进行美颜等处理,循环调用以下方法输入数据就行了(这个调用频率就相当于你的帧率,调用间隔可以自己进行控制,一般最大30帧/秒)
* 视频数据的格式是摄像头采集的格式即:NV21 420sp 自己手动传入时需要将自己处理的数据转为 yuv 格式输入
*/
EMClient.getInstance().callManager().inputExternalVideoData(data, width, height, rotate);
外部输入音频数据:
public int inputExternalAudioData(byte[] data ,int length)
切换摄像头
视频通话时如果有前置摄像头,默认使用前置的,提供切换 API 切换到别的摄像头。
EMClient.getInstance().callManager().switchCamera();
更多视频通话相关 API
视频通话相对复杂,把视频相关的一些 API 封装到了 EMVideoCallHelper 里。
获取 CallHelper
EMVideoCallHelper callHelper = EMClient.getInstance().callManager().getVideoCallHelper();
设置通话最大帧率
设置通话最大帧率,SDK 最大支持(30),默认(20)
EMClient.getInstance().callManager().getCallOptions().setMaxVideoFrameRate(30);
设置图像分辨率
设置视频通话分辨率 默认是(640, 480)
EMClient.getInstance().callManager().getCallOptions().setVideoResolution(640, 480);
设置视频比特率
设置视频通话最大和最小比特率(可以不设置,SDK会根据手机分辨率和网络情况自动适配),最大值默认800, 最小值默认80
EMClient.getInstance().callManager().getCallOptions().setMaxVideoKbps(800);
EMClient.getInstance().callManager().getCallOptions().setMinVideoKbps(80);
离线推送
音视频呼叫对方,如果对方不在线,则发送一条离线消息通知对方(true推送,false不推送)
EMClient.getInstance().callManager().getCallOptions().setIsSendPushIfOffline(false);
音视频采样率
设置音视频采样率,一般不需要设置,除非采集声音有问题才需要手动设置(默认值48000),根据自己硬件设备确定
EMClient.getInstance().callManager().getCallOptions().setAudioSampleRate(48000);