我暂时RTCPeerConnection
没有iceServers
尝试解决以前的问题,而是创建了一个。
let peer = new RTCPeerConnection();
这在我的本地网络上运行良好。
但是,不在同一网络上的设备(例如4G上的移动设备)将无法连接。我记得我有一些重新添加iceServers
到RTCPeerConnection
构造函数。
let peer = RTCPeerConnection(
{
iceServers: [
{
urls: [
"stun:stun1.l.google.com:19302",
"stun:stun2.l.google.com:19302",
],
},
{
urls: [
"stun:global.stun.twilio.com:3478?transport=udp",
],
},
],
iceCandidatePoolSize: 10,
}
);
从那以后,我的WebRTC连接就一直处于连接状态。即使在我的本地网络上,也没有一个成功的连接。(不再是这种情况,请参见下面的编辑2)
这是连接状态:
编辑:似乎比我留下iceServers
空白时,连接仍会收集一个ice候选对象,因此我假设我的浏览器(chrome)提供了默认的ice服务器。在这种情况下,只有我的自定义Ice服务器(如上所示)才引起问题,而不是浏览器默认设置。
编辑2:新观察
我添加了很多日志记录,只要有iceServers
包含,我就会注意到一些东西:
每当对等体A在一段时间内首次启动与对等体B的连接时,对等体B都会收集两个ice候选对象:1个本地主机候选对象和1个远程候选对象。如前所述,连接失败。
但是当我迅速尝试再次连接时...对等B仅收集了一个单独的ice候选对象:一个本地主机候选对象。不会收集远程候选人。我的第一个假设是我正在使用的STUN服务器(在这种情况下,很可能是Google的服务器)对其服务具有某种形式的速率限制。这种情况真正有趣的是,连接成功!!
远程候选人弄乱了连接,这有些不可思议。我希望这些新的细节会有所帮助。我被这个问题困扰了几个月!而且这两个设备都在我的LAN上,因此我希望远程候选对象绝对不会起作用。
对等A代码(发起方):
export class WebRTCConnection {
private _RTCPeerConnection: any;
private _fetch: any;
private _crypto: any;
private _entity: any;
private _hostAddress: any;
private _eventHandlers: ConnectionEventHandlers;
private _peer: any;
private _peerChannel: any;
constructor({
entity,
hostAddress,
eventHandlers,
RTCPeerConnection,
fetch,
crypto,
}: {
entity: any,
hostAddress: any,
eventHandlers: ConnectionEventHandlers,
RTCPeerConnection: any,
fetch: any,
crypto: any,
}) {
this._RTCPeerConnection = RTCPeerConnection;
this._fetch = fetch;
this._crypto = crypto;
this._entity = entity;
this._hostAddress = hostAddress;
this._eventHandlers = eventHandlers;
this._initPeer();
}
async _initPeer() {
this._peer = new this._RTCPeerConnection(/* as shown in question */);
let resolveOfferPromise: (value: any) => void;
let resolveIceCandidatesPromise: (value: any[]) => void;
let iceCandidatesPromise: Promise<any[]> = new Promise((resolve, _reject) => {
resolveIceCandidatesPromise = resolve;
});
let offerPromise: Promise<any> = new Promise((resolve, _reject) => {
resolveOfferPromise = resolve;
});
this._peer.onnegotiationneeded = async () => {
let offer = await this._peer.createOffer();
await this._peer.setLocalDescription(offer);
resolveOfferPromise(this._peer.localDescription);
};
this._peer.onicecandidateerror = () => {
// log error
};
let iceCandidates: any[] = [];
this._peer.onicecandidate = async (evt: any) => {
if (evt.candidate) {
// Save ice candidate
iceCandidates.push(evt.candidate);
} else {
resolveIceCandidatesPromise(iceCandidates);
}
};
(async () => {
// No more ice candidates, send on over signaling service
let offer: any = await offerPromise;
let iceCandidates: any[] = await iceCandidatesPromise;
let sigData = // reponse after sending offer and iceCandidates over signaling service
let answer = sigData.answer;
await this._peer.setRemoteDescription(answer);
for (let candidate of sigData.iceCandidates) {
await this._peer.addIceCandidate(candidate);
}
})();
this._peer.onicegatheringstatechange = (evt: any) => {
// log state
};
this._peer.onconnectionstatechange = async () => {
// log state
};
this._peerChannel = this._peer.createDataChannel("...", {
id: ...,
ordered: true,
});
this._peerChannel.onopen = () => {
// log this
};
this._peerChannel.onmessage = (event: any) => {
// do something
};
}
send(msg: any) {
this._peerChannel.send(
new TextEncoder().encode(JSON.stringify(msg)).buffer,
);
}
close() {
if (this._peer) {
this._peer.destroy();
}
}
}
对等B代码:
export class WebRTCConnection {
constructor({ signalData, eventHandlers, RTCPeerConnection }) {
this._eventHandlers = eventHandlers;
this._peer = new RTCPeerConnection(/* as seen above */);
this._isChannelOpen = false;
this._peer.ondatachannel = (event) => {
event.channel.onopen = () => {
this._mainDataChannel = event.channel;
event.channel.onmessage = async (event) => {
// do something
};
this._isChannelOpen = true;
};
};
this._peer.onicecandidateerror = () => {
// log error
};
this._iceCandidates = [];
this._isIceCandidatesFinished = false;
this._iceCandidatesPromise = new Promise((resolve, _reject) => {
this._resolveIceCandidatesPromise = resolve;
});
this._isAnswerFinished = false;
this._isSignalDataSent = false;
this._peer.onicecandidate = async (evt) => {
if (evt.candidate) {
// Save ice candidate
this._iceCandidates.push(evt.candidate);
} else {
// No more ice candidates, send on over signaling service when ready
this._isIceCandidatesFinished = true;
this._resolveIceCandidatesPromise();
this._sendSignalData();
}
};
(async () => {
let sigData = JSON.parse(signalData);
let offer = sigData.offer;
await this._peer.setRemoteDescription(offer);
this._answer = await this._peer.createAnswer();
await this._peer.setLocalDescription(this._answer);
for (let candidate of sigData.iceCandidates) {
await this._peer.addIceCandidate(candidate);
}
this._isAnswerFinished = true;
this._sendSignalData();
})();
this._peer.onconnectionstatechange = async () => {
// log state
};
}
_sendSignalData() {
if (false
|| !this._isIceCandidatesFinished
|| !this._isAnswerFinished
|| this._isSignalDataSent
) {
return;
}
this._isSignalDataSent = true;
this._eventHandlers.onSignal(JSON.stringify({
answer: {
type: this._answer.type,
sdp: this._answer.sdp,
},
iceCandidates: this._iceCandidates,
}));
}
send(msg) {
this._mainDataChannel.send(new TextEncoder().encode(JSON.stringify(msg)));
}
close() {
this._peer.destroy();
}
}
问题是我正在使用Brave浏览器。
使用Chrome解决了所有问题。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句