IMS Modify Call (2) receive request 收到视频升级请求

主要内容为MT收到视频升级的请求的过程,也是MT消息上传的过程。

流程图

可以看到信息上报跨了4个模块,没有经过service/Telecom

看关键log方便跟踪


06-19 19:05:41.437 3329-4362/com.android.phone V/ImsSenderRxr: Read packet: 24 bytes

06-19 19:05:41.437 3329-4362/com.android.phone V/ImsSenderRxr: processResponse[SUB1]

06-19 19:05:41.437 3329-4362/com.android.phone D/ImsSenderRxr: Response data: [12, 13, -1, -1, -1, -1, 16, 3, 24, -49, 1, 32, 0, 21, 1, 0, 0, 0, 26, 4, 8, 3, 16, 2][SUB1]

06-19 19:05:41.437 3329-4362/com.android.phone D/ImsSenderRxr:  Tag -1 3 207 0[SUB1]

06-19 19:05:41.437 3329-4362/com.android.phone D/ImsSenderRxr: responseModifyCall  1  3 2 callSubState 0 videoPauseState2 mediaId-1 Local Ability  Peer Ability  Cause code 0 0[SUB1]

06-19 19:05:41.438 3329-4362/com.android.phone D/ImsSenderRxr: [UNSL]< UNSOL_MODIFY_CALL  1  3 2 callSubState 0 videoPauseState2 mediaId-1 Local Ability  Peer Ability  Cause code 0 0[SUB1]

06-19 19:05:41.438 3329-3329/com.android.phone D/ImsServiceSub: Message received: what = 13

06-19 19:05:41.438 3329-3329/com.android.phone D/ImsServiceSub: handleCallModifyRequest( 1  3 2 callSubState 0 videoPauseState2 mediaId-1 Local Ability  Peer Ability  Cause code 0 0)

06-19 19:05:41.438 3329-3329/com.android.phone D/VideoCall_ImsCallModification: onReceivedCallModify( 1  3 2 callSubState 0 videoPauseState2 mediaId-1 Local Ability  Peer Ability  Cause code 0 0)

06-19 19:05:41.438 3329-3329/com.android.phone D/VideoCall_ImsCallModification: validateIncomingModifyConnectionType newCallType = 3

06-19 19:05:41.438 3329-3329/com.android.phone D/VideoCall_ImsCallModification: validateIncomingModifyConnectionType modifyToCurrCallType = false isIndexValid = true isLowBattery = false

06-19 19:05:41.439 3329-3329/com.android.phone D/VideoCall_ImsVideoCallProviderImpl: (1) onCallTypeChanged session= callid= 1 mediaId=5 

代码段

vendor/qcom/proprietary/telephony-apps/ims

高通私有代码,略。

frameworks/opt/net/ims

android/frameworks/opt/net/ims/src/java/com/android/ims/internal/ImsVideoCallProvider.java

看到方法名带receive request字样,直译就是收到请求,在响应之后方法名中就会换上类似response。


    /** @see Connection.VideoProvider#receiveSessionModifyRequest */

    public void receiveSessionModifyRequest(VideoProfile VideoProfile) {

        if (mCallback != null) {

            try {

                mCallback.receiveSessionModifyRequest(VideoProfile);

            } catch (RemoteException ignored) {

            }

        }

    }

android/frameworks/opt/net/ims/src/java/com/android/ims/internal/ImsVideoCallProviderWrapper.java


    /**

     * IImsVideoCallCallback stub implementation.

     */

    private final class ImsVideoCallCallback extends IImsVideoCallCallback.Stub {

        @Override

        public void receiveSessionModifyRequest(VideoProfile VideoProfile) {

            mHandler.obtainMessage(MSG_RECEIVE_SESSION_MODIFY_REQUEST,

                    VideoProfile).sendToTarget();

        }

    /** Default handler used to consolidate binder method calls onto a single thread. */

    private final Handler mHandler = new Handler(Looper.getMainLooper()) {

        @Override

        public void handleMessage(Message msg) {

            SomeArgs args;

            switch (msg.what) {

                case MSG_RECEIVE_SESSION_MODIFY_REQUEST:

                    receiveSessionModifyRequest((VideoProfile) msg.obj);

                    break;

frameworks/base/telecomm

android/frameworks/base/telecomm/java/android/telecom/Connection.java


        /**

         * Used to inform listening {@link InCallService} implementations when the

         * {@link VideoProvider} receives a session modification request.

         * <p>

         * Received by the {@link InCallService} via

         * {@link InCallService.VideoCall.Callback#onSessionModifyRequestReceived(VideoProfile)},

         *

         * @param videoProfile The requested video profile.

         * @see #onSendSessionModifyRequest(VideoProfile, VideoProfile)

         */

        public void receiveSessionModifyRequest(VideoProfile videoProfile) {

            if (mVideoCallbacks != null) {

                for (IVideoCallback callback : mVideoCallbacks.values()) {

                    try {

                        callback.receiveSessionModifyRequest(videoProfile);//多处调用

                    } catch (RemoteException ignored) {

                        Log.w(this, "receiveSessionModifyRequest callback failed", ignored);

                    }

                }

            }

        }

android/frameworks/base/telecomm/java/android/telecom/VideoCallImpl.java


 

    /**

     * IVideoCallback stub implementation.

     */

    private final class VideoCallListenerBinder extends IVideoCallback.Stub {

        @Override

        public void receiveSessionModifyRequest(VideoProfile videoProfile) {

            if (mHandler == null) {

                return;

            }

            mHandler.obtainMessage(MessageHandler.MSG_RECEIVE_SESSION_MODIFY_REQUEST,

                    videoProfile).sendToTarget();

 

        }

handleMessage


        @Override

        public void handleMessage(Message msg) {

            if (mCallback == null) {

                return;

            }

 

            SomeArgs args;

            switch (msg.what) {

                case MSG_RECEIVE_SESSION_MODIFY_REQUEST:

                    mCallback.onSessionModifyRequestReceived((VideoProfile) msg.obj);

                    break;

前面几乎都没什么说的,走一条线就是了,然后经InCallService接口回调到InCallUI

packages/apps/InCallUI

一般客户有需求,要修改界面的话也都是该InCallUI,下层的流程是不动的,因此下面一部分比较重要

android/packages/apps/InCallUI/src/com/android/incallui/InCallVideoCallCallback.java

目前为止传想来的消息都只是MODIFY CALL,并没有携带说是升级还是降级,从下面的方法中可以看到有分开两种情况了。


    /**

     * Handles an incoming session modification request.

     *

     * @param videoProfile The requested video call profile.

     */

    @Override

    public void onSessionModifyRequestReceived(VideoProfile videoProfile) {

        Log.d(this, " onSessionModifyRequestReceived videoProfile=" + videoProfile);

        int previousVideoState = CallUtils.getUnPausedVideoState(mCall.getVideoState());

        int newVideoState = CallUtils.getUnPausedVideoState(videoProfile.getVideoState());

 

        InCallPresenter.getInstance().wakeUpScreen();

 

        boolean wasVideoCall = CallUtils.isVideoCall(previousVideoState);

        boolean isVideoCall = CallUtils.isVideoCall(newVideoState);

 

        // Check for upgrades to video and downgrades to audio.

        if (wasVideoCall && !isVideoCall) {

            InCallVideoCallCallbackNotifier.getInstance().downgradeToAudio(mCall);

        } else if (previousVideoState != newVideoState) {

            InCallVideoCallCallbackNotifier.getInstance().upgradeToVideoRequest(mCall,

                newVideoState);

        }

    }

升级视频的请求


 

    /**

     * Inform listeners of an upgrade to video request for a call.

     * @param call The call.

     * @param videoState The video state we want to upgrade to.

     */

    public void upgradeToVideoRequest(Call call, int videoState) {

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

        for (SessionModificationListener listener : mSessionModificationListeners) {

            listener.onUpgradeToVideoRequest(call, videoState);

        }

    }

InCallPresenter


    @Override

    public void onUpgradeToVideoRequest(Call call, int videoState) {

        Log.d(this, "onUpgradeToVideoRequest call = " + call + " video state = " + videoState);

 

        if (call == null) {

            return;

        }

 

        call.setSessionModificationTo(videoState);

    }

android/packages/apps/InCallUI/src/com/android/incallui/Call.java


    /**

     * This method is called when we request for a video upgrade or downgrade. This handles the

     * session modification state RECEIVED_UPGRADE_TO_VIDEO_REQUEST and sets the video state we

     * want to upgrade/downgrade to.

     */

    public void setSessionModificationTo(int videoState) {

        Log.d(this, "setSessionModificationTo - video state= " + videoState);

        if (videoState == getVideoState()) {

            mSessionModificationState = Call.SessionModificationState.NO_REQUEST;

            Log.w(this,"setSessionModificationTo - Clearing session modification state");

        } else {

            mSessionModificationState =

                Call.SessionModificationState.RECEIVED_UPGRADE_TO_VIDEO_REQUEST;

            setModifyToVideoState(videoState);

            CallList.getInstance().onUpgradeToVideo(this);

        }

 

        Log.d(this, "setSessionModificationTo - mSessionModificationState="

            + mSessionModificationState + " video state= " + videoState);

        update();

    }

android/packages/apps/InCallUI/src/com/android/incallui/CallList.java


    public void onUpgradeToVideo(Call call){

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

        for (Listener listener : mListeners) {

            listener.onUpgradeToVideo(call);

        }

    }

看前面的注释

这是modify call的唯一调用的方法,等下我们看下降级的


         * Called when a new modify call request comes in

         * This is the only method that gets called for modify requests.

         */

        public void onUpgradeToVideo(Call call);

android/packages/apps/InCallUI/src/com/android/incallui/AnswerPresenter.java

界面显示,(在5.1上我们自己做过升级声音提示,在6.0上高通加了一个类实现这个功能,不知道AOSP上有没有那个提示音的功能)


    @Override

    public void onUpgradeToVideo(Call call) {

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

        showAnswerUi(true);//一次

        boolean isUpgradePending = isVideoUpgradePending(call);

        InCallPresenter inCallPresenter = InCallPresenter.getInstance();

        if (isUpgradePending

                && inCallPresenter.getInCallState() == InCallPresenter.InCallState.INCOMING) {

            Log.d(this, "declining upgrade request");

            //If there is incoming call reject upgrade request

            inCallPresenter.declineUpgradeRequest(getUi().getContext());

        } else if (isUpgradePending) {

            Log.d(this, "process upgrade request as no MT call");

            processVideoUpgradeRequestCall(call);

        }

    }

 private void processVideoUpgradeRequestCall(Call call) {

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

        int subId = call.getSubId();

        int phoneId = mCalls.getPhoneId(subId);

        mCallId[phoneId] = call.getId();

        mCall[phoneId] = call;

 

        // Listen for call updates for the current call.

        CallList.getInstance().addCallUpdateListener(mCallId[phoneId], this);

 

        final int currentVideoState = call.getVideoState();

        final int modifyToVideoState = call.getModifyToVideoState();

 

        if (currentVideoState == modifyToVideoState) {

            Log.w(this, "processVideoUpgradeRequestCall: Video states are same. Return.");

            return;

        }

 

        AnswerUi ui = getUi();

 

        if (ui == null) {

            Log.e(this, "Ui is null. Can‘t process upgrade request");

            return;

        }

        showAnswerUi(true);//2次

        ui.showTargets(QtiCallUtils.getSessionModificationOptions(getUi().getContext(),

                currentVideoState, modifyToVideoState));

 

    }

QtiCallUtils.java

根据实际情况,在界面AnswerFragment上显示不同选择。


    /**

     * Returns the session modification user options based on session modify request video states

     * (current video state and modify request video state)

     */

    public static int getSessionModificationOptions(Context context, int currentVideoState,

            int modifyToVideoState) {

        if (!useExt(context)) {

            return AnswerFragment.TARGET_SET_FOR_VIDEO_ACCEPT_REJECT_REQUEST;

        }

 

        if (showVideoUpgradeOptions(currentVideoState, modifyToVideoState)) {

            return AnswerFragment.TARGET_SET_FOR_QTI_VIDEO_ACCEPT_REJECT_REQUEST;

        } else if (isEnabled(VideoProfile.STATE_BIDIRECTIONAL, modifyToVideoState)) {

            return AnswerFragment.TARGET_SET_FOR_QTI_BIDIRECTIONAL_VIDEO_ACCEPT_REJECT_REQUEST;

        } else if (isEnabled(VideoProfile.STATE_TX_ENABLED, modifyToVideoState)) {

            return AnswerFragment.TARGET_SET_FOR_QTI_VIDEO_TRANSMIT_ACCEPT_REJECT_REQUEST;

        } else if (isEnabled(VideoProfile.STATE_RX_ENABLED, modifyToVideoState)) {

            return AnswerFragment.TARGET_SET_FOR_QTI_VIDEO_RECEIVE_ACCEPT_REJECT_REQUEST;

        }

        return AnswerFragment.TARGET_SET_FOR_QTI_VIDEO_ACCEPT_REJECT_REQUEST;

    }

在我们的代码中,这个返回值后面被修改了,会根据运营商返回不同的值,


    /**

     * Checks the boolean flag in config file to figure out if we are going to use Qti extension or

     * not

     */

    public static boolean useExt(Context context) {

        if (context == null) {

            Log.w(context, "Context is null...");

        }

        return isConfigEnabled(context, R.bool.video_call_use_ext);//这个布尔值默认为true,但是针对mnc为405的都重写成了false

    }

AnswerFragment.java

显示到界面上


    /**

     * Sets targets on the glowpad according to target set identified by the parameter.

     * @param targetSet Integer identifying the set of targets to use.

     */

    public void showTargets(int targetSet) {

        showTargets(targetSet, VideoProfile.STATE_BIDIRECTIONAL);

    }

 

    /**

     * Sets targets on the glowpad according to target set identified by the parameter.

     * @param targetSet Integer identifying the set of targets to use.

     */

    @Override

    public void showTargets(int targetSet, int videoState) {

        final int targetResourceId;

        final int targetDescriptionsResourceId;

        final int directionDescriptionsResourceId;

        final int handleDrawableResourceId;

        mGlowpad.setVideoState(videoState);

        final boolean isEnhanceUIEnabled = getContext().getResources().getBoolean(

                R.bool.config_enable_enhance_video_call_ui);

 

        switch (targetSet) {

            ...

            case TARGET_SET_FOR_VIDEO_ACCEPT_REJECT_REQUEST:

                targetResourceId =

                        R.array.incoming_call_widget_video_request_targets;

                targetDescriptionsResourceId =

                        R.array.incoming_call_widget_video_request_target_descriptions;

                directionDescriptionsResourceId = R.array

                        .incoming_call_widget_video_request_target_direction_descriptions;

                handleDrawableResourceId = R.drawable.ic_incall_video_handle;

                break;

log


06-19 19:05:41.622 14182-14182/com.android.dialer I/InCall: StatusBarNotifier - Will show "dismiss upgrade" action in the incoming call Notification

06-19 19:05:41.624 14182-14182/com.android.dialer I/InCall: StatusBarNotifier - Will show "accept upgrade" action in the incoming call Notification

关键log

MT receive

收到视频升级请求


//receive

06-19 19:05:41.437 3329-4362/com.android.phone V/ImsSenderRxr: Read packet: 24 bytes

06-19 19:05:41.437 3329-4362/com.android.phone V/ImsSenderRxr: processResponse[SUB1]

06-19 19:05:41.437 3329-4362/com.android.phone D/ImsSenderRxr: Response data: [12, 13, -1, -1, -1, -1, 16, 3, 24, -49, 1, 32, 0, 21, 1, 0, 0, 0, 26, 4, 8, 3, 16, 2][SUB1]

06-19 19:05:41.437 3329-4362/com.android.phone D/ImsSenderRxr:  Tag -1 3 207 0[SUB1]

06-19 19:05:41.437 3329-4362/com.android.phone D/ImsSenderRxr: responseModifyCall  1  3 2 callSubState 0 videoPauseState2 mediaId-1 Local Ability  Peer Ability  Cause code 0 0[SUB1]

06-19 19:05:41.438 3329-4362/com.android.phone D/ImsSenderRxr: [UNSL]< UNSOL_MODIFY_CALL  1  3 2 callSubState 0 videoPauseState2 mediaId-1 Local Ability  Peer Ability  Cause code 0 0[SUB1]

MO send request, accepted, rejected, time out

MT接受升级请求后MO的log


//accepted response

06-25 21:37:21.793 3289-4294/com.android.phone V/ImsSenderRxr: Read packet: 12 bytes

06-25 21:37:21.793 3289-4294/com.android.phone V/ImsSenderRxr: processResponse[SUB1]

06-25 21:37:21.793 3289-4294/com.android.phone D/ImsSenderRxr: Response data: [11, 13, 110, 0, 0, 0, 16, 2, 24, 17, 32, 0][SUB1]

06-25 21:37:21.793 3289-4294/com.android.phone D/ImsSenderRxr:  Tag 110 2 17 0[SUB1]

06-25 21:37:21.793 3289-4294/com.android.phone D/ImsSenderRxr: [0110]< MODIFY_CALL_INITIATE [SUB1]

06-25 21:37:21.793 3289-3289/com.android.phone D/VideoCall_ImsCallModification: EVENT_MODIFY_CALL_INITIATE_DONE received

升级请求被拒绝和超时,可以看到两者的log是一样的


//send request

06-21 16:00:12.167 13623-13623/com.android.phone D/ImsSenderRxr: [0021]> MODIFY_CALL_INITIATE[SUB0]

//reject

06-21 16:00:19.129 13623-14690/com.android.phone D/ImsSenderRxr: [0021]< MODIFY_CALL_INITIATE error: 28

06-21 16:00:19.129 13623-13623/com.android.phone D/VideoCall_ImsCallModification: EVENT_MODIFY_CALL_INITIATE_DONE received




//send request

07-17 10:00:11.655 2915-2915/com.android.phone D/ImsSenderRxr: [0028]> MODIFY_CALL_INITIATE[SUB1]

//time out

07-17 10:00:27.733 2915-4049/com.android.phone D/ImsSenderRxr: [0028]< MODIFY_CALL_INITIATE error: 28
07-17 10:00:27.733 2915-2915/com.android.phone D/VideoCall_ImsCallModification: EVENT_MODIFY_CALL_INITIATE_DONE received


07-17 10:00:27.748 13872-13872/com.android.dialer D/InCall: InCallVideoCallCallback - onSessionModifyResponseReceived status=5 requestedProfile=[VideoProfile videoState = Audio Tx Rx

MT不做任何处理的话15秒后(运营商决定)MO收到运营商发来的响应消息,其中包括InCallVideoCallCallback - onSessionModifyResponseReceived status=5,这个5的定义为VideoProvider.SESSION_MODIFY_REQUEST_REJECTED_BY_REMOTE(5)意为被远端拒绝了可见对于MO来说超时和reject是一样的,而在MT收到的则是VideoProvider.SESSION_MODIFY_REQUEST_TIMED_OUT(4),所以在MT方
reject和time out是区分的。

然后这个error: 28的定义在imsIF.proto中查到,也证明了timeout和reject的。


E_REJECTED_BY_REMOTE = 28;              /* Remote end rejected a change started by

                                                   REQUEST_MODIFY_CALL_INITIATE */

小结

整个流程中的log不多,主要是底层ImsSenderRxr.java中的log多些,UNSOL_MODIFY_CALL (未处理的新消息),MODIFY_CALL_CONFIRM(MT界面应答),MODIFY_CALL_INITIATE(MO发起),然后InCall中在一些场景中有些log,AnswerPresenter和CallCardPresenter的log。

如果出问题的话也基本上在从底层和上层判断,中间应该不会有什么问题,底层看消息首发,上层看信息显示。Modify Call已经包括upgrade和downgrade,流程整体也是一样,在需要区分的时候会通过callType(CallMofidy)来区分。

时间: 2024-10-12 17:38:50

IMS Modify Call (2) receive request 收到视频升级请求的相关文章

IMS Modify Call (1) send request 发出升级视频请求

upgrade/downgrade 升降级,其实就是ModifyCall 整体示意 图中有两种情况,一种是MT对收到的升级请求做出响应,一种是超时后服务器给双发发送消息. 一个完整的Modify call(upgrade)可以分为4个部分,本文主要讲第一部分发出升级请求. 流程图 界面入手 packages/apps/InCallUI packages/apps/InCallUI/src/com/android/incallui/CallButtonFragment.java CallButto

[原创]java WEB学习笔记15:域对象的属性操作(pageContext,request,session,application) 及 请求的重定向和转发

本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱好者,互联网技术发烧友 微博:伊直都在0221 QQ:951226918 ---------------------------------

HttpServletRequest、request常用方法、request常见应用、请求转发、RequestDispatcher

HttpServletRequest对象代表客户端的请求,当客户端通过HTTP协议访问服务器时,HTTP请求头中的所有信息都封装在这个对象中,开发人员通过这个对象的方法,可以获得客户这些信息. request常用方法 获得客户机信息 getRequestURL方法返回客户端发出请求时的完整URL. getRequestURI方法返回请求行中的资源名部分. getQueryString 方法返回请求行中的参数部分. getRemoteAddr方法返回发出请求的客户机的IP地址 getRemoteH

Servlet里面request处理外部POST请求的输入流的工具类

package etcom.servlet; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import javax.servlet.http.HttpServletRequest; public class IoToJsonUtils { public static String getIoToJso

解决为什么已经设置了request.setCharacterEncoding(&quot;utf-8&quot;);POST请求仍然乱码的问题

request.setCharacterEncoding("utf-8");应该在获取请求参数之前设置 在 http://bbs.csdn.net/topics/380124606 和 http://bbs.csdn.net/topics/370125113 找到的答案 由于POST传来数据,Tomcat默认以ISO-8859-1编码成单字节数据,若没有进行请求编码设置或重新编码操作,那么中文字符会在jsp页面中输出???,出现类似多个?形式的乱码现象. 测试发现,尽管jsp页面con

Jetty开发指导:Jetty Websocket API

Jetty WebSocket API使用 Jetty提供了功能更强的WebSocket API,使用一个公共的核心API供WebSockets的服务端和client使用. 他是一个基于WebSocket消息的事件驱动的API. WebSocket事件 每一个WebSocket都能接收多种事件: On Connect Event 表示WebSocket升级成功,WebSocket如今打开. 你将收到一个org.eclipse.jetty.websocket.api.Session对象,相应这个O

ASP.NET之Request和Response对象

经过了牛腩新闻公布系统和html的学习对B/S开发的流程有了些理解.前面尽管用到了非常多知识.但对制作网页仅仅能说知其然.当学到asp.net视频中的解说才干够说開始知其所以然了. 今天来说说client与server之间进行交流用到的Request和Response对象. Request:用户在client使用Web浏览器向Web应用程序发出请求时,会将client信息发给server.server收到一个HTTP请求,包括了全部查询字符串參数或表单參数.Cookie数据以及浏览器信息. 在a

UDP 網路程式設計 (2) --- request / response

在 Oracle 網站上,有個簡單的 UDP 程式範例 --- Lesson: All About Datagrams,這個程式和前一個程式基本上是差不多的,差別在於,它是由 client 先送個 request 給 server 端,server 端接收到後,回應訊息給 client 端,下面是 Oracle 的範例程式. 1 package idv.steven; 2 3 import java.io.*; 4 import java.net.*; 5 import java.util.*;

C#微信开发小白成长教程一(公众平台的工作原理与调试环境部署,附视频)

黑夜给了我黑色的眼睛,我决定录视频到天明.半年前的现在,我还在苦逼着加着班,半年后的今天我依旧苦逼着加着班.不过现在的是为自己加班,作为一个资深程序小白,一个月前我光荣的成了一个不称职的资本家,不称职的原因有二:一是我人丑钱少脸皮薄(没有资本),而是我先阶段还只能剥削我自己. 回想着半年的历程,好像发生很多事.从由于辛辛苦苦准备的微信培训资料被公司的同事忽视而在博客园写下的第一篇微信教程,到电子出版社的编辑联系到我商讨出版的事,从签订出版合同到开始写下书的第一个字,从每天加班到凌晨回去还得加班写