summary refs log tree commit diff
path: root/docs
diff options
context:
space:
mode:
authorKegan Dougal <kegan@matrix.org>2014-10-09 11:08:06 +0100
committerKegan Dougal <kegan@matrix.org>2014-10-09 11:08:06 +0100
commitd224358e21765d42e53674b2078f889dcb28ffb5 (patch)
tree6f49d0d7144f195d3e09f69aba2166b9e340e2a8 /docs
parentFix unit test. (diff)
downloadsynapse-d224358e21765d42e53674b2078f889dcb28ffb5.tar.xz
Restructure specification sections.
Diffstat (limited to 'docs')
-rw-r--r--docs/specification.rst1672
1 files changed, 835 insertions, 837 deletions
diff --git a/docs/specification.rst b/docs/specification.rst
index 84722aa281..9f7c86f21c 100644
--- a/docs/specification.rst
+++ b/docs/specification.rst
@@ -19,9 +19,6 @@ WARNING
 .. contents:: Table of Contents
 .. sectnum::
 
-Introduction
-============
-
 Matrix is a new set of open APIs for open-federated Instant Messaging and VoIP
 functionality, designed to create and support a new global real-time
 communication ecosystem on the internet. This specification is the ongoing
@@ -83,9 +80,11 @@ instant messages, VoIP call setups, or any other objects that need to be
 reliably and persistently pushed from A to B in an interoperable and federated
 manner.
 
+Basis
+=====
 
 Architecture
-============
+------------
 
 Clients transmit data to other clients through home servers (HSes). Clients do
 not communicate with each other directly.
@@ -137,7 +136,7 @@ for events defined in the Matrix specification. Events are usually sent in the
 context of a "Room".
 
 Room structure
---------------
+~~~~~~~~~~~~~~
 
 A room is a conceptual place where users can send and receive events. Rooms can
 be created, joined and left. Events are sent to a room, and all participants in
@@ -183,7 +182,7 @@ if that means the home server has to request more information from another home
 server before processing the event.
 
 Room Aliases
-------------
+~~~~~~~~~~~~
 
 Each room can also have multiple "Room Aliases", which looks like::
 
@@ -218,7 +217,7 @@ that are in the room that can be used to join via.
    |________________________________|
        
 Identity
---------
+~~~~~~~~
 
 Users in Matrix are identified via their user ID. However, existing ID
 namespaces can also be used in order to identify Matrix users. A Matrix
@@ -240,6 +239,97 @@ Usage of an IS is not required in order for a client application to be part of
 the Matrix ecosystem. However, without one clients will not be able to look up
 user IDs using 3PIDs.
 
+Presence
+~~~~~~~~
+.. NOTE::
+  This section is a work in progress.
+
+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:
+
+  - ``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.
+  - ``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).
+
+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.
+
+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.
+
+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
+
+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.
+
+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.
+
+Presence and Permissions
+++++++++++++++++++++++++
+For a viewing user to be allowed to see the presence information of a target
+user, either:
+
+ - 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
+
+In the latter case, this allows for clients to display some minimal sense of
+presence information in a user list for a room.
+
+Profiles
+~~~~~~~~
+.. NOTE::
+  This section is a work in progress.
+
+.. TODO-spec
+  - Metadata extensibility
+
+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
+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.
+
 API Standards
 -------------
 
@@ -354,6 +444,89 @@ In contrast, these are invalid requests::
       "key": "This is a put but it is missing a txnId."
     }
 
+Glossary
+--------
+.. NOTE::
+  This section is a work in progress.
+
+Backfilling:
+  The process of synchronising historic state from one home server to another,
+  to backfill the event storage so that scrollback can be presented to the
+  client(s). Not to be confused with pagination.
+
+Context:
+  A single human-level entity of interest (currently, a chat room)
+
+EDU (Ephemeral Data Unit):
+  A message that relates directly to a given pair of home servers that are
+  exchanging it. EDUs are short-lived messages that related only to one single
+  pair of servers; they are not persisted for a long time and are not forwarded
+  on to other servers. Because of this, they have no internal ID nor previous
+  EDUs reference chain.
+
+Event:
+  A record of activity that records a single thing that happened on to a context
+  (currently, a chat room). These are the "chat messages" that Synapse makes
+  available.
+
+PDU (Persistent Data Unit):
+  A message that relates to a single context, irrespective of the server that
+  is communicating it. PDUs either encode a single Event, or a single State
+  change. A PDU is referred to by its PDU ID; the pair of its origin server
+  and local reference from that server.
+
+PDU ID:
+  The pair of PDU Origin and PDU Reference, that together globally uniquely
+  refers to a specific PDU.
+
+PDU Origin:
+  The name of the origin server that generated a given PDU. This may not be the
+  server from which it has been received, due to the way they are copied around
+  from server to server. The origin always records the original server that
+  created it.
+
+PDU Reference:
+  A local ID used to refer to a specific PDU from a given origin server. These
+  references are opaque at the protocol level, but may optionally have some
+  structured meaning within a given origin server or implementation.
+
+Presence:
+  The concept of whether a user is currently online, how available they declare
+  they are, and so on. See also: doc/model/presence
+
+Profile:
+  A set of metadata about a user, such as a display name, provided for the
+  benefit of other users. See also: doc/model/profiles
+
+Room ID:
+  An opaque string (of as-yet undecided format) that identifies a particular
+  room and used in PDUs referring to it.
+
+Room Alias:
+  A human-readable string of the form #name:some.domain that users can use as a
+  pointer to identify a room; a Directory Server will map this to its Room ID
+
+State:
+  A set of metadata maintained about a Context, which is replicated among the
+  servers in addition to the history of Events.
+
+User ID:
+  A string of the form @localpart:domain.name that identifies a user for
+  wire-protocol purposes. The localpart is meaningless outside of a particular
+  home server. This takes a human-readable form that end-users can use directly
+  if they so wish, avoiding the 3PIDs.
+
+Transaction:
+  A message which relates to the communication between a given pair of servers.
+  A transaction contains possibly-empty lists of PDUs and EDUs.
+
+.. TODO
+  This glossary contradicts the terms used above - especially on State Events v. "State"
+  and Non-State Events v. "Events".  We need better consistent names.
+
+Events
+======
+
 Receiving live updates on a client
 ----------------------------------
 
@@ -374,9 +547,505 @@ When the client first logs in, they will need to initially synchronise with
 their home server. This is achieved via the |initialSync|_ API. This API also
 returns an ``end`` token which can be used with the event stream.
 
+Room Events
+-----------
+.. NOTE::
+  This section is a work in progress.
+
+This specification outlines several standard event types, all of which are
+prefixed with ``m.``
+
+``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.
+
+``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.
+
+``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.
+
+``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.
+
+``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:
+    TODO-doc : Use docs/models/rooms.rst
+   
+``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.
+
+``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.
+
+``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> }``
+  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.
+
+``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:
+    This event is sent by a homeserver directly to inform of changes to the
+    list of aliases it knows about for that room. As a special-case, the
+    ``state_key`` of the event is the homeserver which owns the room alias.
+    For example, an event might look like::
+
+      {
+        "type": "m.room.aliases",
+        "event_id": "012345678ab",
+        "room_id": "!xAbCdEfG:example.com",
+        "state_key": "example.com",
+        "content": {
+          "aliases": ["#foo:example.com"]
+        }
+      }
+
+    The event contains the full list of aliases now stored by the home server
+    that emitted it; additions or deletions are not explicitly mentioned as
+    being such. The entire set of known aliases for the room is then the union
+    of the individual lists declared by all such keys, one from each home
+    server holding at least one alias.
+
+    Clients `should` check the validity of any room alias given in this list
+    before presenting it to the user as trusted fact. The lists given by this
+    event should be considered simply as advice on which aliases might exist,
+    for which the client can perform the lookup to confirm whether it receives
+    the correct room ID.
+
+``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`_.
+
+``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.
+
+m.room.message msgtypes
+~~~~~~~~~~~~~~~~~~~~~~~
+
+.. TODO-spec
+   How a client should handle unknown message types.
+
+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:
+
+``m.text``
+  Required keys:
+    - ``body`` : "string" - The body of the message.
+  Optional keys:
+    None.
+  Example:
+    ``{ "msgtype": "m.text", "body": "I am a fish" }``
+
+``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" }``
+
+``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".
+
+  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)",
+      }
+
+``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::
+
+      {
+        "mimetype" : "string (e.g. audio/aac)",
+        "size" : integer (size of audio in bytes),
+        "duration" : integer (duration of audio in milliseconds),
+      }
+
+``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".
+
+  VideoInfo: 
+    Information about a video::
+
+      {
+        "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)
+      }
+
+``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".
+
+The following keys can be attached to any ``m.room.message``:
+
+  Optional keys:
+    - ``sender_ts`` : integer - A timestamp (ms resolution) representing the
+      wall-clock time when the message was sent from the client.
+
+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.
+
+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.
+
+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.
+
+Events
+~~~~~~
+``m.call.invite``
+This event is sent by the caller when they wish to establish a call.
+
+  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[...]" } }``
+
+``Offer Object``
+  Required keys:
+    - ``type`` : "string" - The type of session description, in this case
+      'offer'
+    - ``sdp`` : "string" - The SDP text of the session description
+
+``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.
+
+  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.
+
+``Candidate Object``
+
+  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
+
+``m.call.answer``
+
+  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
+
+``Answer Object``
+
+  Required keys:
+    - ``type`` : "string" - The type of session description. 'answer' in this
+      case.
+    - ``sdp`` : "string" - The SDP text of the session description
+
+``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.
+
+  Required keys:
+    - ``call_id`` : "string" - The ID of the call this event relates to
+    - ``version`` : "integer" - The version of the VoIP specification this
+      messages
+
+Message Exchange
+~~~~~~~~~~~~~~~~
+A call is set up with messages exchanged as follows:
+
+::
+
+   Caller                   Callee
+ m.call.invite ----------->
+ m.call.candidate -------->
+ [more candidates events]
+                         User answers call
+                  <------ m.call.answer
+               [...]
+                  <------ m.call.hangup
+                  
+Or a rejected call:
+
+::
+
+   Caller                   Callee
+ m.call.invite ----------->
+ m.call.candidate -------->
+ [more candidates events]
+                        User rejects call
+                 <------- m.call.hangup
+
+Calls are negotiated according to the WebRTC specification.
+
+
+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.
+
+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.
+
+The rules for dealing with such a situation are as follows:
+
+ - 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.
+
+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.
+
+Client-Server API
+=================
 
 Registration and Login
-======================
+----------------------
 
 Clients must register with a home server in order to use Matrix. After
 registering, the client will be given an access token which must be used in ALL
@@ -462,7 +1131,7 @@ This specification defines the following login types:
  - ``m.login.email.identity``
 
 Password-based
---------------
+~~~~~~~~~~~~~~
 :Type: 
   ``m.login.password``
 :Description: 
@@ -480,7 +1149,7 @@ The home server MUST respond with either new credentials, the next stage of the
 login process, or a standard error response.
 
 OAuth2-based
-------------
+~~~~~~~~~~~~
 :Type: 
   ``m.login.oauth2``
 :Description:
@@ -533,7 +1202,7 @@ visits the REDIRECT_URI with the auth code= query parameter which returns::
   }
 
 Email-based (code)
-------------------
+~~~~~~~~~~~~~~~~~~
 :Type: 
   ``m.login.email.code``
 :Description:
@@ -569,7 +1238,7 @@ The home server MUST respond to this with either new credentials, the next
 stage of the login process, or a standard error response.
 
 Email-based (url)
------------------
+~~~~~~~~~~~~~~~~~
 :Type: 
   ``m.login.email.url``
 :Description:
@@ -609,7 +1278,7 @@ an errcode of ``M_LOGIN_EMAIL_URL_NOT_YET`` should be returned.
 
 
 Email-based (identity server)
------------------------------
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 :Type:
   ``m.login.email.identity``
 :Description:
@@ -635,7 +1304,7 @@ To respond to this type, reply with::
 
 
 N-Factor Authentication
------------------------
+~~~~~~~~~~~~~~~~~~~~~~~
 Multiple login stages can be combined to create N-factor authentication during
 login.
 
@@ -686,7 +1355,7 @@ This can be represented conceptually as::
   |_______________________|
 
 Fallback
---------
+~~~~~~~~
 Clients cannot be expected to be able to know how to process every single login
 type. If a client determines it does not know how to handle a given login type,
 it should request a login fallback page::
@@ -697,10 +1366,10 @@ This MUST return an HTML page which can perform the entire login process.
 
 
 Rooms
-=====
+-----
 
 Creation
---------
+~~~~~~~~
 To create a room, a client has to use the |createRoom|_ API. There are various
 options which can be set when creating a room:
 
@@ -790,7 +1459,7 @@ includes:
 See `Room Events`_ for more information on these events.
 
 Room aliases
-------------
+~~~~~~~~~~~~
 .. NOTE::
   This section is a work in progress.
 
@@ -833,7 +1502,7 @@ their own by using the federation API to ask other domain name home servers.
 
 
 Permissions
------------
+~~~~~~~~~~~
 .. NOTE::
   This section is a work in progress.
 
@@ -874,7 +1543,7 @@ defined in the following state events:
 
 
 Joining rooms
--------------
+~~~~~~~~~~~~~
 .. TODO-doc What does the home server have to do to join a user to a room?
    -  See SPEC-30.
 
@@ -912,7 +1581,7 @@ room. Other rooms will allow anyone to join the room even if they have not
 received an invite.
 
 Inviting users
---------------
+~~~~~~~~~~~~~~
 .. TODO-doc Invite-join dance 
   - Outline invite join dance. What is it? Why is it required? How does it work?
   - What does the home server have to do?
@@ -951,7 +1620,7 @@ directly by sending the following request to
 See the `Room events`_ section for more information on ``m.room.member``.
 
 Leaving rooms
--------------
+~~~~~~~~~~~~~
 .. TODO-spec - HS deleting rooms they are no longer a part of. Not implemented.
   - This is actually Very Tricky. If all clients a HS is serving leave a room,
   the HS will no longer get any new events for that room, because the servers
@@ -986,7 +1655,7 @@ Once a user has left a room, that room will no longer appear on the
 If all members in a room leave, that room becomes eligible for deletion. 
 
 Banning users in a room
------------------------
+~~~~~~~~~~~~~~~~~~~~~~~
 A user may decide to ban another user in a room. 'Banning' forces the target
 user to leave the room and prevents them from re-joining the room. A banned
 user will not be treated as a joined user, and so will not be able to send or
@@ -1010,7 +1679,7 @@ member's state, by making a request to
   }
 
 Events in a room
-----------------
+~~~~~~~~~~~~~~~~
 Room events can be split into two categories:
 
 :State Events:
@@ -1034,7 +1703,7 @@ convention, e.g. ``com.example.myapp.event``.  This ensures event types are
 suitably namespaced for each application and reduces the risk of clashes.
 
 State events
-------------
+~~~~~~~~~~~~
 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.
@@ -1076,7 +1745,7 @@ In some cases, there may be no need for a ``state_key``, so it can be omitted::
 See `Room Events`_ for the ``m.`` event specification.
 
 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
@@ -1092,7 +1761,7 @@ example::
 See `Room Events`_ for the ``m.`` event specification.
 
 Syncing rooms
--------------
+~~~~~~~~~~~~~
 .. NOTE::
   This section is a work in progress.
 
@@ -1155,7 +1824,7 @@ Room Information:
         A JSON array containing all the current state events for this room.
 
 Getting events for a room
--------------------------
+~~~~~~~~~~~~~~~~~~~~~~~~~
 There are several APIs provided to ``GET`` events for a room:
 
 ``/rooms/<room id>/state/<event type>/<state key>``
@@ -1203,7 +1872,7 @@ There are several APIs provided to ``GET`` events for a room:
     TODO-doc
 
 Redactions
-----------
+~~~~~~~~~~
 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.
@@ -1251,416 +1920,8 @@ 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.
 
-
-Room Events
-===========
-.. NOTE::
-  This section is a work in progress.
-
-This specification outlines several standard event types, all of which are
-prefixed with ``m.``
-
-``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.
-
-``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.
-
-``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.
-
-``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.
-
-``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:
-    TODO-doc : Use docs/models/rooms.rst
-   
-``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.
-
-``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.
-
-``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> }``
-  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.
-
-``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:
-    This event is sent by a homeserver directly to inform of changes to the
-    list of aliases it knows about for that room. As a special-case, the
-    ``state_key`` of the event is the homeserver which owns the room alias.
-    For example, an event might look like::
-
-      {
-        "type": "m.room.aliases",
-        "event_id": "012345678ab",
-        "room_id": "!xAbCdEfG:example.com",
-        "state_key": "example.com",
-        "content": {
-          "aliases": ["#foo:example.com"]
-        }
-      }
-
-    The event contains the full list of aliases now stored by the home server
-    that emitted it; additions or deletions are not explicitly mentioned as
-    being such. The entire set of known aliases for the room is then the union
-    of the individual lists declared by all such keys, one from each home
-    server holding at least one alias.
-
-    Clients `should` check the validity of any room alias given in this list
-    before presenting it to the user as trusted fact. The lists given by this
-    event should be considered simply as advice on which aliases might exist,
-    for which the client can perform the lookup to confirm whether it receives
-    the correct room ID.
-
-``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`_.
-
-``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.
-
-m.room.message msgtypes
------------------------
-
-.. TODO-spec
-   How a client should handle unknown message types.
-
-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:
-
-``m.text``
-  Required keys:
-    - ``body`` : "string" - The body of the message.
-  Optional keys:
-    None.
-  Example:
-    ``{ "msgtype": "m.text", "body": "I am a fish" }``
-
-``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" }``
-
-``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".
-
-  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)",
-      }
-
-``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::
-
-      {
-        "mimetype" : "string (e.g. audio/aac)",
-        "size" : integer (size of audio in bytes),
-        "duration" : integer (duration of audio in milliseconds),
-      }
-
-``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".
-
-  VideoInfo: 
-    Information about a video::
-
-      {
-        "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)
-      }
-
-``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".
-
-The following keys can be attached to any ``m.room.message``:
-
-  Optional keys:
-    - ``sender_ts`` : integer - A timestamp (ms resolution) representing the
-      wall-clock time when the message was sent from the client.
-
 Presence
-========
-.. NOTE::
-  This section is a work in progress.
-
-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:
-
-  - ``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.
-  - ``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).
-
-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.
-
-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.
-
-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
-
-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.
-
-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.
-
-Presence and Permissions
-------------------------
-For a viewing user to be allowed to see the presence information of a target
-user, either:
-
- - 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
-
-In the latter case, this allows for clients to display some minimal sense of
-presence information in a user list for a room.
-
-Client API
-----------
+~~~~~~~~
 The client API for presence is on the following set of REST calls.
 
 Fetching basic status::
@@ -1704,230 +1965,8 @@ Maintaining the presence 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
-
-
-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.
-
-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.
-
-Events
-------
-``m.call.invite``
-This event is sent by the caller when they wish to establish a call.
-
-  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[...]" } }``
-
-``Offer Object``
-  Required keys:
-    - ``type`` : "string" - The type of session description, in this case
-      'offer'
-    - ``sdp`` : "string" - The SDP text of the session description
-
-``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.
-
-  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.
-
-``Candidate Object``
-
-  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
-
-``m.call.answer``
-
-  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
-
-``Answer Object``
-
-  Required keys:
-    - ``type`` : "string" - The type of session description. 'answer' in this
-      case.
-    - ``sdp`` : "string" - The SDP text of the session description
-
-``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.
-
-  Required keys:
-    - ``call_id`` : "string" - The ID of the call this event relates to
-    - ``version`` : "integer" - The version of the VoIP specification this
-      messages
-
-Message Exchange
-----------------
-A call is set up with messages exchanged as follows:
-
-::
-
-   Caller                   Callee
- m.call.invite ----------->
- m.call.candidate -------->
- [more candidates events]
-                         User answers call
-                  <------ m.call.answer
-               [...]
-                  <------ m.call.hangup
-                  
-Or a rejected call:
-
-::
-
-   Caller                   Callee
- m.call.invite ----------->
- m.call.candidate -------->
- [more candidates events]
-                        User rejects call
-                 <------- m.call.hangup
-
-Calls are negotiated according to the WebRTC specification.
-
-
-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.
-
-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.
-
-The rules for dealing with such a situation are as follows:
-
- - 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.
-
-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.
- 
-
 Profiles
-========
-.. NOTE::
-  This section is a work in progress.
-
-.. TODO-spec
-  - Metadata extensibility
-
-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
-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::
@@ -1979,62 +2018,61 @@ 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::
+Security
+--------
 
-  Query type: profile
+Rate limiting
+~~~~~~~~~~~~~
+Home servers SHOULD implement rate limiting to reduce the risk of being
+overloaded. If a request is refused due to rate limiting, it should return a
+standard error response of the form::
 
-  Arguments:
-    user_id: the ID of the user whose profile to return
-    field: (optional) string giving a field name
+  {
+    "errcode": "M_LIMIT_EXCEEDED",
+    "error": "string",
+    "retry_after_ms": integer (optional)
+  }
 
-  Returns: JSON object containing the following keys:
-    displayname: string of freeform text
-    avatar_url: string containing an http-scheme URL
+The ``retry_after_ms`` key SHOULD be included to tell the client how long they
+have to wait in milliseconds before they can try again.
 
-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.
+.. TODO-spec
+  - Surely we should recommend an algorithm for the rate limiting, rather than letting every
+    homeserver come up with their own idea, causing totally unpredictable performance over
+    federated rooms?
 
-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:
+End-to-End Encryption
+~~~~~~~~~~~~~~~~~~~~~
 
- - 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.
+.. TODO-doc
+  - Why is this needed.
+  - Overview of process
+  - Implementation
 
-Both of these should be done automatically by the home server when a user
-successfully changes their displayname or avatar URL fields.
+Content repository
+------------------
+.. NOTE::
+  This section is a work in progress.
 
-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.
+.. TODO-spec
+  - path to upload
+  - format for thumbnail paths, mention what it is protecting against.
+  - content size limit and associated M_ERROR.
 
 
-Identity
-========
+Address book repository
+-----------------------
 .. NOTE::
   This section is a work in progress.
 
-.. TODO-doc Dave
-  - 3PIDs and identity server, functions
-
+.. TODO-spec
+  - format: POST(?) wodges of json, some possible processing, then return wodges of json on GET.
+  - processing may remove dupes, merge contacts, pepper with extra info (e.g. matrix-ability of
+    contacts), etc.
+  - Standard json format for contacts? Piggy back off vcards?
 
-Federation
-==========
+Federation API
+===============
 
 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
@@ -2396,11 +2434,91 @@ State Conflict Resolution
   - How are they resolved (incl tie breaks)
   - How does this work with deleting current state
 
-Security
-========
+Presence
+--------
+The server API for presence is based entirely on exchange of the following
+EDUs. There are no PDUs or Federation Queries involved.
 
-.. NOTE::
-  This section is a work in progress.
+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
+
+Profiles
+--------
+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.
 
 Server-Server Authentication
 ----------------------------
@@ -2411,19 +2529,7 @@ Server-Server Authentication
   - Transaction/PDU signing
   - How does this work with redactions? (eg hashing required keys only)
 
-End-to-End Encryption
----------------------
-
-.. TODO-doc
-  - Why is this needed.
-  - Overview of process
-  - Implementation
-
-Lawful Interception
--------------------
 
-Key Escrow Servers
-~~~~~~~~~~~~~~~~~~
 
 Threat Model
 ------------
@@ -2552,26 +2658,20 @@ Threat: Disclosure to Servers Within Chatroom
 An attacker could take control of a server within a chatroom to expose message
 contents or metadata for messages in that room.
 
-Rate limiting
--------------
-Home servers SHOULD implement rate limiting to reduce the risk of being
-overloaded. If a request is refused due to rate limiting, it should return a
-standard error response of the form::
 
-  {
-    "errcode": "M_LIMIT_EXCEEDED",
-    "error": "string",
-    "retry_after_ms": integer (optional)
-  }
+Identity Servers
+================
+.. NOTE::
+  This section is a work in progress.
 
-The ``retry_after_ms`` key SHOULD be included to tell the client how long they
-have to wait in milliseconds before they can try again.
+.. TODO-doc Dave
+  - 3PIDs and identity server, functions
 
-.. TODO-spec
-  - Surely we should recommend an algorithm for the rate limiting, rather than letting every
-    homeserver come up with their own idea, causing totally unpredictable performance over
-    federated rooms?
+Lawful Interception
+-------------------
 
+Key Escrow Servers
+~~~~~~~~~~~~~~~~~~
 
 Policy Servers
 ==============
@@ -2586,108 +2686,6 @@ Enforcing policies
 ------------------
 
 
-Content repository
-==================
-.. NOTE::
-  This section is a work in progress.
-
-.. TODO-spec
-  - path to upload
-  - format for thumbnail paths, mention what it is protecting against.
-  - content size limit and associated M_ERROR.
-
-
-Address book repository
-=======================
-.. NOTE::
-  This section is a work in progress.
-
-.. TODO-spec
-  - format: POST(?) wodges of json, some possible processing, then return wodges of json on GET.
-  - processing may remove dupes, merge contacts, pepper with extra info (e.g. matrix-ability of
-    contacts), etc.
-  - Standard json format for contacts? Piggy back off vcards?
-
-
-Glossary
-========
-.. NOTE::
-  This section is a work in progress.
-
-Backfilling:
-  The process of synchronising historic state from one home server to another,
-  to backfill the event storage so that scrollback can be presented to the
-  client(s). Not to be confused with pagination.
-
-Context:
-  A single human-level entity of interest (currently, a chat room)
-
-EDU (Ephemeral Data Unit):
-  A message that relates directly to a given pair of home servers that are
-  exchanging it. EDUs are short-lived messages that related only to one single
-  pair of servers; they are not persisted for a long time and are not forwarded
-  on to other servers. Because of this, they have no internal ID nor previous
-  EDUs reference chain.
-
-Event:
-  A record of activity that records a single thing that happened on to a context
-  (currently, a chat room). These are the "chat messages" that Synapse makes
-  available.
-
-PDU (Persistent Data Unit):
-  A message that relates to a single context, irrespective of the server that
-  is communicating it. PDUs either encode a single Event, or a single State
-  change. A PDU is referred to by its PDU ID; the pair of its origin server
-  and local reference from that server.
-
-PDU ID:
-  The pair of PDU Origin and PDU Reference, that together globally uniquely
-  refers to a specific PDU.
-
-PDU Origin:
-  The name of the origin server that generated a given PDU. This may not be the
-  server from which it has been received, due to the way they are copied around
-  from server to server. The origin always records the original server that
-  created it.
-
-PDU Reference:
-  A local ID used to refer to a specific PDU from a given origin server. These
-  references are opaque at the protocol level, but may optionally have some
-  structured meaning within a given origin server or implementation.
-
-Presence:
-  The concept of whether a user is currently online, how available they declare
-  they are, and so on. See also: doc/model/presence
-
-Profile:
-  A set of metadata about a user, such as a display name, provided for the
-  benefit of other users. See also: doc/model/profiles
-
-Room ID:
-  An opaque string (of as-yet undecided format) that identifies a particular
-  room and used in PDUs referring to it.
-
-Room Alias:
-  A human-readable string of the form #name:some.domain that users can use as a
-  pointer to identify a room; a Directory Server will map this to its Room ID
-
-State:
-  A set of metadata maintained about a Context, which is replicated among the
-  servers in addition to the history of Events.
-
-User ID:
-  A string of the form @localpart:domain.name that identifies a user for
-  wire-protocol purposes. The localpart is meaningless outside of a particular
-  home server. This takes a human-readable form that end-users can use directly
-  if they so wish, avoiding the 3PIDs.
-
-Transaction:
-  A message which relates to the communication between a given pair of servers.
-  A transaction contains possibly-empty lists of PDUs and EDUs.
-
-.. TODO
-  This glossary contradicts the terms used above - especially on State Events v. "State"
-  and Non-State Events v. "Events".  We need better consistent names.
 
 .. Links through the external API docs are below
 .. =============================================