WebRTC简介
嘿,希望你一切平安。今天我们来聊聊 WebRTC(Web 实时通信)。
WebRTC 允许您进行点对点实时通信,而无需打扰服务器。是的,您没看错,您可以进行点对点通信并实时共享媒体流,例如音频、视频和任意数据。
我们该怎么做呢?
在我们讨论 WebRTC 之前,我们先来聊聊 Socket 连接。Web Socket 允许我们在客户端发送/接收我们已知的实时事件。我们与 Socket 服务器建立 Socket 连接,然后就可以向服务器广播/接收事件了。
我们连接到服务器。假设有两个客户端(Peer)连接到服务器。因此,通信是通过服务器进行的。服务器负责建立该套接字连接。
由于这个原因,对等点有时可能会遇到连接问题、消息丢失和消息延迟。
这就像魔术一样吗?
稍等一下,在我们向对等方发送任何数据之前,我们需要建立连接,这对于开发人员在两个对等方之间建立 WebRTC 连接是一项具有挑战性的任务。
信号
信令是双方为了建立连接而交换信息的方式。这些信息包含 SDP、ICE 候选、用户信息等。
信号传输可以通过套接字、实时数据库(如 Firestore 等)进行。
您可以随时制定信令逻辑来建立跨同行的连接。
如何建立联系?谈判
该流程从提出报价开始。
- Peer A 创建 Offer以便与 Peer B 进行通信。
- Peer B 需要接受该 offer并发回 Offer 的 Answer。
- 同伴 A 接受答案。
这个过程被称为谈判。
协商是双方协商他们想要交换哪种数据(即媒体流、任意数据)以及在两个设备之间交换数据的最佳方式的过程。
一般而言,在对等体之间建立连接之前,协商会让对等体决定他们想要交换什么类型的数据。
SDP(会话描述协议)
提供/应答协议 (Offer/Answer) 被称为SDP(会话描述协议)。SDP是一种描述跨端多媒体连接和会话的格式。您可以将 SDP 视为基于浏览器的普通会话。
new RTCPeerConnection().createOffer();
// Output of below code SDP Offer
{
"type": "offer",
"sdp": "v=0\r\no=- 6306366628372337755 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=extmap-allow-mixed\r\na=msid-semantic: WMS\r\n"
}
一旦谈判完成,同行们现在就可以相互沟通。
好的!现在显示一些代码。
现在该写一些代码了。我们将在 Peer A 和 Peer B 之间建立 WebRTC 连接。
我假设两个对等体之间有一个套接字连接。我们将使用此套接字作为信令服务器。
创建一个全局连接对象,以便我们稍后可以在函数中使用它。
const connection = new RTCPeerConnection();
设置ICE候选监听器
connection.onicecandidate = e => {
// signalling ICE candidates to Peer B whenever we get it.
socket.emit("ice-candidate", JSON.stringify(e.candidate));
}
每当我们完成信号传输时,就将冰候选者添加到连接中。
socket.on("ice-candidate", e => {
connection.addIceCandidate(JSON.parse(e));
});
步骤 1: Peer A为 Peer B创建并发出报价信号。
const makeOffer = async () => {
// creating offer
const offer = await connection.createOffer();
// setting up offer as Peer's Local Description
connection.setLocalDescription(offer);
// signalling offer with Sockets
socket.emit("offer-created", JSON.stringify({ offer });
}
第二步:同伴 B 接受提议并发出答复信号
const acceptOffer = async (offer) => {
// setting up offer as Remote Description
await connection.setRemoteDescription(new RTCSessionDescription(offer));
// creating answer
const answer = await connection.createAnswer();
// setting up answer as Local Description.
connection.setLocalDescription(answer);
// signalling the answer
socket.emit("answer-added", JSON.stringify({ answer });
}
步骤 3:同伴 A 保存答案
const savingAnswer = async (answer) => {
// lastly, setting up Remote Description of Peer A
await connection.setRemoteDescription(new RTCSessionDescription(answer));
}
恭喜,您已创建点对点连接。现在双方可以互相交换数据了。
在整个过程中,两个连接彼此共享 ICE 候选。因此,每当我们获得 ICE 候选时,我们都会添加监听器和信令。
在两个对等体之间交换任意数据。
我们可以创建一个连接的数据通道,然后就可以发送和接收数据。
对等体 A 可以创建数据通道。
let DataChannel = Connection.createDataChannel("meeting-chat");
对等体 B 可以监听该数据通道
Connection.ondatachannel = e => {
DataChannel = e.channel
}
发送和接收消息
// listening for message
DataChannel.onmessage = e => console.log("I got message", e.data);
// sending message
DataChannel.send(JSON.stringify({ message: "Hey Peer" }));
注意:我们需要在对等体开始相互通信之前创建数据通道。否则,双方需要重新协商。
如果对等方需要重新协商,我们可以监听该事件
// this method can be called anytime if Peers need to
// perform negotiations again.
connection.onnegotiationneeded = e => {
console.log("Please start the negotiation process again");
}
发送媒体流
const sendStream async () => {
if(navigator) {
// browser navigator API to fetch media stream
const stream =
await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
const newStream = new MediaStream();
// sending media tracks to peers
stream.getTracks().forEach((s) => connection.addTrack(s, newStream));
}
}
接收媒体流
connection.ontrack = e => {
// you can use this media stream with <video> tag
console.log("Hey I got Media Streams", e.streams[0]);
}
调试
如果您遇到问题并想要调试您的 WebRTC 连接,您可以在浏览器中进行调试。
brave://webrtc-internals
chrome://webrtc-internals
about:webrtc <!-- For Firefox -->
就是这样。这就是WebRTC 连接的基本实现。如果您想了解更多关于 WebRTC 及其底层工作原理的信息,您需要了解一些网络术语。
网络术语
NAT(网络地址转换)
STUN
TURN(使用中继绕过 NAT)
ICE 候选
SDP(会话描述协议)
我希望这个博客能够帮助您了解如何在下一个项目中使用 WebRTC。
如果你想补充什么,请随时留言。也请在评论区告诉我你最喜欢哪一部分。
谢谢你,
Darshan Ponikar