手机实时提取SIM卡打电话的信令声音-双卡手机来电如何获取哪一个卡的来电

手机实时提取SIM卡打电话的信令声音

--双卡手机来电如何获取哪一个卡的来电

  • 一、前言

前面的篇章《手机实时提取SIM卡打电话的信令声音-智能拨号器的双SIM卡切换方案》中,我们论述了局域网SIP坐席通过手机外呼出去时,手机中主副卡的呼叫调度策略。

但在实际的双SIM卡手机中,除了外呼策略之外,我们仍然需要考虑双卡来电时的应用场景。即不考虑同时来电的手机本身三方通话逻辑的情况下,针对时间上错开的SIM卡1和SIM卡2的来电,我们需要在来电的逻辑中实现如下两个部分的内容需求:

  1. 来电时,应该能识别出是哪一张手机卡的来电,以及对方号码是什么(即需要获知来电的主/被叫号码)。进而根据不同的SIM卡的号码,做不同的分发和处理策略。
  2. 不同手机卡来电时的声音,理应被接收到后分流到不同的局域网SIP坐席中。蓝牙电话app需要能够将这些实时的信令和声音,根据本地SIM1/SIM2号码的不同,而调度到不同的SIP坐席上。双SIM卡手机同时存在时,不同的线路的数据不应该混淆。

基于以上的前提和预设场景,本篇中针对双SIM卡手机的通话部分逻辑,补充了“非默认拨号卡”的常规使用方式的来电部分。真正实现了【双卡双待单通手机】把手机本身的双卡呼叫的能力,复制到了局域网SIP坐席的能力。

  • 二、Android获取来电事件和来电号码的方式

Android操作系统中,针对手机的来电事件通常采用下述方式获取:

  1. 具有android.permission.READ_PHONE_STATE权限;
  2. 接收android.intent.action.PHONE_STATE的广播事件来触发;
  3. 判断TelephonyManager的.getCallState()==TelephonyManager.CALL_STATE_RINGING;
  4. 获取intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER)的号码做为来电号码。

这样,在Android API Level>=29的安卓版本中(Android10及以上),手机app可以通过申请READ_PHONE_STATE权限后,通过上述第3步来获取来电事件,通过第4步来获取来电的对方电话号码。

具体代码的逻辑如下图所示:

  • 三、Android获取哪个SIM卡槽产生的来电

对于双卡双待手机来说,知道了上述的获取来电事件和号码,其实还是不够。因为来电跟外呼不同,没有办法通过设置的【默认呼叫卡】的方式固定来电时的本地接收号码(也没有这个必要)。

对于来电时的场景,正常情况下就需要对不同SIM卡的通话数据(语音和通话状态数据)进行分流,主动调度到不同的SIM卡对应的SIP坐席当中。在这个过程中,手机设备需要能够识别出来电的时候,到底是由哪一张SIM卡产生的来电,并能根据SIM手机卡对应的手机号来做调度和分流。

Android操作系统中,手机来电事件的卡槽号,通常采用下述方式获取:

  1. 具有android.permission.READ_PHONE_STATE权限;
  2. 接收android.intent.action.SUBSCRIPTION_PHONE_STATE的广播事件来触发;
  3. 判断intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER)号码不为空;
  4. 获取intent.getIntExtra("slot", -1)的数值来做为来电是对应SIM卡槽产生的。

通常,slot为0就是SIM卡1,slot为1就是SIM卡2的来电。这部分内容与获取本机SIM卡手机号时的slot-index值的索引保持一致。

我们在互联网上搜索这块内容时,网上对不同版本的Android出现不同的多SIM来电的号码获取方式,但实践表明,别的其它几种方式局限性太大,有的手机可以而有的型号的手机又不行。采用这个方式是普适性最广的一种方法。

具体代码的逻辑如下图所示。

  • ‌四、Android获取双SIM卡槽对应的手机号码的方式

这个需求也可以描述为:手机app获取插入的双SIM卡的手机号。(卡槽1的手机号和卡槽2的手机号)

这是一个非常复杂的任务,其难度不在获取方式,而在于不同Android版本和不同厂商型号的支持适配。

通常来说获取双卡甚至多卡的手机号码,一般需要经过下列3个步骤,不同品牌型号的手机会在不同的阶段获取得到手机号码,如下:

1)通过SubscriptionManager.getActiveSubscriptionInfoList()获取卡号列表。

  1. 具有android.permission.READ_PHONE_STATE权限;
  2. Android API Level>=23;
  3. 通过Context.getSystemService(TELEPHONY_SUBSCRIPTION_SERVICE)获取SubscriptionManager;
  4. 遍历SubscriptionManager.getActiveSubscriptionInfoList()读取卡槽号和手机号。

(注:标准方法,这个方法国内的手机,基本都不能够支持

2)通过content://telephony/siminfo 来读取手机的所有SIM卡号列表。

  1. 普通权限,最多授予READ_PHONE_STATE和通讯录权限即可;
  2. 有一些手机通常无法通过这个来获取号码,代码需要加try-catch;

(注:这个是手机中真实存放SIM卡的地方,拔插物理卡槽会直接变更这个表)

3)从通话历史呼叫中读取subscription_id和phone_account_address

  1. 具有android.permission.READ_CALL_LOG权限;
  2. Android API Level>=29;
  3. 使用Context.getContentResolver().query(CallLog.Calls.CONTENT_URI查询通话记录;
  4. cursor.getString(cursor.getColumnIndex("subscription_id"))读取卡槽号;
  5. cursor.getString(cursor.getColumnIndex("phone_account_address"))读取手机号;

(注:有些手机phone_account_address存有本机号码,有的型号只有subscription_id有值,比如荣耀X10手机)

经由以上三种方式的排列组合的方式,手机app总能够有一种办法可以直接检索出手机中SIM1/SIM2卡槽分别有没有插入手机卡、以及插入的卡的手机号是多少。我们在实际的app中也使用这个方法来适配和兼容多款不同手机厂商、不同型号的安卓手机,使手机插入多张SIM卡时,能将各手机卡的通话的操作、事件状态、以及语音数据,各自单独的分流到局域网内不同的SIP坐席中进行通话调度和操作。

  • 五、方案的局限性和风险点

上述这一堆的过程函数和权限,基本都要求Android API Level在29及以上,即大于等于Android10的版本中才会进入这些授权和权限读取。

但我们实践中发现,使用Android6、Android7以及Android10以下的其它版本时,其实根本不用授权,它自动就能使用上述段落的方法来直接获取到对应的事件和消息内容。Android10及以后,仅仅是把权限给规范化、需要专门授权和弹框授权而已。

在Android系统中,API Level大于等于23,即Android6.0版本的手机,在大陆乃至全球市场上占据几乎100%的市场份额。因此,使用此种方式来进行双SIM卡的外呼和来电转发,在操作系统层面上基本不存在问题。

但是,本篇文章中讲述的安卓手机的通话事件和语音部分,仅仅包括外呼的呼叫发起、新来电、以及呼叫挂断,并不包括呼叫的接通状态、以及来电时的接听/拒接操作。

我们在蓝牙电话方案中针对接通状态、来电接听/拒接操作,均通过蓝牙HFP协议的AT指令来完成。假设蓝牙模块在使用中因故障不能正常工作,或者后续规划的去掉外置蓝牙模块的场景下,手机的多SIM卡呼叫需要针对这块内容进行专项的分析和深入挖掘。

这块内容我们将在后续的篇章中,花一两个篇幅的内容来进行详细的分析和论述。

  • 六、总结

在手机双SIM卡甚至多SIM卡的呼叫业务中,不管是【双卡双待单通】,还是【双卡双待双通】,都会面临通话的发起方和呼叫目标的问题。由于手机硬件设备本身会把所有的语音数据都转接到手机麦克风/听筒/扬声器中进行使用,在外呼的时候可以设置【默认拨号卡】的方式进行呼叫。但在来电时手机设备应能明确区分并标识出是归属于SIM卡1还是SIM卡2产生的来电,并做好卡1/卡2同时来电时的【三方通话】的业务场景约束。

在本篇章中,我们针对Android系统本身的双SIM卡的来电能力进行了一定的探索,实现了在代码逻辑层面中识别“双卡手机来电如何获取哪一个卡的来电”的数据。并在后续的功能逻辑中,根据不同SIM卡手机号来实现通话数据和业务调度到不同的局域网SIP坐席的功能。

这样,对于手机app而言,就充分的利用上了手机本身自带的“双卡双待”的功能,降低了操作的复杂度,也减少了应用扩展的成本,为后续更加复杂的场景提供了理论和数据上的支撑。


上一篇:手机实时提取SIM卡打电话的信令声音-智能拨号器的双SIM卡切换方案

下一篇:手机实时提取SIM卡打电话的信令声音-智能拨号器的SIP线路-双卡双待单通方案

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

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

相关文章

离线语音识别+青云客语音机器人(幼儿园级别教程)

1、使用步骤 确保已安装以下库: pip install vosk sounddevice requests pyttsx3 2、下载 Vosk 模型: 下载适合的中文模型,如 vosk-model-small-cn-0.22。 下载地址: https://alphacephei.com/vosk/models 将模型解压后放置在…

Streaming Dense Video Captioning

原文出处 CVPR 原文链接 [2404.01297] Streaming Dense Video Captioninghttps://arxiv.org/abs/2404.01297 原文笔记 What 1、提出了一种基于聚类传入token的新记忆模块,该模块可以处理任意长的视频,并且可以在不访问视频所有帧的情况下处理视频(…

TCP 连接:三次握手与四次挥手

TCP 协议,全称为“传输控制协议”。 1. TCP 协议段格式 给出几个定义 : 16位源端口号 :用于标识发送端的应用程序。 16位目的端口号 :用于标识接收端的目标应用程序。 32位序号 :用于标识发送的每一个字节流中的第一…

IDEA+Docker一键部署项目SpringBoot项目

文章目录 1. 部署项目的传统方式2. 前置工作3. SSH配置4. 连接Docker守护进程5. 创建简单的SpringBoot应用程序6. 编写Dockerfile文件7. 配置远程部署 7.1 创建配置7.2 绑定端口7.3 添加执行前要运行的任务 8. 部署项目9. 开放防火墙的 11020 端口10. 访问项目11. 可能遇到的问…

【机器学习】回归

文章目录 1. 如何训练回归问题2. 泛化能力3. 误差来源4. 正则化5. 交叉验证 1. 如何训练回归问题 第一步:定义模型 线性模型: y ^ b ∑ j w j x j \hat{y} b \sum_{j} w_j x_j y^​b∑j​wj​xj​ 其中,( w ) 是权重,( b )…

C++ 设计模式:状态模式(State Pattern)

链接:C 设计模式 链接:C 设计模式 - 备忘录 状态模式(State Pattern)是一种行为设计模式,它允许对象在内部状态改变时改变其行为。状态模式将状态的行为封装在独立的状态类中,并将状态的切换逻辑委托给这些…

redis开发与运维-redis0401-补充-redis流水线与Jedis执行流水线

文章目录 【README】【1】redis流水线Pipeline【1.1】redis流水线概念【1.2】redis流水线性能测试【1.2.1】使用流水线与未使用流水线的性能对比【1.2.2】使用流水线与redis原生批量命令的性能对比【1.2.3】流水线缺点 【1.3】Jedis客户端执行流水线【1.3.1】Jedis客户端执行流…

leetcode hot 100 杨辉三角

118. 杨辉三角 已解答 简单 相关标签 相关企业 给定一个非负整数 numRows,生成「杨辉三角」的前 numRows 行。 在「杨辉三角」中,每个数是它左上方和右上方的数的和。 class Solution(object):def generate(self, numRows):""":ty…

Uncaught ReferenceError: __VUE_HMR_RUNTIME__ is not defined

Syntax Error: Error: vitejs/plugin-vue requires vue (>3.2.13) or vue/compiler-sfc to be present in the dependency tree. 第一步 npm install vue/compiler-sfc npm run dev 运行成功,本地打开页面是空白,控制台报错 重新下载了vue-loa…

【微服务】【Sentinel】认识Sentinel

文章目录 1. 雪崩问题2. 解决方案3. 服务保护技术对比4. 安装 Sentinel4.1 启动控制台4.2 客户端接入控制台 参考资料: 1. 雪崩问题 微服务调用链路中的某个服务故障,引起整个链路中的所有微服务都不可用,这就是雪崩。动图演示: 在微服务系统…

【Python运维】构建基于Python的自动化运维平台:用Flask和Celery

《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! 解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 在现代IT运维中,自动化运维平台扮演着至关重要的角色,它能够显著提高运维效率,减少人为错误,并且增强系统的可维护性。本文将引导读者如…

STM32完全学习——使用定时器1精确延时

一、定时器的相关配置 首先一定要是递减定时器,递增的不太行,控制的不够准确,其次在大于10微秒的延时是非常准确的,小于的话,就没有那没准,但是凑合能用。误差都在一个微秒以内。使用高级定时器也就是时钟…

connect to host github.com port 22: Connection timed out 的解决方法

原因是 Github 被 GFW 屏蔽了。 Windows 系统,打开 C:\Windows\System32\drivers\etc,复制其中的 hosts 文件至桌面,用文本编辑器或者其他工具打开。 复制以下内容进去: 140.82.114.4 github.com 151.101.1.6 github.global.ss…

PyTorch中的autocast:混合精度训练的实现原理

PyTorch中的autocast:混合精度训练的实现原理 在深度学习中,尤其是在训练大型模型时,计算资源和显存消耗往往是非常关键的因素。为了优化这些问题,混合精度训练(Mixed Precision Training)应运而生。autoc…

Word格式修改

经常修改格式,留下这篇汇总 Word的累加符号上下标变右标指定目录:word如何取消封面或者目录下方的页码,页码从正文开始加参考文献:【Word】怎样给论文添加引用参考文献删空白页: word中无法删除空白页怎么办&#xff…

常见的排序算法过程和比较分析

比较分析 排序类别排序算法时间复杂度(最好)时间复杂度(最坏)时间复杂度(平均)辅助空间复杂度稳定性插入排序直接插入排序O(n)O(n)O(n)O(1)稳定插入排序折半插入排序O(n)O(n)O(n)O(1)稳定插入排序希尔排序…

随笔 | 写在2024的最后一天

. 前言 转眼又到了一年的末端。过去这一年,和前些年有些不同,变化巨大,感触良多。多到一时竟不知从何开始写。今天这篇随笔,因为时间有限,可能文法也会有些凌乱,就是想到哪里写到哪里,如果未来…

【QGIS入门实战精品教程】7.3:QGIS制作千层饼(DEM+等高线+影像+TIN)

文章目录 一、效果展示二、数据准备三、制作过程1. 打开软件2. 添加图层3. 制作千层饼一、效果展示 二、数据准备 订阅专栏后,从专栏配套案例数据包中的7.3.rar中获取。 1. dem 2. 影像 3. 等高线 4. tin 三、制作过程 1. 打开软件 打开QGIS软件。 QGIS软件主界面。

如何将CSDN文章 导出为 PDF文件

一、首先,打开我们想要导出为 PDF格式的 CSDN文章,以下图为例。 二、按 F12 调出浏览器调式模式后,选择 控制台 三、在控制台处粘贴代码 代码: (function(){ use strict;var articleBox $("div.article_content"…

Apache Hive常见问题

入门问题 什么是Apache Hive? 解释Hive的用途。Hive作为基于Hadoop的数据仓库工具是如何工作的?与传统关系型数据库相比,使用Hive有什么优势? Hive和关系型数据库管理系统(RDBMS)之间的区别是什么&#…