diff --git a/VERSION.properties b/VERSION.properties index 04a29d4..f563309 100644 --- a/VERSION.properties +++ b/VERSION.properties @@ -1,2 +1,2 @@ -client.version=1.2.28 +client.version=1.2.29 server.version=1.2.26 diff --git a/shine-UI/js/pages/developer-settings-view.js b/shine-UI/js/pages/developer-settings-view.js index 82995d3..e39911c 100644 --- a/shine-UI/js/pages/developer-settings-view.js +++ b/shine-UI/js/pages/developer-settings-view.js @@ -179,6 +179,9 @@ function openDeveloperAvatarUploadModal({ walletLogin, storagePwd, gateway } = { } async function forceUiUpdateNow() { + try { + window.location.hash = '#/settings-view'; + } catch {} if (!('serviceWorker' in navigator)) { window.location.reload(); return; diff --git a/shine-UI/js/services/call-service.js b/shine-UI/js/services/call-service.js index 46dcf54..4ba47f7 100644 --- a/shine-UI/js/services/call-service.js +++ b/shine-UI/js/services/call-service.js @@ -517,8 +517,35 @@ function cleanupTimers(call) { } async function closeMedia(call) { - try { call.pc?.close(); } catch {} - try { call.localStream?.getTracks()?.forEach((track) => track.stop()); } catch {} + const pc = call?.pc || null; + 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.localStream = null; call.audioSenders = []; @@ -749,6 +776,7 @@ async function finalizeCall(call, { notifyRemoteHangup = false, } = {}) { if (!call) return; + const diagnosticsBeforeClose = getCallDiagnosticsContext(call); cleanupTimers(call); stopReconnectFlow(call); stopTone(); @@ -788,6 +816,7 @@ async function finalizeCall(call, { const failureContext = { failureStage, connectedBeforeFailure: Boolean(call.connectedAtMs), + ...diagnosticsBeforeClose, }; if (call.direction === 'out') { await sendCallDeliveryReport(call, 'outgoing_failed', `outgoing_${localReasonCode}`, reasonText, failureContext); @@ -923,12 +952,13 @@ async function ensurePeerConnection(call) { return; } if (state === 'failed') { + const failedDetails = `failed;ice=${pc.iceConnectionState || ''};gather=${pc.iceGatheringState || ''};signal=${pc.signalingState || ''}`; if (call.connectedAtMs) { startReconnectFlow(call, 'failed'); return; } - void emitDebug(call, 'warn', 'peer_connection_closed', `state=${state}`); - void finalizeCall(call, { localReasonCode: 'error', debugReason: 'failed' }); + void emitDebug(call, 'warn', 'peer_connection_closed', failedDetails); + void finalizeCall(call, { localReasonCode: 'error', debugReason: failedDetails }); return; } if (state === 'disconnected' && call.phase !== 'ended') {