iOS Call Kit for VOIP

http://www.jianshu.com/p/3bf73a293535

最近苹果 iOS 10 新发布了一个新的框架Call Kit,使第三方VOIP类型语音通话类APP有了更好的展现方式和用户体验的提升,想深入学习一下。基于Apple Audio Unit及开源GCDAsyncSocket做了一个类似’VOIP’的语音通话Demo APP,实现了位于同一局域网下的两台苹果手机之间基础的语音通话功能(拔出、接听、拒接、挂断、双向对讲),然后翻看了下苹果官网SpeakerBox Demo及国外的少部分Call Kit相关技术资料,将Call Kit新特性加入到了这个通话Demo中,下面大概讲解一下实现思路及要点,示例图片基本都来自Apple的WWDC16的Call Kit Session里。

Call Kit 能做什么

在苹果官方WWDC16 Enhancing VoIP Apps with CallKit(Session 230)中,苹果的工程师为我们展示了集成Call Kit后的VOIP 通话APP的效果,例如在iPhone锁屏状态下APP来电时,通过Call Kit可以像iOS原生电话来电一样展现全屏的来电及接听界面,VOIP APP与系统Call有着相同的通话优先级别,而且在通讯录中的拔号记录,Siri唤起,勿扰模式等都有着很好的支持。


incoming call.png

下面这张图简略的描述了原生APP、第三方APP在Call Kit框架下的关系,Call Kit在系统中提供了一种独有的服务,在需要的时刻,原生或者第三方APP通过Call Kit提供的API向系统请求诸如来电、拔出等展现服务,由Call Service统一安排调度这些请求以达成统一的交互响应。


callkit architecture.png

如何使用Call Kit

简单来说,Call Kit就是提供了统一的壳(语音通话UI)及与该壳交互的API而已,实际的通话链路监听、搭建和管理还是APP原有的实现思路,下面以通话的来电、拔出等几个场景描述下APP与Call Kit的交互流程

Prepare

  1. 创建CXProvider,指定Call Kit展现UI中的APP名称和图标,通话数量,来电铃声等Configuration
  2. 实现CXProviderDelegate协议,以接收来自Call Service发来的更新状态,例如用户点击了接听或者挂断等动作,决定网络链路的处理动作;还有AudioSession的激活状态,决定Audio播放录制的启动关闭时机
  3. 创建CXCallController,使APP可以发送更新状态给Call Service,例如用户拔出电话或者对方挂断电话等状态
  4. 如果需要锁屏界面以及APP未启动状态下显示来电界面,要搭建PushKit通路,与APNS差不多,只是APP端处理方式有些不同。文章末尾有一些资料,这里不详细展开了。

prepare callkit.png

Incoming Call

  1. APP前台时收到来自网络Server端的连接请求,或者APP后台时收到来自网络Push Server的PushEvent
  2. APP收到连接请求或者Push消息后,创建CXCallUpdate对象,指定此次来电的号码等属性
  3. 将上面创建的CXCallUpdate对象通过CXProvider的reportNewIncomingCallWithUUID方法报告给iOS系统
  4. Call Service收到新的来电请求后根据当前的状态,展现原生来电UI

incoming call architecture 1.png

Answer Call

  1. 用户点击来电界面上的接听按钮
  2. Call Service通过CXProvider的Delegate协议performAnswerCallAction方法告知APP
  3. APP将接听命令通过网络传给对端,开始实际音频数据传输,进行通话

incoming call architecture 2.png

End Call

  1. 用户点击APP UI中的挂断按钮
  2. 创建CXEndCallAction对象,指定此次通话的UUID属性
  3. 创建CXTransaction,将刚刚的Action指定给它
  4. 通过CXCallController,调用requestTransaction将这个挂断事件通知给Call Service
  5. Call Service通过当前通话状态,通过CXProvider将挂断动作通知回给APP
  6. APP在CXProviderDelegate中的performEndCallAction中结束此次通话的网络链路,停止音频录制播放Loop

incoming call architecture 4.png

Outgoing Call

  1. 用户通过APP UI、通话录、Siri发起一个拔出请求
  2. 创建CXHandle指定拨出的电话号码,创建CXStartCallAction并将CXHandle指定给它
  3. 创建CXTransaction,将刚刚的Action指定给它
  4. 通过CXCallController,调用requestTransaction将这个拔出事件通知给Call Service
  5. Call Service收到新的拨出请求后根据当前的状态,通过CXProvider将拨出动作通知回APP,
  6. APP在CXProviderDelegate中的performStartCallAction中开启此次呼叫的网络链路,通过CXProvider的reportOutgoingCallWithUUID设置呼叫与接通时间,根据链路建立的结果来展现原生呼叫UI的状态(呼叫成功或者失败)

outgoing call.png

Demo APP (MyCall)

正如前面说的,我实现的这个Demo主要是为了实践Call Kit这个新Framework的功能,因此只具备最简单的点对点通话功能,没有很完善的网络通信协议、APP模块结构划分、通话低时延、路由切换、容错、PushKit通知等处理

Demo结构图


MyCall architecture.png

APP中总共封装有四个socket实例对象用来网络通信,其中两个负责监听来电的Server Player和Server Recorder,两个负责呼出的Client Player和Client Recorder,实际通话中只有两路socket处于收发状态。这四个链路对象统一由CallManager对象调度管理。AudioController基于Audio Unit封装,提供音频流的播放和采集功能。CallControoler封装了CallKit的CXCallController对象,ProviderDelegate封装了CXProvider对象,这两个对象负责与Call Service交互。UI比较简单,就是几个通话控制的按钮,拨号地址,通话状态显示这几个控件。

一些说明

  1. Call Kit开关,在Define中我加入了Call Kit开关,不使用Call Kit这个Demo的基本功能也可以正常运行,方便参照对比。
  2. 通信协议,其实基本上没有什么协议,APP启动后就开始监听Socket连接,没有身份注册验证等,有连接就接受开始准备收发音频PCM裸数据。只是为了实现一端拨出,对端选择接听或者拒接这一流程,增加了一个Accept标志位。
  3. 通话标识,由于此demo并不是真正的VOIP,不存在Server注册及身份号码标识,我以局域网的IP地址及固定端口号为"Phone Number",进行Socket连接。

Tips

  1. 开发者通过Call Kit与Service进行交互时需要形成闭环,例如你向Call Service提交了一个StartCallAction请求后,在某些条件下(例如对方挂断或者拒接)必须发送EndCallAction请求,来告诉Call Service此次通话已经结束,否则原生通话UI会显示呼叫失败
  2. 在CXProviderDelegate协议中收到Action并且处理完自己的逻辑后,要调用fulfill或者fail告诉Call Service用户引发的这个Action是成功还是失败
  3. Audio播放录制loop的启动一定要放在CXProviderDelegate的didActivateAudioSession中,而不是performStartCall或者performAnswerCall中,大概是因为Call Service本身也要播放铃声的关系
  4. 在Call Kit使用中,主要面对的就是CXProvider与CXCallController这两个类,尽量以两个层面看待问题,一个是UI层,用户通过APP UI或者APP自主发起的电话状态更新,基本都是通过CXCallController;另一个是Model层,即实际数据传输链接的搭建,甚至Audio Loop,都是在CXProvider的Delegate里完成。Call Kit的原生UI该怎样展现,取决于APP内网络链路的处理方式和结果

demo代码地址
download

参考资料
XAMARIN Introduction to CallKit
WWDC16 Session 230 (Enhancing VoIP Apps with CallKit)
Apple Call Kit Speakerbox Demo
PushKit Practice



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值