微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

iOS Safari 上的 Twilio 视频通话问题,通话后开始视频冻结 nodejs 问题

如何解决iOS Safari 上的 Twilio 视频通话问题,通话后开始视频冻结 nodejs 问题

我使用 Nodejs 和 Twilio CLI 创建了一个视频通话应用程序。并在我的 Android 和 iOS 移动应用程序中使用它。在 Android 上运行良好。但是在 iOS 上,存在一个问题,当用户到达视频通话页面时,它显示预览,但是当用户单击“加入房间”按钮时,他/她的视频停止并只显示黑屏。虽然他可以与其他用户交谈并可以看到他们的视频。而第二个用户也可以完美地看到他/她的视频。只有他/她在那个通话中看不到他/她的视频的问题。

我的HTML代码

<!DOCTYPE html>
<html>
<head>
<style>
    .joinbtn {
        border: none;
        padding: 10px 10px;
        text-align: center;
        text-decoration: none;
        display: inline-block;
        font-size: 14px;
        margin: 4px 2px;
        cursor: pointer;
        background-color: #2b96cc;
        color: #fff;
    }
    .stvbtn {
        border: none;
        padding: 10px 10px;
        text-align: center;
        text-decoration: none;
        display: inline-block;
        font-size: 14px;
        margin: 4px 2px;
        cursor: pointer;
        background-color: #2b96cc;
        color: #fff;
    }
    .endbtn {
        float:right;
        border: none;
        padding: 10px 10px;
        text-align: center;
        text-decoration: none;
        display: inline-block;
        font-size: 14px;
        margin: 4px 2px;
        cursor: pointer;
        background-color: #dc3545;
        color: #fff;
    }
    @media screen and (max-width: 820px) {
        video {
            object-fit: cover;
            width: 100%;
            height: 47vh;
        }
    }
    @media screen and (min-width: 821px){
        video {
            object-fit: contain;
        }
    }
    .connect_btn{
        display: flex;
        justify-content: center;
        align-content: space-around;
        margin-top: -50px;
        opacity: 0.8;
        padding-bottom:8px;
    }
    button.endbtn:disabled,button.joinbtn:disabled {
       background-color: #607d8b;
        color: #ffffff;
    }
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/webrtc-adapter/6.4.0/adapter.js" type="text/javascript"></script>
<script src="webrtc.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<Meta charset="utf-8"/>
<Meta http-equiv="X-UA-Compatible"/>
<Meta name="viewport" content="width=device-width,initial-scale=1"/>
<title>Clifix Video Chat</title>
</head>
<body>
    <div id="room-controls">
        <video id="video" autoplay muted playsinline loop width="100%"></video>
        <div class="connect_btn">
            <label for="passcode"></label>
            <input id="passcode" type="hidden" value="8514"/>
            <!--button class="stvbtn" id="start-video" onclick="viplay()">On/Off</button-->
            <button class="joinbtn" id="button-join">Join Room</button>
            <button class="endbtn" id="button-leave" disabled="disabled">End Call</button>
        </div>
    </div>
    <!-- EDIT_CODE -->
    <script src="//media.twiliocdn.com/sdk/js/video/releases/2.3.0/twilio-video.min.js"></script>
    <script src="index.js"></script>
</body>
</html>

我的 nodejs 代码

'use strict';
(() => {
  //const ROOM_NAME = 'demo';
  var urltemp = location.search;
  var array = urltemp.split('?');
  var array1 = array[1];
  var array2 = array1.split('=');
  var id = array2[1];
  const ROOM_NAME = id;
  const Video = Twilio.Video;
  let videoRoom,localStream;
  const video = document.getElementById('video');
    
  // preview screen
  navigator.mediaDevices
    .getUserMedia({ video: true,audio: true })
    .then((vid) => {
      video.srcObject = vid;
      localStream = vid;
    });

  // buttons
  const joinRoomButton = document.getElementById('button-join');
  const leaveRoomButton = document.getElementById('button-leave');
  joinRoomButton.onclick = () => {
    //video.play();
    // get access token
    fetch(`video-token?passcode=${getpasscode()}&room=${ROOM_NAME}`)
      .then((resp) => {
        if (resp.ok) {
            var url=window.location.href,separator = (url.indexOf("?")===-1)?"?":"&",newParam=separator + "join=true";
            var newUrl=url.replace(newParam,"");
            newUrl+=newParam;
            window.history.replaceState(null,null,newUrl);
          return resp.json();
        } else {
          console.error(resp);
          if (resp.status === 401) {
            throw new Error('Go Back & Join Again');
          } else {
            throw new Error('Unexpected error. Open dev tools for logs');
          }
        }
      })
      .then((body) => {
        const token = body.token;
        //console.log(token);
        //connect to room
        return Video.connect(token,{ name: ROOM_NAME });
      })
      .then((room) => {
        //console.log(`Connected to Room ${room.name}`);
        videoRoom = room;

        room.participants.forEach(participantConnected);
        room.on('participantConnected',participantConnected);

        room.on('participantdisconnected',participantdisconnected);
        room.once('disconnected',(error) =>
          room.participants.forEach(participantdisconnected)
        );
        joinRoomButton.disabled = true;
        leaveRoomButton.disabled = false;
      })
      .catch((err) => {
        alert(err.message);
      });
  };
  // leave room
  leaveRoomButton.onclick = () => {
      var url=window.location.href,newParam=separator + "end=true";
            var newUrl=url.replace(newParam,newUrl);
    videoRoom.disconnect();
    //console.log(`disconnected from Room ${videoRoom.name}`);
    joinRoomButton.disabled = false;
    leaveRoomButton.disabled = true;
  };
})();

const getpasscode = () => {
  const passcodeInput = document.getElementById('passcode') || {};
  const passcode = passcodeInput.value;
  passcodeInput.value = '';

  return passcode;
};

// connect participant
const participantConnected = (participant) => {
  //console.log(`Participant ${participant.identity} connected'`);

  const div = document.createElement('div'); //create div for new participant
  div.id = participant.sid;

  participant.on('trackSubscribed',(track) => trackSubscribed(div,track));
  participant.on('trackUnsubscribed',trackUnsubscribed);
  participant.tracks.forEach((publication) => {
    if (publication.isSubscribed) {
      trackSubscribed(div,publication.track);
    }
  });
  document.body.appendChild(div);
};

const participantdisconnected = (participant) => {
  //console.log(`Participant ${participant.identity} disconnected.`);
  document.getElementById(participant.sid).remove();
};

const trackSubscribed = (div,track) => {
  div.appendChild(track.attach());
};

const trackUnsubscribed = (track) => {
  track.detach().forEach((element) => element.remove());
};

据我所知,在此之前,我的视频无法在 iOS Safari 上运行,然后我对 HTML 视频代码进行了修改

从这里:

<video id="video" autoplay muted width="100%"></video>

致:

<video id="video" autoplay muted playsinline loop width="100%"></video>

然后当他/她开始呼叫时,它开始在 iOS 用户端冻结视频。

解决方法

这里是 Twilio 开发者布道者。

当您调用 Video.connect 时,视频 SDK 会请求使用您的麦克风和摄像头的许可。 Safari 不喜欢一次多次访问麦克风和摄像头,并且由于您还要求媒体访问以显示预览,它会删除预览轨道并为视频通话创建新轨道。这就是预览变暗的原因,但其他参与者可以看到和听到视频/音频。

相反,您应该通过存储对它们的引用然后将它们作为 Video.connect 传递给 tracks property in the ConnectOptions 来重用您为预览获得的轨道。您已经存储了对 localStream 的引用,因此您可以在连接时使用它,如下所示:

return Video.connect(token,{
  name: ROOM_NAME,tracks: localStream.getTracks()
});

这样,预览的轨道将重新用于视频通话,并且不会变暗。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。