通话类型转换流程之AudioCall到VideoCall

news2024/11/26 15:35:50

目录

  1. 概述
  2. 时序图
  3. 关键代码
  4. 关键log
  5. 总结

一、概述

  这里的通话类型指的是语音通话和视频通话,转换包括upgrade/ downgrade升降级,就是语音通话升级为视频通话、视频通话降级为语音通话。升级为视频通话一般就是包括如下图示的4步,MO发起请求,MT接收请求,MT响应请求,MO接收响应。本文主要学习第一步,MO发起请求的流程(upgradeToVideo为例)。

二、时序图

如上为MO发起请求upgradeToVideo的时序图,主要包含从App(Dialer)到最终通过imsRadio发起请求的过程。

下面跟着关键代码进一步理解这一过程。

三、关键代码

代码主要包含如下几个路径,时序图最上面也有标识出。

packages\apps\Dialer

frameworks\base\telecomm

frameworks\opt\net\ims

vendor\qcom\proprietary\commonsys\telephony-apps\ims

  1. App界面点击

packages/apps/Dialer/java/com/android/incallui/incall/impl/ButtonController.java

 class UpgradeToVideoButtonController extends SimpleNonCheckableButtonController {
    public UpgradeToVideoButtonController(@NonNull InCallButtonUiDelegate delegate) {
      super(
          delegate,
          InCallButtonIds.BUTTON_UPGRADE_TO_VIDEO,
          0,
          R.string.incall_label_videocall,
          R.drawable.quantum_ic_videocam_white_36);
      Assert.isNotNull(delegate);
    }
    @Override
    public void onClick(View view) {
      delegate.changeToVideoClicked();
    }
  }

 

packages/apps/Dialer/java/com/android/incallui/CallButtonPresenter.java

  @Override
  public void changeToVideoClicked() {
    LogUtil.enterBlock("CallButtonPresenter.changeToVideoClicked");
    Logger.get(context)
        .logCallImpression(
            DialerImpression.Type.VIDEO_CALL_UPGRADE_REQUESTED,
            call.getUniqueCallId(),
            call.getTimeAddedMs());
    call.getVideoTech().upgradeToVideo(context);
  }

packages/apps/Dialer/java/com/android/incallui/videotech/ims/ImsVideoTech.java

  @Override
  public void upgradeToVideo(@NonNull Context context) {
    LogUtil.enterBlock("ImsVideoTech.upgradeToVideo");
    int unpausedVideoState = getUnpausedVideoState(call.getDetails().getVideoState());
    call.getVideoCall()
        .sendSessionModifyRequest(
            new VideoProfile(unpausedVideoState | VideoProfile.STATE_BIDIRECTIONAL));
setSessionModificationState(SessionModificationState.WAITING_FOR_UPGRADE_TO_VIDEO_RESPONSE);
    logger.logImpression(DialerImpression.Type.IMS_VIDEO_UPGRADE_REQUESTED);
  }

 

sendSessionModifyRequest,Dialer中的点击事件完成,下一步是frameworks中的流程。

  1. frameworks中的流程

video provider发送callType修改请求。
frameworks/base/telecom/java/android/telecom/VideoCallImpl.java

 

    public void sendSessionModifyRequest(VideoProfile requestProfile) {
        try {
            VideoProfile originalProfile = new VideoProfile(mVideoState, mVideoQuality);
            mVideoProvider.sendSessionModifyRequest(originalProfile, requestProfile);
        } catch (RemoteException e) {
        }
    }

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

VideoProviderBinder

/**
* IVideoProvider stub implementation.
*/
private final class VideoProviderBinder extends IVideoProvider.Stub {
    public void sendSessionModifyRequest(VideoProfile fromProfile, VideoProfile toProfile) {
       SomeArgs args = SomeArgs.obtain();
       args.arg1 = fromProfile;
       args.arg2 = toProfile;
       mMessageHandler.obtainMessage(MSG_SEND_SESSION_MODIFY_REQUEST, args).sendToTarget();
    }
}

 

VideoProviderHandler

case MSG_SEND_SESSION_MODIFY_REQUEST: {
   SomeArgs args = (SomeArgs) msg.obj;
   try {
      onSendSessionModifyRequest((VideoProfile) args.arg1, (VideoProfile) args.arg2);
   } finally {
      args.recycle();
   }
   break;
}
public abstract void onSendSessionModifyRequest(VideoProfile fromProfile,
    VideoProfile toProfile);

 

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

重写 Connection.java中的onSendSessionModifyRequest方法。

/** @inheritDoc */
public void onSendSessionModifyRequest(VideoProfile fromProfile, VideoProfile toProfile) {
   try {
……
       mVideoCallProvider.sendSessionModifyRequest(fromProfile, toProfile);
   } catch (RemoteException e) {
   }
}

 

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

public void sendSessionModifyRequest(VideoProfile fromProfile, VideoProfile toProfile) {
    SomeArgs args = SomeArgs.obtain();
    args.arg1 = fromProfile;
    args.arg2 = toProfile;
    mProviderHandler.obtainMessage(MSG_SEND_SESSION_MODIFY_REQUEST, args).sendToTarget();
}

 

mProviderHandler

case MSG_SEND_SESSION_MODIFY_REQUEST: {
    SomeArgs args = (SomeArgs) msg.obj;
    try {
        VideoProfile fromProfile = (VideoProfile) args.arg1;
        VideoProfile toProfile = (VideoProfile) args.arg2;
        onSendSessionModifyRequest(fromProfile, toProfile);
    } finally {
        args.recycle();
    }
    break;
}
/** @see Connection.VideoProvider#onSendSessionModifyRequest */
public abstract void onSendSessionModifyRequest(VideoProfile fromProfile,
            VideoProfile toProfile);

frameworks中的处理完成,下一步到高通私有类中接着处理

3、高通私有类中的流程

vendor/qcom/proprietary/commonsys/telephony-apps/ims/src/com/qualcomm/ims/

vt/ImsVideoCallProviderImpl.java

重写 onSendSessionModifyRequest方法

@Override
public void onSendSessionModifyRequest(VideoProfile fromProfile, VideoProfile toProfile) {
......
        // Neither pause or resume, so this is upgrade/downgrade request
        Message newMsg = mHandler.obtainMessage(EVENT_SEND_SESSION_MODIFY_REQUEST_DONE);
        int callType = ImsCallUtils.convertVideoStateToCallType(toProfile.getVideoState());
        mImsCallModification.changeConnectionType(newMsg, callType, null);
}

到这可以看到,从传过来的VideoProfile中获取了需要转换的callType。

Vendor/qcom/proprietary/commonsys/telephony-apps/ims/src/org/codeaurora/ims/ ImsCallModification.java

// MODIFY_CALL_INITIATE

public void changeConnectionType(Message msg, int newCallType, Map<String, String> newExtras){
......
    modifyCallInitiate(newMsg, newCallType, newExtras);
......
}
private void modifyCallInitiate(Message newMsg, int newCallType, Map<String, String> newExtras){
......
   CallDetails callDetails = new CallDetails(newCallType, mImsCallSessionImpl.getCallDomain(),
                CallDetails.getExtrasFromMap(newExtras));
   ImsCallProfile callProfile = mImsCallSessionImpl.getCallProfile();
   if (callProfile != null) {
      callDetails.setRttMode(callProfile.mMediaProfile.mRttMode);
   }
   CallModify callModify = new CallModify(callDetails, mIndex);
   mCi.modifyCallInitiate(newMsg, callModify);
}

将newCallType转换为callModify传入。

Vendor/qcom/proprietary/commonsys/telephony-apps/ims/src/org/codeaurora/

ims/ImsSenderRxr.java

 

public void modifyCallInitiate(Message result, CallModify callModify) {
    ......
    try {
        logSolicitedRequest(rr);
        imsRadioV10().modifyCallInitiate(rr.mSerial,
                ImsRadioUtils.buildCallModifyInfo(callModify));
    } catch (Exception ex) {
        removeFromQueueAndSendResponse(rr.mSerial);
        Log.e(this, msgIdString + "request to IImsRadio: Exception: " + ex);
    }
}

最后通过imsRadio将callModify发送出去

关键log

//upgrade
03-01 00:12:58.120  4918  4918 D VideoCall_ImsVideoCallProviderImpl: (1) onSendSessionModifyRequest, videoState=3 quality= 4
03-01 00:12:58.120  4918  4918 D VideoCall_ImsCallModification: validateOutgoingModifyConnectionType newCallType=3//CalllType 和videoState对应
03-01 00:12:58.120  4918  4918 D VideoCall_ImsCallModification: validateOutgoingModifyConnectionType modifyToCurrCallType = false isIndexValid = true isLowBattery = false
03-01 00:12:58.120  4918  4918 V ImsSenderRxr: modifyCallInitiate callModify=  1  3 2 callSubState 0 videoPauseState2 mediaId-1 Local Ability  Peer Ability  Cause code 0 0[SUB1]
03-01 00:12:58.120  4918  4918 V ImsSenderRxr: setCallModify callModify=  1  3 2 callSubState 0 videoPauseState2 mediaId-1 Local Ability  Peer Ability  Cause code 0 0[SUB1]
03-01 00:12:58.120  4918  4918 D ImsSenderRxr: [0044]> MODIFY_CALL_INITIATE[SUB1]
03-01 00:13:02.989  4918  5512 D ImsSenderRxr: [0044]< MODIFY_CALL_INITIATE [SUB1]
03-01 00:13:02.989  4918  4918 D VideoCall_ImsCallModification: EVENT_MODIFY_CALL_INITIATE_DONE received
03-01 00:13:02.989  4918  4918 D VideoCall_ImsCallModification: clearPendingModify imsconn=org.codeaurora.ims.ImsCallModification@1ea212
03-01 00:13:02.990  4918  4918 D VideoCall_ImsVideoCallProviderImpl: (1) handleSessionModifyDone msg.what=0
03-01 00:13:02.990  4918  4918 D VideoCall_ImsVideoCallProviderImpl: (1) Session modify success

五、总结

在实际开发中,无论是需求还是解bug,重点需要关注的是Dialer App中和framework中的流程,Vendor中的高通私有类的流程了解即可,一般不会修改到,对关键log信息要熟悉,便于对此类问题的分析。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/90196.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Microsoft SharePoint Online 更新功能可能是下一次勒索攻击的目标

Microsoft SharePoint Online是被使用最广泛的内容管理平台之一。但令人担忧的是&#xff0c;最近几年我们发现大部分攻击者可以滥用 SharePoint Online 和 OneDrive for Business 中的某项功能来加密您的所有文件并以此来勒索赎金。 SharePoint Online 据观察发现可能存在潜在…

四旋翼无人机学习第15节--PCB Editor简单绘制封装-手动绘制封装

文章目录1 前言2 class与sub class3 手动绘制3.1 芯片手册分析3.2 手动绘制1 前言 上一篇博客我们学习了获取封装的几种途径&#xff0c;分别是下载&#xff0c;软件生成与软件转化。本次博客开始讲手动绘制封装。 2 class与sub class 参考博客&#xff1a;第11讲、Allegro …

前端高频手写面试题集锦

手写深度比较isEqual 思路&#xff1a;深度比较两个对象&#xff0c;就是要深度比较对象的每一个元素。> 递归 递归退出条件&#xff1a; 被比较的是两个值类型变量&#xff0c;直接用“”判断被比较的两个变量之一为null&#xff0c;直接判断另一个元素是否也为null 提前结…

对受控组件和非受控组件的理解,以及应用场景?

一、受控组件 受控组件&#xff0c;简单来讲&#xff0c;就是受我们控制的组件&#xff0c;组件的状态全程响应外部数据 举个简单的例子&#xff1a; class TestComponent extends React.Component {constructor (props) {super(props);this.state { username: lindaidai }…

从事生活垃圾(含粪便)经营性清扫、收集、运输服务许可证

《城市生活垃圾管理办法》&#xff08;2007年4月28日建设部令第157号公布2015年5月4日修正本&#xff09;第十七条从事城市生活垃圾经营性清扫、收集、运输的企业&#xff0c;应当取得城市生活垃圾经营性清扫、收集、运输服务许可证。 未取得城市生活垃圾经营性清扫、收集、运输…

安卓玩机搞机技巧综合资源-----查看手机硬件全部参数 隐藏参数 多个软件【十七】

接上篇 安卓玩机搞机技巧综合资源------如何提取手机分区 小米机型代码分享等等 【一】 安卓玩机搞机技巧综合资源------开机英文提示解决dm-verity corruption your device is corrupt. 设备内部报错 AB分区等等【二】 安卓玩机搞机技巧综合资源------EROFS分区格式 小米红…

绿色消费积分,共建开放生态,让消费变投资

随着市场的逐渐饱和&#xff0c;不断推出新产品、开拓推广渠道、增加客户量是商家想要实现可持续发展的生存之道。商家为了刺激消费&#xff0c;可以说是无所不用&#xff0c;但还是面临着缺少新用户&#xff0c;推广难&#xff0c;客户活跃度低&#xff0c;复购率低等痛点。 商…

7个用Python就可以搞副业的方法

抢茅台 全民开抢1499元的茅台&#xff0c;你抢到过吗&#xff1f;我表弟去年开始到现在抢到30瓶&#xff0c;一瓶轻松赚1000元。 没想到表弟私信我说&#xff0c;他的茅台都是用软件抢的。 Python是啥&#xff1f;我是2G网了吗&#xff0c;还有这么好用的工具&#xff01;&…

如何把自定义的函数,记录到你的Airtest报告里

1. 前言 熟悉Airtest的同学都知道&#xff0c;像touch、swipe这类核心API&#xff0c;运行之后&#xff0c;都会在Airtest报告里记录一个步骤&#xff1a; 但有很多情况下&#xff0c;我们可能会使用自定义的函数&#xff0c;这种自定义的函数&#xff0c;就不会被记录到我们的…

易观分析:手机银行季度活跃用户突破7亿人,个人养老金业务争夺战开启

易观分析&#xff1a;近期&#xff0c;个人养老金制度正式启动实施&#xff0c;在全国36个先行城市或地区落地&#xff0c;首批可开办个人养老金业务的23家商业银行争抢养老蓝海市场&#xff0c;纷纷上线了个人养老金资金账户开户、缴存、产品代销费率优惠等激励活动。 由于个人…

JBoss漏洞 - CVE-2017-12149

文章目录漏洞简介影响范围靶场环境搭建漏洞发现漏洞利用攻击机检查JAVA环境下载利用反序列化工具 CVE-2015-7501进行漏洞测试Jboss Application Server反序列化命令执行漏洞 漏洞简介 JBOSSApplication Server 反序列化命令执行漏洞(CVE-2017-12149)&#xff0c;远程攻击者利用…

RTP协议--介绍

一、什么是RTP 数据传输协议RTP&#xff0c;用于实时传输数据。RTP报文由两部分组成&#xff1a;报头和有效载荷。 二、RTP的会话过程 当应用程序建立一个RTP会话时&#xff0c;应用程序将确定一对目的传输地址。目的传输地址由一个网络地址和一对端口组成&#xff0c;有两个…

js多边形算法:多边形缩放、获取中心、获取重心/质心、判断是否在多边形内、判断点排序是否顺时针等

一、前言 最近做多边形相关的工作&#xff0c;涉及比较多相关算法&#xff0c;总结一下&#xff0c;方便大家&#xff0c;如果帮到您&#xff0c;记得点赞&#xff01; 二、演示 【在线演示】 【源码gitee】 三、使用 所有核心算法都在utils.js里面&#xff0c;含参数说明…

扩散模型代码剖析

前言 相信大家对扩散模型早有耳闻&#xff0c;其着实大火了一把&#xff0c;效果也确实是好。今天写这篇博客的主要动机就是想真正进入到代码层面去看看其到底是怎么实现的。 其实在看完代码后&#xff0c;会觉得其实现的非常简单&#xff0c;而且也会对原理的理解有一个更好的…

如何快速构建企业级数据湖仓?

更多技术交流、求职机会&#xff0c;欢迎关注字节跳动数据平台微信公众号&#xff0c;回复【1】进入官方交流群 本文整理自火山引擎开发者社区技术大讲堂第四期演讲&#xff0c;主要介绍了数据湖仓开源趋势、火山引擎 EMR 的架构及特点&#xff0c;以及如何基于火山引擎 EMR 构…

Python+Yolov5人脸口罩识别

程序示例精选 PythonYolov5人脸口罩识别 如需安装运行环境或远程调试&#xff0c;见文章底部微信名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 Yolov5比较Yolov4,Yolov3等其他识别框架&#xff0c;速度快&#xff0c;代码结构简单&#xff0c;识别效率高&#xf…

【王道计算机网络笔记】网络层-网络层协议

文章目录地址解析协议ARP动态主机配置协议DHCP国际控制报文协议ICMPICMP差错报文ICMP询问报文ICMP的应用地址解析协议ARP 由于在实际网络的链路上传送数据帧时&#xff0c;最终必须使用MAC地址 ARP协议&#xff1a;完成主机或路由器IP地址到MAC地址的映射。解决下一跳走哪的问…

Metal每日分享,海报画滤镜效果

本案例的目的是理解如何用Metal实现海报画效果滤镜&#xff0c;主要就是改变颜色级别数量从而获取到新的像素颜色&#xff1b; Demo HarbethDemo地址 实操代码 // 海报画滤镜 let filter C7Posterize.init(colorLevels: 2.3)// 方案1: ImageView.image try? BoxxIO(eleme…

不用虚拟机也能在Windows下使用Linux

想学习热门的Linux系统&#xff0c;可是一开始就需要安装虚拟机软件&#xff0c;这样很容易消耗Linux初学者的热情。比如常用的VMWare虚拟机&#xff0c;虽然步骤并不复杂&#xff0c;但是一开始的搭建和配置过程&#xff0c; 容易劝退一部分新手。我认为学习新的操作系统&…

看了这篇文章后,面试官再也不敢问你非结构化存储的原理了

那么你可能会说&#xff0c;是不是我无限制地增加从库的数量就可以抵抗大量的并发呢&#xff1f; 实际上并不是的。因为随着从库数量增加&#xff0c;从库连接上来的 IO 线程比较多&#xff0c;主库也需要创建同样多的 log dump 线程来处理复制的请求&#xff0c;对于主库资源消…