如何用WebRTC和Socket.IO实现共享屏幕?

我们可以在几乎所有的会议应用程序中找到共享屏幕。这些应用程序可以是本机应用程序,也可以只是Web应用程序。有了屏幕共享权限,你的Web应用可以捕捉你的浏览器标签或整个屏幕。而且,你可以与所有人分享它。

在本文中,我将向你介绍一个简单的屏幕共享Web应用,它使用WebRTC来创建点对点连接,并使用NodeJs + Socket.IO来构建一个信令服务器。

系统流程概述

如何用WebRTC和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 candidates RTCPeerConnection,并将 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

如何用WebRTC和Socket.IO实现共享屏幕?

点击Need help客户端窗口中的按钮,选择当前选项卡内容并点击Share

如何用WebRTC和Socket.IO实现共享屏幕?

可以在管理窗口中看到客户端选项卡的内容:

如何用WebRTC和Socket.IO实现共享屏幕?
共享成功

结论

正如你所看到的,我们没有花那么多时间来建立一个屏幕共享应用程序。这个应用程序向你展示了一个点对点应用程序如何工作的概况。

请注意,该演示程序在 “在线 “环境下几乎不能很好地工作。你需要阅读更多关于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

(0)

相关推荐

发表回复

登录后才能评论