This specification defines an abstraction for establishing and operating a direct peer-to-peer connection between two participants. It defines the offer-and-contract exchange, the connection lifecycle, application message transfer, media publication, media observation, failure conditions, and automatic renegotiation.

This specification is maintained alongside a reference implementation.

You can check the reference implementation docs:

See it in action:

Or use the reference implementation:

Introduction

The abstraction defined here is built on the peer connection, data channel, session description, and media-capture concepts defined by [[WEBRTC]], [[MEDIACAPTURE_STREAMS]], and [[SCREEN_CAPTURE]].

One participant creates an offer. The other participant accepts that offer and returns a corresponding answer inside a role-specific contract copy. Once each participant holds the appropriate contract copy, each participant can construct a live connection and exchange application messages over a data channel.

A conforming implementation MUST exhibit the behavior defined in this document. Unless stated otherwise, structural terms such as list, map, string, and record are to be interpreted consistently with [[INFRA]].

Core Concepts

Concept Meaning
peer One of the two participants in a connection.
offeror The peer that creates an offer.
offeree The peer that accepts an offer.
offer identifier A text value that correlates an offer with the contract copies derived from that offer.
connection A live association built from one role-specific contract copy.
application message Any MessagePack-encodable value that is not a reserved internal signal.
presentation handle An implementation-defined value that represents a renderable view of visual media.
polite peer The peer that yields during renegotiation glare. The offeree is the polite peer.
impolite peer The peer that may ignore a colliding renegotiation offer. The offeror is the impolite peer.

Data Model

Offer

An Offer record transports the local session description created by the offeror.

Member Type Meaning
offerId String The offer identifier.
description Session description The local offer description after ICE gathering completes.

Offeror Contract Copy

Member Type Meaning
offerId String The offer identifier.
role String The literal value "offeror".
answer Session description The local answer created by the offeree.

Offeree Contract Copy

Member Type Meaning
offerId String The offer identifier.
role String The literal value "offeree".

Contract and Contract Copies

Concept Meaning
Contract Either an offeror contract copy or an offeree contract copy.
ContractCopies A record with members offeror and offeree, containing the two role-specific contract copies derived from one accepted offer.

Reserved Internal Signal

The following record shape is reserved for internal renegotiation traffic carried over the data channel:

{
  __anbs_peer2peer: 'renegotiate-offer' | 'renegotiate-answer',
  description: SessionDescriptionInit
}
        

A received payload that matches this shape MUST be processed as an internal signal rather than as an application message.

Reserved State

A conforming implementation MUST maintain the following reserved state:

State Meaning
pending offers A map from offer identifier to a reserved peer connection and its locally created data channel.
accepted offers A map from offer identifier to a reserved peer connection and a pending incoming data channel.
shared user-media source A cached media source reused by microphone and camera publication.
shared display-media source A cached media source reused by screen publication.
shared local camera presentation A shared presentation handle associated with local camera media.
shared local screen presentation A shared presentation handle associated with local screen media.

Failure Model

A conforming implementation MUST surface failure conditions when an operation defined by this specification cannot complete.

The representation of those failures is implementation-defined. A conforming implementation MAY expose error codes, error objects, exceptions, rejected promises, events, or equivalent diagnostics.

Failure condition Meaning
Data channel error before readiness The data channel emitted an error indication before reaching the "open" state.
Data channel close before readiness The data channel closed before reaching the "open" state.
Incoming data channel unavailable The peer connection reached "failed" or "closed" before an incoming data channel was observed.
Application message sent before readiness An application message was sent before the data channel was available and open.
Unknown contract state Connection construction was attempted with a contract whose reserved local state did not exist.
Missing local description A local offer or answer description was absent after ICE gathering completed.

Event Model

Each connection exposes a connection-scoped event surface with the following event kinds:

Event kind Payload When emitted
message Decoded application message When a received MessagePack payload does not match the reserved internal-signal shape.
camera Presentation handle When remote user-media is associated with a camera presentation.
screen Presentation handle When remote display media is associated with a screen presentation.

Connection Operations

Operation Purpose
makeOffer(additionalIceServers?) Create a new offer and reserve offeror-side state.
acceptOffer(offer, additionalIceServers?) Accept an offer and derive the paired contract copies.
Connection construction from Contract Create a live connection from one contract copy.
ready() Wait until the data channel is open.
sendMessage(message) Send an application message over the data channel.
closeConnection() Close the channel and the underlying peer connection.
shareMicrophone() Publish microphone media.
stopSharingMicrophone() Stop publishing microphone media.
shareCamera() Publish camera media.
stopSharingCamera() Stop publishing camera media.
shareScreen() Publish display media.
stopSharingScreen() Stop publishing display media.

Common ICE Configuration

Connection-establishment operations MAY apply implementation-defined internal ICE server defaults.

If supplementary ICE server configuration is not supplied, it MUST be treated as empty. If supplementary ICE server configuration is supplied, it MUST be incorporated in addition to any internal defaults.

The peer connection MUST use iceTransportPolicy equal to "all".

makeOffer()

  1. Create a new peer connection using the common ICE configuration.
  2. Create a data channel named "data".
  3. Create a new offer identifier.
  4. Create a local offer description.
  5. Set that offer as the local description.
  6. Wait until ICE gathering completes.
  7. If the local description is absent after ICE gathering completes, throw MISSING_LOCAL_DESCRIPTION.
  8. Store the peer connection and the data channel in the pending-offer map under the offer identifier.
  9. Return an Offer record containing the offer identifier and the local description.

acceptOffer()

  1. Create a new peer connection using the common ICE configuration.
  2. Begin waiting for the next incoming data channel.
  3. Set the remote description from offer.description.
  4. Create a local answer description.
  5. Set that answer as the local description.
  6. Wait until ICE gathering completes.
  7. If the local description is absent after ICE gathering completes, throw MISSING_LOCAL_DESCRIPTION.
  8. Store the peer connection and the pending incoming data channel in the accepted-offer map under offer.offerId.
  9. Return a ContractCopies record whose offeror member is an offeror contract copy and whose offeree member is an offeree contract copy.

Connection Construction

Constructing a connection consumes exactly one reserved state entry. A contract copy MUST NOT be reusable after it has been consumed.

  1. If the contract role is "offeror", look up the pending offer state using contract.offerId.
  2. If no such state exists, throw UNKNOWN_PEER_CONTRACT.
  3. Use the reserved peer connection and data channel as the live state of the connection.
  4. Delete the consumed pending-offer entry.
  5. Set the remote description from contract.answer.
  6. If the contract role is "offeree", look up the accepted-offer state using contract.offerId.
  7. If no such state exists, throw UNKNOWN_PEER_CONTRACT.
  8. Use the reserved peer connection and the pending incoming data channel as the live state of the connection.
  9. Delete the consumed accepted-offer entry.
  10. Assign the offeree role as polite and the offeror role as impolite.
  11. When the live data channel becomes available, install the message processing and readiness observers defined by this specification.
  12. Install the renegotiation-needed and incoming-track observers defined by this specification.

ready()

The ready() operation returns a promise-like result that resolves only after the live data channel reaches the "open" state.

If the channel is already open, the result MUST resolve immediately.

The result MUST reject with:

sendMessage()

The sendMessage(message) operation MUST verify that a live data channel exists and that its ready state is "open".

If either condition is false, the operation MUST throw CONNECTION_NOT_READY.

Otherwise, the operation MUST encode message using MessagePack as defined by [[MSGPACK]] and send the resulting bytes on the live data channel.

Observer Registration

A connection MUST expose the connection-scoped event surface through an observer registration mechanism.

A conforming implementation MAY realize that mechanism using the EventTarget model defined by [[DOM]], including addEventListener() and removeEventListener(), or an equivalent observer API.

In either case, observers MUST be able to subscribe to and unsubscribe from each event kind defined by this specification.

closeConnection()

The closeConnection() operation MUST close the live data channel if one has been attached and MUST then close the underlying peer connection.

Application Message Processing

  1. Receive a payload from the data channel.
  2. Decode the payload using MessagePack.
  3. If the decoded value matches the reserved internal-signal shape, process it using the internal renegotiation algorithm and stop.
  4. Otherwise, emit a message notification whose payload is the decoded value.

Media Publication and Observation

shareMicrophone()

  1. If no shared user-media source exists, request one with both audio and video enabled and cache the result.
  2. Read the first audio track from the shared user-media source.
  3. If no audio track exists, return.
  4. Add that audio track to the peer connection and store the returned sender as the current user-audio sender.

stopSharingMicrophone()

If a current user-audio sender exists, remove it from the peer connection and clear the stored sender. Otherwise, do nothing.

shareCamera()

  1. If no shared user-media source exists, request one with both audio and video enabled and cache the result.
  2. Read the first video track from the shared user-media source.
  3. If no video track exists, return.
  4. Add that video track to the peer connection and store the returned sender as the current user-video sender.
  5. If no shared local camera presentation exists, create one and mark it for local camera presentation.
  6. If the shared local camera presentation does not already present media, associate it with a stream containing the selected video track and begin presentation.

stopSharingCamera()

If a current user-video sender exists, remove it from the peer connection and clear the stored sender. Otherwise, do nothing.

shareScreen()

  1. If no shared display-media source exists, request one with video and audio enabled and cache the result.
  2. Read the first video track from the shared display-media source. If present, add it to the peer connection and store the returned sender as the current display-video sender.
  3. Read the first audio track from the shared display-media source. If present, add it to the peer connection and store the returned sender as the current display-audio sender.
  4. If no shared local screen presentation exists, create one and mark it for local screen presentation.
  5. If the shared local screen presentation does not already present media, associate it with a stream containing the selected display video track and begin presentation.

stopSharingScreen()

If a current display-video sender exists, remove it from the peer connection and clear the stored sender. If a current display-audio sender exists, remove it from the peer connection and clear the stored sender. If neither sender exists, do nothing.

Incoming Track Classification

  1. When an incoming track indication is received, use the first associated stream if one is present.
  2. If no stream is present, synthesize a new stream containing only the received track.
  3. If no remote user-media stream identifier has yet been recorded, or the stream identifier equals the recorded remote user-media stream identifier, then: set or reuse the remote camera presentation, associate it with the stream, begin presentation, emit camera, and stop.
  4. If no remote display stream identifier has yet been recorded, or the stream identifier equals the recorded remote display stream identifier, then: set or reuse the remote screen presentation, associate it with the stream, begin presentation, and emit screen.

Automatic Renegotiation

The data channel is used as the transport for internal renegotiation.

On Renegotiation Needed

  1. If no live data channel has yet been attached to the connection, return.
  2. Mark the connection as currently producing a local offer.
  3. Create a fresh local offer description.
  4. Wait until ICE gathering completes.
  5. Send a reserved internal signal whose discriminator is "renegotiate-offer" and whose description is the new local offer description.
  6. Clear the marker that indicates that the connection is currently producing a local offer.

On Internal Signal Received

  1. Determine whether the connection is ready to accept a remote offer.
  2. A renegotiation-offer signal collides if the connection is not ready to accept a remote offer.
  3. If the signal is a colliding renegotiation-offer and the connection is impolite, ignore the signal and return.
  4. If the signal discriminator is "renegotiate-answer", mark the connection as currently applying a remote answer.
  5. Apply the remote description carried by the signal.
  6. Clear the marker that indicates that a remote answer is pending.
  7. If the signal discriminator is "renegotiate-offer", then: create a fresh local answer description, wait until ICE gathering completes, and send a reserved internal signal whose discriminator is "renegotiate-answer" and whose description is the new local answer description.

Security and Privacy Considerations

Offer and answer values may contain ICE candidates and related network metadata. Signaling paths should therefore be treated as sensitive.

Confidentiality and integrity for the peer-to-peer media and data path depend on the underlying WebRTC stack.

Media capture operations rely on ambient permission and policy controls supplied by the environment.