React Hooks 通过js获取电脑麦克风、扬声器等设备列表,检测设备改变执行回调

 

可以获取到当前麦克风权限,系统和外部连接的麦克风、扬声器设备对象,检测麦克风设备改变

import React, { useEffect, useMemo, useState } from "react";
type Props = {
  onUpdated?: (devices: MediaDeviceInfo[]) => void;
};
enum PermissionState {
  GRANTED = "granted",
  DENIED = "denied",
  PROMPT = "prompt",
}
interface DevicesListData {
  devices: MediaDeviceInfo[]; //所有设备信息
  currentAudioInputDevice: MediaDeviceInfo; //当前默认麦克风
  currentAudioOutputDevice: MediaDeviceInfo; //当前默认扬声器
  videoInputs: MediaDeviceInfo[]; //摄像头设备
  userAudioInputs: MediaDeviceInfo[]; //系统和外部连接的麦克风设备
  userAudioOutputs: MediaDeviceInfo[]; //系统和外部连接的扬声器设备
  isSupported: boolean; //是否支持
  microphonePermission: PermissionState; //麦克风权限 granted ,denied,error
}
/**
 *
 * @description 获取设备列表,包括摄像头,麦克风,扬声器;并且可以获取当前默认设备信息
 * @param props {onUpdated} 当设备列表更新时触发
 * @returns DevicesListData
 * @example
 * const {
 *  userAudioInputs,
 * userAudioOutputs,
 * currentAudioInputDevice,
 * currentAudioOutputDevice,
 * } = useDevicesList({});
 */
export function useDevicesList(props: Props): DevicesListData {
  const navigator = window.navigator;
  const [devices, setDevices] = useState<MediaDeviceInfo[]>([]);
  const [microphonePermission, setMicrophonePermission] = useState(
    PermissionState.DENIED
  );
  const videoInputs = useMemo(
    () => devices.filter((i) => i.kind === "videoinput"),
    [devices]
  );
  const audioInputs = useMemo(
    () => devices.filter((i) => i.kind === "audioinput"),
    [devices]
  );
  const audioOutputs = useMemo(
    () => devices.filter((i) => i.kind === "audiooutput"),
    [devices]
  );
  const userAudioInputs = useMemo(
    () =>
      audioInputs.filter(
        (i) => i.deviceId !== "default" && i.deviceId !== "communications"
      ),
    [audioInputs]
  );
  const userAudioOutputs = useMemo(
    () =>
      audioOutputs.filter(
        (i) => i.deviceId !== "default" && i.deviceId !== "communications"
      ),
    [audioOutputs]
  );
  const currentAudioInputDevice = useMemo(
    () => audioInputs.find((i) => i.deviceId === "default"),
    [audioInputs]
  ) as MediaDeviceInfo;
  const currentAudioOutputDevice = useMemo(
    () => audioOutputs.find((i) => i.deviceId === "default"),
    [audioOutputs]
  ) as MediaDeviceInfo;
  const isSupported = useMemo(
    () =>
      Boolean(
        navigator &&
          navigator.mediaDevices &&
          navigator.mediaDevices.enumerateDevices
      ),
    [navigator]
  );
  async function update() {
    if (!isSupported) return;
    const _devices = await navigator!.mediaDevices.enumerateDevices();
    setDevices(_devices);
    props.onUpdated && props.onUpdated(_devices);
  }
  // 权限检测
  async function checkMicrophonePermission() {
    try {
      const stream = await navigator.mediaDevices.getUserMedia({
        audio: true,
      });
      // 如果获取媒体流成功,表示用户已经授予麦克风权限
      setMicrophonePermission(PermissionState.GRANTED);

      // 关闭获取媒体流的轨道
      const audioTracks = stream.getAudioTracks();
      audioTracks.forEach((track) => track.stop());
    } catch (error: any) {
      // 如果获取媒体流失败,可能是因为用户拒绝了权限请求
      if (
        error.name === "NotAllowedError" ||
        error.name === "PermissionDeniedError"
      ) {
        setMicrophonePermission(PermissionState.DENIED);
      } else {
        setMicrophonePermission(PermissionState.PROMPT);
      }
    }
  }
  useEffect(() => {
    isSupported && update();
    navigator!.mediaDevices.addEventListener("devicechange", update);
    return () => {
      navigator!.mediaDevices.removeEventListener("devicechange", update);
    };
  }, [navigator]);
  useEffect(() => {
    checkMicrophonePermission();
  }, [navigator, devices]);

  return {
    devices,
    videoInputs,
    isSupported,
    microphonePermission,
    userAudioInputs,
    userAudioOutputs,
    currentAudioInputDevice,
    currentAudioOutputDevice,
  };
}

猜你喜欢

转载自blog.csdn.net/SAXX2/article/details/134737569