WebRtc基础,流的捕捉与其认识

215 阅读4分钟

我正在参加「掘金·启航计划」

1. 设备屏幕捕捉

getDisplayMedia.png

1.1 API使用

屏幕捕获 API 对现有的媒体捕获和流 API 进行了补充,让用户选择一个屏幕或屏幕的一部分(如一个窗口)作为媒体流进行捕获。然后,该流可以被记录或通过网络与他人共享。

其API很简单:MediaDevices.getDisplayMedia()

const captureStream = await navigator.mediaDevices.getDisplayMedia(displayMediaOptions);

这样返回的就是你选择的捕获的流,其界面一般如下(在electron中使用该功能是没有这个选择弹框的):

效果就是会弹出浏览器弹窗,让用户选择需要的媒体流进行分享(此功能目前大部分浏览器不支持,只有较新的Chrome浏览器才支持,因此该功能适用在Electron项目上)

不过值得注意的是,如果要关闭对流的捕获,需要这样去做:

captureStream.getTracks().forEach((track) => {
    track.stop();
});

1.2 入参displayMediaOptions类型

navigator.mediaDevices.getDisplayMedia(displayMediaOptions)中函数入参displayMediaOptions是一个MediaStreamConstraints对象,也就是媒体追踪约束对象

在设备屏幕捕获的流当中,媒体追踪约束有如下值得注意的属性:

  • MediaTrackConstraints.cursor: 指示光标是否应该包含在捕获的显示面流中,以及它应该始终可见还是只在鼠标移动时可见。
  • MediaTrackConstraints.displaySurface:指示要捕获的显示表面的类型。取值为applicationbrowsermonitorwindow中的一个。
  • MediaTrackConstraints.logicalSurface:一个布尔值,如果正在捕获的视频不直接对应于单个屏幕显示区域,则该值为true

整个功能的实现在浏览器上还是颇为简单的,更多指导文档

2. 设备摄像头等输入设备流的捕捉

其实也很简单,使用的就是MediaDevices.getUserMedia(constraints)这个api,通常我们不设置constraints参数,那么默认就是获取摄像头和麦克风的媒体流,如果我们只想要获取摄像头的媒体流,那么我们可以这样设置constraints参数

const constraints = {
  audio: false,
  video: true,
}

其他使用基本和上面的获取屏幕流差不多因此我们可以自己手动对这个获取流的方法进行一个整合封装

/**
 * 获取可用设备
 * @returns Promise
 */
const getUseAbleDevices = async () => {
  if (navigator.mediaDevices && navigator.mediaDevices.enumerateDevices) {
    return await navigator.mediaDevices.enumerateDevices();
  } else {
    console.error('navigator.mediaDevices.enumerateDevices');
    return null;
  }
};
/**
 * 选择分享流(本地视频流) / 捕获用户许可的输入信号流
 * @returns Promise
 */
const getMediaStream = (type: 'user' | 'display' = 'display') => {
  const runFnMap: 'getUserMedia' | 'getDisplayMedia' =
    type === 'display' ? 'getDisplayMedia' : 'getUserMedia';
  return async (constraints?: MediaStreamConstraints) => {
    if (navigator.mediaDevices[runFnMap]) {
      const _constraints = constraints || {
        video: true,
        audio: {
          noiseSuppression: true,
          echoCancellation: true,
          enableBackground: false,
          suppressLocalAudioPlayback: true,
        },
      };
      const streams = await navigator.mediaDevices[runFnMap](_constraints);
      return {
        streams,
        close() {
          streams.getTracks().forEach((track) => {
            track.stop();
          });
        },
      };
    } else {
      console.error('不支持mediaDevices');
      return null;
    }
  };
};

用改api就能很好的对输入输出设备进行检查,能够根据设备情况在建立连接的时候判断可以捕获到哪些流发送给远程

3. 认识MediaStream

媒体流可以是来自本地设备的,也可以是来自远程设备的。媒体流可以是实时的,也可以是非实时的。媒体流,我们可以通过摄像头,麦克风,屏幕共享等方式获取到媒体流MediaStream。代码层面,上面的代码就是一个很好的一个获取媒体流的例子,除开上面的媒体流捕获,还可以直接new MediaStream()去创建一个媒体流

3.1 手动创建媒体流

  1. new MediaStream(stream),构造函数中传入一个流媒体
  2. new MediaStream(tracks),构造函数中传入一个媒体轨道数组MediaStreamTrack[]

3.2 常用方法

  1. addTrack(track),方法向流中添加一个新轨道。轨道被指定为类型的参数
  2. getAudioTracks,方法返回一个序列,该序列表示此流的轨道集中的所有MediaStreamTrack对象,其中MediaStreamTrack.kindaudio
  3. getVideoTracks(),类似getAudioTracks只不过MediaStreamTrack.kindvideo
  4. getTracks(),类似getAudioTracks,只不过MediaStreamTrack.kindvideoaudio

3.3 播放媒体流

当获取到流mediaStream后,我们可以把媒体流赋值给video标签或者是audio标签:

const player:HTMLVideoElement = document.getElementById('localVideo')
player?.setAttribute('autoplay', '');
player?.setAttribute('playsinline', '');
player && (player.srcObject = mediaStream);

4. 认识MediaStreamTrack

MediaStreamTrack 接口在 User Agent 中表示一段媒体源,比如音轨或视频。

这个东西一般是从MediaStream里面获取的,在MediaStream使用getTracks()方法即可得到这个媒体当中的多个媒体轨道组

4.1 常用属性

  • kind,这个属性是表明这是一个属于什么类型的轨道,有两个值,audio和video,分别指音频轨道和视频轨道
  • enabled,如果允许轨道呈现源流,则为true,否则为false,如果要做一个视频的静音效果就可以将track的kind为audioenabled设置为false

4.2 常用方法

  • stop(),停止追踪媒体轨道,在webRTC连接中,关闭了点对点连接后其实关闭各个rtc实例下的媒体轨道追踪和捕获流的媒体轨道追踪是很重要的一步