- 📢欢迎点赞 :👍 收藏 ⭐留言 📝 如有错误敬请指正,赐人玫瑰,手留余香!
- 📢本文作者:由webmote 原创
- 📢作者格言:新的征程,我们面对的不是技术而是人心,人心不可测,海水不可量,唯有技术,才是深沉黑夜中的一座闪烁的灯塔 !
序言
当下直播界最炙手可热的技术,WebRTC应该时其中之一,而想在此技术领域登堂入室,确实有很多的知识和积累需要熟悉和学习,作为一个技术新手,怎么从懵懂到会用再到理解内涵而会心一笑,确实是挺难的一件事情。
也许我们永远也无法企及大师的项背,但有一点可以坚信,只要我们努力去学习,会使用这个最简单而直接的要求肯定能达到。
1. WebRTC技术
WebRTC(Web实时通信)是一种开放标准和技术,用于在Web浏览器之间实现实时通信,包括音频、视频和数据传输。它是由Google推出的,并得到了其他大型技术公司的支持和采用,目前众多的浏览器都已经支持WebRTC了,因此其应用也越来越多。
WebRTC的主要特点包括:
-
实时通信:WebRTC允许实时的音频、视频和数据传输,使用户可以通过浏览器直接进行语音和视频通话,而无需其他插件或软件。
-
网页集成:WebRTC可以直接集成到Web浏览器中,通过JavaScript API进行操作,无需下载或安装额外的应用程序。
-
点对点通信:WebRTC支持点对点(peer-to-peer)通信,这意味着数据可以直接在两个浏览器之间传输,而无需通过中间服务器。这种直接的通信方式可以提高速度和减少延迟。
-
安全性:WebRTC使用安全的传输协议(如SRTP)来保护音频和视频通信的隐私和安全性。它还支持加密和身份验证,确保通信的机密性和完整性。
-
开放标准:WebRTC是一个开放的标准,由W3C和IETF进行标准化和规范化。这意味着它是一个公开的技术,并且可以被广泛采用和支持。
WebRTC技术的特点使其在在线会议、远程协作、客户支持和实时通信应用中得到广泛应用。它提供了一种简单、便捷和安全的方式来进行实时通信,为用户提供了更好的体验和互动性。
2. 信令服务
虽然WebRTC支持点对点通信,但它仍然需要服务器,以便客户端可以交换元数据,通过称为信令的过程协调通信,并处理网络地址转换器(NAT)和防火墙。
这里我们主要介绍如何构建信令服务,以及如何处理与 STUN 和 TURN 服务器进行实际连接的行为。当然它还解释了WebRTC应用程序如何处理多方呼叫并与VoIP和PSTN(也称为电话)等服务进行交互。
如果您不熟悉WebRTC的基础知识,请在阅读本文之前参阅WebRTC入门。
那么,什么是信令呢?
信令是协调通信的过程。
为了使WebRTC应用程序能够配置呼叫,其客户端需要交换以下信息:
- 用于打开或关闭通信的会话控制消息
- 错误消息
- 多媒体元数据,例如编解码器、编解码器设置、带宽和媒体类型
- 用于建立安全连接的关键数据
- 网络数据,例如外界看到的主机的 IP 地址和端口
此信令过程需要和客户端来回传递消息,该机制不是由WebRTC API实现的,您需要亲自构建它。
2.1 为什么WebRTC没有定义信令?
为了避免冗余并最大限度地与现有技术兼容,WebRTC标准没有指定信令方法和协议。
JavaScript 会话建立协议 (JSEP
) 概述了此方法:
WebRTC呼叫背后的思想是完全指定和控制媒体,尽可能将信令留给应用程序。理由是不同的应用程序可能更喜欢使用不同的协议,例如现有的 SIP 或 Jingle 呼叫信令协议,或者针对特定应用程序自定义的内容。
JSEP 的体系结构还避免了浏览器必须保存状态,即充当信号状态机的功能。例如,如果每次重新加载页面时都会丢失信令数据,这将是一个问题。相反,信令状态可以保存在服务器上,这样看起来架构就更完美了,下图是JSEP体系架构。
JSEP 要求新的的交换在提问者offer
和 回答者answer
之间, 即上面提到的媒体元数据。Offer
和Answer
以会话描述协议 (SDP) 格式传达,如下所示:
v=0
o=- 7614219274584779017 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE audio video
a=msid-semantic: WMS
m=audio 1 RTP/SAVPF 111 103 104 0 8 107 106 105 13 126
c=IN IP4 0.0.0.0
a=rtcp:1 IN IP4 0.0.0.0
a=ice-ufrag:W2TGCZw2NZHuwlnf
a=ice-pwd:xdQEccP40E+P0L5qTyzDgfmW
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=mid:audio
a=rtcp-mux
a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:9c1AHz27dZ9xPI91YNfSlI67/EMkjHHIHORiClQe
a=rtpmap:111 opus/48000/2
…
想知道所有这些SDP胡言乱语实际上意味着什么吗?可以查看互联网工程任务组 (IETF) 示例。
请记住,WebRTC的设计使得在通过编辑SDP文本中的值设置为本地或远程描述之前可以调整offer
或answer
。例如,appr.tc 中的函数可用于设置默认编解码器和比特率。
SDP用JavaScript操作起来有些痛苦,并且有关于WebRTC的未来版本是否应该使用JSON的讨论,但是坚持使用SDP也有一些优点。
2.2 Alice呼叫Eve
当Alice想要呼叫Eve时,使用WebRTC的过程大致如下:
-
Alice打开她的Web浏览器,并通过getUserMedia方法获取她的音频和视频流。这将启动她的摄像头和麦克风。
-
Alice创建一个RTCPeerConnection对象,这是WebRTC中用于建立对等连接的主要对象。
-
Alice将她的本地流(音频和视频)添加到RTCPeerConnection对象中。
-
Alice创建一个数据通道(Data Channel),这是用于在对等连接之间传输任意数据的通道。数据通道可以用于发送文本消息、文件等。
-
Alice为数据通道设置消息接收的回调函数,以便在收到来自Eve的消息时进行处理。
-
Alice创建一个offer(邀请),其中包含她的媒体信息和网络配置。这个offer描述了Alice希望与Eve建立连接的条件。
-
Alice将她的本地描述(offer)设置为RTCPeerConnection的本地描述。
-
Alice通过信令服务器将她的本地描述发送给Eve。信令服务器充当中介,帮助Alice和Eve交换网络配置和媒体信息。
-
Eve收到Alice的本地描述,并创建一个RTCPeerConnection对象。
-
Eve将她的本地流(音频和视频)添加到RTCPeerConnection对象中。
-
Eve将Alice的本地描述设置为她的RTCPeerConnection的远程描述。
-
Eve创建一个answer(回答),其中包含她的媒体信息和网络配置。这个answer是对Alice的offer的回应。
-
Eve将她的本地描述(answer)设置为RTCPeerConnection的本地描述。
-
Eve通过信令服务器将她的本地描述发送给Alice。
-
Alice收到Eve的本地描述,并将其设置为她的RTCPeerConnection的远程描述。
-
Alice和Eve的RTCPeerConnection对象之间开始进行ICE(Interactive Connectivity Establishment)协商,以确定最佳的网络连接路径。
-
一旦ICE协商完成,Alice和Eve之间的对等连接建立成功,他们可以通过数据通道交换消息、音频和视频。
总的来说,WebRTC通过使用RTCPeerConnection对象和信令服务器来协调双方之间的通信,使Alice能够呼叫Eve并建立实时的音视频通信。
JSEP 支持 ICE Candidate Trickling,它允许呼叫者在初始报价后以增量方式向被呼叫者提供候选人,并允许被呼叫者开始对呼叫执行操作并建立连接,而无需等待所有候选人到达。
2.3 使用信令
看下代码,如下:
// handles JSON.stringify/parse
const signaling = new SignalingChannel();
const constraints = {audio: true, video: true};
const configuration = {iceServers: [{urls: 'stun:stun.example.org'}]};
const pc = new RTCPeerConnection(configuration);
// Send any ice candidates to the other peer.
pc.onicecandidate = ({candidate}) => signaling.send({candidate});
// Let the "negotiationneeded" event trigger offer generation.
pc.onnegotiationneeded = async () => {
try {
await pc.setLocalDescription(await pc.createOffer());
// send the offer to the other peer
signaling.send({desc: pc.localDescription});
} catch (err) {
console.error(err);
}
};
// After remote track media arrives, show it in remote video element.
pc.ontrack = (event) => {
// Don't set srcObject again if it is already set.
if (remoteView.srcObject) return;
remoteView.srcObject = event.streams[0];
};
// Call start() to initiate.
async function start() {
try {
// Get local stream, show it in self-view, and add it to be sent.
const stream =
await navigator.mediaDevices.getUserMedia(constraints);
stream.getTracks().forEach((track) =>
pc.addTrack(track, stream));
selfView.srcObject = stream;
} catch (err) {
console.error(err);
}
}
signaling.onmessage = async ({desc, candidate}) => {
try {
if (desc) {
// If you get an offer, you need to reply with an answer.
if (desc.type === 'offer') {
await pc.setRemoteDescription(desc);
const stream =
await navigator.mediaDevices.getUserMedia(constraints);
stream.getTracks().forEach((track) =>
pc.addTrack(track, stream));
await pc.setLocalDescription(await pc.createAnswer());
signaling.send({desc: pc.localDescription});
} else if (desc.type === 'answer') {
await pc.setRemoteDescription(desc);
} else {
console.log('Unsupported SDP type.');
}
} else if (candidate) {
await pc.addIceCandidate(candidate);
}
} catch (err) {
console.error(err);
}
};
更多详细的代码,可以参看一个例子程序。
2.4 发现对方
这是一种奇特的提问方式,我如何找到可以交谈的人?
对于电话呼叫,您有电话号码和目录。对于在线视频聊天和消息传递,您需要身份和状态管理系统,以及用户启动会话的方法。WebRTC应用程序需要一种方法,让客户端相互发出信号,表明他们想要开始或加入通话。
对等发现机制不是由WebRTC定义的,该过程可以像通过电子邮件发送或消息传递 URL 一样简单。对于视频聊天应用(如对讲和浏览器会议),您可以通过共享自定义链接来邀请他人加入通话。
2.5 如何构建信令服务
重申一下,信令协议和机制不是由WebRTC标准定义的。
无论您选择什么,都需要一个中间服务器在客户端之间交换信令消息和应用程序数据。可悲的是,网络应用程序不能简单地对互联网大喊:“将我连接到我的朋友!”
值得庆幸的是,信令消息很小,主要在通话开始时交换。在视频聊天会话的测试中,信令服务总共处理了大约 30-45 条消息,所有消息的总大小约为 10KB。
除了在带宽方面相对不要求外,WebRTC信令服务不会消耗太多的处理或内存,因为它们只需要中继消息并保留少量会话状态数据,例如连接了哪些客户端。
2.6 将消息从服务器推送到客户端
用于信令的消息服务必须是双向的:客户端到服务器和服务器到客户端。
双向通信违背了HTTP客户端/服务器请求/响应模型,但是多年来已经开发了各种技术黑客行为,例如长轮询,以便将数据从Web服务器上运行的服务推送到浏览器中运行的Web应用程序。
最近,EventSource API 已被广泛实现。这将启用服务器发送的事件 - 通过 HTTP 从 Web 服务器发送到浏览器客户端的数据。 专为单向消息传递而设计,但它可以与 XHR 结合使用,以构建用于交换信令消息的服务。信令服务通过向被叫方推送消息来传递来自呼叫方的消息,该消息由 XHR 请求传递。
WebSocket 是一种更自然的解决方案,专为全双工客户端-服务器通信而设计 - 可以同时在两个方向上流动的消息。使用纯 WebSocket 或服务器发送的事件, 构建的信令服务的一个优点是,这些 API 的后端可以在各种 Web 框架上实现,这些框架是大多数 Web 托管包(如 PHP、Python 和 Ruby)通用的。
当然,也可以通过让WebRTC客户端通过Ajax反复轮询消息传递服务器来处理信令,但这会导致大量冗余的网络请求,这对于移动设备来说尤其成问题。即使在建立会话后,对等方也需要轮询信令消息,以防其他对等方更改或会话终止。
2.7 现成的信令服务器
如果你不想自己动手,有几个WebRTC信令服务器可用,它们使用 Socket.IO ,并与WebRTC客户端JavaScript库集成:
- webRTC.io 是WebRTC最早的抽象库之一。
- Signalmaster是为与SimpleWebRTC JavaScript客户端库一起使用而创建的信令服务器。
如果你根本不想写任何代码,可以从vLine,OpenTok和Asterisk等公司获得完整的商业WebRTC平台。