我们可以在几乎所有的会议应用程序中找到共享屏幕。这些应用程序可以是本机应用程序,也可以只是Web应用程序。有了屏幕共享权限,你的Web应用可以捕捉你的浏览器标签或整个屏幕。而且,你可以与所有人分享它。
在本文中,我将向你介绍一个简单的屏幕共享Web应用,它使用WebRTC来创建点对点连接,并使用NodeJs + Socket.IO来构建一个信令服务器。
系统流程概述
我们将构建一个 Web 应用程序,客户可以在其中与管理员共享他们的屏幕。
客户端和管理员都使用信令服务器来创建对等连接。之后,他们可以直接共享数据(媒体流)。
执行
让我们创建一个简单的 NodeJS 应用程序并安装一些依赖项:
npm init -y
npm install express socket.io
服务器
使用 express 和 socket.io 创建一个简单的 HTTP 服务器:
// server.js
const express = require('express');
const { Server: SocketServer } = require('socket.io');
const app = express();
app.use('/', express.static('public'));
const httpServer = app.listen(3000, () => {
console.log(`Server started on 3000`);
});
const io = new SocketServer(httpServer);
io.on('connection', (socket) => {
console.log('new connection from ', socket.id);
socket.on('offer', (offer) => {
console.log('new offer from ', socket.id);
socket.broadcast.emit('offer', offer);
});
socket.on('answer', (answer) => {
console.log('new answer from ', socket.id);
socket.broadcast.emit('answer', answer);
});
socket.on('icecandidate', (candidate) => {
console.log('new ice candidate from ', socket.id);
socket.broadcast.emit('icecandidate', candidate);
});
});
该服务器将监听3000端口。它把/public下的所有东西都作为静态文件提供。
套接字服务器只是转发来自客户端或管理员的消息,相互之间。
offer : 步骤(1) – 客户端向管理员发送一个提议
answer : 第(3)步 – 管理员给客户端一个答复。
icecandidate: 它们交换ice candidates
客户端
我们将建立一个简单的 HTML 页面,嵌入客户端应用程序的 JavaScript 逻辑。
<!-- public/client.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
#need-help {
position: fixed;
bottom: 50px;
right: 50px;
color: white;
background-color: red;
padding: 10px;
border: 1px solid red;
border-radius: 4px;
}
</style>
<title>Client</title>
</head>
<body>
<!-- A simple form to demo -->
<form>
<fieldset>
<legend>Fruit juice size</legend>
<p>
<input type="radio" name="size" id="size_1" value="small" />
<label for="size_1">Small</label>
</p>
<p>
<input type="radio" name="size" id="size_2" value="medium" />
<label for="size_2">Medium</label>
</p>
<p>
<input type="radio" name="size" id="size_3" value="large" />
<label for="size_3">Large</label>
</p>
</fieldset>
</form>
<button id="need-help">Need help!</button>
</body>
<!-- Client script -->
<script src="/socket.io/socket.io.js"></script>
<script src="./client.js"></script>
</html>
// public/client.js
'use strict';
const socket = io();
const peer = new RTCPeerConnection();
const helpButton = document.getElementById('need-help');
helpButton.addEventListener('click', async () => {
try {
const stream = await navigator.mediaDevices.getDisplayMedia({
audio: false,
video: true,
preferCurrentTab: true,
});
peer.addTrack(stream.getVideoTracks()[0], stream);
const sdp = await peer.createOffer();
await peer.setLocalDescription(sdp);
socket.emit('offer', peer.localDescription);
} catch (error) {
console.error(error);
alert(error.message);
}
});
socket.on('answer', async (adminSDP) => {
peer.setRemoteDescription(adminSDP);
});
peer.addEventListener('icecandidate', (event) => {
if (event.candidate) {
socket.emit('icecandidate', event.candidate);
}
});
socket.on('icecandidate', async (candidate) => {
await peer.addIceCandidate(new RTCIceCandidate(candidate));
});
首先,我们连接到套接字服务器并创建一个RTCPeerConnection
对象。
当客户端用户点击帮助按钮时,浏览器会要求用户选择要分享的内容。
- 步骤 (1):创建一个
offer
,设置报价和本地描述,并将其发送offer
给管理员。 - 步骤 (3):听取
answer
管理员的意见。 - 通过监听对象
icecandidate
的事件来交换 ice candidatesRTCPeerConnection
,并将 ice candidates 发送给管理员。还听取了 admin ice candidate 更新我们的连接对象。
Admin
当连接设置成功后,管理页面将显示客户端屏幕。
<!-- public/admin.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
#client-screen {
border: 1px solid red;
background-color: gray;
width: 100%;
margin: auto;
}
</style>
<title>Admin</title>
</head>
<body>
<h1>Admin</h1>
<video id="client-screen" autoplay muted playsinline></video>
</body>
<script src="/socket.io/socket.io.js"></script>
<script src="./admin.js"></script>
</html>
// public/client.js
'use strict';
const socket = io();
const peer = new RTCPeerConnection();
const video = document.getElementById('client-screen');
peer.addEventListener('track', (track) => {
video.srcObject = track.streams[0];
});
socket.on('offer', async (clientSDP) => {
await peer.setRemoteDescription(clientSDP);
const sdp = await peer.createAnswer();
await peer.setLocalDescription(sdp);
socket.emit('answer', peer.localDescription);
});
peer.addEventListener('icecandidate', (event) => {
if (event.candidate) {
socket.emit('icecandidate', event.candidate);
}
});
socket.on('icecandidate', async (candidate) => {
await peer.addIceCandidate(new RTCIceCandidate(candidate));
});
与客户端相同,我们连接到套接字服务器并创建一个RTCPeerConnection
对象。
管理员将监听track
事件,将客户端屏幕显示为媒体源。
- 步骤(2):管理员收到
offer
,它将报价设置为对等连接的远程描述。并创建一个answer
并将其发送回客户端,不要忘记将答案设置为本地描述。 - 执行与客户端逻辑相同的操作来交换 ice candidates。
验证
启动服务器并在不同的浏览器窗口中访问客户端和管理员。
node server.js
客户端端点:http://localhost:3000/client.html
管理端点:http://localhost:3000/admin.html
点击Need help
客户端窗口中的按钮,选择当前选项卡内容并点击Share
:
可以在管理窗口中看到客户端选项卡的内容:
结论
正如你所看到的,我们没有花那么多时间来建立一个屏幕共享应用程序。这个应用程序向你展示了一个点对点应用程序如何工作的概况。
请注意,该演示程序在 “在线 “环境下几乎不能很好地工作。你需要阅读更多关于STUN、STUNR和NAT……等,以便在互联网上部署你的应用程序。
该应用程序的源代码发布在https://github.com/codetheworld-io/remote-assistant-system。
作者:Hoang Dinh
来自:JavaScript in Plain English
本文来自作者投稿,版权归原作者所有。如需转载,请注明出处:https://www.nxrte.com/jishu/webrtc/27084.html