MTK VILTE预研文档

本文是在乐视做Phone开发时,预研视频通话功能的文档

简介        

       本文作为mtk的viLTE的预研文档,主要从从视频通话流程的角度阐述viLTE相关内容,为后续开发做充分的理论准备。从上层代码结构看,高通和MTK的代码调用和路径是相同的,没有太大的差异,但从实现方式上看,高通和MTK不同。高通方面,与volte通话一样,指令通过ImsSenderRxr.java发送给modem层,同样,上层也是通过 ImsSendRxr.java来获取modem上报的信息; 与ImsSendRxr.java交互的是ImsCallModification.java。MTK则有所不同,MTK将viLTE大部分业务逻辑放在了native层,如与modem交互的逻辑、与Camera交互的逻辑等。上层通过与native层交发送和接收消息。所以上层是相对封闭的,也较好维护。
        视频通话主要有发起视频通话请求和接受视频通话请求。 发起视频请求有两种方式,从联系人中直接拨打视频通话;或在通话过程中发起通话升级请求,将当前通话升级为视频通话。同样接收视频通话请求也可以在语音通话过程和非语音通话中接收。上述这两种方式走的代码路径是一样的,我们就以语音通话过程中发起视频通话请求(send upgrade call request)和接收视频通话请求(receive upgrade request)为例,分析流程
整体流程示意:
    上图中有两种情况,第一种为正常upgrade call的流程。MO向服务器发送send request请求,服务器处理后向MT发送指令,MT方modem会上报receive request。MT处理后(receive或reject)向服务器send response。MO的modem会上报receive response。第二种是超时后服务器给双发送消息。我们就以第一种情况来分析视频通话的功能流程。

viLTE功能流程

发起视频请求(send upgrade call request)

流程

    当用户发起upgrade call请求后,InCallUI会向下发送sendSessionModifyRequest(),这个比较好理解,up/down grade都可以理解为modify call,向网络请求建立视频通话,当然是sendRequest。请求最后由ImsVTProvider传递给native层,由native层与modem交互。对方接听/拒接后,native层会回调ImsVTProvider的postEventFromNative()方法,将modem的信息传递上来。随后ImsVTProvider上报receiveSessionModifyResponse()消息。最终由CallList将消息传递给Presenter。流程如下图

关键log
做ROM开发时,系统Log是重要的调试流程通畅的关键依据,所以这里将关键log贴出


 //发起升级请求
        VideoCallImpl.sendSessionModifyRequest()
        logv("[sendSessionModifyRequest]current: " + originalProfile + ", requesting: " + requestProfile);

        //收到native层上报的消息
        ImsVTProvider.postEventFromNative() 
        Log.d(TAG, "postEventFromNative : msg = SESSION_EVENT_RECV_SESSION_CONFIG_RSP");

         //InCallUI收到消息
         InCallVideoCallCallback.onSessionModifyResponseReceived()
         Log.d(this, "onSessionModifyResponseReceived status=" + status + " requestedProfile=" + requestedProfile 
         + " responseProfile=" + responseProfile);
        
         InCallUI.Call.setSessionModificationState()
         Log.d(this, "setSessionModificationState " + state + " mSessionModificationState="  + mSessionModificationState);

         CallCardPresenter.onSessionModificationStateChange()
         Log.d(this, "onSessionModificationStateChange : sessionModificationState = " + sessionModificationState);

接收视频通话请求(receive upgrade request)

流程

    当MT收到modem上报的视频请求时,ImsVTProvider.java收到来自native层的recevieSessionModifyRequest()消息,一步步将消息更新至UI,代码路径与send request一致;用户接听后,向下发送sendSessionModifyResponse()消息。同样,通过ImsVTProvider.java将消息发送至native层,从而下发到modem。流程图如下:

 另外,我们在请求或接受视频通话时,都会带有一个参数,那就是VideoProfile,类位于framework/base/telecom目录下,它封装了viLTE的业务数据,包括视频通话质量、摄像 头使用情况、viLTE状态等。我们可以使用该类获取或表示viLTE的当前状态来进行相应逻辑操作。例如根据视频质量来toast信息。由于它需要在进程间通信,所以它实现了Parcelable接口。

关键log
 ImsVTProvider.postEventFromNative()
           Log.d(TAG, "postEventFromNative : msg = SESSION_EVENT_RECV_SESSION_CONFIG_REQ");

           InCallVideoCallCallback.onSessionModifyRequestReceived()
           Log.d(this, " onSessionModifyRequestReceived videoProfile=" + videoProfile);
           Log.d(this, "VideoState[pre:" + previousVideoState + ",new:" + newVideoState + ",preVC:" 
          + wasVideoCall + ",curVC" + isVideoCall);

           InCallVideoCallCallbackNotifier.upgradeToVideoRequest()
           Log.d(this, "upgradeToVideoRequest call = " + call + " new video state = " + videoState);

           VideoSessionController.onUpgradeToVideoRequest()
           logd("onUpgradeToVideoRequest callId = " + getId(call) + " new video state = " + videoState);

           InCallUI.Call.setRequestedVideoState()
           Log.d(this, "setRequestedVideoState - video state= " + videoState);
           Log.d(this, "setRequestedVideoState - mSessionModificationState=" + mSessionModificationState 
           + " video state= " + videoState);

           CallList.onUpgradeToVideo()
           Log.d(this, "onUpgradeToVideo call=" + call);
  

视频通话界面初始化(video call UI Init

     当对方接受upgrade request后,modem上报的call信息就会变化,消息一层层传递到InCallUI,VideoCallPresenter.onStateChange()方法会监听到这种变化,将通话界面更新 为视频通话。也就是初始化video call UI。其中主要有两部分,打开Camera以及启动 VideoCallFragment

打开摄像头(setCamera(int CameraId) 

流程

 通过调用Camera API看开启摄像头, 默认开启前置摄像头,CameraId为1。转换摄像头的操作也是通过setCamera()实现,只不过是参数CameraId不同。流程如下:

与send reques操作的代码路径一样,调用Camera API的逻辑实现也是在native中。上层通过ImsVTProvider下发消息。但需要注意的是,ImsVTProvider的native回调方法postEventFromNative中调用的是ImsVideoCallProvider.handleCallSessionEvent()向上反馈信息,从方法名可以看出来,这是个通用方法,底层的好多消息都是通过该方法向上传递的。如下:


关键log

 VideoCallImpl.setCamera()
 logv("[setCamera]cameraId = " + cameraId);
 ImsVTProvider.postEventFromNative()
 Log.d(TAG, "postEventFromNative : msg = MSG_PEER_CAMERA_OPEN");

VideoCallFragment初始化

流程

     从打开摄像头的流程图可以看出,VideoCallPresenter向VideoCallFragment发送消息showVideoViews()从而启动VideoCallFragment,那么 VideoCallFragment是如何展现Camera捕获到的本端媒体流以及网络上报的对端媒体流呢?VideoCallFragment的初始化就进行了准备工作。
     首先,VideoImpl.java提供了方法 setPreviewSurface(Surface surface)及setDisplaySurface(Surface surface)来设置用于展现本端媒体流(Preview)及对端媒体流(Display)的Surface。Surface是一个控件,用于展示媒体流,它有很多子类,在VideoCallFragment中使用的是Surface的子类之一 TextureView来展现媒体流。在VideoCallFragment中,内部类VideoCallSurface封装了TextureView及获取媒体流的逻辑,我们通过调用创建VideoCallSurface对象及调用其暴露的方法便可以获取媒体流。 
           VideoCallSurface类实现了TextureView.SurfaceTextureListener接口,并实现onSurfaceTextureAvailable()、onSurfaceTextureDestroyed()等接口方法。首先调用TextureView.setSurfaceTextureListener(this),这样,在SurfaceTexture准备好后,会调用到onSurfaceTextureAvailable()方法,在该方法中上报了准备好的surfaceTexture。这时我们将获取到的surfaceTexture设置给TextureView,随后,调用VideoImpl.setPreviewSurface()或setDisplaySurface()将TextureView传递到VideoImpl中。这样,TextureView便能显示图像流了。流程如下:

    上图中,setPreviewSurface()的代码路径与setCamera、send requset等一样,因此在流程图中简化了VideoCallImpl向下发送setPreviewSurface的流程。另外,在步骤3inflatVideoCallViews()在,构造了两个VideoCallSurface,在构造时传入了参数surfaceId用于标记该VideoCallSurface是用于Preview还是Display。这样,在步骤10 onSurfaceCreated中,可以用该Id来决定调用setPreviewSurface还是setDisplaySurface(),code如下:

inflatVideoCallViews()代码截图

setPreviewSurface()代码截图

关键log

//VideoCallPresenter收到通话信息的变化
VideoCallPresenter.onStateChange()
Log.d(this, "onStateChange oldState" + oldState + " newState=" + newState +" isVideoMode=" + isVideoMode());
VideoCallPresenter.checkForVideoCallChange()
Log.d(this, "checkForVideoCallChange: videoCall=" + videoCall + " mVideoCall=" + mVideoCall);
VideoCallPresenter.checkForVideoStateChange()
Log.d(this, "checkForVideoStateChange: isVideoCall= " + isVideoCall + " hasVideoStateChanged=" +
      hasVideoStateChanged + " isVideoMode=" + isVideoMode() + " previousVideoState: " +
      VideoProfile.videoStateToString(mCurrentVideoState) + " newVideoState: "+ 
      VideoProfile.videoStateToString(call.getVideoState()));
 //当视频通话成功建立,isVideoCall = true
VideoCallPresenter.enterVideoMode()
Log.d(this, "enterVideoMode videoCall= " + videoCall + " videoState: " + newVideoState);
//videoCallFragment初始化
VideoCallFragment.inflateVideoCallViews()
Log.d(this, "inflateVideoCallViews");
Log.d(this, "inflateVideoCallViews: sVideoSurfacesInUse=" + sVideoSurfacesInUse);
Log.d(this, " inflateVideoCallViews screenSize" + screenSize);
VideoCallSurface.VideoCallSurface()
Log.d(this, "VideoCallSurface: surfaceId=" + surfaceId + " width=" + width + " height=" + height);
Log.d(this, "recreateView: SavedSurfaceTexture=" + mSavedSurfaceTexture + " 
    areSameSurfaces=" + areSameSurfaces);

VideoCallSurface.onSurfaceTextureAvailable()
Log.d(this, " onSurfaceTextureAvailable mSurfaceId=" + mSurfaceId + " surfaceTexture="  +
    surfaceTexture + " width=" + width+ " height=" + height + " mSavedSurfaceTexture=" + 
    mSavedSurfaceTexture);
VideoCallPresenter.onSurfaceCreated()
Log.d(this, "onSurfaceCreated surface=" + surface + " mVideoCall=" + mVideoCall);
Log.d(this, "onSurfaceCreated PreviewSurfaceState=" + mPreviewSurfaceState);
Log.d(this, "onSurfaceCreated presenter=" + this);

VideoCallImpl.setPreviewSurface()
logv("[setPreviewSurface]preview = " + surface);    
VideoCallImpl.setDisplaySurface()
logv("[setDisplaySurface]display = " + surface);  

猜你喜欢

转载自blog.csdn.net/u012545728/article/details/80549415
MTK
今日推荐