fix(e2ee): aggressive video re-keying after track subscription (MAT-144)

Video frame cryptors may not be fully initialized when set_key() is
first called during on_track_subscribed. Audio works immediately but
video oscillates OK↔DEC_FAILED with the same key.

Add staggered re-keying at 0.3s, 0.8s, 2s, 5s after video track
subscription to ensure the key is applied after the frame cryptor
is fully ready.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Christian Gick
2026-03-10 09:38:17 +02:00
parent 7e59593c3e
commit 1118ab5060

View File

@@ -693,8 +693,25 @@ class VoiceSession:
if self._caller_all_keys:
for idx, base_k in sorted(self._caller_all_keys.items()):
_derive_and_set_key(kp_local, caller_id, base_k, idx)
logger.info("on_ts: derived+set key[%d] for %s (%s track)",
logger.info("on_ts: set key[%d] for %s (%s track)",
idx, caller_id, track_type)
# MAT-144: Video frame cryptors may not be fully initialized
# when set_key is first called. Schedule aggressive re-keying.
if int(t.kind) == 2:
async def _video_rekey(pid=caller_id):
for delay in (0.3, 0.8, 2.0, 5.0):
await asyncio.sleep(delay)
if not self.lk_room:
break
try:
kp_v = self.lk_room.e2ee_manager.key_provider
for idx, base_k in sorted(self._caller_all_keys.items()):
_derive_and_set_key(kp_v, pid, base_k, idx)
logger.info("video_rekey: re-set %d keys for %s (delay=%.1fs)",
len(self._caller_all_keys), pid, delay)
except Exception as exc:
logger.warning("video_rekey failed: %s", exc)
asyncio.ensure_future(_video_rekey())
else:
logger.warning("on_ts: no caller keys yet — scheduling 0.5s retry")
async def _brief_key_retry(pid=caller_id):
@@ -704,7 +721,7 @@ class VoiceSession:
kp_r = self.lk_room.e2ee_manager.key_provider
for idx, base_k in sorted(self._caller_all_keys.items()):
_derive_and_set_key(kp_r, pid, base_k, idx)
logger.info("on_ts_retry: derived+set key[%d] for %s", idx, pid)
logger.info("on_ts_retry: set key[%d] for %s", idx, pid)
except Exception as exc:
logger.warning("on_ts_retry: set_key failed: %s", exc)
else: