使用 WebRTC 进行视频通话第 5 步:与 WebRTC 共享您的屏幕

亚历克斯·利特文( Alex Litvin)Unsplash上传的照片

WebRTC(Web 实时连接)是一个带有 JavaScript API 的开源项目,它允许你在浏览器之间创建点对点连接。尽管它可以用于不同类型的数据传输,但其主要应用是视频通话。在之前的文章中,我们从浏览器访问麦克风和摄像头数据流,在用户之间通过 WebSocket 建立连接,然后我们将其用于信令过程,并且我们允许用户使用共享代码与给定的联系人建立连接。

以下是本系列文章的链接:

1.来自网络摄像头和麦克风的数据流(访问用户设备以及数据流,并在浏览器上显示视频(带音频))
2.通过 WebSocket 建立连接(在两个用户之间通过 WebSocket 建立 P2P 连接)
3.建立 WebRTC 连接( 建立 WebRTC 连接,真正开启视频聊天)
4.查找联系人(调整 WebSocket 服务器和客户端代码,使用户只有输入相同代码才会建立彼此联系)
5.与 WebRTC 共享您的屏幕(将 RTCPeerConnection 对象的视频轨道替换为显示媒体流的视频轨道,使用户之间共享屏幕)

在上一篇文章,我们可以通过 WebRTC 与联系人创建视频通话。链接对象可以看到和听到对方,但我们现在还希望他们能够共享他们的屏幕。这里假设你已经可以在连接对象之间建立 WebRTC 连接,如果没有,你可以按照第三篇文章的步骤操作。

访问用户的屏幕非常简单。在第一篇文章中,我们通过调用MediaDevices接口的getUserMedia 函数来请求访问用户的摄像头。

const stream = await window.navigator.mediaDevices.getUserMedia(
  {
    video: true,
    audio: true,
  },
);

有一个类似的函数可以访问用户的屏幕:getDisplayMedia

const stream = await navigator.mediaDevices.getDisplayMedia();

为了让用户能够共享他们的屏幕,我们必须将 RTCPeerConnection 对象的视频轨道替换为显示媒体流的视频轨道。我们不用替换整个流,因为我们仍希望用户能听到彼此的声音。但首先让我们在视频上显示一个工具栏和一个共享屏幕的按钮:

HTML 和 CSS

像以前一样,用户首先看到起始页,在该页中需要输入代码。![|60xauto]1_vVQ9rD39nhGC0qie6C7rCg

一旦输入了代码,她就可以点击开始按钮。浏览器请求访问麦克风和摄像头的权限,一旦用户接受,她就能进入聊天室。如果第二个用户使用相同的代码执行相同的过程,则双方将能够看到对方并听到对方的声音:

1_nNN6dLQaL3EdK3skH2-UsQ

这里的创新点是底部的这个工具栏,你可以在其中看到一个“眼睛”图标。默认情况下,此工具栏不显示,仅在暂停时可见。

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <title>VideoChat</title>
  <link rel="stylesheet" href="styles.css">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.13.0/js/all.min.js"></script>
</head>

<body>
  <div id="chat-room" style="display: none;">
    <video id="self-view" autoplay></video>
    <div id="remote-view-container">
      <video id="remote-view" autoplay></video>
      <div id="view-buttons">
        <button class="view-button" id="share-button"><i id="share-button-icon" class="fas fa-eye"></i></button>
        <button class="view-button" style="display: none" id="stop-share-button"><i id="stop-share-button-icon" class="fas fa-eye-slash"></i></button>
      </div>
    </div>
  </div>
  <div id="start">
    <input id="code-input" placeholder="Enter your code" />
    <button id="start-button" disabled>Start Video Chat</button>
  </div>
</body>

<script src="index.js"></script>
</html>
html, body {
  height: 100%;
  margin: 0;
}

body {
  background-color:#01284a;
  padding: 8px;
}

#start {
  position: relative;
  top: 40%;
  width: 100%;
  text-align: center;
}

#code-input {
  border-radius: 3px;
  margin-bottom: 20px;
  padding: 5px;
  font-size: 16px;
  text-align: center;
  border: none;
}

#start-button {
  display: block;
  margin: auto;
  padding: 10px;
  font-size: 16px;
  border-radius: 3px;
  font-weight: bold;
  color: white;
  border: none;
}

#start-button:not(:disabled) {
  cursor: pointer;
  background-color: #000f1c;
}

#start-button:disabled {
  cursor: not-allowed ;
  background-color: #7691a8;
}

video {
  width: 100%;
}

#chat-room {
  display: grid;
  grid-gap: 16px;
  width: 100%;
  grid-template-columns: 1fr 3fr;
}

#remote-view-container{
  position: relative;
  grid-column: 2;
  background-color: black;
  height: 95vh;
}

#self-view {
  grid-column: 1;
  background-color: black;
}

#remote-view {
  position: absolute;
  height: 100%;
  width: 100%;
}

#view-buttons {
  opacity: 0;
  transition: opacity 0.5s ease-out;
  position: absolute;
  border-radius: 3px;
  background-color: darkgray;
  bottom: 10px;
  padding: 10px;
  left: 0;
  right: 0;
  margin: 20px;
  text-align: center;
}

#view-buttons:hover {
  opacity: 0.7;
}

.view-button {
  background-color: darkgray;
  border-color: darkgray;
  border-radius: 3px;
  font-size: 20px;
  color: white;
  padding: 5px;
  border: none;
}

.view-button:hover {
  cursor: pointer;
  background-color: #757272;
}

单击此按钮后,该用户应该共享她的屏幕。

分享屏幕

上一篇文章,我重新设计了这个微项目的 JavaScript 部分,但一个重要的变化是新的变量senders 。RTCPeerConnection 对象的addTrack 方法返回一个RTCRtpSender对象,让我们可以控制发送到对等方的轨道。我们希望将视频轨道替换为屏幕视频轨道,因此我们希望将发送者保存在一个变量中以便稍后访问它们。

const senders = [];

[...]
 
const startChat = async () => {

  [...]

  userMediaStream.getTracks()
    .forEach(track => senders.push(peerConnection.addTrack(track, userMediaStream)));

  [...]

});

单击按钮时,我们首先请求访问用户的显示媒体流(他的屏幕视频流)。我们不想在用户每次打开和关闭屏幕共享时都要进行询问,因此我们将流保存在变量displayMediaStream 中。 如果我们已经有了流,就跳过此步。

然后我们在senders 数组中找到视频轨道的发送者 ,并用我们的新轨道替换它的轨道(显示媒体流中只有一个轨道,所以我们只取第一个)。

最后,我们调整视图:首先我们在用户的自拍微视频中显示屏幕,让她看到她同伴正在看的内容,我们隐藏分享按钮以显示“停止分享”的按钮。

 document.getElementById('share-button').addEventListener('click', async () => {
    if (!displayMediaStream) {
      displayMediaStream = await navigator.mediaDevices.getDisplayMedia();
    }
    senders.find(sender => sender.track.kind === 'video').replaceTrack(displayMediaStream.getTracks()[0]);
    
    //show what you are showing in your "self-view" video.
    document.getElementById('self-view').srcObject = displayMediaStream;
    
    //hide the share button and display the "stop-sharing" one
    document.getElementById('share-button').style.display = 'none';
    document.getElementById('stop-share-button').style.display = 'inline';
  });

停止共享屏幕

停止共享并没有什么不同。

  document.getElementById('stop-share-button').addEventListener('click', async () => {
    senders.find(sender => sender.track.kind === 'video')
      .replaceTrack(userMediaStream.getTracks().find(track => track.kind === 'video'));
    document.getElementById('self-view').srcObject = userMediaStream;
    document.getElementById('share-button').style.display = 'inline';
    document.getElementById('stop-share-button').style.display = 'none';
  });

在发件人中,我们找到带有视频轨道的那个,并将其轨道替换为用户媒体流的视频轨道(因此轨道来自用户的相机)。我们更新了自拍微视频并再次更改按钮,用户现在可以再次看到彼此了。

你可以在此处找到完整的 JavaScript 代码。

用户现在可以将他们的屏幕分享给他们的联系人。在接下来的文章中,我们还能看到用户怎样使用WebRTC交换文件。

原文作者 Heloise Parein
原文链接 https://levelup.gitconnected.com/share-your-screen-with-webrtc-video-call-with-webrtc-step-5-b3d7890c8747