WebRTC video/audio 呼叫在不同网络上有 90% 的时间失败,但在同一网络上有 90% 的时间成功
WebRTC video/audio calling failed 90% of time on different network but got success 90% on same network
我已经使用 webRTC 和 Django 创建了视频聊天应用程序 channel.My 应用程序在同一网络中使用时 90% 的时间都可以正常工作,但在不同的网络中使用时会失败 network.I 我无法在不同的网络上使用时看到远程人员的视频。
我使用 chrome://webrtc-internals/ 来跟踪我的 webRTC 响应,我得到了 iceconnectionstate:使用不同网络调用时失败
下图是我在同一个网络成功时的截图
并且在成功之后它还在同一网络上给出了 addIceCandidateFailed 错误,但是视频通话工作正常并且这个错误只出现在 chrome 而不是在 firefox 中。 下面是屏幕截图
下面是我的 STUN/TUNE 服务器配置,它是 free.I 从 Whosebug 链接之一获得的。
var peerConnectionConfig = {
iceServers: [{
urls: ["turn:173.194.72.127:19305?transport=udp",
"turn:[2404:6800:4008:C01::7F]:19305?transport=udp",
"turn:173.194.72.127:443?transport=tcp",
"turn:[2404:6800:4008:C01::7F]:443?transport=tcp"
],
username: "CKjCuLwFEgahxNRjuTAYzc/s6OMT",
credential: "u1SQDR/SQsPQIxXNWQT7czc/G4c="
},
{
urls: ["stun:stun.l.google.com:19302"]
}
]
};
下面是我的 webRTC javascript 代码
$(function() {
var initiator,pc;
var isSender = false;
var peerConnectionConfig = {
iceServers: [{
urls: ["turn:173.194.XX.127:19305?transport=udp",
"turn:[2404:XXXX:XXXX:C01::7F]:19305?transport=udp",
"turn:173.194.XX.127:443?transport=tcp",
"turn:[2404:XXXX:XXXX:C01::7F]:443?transport=tcp"
],
username: "XXXXXXXXXX",
credential: "YYYYYYYYYYY"
},
{
urls: ["stun:stun.l.google.com:19302"]
}
]
};
$.ajax({
type: "GET",
url: '/isRoomExist/?roomName=121' ,
beforeSend: function() {},
success: function(data) {
data = JSON.parse(data);
initiatorCtrl(data[0].flgInitiator);
}
});
var ws_scheme = window.location.protocol == "https:" ? "wss" : "ws";
var chatsock = new ReconnectingWebSocket(ws_scheme + '://' + window.location.host + "/chat" + window.location.pathname);
function initiatorCtrl(event) {
if (event == "fullhouse") {
alert("full house");
}
if (event == "initiator") {
initiator = false;
init();
}
if (event == "not initiator") {
initiator = true;
init();
}
}
function init() {
var constraints = {
audio: true,
video: true
};
getUserMedia(constraints, connect, fail);
}
function connect(stream) {
pc = new RTCPeerConnection(peerConnectionConfig);
if (stream) {
pc.addStream(stream);
$('#local').attachStream(stream);
}
pc.onaddstream = function(event) {
$('#remote').attachStream(event.stream);
logStreaming(true);
};
pc.onicecandidate = function(event) {
if (event.candidate) {
chatsock.send(JSON.stringify(event.candidate));
isSender = true;
}
};
if (initiator) {
createOffer();
} else {
log('waiting for offer...');
}
logStreaming(false);
chatsock.onmessage = function(event) {
var signal1 = JSON.parse(event.data);
var signal = JSON.parse(signal1);
if (isSender) {
isSender = false
} else {
if (signal.sdp) {
if (initiator) {
receiveAnswer(signal);
} else {
receiveOffer(signal);
}
} else if (signal.candidate) {
pc.addIceCandidate(new RTCIceCandidate(signal));
}
}
};
}
function createOffer() {
pc.createOffer(function(offer) {
pc.setLocalDescription(offer, function() {
chatsock.send(JSON.stringify(offer));
isSender = true;
}, fail);
}, fail);
}
function receiveOffer(offer) {
pc.setRemoteDescription(new RTCSessionDescription(offer), function() {
pc.createAnswer(function(answer) {
pc.setLocalDescription(answer, function() {
chatsock.send(JSON.stringify(answer));
isSender = true;
}, fail);
}, fail);
}, fail);
}
function receiveAnswer(answer) {
pc.setRemoteDescription(new RTCSessionDescription(answer));
}
function log() {
console.log(Array.prototype.join.call(arguments, ' '))
console.log.apply(console, arguments);
}
function logStreaming(streaming) {
$('#streaming').text(streaming ? '[streaming]' : '[..]');
}
function fail() {
console.error.apply(console, arguments);
}
jQuery.fn.attachStream = function(stream) {
this.each(function() {
this.src = URL.createObjectURL(stream);
this.play();
});
};
});
As per your webrtc-internals, you are adding the remote candidates before setting the remote description.
将候选人放入队列中,直到您收到远程描述。
设置远程描述后,
您可以将本地候选人从队列或从 onicecandidate
发送到远程用户
并将远程候选人添加到您的电脑。
更新:
消息的顺序一般和POST顺序不一样
来自另一个客户端,因为 POSTs 是异步的,服务器可能会处理
候选人比offer/answer(需要处理routing/cdr/forking)更快(只是中继和更小的尺寸)。
正在排队远程候选人:我们需要在添加候选人之前处理远程录取。
排队本地候选人: 如果 call/offer 被分叉到多个目的地(用户登录手机和浏览器或群组呼叫),那么只有第一个答案将被发起者接受。因此所有接收端点都需要对本地候选人进行排队,直到他们的答案得到确认。
按照 Ajay 的建议检查消息顺序确实很有帮助。
要添加一件事:指向使订单检查更容易的图表的链接:
SDP packet exchange diagram
和
ICE candidate exchange diagram
还有一篇解释图表的优秀文章:
article on mdn.mozillademos.org
我已经使用 webRTC 和 Django 创建了视频聊天应用程序 channel.My 应用程序在同一网络中使用时 90% 的时间都可以正常工作,但在不同的网络中使用时会失败 network.I 我无法在不同的网络上使用时看到远程人员的视频。
我使用 chrome://webrtc-internals/ 来跟踪我的 webRTC 响应,我得到了 iceconnectionstate:使用不同网络调用时失败
下图是我在同一个网络成功时的截图
并且在成功之后它还在同一网络上给出了 addIceCandidateFailed 错误,但是视频通话工作正常并且这个错误只出现在 chrome 而不是在 firefox 中。 下面是屏幕截图
下面是我的 STUN/TUNE 服务器配置,它是 free.I 从 Whosebug 链接之一获得的。
var peerConnectionConfig = {
iceServers: [{
urls: ["turn:173.194.72.127:19305?transport=udp",
"turn:[2404:6800:4008:C01::7F]:19305?transport=udp",
"turn:173.194.72.127:443?transport=tcp",
"turn:[2404:6800:4008:C01::7F]:443?transport=tcp"
],
username: "CKjCuLwFEgahxNRjuTAYzc/s6OMT",
credential: "u1SQDR/SQsPQIxXNWQT7czc/G4c="
},
{
urls: ["stun:stun.l.google.com:19302"]
}
]
};
下面是我的 webRTC javascript 代码
$(function() {
var initiator,pc;
var isSender = false;
var peerConnectionConfig = {
iceServers: [{
urls: ["turn:173.194.XX.127:19305?transport=udp",
"turn:[2404:XXXX:XXXX:C01::7F]:19305?transport=udp",
"turn:173.194.XX.127:443?transport=tcp",
"turn:[2404:XXXX:XXXX:C01::7F]:443?transport=tcp"
],
username: "XXXXXXXXXX",
credential: "YYYYYYYYYYY"
},
{
urls: ["stun:stun.l.google.com:19302"]
}
]
};
$.ajax({
type: "GET",
url: '/isRoomExist/?roomName=121' ,
beforeSend: function() {},
success: function(data) {
data = JSON.parse(data);
initiatorCtrl(data[0].flgInitiator);
}
});
var ws_scheme = window.location.protocol == "https:" ? "wss" : "ws";
var chatsock = new ReconnectingWebSocket(ws_scheme + '://' + window.location.host + "/chat" + window.location.pathname);
function initiatorCtrl(event) {
if (event == "fullhouse") {
alert("full house");
}
if (event == "initiator") {
initiator = false;
init();
}
if (event == "not initiator") {
initiator = true;
init();
}
}
function init() {
var constraints = {
audio: true,
video: true
};
getUserMedia(constraints, connect, fail);
}
function connect(stream) {
pc = new RTCPeerConnection(peerConnectionConfig);
if (stream) {
pc.addStream(stream);
$('#local').attachStream(stream);
}
pc.onaddstream = function(event) {
$('#remote').attachStream(event.stream);
logStreaming(true);
};
pc.onicecandidate = function(event) {
if (event.candidate) {
chatsock.send(JSON.stringify(event.candidate));
isSender = true;
}
};
if (initiator) {
createOffer();
} else {
log('waiting for offer...');
}
logStreaming(false);
chatsock.onmessage = function(event) {
var signal1 = JSON.parse(event.data);
var signal = JSON.parse(signal1);
if (isSender) {
isSender = false
} else {
if (signal.sdp) {
if (initiator) {
receiveAnswer(signal);
} else {
receiveOffer(signal);
}
} else if (signal.candidate) {
pc.addIceCandidate(new RTCIceCandidate(signal));
}
}
};
}
function createOffer() {
pc.createOffer(function(offer) {
pc.setLocalDescription(offer, function() {
chatsock.send(JSON.stringify(offer));
isSender = true;
}, fail);
}, fail);
}
function receiveOffer(offer) {
pc.setRemoteDescription(new RTCSessionDescription(offer), function() {
pc.createAnswer(function(answer) {
pc.setLocalDescription(answer, function() {
chatsock.send(JSON.stringify(answer));
isSender = true;
}, fail);
}, fail);
}, fail);
}
function receiveAnswer(answer) {
pc.setRemoteDescription(new RTCSessionDescription(answer));
}
function log() {
console.log(Array.prototype.join.call(arguments, ' '))
console.log.apply(console, arguments);
}
function logStreaming(streaming) {
$('#streaming').text(streaming ? '[streaming]' : '[..]');
}
function fail() {
console.error.apply(console, arguments);
}
jQuery.fn.attachStream = function(stream) {
this.each(function() {
this.src = URL.createObjectURL(stream);
this.play();
});
};
});
As per your webrtc-internals, you are adding the remote candidates before setting the remote description.
将候选人放入队列中,直到您收到远程描述。
设置远程描述后,
您可以将本地候选人从队列或从 onicecandidate
发送到远程用户
并将远程候选人添加到您的电脑。
更新:
消息的顺序一般和POST顺序不一样
来自另一个客户端,因为 POSTs 是异步的,服务器可能会处理
候选人比offer/answer(需要处理routing/cdr/forking)更快(只是中继和更小的尺寸)。
正在排队远程候选人:我们需要在添加候选人之前处理远程录取。
排队本地候选人: 如果 call/offer 被分叉到多个目的地(用户登录手机和浏览器或群组呼叫),那么只有第一个答案将被发起者接受。因此所有接收端点都需要对本地候选人进行排队,直到他们的答案得到确认。
按照 Ajay 的建议检查消息顺序确实很有帮助。
要添加一件事:指向使订单检查更容易的图表的链接: SDP packet exchange diagram 和 ICE candidate exchange diagram
还有一篇解释图表的优秀文章: article on mdn.mozillademos.org