我正在开发一个使用 webRTC 的视频通话应用程序。我仅在本地网络中使用此应用程序。在测试了几台连接设备后发现连接非常成功。但是,有一些设备不知道为什么无法拨打某些设备的电话。而且它的行为是如此奇怪。 这是我所做的呼叫模拟:
*所有设备连接到同一本地网络/wifi,
** 有问题的设备以粗体显示
这是我从
chrome://webrtc-internals/
获得的屏幕截图
有问题设备的连接状态
状态仍处于新状态,没有改变
从有问题的设备接听电话时被叫方连接状态
连接成功示例
我正在使用谷歌的Stun服务器,我也尝试过不使用iceServers。结果还是一样。我想如果我们只在本地网络中,我们不需要眩晕/转向服务器,对吗?
奇怪的是,有问题的设备无法向其他桌面设备拨打电话,但可以使用移动设备拨打/接听电话。 并且有问题的设备之间也无法连接,因为在我看来问题在于有问题的设备无法拨打电话。
我很困惑的是,是什么原因导致某些设备无法像上述情况那样拨打电话?我相信这不是代码中的错误,因为该调用在其他正常设备上运行完美。我尝试了各种方法,直到此时使用了完美的协商逻辑,结果还是一样。
也许有人经历过类似的事情,可以提供上述情况的解决方案。 非常感谢我
在本地网络中,我们不需要直接眩晕它就会连接。 如果我们尝试从公共到私人以及私人到公共进行呼叫,我们必须集中注意是否存在防火墙限制或收集候选人时的任何可达性问题,或者可能是对称 NAT 问题。
终于找到问题所在了。是的,问题出在防火墙上。看起来 webRTC 使用的 UDP 端口被防火墙阻止了。解决办法是在防火墙上打开一个UDP端口,这样就不用关闭防火墙了。我的情况发生可能是因为我只在一个本地网络上使用 webRTC 并且不需要 STUN/TURN 服务器,因此它需要一个 UDP 端口来连接到对等点。
我也遇到和你一样的问题。能告诉我你是怎么解决的吗?
> this is the offer creation page
(async () => {
// Span Elementinin içerisinden Offer değerini alır.
var offerValue = document.getElementById("offervalue").textContent;
const localVideo = document.getElementById('local');
const StartButton = document.getElementById("start");
// Button clicklendiği zaman Start Metodu çalışıyor.
StartButton.addEventListener('click', async function () {
await Start(offerValue);
});
var connection = new signalR.HubConnectionBuilder()
.withUrl("/myhub") // Hub'ın URL'sini belirtin
.build();
connection.start(); // Bağlantıyı başlatın
// Psikolg Diğer sayfada görüşmeyi başlat buttonuna tıkladığı zaman burası tetiklenir.
// Ve OfferIsReady metodu kendisiyle birlikte offer değerlerinide getirir.
connection.on("OfferIsReady", function (Offer) {
//Start Fonksiyonuna Psikologdan gelen Offer değerleri gönderiliyor.
offerValue = Offer;
// Start Buttonu aktifleştirilir
StartButton.disabled = false;
});
// Kullanıcının kamerası ve mikrofonu kullanarak medya akışını al.
var stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true })
localVideo.srcObject = stream; // kendi videosunu lokalda kendisine izlet
///////////////////////////////////////////////
// https://www.expressturn.com
const TurnServer = {
urls: 'turn:relay1.expressturn.com:3478',
username: 'ef69HPFDI0CMQ9WZB5',
credential: 'OyUNsXZP9zCPVG61'
};
const StunServer = { urls: 'stun:stun.l.google.com:19302' }
///////////////////////////////////////////////////////////////////
// RTCPeerConnection nesnesini oluşturun ve STUN sunucusu yapılandırın.
const peerConnection = new RTCPeerConnection(iceServers: [StunServer]);
//////////////////////////////////////////////
// RTCPeerConnection nesnesini oluşturun ve STUN sunucusu yapılandırın.
//const peerConnection = new RTCPeerConnection({ iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] });
// Kendi kamerasının çektiği videoyu karşı tarafa yani psikoloğa göndermek.
stream.getTracks().forEach(t => peerConnection.addTrack(t, stream));
// Ice adaylarını toplamak için bir dizi oluşturun.
const iceCandidates = [];
peerConnection.onicecandidate = e => {
if (e.candidate) {
iceCandidates.push(e.candidate);
}
};
//Psikologdan Gelen Videoyu göstermek için bir olay dinleyici ekleyin.
peerConnection.ontrack = e => {
document.getElementById('remote').srcObject = e.streams[0];
};
///// Bura qeder ikisindede eyn gelir.
const Start = async (OfferAndIceCandidates) => {
// Ice adaylarının toplandığı zaman
peerConnection.onicegatheringstatechange = async () => {
// Eğer ice gathering tamamlandıysa
if (peerConnection.iceGatheringState === 'complete') {
// Sunucuya ve Psikoloğa (answer)cevap ve ice adaylarını gönder
await connection.invoke("AnswerHazir", JSON.stringify({ answer, iceCandidates }));
}// if - 1
};// onicegatheringstatechange
// Gelen string verisini JSON'a dönüştür.
const { offer, iceCandidates } = JSON.parse(OfferAndIceCandidates);
// Bu işlem, diğer cihazın teklifini kabul eder ve işler.
await peerConnection.setRemoteDescription(offer);
// Yanıt(answer) oluşturmak için createAnswer metodunu kullanıyoruz.
const answer = await peerConnection.createAnswer();
// Oluşturulan yanıtı (answer), yerel cihazın açıklaması olarak ayarlamak için setLocalDescription metodunu kullanıyoruz.
await peerConnection.setLocalDescription(answer);
// Ice adaylarını ekleyin
iceCandidates.forEach(candidate => peerConnection.addIceCandidate(candidate));
}// Start
})(); // (async () => {
@{
string buttonDisabled = string.Empty;
if (ViewBag.Offer != null && ViewBag.Offer.Length < 40)
{
buttonDisabled = "disabled";
}
}
<span id="offervalue" style="display: none;">@ViewBag.Offer</span>
<div class="container position-relative">
<h2 class="p-2 pt-2 h2">Qəbul edən səhifə.</h2>
<div class="text-center w-50 my-4">
<button id="start" class="btn btn-primary px-5" type="button" @buttonDisabled>Start.</button>
</div>
</div>
<video id="local" class="position-absolute local" autoplay></video>
<video id="remote" class="w-75 mt-1" autoplay></video>
</div>
<script src="~/js/answer.js"></script>
> this is the answer creation page
(async () => {
const localVideo = document.getElementById('local');
const StartButton = document.getElementById("start");
const connection = new signalR.HubConnectionBuilder()
.withUrl("/myhub") // Hub'ın URL'sini belirtin
.build();
connection.start(); // Bağlantıyı başlatın
// Görüşmeyi başlatmak için function.
const Start = async () => {
console.log("Görüşme başlatılıyor.")
// Kullanıcının kamerası ve mikrofonu kullanarak medya akışını al.
var stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true })
localVideo.srcObject = stream; // kendi videosunu lokalda kendisine izlet
const StunServer = { urls: 'stun:stun.l.google.com:19302' }
// RTCPeerConnection nesnesini oluşturun ve STUN sunucusu yapılandırın.
const peerConnection = new RTCPeerConnection({ iceServers: [StunServer] });
// Kendi kamerasının çektiği videoyu karşı tarafa yani danışana göndermek.
stream.getTracks().forEach(t => peerConnection.addTrack(t, stream));
// Ice adaylarını toplamak için bir dizi oluşturun.
const iceCandidates = [];
peerConnection.onicecandidate = e => {
if (e.candidate) {
iceCandidates.push(e.candidate);
}
};
// Danışandan Gelen Videoyu göstermek için bir olay dinleyici ekleyin.
peerConnection.ontrack = e => {
document.getElementById('remote').srcObject = e.streams[0];
};
const offer = await peerConnection.createOffer();
peerConnection.onicegatheringstatechange = () => {
if (peerConnection.iceGatheringState === 'complete') {
//SunucuyaGonder(JSON.stringify({ offer, iceCandidates }));
console.log("Offer sunucuya gonderildi");
(async () => { await connection.invoke("OfferHazir", JSON.stringify({ offer, iceCandidates })); })();
}
}; // onicegatheringstatechange
connection.on("AnswerIsReady", async function (message) { // Offer(istək) göndərilib Answer(cavab) gözlənilir
console.log("Qebuleden sayfasi offeri işleyip geri gönderdi.");
await HalletmekAnswerAndIceCandidates(message);
});
await peerConnection.setLocalDescription(offer);
// Bu fonksiyon, alınan yanıtı(answer) ve ice adaylarını kullanarak peerConnection'ı yapılandırır.
// Parametre olarak AnswerANDiceCandidates dizesini alır.
const HalletmekAnswerAndIceCandidates = async (AnswerANDiceCandidates) => {
// AnswerANDiceCandidates dizesini ayrıştırarak answer ve iceCandidates değişkenlerine atar.
const { answer, iceCandidates } = JSON.parse(AnswerANDiceCandidates);
// PeerConnection'a uzaktaki cihazın yanıtını ayarlar.
await peerConnection.setRemoteDescription(answer);
// Her bir ice adayını peerConnection'a ekler.
iceCandidates.forEach(candidate => peerConnection.addIceCandidate(candidate));
}; // HalletmekAnswerAndIceCandidates
} // Start function
// Görüşmeyi başlat.
StartButton.addEventListener('click', Start);
})();
<div class="container position-relative">
<h2 class="p-2 pt-2 h2">istək göndərən səhifə</h2>
<div class="text-center w-50 my-4">
<button id="start" class="btn btn-primary px-5" type="button">Start.</button>
</div>
<video id="local" class="position-absolute local" autoplay></video>
<video id="remote" class="w-75 mt-1" autoplay></video>
</div>
<p id="hata">bu p</p>
<script src="~/js/offer.js"></script>