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.mzph.cn/news/838637.shtml

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

相关文章

【Linux】19. 习题②

2022-11-12_Linux环境变量 1. 分页存储(了解) 一个分页存储管理系统中,地址长度为 32 位,其中页号占 8 位,则页表长度是__。 A.2的8次方 B.2的16次方 C.2的24次方 D.2的32次方 【答案解析】A 页号即页表项的序号,总共占8个二进制…

go语言之控制结构2

1.for结构 如果想要重复执行某些语句&#xff0c;Go 语言中您只有 for 结构可以使用 1.1 基于计数器的迭代 基本格式为&#xff1a; for 初始化语句; 条件语句; 修饰语句 {} 例子1&#xff1a; package mainimport "fmt"func main() {for i : 0; i < 5; i {f…

STM32的FLASH学习笔记

不同型号的 STM32&#xff0c;其 FLASH 容量也有所不同&#xff0c;最小的只有 16K 字节&#xff0c;最大的则达到了1024K 字节。大容量产品的闪存模块组织如图所示&#xff1a; STM32 的闪存模块由&#xff1a;主存储器、信息块和闪存存储器接口寄存器等 3 部分组成。 ​ ①主…

骨架油封在工业应用中的重要性

为什么我们会选择使用山峰骨架油封?这个问题直接关系到工业生产的效率和成本管理。山峰骨架油封凭借其卓越的性能和多重优势已经成为众多工程师和维护人员的很好选。 全方位的应用优势 山峰骨架油封不仅在密封效果上表现出色&#xff0c;同时还适用于各种工业应用场景。无论…

路由跟踪,追踪请求的网址链接情况

追踪请求的网址链接情况,多节点情况可查看是否有节点拒绝响应 linux&#xff1a; traceroute open.XXX.com windows tracert open.XXX.com

Java环境搭建(二)Notepad++和IDEA的下载

Notepad&#xff08;不推荐使用&#xff09; 高级记事本 下载地址 Notepad (juxinwk1.cn) 下载安装后一直下一步就可以了 注&#xff1a;改一下路径还有建立快捷方式&#xff08;自己选择&#xff09; IDEA 集成环境 下载地址 IntelliJ IDEA – the Leading Java and Kotl…

React 第三十二章 虚拟DOM

面试题&#xff1a;什么是虚拟DOM&#xff1f;其优点有哪些&#xff1f; 标准且浅显的答案 虚拟dom本质上就是一个普通的 JS 对象&#xff0c;用于描述视图的界面结构 虚拟 DOM 最早是由 React 团队提出来的&#xff0c;因此 React 团队在对虚拟 DOM 的定义上面有绝对的话语权。…

若依-生成主子表

1. sql语句建表导入到数据库中&#xff1a; -- ---------------------------- -- Table structure for t_ques————主表 -- ----------------------------CREATE TABLE ques (ques_id INT NOT NULL AUTO_INCREMENT COMMENT Id,name VARCHAR(255) NOT NULL COMMENT 测评名称…

未授权访问:Rsync 未授权访问漏洞

目录 1、漏洞原理 2、环境搭建 3、未授权访问 4、利用rsync下载任意文件 5、利用rsync反弹shell 防御手段 今天继续学习各种未授权访问的知识和相关的实操实验&#xff0c;一共有好多篇&#xff0c;内容主要是参考先知社区的一位大佬的关于未授权访问的好文章&#xff0c…

ApiHug - 闭门造车, 出门合辙

&#x1f917; ApiHug {Postman|Swagger|Api...} 快↑ 准√ 省↓ GitHub - apihug/apihug.com: All abou the Apihug apihug.com: 有爱&#xff0c;有温度&#xff0c;有质量&#xff0c;有信任ApiHug - API design Copilot - IntelliJ IDEs Plugin | Marketplace The Nex…

RocketMQ:新增consumer消费组group从最新消息开始消费skip last offset message

场景 想创建一个新的consumer去消费一个已经再使用的topic时&#xff0c;默认情况下会从topic中的第一条消息开始消费&#xff0c;大多数情况是需要从最新的消息开始。然后再使用CONSUME_FROM_LAST_OFFSET设置时并不会对新的consumer生效&#xff0c;它只是在停用consumer重新启…

Vue学习之:在 vue2 中引入 pdf.js 并配置使其能工作

安装 不同版本的 pdfjs 在 node_modules 中的目录不太一样&#xff0c;如果你想让他正常运行就按照我下面的来确保你的 nvm 版本是 18.17 如果不是的话&#xff0c;建议你配置跟我调成一样的&#xff0c;否则很容易出问题 nvm install 18.17.0 nvm use 18.17.0安装 pdfjs&…

代码随想录算法训练营day25 | 669. 修剪二叉搜索树、108.将有序数组转换为二叉搜索树、538.把二叉搜索树转换为累加树

669. 修剪二叉搜索树 看题解做出来的 class Solution:def trimBST(self, root: Optional[TreeNode], low: int, high: int) -> Optional[TreeNode]:if not root:return Noneif root.val < low:return self.trimBST(root.right, low, high)if root.val > high:return…

【栈的应用】中缀和后缀表达式 {中缀转后缀表达式;中缀表达式求值;后缀表达式求值}

中缀转后缀表达式 在中缀变后缀时&#xff0c;操作数的顺序不会发生变化&#xff0c;只有运算符的顺序可能发生变化。同时又没有括号。所以在转换的过程中&#xff0c;只要碰到操作数&#xff0c;可以直接输出&#xff0c;而遇到运算符和括号进行相应的处理即可。 转换原则如…

SD8063音频功率放大器5V音频功率放大器低功耗

SD8063是一个双桥接音频功率放大器&#xff0c;当 连接到一个5V的pp时&#xff0c;将ver2.2W toa4ΩL oad(No电话)or2.5瓦至a3欧洛a(第2项) THDN含量小于an1.0%此外&#xff0c;耳机输入引 脚允许放大器在单端模式下工作时&#xff0c;驾驶立 体声耳机。 Boomer音频功率放大器的…

Java静态方法和实例方法有何不同?

在Java中&#xff0c;方法可以分为静态方法和实例方法。这两种方法的区别在于它们的调用方式、访问权限以及应用场景。理解这两者的区别对于掌握Java编程非常重要。下面我们将详细剖析这两者的区别&#xff0c;并通过代码示例加以说明。 1. 调用方式 静态方法的调用 静态方法…

代码随想录算法训练营day26 | 77. 组合

理论 回溯法也可以叫做回溯搜索法&#xff0c;它是一种搜索的方式。 回溯法并不是什么高效的算法。因为回溯的本质是穷举&#xff0c;穷举所有可能&#xff0c;然后选出我们想要的答案&#xff0c;如果想让回溯法高效一些&#xff0c;可以加一些剪枝的操作&#xff0c;但也改…

MySQL单表查询案例演示

目录 一、创建数据库lianxi 二、选择数据库为lianxi 三、新建一个数据表grade&#xff0c;在grade表中插入数据 四、开始进行查询操作&#xff08;验证表中数据&#xff09; 1、查询1945班的成绩信息 2、查询1945班&#xff0c;语文成绩大于60小于90的成绩信息 3、查询学…

优雅谈论大模型8:神经网络与矩阵

向量与矩阵 上个章节的神经网络是为了解Transformer或者Mamba做好铺垫&#xff0c;在和后辈交流过程中发现有个障碍&#xff0c;那就是向量和矩阵。其实向量和矩阵的表达方式不是所有人都很习惯。在继续下面的章节之前小编认为有必要将向量、矩阵和神经网络做下补充解释。 向…

18.双线性插值缩放算法的matlab与FPGA实现

一篇文章为你讲透双线性插值 简介 1.什么是插值 图片放大是图像处理中的一个特别基础的操作。几乎在每一个图片相关的项目中&#xff0c;从传统图像处理到i深度学习&#xff0c;都有应用。   简单来说&#xff0c;插值指利用已知的点来“猜”未知的点&#xff0c;图像领域插…