Newer
Older
Paul "LeoNerd" Evans
committed
suitably namespaced for each application and reduces the risk of clashes.
State events
Kegan Dougal
committed
------------
Paul "LeoNerd" Evans
committed
State events can be sent by ``PUT`` ing to
|/rooms/<room_id>/state/<event_type>/<state_key>|_. These events will be
overwritten if ``<room id>``, ``<event type>`` and ``<state key>`` all match.
If the state event has no ``state_key``, it can be omitted from the path. These
requests **cannot use transaction IDs** like other ``PUT`` paths because they
cannot be differentiated from the ``state_key``. Furthermore, ``POST`` is
unsupported on state paths. Valid requests look like::
Kegan Dougal
committed
Paul "LeoNerd" Evans
committed
PUT /rooms/!roomid:domain/state/m.example.event
{ "key" : "without a state key" }
Paul "LeoNerd" Evans
committed
PUT /rooms/!roomid:domain/state/m.another.example.event/foo
{ "key" : "with 'foo' as the state key" }
Paul "LeoNerd" Evans
committed
In contrast, these requests are invalid::
Paul "LeoNerd" Evans
committed
POST /rooms/!roomid:domain/state/m.example.event/
{ "key" : "cannot use POST here" }
Paul "LeoNerd" Evans
committed
PUT /rooms/!roomid:domain/state/m.another.example.event/foo/11
{ "key" : "txnIds are not supported" }
Paul "LeoNerd" Evans
committed
Care should be taken to avoid setting the wrong ``state key``::
Paul "LeoNerd" Evans
committed
PUT /rooms/!roomid:domain/state/m.another.example.event/11
{ "key" : "with '11' as the state key, but was probably intended to be a txnId" }
Paul "LeoNerd" Evans
committed
The ``state_key`` is often used to store state about individual users, by using
the user ID as the ``state_key`` value. For example::
Paul "LeoNerd" Evans
committed
PUT /rooms/!roomid:domain/state/m.favorite.animal.event/%40my_user%3Adomain.com
{ "animal" : "cat", "reason": "fluffy" }
Paul "LeoNerd" Evans
committed
In some cases, there may be no need for a ``state_key``, so it can be omitted::
Paul "LeoNerd" Evans
committed
PUT /rooms/!roomid:domain/state/m.room.bgd.color
{ "color": "red", "hex": "#ff0000" }
Paul "LeoNerd" Evans
committed
See `Room Events`_ for the ``m.`` event specification.
Paul "LeoNerd" Evans
committed
Non-state events
----------------
Non-state events can be sent by sending a request to
|/rooms/<room_id>/send/<event_type>|_. These requests *can* use transaction
IDs and ``PUT``/``POST`` methods. Non-state events allow access to historical
events and pagination, making it best suited for sending messages. For
example::
Paul "LeoNerd" Evans
committed
POST /rooms/!roomid:domain/send/m.custom.example.message
{ "text": "Hello world!" }
Paul "LeoNerd" Evans
committed
PUT /rooms/!roomid:domain/send/m.custom.example.message/11
{ "text": "Goodbye world!" }
Paul "LeoNerd" Evans
committed
See `Room Events`_ for the ``m.`` event specification.
Paul "LeoNerd" Evans
committed
Syncing rooms
-------------
.. NOTE::
This section is a work in progress.
Paul "LeoNerd" Evans
committed
When a client logs in, they may have a list of rooms which they have already
joined. These rooms may also have a list of events associated with them. The
purpose of 'syncing' is to present the current room and event information in a
convenient, compact manner. The events returned are not limited to room events;
presence events will also be returned. There are two APIs provided:
Paul "LeoNerd" Evans
committed
- |initialSync|_ : A global sync which will present room and event information
for all rooms the user has joined.
Paul "LeoNerd" Evans
committed
- |/rooms/<room_id>/initialSync|_ : A sync scoped to a single room. Presents
room and event information for this room only.
Paul "LeoNerd" Evans
committed
.. TODO-doc kegan
Paul "LeoNerd" Evans
committed
- TODO: JSON response format for both types
- TODO: when would you use global? when would you use scoped?
Paul "LeoNerd" Evans
committed
Getting events for a room
-------------------------
There are several APIs provided to ``GET`` events for a room:
Paul "LeoNerd" Evans
committed
``/rooms/<room id>/state/<event type>/<state key>``
Description:
Get the state event identified.
Response format:
A JSON object representing the state event **content**.
Example:
``/rooms/!room:domain.com/state/m.room.name`` returns ``{ "name": "Room name" }``
Paul "LeoNerd" Evans
committed
|/rooms/<room_id>/state|_
Description:
Get all state events for a room.
Response format:
``[ { state event }, { state event }, ... ]``
Example:
Paul "LeoNerd" Evans
committed
TODO-doc
Paul "LeoNerd" Evans
committed
|/rooms/<room_id>/members|_
Description:
Get all ``m.room.member`` state events.
Response format:
``{ "start": "<token>", "end": "<token>", "chunk": [ { m.room.member event }, ... ] }``
Example:
Paul "LeoNerd" Evans
committed
TODO-doc
Paul "LeoNerd" Evans
committed
|/rooms/<room_id>/messages|_
Description:
Get all ``m.room.message`` and ``m.room.member`` events. This API supports
pagination using ``from`` and ``to`` query parameters, coupled with the
``start`` and ``end`` tokens from an |initialSync|_ API.
Response format:
``{ "start": "<token>", "end": "<token>" }``
Example:
Paul "LeoNerd" Evans
committed
TODO-doc
Paul "LeoNerd" Evans
committed
|/rooms/<room_id>/initialSync|_
Description:
Get all relevant events for a room. This includes state events, paginated
non-state events and presence events.
Paul "LeoNerd" Evans
committed
Response format:
Paul "LeoNerd" Evans
committed
`` { TODO-doc } ``
Paul "LeoNerd" Evans
committed
Example:
Paul "LeoNerd" Evans
committed
TODO-doc
Since events are extensible it is possible for malicious users and/or servers
to add keys that are, for example offensive or illegal. Since some events
cannot be simply deleted, e.g. membership events, we instead 'redact' events.
This involves removing all keys from an event that are not required by the
protocol. This stripped down event is thereafter returned anytime a client or
remote server requests it.
Events that have been redacted include a ``redacted_because`` key whose value
is the event that caused it to be redacted, which may include a reason.
Redacting an event cannot be undone, allowing server owners to delete the
offending content from the databases.
Currently, only room admins can redact events by sending a ``m.room.redaction``
event, but server admins also need to be able to redact events by a similar
mechanism.
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
Upon receipt of a redaction event, the server should strip off any keys not in
the following list:
- ``event_id``
- ``type``
- ``room_id``
- ``user_id``
- ``state_key``
- ``prev_state``
- ``content``
The content object should also be stripped of all keys, unless it is one of
one of the following event types:
- ``m.room.member`` allows key ``membership``
- ``m.room.create`` allows key ``creator``
- ``m.room.join_rules`` allows key ``join_rule``
- ``m.room.power_levels`` allows keys that are user ids or ``default``
- ``m.room.add_state_level`` allows key ``level``
- ``m.room.send_event_level`` allows key ``level``
- ``m.room.ops_levels`` allows keys ``kick_level``, ``ban_level``
and ``redact_level``
- ``m.room.aliases`` allows key ``aliases``
The redaction event should be added under the key ``redacted_because``.
When a client receives a redaction event it should change the redacted event
in the same way a server does.
Paul "LeoNerd" Evans
committed
Room Events
===========
.. NOTE::
This section is a work in progress.
Paul "LeoNerd" Evans
committed
This specification outlines several standard event types, all of which are
prefixed with ``m.``
Paul "LeoNerd" Evans
committed
``m.room.name``
Summary:
Set the human-readable name for the room.
Type:
State event
JSON format:
``{ "name" : "string" }``
Example:
``{ "name" : "My Room" }``
Description:
A room has an opaque room ID which is not human-friendly to read. A room
alias is human-friendly, but not all rooms have room aliases. The room name
is a human-friendly string designed to be displayed to the end-user. The
room name is not *unique*, as multiple rooms can have the same room name
set. The room name can also be set when creating a room using |createRoom|_
with the ``name`` key.
Paul "LeoNerd" Evans
committed
``m.room.topic``
Summary:
Set a topic for the room.
Type:
State event
JSON format:
``{ "topic" : "string" }``
Example:
``{ "topic" : "Welcome to the real world." }``
Description:
A topic is a short message detailing what is currently being discussed in
the room. It can also be used as a way to display extra information about
the room, which may not be suitable for the room name. The room topic can
also be set when creating a room using |createRoom|_ with the ``topic``
key.
Paul "LeoNerd" Evans
committed
``m.room.member``
Summary:
The current membership state of a user in the room.
Type:
State event
JSON format:
``{ "membership" : "enum[ invite|join|leave|ban ]" }``
Example:
``{ "membership" : "join" }``
Description:
Adjusts the membership state for a user in a room. It is preferable to use
the membership APIs (``/rooms/<room id>/invite`` etc) when performing
membership actions rather than adjusting the state directly as there are a
restricted set of valid transformations. For example, user A cannot force
user B to join a room, and trying to force this state change directly will
fail. See the `Rooms`_ section for how to use the membership APIs.
Paul "LeoNerd" Evans
committed
``m.room.create``
Summary:
The first event in the room.
Type:
State event
JSON format:
``{ "creator": "string"}``
Example:
``{ "creator": "@user:example.com" }``
Description:
This is the first event in a room and cannot be changed. It acts as the
root of all other events.
Paul "LeoNerd" Evans
committed
``m.room.join_rules``
Summary:
Descripes how/if people are allowed to join.
Type:
State event
JSON format:
``{ "join_rule": "enum [ public|knock|invite|private ]" }``
Example:
``{ "join_rule": "public" }``
Description:
Paul "LeoNerd" Evans
committed
TODO-doc : Use docs/models/rooms.rst
Paul "LeoNerd" Evans
committed
``m.room.power_levels``
Summary:
Defines the power levels of users in the room.
Type:
State event
JSON format:
``{ "<user_id>": <int>, ..., "default": <int>}``
Example:
``{ "@user:example.com": 5, "@user2:example.com": 10, "default": 0 }``
Description:
If a user is in the list, then they have the associated power level.
Otherwise they have the default level. If not ``default`` key is supplied,
it is assumed to be 0.
Paul "LeoNerd" Evans
committed
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
``m.room.add_state_level``
Summary:
Defines the minimum power level a user needs to add state.
Type:
State event
JSON format:
``{ "level": <int> }``
Example:
``{ "level": 5 }``
Description:
To add a new piece of state to the room a user must have the given power
level. This does not apply to updating current state, which is goverened
by the ``required_power_level`` event key.
``m.room.send_event_level``
Summary:
Defines the minimum power level a user needs to send an event.
Type:
State event
JSON format:
``{ "level": <int> }``
Example:
``{ "level": 0 }``
Description:
To send a new event into the room a user must have at least this power
level. This allows ops to make the room read only by increasing this level,
or muting individual users by lowering their power level below this
threshold.
Paul "LeoNerd" Evans
committed
``m.room.ops_levels``
Summary:
Defines the minimum power levels that a user must have before they can
kick and/or ban other users.
Type:
State event
JSON format:
``{ "ban_level": <int>, "kick_level": <int>, "redact_level": <int> }``
Paul "LeoNerd" Evans
committed
Example:
``{ "ban_level": 5, "kick_level": 5 }``
Description:
This defines who can ban and/or kick people in the room. Most of the time
``ban_level`` will be greater than or equal to ``kick_level`` since
banning is more severe than kicking.
Paul "LeoNerd" Evans
committed
``m.room.aliases``
Summary:
These state events are used to inform the room about what room aliases it
has.
Type:
State event
JSON format:
``{ "aliases": ["string", ...] }``
Example:
``{ "aliases": ["#foo:example.com"] }``
Description:
A server `may` inform the room that it has added or removed an alias for
the room. This is purely for informational purposes and may become stale.
Clients `should` check that the room alias is still valid before using it.
The ``state_key`` of the event is the homeserver which owns the room alias.
Paul "LeoNerd" Evans
committed
``m.room.message``
Summary:
A message.
Type:
Non-state event
JSON format:
``{ "msgtype": "string" }``
Example:
``{ "msgtype": "m.text", "body": "Testing" }``
Description:
This event is used when sending messages in a room. Messages are not
limited to be text. The ``msgtype`` key outlines the type of message, e.g.
text, audio, image, video, etc. Whilst not required, the ``body`` key
SHOULD be used with every kind of ``msgtype`` as a fallback mechanism when
a client cannot render the message. For more information on the types of
messages which can be sent, see `m.room.message msgtypes`_.
Paul "LeoNerd" Evans
committed
``m.room.message.feedback``
Summary:
A receipt for a message.
Type:
Non-state event
JSON format:
``{ "type": "enum [ delivered|read ]", "target_event_id": "string" }``
Example:
``{ "type": "delivered", "target_event_id": "e3b2icys" }``
Description:
Feedback events are events sent to acknowledge a message in some way. There
are two supported acknowledgements: ``delivered`` (sent when the event has
been received) and ``read`` (sent when the event has been observed by the
end-user). The ``target_event_id`` should reference the ``m.room.message``
event being acknowledged.
``m.room.redaction``
Summary:
Indicates a previous event has been redacted.
Type:
Non-state event
JSON format:
``{ "reason": "string" }``
Description:
Events can be redacted by either room or server admins. Redacting an event
means that all keys not required by the protocol are stripped off, allowing
admins to remove offensive or illegal content that may have been attached
to any event. This cannot be undone, allowing server owners to physically
delete the offending data. There is also a concept of a moderator hiding a
non-state event, which can be undone, but cannot be applied to state
events.
The event that has been redacted is specified in the ``redacts`` event
level key.
Paul "LeoNerd" Evans
committed
m.room.message msgtypes
-----------------------
.. TODO-spec
How a client should handle unknown message types.
Paul "LeoNerd" Evans
committed
Each ``m.room.message`` MUST have a ``msgtype`` key which identifies the type
of message being sent. Each type has their own required and optional keys, as
outlined below:
Paul "LeoNerd" Evans
committed
``m.text``
Required keys:
- ``body`` : "string" - The body of the message.
Optional keys:
None.
Example:
``{ "msgtype": "m.text", "body": "I am a fish" }``
Paul "LeoNerd" Evans
committed
``m.emote``
Required keys:
- ``body`` : "string" - The emote action to perform.
Optional keys:
None.
Example:
``{ "msgtype": "m.emote", "body": "tries to come up with a witty explanation" }``
Paul "LeoNerd" Evans
committed
``m.image``
Required keys:
- ``url`` : "string" - The URL to the image.
Optional keys:
- ``info`` : "string" - info : JSON object (ImageInfo) - The image info for
image referred to in ``url``.
- ``thumbnail_url`` : "string" - The URL to the thumbnail.
- ``thumbnail_info`` : JSON object (ImageInfo) - The image info for the
image referred to in ``thumbnail_url``.
- ``body`` : "string" - The alt text of the image, or some kind of content
description for accessibility e.g. "image attachment".
Paul "LeoNerd" Evans
committed
ImageInfo:
Information about an image::
{
"size" : integer (size of image in bytes),
"w" : integer (width of image in pixels),
"h" : integer (height of image in pixels),
"mimetype" : "string (e.g. image/jpeg)",
}
Paul "LeoNerd" Evans
committed
``m.audio``
Required keys:
- ``url`` : "string" - The URL to the audio.
Optional keys:
- ``info`` : JSON object (AudioInfo) - The audio info for the audio
referred to in ``url``.
- ``body`` : "string" - A description of the audio e.g. "Bee Gees - Stayin'
Alive", or some kind of content description for accessibility e.g.
"audio attachment".
AudioInfo:
Information about a piece of audio::
Paul "LeoNerd" Evans
committed
{
"mimetype" : "string (e.g. audio/aac)",
"size" : integer (size of audio in bytes),
"duration" : integer (duration of audio in milliseconds),
}
Paul "LeoNerd" Evans
committed
``m.video``
Required keys:
- ``url`` : "string" - The URL to the video.
Optional keys:
- ``info`` : JSON object (VideoInfo) - The video info for the video
referred to in ``url``.
- ``body`` : "string" - A description of the video e.g. "Gangnam style", or
some kind of content description for accessibility e.g. "video
attachment".
Paul "LeoNerd" Evans
committed
VideoInfo:
Information about a video::
Paul "LeoNerd" Evans
committed
{
"mimetype" : "string (e.g. video/mp4)",
"size" : integer (size of video in bytes),
"duration" : integer (duration of video in milliseconds),
"w" : integer (width of video in pixels),
"h" : integer (height of video in pixels),
"thumbnail_url" : "string (URL to image)",
"thumbanil_info" : JSON object (ImageInfo)
}
Paul "LeoNerd" Evans
committed
``m.location``
Required keys:
- ``geo_uri`` : "string" - The geo URI representing the location.
Optional keys:
- ``thumbnail_url`` : "string" - The URL to a thumnail of the location
being represented.
- ``thumbnail_info`` : JSON object (ImageInfo) - The image info for the
image referred to in ``thumbnail_url``.
- ``body`` : "string" - A description of the location e.g. "Big Ben,
London, UK", or some kind of content description for accessibility e.g.
"location attachment".
Paul "LeoNerd" Evans
committed
The following keys can be attached to any ``m.room.message``:
Paul "LeoNerd" Evans
committed
Optional keys:
- ``sender_ts`` : integer - A timestamp (ms resolution) representing the
wall-clock time when the message was sent from the client.
Paul "LeoNerd" Evans
committed
Presence
========
.. NOTE::
This section is a work in progress.
Paul "LeoNerd" Evans
committed
Each user has the concept of presence information. This encodes the
"availability" of that user, suitable for display on other user's clients. This
is transmitted as an ``m.presence`` event and is one of the few events which
are sent *outside the context of a room*. The basic piece of presence
information is represented by the ``presence`` key, which is an enum of one of
the following:
Paul "LeoNerd" Evans
committed
- ``online`` : The default state when the user is connected to an event
stream.
- ``unavailable`` : The user is not reachable at this time.
- ``offline`` : The user is not connected to an event stream.
- ``free_for_chat`` : The user is generally willing to receive messages
moreso than default.
Paul "LeoNerd" Evans
committed
- ``hidden`` : Behaves as offline, but allows the user to see the client
state anyway and generally interact with client features. (Not yet
implemented in synapse).
Paul "LeoNerd" Evans
committed
This basic ``presence`` field applies to the user as a whole, regardless of how
many client devices they have connected. The home server should synchronise
this status choice among multiple devices to ensure the user gets a consistent
experience.
Paul "LeoNerd" Evans
committed
In addition, the server maintains a timestamp of the last time it saw an active
action from the user; either sending a message to a room, or changing presence
state from a lower to a higher level of availability (thus: changing state from
``unavailable`` to ``online`` will count as an action for being active, whereas
in the other direction will not). This timestamp is presented via a key called
``last_active_ago``, which gives the relative number of miliseconds since the
message is generated/emitted, that the user was last seen active.
Paul "LeoNerd" Evans
committed
Home servers can also use the user's choice of presence state as a signal for
how to handle new private one-to-one chat message requests. For example, it
might decide:
- ``free_for_chat`` : accept anything
- ``online`` : accept from anyone in my addres book list
- ``busy`` : accept from anyone in this "important people" group in my
address book list
Paul "LeoNerd" Evans
committed
Presence List
-------------
Each user's home server stores a "presence list" for that user. This stores a
list of other user IDs the user has chosen to add to it. To be added to this
list, the user being added must receive permission from the list owner. Once
granted, both user's HS(es) store this information. Since such subscriptions
are likely to be bidirectional, HSes may wish to automatically accept requests
when a reverse subscription already exists.
Paul "LeoNerd" Evans
committed
As a convenience, presence lists should support the ability to collect users
into groups, which could allow things like inviting the entire group to a new
("ad-hoc") chat room, or easy interaction with the profile information ACL
implementation of the HS.
Paul "LeoNerd" Evans
committed
Presence and Permissions
------------------------
For a viewing user to be allowed to see the presence information of a target
user, either:
Paul "LeoNerd" Evans
committed
- The target user has allowed the viewing user to add them to their presence
list, or
- The two users share at least one room in common
Paul "LeoNerd" Evans
committed
In the latter case, this allows for clients to display some minimal sense of
presence information in a user list for a room.
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
Client API
----------
The client API for presence is on the following set of REST calls.
Fetching basic status::
GET $PREFIX/presence/:user_id/status
Returned content: JSON object containing the following keys:
presence: "offline"|"unavailable"|"online"|"free_for_chat"
status_msg: (optional) string of freeform text
last_active_ago: miliseconds since the last activity by the user
Setting basic status::
PUT $PREFIX/presence/:user_id/status
Content: JSON object containing the following keys:
presence and status_msg: as above
When setting the status, the activity time is updated to reflect that activity;
the client does not need to specify the ``last_active_ago`` field.
Fetching the presence list::
GET $PREFIX/presence/list
Returned content: JSON array containing objects; each object containing the
following keys:
user_id: observed user ID
presence: "offline"|"unavailable"|"online"|"free_for_chat"
status_msg: (optional) string of freeform text
last_active_ago: miliseconds since the last activity by the user
Maintaining the presence list::
POST $PREFIX/presence/list
Content: JSON object containing either or both of the following keys:
invite: JSON array of strings giving user IDs to send invites to
drop: JSON array of strings giving user IDs to remove from the list
.. TODO-spec
- Define how users receive presence invites, and how they accept/decline them
Server API
----------
The server API for presence is based entirely on exchange of the following
EDUs. There are no PDUs or Federation Queries involved.
Performing a presence update and poll subscription request::
EDU type: m.presence
Content keys:
push: (optional): list of push operations.
Each should be an object with the following keys:
user_id: string containing a User ID
presence: "offline"|"unavailable"|"online"|"free_for_chat"
status_msg: (optional) string of freeform text
last_active_ago: miliseconds since the last activity by the user
poll: (optional): list of strings giving User IDs
unpoll: (optional): list of strings giving User IDs
The presence of this combined message is two-fold: it informs the recipient
server of the current status of one or more users on the sending server (by the
``push`` key), and it maintains the list of users on the recipient server that
the sending server is interested in receiving updates for, by adding (by the
``poll`` key) or removing them (by the ``unpoll`` key). The ``poll`` and
``unpoll`` lists apply *changes* to the implied list of users; any existing IDs
that the server sent as ``poll`` operations in a previous message are not
removed until explicitly requested by a later ``unpoll``.
On receipt of a message containing a non-empty ``poll`` list, the receiving
server should immediately send the sending server a presence update EDU of its
own, containing in a ``push`` list the current state of every user that was in
the orginal EDU's ``poll`` list.
Sending a presence invite::
EDU type: m.presence_invite
Content keys:
observed_user: string giving the User ID of the user whose presence is
requested (i.e. the recipient of the invite)
observer_user: string giving the User ID of the user who is requesting to
observe the presence (i.e. the sender of the invite)
Accepting a presence invite::
EDU type: m.presence_accept
Content keys - as for m.presence_invite
Rejecting a presence invite::
EDU type: m.presence_deny
Content keys - as for m.presence_invite
.. TODO-doc
- Explain the timing-based roundtrip reduction mechanism for presence
messages
- Explain the zero-byte presence inference logic
See also: docs/client-server/model/presence
Paul "LeoNerd" Evans
committed
Paul "LeoNerd" Evans
committed
Voice over IP
=============
Matrix can also be used to set up VoIP calls. This is part of the core
specification, although is still in a very early stage. Voice (and video) over
Matrix is based on the WebRTC standards.
Paul "LeoNerd" Evans
committed
Call events are sent to a room, like any other event. This means that clients
must only send call events to rooms with exactly two participants as currently
the WebRTC standard is based around two-party communication.
Paul "LeoNerd" Evans
committed
Events
------
``m.call.invite``
This event is sent by the caller when they wish to establish a call.
Paul "LeoNerd" Evans
committed
Required keys:
- ``call_id`` : "string" - A unique identifier for the call
- ``offer`` : "offer object" - The session description
- ``version`` : "integer" - The version of the VoIP specification this
message adheres to. This specification is version 0.
- ``lifetime`` : "integer" - The time in milliseconds that the invite is
valid for. Once the invite age exceeds this value, clients should discard
it. They should also no longer show the call as awaiting an answer in the
UI.
Optional keys:
None.
Example:
``{ "version" : 0, "call_id": "12345", "offer": { "type" : "offer", "sdp" : "v=0\r\no=- 6584580628695956864 2 IN IP4 127.0.0.1[...]" } }``
Paul "LeoNerd" Evans
committed
``Offer Object``
Required keys:
- ``type`` : "string" - The type of session description, in this case
'offer'
- ``sdp`` : "string" - The SDP text of the session description
Paul "LeoNerd" Evans
committed
``m.call.candidates``
This event is sent by callers after sending an invite and by the callee after
answering. Its purpose is to give the other party additional ICE candidates to
try using to communicate.
Paul "LeoNerd" Evans
committed
Required keys:
- ``call_id`` : "string" - The ID of the call this event relates to
- ``version`` : "integer" - The version of the VoIP specification this
messages adheres to. his specification is version 0.
- ``candidates`` : "array of candidate objects" - Array of object
describing the candidates.
Paul "LeoNerd" Evans
committed
``Candidate Object``
Paul "LeoNerd" Evans
committed
Required Keys:
- ``sdpMid`` : "string" - The SDP media type this candidate is intended
for.
- ``sdpMLineIndex`` : "integer" - The index of the SDP 'm' line this
candidate is intended for
- ``candidate`` : "string" - The SDP 'a' line of the candidate
Paul "LeoNerd" Evans
committed
``m.call.answer``
Paul "LeoNerd" Evans
committed
Required keys:
- ``call_id`` : "string" - The ID of the call this event relates to
- ``version`` : "integer" - The version of the VoIP specification this
messages
- ``answer`` : "answer object" - Object giving the SDK answer
Paul "LeoNerd" Evans
committed
``Answer Object``
Paul "LeoNerd" Evans
committed
Required keys:
- ``type`` : "string" - The type of session description. 'answer' in this
case.
- ``sdp`` : "string" - The SDP text of the session description
Paul "LeoNerd" Evans
committed
``m.call.hangup``
Sent by either party to signal their termination of the call. This can be sent
either once the call has has been established or before to abort the call.
Paul "LeoNerd" Evans
committed
Required keys:
- ``call_id`` : "string" - The ID of the call this event relates to
- ``version`` : "integer" - The version of the VoIP specification this
messages
Paul "LeoNerd" Evans
committed
Message Exchange
----------------
A call is set up with messages exchanged as follows:
Paul "LeoNerd" Evans
committed
::
Paul "LeoNerd" Evans
committed
Caller Callee
m.call.invite ----------->
m.call.candidate -------->
[more candidates events]
User answers call
<------ m.call.answer
[...]
<------ m.call.hangup
Or a rejected call:
Paul "LeoNerd" Evans
committed
::
Paul "LeoNerd" Evans
committed
Caller Callee
m.call.invite ----------->
m.call.candidate -------->
[more candidates events]
User rejects call
<------- m.call.hangup
Paul "LeoNerd" Evans
committed
Calls are negotiated according to the WebRTC specification.
Paul "LeoNerd" Evans
committed
Glare
-----
This specification aims to address the problem of two users calling each other
at roughly the same time and their invites crossing on the wire. It is a far
better experience for the users if their calls are connected if it is clear
that their intention is to set up a call with one another.
Paul "LeoNerd" Evans
committed
In Matrix, calls are to rooms rather than users (even if those rooms may only
contain one other user) so we consider calls which are to the same room.
Paul "LeoNerd" Evans
committed
The rules for dealing with such a situation are as follows:
Paul "LeoNerd" Evans
committed
- If an invite to a room is received whilst the client is preparing to send an
invite to the same room, the client should cancel its outgoing call and
instead automatically accept the incoming call on behalf of the user.
- If an invite to a room is received after the client has sent an invite to
the same room and is waiting for a response, the client should perform a
lexicographical comparison of the call IDs of the two calls and use the
lesser of the two calls, aborting the greater. If the incoming call is the
lesser, the client should accept this call on behalf of the user.
Paul "LeoNerd" Evans
committed
The call setup should appear seamless to the user as if they had simply placed
a call and the other party had accepted. Thusly, any media stream that had been
setup for use on a call should be transferred and used for the call that
replaces it.
Paul "LeoNerd" Evans
committed
Paul "LeoNerd" Evans
committed
Profiles
========
.. NOTE::
This section is a work in progress.
Paul "LeoNerd" Evans
committed
- Metadata extensibility
Paul "LeoNerd" Evans
committed
Internally within Matrix users are referred to by their user ID, which is
typically a compact unique identifier. Profiles grant users the ability to see
human-readable names for other users that are in some way meaningful to them.
Additionally, profiles can publish additional information, such as the user's
age or location.
A Profile consists of a display name, an avatar picture, and a set of other
metadata fields that the user may wish to publish (email address, phone
numbers, website URLs, etc...). This specification puts no requirements on the
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
display name other than it being a valid unicode string. Avatar images are not
stored directly; instead the home server stores an ``http``-scheme URL where
clients may fetch it from.
Client API
----------
The client API for profile management consists of the following REST calls.
Fetching a user account displayname::
GET $PREFIX/profile/:user_id/displayname
Returned content: JSON object containing the following keys:
displayname: string of freeform text
This call may be used to fetch the user's own displayname or to query the name
of other users; either locally or on remote systems hosted on other home
servers.
Setting a new displayname::
PUT $PREFIX/profile/:user_id/displayname
Content: JSON object containing the following keys:
displayname: string of freeform text
Fetching a user account avatar URL::
GET $PREFIX/profile/:user_id/avatar_url
Returned content: JSON object containing the following keys:
avatar_url: string containing an http-scheme URL
As with displayname, this call may be used to fetch either the user's own, or
other users' avatar URL.
Setting a new avatar URL::
PUT $PREFIX/profile/:user_id/avatar_url
Content: JSON object containing the following keys:
avatar_url: string containing an http-scheme URL
Fetching combined account profile information::
GET $PREFIX/profile/:user_id
Returned content: JSON object containing the following keys:
displayname: string of freeform text
avatar_url: string containing an http-scheme URL
At the current time, this API simply returns the displayname and avatar URL
information, though it is intended to return more fields about the user's
profile once they are defined. Client implementations should take care not to
expect that these are the only two keys returned as future versions of this
specification may yield more keys here.
Server API
----------
The server API for profiles is based entirely on the following Federation
Queries. There are no additional EDU or PDU types involved, other than the
implicit ``m.presence`` and ``m.room.member`` events (see section below).
Querying profile information::
Query type: profile
Arguments:
user_id: the ID of the user whose profile to return
field: (optional) string giving a field name
Returns: JSON object containing the following keys:
displayname: string of freeform text
avatar_url: string containing an http-scheme URL
If the query contains the optional ``field`` key, it should give the name of a
result field. If such is present, then the result should contain only a field
of that name, with no others present. If not, the result should contain as much
of the user's profile as the home server has available and can make public.
Events on Change of Profile Information
---------------------------------------
Because the profile displayname and avatar information are likely to be used in
many places of a client's display, changes to these fields cause an automatic
propagation event to occur, informing likely-interested parties of the new
values. This change is conveyed using two separate mechanisms:
- a ``m.room.member`` event is sent to every room the user is a member of,
to update the ``displayname`` and ``avatar_url``.
- a presence status update is sent, again containing the new values of the
``displayname`` and ``avatar_url`` keys, in addition to the required
``presence`` key containing the current presence state of the user.
Both of these should be done automatically by the home server when a user
successfully changes their displayname or avatar URL fields.
Additionally, when home servers emit room membership events for their own
users, they should include the displayname and avatar URL fields in these
events so that clients already have these details to hand, and do not have to
perform extra roundtrips to query it.
Identity
========
.. NOTE::
This section is a work in progress.
Paul "LeoNerd" Evans
committed
.. TODO-doc Dave
- 3PIDs and identity server, functions
Paul "LeoNerd" Evans
committed
Federation
==========
Federation is the term used to describe how to communicate between Matrix home
servers. Federation is a mechanism by which two home servers can exchange
Matrix event messages, both as a real-time push of current events, and as a
historic fetching mechanism to synchronise past history for clients to view. It
uses HTTPS connections between each pair of servers involved as the underlying
transport. Messages are exchanged between servers in real-time by active
pushing from each server's HTTP client into the server of the other. Queries to
fetch historic data for the purpose of back-filling scrollback buffers and the
like can also be performed. Currently routing of messages between homeservers
is full mesh (like email) - however, fan-out refinements to this design are
currently under consideration.
There are three main kinds of communication that occur between home servers:
Kegan Dougal
committed
:Queries:
These are single request/response interactions between a given pair of
servers, initiated by one side sending an HTTPS GET request to obtain some
information, and responded by the other. They are not persisted and contain
no long-term significant history. They simply request a snapshot state at
the instant the query is made.
Kegan Dougal
committed
:Ephemeral Data Units (EDUs):
These are notifications of events that are pushed from one home server to
another. They are not persisted and contain no long-term significant
history, nor does the receiving home server have to reply to them.
Kegan Dougal
committed
:Persisted Data Units (PDUs):
These are notifications of events that are broadcast from one home server to
any others that are interested in the same "context" (namely, a Room ID).
They are persisted to long-term storage and form the record of history for
that context.
EDUs and PDUs are further wrapped in an envelope called a Transaction, which is
transferred from the origin to the destination home server using an HTTP PUT
request.
Kegan Dougal
committed
Transactions
------------
.. WARNING::
This section may be misleading or inaccurate.
The transfer of EDUs and PDUs between home servers is performed by an exchange
of Transaction messages, which are encoded as JSON objects, passed over an HTTP
PUT request. A Transaction is meaningful only to the pair of home servers that
Kegan Dougal
committed
exchanged it; they are not globally-meaningful.
Kegan Dougal
committed
Each transaction has:
- An opaque transaction ID.
- A timestamp (UNIX epoch time in milliseconds) generated by its origin
server.
Kegan Dougal
committed
- An origin and destination server name.
- A list of "previous IDs".
- A list of PDUs and EDUs - the actual message payload that the Transaction
carries.
``origin``
Type:
String