Звонки/UI: освобождение микрофона после звонка, детальнее failed и возврат в Настройки после принудительного обновления

This commit is contained in:
AidarKC 2026-05-01 18:05:39 +03:00
parent 27bd47dbe0
commit d96985303d
3 changed files with 38 additions and 5 deletions

View File

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

View File

@ -179,6 +179,9 @@ function openDeveloperAvatarUploadModal({ walletLogin, storagePwd, gateway } = {
} }
async function forceUiUpdateNow() { async function forceUiUpdateNow() {
try {
window.location.hash = '#/settings-view';
} catch {}
if (!('serviceWorker' in navigator)) { if (!('serviceWorker' in navigator)) {
window.location.reload(); window.location.reload();
return; return;

View File

@ -517,8 +517,35 @@ function cleanupTimers(call) {
} }
async function closeMedia(call) { async function closeMedia(call) {
try { call.pc?.close(); } catch {} const pc = call?.pc || null;
try { call.localStream?.getTracks()?.forEach((track) => track.stop()); } catch {} try {
const senders = pc?.getSenders?.() || [];
senders.forEach((sender) => {
try {
if (typeof sender?.replaceTrack === 'function') sender.replaceTrack(null);
} catch {}
});
} catch {}
try {
const transceivers = pc?.getTransceivers?.() || [];
transceivers.forEach((tr) => {
try { tr?.stop?.(); } catch {}
});
} catch {}
try {
call.localStream?.getTracks?.()?.forEach((track) => {
try { track.enabled = false; } catch {}
try { track.stop(); } catch {}
});
} catch {}
try {
if (call.remoteAudio) {
try { call.remoteAudio.pause?.(); } catch {}
try { call.remoteAudio.srcObject = null; } catch {}
call.remoteAudio = null;
}
} catch {}
try { pc?.close?.(); } catch {}
call.pc = null; call.pc = null;
call.localStream = null; call.localStream = null;
call.audioSenders = []; call.audioSenders = [];
@ -749,6 +776,7 @@ async function finalizeCall(call, {
notifyRemoteHangup = false, notifyRemoteHangup = false,
} = {}) { } = {}) {
if (!call) return; if (!call) return;
const diagnosticsBeforeClose = getCallDiagnosticsContext(call);
cleanupTimers(call); cleanupTimers(call);
stopReconnectFlow(call); stopReconnectFlow(call);
stopTone(); stopTone();
@ -788,6 +816,7 @@ async function finalizeCall(call, {
const failureContext = { const failureContext = {
failureStage, failureStage,
connectedBeforeFailure: Boolean(call.connectedAtMs), connectedBeforeFailure: Boolean(call.connectedAtMs),
...diagnosticsBeforeClose,
}; };
if (call.direction === 'out') { if (call.direction === 'out') {
await sendCallDeliveryReport(call, 'outgoing_failed', `outgoing_${localReasonCode}`, reasonText, failureContext); await sendCallDeliveryReport(call, 'outgoing_failed', `outgoing_${localReasonCode}`, reasonText, failureContext);
@ -923,12 +952,13 @@ async function ensurePeerConnection(call) {
return; return;
} }
if (state === 'failed') { if (state === 'failed') {
const failedDetails = `failed;ice=${pc.iceConnectionState || ''};gather=${pc.iceGatheringState || ''};signal=${pc.signalingState || ''}`;
if (call.connectedAtMs) { if (call.connectedAtMs) {
startReconnectFlow(call, 'failed'); startReconnectFlow(call, 'failed');
return; return;
} }
void emitDebug(call, 'warn', 'peer_connection_closed', `state=${state}`); void emitDebug(call, 'warn', 'peer_connection_closed', failedDetails);
void finalizeCall(call, { localReasonCode: 'error', debugReason: 'failed' }); void finalizeCall(call, { localReasonCode: 'error', debugReason: failedDetails });
return; return;
} }
if (state === 'disconnected' && call.phase !== 'ended') { if (state === 'disconnected' && call.phase !== 'ended') {