WebRTC 信令 Demo:如何建立连接

WebRTC 是 RTC 技术中流行的概念之一,有各种教程。此外,有大量库(尤其是 NPM 库)使用 WebRTC 建立通信,用途广泛。许多教程使用这些库来展示如何构建 Zoom、Discord 等的克隆应用程序。但是,它们未能展示 WebRTC 的核心工作原理。

在本文中,我们将制作一个简单的Demo,演示两个浏览器之间的信号传输。它只需要一个浏览器和一些 Javascript 代码。由于目标是掌握信号概念,因此它不会是一个有用的应用程序,而只是一个Demo,以简单的方式演示建立连接所需的每个组件。

设置

在本 Demo 中,我们需要两个浏览器同时工作。文件结构如下图所示。如果你愿意,可以使用两台电脑来查看不同设备之间的连接。无论是使用同一台设备还是两台设备,情况都是一样的。

signaling demo
├── userA
│   ├── index.html
│   └── scriptA.js
└── userB
    ├── index.html
    └── scriptB.js

HTML 文件将是空白的,它们只需要一个 HTML 模板,并需要连接到它们的脚本文件。

<!-- userA/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <title>User A</title>
</head>

    <script src="scriptA.js"></script>
</html>
<!-- userB/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <title>User B</title>
</head>

    <script src="scriptB.js"></script>
</html>

为了使用我们的环境,我建议在 VS Code 中打开signaling demo文件夹并启用 Live Share。然后我们可以打开两个选项卡来访问其中两个目录:

http://127.0.0.1:5500/userA 
http://127.0.0.1:5500/userB

不过,只要在浏览器上打开 HTML 文件就足够了。我们不需要页面本身,只需要像下面这样打开两个标签页及其控制台。

WebRTC 信令 Demo:如何建立连接

创建 SDP

设置已就绪,让我们开始使用 scriptA.js:

const localConnection = new RTCPeerConnection();

const dataChannel = localConnection.createDataChannel('dataChannel');

//Event listeners
dataChannel.onopen = () => {
    console.log('Data channel opened');
}

dataChannel.onmessage = event => {
    console.log("New Message: " + event.data);
}
  • 第一步是创建 RTCPeerConnection,建立我们的连接。
  • 该连接需要一个数据通道来传输我们的信息。我们为 a 创建 localConnection通道,并将其标签设置为 dataChannel
  • 我们需要一些事件监听器来从连接中获取更新:
  • 第一个事件监听器监听数据通道是否已打开。打开是指与远端peer的连接成功,peer之间的数据通道连通。
  • 一旦数据通道打开,我们就可以开始监听传入的信息。
localConnection.createOffer().then( offer => {
    localConnection.setLocalDescription(offer);
}).then( a => {
    console.log("Offer created!");
})

localConnection.onicecandidate = event => {
    console.log("New candidate! SDP updated: ");
    console.log(localConnection.localDescription);
}
  • 为了获取 SDP 对象,我们需要创建一个报价。该报价将保存到用户 A 的本地描述中。
  • 现在我们倾听 ICE 候选人的声音。一旦报价创建,我们将为我们的设备找到几个 ICE 候选者。每次我们获得新的 ICE 候选者时,我们都会更新 SDP,以便它包含迄今为止的所有候选者。

SDP已创建,我们可以在控制台中看到它。我们将有几个 SDP 对象,但我们需要最后一个,因为它包含所有 ICE 候选对象。

WebRTC 信令 Demo:如何建立连接

我们可以轻松复制它,如上图所示。为了完成信令,我们需要将此 SDP 对象传输到远程对等点。对于此Demo,我们只需复制它并将在用户 B 中使用它。在下一篇文章中,我们将研究如何通过 Firebase 数据库发送 SDP 信号。

发出报价并创建答案

在继续与用户 A 讨论之前,我们需要将 SDP 传递给用户 B。开始编写scriptB.js代码:

const remoteConnection = new RTCPeerConnection();

remoteConnection.onicecandidate = event => {
    console.log("New candidate! SDP updated: ");
    console.log(remoteConnection.localDescription);
}

remoteConnection.ondatachannel = event => {
    const dataChannel = event.channel;
    remoteConnection.dataChannel = dataChannel;

    dataChannel.onmessage = event => {
        console.log("New Message: " + event.data);
    }

    dataChannel.onopen = () => {
        console.log('Data channel opened');
    }
}
  • 就像我们对用户 A 所做的那样,我们创建一个RTCPeerConnection对象并监听新的 ICE 候选者。当我们为用户 B 创建答案时,这些候选者将会出现。
  • 事件侦听器很相似,但有一些细微的差别。由于用户A发起了信令过程,因此当连接建立时,其数据通道将被传递给用户B,这意味着他们将共享相同的数据通道。因此,我们需要监听用户B的数据通道。当数据通道中发生事件时,用户B将像用户A一样监听打开和消息事件。
function setOffer(offer) {
    remoteConnection.setRemoteDescription(offer).then( a => {
        console.log("Offer set!");
    })

    remoteConnection.createAnswer().then( answer => {
        remoteConnection.setLocalDescription(answer);
    }).then( a => {
        console.log("Answer created!");
    })
}
  • 我们在这里使用一个函数,因为一旦我们从用户 A 获得 SDP 报价,我们就会调用这个函数。
  • 为了将 SDP 传递给用户 B,我们将报价设置为远程描述。
  • 当我们设置远程描述时,我们可以创建我们的答案并将其设置为本地描述。
// Execute this in the console of User B (SDP object is only given for example, you need to pass your own SDP object you copied)
setOffer({
    "type": "offer",
    "sdp": "v=0\r\no=- 6903397949454729551 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE 0\r\na=extmap-allow-mixed\r\na=msid-semantic: WMS\r\nm=application 56524 UDP/DTLS/SCTP webrtc-datachannel\r\nc=IN IP4 10.254.127.14\r\na=candidate:2579874737 1 udp 2122260223 10.254.127.14 56524 typ host generation 0 network-id 1 network-cost 10\r\na=candidate:3611705153 1 tcp 1518280447 10.254.127.14 9 typ host tcptype active generation 0 network-id 1 network-cost 10\r\na=ice-ufrag:JApg\r\na=ice-pwd:AHSRC03UbXKzl2P+e9dPNLZT\r\na=ice-options:trickle\r\na=fingerprint:sha-256 42:50:14:BB:F9:6B:A0:3B:62:15:59:86:14:20:48:30:DD:50:8B:C0:30:31:AD:61:E3:42:B0:20:93:EE:14:30\r\na=setup:actpass\r\na=mid:0\r\na=sctp-port:5000\r\na=max-message-size:262144\r\n"
})

一旦我们执行该函数,就会创建一个答案,并且每次找到新的 ICE 候选者时,用户 B 的 SDP 都会更新。就像我们之前所做的那样,我们将复制答案 SDP 对象。

WebRTC 信令 Demo:如何建立连接

建立连接并发送消息

我们回到用户 A 并完成scriptA.js。我们将定义另外两个函数来获得聊天功能。

function setAnswer(answer) {
    localConnection.setRemoteDescription(answer);
}

function sendMessage(message) {
    dataChannel.send(message);
}
// Execute this in the console of User A (SDP object is only given for example, you need to pass your own SDP object you copied)
setAnswer({
    "type": "answer",
    "sdp": "v=0\r\no=- 8372747172637914019 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE 0\r\na=extmap-allow-mixed\r\na=msid-semantic: WMS\r\nm=application 52700 UDP/DTLS/SCTP webrtc-datachannel\r\nc=IN IP4 10.254.127.14\r\na=candidate:2579874737 1 udp 2122260223 10.254.127.14 52700 typ host generation 0 network-id 1 network-cost 10\r\na=ice-ufrag:9BNJ\r\na=ice-pwd:duKEejZ669stZBln7bBESiii\r\na=ice-options:trickle\r\na=fingerprint:sha-256 1B:17:0E:A8:41:90:C5:79:F1:12:0E:61:E2:05:EE:CE:4D:91:12:A3:97:20:91:D8:A7:42:17:F1:C8:9E:23:16\r\na=setup:active\r\na=mid:0\r\na=sctp-port:5000\r\na=max-message-size:262144\r\n"
})
  • 为了完成信令过程,我们需要向用户 A 发回信号。我们将应答SDP设置为用户A的远程描述。
  • 一旦我们完成信令,数据通道就会为双方打开。我们可以轻松地通过数据通道从用户 A 向用户 B 发送消息。

还剩下最后一个函数,我们将在scriptB.js中声明它:

function sendMessage(message) {
    remoteConnection.dataChannel.send(message);
}

这个函数有点不同,因为用户 B 使用从用户 A 处获得的数据通道,所以它需要使用与其连接绑定的数据通道。

WebRTC 信令 Demo:如何建立连接

通过建立连接,我们可以轻松地向远程对等设备发送字符串等简单变量。不仅如此,您还可以发送视频音轨、对象甚至文件。在下一篇文章中,我们将开始构建能实现所有这些功能的应用程序。

如果你想试用该 Demo,可以在 GitHub 代码库 中找到它。

本文来自作者投稿,版权归原作者所有。如需转载,请注明出处:https://www.nxrte.com/jishu/webrtc/31214.html

(0)

相关推荐

发表回复

登录后才能评论