This specification defines an API to enable web content to access external presentation-type displays and use them for presenting web content.
This document is a work in progress and is subject to change. Some sections are still incomplete or underspecified. Security and privacy considerations need to be adjusted based on feedback and experience. Some open issues are noted inline; please check the group's issue tracker on GitHub for all open issues. Feedback from early experimentations is encouraged to allow the Second Screen Presentation Working Group to evolve the specification based on implementation issues.
This specification aims to make presentation displays such as projectors or connected TVs, available to the Web and takes into account displays that are attached using wired (HDMI, DVI, or similar) and wireless technologies (Miracast, Chromecast, DLNA, AirPlay, or similar).
Devices with limited screen size lack the ability to show content to a larger audience, for example, a group of colleagues in a conference room, or friends and family at home. Showing content on an external large presentation display helps to improve the perceived quality and impact of the presented content.
At its core, this specification enables an exchange of messages between a page that acts as the controller and another page that represents the presentation shown in the presentation display. How the messages are transmitted is left to the UA in order to allow the use of presentation display devices that can be attached in a wide variety of ways. For example, when a presentation display device is attached using HDMI or Miracast, the same UA that acts as the controller renders the presentation. Instead of displaying the presentation in another window on the same device, however, it can use whatever means the operating system provides for using the external presentation displays. In such a case, both the controller and presentation run on the same UA and the operating system is used to route the presentation display output to the presentation display. This is commonly referred to as the 1-UA case. This specification imposes no requirements on the presentation display devices connected in such a manner.
If the presentation display is able to render HTML documents and communicate with the controller, the controller does not need to render the presentation. In this case, the UA acts as a proxy that requests the presentation display to show and render the presentation itself. This is commonly referred to as the 2-UA case. This way of attaching to displays could be enhanced in the future by defining a standard protocol for delivering these types of messages that display devices could choose to implement.
The API defined here is intended to be used with UAs that attach to presentation display devices through any of the above means.
Use cases and requirements are captured in a separate Presentation API Use Cases and Requirements document.
Requirements phrased in the imperative as part of algorithms (such as "strip any leading space characters" or "return false and terminate these steps") are to be interpreted with the meaning of the key word ("MUST", "SHOULD", "MAY", etc.) used in introducing the algorithm.
Conformance requirements phrased as algorithms or specific steps may be implemented in any manner, so long as the result is equivalent. (In particular, the algorithms defined in this specification are intended to be easy to follow, and not intended to be performant.)
The terms browsing context, event handler, event handler event type, firing an event, firing a simple event navigate, queue a task, trusted event, allowed to show a popup are defined in [[!HTML5]].
This document provides interface definitions using the Web IDL standard ([[!WEBIDL]]). The terms Promise, ArrayBuffer, ArrayBufferView and DOMException are defined in [[!WEBIDL]].
The terms resolving a Promise, and rejecting a Promise are used as explained in [[!PROMGUIDE]].
The term URL is defined in the WHATWG URL standard [[!URL]].
The term Blob is defined in the File API specification [[!FILEAPI]].
The term RTCDataChannel is defined in the WebRTC API specification ([[WEBRTC]]).
This section shows example codes that highlight the usage of main
features of the Presentation API. In these examples,
controller.html
implements the controller and
presentation.html
implements the presentation. Both pages
are served from the domain http://example.org
(http://example.org/controller.html
and
http://example.org/presentation.html
). Please refer to the
comments in the code examples for further details.
<!-- controller.html --> <button id="castBtn" style="display: none;">Cast</button> <script> // it is also possible to use relative presentation URL e.g. "presentation.html" var presUrl = "http://example.com/presentation.html"; // the cast button is visible if at least one presentation display is available var castBtn = document.getElementById("castBtn"); // show or hide cast button depending on display availability var handleAvailabilityChange = function(available) { castBtn.style.display = available ? "inline" : "none"; }; // Promise is resolved as soon as the presentation display availability is known. var request = new PresentationRequest(presUrl); request.getAvailability().then(function(availability) { // availability.value may be kept up-to-date by the UA as long as the availability // object is alive. It is advised for the web developers to discard the object // as soon as it's not needed. handleAvailabilityChange(availability.value); availability.onchange = function() { handleAvailabilityChange(this.value); }; }).catch(function() { // Availability monitoring is not supported by the platform, so discovery of presentation // displays will happen only after request.start() is called. Pretend the // devices are available for simplicity; or, one could implement a third state for the // button. handleAvailabilityChange(true); }); </script>
<!-- controller.html --> <script> // Start new session. request.start() // the new started session will be passed to setSession on success .then(setSession) // user cancels the selection dialog or an error is occurred .catch(endSession); </script>
<!-- controller.html --> <script> // read presId from localStorage if exists var presId = localStorage && localStorage["presId"] || null; // presId is mandatory when reconnecting to a session. if (presId) { request.reconnect(presId) // The reconnected session will be passed to setSession on success .then(setSession) // no session found for presUrl and presId or an error is occurred .catch(endSession); } </script>
<!-- controller.html --> <head> <!-- Setting presentation.defaultRequest allows the page to specify the PresentationRequest to use when the UA initiates a presentation session. --> </head> <script> navigator.presentation.defaultRequest = new PresentationRequest(defaultUrl); navigator.presentation.defaultRequest.onsessionconnect = function(evt) { setSession(evt.session); }; </script>
<!-- controller.html --> <script> var session; var setSession = function (theSession) { // end existing session, if any endSession(); // set the new session session = theSession; if (session) { // save presId in localStorage localStorage && (localStorage["presId"] = session.id); // monitor session's state session.onstatechange = function () { if (this == session && this.state == "disconnected") endSession(); }; // register message handler session.onmessage = function (evt) { console.log("receive message", evt.data); }; // send message to presentation page session.send("say hello"); } }; var endSession = function () { // close old session if exists session && session.close(); // remove old presId from localStorage if exists localStorage && delete localStorage["presId"]; }; </script>
<!-- presentation.html --> <script> var addSession = function(session) { session.onstatechange = function () { // session.state is either 'connected' or 'disconnected' console.log("session's state is now", session.state); }; session.onmessage = function (evt) { if (evt.data == "say hello") session.send("hello"); } }); navigator.presentation.getSession().then(addSession); navigator.presentation.onsessionavailable = function(evt) { navigator.presentation.getSessions().then(function(sessions) { addSession(sessions[sessions.length-1]); }); }; </script>
A presentation display refers to an external screen available to the user agent via an implementation specific connection technology.
A presentation session is an object relating a controlling browsing context to its presenting browsing context and enables two-way-messaging between them. Each presentation session has a presentation session state, a presentation session identifier to distinguish it from other presentation sessions, and a presentation session URL that is a URL used to create or resume the presentation session. A valid presentation session identifier consists of alphanumeric ASCII characters only, is at least 16 characters long, and is unique within the set of presentations.
A controlling
browsing context (or controller for short) is a
browsing context that has connected to a presentation
session by calling start()
or reconnect()
, or received a
presentation session via a sessionconnect
event.
The presenting browsing context (or presentation for short) is the browsing context responsible for rendering to a presentation display. A presenting browsing context can reside in the same user agent as the controlling browsing context or a different one.
The set of presentations, initially empty, contains the presentation sessions created by the controlling browsing contexts for the user agent (or a specific user profile within the user agent). The set of presentations is represented by a list of tuples, where each tuple consists of a presentation session URL, a presentation session identifier, and the presentation session itself. The presentation session URL and presentation session identifier uniquely identify the presentation session.
PresentationSession
Each presentation session is represented by a PresentationSession object.
enum PresentationSessionState { "connected", "disconnected" /*, "resumed" */ }; enum BinaryType { "blob", "arraybuffer" }; interface PresentationSession : EventTarget { readonly attribute DOMString? id; readonly attribute PresentationSessionState state; void close(); attribute EventHandler onstatechange; // Communication attribute BinaryType binaryType; attribute EventHandler onmessage; void send (DOMString message); void send (Blob data); void send (ArrayBuffer data); void send (ArrayBufferView data); };
The id
attribute specifies the
presentation session's presentation session
identifier.
The state
attribute represents the
presentation session's current state. It can take one of the
values of PresentationSessionState depending on connection
state.
When the send()
method is called on a
PresentationSession object with a message
, the
user agent MUST run the algorithm to send
a message through a PresentationSession
.
When the close()
method is called on a
PresentationSession, the user agent MUST run the algorithm
to close a presentation session with
PresentationSession.
PresentationSession
send()
it has to be ensured that
messages are delivered to the other end reliably and in sequence.
The transport should function equivalently to an
RTCDataChannel
in reliable mode.
Let presentation message data be the payload data to be
transmitted between two browsing contexts. Let presentation
message type be the type of that data, one of
text
and binary
.
When the user agent is to send a
message through a PresentationSession
S, it MUST
run the following steps:
"disconnected"
, throw an
InvalidStateError
exception.
binary
if data
is one of
ArrayBuffer
, ArrayBufferView
, or
Blob
. Let messageType be text
if
data
is of type DOMString
)
send()
is called in the presenting
browsing context.
send()
is called from the controlling
browsing context.
data
argument as presentation
message data and presentation message type
messageType to the destination browsing context
side.
PresentationSession
When the user agent has received a transmission from the remote side consisting of presentation message data and presentation message type, it MUST run the following steps:
"disconnected"
, abort these steps.
MessageEvent
interface, with the event type
message
, which does not bubble, is not cancelable, and
has no default action.
text
, then initialize event's
data
attribute to the contents of presentation
message data of type DOMString
.
binary
, and binaryType is set to
blob
, then initialize event's
data
attribute to a new Blob
object
that represents presentation message data as its raw
data.
binary
, and binaryType is set to
arraybuffer
, then initialize event's
data
attribute to a new ArrayBuffer
object whose contents are presentation message data.
PresentationSession
.
PresentationSession
When the user agent is to close a presentation session using session, it MUST run the following steps:
connected
, then abort these steps.
disconnected
.
statechange
at session.
The following are the event handlers (and their corresponding event handler event types) that must be supported, as event handler IDL attributes, by objects implementing the PresentationSession interface:
Event handler | Event handler event type |
---|---|
onmessage
|
message
|
onstatechange
|
statechange
|
PresentationAvailability
interface PresentationAvailability : EventTarget { readonly attribute boolean value; attribute EventHandler onchange; };
A PresentationAvailability
object is associated
with a presentation display and represents its
presentation display availability.
The value attribute MUST return the last value it was set to. The value is updated by the monitor the list of available presentation displays algorithm.
The onchange attribute is
an event handler whose corresponding event handler event
type is change
.
The user agent MUST keep track of the set of availability
objects requested through the getAvailability()
method. The
set of availability objects is represented as a set of
tuples (A, availabilityUrl), initially empty, where:
availabilityUrl
passed to getAvailability()
to create A.
The user agent MUST keep a list of available presentation displays. This current list of presentation displays may be used for starting new presentations, and is populated based on an implementation specific discovery mechanism. It is set to the most recent result of the algorithm to monitor the list of available presentation displays.
While there are live PresentationAvailability objects, the
user agent MAY monitor the list of available presentation
displays continuously, so that pages can use the value property of an
PresentationAvailability object to offer presentation only
when there are available displays. However, the user agent may not
support continuous availability monitoring; for example, because of
platform or power consumption restrictions. In this case the
Promise returned by getAvailability()
MUST be
rejected and the algorithm to monitor the
list of available presentation displays will only run as part
of the start a
presentation session algorithm.
When there are no live PresentationAvailability objects (that is, the set of availability objects is empty), user agents SHOULD NOT monitor the list of available presentation displays to satisfy the power saving non-functional requirement. To further save power, the user agent MAY also keep track of whether the page holding a PresentationAvailability object is in the foreground. Using this information, implementation specific discovery of presentation displays can be resumed or suspended.
Some presentation displays may only be able to display a subset of Web content because of functional, security or hardware limitations. Examples are set-top boxes, smart TVs or networked speakers capable of rendering only audio. We say that such a display is a compatible presentation display for a display availability URL if the user agent can reasonably guarantee that the presentation of the URL on that display will succeed.
If set of availability objects is non-empty, or there is a pending request to start a presentation session, the user agent MUST monitor the list of available presentation displays by running the following steps.
true
if
newDisplays is not empty and at least one display in
newDisplays is a compatible presentation
display for availabilityUrl. Otherwise, set
newAvailability to false
.
change
at A.
When a PresentationAvailability object is no longer alive (i.e., is eligible for garbage collection), the user agent SHOULD run the following steps:
PresentationRequest
[Constructor(DOMString url)] interface PresentationRequest : EventTarget { Promise<PresentationSession> start(); Promise<PresentationSession> reconnect(DOMString presentationId); Promise<PresentationAvailability> getAvailability(); attribute EventHandler onsessionconnect; };
When a PresentationRequest
is constructed, the
given url
MUST be used as the presentation request
URL which is the presentation session URL for the
PresentationRequest
instance.
When the start
method is called, the user agent MUST run the following steps to
start a presentation session:
presentationRequest
, the
PresentationRequest
object
presentationUrl
, the presentation request URL
"InvalidAccessError"
and abort these steps.
presentationUrl
;
"NotFoundError"
.
disconnected
.
presentationUrl
in it.
sessionconnect
at
presentationRequest
with S
as its session
attribute.
"OperationError"
.
"AbortError"
.
presentationUrl
should name a resource accessible
to the local or a remote user agent. This specification defines
behavior for presentationUrl
using the
http
or https
schemes; behavior for other
schemes is not defined by this specification.
getAvailability()
.
When the reconnect(presentationId)
method
is called, the user agent MUST run the following steps to reconnect
to a presentation session:
presentationRequest
, the
PresentationRequest
object
presentationUrl
, the presentation request URL
presentationId
, the presentation session
identifier
presentationUrl
, and
the presentation session identifier of known
session is equal to presentationId
, run
the following steps:
sessionconnect
at
presentationRequest
with S as its
session
attribute.
"NotFoundError"
.
When the user agent is to establish a presentation connection using a presentation session S, it MUST run the following steps:
connected
, then:
connected.
statechange
at s.
DOMString
payloads in a reliable and in-order
fashion as described in the Send Message and Receive
Message steps below.
When the getAvailability()
method is
called, the user agent MUST run the following steps:
presentationUrl
, the presentation request URL
PresentationAvailability
object with its value
property set to false
.
"NotSupportedError"
.
PresentationAvailability
object with its value
property set to
false
if the list of available presentation
displays is empty or non of them is a compatible
presentation display, true
otherwise.
When a new presenting browsing context has been created and
navigated to the presentationUrl
on a user-selected
presentation display, the user agent MUST run the following
steps:
The following are the event handlers (and their corresponding event handler event types) that must be supported, as event handler IDL attributes, by objects implementing the PresentationRequest interface:
Event handler | Event handler event type |
---|---|
onsessionconnect
|
sessionconnect
|
PresentationSessionConnectEvent
[Constructor(DOMString type, PresentationSessionConnectEventInit eventInitDict)] interface PresentationSessionConnectEvent : Event { [SameObject] readonly attribute PresentationSession session; }; dictionary PresentationSessionConnectEventInit : EventInit { required PresentationSession session; };
An event named sessionconnect
is fired on a
PresentationRequest when a session associated with the
object is created. It is fired at the PresentationRequest
instance, using the PresentationSessionConnectEvent
interface, with the session attribute set to the
PresentationSession
object that was created.
The event is fired for all sessions that are created for the
controller, either by the controller calling
start()
or reconnect()
, or by the UA creating
a session on the controller's behalf via defaultRequest
.
The UA MUST fire the event as soon as it can create the
PresentationSession
associated with the event.
Presentation
partial interface Navigator { [SameObject] readonly attribute Presentation presentation; };
The presentation
attribute is
used to retrieve an instance of the Presentation interface.
interface Presentation : EventTarget { // This API used by controlling browsing context. attribute PresentationRequest? defaultRequest; // This API used by presenting browsing context. Promise<PresentationSession> getSession(); Promise<sequence<PresentationSession>> getSessions(); attribute EventHandler onsessionavailable; };
The defaultRequest
MUST
return the default presentation request if any, null
otherwise.
If set by the controller, the defaultRequest SHOULD be used by the UA as the
default presentation request for that controller. When
the UA wishes to initiate a PresentationSession on the
controller's behalf, it MUST start a presentation session
using the default presentation request for the
controller (as if the controller had called
defaultRequest.start()
).
The user agent SHOULD initiate presentation using the default presentation request only when the user has expressed an intention to do so, for example by clicking a button in the browser.
defaultRequest
has no effect.
When the user agent is to start monitoring incoming presentation sessions in a presenting browsing context from controlling browsing contexts, it MUST run the following steps:
connected
.
undefined
, presentation
session identifier of S, S) to the
set of presentations.
sessionavailable
at presentation
.
When the getSession()
method is called, the user agent MUST run the following steps:
getSession()
will resolve with a
presentation session that has its presentation session
state set to disconnected
.
When the getSessions()
method is called, the user agent MUST run the following steps:
The following are the event handlers (and their corresponding event handler event types) that must be supported, as event handler IDL attributes, by objects implementing the Presentation interface:
Event handler | Event handler event type |
---|---|
onsessionavailable
|
sessionavailable
|
The change
event fired on the
PresentationAvailability object reveals one bit of information
about the presence (or non-presence) of a presentation display
typically discovered through the local area network. This could be used
in conjunction with other information for fingerprinting the user.
However, this information is also dependent on the user's local network
context, so the risk is minimized.
A presentation session is allowed to be accessed across origins; the presentation URL and presentation ID used to create the presentation are the only information needed to reconnect to a session from any origin in that user agent. In other words, a presentation is not tied to a particular opening origin.
This design allows controlling contexts from different domains to connect to a shared presentation resource. The security of the presentation ID prevents arbitrary pages from connecting to an existing presentation.
This specification does not prohibit a user agent from publishing information about its set of presentations. The group envisions a user agent on another device (distinct from the controller or presentation) becoming authorized to reconnect to the presentation, either by user action or by discovering the presentation's URL and id.
The presentation API abstracts away what "local" means for displays, meaning that it exposes network-accessible displays as though they were local displays. The Presentation API requires user permission for a page to access any display to mitigate issues that could arise, such as showing unwanted content on a display viewable by others.
The presentation URL and presentation ID can be used to connect to a presentation session from another browsing context. They can be intercepted if an attacker can inject content into the controlling page.
The content displayed on the presentation is different from the controller. In particular, if the user is logged in in both contexts, then logs out of the controlling browsing context, she will not be automatically logged out from the presenting browsing context. Applications that use authentication should pay extra care when communicating between devices.
The set of presentations known to the user agent should be cleared when the user requests to "clear browsing data."
This spec will not mandate communication protocols between the controlling browsing context and the presenting browsing context, but it should set some guarantees of message confidentiality and authenticity between corresponding presentation sessions.
Thanks to Wayne Carr, Louay Bassbouss, Anssi Kostiainen, 闵洪波 (Hongbo Min), Anton Vayvod, and Mark Foltz for help with editing, reviews and feedback to this draft.