-
Notifications
You must be signed in to change notification settings - Fork 450
MSC4196: Voice and video calling application for MatrixRTC #4196
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
hughns
wants to merge
32
commits into
main
Choose a base branch
from
hughns/matrixrtc-m-call
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+207
−0
Open
Changes from 5 commits
Commits
Show all changes
32 commits
Select commit
Hold shift + click to select a range
023cfea
Create xxxx-matrixrtc-m-call.md
hughns ff42c61
Allocated MSC number
hughns 3623ff0
Latest
hughns dd1c832
major rewrite addressing a lot of feedback from offline discussions.
fkwp fea4875
big typo
fkwp 6491288
Clarify slot ID value
Johennes 5add2f0
Fix MSC reference
Johennes 096fa46
Rework introduction
Johennes e32d707
Clean up slot description
Johennes 2849eea
Fix typo
Johennes 7441374
Clean up membership event section
Johennes a16bb1b
Clean up leave_reasons
Johennes 82d3286
Remove notification section
Johennes 598d9af
Clean up intent handling
Johennes ee403f0
Clean-up room creation section
Johennes 6fb5505
Clean up unstable prefix and dependencies sections
Johennes 4d2dded
Add some basic alternative and security considerations
Johennes d8bdc90
Fix typo
Johennes 025ba25
Add notes about usage with m.livekit
Johennes bee7f53
Small clarification
Johennes 501d90b
Fix typo
Johennes 08ca86c
ROOM -> room
Johennes ff4a7a2
Clarify intent rules
Johennes 8b383fc
session -> call
Johennes 950cc07
Add that joining would be a visible choice
Johennes a461542
Remove recommendation for withheld intents
Johennes 15a95f6
Remove slot replication on room upgrades
Johennes 16cb63a
Remove encryption_error
Johennes fb6fd97
Link to MSC3417
Johennes 76dce0b
Also create the slot when using the trusted_private_chat preset
Johennes d591b56
Rework faking intent section
Johennes 29b1805
Simply intent leak section
Johennes File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,195 @@ | ||
| # MSC4196: MatrixRTC voice and video calling application `m.call` | ||
|
Johennes marked this conversation as resolved.
Outdated
|
||
|
|
||
| ## Proposal | ||
|
|
||
| We define a **MatrixRTC application** of type `m.call` for real-time calling, designed to support | ||
| the following use cases: | ||
|
|
||
| * **1:1 calls in direct messages (DMs)** – Private, peer-to-peer conversations. | ||
| * **Huddles** – Adding a call to an existing room for spontaneous group discussions. | ||
| * **Persistent “social” rooms** – Discord-style voice or video spaces that are fixed in type but act | ||
| as a permanent hangout, where users can drop in and out freely, similar to a pub or watercooler. | ||
|
|
||
| ### MatrixRTC Slots for voice and video calling | ||
|
|
||
| For voice and video calling, MatrixRTC defines **a room-level slot model** to represent calls that | ||
| are scoped to a Matrix room and shared among its participants: | ||
|
|
||
| * **`m.call#ROOM` — Room-level call slot** | ||
|
Johennes marked this conversation as resolved.
Outdated
|
||
| Represents a call instance associated with the entire room. This slot is **managed by a user with | ||
| sufficient power level** and is intended for calls where **any room member is welcome to join**. | ||
| Ownership of the call is **shared** — it does not depend on who initiated it. This slot type is | ||
| also suitable for **1:1 direct message (DM) calls**, including use cases resembling traditional | ||
| **telephone-style calling semantics**. | ||
|
|
||
| ### MatrixRTC Member JSON Object for Application `m.call` | ||
|
|
||
| A valid `m.rtc.member` state event with **application type** `m.call` includes the standard fields | ||
| defined in [MSC4143](https://github.com/matrix-org/matrix-spec-proposals/pull/4143), **plus | ||
| additional fields specific to `m.call`**: | ||
|
|
||
| ``` | ||
| { | ||
| "application": { | ||
| "type": "m.call", | ||
| // additional fields for m.call: | ||
| "m.call.id": UUID // optional | ||
| "m.call.intent": "voice" | "video" | "any-value" // optional | ||
| }, | ||
| } | ||
| ``` | ||
|
|
||
| **Field Description** | ||
|
|
||
| | Field | Type | Required | Description | | ||
| | :---- | :---- | ----- | :---- | | ||
| | `type` | string | ✅ | Must be `"m.call"`. Identifies the application type. | | ||
| | `m.call.id` | string | ⚪ | Optional call ID of the session. Serves as a unique identifier for the call instance. | | ||
| | `m.call.intent` | string | ⚪ | Optional hint expressing the intended use-case of the session, e.g., `"voice"`, `"video"`, or `"spatial-audio"`. This field is **informational only** and non-authoritative, reflecting the participant's perception of the session. | | ||
|
Johennes marked this conversation as resolved.
Outdated
|
||
|
|
||
| Participants MAY include a `m.call.intent` field to express the intended use-case of their `m.call` | ||
| session (e.g. `"voice"`, `"video"`, `"spatial-audio"`). Because of Matrix decentralisation, this | ||
| field is purely informational and non-authoritative, serving only as a hint about how the | ||
| participant perceives the session. | ||
|
|
||
| The following is an example of a well-formed `m.rtc.member` event for a participant joining a | ||
|
Johennes marked this conversation as resolved.
Outdated
|
||
| room-level call (`m.call#ROOM`) using the `m.call` application type: | ||
|
|
||
| ``` | ||
| // event type: "m.rtc.member" | ||
| { | ||
| "slot_id": "m.call#ROOM", | ||
| "member": { | ||
| "id": "xyzABCDEF0123" // UUID, unique participation instance | ||
| "claimed_device_id": "DEVICEID", | ||
| "claimed_user_id": "@user:matrix.domain" | ||
|
Johennes marked this conversation as resolved.
Outdated
|
||
| }, | ||
| "sticky_key": "xyzABCDEF0123" // same as member.id | ||
| "application": { | ||
| "type": "m.call", | ||
| // additional fields for m.call: | ||
| "m.call.id": UUID | ||
| "scope": "m.room" | ||
|
Johennes marked this conversation as resolved.
Outdated
|
||
| "m.call.intent": "voice" | "video" | "any-value" // optional | ||
| }, | ||
| "m.relates_to":{ // Reference to original join event; omit if first event | ||
| rel_type: "m.reference", | ||
| event_id: "$connect_event_id" | ||
| }, | ||
|
Johennes marked this conversation as resolved.
Outdated
|
||
| "rtc_transports": [ | ||
| { /* TRANSPORT_1 details */ } | ||
| ], | ||
| "versions": [ | ||
| "v0" | ||
| ], | ||
|
Johennes marked this conversation as resolved.
Outdated
|
||
| } | ||
| ``` | ||
|
|
||
| ### Ending a Call and Post-Connect Error Handling | ||
|
|
||
| Participation in a call is ended by disconnecting the MatrixRTC slot, as defined in | ||
| [MSC4143](https://github.com/matrix-org/matrix-spec-proposals/pull/4143). The | ||
| **`disconnect_reason`** field is used to provide further details about the disconnection and can | ||
| also be used for structured error handling. | ||
|
|
||
| A valid `m.rtc.member` event, as a prerequisite for disconnecting from a slot, has the following | ||
| schema: | ||
|
|
||
| ``` | ||
| // event type: "m.rtc.member" | ||
| { | ||
| "slot_id": "m.call.ROOM", | ||
|
Johennes marked this conversation as resolved.
Outdated
|
||
| "sticky_key": "xyzABCDEF0123", | ||
| "m.relates_to":{ // SHOULD | ||
| rel_type: "m.reference", | ||
| event_id: "$connect_event_id" | ||
| }, | ||
| // Optional | ||
| "disconnect_reason": { | ||
| "class": "server_error", | ||
| "reason": "ice_failed", | ||
| "description": "Failed to establish peer-to-peer connection via ICE", | ||
| } | ||
|
Johennes marked this conversation as resolved.
Outdated
|
||
| } | ||
| ``` | ||
|
|
||
| **Field explanations:** | ||
|
|
||
| * `slot_id` — The slot this member belongs to. | ||
| * `m.relates_to` — The `m.relates_to` field optionally references the initial connect event | ||
| * `sticky_key` — Same as above | ||
| * `disconnect_reason` as defined below | ||
|
|
||
| `disconnect_reason` **field explanations:** | ||
|
|
||
| | Class | Example Reason | Description / When Used | | ||
| | ----- | ----- | ----- | | ||
| | `user_action` | `hangup` | Participant intentionally ended the call after joining. | | ||
| | | `switch_device` | User moved the session to another device mid-call. | | ||
| | `client_error` | `media_error` | Failed to capture or transmit audio/video after joining. | | ||
| | | `transport_failure` | Local ICE/DTLS setup failed despite a successful `m.rtc.member` event. | | ||
| | | `encryption_error` | Failed to set up E2EE for the media channel after connecting. | | ||
| | `server_error` | `ice_failed` | ICE negotiation could not complete due to network/server issues. | | ||
| | | `dtls_failed` | DTLS handshake failed. | | ||
| | | `network_error` | Temporary network outage caused the connection to drop. | | ||
| | `redirection` | `call_transferred` | Call was redirected to another slot, device, or user. | | ||
| | | `moved_temporarily` | Session temporarily moved (e.g., server migration). | | ||
| | `permanent_failure` | `codec_mismatch` | Participant cannot decode/encode the call media. | | ||
| | | `unsupported_features` | Session requested unsupported capabilities. | | ||
|
|
||
| ### Call Ringing Using `m.rtc.notification` room event | ||
|
|
||
| A valid `m.rtc.notification` event for a MatrixRTC session with application `m.call` MAY have the | ||
| following fields in addition to the fields defined in | ||
| [MSC4075](https://github.com/matrix-org/matrix-spec-proposals/pull/4075): | ||
| - `m.call.intent` | ||
|
|
||
| ``` | ||
| // event type: "m.rtc.notification" | ||
| { | ||
| "type":"m.rtc.notification", // org.matrix.msc4075.rtc.notification | ||
| "content": { | ||
| "sender_ts": 1752583130365, | ||
| "lifetime": 30000, | ||
| "m.mentions": {"user_ids": [], "room": true | false}, | ||
| "m.relates_to": {"rel_type":"m.reference", "event_id":"$rtc_member_event_id"}, | ||
| "notification_type": "ring | notification", | ||
| // additional fields for m.call: | ||
| "m.call.intent": "voice" | "video" | "any-value" // optional, | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ### Handling of `m.call.intent` | ||
|
|
||
| Clients SHOULD infer a “voice” `m.call.intent` as a voice call, and “video” as a voice and video | ||
| call. | ||
|
|
||
| Clients SHOULD NOT submit a video track if the user has requested a “voice” call initially, although | ||
| this is a soft limitation and users may choose to upgrade to include a video track later in the | ||
| call. | ||
|
|
||
| If the intent is not understood, the default value of “video” should be assumed (both voice and | ||
| video tracks may be expected). | ||
|
|
||
| ### Defaults | ||
|
|
||
| [The createRoom preset | ||
| option](https://spec.matrix.org/v1.16/client-server-api/#post_matrixclientv3createroom) | ||
| `trusted_private_chat` should enable a default room slot `m.call#ROOM` for the application `m.call`. | ||
|
|
||
| ## Potential issues | ||
|
|
||
| ## Alternatives | ||
|
|
||
| ## Security considerations | ||
|
|
||
| ## Unstable prefix | ||
|
|
||
| The `m.call` application type is already within unstable prefixed entries (i.e. | ||
| `org.matrix.msc4143.rtc.member`) and as such doesn't need its own unstable prefix. | ||
|
|
||
| ## Dependencies | ||
|
|
||
| This MSC builds on [MSC4143](https://github.com/matrix-org/matrix-spec-proposals/pull/4143) and | ||
| [MSC4075](https://github.com/matrix-org/matrix-spec-proposals/pull/4075). | ||
|
Johennes marked this conversation as resolved.
Outdated
|
||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implementation requirements:
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
m.callapplication inm.rtc.slotevents: Use MatrixRTC slots behind labs flag element-hq/element-web#34392m.callapplication inm.rtc.memberevents: https://github.com/matrix-org/matrix-js-sdk/blob/e16b0bcc06d0b17889f3eedef972f3cae9790f08/src/matrixrtc/MembershipManager.ts#L1102-L1125Note
The implementation uses
m.call.intentinstead ofintent.Supplying an
m.rtc.slotevent form.callininitial_stateon/createRoomis not currently implemented (but trivial). There is an open discussion about whether this should happen on the client or the server.