From 3fffbd039274f6eba11f98c8af1f55b4bcf20bd7 Mon Sep 17 00:00:00 2001 From: k1ngsterr1 Date: Thu, 26 Mar 2026 00:31:35 +0500 Subject: [PATCH] =?UTF-8?q?=D0=9F=D1=80=D0=BE=D0=BC=D0=B5=D0=B6=D1=83?= =?UTF-8?q?=D1=82=D0=BE=D1=87=D0=BD=D1=8B=D0=B9=20=D0=BA=D0=BE=D0=BC=D0=BC?= =?UTF-8?q?=D0=B8=D1=82=20=D1=81=D0=BE=20=D0=B7=D0=B2=D0=BE=D0=BD=D0=BA?= =?UTF-8?q?=D0=B0=D0=BC=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/cpp/rosetta_e2ee.cpp | 133 ++---------------- .../rosetta/messenger/network/CallManager.kt | 32 +++-- 2 files changed, 31 insertions(+), 134 deletions(-) diff --git a/app/src/main/cpp/rosetta_e2ee.cpp b/app/src/main/cpp/rosetta_e2ee.cpp index d0c7148..ed7fc4e 100644 --- a/app/src/main/cpp/rosetta_e2ee.cpp +++ b/app/src/main/cpp/rosetta_e2ee.cpp @@ -72,13 +72,6 @@ struct GeneratedTsState { uint32_t next_step = 960; // 20 ms @ 48 kHz (default Opus packetization) }; -struct AdditionalTsState { - bool initialized64 = false; - bool initialized32 = false; - uint64_t base64 = 0; - uint32_t base32 = 0; -}; - static inline uint16_t load16_be(const uint8_t* p) { return (uint16_t)(((uint16_t)p[0] << 8) | (uint16_t)p[1]); } @@ -90,27 +83,6 @@ static inline uint32_t load32_be(const uint8_t* p) { ((uint32_t)p[3]); } -static inline uint64_t load64_be(const uint8_t* p) { - return ((uint64_t)p[0] << 56) | - ((uint64_t)p[1] << 48) | - ((uint64_t)p[2] << 40) | - ((uint64_t)p[3] << 32) | - ((uint64_t)p[4] << 24) | - ((uint64_t)p[5] << 16) | - ((uint64_t)p[6] << 8) | - ((uint64_t)p[7]); -} - -static inline void store64_be(uint8_t* p, uint64_t v) { - p[0] = (uint8_t)(v >> 56); - p[1] = (uint8_t)(v >> 48); - p[2] = (uint8_t)(v >> 40); - p[3] = (uint8_t)(v >> 32); - p[4] = (uint8_t)(v >> 24); - p[5] = (uint8_t)(v >> 16); - p[6] = (uint8_t)(v >> 8); - p[7] = (uint8_t)(v); -} static bool parse_rtp_packet(const uint8_t* data, size_t len, ParsedRtpPacket* out) { if (!data || !out || len < 12) return false; @@ -216,27 +188,22 @@ static bool fill_nonce_from_rtp_frame(const uint8_t* data, static bool fill_nonce_from_additional_data(const uint8_t* data, size_t len, uint8_t nonce[24], - AdditionalTsState* ts_state, - bool normalize_timestamps, - bool* used_normalized, bool* used_rtp_header) { - if (used_normalized) *used_normalized = false; if (used_rtp_header) *used_rtp_header = false; if (!data || len < 8) return false; - // Common native WebRTC layout: additional_data is RTP header bytes. + // Desktop-compatible path: additional_data contains encoded frame timestamp + // as 8-byte BE value. Use it directly as nonce[0..7]. + if (len == 8) { + memcpy(nonce, data, 8); + return true; + } + + // Legacy native WebRTC layout: additional_data can be RTP header bytes. if (len >= 12) { const uint8_t version = (data[0] >> 6) & 0x03; if (version == 2) { uint32_t ts = load32_be(data + 4); - if (normalize_timestamps && ts_state) { - if (!ts_state->initialized32) { - ts_state->initialized32 = true; - ts_state->base32 = ts; - } - ts = (uint32_t)(ts - ts_state->base32); - if (used_normalized) *used_normalized = true; - } nonce[4] = (uint8_t)(ts >> 24); nonce[5] = (uint8_t)(ts >> 16); nonce[6] = (uint8_t)(ts >> 8); @@ -246,17 +213,8 @@ static bool fill_nonce_from_additional_data(const uint8_t* data, } } - // Generic 8-byte timestamp layout (desktop's nonce[0..7] layout). - uint64_t ts = load64_be(data); - if (normalize_timestamps && ts_state) { - if (!ts_state->initialized64) { - ts_state->initialized64 = true; - ts_state->base64 = ts; - } - ts = (uint64_t)(ts - ts_state->base64); - if (used_normalized) *used_normalized = true; - } - store64_be(nonce, ts); + // Generic fallback: first 8 bytes as BE timestamp-like payload. + memcpy(nonce, data, 8); return true; } @@ -401,7 +359,6 @@ public: bool nonce_from_rtp_header = false; bool nonce_from_generated_ts = false; bool nonce_from_additional_data = false; - bool nonce_from_additional_normalized = false; bool additional_was_rtp_header = false; uint32_t generated_ts_used = 0; @@ -411,9 +368,6 @@ public: additional_data.data(), additional_data.size(), nonce, - &additional_ts_, - true, - &nonce_from_additional_normalized, &additional_was_rtp_header); if (!nonce_from_additional_data) { nonce_from_rtp_header = @@ -464,9 +418,7 @@ public: : (nonce_from_generated_ts ? "gen" : (nonce_from_additional_data - ? (additional_was_rtp_header - ? (nonce_from_additional_normalized ? "ad-rtp-norm" : "ad-rtp") - : (nonce_from_additional_normalized ? "raw-norm" : "raw-abs")) + ? (additional_was_rtp_header ? "ad-rtp" : "raw-abs") : "raw-abs")); LOGI("ENC frame#%d: sz=%zu ad=%zu hdr=%zu mode=%s nonce=%02x%02x%02x%02x", n, frame.size(), additional_data.size(), header_size, mode, @@ -490,7 +442,6 @@ private: mutable std::atomic diag_count_{0}; mutable RtpProbeState rtp_probe_; mutable GeneratedTsState generated_ts_; - mutable AdditionalTsState additional_ts_; uint8_t key_[32]; }; @@ -533,17 +484,12 @@ public: bool nonce_from_rtp_header = false; bool nonce_from_generated_ts = false; bool nonce_from_additional_data = false; - bool nonce_from_additional_normalized = false; bool additional_was_rtp_header = false; - bool used_absolute_additional_fallback = false; uint32_t generated_ts_used = 0; nonce_from_additional_data = fill_nonce_from_additional_data( additional_data.data(), additional_data.size(), nonce, - &additional_ts_, - true, - &nonce_from_additional_normalized, &additional_was_rtp_header); if (!nonce_from_additional_data) { nonce_from_rtp_header = @@ -581,55 +527,6 @@ public: rosetta_xchacha20_xor(frame.data(), encrypted_frame.data(), encrypted_frame.size(), nonce, key_); } - // additional_data on Android can be absolute RTP-ish timestamp, while - // desktop nonce source is normalized stream timestamp. If normalized - // nonce gives implausible Opus, retry with absolute additional_data. - if (!nonce_from_generated_ts && - nonce_from_additional_data && - encrypted_frame.size() > 0 && - additional_data.size() >= 8) { - const uint8_t* payload_ptr = frame.data() + header_size; - const size_t payload_size = encrypted_frame.size() - header_size; - if (!is_plausible_opus_packet(payload_ptr, payload_size)) { - uint8_t nonce_abs[24] = {0}; - bool abs_norm = false; - bool abs_rtp = false; - if (fill_nonce_from_additional_data( - additional_data.data(), - additional_data.size(), - nonce_abs, - nullptr, - false, - &abs_norm, - &abs_rtp) && - memcmp(nonce_abs, nonce, 24) != 0) { - if (nonce_from_rtp_header && header_size <= encrypted_frame.size()) { - if (header_size > 0) { - memcpy(frame.data(), encrypted_frame.data(), header_size); - } - rosetta_xchacha20_xor( - frame.data() + header_size, - encrypted_frame.data() + header_size, - payload_size, - nonce_abs, - key_); - } else { - rosetta_xchacha20_xor( - frame.data(), - encrypted_frame.data(), - encrypted_frame.size(), - nonce_abs, - key_); - } - payload_ptr = frame.data() + header_size; - if (is_plausible_opus_packet(payload_ptr, payload_size)) { - memcpy(nonce, nonce_abs, 24); - used_absolute_additional_fallback = true; - } - } - } - } - if (nonce_from_generated_ts) { bool plausible = is_plausible_opus_packet(frame.data(), encrypted_frame.size()); @@ -669,13 +566,8 @@ public: mode = "rtp"; } else if (nonce_from_generated_ts) { mode = used_generated_resync ? "gen-resync" : "gen"; - } else if (used_absolute_additional_fallback) { - mode = additional_was_rtp_header ? "ad-rtp-abs-fb" : "raw-abs-fb"; } else if (nonce_from_additional_data) { - mode = - additional_was_rtp_header - ? (nonce_from_additional_normalized ? "ad-rtp-norm" : "ad-rtp") - : (nonce_from_additional_normalized ? "raw-norm" : "raw-abs"); + mode = additional_was_rtp_header ? "ad-rtp" : "raw-abs"; } else { mode = "raw-abs"; } @@ -702,7 +594,6 @@ private: mutable std::atomic diag_count_{0}; mutable RtpProbeState rtp_probe_; mutable GeneratedTsState generated_ts_; - mutable AdditionalTsState additional_ts_; uint8_t key_[32]; }; diff --git a/app/src/main/java/com/rosetta/messenger/network/CallManager.kt b/app/src/main/java/com/rosetta/messenger/network/CallManager.kt index 39f2cc3..2a883c6 100644 --- a/app/src/main/java/com/rosetta/messenger/network/CallManager.kt +++ b/app/src/main/java/com/rosetta/messenger/network/CallManager.kt @@ -234,7 +234,12 @@ object CallManager { } fun endCall() { - breadcrumb("UI: endCall requested") + val callerTrace = + Throwable() + .stackTrace + .take(6) + .joinToString(" | ") { "${it.className}.${it.methodName}:${it.lineNumber}" } + breadcrumb("UI: endCall requested by $callerTrace") resetSession(reason = null, notifyPeer = true) } @@ -605,29 +610,30 @@ object CallManager { onCallConnected() } PeerConnection.PeerConnectionState.FAILED, - PeerConnection.PeerConnectionState.CLOSED -> { - disconnectResetJob?.cancel() - disconnectResetJob = null - // Dispatch to our scope — this callback fires on WebRTC thread - scope.launch { - resetSession(reason = "Connection lost", notifyPeer = false) - } - } + PeerConnection.PeerConnectionState.CLOSED, PeerConnection.PeerConnectionState.DISCONNECTED -> { - // Desktop tolerates short network dips; do not kill call immediately. + // Desktop flow is signal-driven. Keep call alive across short + // transport glitches and only fallback-reset after timeout. disconnectResetJob?.cancel() disconnectResetJob = scope.launch { - delay(5_000L) + val timeoutMs = + when (newState) { + PeerConnection.PeerConnectionState.DISCONNECTED -> 15_000L + PeerConnection.PeerConnectionState.FAILED -> 12_000L + PeerConnection.PeerConnectionState.CLOSED -> 12_000L + else -> 12_000L + } + delay(timeoutMs) val pcState = peerConnection?.connectionState() if (pcState == PeerConnection.PeerConnectionState.DISCONNECTED || pcState == PeerConnection.PeerConnectionState.FAILED || pcState == PeerConnection.PeerConnectionState.CLOSED ) { - breadcrumb("PC: DISCONNECTED timeout → reset") + breadcrumb("PC: $newState timeout ($timeoutMs ms) → reset") resetSession(reason = "Connection lost", notifyPeer = false) } else { - breadcrumb("PC: DISCONNECTED recovered (state=$pcState)") + breadcrumb("PC: $newState recovered (state=$pcState)") } } }