MatrixRTC is the modern Matrix calling architecture that replaces the legacyDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/matrix-org/matrix-js-sdk/llms.txt
Use this file to discover all available pages before exploring further.
GroupCall mesh topology. Instead of establishing a direct WebRTC peer connection between every pair of participants, MatrixRTC routes media through a Selective Forwarding Unit (SFU) — typically a LiveKit server — while Matrix handles signalling and membership.
Scalable
SFU-based routing supports large calls without O(n²) connections.
E2E Encrypted
Per-call media keys distributed via to-device messages keep calls private end-to-end.
Membership via room state
Participants are tracked with
m.call.member / m.rtc.member state events.Transport-agnostic
The MatrixRTC layer only manages membership and keys; media transport is pluggable.
MatrixRTC vs legacy GroupCall
| Feature | Legacy GroupCall | MatrixRTC |
|---|---|---|
| Media routing | Peer-to-peer mesh | SFU (LiveKit) |
| Scales to | ~4–6 participants | Hundreds of participants |
| Signalling | m.call.* to-device messages | m.call.member state events |
| E2E encryption | Optional | Built-in via ToDeviceKeyTransport |
| SDK support class | GroupCall | MatrixRTCSession |
Legacy
GroupCall is still available but new applications should use MatrixRTCSession.Key classes
MatrixRTCSessionManager
MatrixRTCSessionManager is the top-level manager. It watches for m.call.member state events across all rooms and maintains a single MatrixRTCSession object per room.
Access it through the client:
MatrixRTCSession
MatrixRTCSession manages membership and encryption keys for a single room’s RTC session. It does not handle media — that is the responsibility of your LiveKit integration.
Joining a MatrixRTC session
session.on(
MatrixRTCSessionEvent.MembershipsChanged,
(oldMemberships, newMemberships) => {
console.log(`Memberships changed: ${newMemberships.length} participants`);
for (const m of newMemberships) {
console.log(" -", m.userId, m.deviceId);
}
},
);
session.on(
MatrixRTCSessionEvent.EncryptionKeyChanged,
(key, keyIndex, membership, rtcBackendIdentity) => {
// Pass the key to your LiveKit encryption layer
myLiveKitClient.setEncryptionKey(membership.memberId, key, keyIndex);
},
);
session.on(MatrixRTCSessionEvent.JoinStateChanged, (isJoined: boolean) => {
console.log(isJoined ? "Joined RTC session" : "Left RTC session");
});
session.joinRoomSession(
/*fociPreferred=*/ [{ type: "livekit", livekit_service_url: "https://livekit.example.org" }],
/*multiSfuFocus=*/ undefined,
/*joinConfig=*/ {
manageMediaKeys: true, // generate and distribute E2EE media keys
},
);
Once joined, read the active foci from the session memberships to obtain the LiveKit URL, then connect using the LiveKit SDK:
Leaving a session
Reading current memberships
session.memberships is an array of CallMembership objects, each representing an active participant:
End-to-end encryption
MatrixRTC encrypts media at the application layer using symmetric keys distributed between participants over to-device messages (ToDeviceKeyTransport). The flow is:
- When
manageMediaKeys: trueis set injoinRoomSession, the SDK generates a random media key for this device. - The key is sent to every other session participant over encrypted to-device messages.
- When participants join or leave, the key is rotated (with a configurable
keyRotationGracePeriodMsdelay to batch rapid membership changes). - The SDK emits
MatrixRTCSessionEvent.EncryptionKeyChangedwhenever a new key arrives — pass this to the LiveKitE2EEManager.