WebRTC: очередь ранних ICE, игнор дублирующего ANSWER и деплой UI 1.2.30

This commit is contained in:
AidarKC 2026-05-01 18:08:43 +03:00
parent d96985303d
commit c5dfa47903
2 changed files with 39 additions and 2 deletions

View File

@ -1,2 +1,2 @@
client.version=1.2.29
client.version=1.2.30
server.version=1.2.26

View File

@ -516,6 +516,21 @@ function cleanupTimers(call) {
call.timers.transportProbe = null;
}
async function flushPendingIceCandidates(call) {
if (!call?.pc) return;
const pending = Array.isArray(call.pendingRemoteIceCandidates) ? call.pendingRemoteIceCandidates : [];
if (!pending.length) return;
call.pendingRemoteIceCandidates = [];
for (const candidate of pending) {
try {
await call.pc.addIceCandidate(new RTCIceCandidate(candidate));
await emitDebug(call, 'info', 'ice_processed_from_queue', 'candidate added');
} catch (error) {
await emitDebug(call, 'warn', 'ice_process_failed_from_queue', toErrorText(error));
}
}
}
async function closeMedia(call) {
const pc = call?.pc || null;
try {
@ -551,6 +566,7 @@ async function closeMedia(call) {
call.audioSenders = [];
call.connectionRouteLabel = '';
call.connectionRouteDetails = '';
call.pendingRemoteIceCandidates = [];
}
function stopReconnectFlow(call) {
@ -1006,6 +1022,9 @@ async function ensurePeerConnection(call) {
};
call.pc = pc;
if (!Array.isArray(call.pendingRemoteIceCandidates)) {
call.pendingRemoteIceCandidates = [];
}
return pc;
}
@ -1125,9 +1144,11 @@ export async function startDebugConnectionAsResponder({ runId, callId, peerLogin
debugMode: true,
debugRunId: String(runId || '').trim(),
debugRole: 'responder',
pendingRemoteIceCandidates: [],
};
calls.set(cleanCallId, call);
}
if (!Array.isArray(call.pendingRemoteIceCandidates)) call.pendingRemoteIceCandidates = [];
activeCallId = cleanCallId;
await emitDebug(call, 'info', 'debug_prepare_responder', `peerSessionId=${cleanPeerSessionId}`);
@ -1158,6 +1179,7 @@ export async function startDebugConnectionAsInitiator({ runId, callId, peerLogin
debugMode: true,
debugRunId: String(runId || '').trim(),
debugRole: 'initiator',
pendingRemoteIceCandidates: [],
};
calls.set(cleanCallId, call);
@ -1202,6 +1224,7 @@ export async function startOutgoingCall(peerLogin) {
debugMode: false,
debugRunId: '',
debugRole: '',
pendingRemoteIceCandidates: [],
};
calls.set(callId, call);
activeCallId = callId;
@ -1271,6 +1294,7 @@ export async function handleIncomingCallInvite(evt) {
debugMode: false,
debugRunId: '',
debugRole: '',
pendingRemoteIceCandidates: [],
};
calls.set(callId, call);
}
@ -1364,6 +1388,7 @@ export async function handleIncomingCallSignal(evt) {
try {
const pc = await ensurePeerConnection(call);
await pc.setRemoteDescription(new RTCSessionDescription(JSON.parse(data)));
await flushPendingIceCandidates(call);
const answer = await pc.createAnswer();
await pc.setLocalDescription(answer);
await sendSignal(call, TYPES.ANSWER, JSON.stringify(answer));
@ -1379,7 +1404,12 @@ export async function handleIncomingCallSignal(evt) {
if (type === TYPES.ANSWER) {
try {
const pc = await ensurePeerConnection(call);
if (pc.signalingState === 'stable' && pc.remoteDescription) {
await emitDebug(call, 'warn', 'answer_duplicate_ignored', 'remote description already set');
return;
}
await pc.setRemoteDescription(new RTCSessionDescription(JSON.parse(data)));
await flushPendingIceCandidates(call);
setStatus(call, 'Соединяем…', 'connecting');
await emitDebug(call, 'info', 'answer_processed', 'remote description set');
} catch (error) {
@ -1392,7 +1422,14 @@ export async function handleIncomingCallSignal(evt) {
if (type === TYPES.ICE) {
try {
const pc = await ensurePeerConnection(call);
await pc.addIceCandidate(new RTCIceCandidate(JSON.parse(data)));
const candidate = JSON.parse(data);
if (!pc.remoteDescription) {
if (!Array.isArray(call.pendingRemoteIceCandidates)) call.pendingRemoteIceCandidates = [];
call.pendingRemoteIceCandidates.push(candidate);
await emitDebug(call, 'info', 'ice_queued_before_remote_description', `queue=${call.pendingRemoteIceCandidates.length}`);
return;
}
await pc.addIceCandidate(new RTCIceCandidate(candidate));
await emitDebug(call, 'info', 'ice_processed', 'candidate added');
} catch (error) {
await emitDebug(call, 'error', 'ice_process_failed', toErrorText(error));