问题描述
我使用 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()
});
这样,预览的轨道将重新用于视频通话,并且不会变暗。