gpt4 book ai didi

webrtc - 远程视频在 WebRTC 中黑屏或空白

转载 作者:行者123 更新时间:2023-12-02 00:47:25 38 4
gpt4 key购买 nike

我在 java 和 websocket 中有信令服务器。它适用于本地视频。但远程视频是黑屏或空白但它并不总是一片空白。如果您关闭服务器并再次打开它,远程视频将显示在您的 Remote 上。为什么有时出不来,有时出不来?

这是我的代码...

 navigator.getUserMedia = navigator.getUserMedia || navigator.mozGetUserMedia || navigator.webkitGetUserMedia;
window.RTCPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection;
window.RTCIceCandidate = window.RTCIceCandidate || window.mozRTCIceCandidate || window.webkitRTCIceCandidate;
window.RTCSessionDescription = window.RTCSessionDescription || window.mozRTCSessionDescription || window.webkitRTCSessionDescription;
window.SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition || window.mozSpeechRecognition
|| window.msSpeechRecognition || window.oSpeechRecognition;

var localVideoStream = null;
var peerConn = null,
wsc = new WebSocket("ws://localhost:8080/signaling"),
peerConnCfg = {
'iceServers': [{
'url': 'stun:stun.l.google.com:19302'
}]
};


var videoCallButton = document.getElementById("caller");
var endCallButton = document.getElementById("callee");
var localVideo = document.getElementById('localVideo');
var remoteVideo = document.getElementById('remoteVideo');
videoCallButton.addEventListener("click", initiateCall);

endCallButton.addEventListener("click", function (evt) {
wsc.send(JSON.stringify({"closeConnection": true }));
});
var sdpConstraints = {
'mandatory': {
'OfferToReceiveAudio': true,
'OfferToReceiveVideo': true
}
};
function prepareCall() {
peerConn = new RTCPeerConnection(peerConnCfg);
// send any ice candidates to the other peer
peerConn.onicecandidate = onIceCandidateHandler;
// once remote stream arrives, show it in the remote video element
peerConn.onaddstream = onAddStreamHandler;
};

// run start(true) to initiate a call
function initiateCall() {
prepareCall();
// get the local stream, show it in the local video element and send it
navigator.getUserMedia({ "audio": true, "video": true }, function (stream) {
localVideoStream = stream;
localVideo.src = URL.createObjectURL(localVideoStream);
peerConn.addStream(localVideoStream);
createAndSendOffer();

}, function(error) { console.log(error);});
};

function answerCall() {
prepareCall();
// get the local stream, show it in the local video element and send it
navigator.getUserMedia({ "audio": true, "video": true }, function (stream) {
localVideoStream = stream;
localVideo.src = URL.createObjectURL(localVideoStream);
peerConn.addStream(localVideoStream);
createAndSendAnswer();

}, function(error) { console.log(error);});
};

wsc.onmessage = function (evt) {
var signal = null;
if (!peerConn) answerCall();
signal = JSON.parse(evt.data);

if (signal.sdp) {
console.log("Received SDP from remote peer.");
console.log("signal"+ signal);
peerConn.setRemoteDescription(new RTCSessionDescription(signal.sdp));
}
else if (signal.candidate) {
console.log("signal"+ signal.candidate);
console.log("Received ICECandidate from remote peer.");
peerConn.addIceCandidate(new RTCIceCandidate(signal.candidate));
} else if ( signal.closeConnection){
console.log("Received 'close call' signal from remote peer.");
endCall();
}else{
console.log("signal"+ signal.candidate);
}
};

function createAndSendOffer() {
peerConn.createOffer(
function (offer) {
var off = new RTCSessionDescription(offer);
peerConn.setLocalDescription(new RTCSessionDescription(off),
function() {
wsc.send(JSON.stringify({"sdp": off }));
},
function(error) { console.log(error);}
);
},
function (error) { console.log(error);}
);
};

function createAndSendAnswer() {
peerConn.createAnswer(
function (answer) {
var ans = new RTCSessionDescription(answer);
peerConn.setLocalDescription(ans, function() {
wsc.send(JSON.stringify({"sdp": ans }));
},
function (error) { console.log(error);}
);
},
function (error) {console.log(error);}
);
};

function onIceCandidateHandler(evt) {
if (!evt || !evt.candidate) return;
wsc.send(JSON.stringify({"candidate": evt.candidate }));
};

function onAddStreamHandler(evt) {
videoCallButton.setAttribute("disabled", true);
endCallButton.removeAttribute("disabled");
// set remote video stream as source for remote video HTML5 element

remoteVideo.src = window.URL.createObjectURL(evt.stream);
remoteVideo.play();
console.log("remote src : "+ remoteVideo.src);
};

function endCall() {
peerConn.close();
peerConn = null;
videoCallButton.removeAttribute("disabled");
endCallButton.setAttribute("disabled", true);
if (localVideoStream) {
localVideoStream.getTracks().forEach(function (track) {
track.stop();
});
localVideo.src = "";
}
if (remoteVideo){
remoteVideo.src = "";
window.URL.revokeObjectURL(remoteVideo);
}
};

最佳答案

WebRTC 空白/空视频的原因之一是丢包率高。在这种情况下,在服务器和客户端日志中,它将显示为连接成功且视频正常播放,因此您不会看到任何警告或错误。

要检查是否存在高丢包,您可以在 firefox 上访问 about:webrtc,或在 chrome 上访问 chrome://webrtc-internals。对于 Firefox,您可以导航到“RTP Stats”。您会看到它显示 Received: ... packetsLost: ... packets。您可以使用这些计数来计算丢包率。对于 chrome,有一个丢包率图表。您可能会有非常高的丢包率,例如 70%。

如果丢包率极高,原因之一是 MTU 较小 https://en.wikipedia.org/wiki/Maximum_transmission_unit在客户端网络接口(interface)上比服务器使用的 MTU。例如,您的客户端网络接口(interface)在未连接到 VPN 时可以具有 MTU=1500 字节,而在连接到 VPN 时 MTU=1250 字节。如果服务器发送 MTU=1400 的 RTP 数据包(通过 UDP),如果客户端未使用 VPN,则客户端可以接收到该数据包,但大于 1250 字节的数据包将被客户端网络接口(interface)丢弃。

如果你想在本地检查客户端MTU,你可以在mac或linux上运行ifconfig

Mac 示例,没有示例 vpn:

en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
...
inet SOME_IP netmask 0xffffff00 broadcast 192.168.1.255
media: autoselect
status: active

Mac 示例,以 vpn 为例:

utun2: flags=80d1<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST> mtu 1250
inet SOME_IP --> SOME_IP netmask 0xffffffff
nd6 options=201<PERFORMNUD,DAD>

如何为服务器配置MTU:

如果您将 GStreamer 用于 WebRTC 服务器,则负载生成器元素(例如 rtpvp8pay)具有设置所需 MTU 值的属性。通过使用 gst-inspect-1.0 rtpvp8pay,您可以看到它默认使用 1400 作为 MTU,这可能比您的客户端网络接口(interface)可以处理的更大(例如,上例中的 1250)。您可以通过在 GStreamer 管道上设置较低的 MTU 来使其工作,这样您的客户端网络接口(interface)就不会再丢弃大部分包(只需更改服务器上 GStreamer 管道上的 MTU,包丢失率就可以降低到 0.01%)。

在这种情况下,当 VPN 刚重新连接时,传入视频可以工作约 10 秒,然后传入视频可能会卡住,随后的页面刷新可能会导致只有空白视频,且数据包丢失超过 70%。

这是一个非常具体的场景,但当它发生时,它是一个完全无声/隐藏的错误,因此希望这对某人有所帮助。

关于webrtc - 远程视频在 WebRTC 中黑屏或空白,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42720530/

38 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com