探索Media Streams API: 深入了解Web上的实时音频和视频处理

大家好。你们经常在网站上使用摄像头或麦克风吗?或者,作为用户,你们自己也使用过?今天我们就来谈谈如何使用它以及它可能带来的问题。

在谈到网站使用用户设备时,我们需要考虑以下因素:

  • 它应能在大多数浏览器上运行
  • 必须能在手机上运行
  • 必须对用户友好

要使用用户设备,就必须使用媒体捕捉和流 API(媒体流),即 MediaDevices。我们将创建一个类来使用该 API,并在其中添加我们需要的逻辑。

export class MediaDevices {
    private readonly mediaDevices: MediaDevices = navigator.mediaDevices;
    
    // Requests a list of the currently available media input and output devices, such as microphones, cameras, headsets, and so forth
    public getUserDevices(): Promise<MediaDeviceInfo[]> {
      return this.mediaDevices.enumerateDevices();
    }
    
    // Prompts the user for permission to use a media input which produces a MediaStream with tracks containing the requested types of media.
    public getUserMedia(constraints?: MediaStreamConstraints): Promise<MediaStream> {
      return this.mediaDevices.getUserMedia(constraints)
    }
  }

此时此刻,我们可以说,只要把这些方法结合起来,就可以享受生活了,但遗憾的是,事情并没有那么简单。

为什么需要这么多浏览器?

并非所有浏览器都有相同的接收 MediaStream 的方法。举例来说,可以使用以下几种(最常用的几种):

  • 基于 Chromium 的 Safari – getUserMedia
  • Firefox 浏览器 – mozGetUserMedia
  • 旧版 Chrome 浏览器 – webkitGetUserMedia
  • *让我们忘掉 IE 吧。
探索Media Streams API: 深入了解Web上的实时音频和视频处理

这看起来使用起来不是很方便,让我们更新一下 getUserMedia 方法。

public getUserMedia(constraints?: MediaStreamConstraints): Promise<MediaStream> {
 return (
  this.mediaDevices.getUserMedia?.(constraints) ||
     this.mediaDevices.webkitGetUserMedia?.(constraints) ||
       this.mediaDevices.mozGetUserMedia?.(constraints)
    )
}

如果你像我一样使用 TypeScript,可以创建一个 global.d.ts 文件并添加以下内容,以避免出现方法缺失的问题。

type GetUserMediaMethod = (...args: Parameters<MediaDevices['getUserMedia']>) => ReturnType<MediaDevices['getUserMedia']>;

// Update Global MediaDevices interfact
interface MediaDevices {
  // Old chrome browsers
  webkitGetUserMedia?: GetUserMediaMethod;
  // Firefox
  mozGetUserMedia?: GetUserMediaMethod;
}

你还可以编写 getUserMedia 多填充代码,以支持最老版本的浏览器。

if (navigator.mediaDevices === undefined) {
  navigator.mediaDevices = {};
}

if (navigator.mediaDevices.getUserMedia === undefined) {
  navigator.mediaDevices.getUserMedia = function (constraints) {
      const getUserMedia =
        navigator.webkitGetUserMedia ||
        navigator.mozGetUserMedia ||
        navigator.getUserMedia;

      if (!getUserMedia) {
        return Promise.reject(
          new Error("getUserMedia is not implemented in this browser")
        );
      }

      return new Promise(function (resolve, reject) {
        getUserMedia.call(navigator, constraints, resolve, reject);
      });
    };
}

这可以在类中或其他地方描述。最重要的是,应在调用 MediaDevices 类的 getUserMedia 方法之前调用该方法。

那么手机呢?

使用手机时,原理是一样的。不过,我在手机上遇到了麻烦。

在某些设备上,getUserMedia 方法可能会被拒绝,并出现 “无法启动视频源 “的错误。

探索Media Streams API: 深入了解Web上的实时音频和视频处理

这是我给你的建议:在获取新的 MediaStream 之前,请始终停止前一个 MediaStream。

mediaStream.getTracks().forEach((track) => track.stop()); or

mediaStream.getAudioTracks().forEach((track) => track.stop()); or

mediaStream.getVideoTracks().forEach((track) => track.stop());

class MediaDevices {
 //...

    private currentMediaStream: MediaStream;
 
    //...

    public stopCurrentMediaStream(): void {
        this.currentMediaStream?.getTracks().forEach((track) => track.stop());
    }
}

在我的情况下,只有在前一个数据流停止后才能更换摄像头。如果您的摄像机已在另一个标签页中使用,也会出现这个问题。遗憾的是,这只能通过在另一个选项卡中禁用摄像机来解决。

使用音频输出

当我们使用麦克风工作时,有时可能希望能听到自己的声音。或者,假设我们有一个听音乐的网站,我们希望将声音输出到扬声器。Web API 为我们提供了以下 setSinkId 函数。该函数适用于 HTMLMediaElement(HTMLVideoElement、HTMLAudioElement)和 AudioContext。不过,我们在使用时要小心,因为虽然这个函数很有用,但它并不适用于所有浏览器。

就我而言,我使用了 AudioContext 来播放来自设备的音频,这取决于用户的选择。我们需要检查浏览器中是否有此功能。我们还需要检查我们使用的是什么 ID。如果在 Chrome 浏览器中没有过滤默认设备,则需要插入一个空字符串,因为 setSinkId 不会理解默认设备 ID 是什么。

function setAudioOutput(audioContext: AudioContext, sinkId: string = ''): void {
  const deviceSinkId = sinkId === 'default' ? '' : sinkId;
  if ('setSinkId' in audioContext) {
    audioContext.setSinkId(id);
  }
}

如果浏览器中的 AudioContext 可用该函数,则条件将返回 true。SinkId 是 Chrome 浏览器的一种变通方法。因为它已选择了默认设备,其 id 将是默认的,所以 setSinkId 方法无法理解这样的 id。

结论

目前,在浏览器中处理用户设备并不困难。但是,当我们开始扩大使用设备的范围时,就会有很多陷阱。不过,我们了解得越多,分享的信息越多,大家就会越轻松!

作者:Vladislav Stepanov

本文来自作者投稿,版权归原作者所有。如需转载,请注明出处:https://www.nxrte.com/jishu/webrtc/35336.html

(0)

相关推荐

发表回复

登录后才能评论