Twilio + React:如何在通话期间更改音频或视频输入设备?

问题描述

我一直在查看文档,但我无法弄清楚。当用户选择不同的设备时,其他用户将无法再听到那个人的声音。这一定意味着取消发布曲目的事情进展顺利,对吗?我不确定。

这是我的用户更换设备的代码

const setDevice = (device) => {
    if(!room) return
    let deviceid = device.deviceid
    const localParticipant = room.localParticipant

    if(device.kind === 'audioinput'){
        setSelectedAudioDevice(device.label)

        Video.createLocalAudioTrack({
            deviceid: {exact: deviceid}
        }).then((localAudioTrack) => {
            const tracks = localParticipant.audioTracks

            tracks.forEach((track) => {
                localParticipant.unpublishTrack(track.track)
            })

            localParticipant.publishTrack(localAudioTrack)
        })
    } else if(device.kind === 'videoinput'){
        setSelectedVideoDevice(device.label)

        Video.createLocalVideoTrack({
            deviceid: {exact: deviceid}
        }).then((localVideoTrack) => {
            const tracks = localParticipant.videoTracks

            tracks.forEach((track) => {
                localParticipant.unpublishTrack(track.track)
            })

            localParticipant.publishTrack(localVideoTrack)
        })
    }
}

每个参与者都有自己的组件,他们在其中订阅曲目。但是,此代码来自 Twilio 示例之一,因此我不完全确定它是如何工作的。

const trackpubsToTracks = (trackMap) =>
    Array.from(trackMap.values())
      .map((publication) => publication.track)
      .filter((track) => track !== null);

useEffect(() => {
    setVideoTracks(trackpubsToTracks(participant.videoTracks));
    setAudioTracks(trackpubsToTracks(participant.audioTracks));

    const trackSubscribed = (track) => {
      if (track.kind === "video") {
        setVideoTracks((videoTracks) => [...videoTracks,track]);
      } else if (track.kind === "audio") {
        setAudioTracks((audioTracks) => [...audioTracks,track]);
      }
    };

    const trackUnsubscribed = (track) => {
      if (track.kind === "video") {
        setVideoTracks((videoTracks) => videoTracks.filter((v) => v !== track));
      } else if (track.kind === "audio") {
        setAudioTracks((audioTracks) => audioTracks.filter((a) => a !== track));
      }
    };

    participant.on("trackSubscribed",trackSubscribed);
    participant.on("trackUnsubscribed",trackUnsubscribed);

    return () => {
      setVideoTracks([]);
      setAudioTracks([]);
      participant.removeAllListeners();
    };
  },[participant]);

  useEffect(() => {
    const videoTrack = videoTracks[0];
    if (videoTrack) {
      videoTrack.attach(videoRef.current);

      return () => {
        videoTrack.detach();
      };
    }
  },[videoTracks]);

  useEffect(() => {
    const audioTrack = audioTracks[0];
    if (audioTrack) {
      audioTrack.attach(audioRef.current);

      return () => {
    audioTrack.detach();
      };
    }
  },[audioTracks]);

如果有人知道我如何在通话中处理设备切换,我将不胜感激。

解决方法

这里是 Twilio 开发者布道者。

我发现这里的最佳操作顺序是:

  1. 从房间取消发布本地参与者的现有曲目,这将在房间中为任何其他参与者触发 trackRemoved 事件
  2. 从页面分离现有轨道
  3. 完全停止轨道
  4. 使用 createLocal(Video|Audio)Track 请求新曲目
  5. 将新曲目附加到页面
  6. 将新曲目发布到房间,为其他参与者触发房间上的 trackAdded 事件

对于不允许您一次访问多个摄像头的 iOS 设备尤其如此。

以下是我之前使用过的一些代码,但未在 React 应用程序中使用:

function stopTracks(tracks) {
  tracks.forEach(function(track) {
    if (track) { track.stop(); }
  })
}

function updateVideoDevice(event) {
  const select = event.target;
  const localParticipant = activeRoom.localParticipant;
  if (select.value !== '') {
    const tracks = Array.from(localParticipant.videoTracks.values()).map(
      function(trackPublication) {
        return trackPublication.track;
      }
    );
    localParticipant.unpublishTracks(tracks);
    detachTracks(tracks);
    stopTracks(tracks);
    Video.createLocalVideoTrack({
      deviceId: { exact: select.value }
    }).then(function(localVideoTrack) {
      localParticipant.publishTrack(localVideoTrack);
      log(localParticipant.identity + ' added track: ' + localVideoTrack.kind);
      const previewContainer = document.getElementById('local-media');
      attachTracks([localVideoTrack],previewContainer);
    });
  }
}

您可以在 this repo on GitHubI wrote about it here 中查看整个应用程序。

我认为您所指的 React 示例也是我的示例之一。我实际上尝试将相机更改添加到分支上的该存储库。显然是一年前,但you can see the updates here。希望这也能为您指明正确的方向。