WebRTC实现音视频通信


一、方案选型


1、XMPP协议 + Jingle扩展协议:应用层协议,可以用来实现音视频传输,但完善的客户端开发资料有限,无开源库,开发难度大,开发周期长。(选型排名第三)

2、SIP协议:应用层协议,专门用来实现音视频传输,但客户端开发资料较少,无开源库,开发难度较大,开发周期较长。(选型排名第四)

3、RTMP协议(Real Time Messaging Protocol,实时消息传输协议):传输层协议,基于TCP实现,是目前主流的音视频等流媒体传输协议,广泛应用于直播领域,开发资料较全,但是传输成本高,对服务器要求较高。(选型排名第二)

4、WebRTC(Web Real-Time Communication,网页即时通讯):本身并不是什么协议,而是谷歌的一套开源库,专门用来做点对点音视频通信,应用层采用的是XMPP协议的扩展组件libjingle,传输层采用UDP协议,采用ICE/STUN协议进行NAT穿透。协议分层如下

优势:

  • 可实现Web浏览器、安卓、iOS多端通信

  • 客户端难的地方主要体现在两个方面,一是网络传输有关,像侦听事件,同步主线程和读线程,穿透;二是流数据有关,像音视频编码、解码、回声消除等;而这两大问题WebRTC内部已经帮我们解决了。

现在许多SDK都使用WebRTC作为框架来实现,开发资料较完善。(选型排名第一)


二、WebRTC的架构模式


上面我们说到:WebRTC本身并不是什么协议,而是谷歌的一套开源库,专门用来做点对点音视频通信,应用层采用的是XMPP协议的扩展组件libjingle,传输层采用UDP协议,采用ICE/STUN协议进行NAT穿透。

1、点对点模式

传统的连接模式一般都是C/S架构(Client/Server架构)的,例如XMPP,A和B之间互相发送数据的流程是:A-->服务端-->B,B-->服务端-->A。

而WebRTC则是P2P模式(peer-to-peer模式)的,即点对点的,也就是说,一旦点与点之间的连接形成,那么它们之间的数据传输是不经过服务端的,而是在两者之间直接发送。如:A-->B,B-->A。这样做的一个很大的好处就是大大的降低了服务端的压力

2、服务端、信道与信令

那这是否就意味着我们使用WebRTC开发就不需要服务端了呢?这种观点很明显是错误的,严格来说,我们使用WebRTC仅仅是不需要服务端来进行数据中转,服务端还是必不可少的,虽然服务端会比C/S架构下少做很多事,但还是不能没有它。使用WebRTC至少要用服务端做两件事:

  • A-->服务端-->B这样的模式来传递一些基本信令来控制P2P连接的连接与断开,还有一些自定义业务的信令,也就是说服务端的主要作用其实就是在两个客户端之间传递信令。信令其实就是一些指令型的数据,而客户端与服务端之间传输信令通道就是信道,我们用websokcet搭建长连接作为信道。

  • 穿越NAT。

什么是NAT?

NAT(Network Address Translation)即网络地址转换,NAT技术的出现,就是为了解决IPV4下IP地址匮乏的问题。比如说,我们有很多设备处于同一个路由器下,这个路由器只有一个公网IP,但是通过NAT技术我们的设备都会被分配到相应的内网IP(192.168.0.1 、192.168.0.2等),这样一个路由器的公网IP就对应了n个内网IP,就通过这种使用少量的公有IP代表较多的私有IP的方式,减缓了可用的IP地址空间的枯竭。

为什么要穿越NAT?

但是这也带来了一系列的问题,例如这里点对点连接下,会导致这样一个问题:如果客户端A想给客户端B发送数据,则数据来到客户端B所在的路由器下,会被NAT阻拦,这样B就无法收到A的数据了。所以需要穿越NAT。

怎么穿越NAT?

两个客户端分别去谷歌的STU Server获取自己对应的公网IP,通过信令的方式经过服务端传递给对方挂在peerConnection上就可以了。


三、peerConnection的详细连接流程及信令传输


共7步,7个信令。

  • 第一步:用户打开聊天室页面,客户端与服务端建立websocket连接,打通信道,此时服务端为该用户分配一个socketid作为WebRTC音视频通话的唯一标识。

  • 第二步:加入聊天室信令join

信道打通后,客户端需要向服务端发送一个加入聊天室信令join,信令中要包含当前聊天室的唯一标识。

加入聊天室信令```join```
  • 第三步:当前聊天室里所有用户信令peers,有新用户加入的信令_new_peer

服务端收到join信令后,根据客户端加入的房间,发送一个当前聊天室里所有用户(包括当前客户端自己)的信令peers给客户端,这个信令的一个作用就是服务端告诉客户端他加入聊天室成功了,二来也把当前聊天室里所有用户发送给客户端。此时,客户端会创建本地流,并与房间里的其它用户分别建立peerConnection连接,并把本地流添加到所有的P2P连接上。

加入聊天室成功,此聊天室没有人的情况

{
    data =     {
        connections =         (
        );
        you = "e297f0c0-fda5-4e67-b4dc-3745943d91bd";
    };
    eventName = "_peers";
}

加入聊天室成功,此聊天室有人的情况

{
    data =     {
        connections =         (
            "85fc08a4-77cb-4f45-81f9-c0a0ef1b6949"
        );
        you = "4b73e126-e9c4-4307-bf8e-20a5a9b1f133";
    };
    eventName = "_peers";
}

同时服务端还需要发送有新用户加入的信令_new_peer给聊天室里其它所有的人,要包含这个新人的socketid,用来让房间内所有其它用户跟这个建立新加入的人建立peerConnection,并把它们的本地流添加到这个连接上去。

这样,双方互相发起和对方的连接,经过WebRTC的处理,该连接建立成功,但是这个连接还不能正常传数据,还有两件事要做:

往这个连接上挂上双方的公网ip,用来穿越NAT。

往这个连接上挂上双方的sdp,用来描述这个连接传递的具体内容。

  • 第四步:发送公网IP信令__ice_candidate

我们在第三步建立每条peerConnection的同时,就会为每条peerConnection都发起向谷歌STUN服务器发起获取ice candidate的请求(直接理解为公网IP就行了),获取到后会触发我们的一个回调,当我们获取到这个公网IP后,要通过发送公网IP信令__ice_candidate发送给服务端。

发送公网IP给服务端信令```__ice_candidate```

服务端收到A发送的ice candidate,也需要发送一个_ice_candidate信令给房间其他所有的用户,让他们把A的公网IP挂在它们和A的peerConnection中。

同理,B在建立和A的peerConnection时也会去请求自己的公网IP,并经过服务端发给A,让A把B的公网IP关在它们俩的peerConnection上。

这样就完成了NAT穿越。

  • 第五步:offeranswer信令

那么当新加入的用户收到peers信令并建立连接完成、并传输公网IP完成后,需要给聊天室里所有的人都发送offer信令把自己的sdp传给他们,他们则要在收到offer信令后回复我们一个answer信令把它们的sdp传给我们,以此来完成sdp的互相存储。

早就在房间里收到newPeer信令的用户不需要发offer信令并等待answer信令。sdp的交换已经有上面那一条传输线完成了。

offer和answer信令的作用都是传递sdp,只不过offer信令是发起方发送的,answer信令是接收方发送的,信令的主要内容都是sdp信息。

那么当我们建立了peerconnection,并完成了公网IP的发送与接收后,我们还需要完成sdp的发送与接收。

我们发送方需要先主动create一个Offer,Offer里包含着一个本地的sdp信息(创建offer,核心就是创建本地sdp,创建本地sdp成功后会触发一个回调,我们在回调里发信令),创建好后,我们要发送一个发送sdp的信令__offer给服务端。

客户端A把通过```__offer ```信令把自己的sdp发送给服务端

服务端同样通过__offer信令再把这个sdp发给聊天室的所有其它用户,让他们把这个sdp挂在相应的peerConnection上。

其他用户收到服务端发来的A的sdp信息后,通过setRemoteDescriptionWithDelegate: sessionDescription:方法把A的sdp信息存储在A和B的peerConnection中,设置成功后会触发一个代理方法,其它用户就要在这个代理方法里发出一个__ answer信令把自己本地的sdp信息发送给服务端。

客户端B通过```__answer ```信令把自己的sdp发送给服务端

服务端同样通过__ answer信令再把这个sdp发送给客户端A,A把这个sdp挂在相应的peerConnection上。

这样这个连接才算真正打通,可以把它上面挂着的流进行点到点的传输了。

  • 第七步:有用户离开的信令_remove_peer

当你退出聊天室时,你不需要发送信令,服务端可以知道是谁退出了,就好像刚开始知道是谁加入了一样,你只需要要关闭多媒体流,关闭和所有用户的连接,关闭和服务端的socket连接。

而服务端则给房间里其它用户发送一个有用户离开的信令_remove_peer,让别人和你断开连接。

注意:

  • 客户端和服务端的连接必须为长连接,你用啥协议实现都行,但是必须是长连接,因为在一个聊天存在时客户端和服务端会反复传输数据。(这个长连接就是信道,传输的数据就是信令)

  • ice candidate其实就是客户端的公网地址,用来进行NAT穿透。

  • SDP就是一个描述多媒体连接内容的协议,例如分辨率,格式,编码,加密算法等,通信双端要一致。

  • 双端之间的连接和信令传输是本次实现的重难点。


参考博客:
有了这一篇,吃喝不愁:iOS下音视频通信-基于WebRTC
RTMP vs. WebRTC 视频直播技术合集
STUN, TURN, ICE介绍
# 基于 WebRTC 技术的实时通信服务开发实践


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 161,780评论 4 369
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,424评论 1 305
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,397评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,576评论 0 218
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,997评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,945评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,107评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,850评论 0 208
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,625评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,804评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,285评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,613评论 3 261
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,291评论 3 242
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,164评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,963评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,096评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,886评论 2 278

推荐阅读更多精彩内容