WebRTC实时音视频通话之语音通话设计与实践

一、背景

在移动互联网流量时代,很多业务场景都有音视频通信的需求,比如IM场景,除了文字交流还需要音视频通话进行实时交互。为了帮助58、赶集、安居客等业务线更好的为用户提供服务,节约沟通成本,提升效率,TEG基于WebRTC提供了一套完整的实时音视频通话解决方案——WRTC。

另外还有一种场景,比如在进行语音通话时,APP中的两个用户可能不是同时在线,导致一端无法向另一端发起实时通话。为了解决这个问题,WRTC还具备语音转IP电话的能力。业务方可以通过后端配置选择是否使用。本文主要以语音通话为切入点,详细介绍语音及语音转IP电话在WRTC中的设计与实践。

二、WebRTC简介

作为音视频开源核心项目之一,WebRTC整个框架的设计非常庞大,很多大型公司都在基于WebRTC进行音视频能力开发,包括阿里云、网易云、七牛云等。TEG也在2016年就开始提供基于WebRTC的实时音视频通话能力。同时WebRTC的架构设计灵活,功能强大,覆盖了大部分移动端多媒体技术。

比如APM(声音处理模块),被很多公司借鉴用于音频的AEC、NS、AGC。JitterBuffer用于视频抗抖动。Android端Camera和Camera2结合使用,用于视频采集,可扩展的软编码框架以及软硬编结合方式处理视频流等。可以说WebRTC的每个模块都值得我们深入研究,学习其中的设计思想和音视频处理技术。

目前网上关于WebRTC资料有很多,限于篇幅,本文也只做个简单介绍,具体细节,感兴趣的同学可以深入研究模块代码,就像Linux鼻祖Linus曾说的至理名言"Read the f*** source code"。

  • 音频,音频采集、处理模块
  • 视频,视频采集、编解码模块
  • ICE打洞中继服务器,STUN/TURN
  • 媒体流传输,RTP/RTCP

WRTC功能模块主要分为视频通话、语音通话、语音转IP电话。本文主要介绍语音和语音转IP电话部分。

三、音视频通话架构

音视频通话包括音频通话和视频通话。同时,为了丰富音视频电话在当前网络环境下的应用场景和通话能力,WRTC还需要提供IP电话的解决方案。业界比较流行的IP电话方案是用FreeSwitch作为电话网关后台,该方案支撑的架构如下图:

在上图这种架构下,客户端除了实现WRTC需要的信令协议通信之外,还需要额外增加同FreeSwitch服务之间的SIP协议通信。从SDK的角度来考虑,这对客户端SDK的包体积、接入复杂度、容错率以及版本灵活性等都带来了额外的挑战。所以我们最终决定将这部分实现放在服务端,架构如下图:

架构优化后,在没有增加客户端和服务端交互复杂度的前提下,由服务端对音频流进行转接,通过SIP协议对接到电话网关,实现与对端手机的通信。另外,服务端还可以进行语音录制,为后期业务方的语音监控、通话记录分析等需求增加了便利。

通话流程

首先介绍下WRTC的音视频通话流程,如下图所示,主叫通过Room/Signaling服务和被叫进行信息交互,IM服务器对于音视频通话来说并不是必须的,把它放在WRTC的流程当中是为了让被叫顺利接收主叫的通话请求。在一个完整的通话流程中,主叫首先尝试和被叫建立音视频通话的连接,假如连接超时或者主叫主动发起IP电话时,WRTC服务端会通过运营商拨打被叫电话,从而完成IP电话的流程。

客户端:

1、房间管理。房间是一个抽象概念,目的是在主被叫之间建立一个随时可查询可追溯的信息通道,比如说当主叫发起音视频通话请求时,被叫需要一个标识来确定需要和哪一方进行通话,这个标识就是用房间信息来储存的。音视频通话需要双方先加入房间,然后再使用PeerConnection建立连接进行通话。下面举几个房间管理的例子:

/**@brief 请求RoomInfo(后台需要进行身份验证,并分配roomId等)@param completeHandler 回调block@since v1.0.0*/
+ (void)requestRoomInfo:(CompleteHandler)completeHandler;/**@brief 加入房间@param roomid 房间的id@param params 参数字典@param completeHandler 回调返回@since v1.1.1*/
+ (void)joinToRoom:(NSString *)roomIdParameters:(NSDictionary *)paramsComplete:(CompleteHandler)completeHandler;/**@brief 通知此时处于忙状态@param roomId 第三方呼叫发来的roomId@since v1.0.0*/
+ (void)notifyBusy:(NSString *)roomId;

2、信令管理。WRTC采用的是Websocket作为信令服务器,进行媒体协商,发送SDP会话描述协议和Candidate候选信息等。这里主要涉及SDP会话描述协议(offer/answer)和Candidate信息交换。为了提升编码性能,WRTC视频编解码采用H264,音频编解码综合考虑性能和带宽,采用的是OPUS。Candidate交换的是打洞候选IP地址和端口号,用于p2p连接和中继。

下面是一对一音频通话,主叫方发送的SDP(offer)。

offer   
...  
a=mid:audio  
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level  
a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time  
a=sendrecv  
a=rtcp-mux  
a=rtpmap:111 opus/48000/2  
a=rtcp-fb:111 transport-cc  
a=fmtp:111 minptime=10;useinbandfec=1  
a=rtpmap:103 ISAC/16000  
a=rtpmap:104 ISAC/32000  
a=rtpmap:9 G722/8000  
a=rtpmap:102 ILBC/8000  
a=rtpmap:0 PCMU/8000  
a=rtpmap:8 PCMA/8000  
a=rtpmap:106 CN/32000  
a=rtpmap:105 CN/16000  
a=rtpmap:13 CN/8000  
a=rtpmap:126 telephone-event/8000  
...  

主叫发送的sdp信息通过信令服务器发送到被叫,被叫收到该offer后,会根据该offer回一个answer信息。至此,主叫和被叫完成了媒体信息的协议协商。

3、状态管理。通过信令服务器进行双方通话状态的管理,状态包括busy、refuse、cancel等。状态管理一方面可以防止双通话,另一方面也能根据通话状态进行用户行为统计分析,然后进行迭代优化,为各个业务线提供更好、更稳定的音视频通话服务。

4、音频模块、视频模块、ICE打洞服务、媒体流传输等在上文做了简单介绍,其实这里的每一个模块,都值得我们去深入研究学习,比如我们也在尝试借鉴其中的音频处理模块用于直播服务。篇幅所限,本文不做过多描述。

服务端:

后台服务管理整个WRTC音视频通话的连接建立、信息交换、房间信息等。

  • 房间服务,对加入房间的主叫Caller和被叫Callee的行为进行管理,比如加入房间、退出房间等等(上文已经在客户端部分做过介绍,此处不再重复)。
  • 信令服务,控制双端用户的媒体协商、Candidate交换等。
  • ICE打洞服务,WRTC音视频通话方式分为p2p和中继两种方式。ICE包括STUN和TURN服务,用于打洞,STUN可以进行NAT类型检测,并获取NAT背后的外网IP地址和端口号。其中NAT类型主要分为Full Cone NAT、RestrictedCone NAT、Port Restricted Cone NAT、Symmetric NAT四种。对于前三种都可以建立p2p直连,对于Symmetric NAT(对称性NAT),因为每次连接端口都是变化的,所以通过STUN获取的端口号是无效的。此时WRTC会改走中继模式,来保证双端的正常通话。

考虑到一旦建立p2p连接,后续服务端不能控制干预媒体流,后端服务后续也计划进行系统升级,统一采用中继的方式进行音视频通话,来保证音视频通话的可靠性和可控性。

运营商(网关代理):

后端服务经过判断需要向被叫拨打IP电话时,协议转换服务会将接到的offer转换为SIP的带有协商信息的invite协议,发送给运营商,然后运营商会回复给100trying,表明正在处理SIP信令。

当被叫手机振铃时,运营商回复180或183协议给协议转换服务,并带有第一次协商的结果,协议转换服务将其转化为answer回复给客户端,完成第一次媒体通信即客户端听到彩铃。

当被叫手机接听时,运营商会发送200给协议转换服务,并带有第二次协商的结果,协议转换服务将其转化为answer回复给客户端,完成第二次媒体通信即被叫和主叫开始通话。

如下图所示:

IP电话二次拨号:

对于IP电话,WRTC也具备对分机二次拨号的能力。比如被叫方是座机,可以通过二次拨号和指定用户进行语音通话。

电话拨号,就必须要提到双音多频信号DTMF。DTMF是电话系统中电话机与交换机之间的一种用户信令,用于电话拨号。通过研究WebRTC底层代码,其实它是支持DTMF拨号能力的,只是没有对外部暴露。

我们需要修改PeerConnection,增加insertDtmf功能。拨打分机号时需要传入本地AudioTrack ID,默认值为ARDAMSa0。分机号码ext_number取值范围0~15,对应event为0-9,*, #, A-D。拨号音duration SDK设置的为1000ms。

下面是insertDtmf部分代码:

bool PeerConnection::insertDtmf(const std::string& audio_track_id,const int ext_number,const int duration){//判断是否支持发送DTMF信号bool canInsertDtmf = session_->CanInsertDtmf(audio_track_id);if (canInsertDtmf) {//WebRTCSession对象发送DTMFisInsert = session_->InsertDtmf(audio_track_id,ext_number,duration);}return isInsert;
}

下面具体说说音视频开发WebRTC方面需要学习哪些内容,以及推荐的资源:

关于选取资源,我的建议是:资源不在多,而贵在精。不要总是屯一大堆资源而却一直放在那里吃灰

四、总结

本文主要介绍了WRTC的实现方案、流程以及IP电话的原理。其中涉及到的细节还有很多,这里就不再赘述。目前WRTC已经能提供了稳定的音视频通话输出能力,后续我们将继续在WRTC方案的基础之上,结合TEG的短视频SDK,从采集端、通话端进行持续优化,采集端丰富音视频处理细节,通话端增加多人通话,最终形成一对一以及多对多的音频、视频、IP电话混合对话的能力。

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

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

相关文章

Qt编译和使用freetype矢量字库方法

在之前讲过QT中利用freetype提取字库生成图片的方法: #QT利用freetype提取字库图片_qt freetype-CSDN博客文章浏览阅读1.2k次。这是某个项目中要用到的片段,结合上一篇文章#QT从字体名获取字库文件路径使用// 保存位图int SaveBitmapToFile(HBITMAP hBi…

CSS引入方式

CSS引入方式 1 行内式2 内嵌式3 连接式/外部样式表 1 行内式 行内式,通过元素开始标签的style属性引入 样式语法为&#xff1a; 样式名:样式值; 样式名:样式值; 代码 <input type"button" value"按钮"style"display: block;width: 60px; height: 4…

45°和68°焕新上市,五粮液完成产品体系化布局

执笔 | 尼 奥 编辑 | 扬 灵 如今&#xff0c;白酒行业正经历周期性调整&#xff0c;头部化和品牌化集中趋势日益显著。五粮液在这一关键时刻&#xff0c;敏锐地捕捉到市场机遇&#xff0c;通过产品焕新&#xff0c;进一步完善和丰富了其代际系列产品体系。 这一举措不仅巩…

24年湖南三支一扶报名流程图及报名照片要求

24湖南三支一扶报名流程图&#xff0c;照片要求☑️ ✔️报名时间&#xff1a;5月15日9:00至5月23日17:00 ✔️报名方式 报考人员登录市州人力资源社会保障局官网、市州人事考试网等查看各地公告&#xff0c;按要求报名。 ✔️报名流程&#xff08;湖南各地市单独报名&…

MATLAB基础—变量及其操作

众所周知&#xff0c;计算机所处理的数据都是存放在内存单元中的&#xff0c;而每个内存单元都有一个唯一的地址&#xff0c;程序就是通过这个内存单元的地址来访问内存单元的。 在高级语言中&#xff0c;只需要给每个内存单元取一个名字&#xff0c;然后通过这个名字就能够访问…

kubernetes二进制多master部署

文章目录 一、master02 节点部署&#xff08;在上期博客部署完成的情况下&#xff09;1、准备master02节点需要的文件2、修改配置文件kube-apiserver中的IP3、启动各服务并设置开机自启4、查看node节点状态 二、负载均衡部署1、配置load balancer集群双机热备负载均衡1.1 准备n…

【Shell】shell编程之数组

目录 一、数组的概念 二、数组定义方法 三、数组 1.获取数组长度 2.获取数组数据列表 3.获取数组下标列表 4.读取某下标赋值 5.数组遍历 6.数组切片 7.数组替换 8.数组删除 四、数组追加元素 五、向函数传数组参数 ​编辑六、数组排序算法 1.冒泡排序 2.直接选…

计算机毕业设计hadoop+hive+hbase学情分析 在线教育大数据 课程推荐系统 机器学习 深度学习 人工智能 大数据毕业设计 知识图谱

毕 业 设 计&#xff08;论 文&#xff09;开 题 报 告 1&#xff0e;结合毕业设计&#xff08;论文&#xff09;课题情况&#xff0c;根据所查阅的文献资料&#xff0c;每人撰写不少于1000字的文献综述&#xff1a; 一、研究背景和意义 “互联网”和大数据带来了网络教育的蓬…

Google:站长移除无效网址

当您的网址不需要呈现在Google站长中时&#xff0c;您可以在站长工具中移除网址 操作步骤&#xff1a;登录Google站长&#xff0c;绑定网站完成后&#xff0c;点击左侧删除 >> 输入网址 如果遇到一些网址&#xff0c;可以找寻网址间的规律&#xff0c;比如说&#xff0…

16.投影矩阵,最小二乘

文章目录 1. 投影矩阵1.1 投影矩阵P1.2 投影向量 1. 投影矩阵 1.1 投影矩阵P 根据上节知识&#xff0c;我们知道当我们在解 A X b AXb AXb的时候&#xff0c;发现当向量b不在矩阵A的列空间的时候&#xff0c;我们希望的是通过投影&#xff0c;将向量b投影到矩阵A的列空间中&…

每日一题13:Pandas:方法链

一、每日一题 &#xff1b;&#xff1a;&#xff1a; 解答&#xff1a; import pandas as pddef findHeavyAnimals(animals: pd.DataFrame) -> pd.DataFrame:heavy_animals animals[animals[weight] > 100].sort_values(byweight, ascendingFalse)result heavy_anim…

小红书“脆皮”用户健康研究报告

人均脆皮、血脉觉醒、爆肝打工、脱发危机……各式各样的健康议题不断被推上生活舞台&#xff0c;年轻人纷纷自嘲&#xff1a;“20多岁的年纪&#xff0c;却有了60多岁的身体”。 近年&#xff0c;大健康行业欣欣向荣&#xff0c;小红书成为大众分享健康生活的聚集地&#xff0c…