互联网点对点音视频

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]);
  •                     }
  •                 }
  •             }
  •         }
  •  }