diff --git a/voice.py b/voice.py index 81f16df..d1c3319 100644 --- a/voice.py +++ b/voice.py @@ -69,16 +69,17 @@ def _generate_lk_jwt(room_id, user_id, device_id): KDF_HKDF = 1 -def _build_e2ee_options(shared_key: bytes) -> rtc.E2EEOptions: +def _build_e2ee_options() -> rtc.E2EEOptions: """Build HKDF E2EE options matching Element Call's key derivation. - Element Call uses: ratchetWindowSize=10, keyringSize=256, salt="LKFrameEncryptionKey" + No shared_key — initializes in per-participant mode so set_key() works. + Element Call uses: ratchetWindowSize=16, keyringSize=256, salt="LKFrameEncryptionKey" """ key_opts = rtc.KeyProviderOptions( - shared_key=shared_key, - ratchet_window_size=10, + shared_key=None, + ratchet_window_size=16, ratchet_salt=b"LKFrameEncryptionKey", - failure_tolerance=10, + failure_tolerance=-1, key_ring_size=256, key_derivation_function=KDF_HKDF, ) @@ -209,9 +210,9 @@ class VoiceSession: break await asyncio.sleep(0.1) - # Connect with E2EE enabled using bot's key as initial shared_key - # (required to initialize encryption framework, we override per-participant after) - e2ee_opts = _build_e2ee_options(self._bot_key) + # Connect with E2EE in per-participant mode (no shared_key) + # so set_key() calls work correctly for both directions + e2ee_opts = _build_e2ee_options() room_opts = rtc.RoomOptions(e2ee=e2ee_opts) self.lk_room = rtc.Room()