调用 navigator.mediaDevices.getUserMedia() 或删除视频轨道后请求/添加网络摄像头

维亚切斯拉夫

我创建了一个基本的 MediaStream,它在我的 react-app 中获取视频和音轨,如下所示:

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

setLocalStream(getLocalStream);
  const handleShowCamClick = async () => {
    if (!callContext.localStream) return;
    callContext.localStream.getVideoTracks().forEach((track: MediaStreamTrack) => track.enabled = true);
    callContext.setShowCam(true); 
  };

  const handleHideCamClick = () => {
    if (!callContext.localStream) return;
    // callContext.localStream.getVideoTracks().forEach((track: MediaStreamTrack) => track.enabled = false);
    callContext.localStream.getVideoTracks().forEach((track: MediaStreamTrack) => track.stop());
    callContext.setShowCam(false); 
  };

所以现在我希望用户能够禁用其网络摄像头。设置track.enabled = false将导致网络应用程序仍在使用网络摄像头,但将视频变为黑色,这不是我想要的行为。

相反,我希望网络应用不再使用网络摄像头。我有一个网络摄像头,每次都会发出蓝光,表明摄像头正在录制。track.enabled = false我的网络摄像头向我展示了它仍然在技术上录制

如果我删除视频,track.stop()将导致我想要的行为。网络摄像头不再使用,但我如何将网络摄像头的视频轨道添加回localStream

track.stop()从 MediaStream中删除轨道localStream并释放网络摄像头,但由于视频轨道不再存在,如何在localStream不重新初始化 MediaStream 的情况下请求网络摄像头的新视频轨道并将其附加到?

BkiD

以下解决方案使用 Vanilla Javascript,因为我相信很多人将来都会有兴趣解决这个问题。

将此视为可以适应任何 Javascript 框架以支持 WebRTC 任务的概念证明。

最后说明 - 此示例仅处理媒体流的获取、显示和合并。所有其他 WebRTC 内容,例如通过 RTCPeerConnection 发送流等,都必须使用此处创建的流执行 - 替换/更新这些流超出了本示例的范围。

核心理念:

  1. 通过 getUserMedia() 获取流

  2. 将流分配给 HTMLMediaElement

  3. 使用 getVideoTracks() 仅停止视频轨道。

  4. 再次使用 getUserMedia() 获取没有音频的新流。

  5. 使用 MediaStream 构造函数创建一个新流,使用 - 来自新流的视频 + 来自现有流的音频,如下所示 -

    新的 MediaStream([...newStream.getVideoTracks(), ...existingStream.getAudioTracks()]);

  6. 根据需要使用新生成的MediaStream(即RTCPeerConnection中的replace等)。

CodePen 演示

let localStream = null;
let mediaWrapperDiv = document.getElementById('mediaWrapper');
let videoFeedElem = document.createElement('video');
videoFeedElem.id = 'videoFeed';
videoFeedElem.width = 640;
videoFeedElem.height = 360;
videoFeedElem.autoplay = true;
videoFeedElem.setAttribute('playsinline', true);

mediaWrapperDiv.appendChild(videoFeedElem);

let fetchStreamBtn = document.getElementById('fetchStream');
let killEverythingBtn = document.getElementById('killSwitch');
let killOnlyVideoBtn = document.getElementById('killOnlyVideo');
let reattachVideoBtn = document.getElementById('reattachVideo');

async function fetchStreamFn() {
  localStream = await navigator.mediaDevices.getUserMedia({
    video: true,
    audio: true
  });
  if (localStream) {
    await attachToDOM(localStream);
  }
}

async function killEverythingFn() {
  localStream.getTracks().map(track => track.stop());
  localStream = null;
}

async function killOnlyVideoFn() {
  localStream.getVideoTracks().map(track => track.stop());
}

async function reAttachVideoFn() {
  let existingStream = localStream;
  let newStream = await navigator.mediaDevices.getUserMedia({
    video: true,
    audio: false
  });
  localStream = new MediaStream([...newStream.getVideoTracks(), ...existingStream.getAudioTracks()]);
  if (localStream) {
    await attachToDOM(localStream);
  }
}

async function attachToDOM(stream) {
  videoFeedElem.srcObject = new MediaStream(stream.getTracks());
}

fetchStreamBtn.addEventListener('click', fetchStreamFn);
killOnlyVideoBtn.addEventListener('click', killOnlyVideoFn);
reattachVideoBtn.addEventListener('click', reAttachVideoFn);
killEverythingBtn.addEventListener('click', killEverythingFn);
div#mediaWrapper {
  margin: 0 auto;
  text-align: center;
}

div#mediaWrapper video {
  object-fit: cover;
}

div#mediaWrapper video#videoFeed {
  border: 2px solid blue;
}

div#btnWrapper {
  text-align: center;
  margin-top: 10px;
}

button {
  border-radius: 0.25rem;
  color: #ffffff;
  display: inline-block;
  font-size: 1rem;
  font-weight: 400;
  line-height: 1.6;
  padding: 0.375rem 0.75rem;
  text-align: center;
  cursor: pointer;
}

button.btn-blue {
  background-color: #007bff;
  border: 1px solid #007bff;
}

button.btn-red {
  background-color: #dc3545;
  border: 1px solid #dc3545;
}

button.btn-green {
  background-color: #28a745;
  border: 1px solid #28a745;
}
<h3>How to check if this actually works?
  <h3>
    <h4>Just keep speaking in an audibly loud volume, you'll hear your own audio being played from your device's speakers.<br> You should be able to hear yourself even after you "Kill Only Video" (i.e. Webcam light goes off)
    </h4>
    <div id="mediaWrapper"></div>
    <div id="btnWrapper">
      <button id="fetchStream" class="btn-blue" type="button" title="Fetch Stream (Allow Access)">Fetch Stream</button>
      <button id="killOnlyVideo" class="btn-red" type="button" title="Kill Only Video">Kill Only Video</button>
      <button id="reattachVideo" class="btn-green" type="button" title="Re-attach Video">Re-attach Video</button>
      <button id="killSwitch" class="btn-red" type="button" title="Kill Everything">Kill Everything</button>
    </div>

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

navigator.mediaDevices.getUserMedia 返回 NotReadableError:无法启动视频源

JS,navigator.mediaDevices.getUserMedia() 不工作

2019年访问navigator.mediaDevices.getUserMedia()的方式

从navigator.mediaDevices.getUserMedia()获取字节流?

Firefox从不解析navigator.mediaDevices.getUserMedia()

使用navigator.mediaDevices.getUserMedia录制浏览器音频

在JavaScript的navigator.mediaDevices.getUserMedia中设置采样频率

Navigator.getUserMedia() 已弃用。如何更改为 MediaDevices.getUserMedia()

停止navigator.GetUserMedia摄像头访问

使用 mediaDevices.getUserMedia 访问笔记本电脑上的前置摄像头

渐进式Web应用程序:访问navigator.mediaDevices.getUserMedia时出错?

Google chrome DOMException:系统拒绝了navigator.mediaDevices.getUserMedia的权限

我可以在Android / IOS Webview中使用navigator.mediaDevices.getUserMedia吗?

如何使用 navigator.mediaDevices.getUserMedia 降低麦克风输入音量?

停止/关闭由navigator.getUserMedia打开的网络摄像头

导航器MediaDevices getUserMedia notAllowedError

mediaDevices.getUserMedia无法在iOs 11中使用Safari 11(视频为黑色)

mediaDevices.getUserMedia,音频播放完毕后开始麦克风录制,Safari问题

使用getUserMedia后关闭网络摄像头/相机

如何从移动网络中的navigator.getUserMedia()获取对象?

更新到Chrome 74后未定义Navigator.getUserMedia和Navigator.webkitGetUserMedia

部署网站后,我无权访问navigator.mediaDevices。我该如何解决?

Web RTC navigator.getUserMedia

navigator.mediaDevices.enumerateDevices()返回空标签

未定义不是对象(评估'navigation.mediaDevices.getUserMedia')

WebcamToy如何在getUserMedia()网络摄像头视频之上获得怪异的效果?

网络摄像头getUserMedia API-AngularJS错误?

通过ReactJS中的.getUserMedia访问网络摄像头后,断开其单击

Firefox:navigator.getUserMedia不是函数