互联网点对点音视频
1、点对点音视频开发说明
1.1、实时音频、实时视频均通过相同的接口进行调用,遵循相同的业务流程。不同的业务通过呼叫接口参数CallType进行区分,CallType一共有2种类型:CallType.VIDEO(视频),CallType.VOICE(音频)。
注意:5.0以上的SDK集成的客户端,测试点对点音视频,音视频会议,群组等功能,建议先将在官网控制台创建的应用上线,才可测试(控制台提供的测试demo中的应用id和应用token,不能用来测试,需要使用自己在官网控制台创建的应用的id和应用token)。
1.2、接口逻辑
接口调用是采取异步调用的方式。所有的呼叫相关接口的调用结果通过回调接口OnVoipListener中的方法OnCallEvents来接受服务端返回的各种状态。
1.3、业务流程
- 客户A呼叫客户B发起请求
- 云通讯服务端收到A请求并把请求转发给B
- 客户B收到请求并应答
- 云通讯服务端收到B应答并转发A
- A收到应答,通话建立
2、代码示例
音频呼叫
我们假设Tony音频呼叫John,则代码如下:
- String mCurrentCallId = ECDevice.getECVoIPCallManager().makeCall(ECVoIPCallManager.CallType.VOICE,"john的账号");
- 说明:mCurrentCallId如果返回空则代表呼叫失败,可能是参数错误引起。否则返回是一串数字,是当前通话的标识。
视频呼叫
我们假设Tony视频呼叫John,此时代码和音频呼叫相同,区别是呼叫类型需要传入CallType.VIDEO,并且在呼叫前需要设置本地和对方的视频view,代码如下:
- //view 显示远端视频的surfaceview
- //localView本地显示视频的
- viewECDevice.getECVoIPSetupManager().setVideoView(view, localView);
- String mCurrentCallId = ECDevice.getECVoIPCallManager().makeCall(ECVoIPCallManager.CallType.VIDEO, "john的账号");
- 说明:mCurrentCallId如果返回空则代表呼叫失败,可能是参数错误引起。否则返回是一串数字,是当前通话的标识。
获取来电参数
被叫John接到Tony的呼叫,John同意接听该呼叫,John侧的呼入activity的设置已经在sdk初始化的回调onInitialized中设置过。Sdk底层收到呼入请求后,会自动弹出该Activity,在Activity的onCreate中取出相关的参数。
1、 在呼入调起的界面中,获取到呼入的类型是音频或者视频呼叫,然后来设置对应UI布局,代码如下:
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- Bundle extras = savedInstanceState;//或者Bundle extras = getIntent().getExtras();
- if (extras == null) {
- finish();
- return;
- }
- //获取是否是呼入还是呼出
- mIncomingCall = !(getIntent().getBooleanExtra(EXTRA_OUTGOING_CALL, false));
- //获取是否是音频还是视频
- mCallType = (ECVoIPCallManager.CallType)
- getIntent().getSerializableExtra(ECDevice.CALLTYPE);
- //获取当前的callid
- mCallId = getIntent().getStringExtra(ECDevice.CALLID);
- //获取对方的号码
- mCallNumber = getIntent().getStringExtra(ECDevice.CALLER);
- }
- }
2、假设John侧调起来音频或者视频呼入的界面,界面上有“接受”和“拒绝”两个按钮;
(1)John点击“接受”按钮,则调用的代码:
- //如果视频呼叫,则在接受呼叫之前,需要先设置视频通话显示的view
- ECDevice.getECVoIPSetupManager().setVideoView(view, localView);
- //view 显示远端视频的surfaceview
- //localView本地显示视频的view
- ECDevice.getECVoIpCallManager().acceptCall(mCurrentCallId);
(2)John点击“拒绝”按钮,音视频拒绝的代码是一致的,调用的代码是:
- ECDevice.getECVoIpCallManager().rejectCall(mCurrentCallId,”拒绝的原因,传入整型值”);
处理回调事件
Tony在呼叫John的过程中,会有若干状态返回,都在回调onCallEvents中处理,其监听的设置已经在sdk初始化的回调onInitialized中设置过。代码示例如下:
注意:在集成音视频通话的时候,当结束当前通话的时候,需要在处理回调事件的onCallEvents中调用一下releaseCall方法,以保证当前通话占用的资源都释放了,避免在下次呼叫的时候出现线路被占用现象。(android、ios均需这样操作),Android的调用地方,onCallEvents中的 ECCALL_RELEASED:
- @Override
- protected void onCallEvents(ECVoIPCallManager.VoIPCall voipCall) {
- if(voipCall==null) return;
- switch(voipCall. callState){
- case ECCALL_ALERTING:
- Log(” 对方振铃”);
- break;
- case ECCALL_PROCEEDING:
- Log(” 呼叫中”);
- break;
- case ECallAnswered:
- Log(” John接受了呼叫应答”);
- break;
- case ECCALL_FAILED://
- Log(” 呼叫失败”);
- break;
- case ECCALL_RELEASED:
- //无论是Tony还是John主动结束通话,双方都会进入到此回调
- Log(” 结束当前通话”);
- break;
- default:
- break;
- }
- }
- }
结束通话
Tony和John的通话过程中,任何一方想结束呼叫,都可以调用如下代码:
- ECDevice.getECVoIpCallManager().releaseCall(mCurrentCallId);
3、辅助接口
设置扬声器状态
- ECDevice. getECVoIPSetupManager().enableLoudSpeaker(boolean on);
- 功能: 设置扬声器的状态;
- 参数:on:true是开启,false则为关闭。
获取扬声器状态
- ECDevice. getECVoIPSetupManager().getLoudSpeakerStatus();
- 功能:获取当前扬声器的状态
- 参数:无
- 返回值:true 开启 false 关闭
设置静音
- ECDevice. getECVoIPSetupManager().setMute(boolean on);
- 功能:设置通话静音状态
- 参数:on:传入true则对方听不到说话,false则对方可以听到说话
- 返回值:无
获取静音的状态
- ECDevice.getECVoIPSetupManager().getMuteStatus();
- 功能:获取当前通话静音状态
- 参数:无
- 返回值:返回true则是静音状态,false则不是静音状态
设置视频通话显示的窗口
- ECDevice.getECVoIPSetupManager().setVideoView( SurfaceView view, SurfaceView localView);
- 功能:设置视频通话过程中显示的视图
- 参数:view对方显示的视图,localView本地显示的视图
- 返回值:无
创建一个用于绘制视频图像的ECOpenGlView控件
- ECOpenGlView mGlView = new ECOpenGlView(this);
- // 设置预览类型为本地预览、可以显示于其他SurfaceView之上
- mGlView.setGlType(ECOpenGlView.RenderType.RENDER_PREVIEW);
- // 或者设置为远端绘制
- mGlView.setGlType(ECOpenGlView.RenderType.RENDER_REMOTE);
- // 设置当前图像填充方式(根据中心区域显示,填充屏幕并剪切)
- mSelfGlView.setAspectMode(ECOpenGlView.AspectMode.CROP);
- // 按照图像的比例显示(分辨率和图像分辨率不等时上下、左右会出现一种黑边情况)
- mSelfGlView.setAspectMode(ECOpenGlView.AspectMode.FIT);
- // 按照View的宽高拉伸图像
- mSelfGlView.setAspectMode(ECOpenGlView.AspectMode.FILL);
设置远端视频图像显示View为ECOpenGlView
- ECVoIPSetupManager setUpMgr = ECDevice.getECVoIPSetupManager();if(setUpMgr != null) {
- setUpMgr.setVideoView(mGlView , mCaptureView);}
设置本地/远端视频图像显示View为ECOpenGlView
- // 创建一个本地图像显示控件
- ECOpenGlView mSelfGlView = new ECOpenGlView(this);
- // 设置预览类型为本地预览、可以显示于其他SurfaceView之上
- mSelfGlView.setGlType(ECOpenGlView.RenderType.RENDER_PREVIEW);
- // 设置当前图像填充方式(根据中心区域显示,填充屏幕并剪切)
- mSelfGlView.setAspectMode(ECOpenGlView.AspectMode.CROP);
- // 创建一个远端图像显示控件
- ECOpenGlView mRemoteGlView = new ECOpenGlView(this);
- // 设置预览类型为远端、可以显示于其他SurfaceView之下
- mRemoteGlView.setGlType(ECOpenGlView.RenderType.RENDER_PREVIEW);
- // 设置当前图像填充方式(根据中心区域显示,填充屏幕并剪切)
- mRemoteGlView.setAspectMode(ECOpenGlView.AspectMode.CROP);
- // 调用SDK接口设置图像显示
- ECVoIPSetupManager setUpMgr = ECDevice.getECVoIPSetupManager();
- if(setUpMgr != null) {
- // 设置图像采集
- setUpMgr.setCaptureView(new ECCaptureView(this));
- // 设置本地远端图像显示View
- setUpMgr.setGlDisplayWindow(mSelfGlView , mRemoteGlView);
- }
动态切换本地/远端图像(对换本地远端图像显示位置)
- mSelfGlView.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- ECVoIPSetupManager setUpMgr = ECDevice.getECVoIPSetupManager();
- if(setUpMgr != null) {
- // 设置当前远端图像显示为全屏/小屏幕
- mMaxSizeRemote = !mMaxSizeRemote;
- // 调用接口对换View位置
- if(mMaxSizeRemote) {
- setUpMgr.setGlDisplayWindow(mSelfGlView , mRemoteView);
- } else {
- setUpMgr.setGlDisplayWindow(mRemoteView , mSelfGlView);
- }
- }
- }
- });
视频会议使用ECOpenGlView显示成员图像
- // 创建一个图像显示控件
- ViewECOpenGlView mGlView = new ECOpenGlView(this);
- mGlView.setGlType(ECOpenGlView.RenderType.RENDER_REMOTE);
- mSelfGlView.setAspectMode(ECOpenGlView.AspectMode.CROP);
- // 获取会议管理API接口
- ECMeetingManager meetMgr = ECDevice.getECMeetingManager();
- // 使用接口设置图像显示View
- meetMgr.requestMemberVideoInVideoMeeting("conf0000", null, "yuntx", mGlView , "ip", 8080, null);
获取手机摄像头参数
- ECDevice.getECVoIPSetupManager().getCameraInfos();
- 功能: 获取手机摄像头参数信息(摄像头个数,名称、以及摄像头所持有的分辨率)
- 参数:无
- 返回值:手机摄像头参数信息
切换前置和后置摄像头(调整分辨率)
- /**
- * 选择摄像头。可以在通话过程中选择;如果不调用,底层将使用系统默认摄像头
- * @param cameraIndex CameraInfo的index值
- * @param capabilityIndex CameraCapability的index值。范围[0,capabilityCount-1]
- * @param fps 最大帧数
- * @param rotate 旋转的角度( {ROTATE_AUTO,ROTATE_0,ROTATE_90,ROTATE_180,ROTATE_270};中的值)
- * @param force 是否强制启动本SDK调用的摄像头。默认选false
- * @param scale 缩放
- * @return 是否成功 0:成功; 非0失败
- */
- ECDevice.getECVoIPSetupManager().selectCamera(int cameraIndex, int capabilityIndex,
- int fps, Rotate rotate, boolean force,float scale);
设置VoIP呼叫透传信息
- // 创建一个个人信息参数对象
- VoIPCallUserInfo mUserInfo = new VoIPCallUserInfo();
- // 调用VoIP设置接口注入VoIP呼叫透传参数
- mUserInfo.setNickName("nickname");
- mUserInfo.setPhoneNumber("PhoneNumber");
- ECVoIPSetupManager setupManager = ECDevice.getECVoIPSetupManager();
- setupManager.setVoIPCallUserInfo(mUserInfo);
设置是否启用来去电铃声播放
- // 设置VOIP 自定义铃声路径
- ECVoIPSetupManager setupManager = ECDevice.getECVoIPSetupManager();if(setupManager != null) {
- // 目前支持下面三种路径查找方式
- // 1、如果是assets目录则设置为前缀[assets://]
- setupManager.setInComingRingUrl(true, "assets://phonering.mp3");
- setupManager.setOutGoingRingUrl(true, "assets://phonering.mp3");
- setupManager.setBusyRingTone(true, "assets://played.mp3");
- // 2、如果是raw目录则设置为前缀[raw://]
- // 3、如果是SDCard目录则设置为前缀[file://]}
设置音频处理开关,在通话前调用
- // 获取一个VoIP设置接口对象
- ECVoIPSetupManager setupManager = ECDevice.getECVoIPSetupManager();
- // 比如设置开启回音消除模式
- setupManager.setAudioConfigEnabled(ECVoIPSetupManager.AudioType.AUDIO_EC ,
- true , ECVoIPSetupManager.AudioMode.EC_Conference);
查询相关的音频处理参数
- // 获取一个VoIP设置接口对象
- ECVoIPSetupManager setupManager = ECDevice.getECVoIPSetupManager();
- // 比如是否启用回音消除
- setupManager.getAudioConfig(ECVoIPSetupManager.AudioType.AUDIO_EC);
- // 查询回音消除模式
- setupManager.getAudioConfigMode(ECVoIPSetupManager.AudioType.AUDIO_EC);
设置视频通话码流(需要在通话前使用)
- // 获取一个VoIP设置接口对象
- ECVoIPSetupManager setupManager = ECDevice.getECVoIPSetupManager();
- // 比如:将视频通话码流设置成150
- setupManager.setVideoBitRates(150);
设置SDK支持的编解码方式,默认全部支持
- // 获取一个VoIP设置接口对象
- ECVoIPSetupManager setupManager = ECDevice.getECVoIPSetupManager();
- // 比如:设置当前通话使用 G729编码传输
- setupManager.setCodecEnabled(ECVoIPSetupManager.Codec.Codec_G729 , true);
- // 查询制定编解码是否支持
- setupManager.getCodecEnabled(ECVoIPSetupManager.Codec.Codec_G729);
实时获取通话中的统计数据
- // 获取一个VoIP设置接口对象
- ECVoIPSetupManager setupManager = ECDevice.getECVoIPSetupManager();
- // 比如:获取音频通话信息
- // 具体参数信息可以参考API文档
- CallStatisticsInfo CallStatisticsInfo statistics = setupManager.getCallStatistics("callId", false);
获取VoIP、视频、实时对讲、聊天室、会议上下行流量
- // 获取一个VoIP设置接口对象
- ECVoIPSetupManager setupManager = ECDevice.getECVoIPSetupManager();
- // 具体参数信息可以参考API文档
- NetworkStatisticNetworkStatistic networkStatistic = setupManager.getNetworkStatistic("callId")
获取服务器callSid
建议通话建立后获取。代码示例如下:
- private Map map = new HashMap();
- private void get(){
- String s = ECDevice.getECVoIPCallManager().getUserData(3,mCallId);
- if(!TextUtils.isEmpty(s)){
- if(s.contains(";")) {
- String[] arr = s.split("\\;");
- if (arr != null) {
- for (String item : arr) {
- if (!TextUtils.isEmpty(item) && item.startsWith("servercallid")){
- String[] arr2 = item.split("\\=");
- if (arr2 != null && arr2.length == 2) {
- map.put("sid", arr2[1]);
- }
- }
- }
- }
- }else {
- if(s.startsWith("servercallid=")){
- String [] arr = s.split("\\=");
- if(arr!=null&&arr.length==2){
- map.put("sid",arr[1]);
- }
- }
- }
- }
- }