WebRTC从入门到入土

简介

WebRTC (Web Real-Time Communications) 是一项实时通讯技术,它允许网络应用或者站点,在不借助中间媒介的情况下,建立浏览器之间点对点(Peer-to-Peer)的连接,实现视频流和(或)音频流或者其他任意数据的传输。

通讯流程的建立

首先,从概念可以看出,WebRTC 通讯过程不需要中间媒介(P2P)。但实现起来仍然存在以下几个问题:

如果需要通讯的两台设备的网络环境是局域网,该如何建立连接?
如果通讯的两台设备建立连接后,无法解析对方的音视频格式该如何?
这里需要明白一个概念,两者进行连接当然是需要通过 IP + 端口进行连接,毕竟只有通过 IP 才能找到对应的设备
第一个问题可以通过内网映射(NAT)的方式解决; 第二个问题可以在连接之前先互相确定好双方支持的格式(一方支持 H264 和 VP8,另一方支持 H264 和 VP9,那么就可以在连接之前确定好双方的编解码格式是 H264 格式,此格式是双方都支持的)。

第二个问题需要在连接之前相互确定,那还没连接上,怎么相互确定呢?这时就可以通过一台中间的服务器来传递双方的信息了(双方 NAT 后的 IP 和端口也可以通过此服务器进行传递)。

所以基于以上问题,通讯过程可能如下:

用户 A 和 用户 B 通过 NAT 服务进行映射;
用户 A 和 用户 B 通过一台中间服务器进行交换各自支持的格式和映射后的 IP + 端口;
各自得知对方的信息后就可以开始连接通讯。

通讯流程

上面得知了一个简单粗糙的建立通讯的流程,但要知道更加细节的流程就需要明白以下几个概念:

媒体协商(SDP):两个用户在连接之前相互确定并交换双方支持的音视频格式的过程就是媒体协商。SDP 是描述信息的一种格式,其格式组成可自行查找了解;
网络协商(candidate):两个用户在 NAT 后交换各自的网络信息的过程就是网络协商。candidate 也是一种描述信息的一种格式,其格式组成可自行查找了解。
信令服务器:传递双方信息的服务器就是信令服务器,此服务其实就是 web 服务,其职责也不止传输媒体格式以及网络信息,还可传输业务信息。其传输信息的协议可是 HTTP 或 Socket 等。
STUN:STUN 是一种网络协议,其目的是进行 NAT 穿越。 内网进行 NAT 后进行 P2P 连接会有两个问题:
由于 NAT 的安全机制,NAT 会过滤掉一些外网主动发送到内网的报文,而 P2P 恰恰就需要主动发起访问;
NAT 后,会得到一个 IP + 端口的地址,而在进行 P2P 连接时并不知道这个地址,难道要用户手动填写吗。
所以 STUN 的作用就是能够检测网络中是否存在 NAT 设备,有就可以获取到 NAT 分配的 IP + 端口地址,然后建立一条可穿越 NAT 的 P2P 连接(这一过程就是打洞)。

TURN:TURN 是 STUN 协议的扩展协议,其目的是如果 STUN 在无法打通的情况下,能够正常进行连接,其原理是通过一个中继服务器进行数据转发,此服务器需要拥有独立的公网 IP。
TURN 很明显的一个问题就是其转发数据所产生的带宽费用需要由自己承担!

ICE:ICE(Interactive Connectivity Establishment),是一种用于实现网络连接的技术框架,用于在对等连接(如实时通信、P2P 文件共享等)中解决 NAT(Network Address Translation)和防火墙等网络障碍的问题。 ICE 是一种框架,可以通过使用多种技术(如 STUN、TURN、NAT 透明性检测等)来搜索可用的网络路径,并选择最优的路径建立连接,从而解决了 NAT 和防火墙等网络障碍的问题。 ICE 框架包含了以下几个步骤:
收集网络接口信息,包括本地 IP 地址、端口等;
通过 STUN 服务器获取公网 IP 地址和端口号;
通过 NAT 透明性检测来确定 NAT 类型和行为;
尝试直接连接对等端点;
如果直接连接失败,则使用 TURN 服务器作为中继节点进行连接。 也就是,ICE 更好的进行 NAT 穿越效果,从而提高实时通信的质量和效率。
明白以上概念后,那么就来看看更加详细的流程吧,先看下图:
在这里插入图片描述

根据上图,整体流程是:

用户 A 和用户 B 都需要先连接到信令服务器;
用户 A 和用户 B 都创建一个 PeerConnection(此时 WebRTC 会自动向 STUN/TURN 服务获取 candidate 信息, WebRTC 内置了 ICE);
用户 A 将本地音视频流添加到 PeerConnection 中(通过 getUserMedia 获取音视频流);
用户 A 作为发起方创建 offer(offer 中包含了 SDP 信息),并将获取的本地 SDP 信息添加到 PeerConnection 中(setLocalDescription),然后再通过信令服务器转发给用户 B;
用户 B 接收到用户 A 的 offer 后,将其添加到 PeerConnection 中(setRemoteDescription);
用户 B 将本地音视频流添加到 PeerConnection 中(通过 getUserMedia 获取音视频流);
用户 B 创建一个 Answer,并添加到 PeerConnection 中(setLocalDescription);
用户 B 通过信令服务器将 answer 转发给用户 A;
用户 A 接收到 answer 后将其添加到 PeerConnection 中;
用户 A 和 用户 B 都接收到了 candidate 信息后,都通过信令服务器转发给对方并添加到 PeerConnection 中(addIceCandidate);
媒体信息和网络信息交换完毕后,WebRTC 开始尝试建立 P2P 连接;
建立成功后,双方就可以通过 onTrack 获取数据并渲染到页面上。
上图是以用户 A 为发起方,用户 B 为接收方。

实现一对一实时通信
根据上面流程,我们需要:

STUN/TURN 服务
使用 coturn 搭建 STUN/TURN 服务

充当转发的服务(信令服务)
使用 node 的 第三方库实现 websocket 服务

coturn 搭建
coturn 是开源的服务器应用,完整实现了 STUN 和 TURN 协议。借助 coturn,我们可以快捷方便的搭建一个 STUN/TURN 服务。

重要概念

MediaStream

流媒体对象,音/视频数据的一种封装格式,挂载到 video 或 audio 标签上播放

RTCPeerConnection

会话控制,网络和媒体信息收发,作用类似 http 对象

SDP

主要用于两个会话实体之间的媒体协商,作用类似 http 中的配置项

结合下图类比会更容易理解:
在这里插入图片描述

代码实例

创建数据源

localStream 作为发送端本地预览画面:

// 创建数据源
const localStream = await navigator.mediaDevices.getUserMedia({
video: true,
audio: true,
});
// 显示数据源,localVideo 是 html 中的 video 标签
localVideo.srcObject = localStream;
创建发送数据实例

// 本地实例
const pc1 = new RTCPeerConnection();
// 对端实例
const pc2 = new RTCPeerConnection();
配置实例
// 告诉对端,本端地址
pc1.addEventListener('icecandidate', async (e) => {
// 发送给对端
// 对端添加本端地址
if (e.candidate) {
await pc2.addIceCandidate(e.candidate);
}
});
 
 
pc2.addEventListener('icecandidate', async (e) => {
// 发送给本端
// 本端添加对端地址
if (e.candidate) {
await pc1.addIceCandidate(e.candidate);
}
});
 
 
// 创建本端SDP,告诉本端浏览器支持哪些能力
const offer = await pc1.createOffer();
pc1.setLocalDescription(offer);
// 创建远端SDP,告诉远端浏览器支持哪些能力
const answer = await pc2.createAnswer();
pc2.setLocalDescription(answer);
// 。。。。发送远端SDP给本端
// 接收远端sdp,告诉远端浏览器支持哪些能力
pc1.setRemoteDescription(answer);
// 接收客户端sdp,告诉远端浏览器支持哪些能力
pc2.setRemoteDescription(offer);
发送数据
localStream.getTracks().forEach(
(track) => pc1.addTrack(track, localStream)
);
完整精简版Typescript代码
const pc1 = new RTCPeerConnection();
pc1.addEventListener('icecandidate', async (e) => {
if (e.candidate) {
await pc2.addIceCandidate(e.candidate);
}
});
pc1.addEventListener('iceconnectionstatechange', (e) => {
console.log('pc1: iceconnectionstatechange', e);
});
 
 
const pc2 = new RTCPeerConnection();
pc2.addEventListener('icecandidate', async (e) => {
if (e.candidate) {
await pc1.addIceCandidate(e.candidate);
}
});
 
 
pc2.addEventListener('iceconnectionstatechange', (e) => {
console.log('pc2: iceconnectionstatechange', e);
});
 
 
pc2.addEventListener('track', (e) => {
if (e.streams.length > 0) {
remoteVideo.srcObject = e.streams[0];
}
});
 
 
const remoteVideo = document.querySelector('#remoteVideo') as HTMLVideoElement;
const localVideo = document.querySelector('#localVideo') as HTMLVideoElement;
 
async function pushStream(answer: RTCSessionDescriptionInit) {
pc1.setRemoteDescription(answer);
}
 
async function pullStream(offer: RTCSessionDescriptionInit): Promise<void> {
pc2.setRemoteDescription(offer);
const answer = await pc2.createAnswer();
pc2.setLocalDescription(answer);
console.warn('answer', answer);
pushStream(answer);
}
 
 
window.onload = async () => {
const localStream = await navigator.mediaDevices.getUserMedia({
video: true,
audio: true,
});
 
 
localVideo.srcObject = localStream;
localStream.getTracks().forEach((track) => pc1.addTrack(track, localStream));
 
 
const offer = await pc1.createOffer();
pc1.setLocalDescription(offer);
console.warn('pc1 offer', offer);
pullStream(offer);
};
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
WebRTC 简介 WebRTC,名称源自网页实时通信(Web Real-Time Communication)的缩写,是一个支持网页浏览器进行实时语音通话或视频聊天的技术,是谷歌2010年以6820万美元收购Global IP Solutions公司而获得的一项技术。 WebRTC提供了实时音视频的核心技术,包括音视频的采集、编解码、网络传输、显示等功能,并且还支持跨平台:windows,linux,mac,android。 虽然WebRTC的目标是实现跨平台的Web端实时音视频通讯,但因为核心层代码的Native、高品质和内聚性,开发者很容易进行除Web平台外的移殖和应用。很长一段时间内WebRTC是业界能免费得到的唯一高品质实时音视频通讯技术。 为什么需要 WebRTC 开发者教程? 虽然WebRTC技术已经较为成熟,其集成了最佳的音/视频引擎,十分先进的codec,且包含了使用STUN、ICE、TURN、RTP-over-TCP的关键NAT和防火墙穿透等众多门槛并不低的技术。抛开音视频技术本身的复杂性外,要想找到合适的资料、完整的代码和库、配合合适的IDE和辅助工具能正常地实现编译和安装都非常的不容易,而这还只是个开始。没有靠谱的教程,你该怎么开始?那么地坑等在那,难道你打算一个一个趟过去? 本《WebRTC 零基础开发者教程》主要讲了什么 本文中提供下载的《WebRTC 零基础开发者教程》将以一个初学者的角度,从0开始逐步引导你掌握WebRTC开发的方方面面(当然,教程中更多的是操作性的内容,具体到技术原理和实现,显然不是本教程的讨论范畴)。 《WebRTC 零基础开发者教程》目录 1 工具 1.1 depot_tools 1.1.1 目标 1.1.2 Chromium 1.1.3 使用说明在这儿 1.1.4 下载 1.1.5 使用 1.1.6 具体使用例子 1.2 Gyp工具 1.3 Python工具 1.4 本地集成开发环境(IDE ) 1.4.1 Visual studio 1.4.2 Kdevelop 1.4.3 Eclipse 2 Webrtc 2.1 下载、编译 2.1.1 Windows下 2.1.2 ubuntu下编译 2.1.3 编译Android(只能在 linux 下) 3 webrtc开发 3.1 开发P2P视频软件需要处理的问题 3.1.1 用户列的获取、交换、信令的交换 3.1.2 P2P通信 3.1.3 多媒体处理 3.2 webrtc架构 3.2.1 WebRTC架构组件介绍 3.2.2 WebRTC核心模块API介绍 3.2.3 webRTC核心API详解 4 Libjingle详细介绍 4.1 重要组件 4.1.1 信号 4.1.2 线程和消息 4.1.3 名称转换 4.1.4 SSL支持 4.1.5 连接 4.1.6 传输,通道,连接 4.1.7 候选项 4.1.8 数据包 4.2 如何工作 4.2.1 Application模块 4.2.2 XMPP Messaging Component 模块 4.2.3 Session Logic and management commponent 模块 4.2.4 Peer to peer Component 模块 4.2.5 其他 4.3 建立libjingle应用程序 5 代码分析 5.1 音频通道建立过程 5.2 音频接收播放过程 5.3 视频接收播放过程 6 协议 6.1 XMPP协议 6.1.1 原理介绍 6.1.2 XMPP 协议网络架构 6.1.3 XMPP 协议的组成 6.1.4 Xmpp介绍 6.1.5 协议内容 6.2 Stun协议 6.2.1 P2P实现的原理 6.2.2 P2P的常用实现 6.2.3 Stun URI 6.2.4 内容 6.2.5 中文内容 6.2.6 开源服务器 6.2.7 公开的免费STUN服务器 6.3 Turn协议 6.3.1 概念 6.3.2 Turn uri 6.3.3 开源服务器工程 6.3.4 开源库 6.4 交互式连接建立(Interactive Connectivity Establishment) 6.4.1 IETF规格 6.4.2 开源工程 6.5 XEP-0166 Jingle 6.5.1 绪论 6.5.2 需求 6.6 Sctp协议 6.7 Rtp协议 7 附件 7.1 Gyp工具 7.2 Google test程序 7.3 Webrtc库介绍 7.4 webrtc代码相关基础知识 7.5 STUN和TURN技术浅析 7.6 基于ICE的VoIP穿越NAT改进方案 7.7 ubuntu安装使用stuntman 7.8 一个开源的ICE库——libnice介绍 7.9 4种利用TURN穿越对称型NAT方案的设计与实现 7.10 基于ICE方式SIP信令穿透Symmetric_NAT技术研究
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

热爱技术的小胡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值