Copyright © 2014 the Contributors to the Presentation API Specification, published by the Second Screen Presentation Community Group under the W3C Community Final Specification Agreement (FSA). A human-readable summary is available.
This specification defines an API to enable web content to access external presentation-type displays and use them for presenting web content.
This specification was published by the Second Screen Presentation Community Group. It is not a W3C Standard nor is it on the W3C Standards Track. Please note that under the W3C Community Final Specification Agreement (FSA) other conditions apply. Learn more about W3C Community and Business Groups.
This report documents the use cases, requirements, examples and interfaces needed to enable web pages to display web content on secondary screens. It is an evolved version of the initial Presentation API that represents the result of discussions within the Second Screen Presentation Community Group so far. API semantics still need to be specified. The report may serve as starting point for a possible Working Group chartered to work on the same topic.
This specification aims to make secondary displays such as a projector or a connected TV 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 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 requesting page and a presentation page shown in the secondary display. How those messages are transmitted is left to the UA in order to allow for use of display devices that can be attached in a wide variety of ways. For example, when a display device is attached using HDMI or MiraCast, the UA on the requesting device can render the requested presentation page in that same UA, but instead of displaying in a window on that same device, it can use whatever means the operating system provides for using those external displays. In that case, both the requesting page and the presentation page run on the requesting device and the operating system is used to route the presentation display output to the other display device. The second display device doesn't need to know anything about this spec or that the content involves HTML5.
Alternately, some types of external displays may be able to render HTML5 themselves and may have defined their own way to send messages to that content. In that case, the UA on the requesting device would not need to render the presentation page itself. Instead, the UA could act as a proxy translating the request to show a page and the messages into the form understood by the display device.
This way of attaching to displays could be enhanced in the future through definition of a standard protocol for delivering these types of messages that display devices could choose to implement.
The API defined here is intended be used with UAs that attach to display devices through any of the above means.
A user is preparing a set of slides for a talk. Using a web based service, she is editing her slides and speaker notes on the primary screen, while the secondary larger screen shows a preview of the current slide. When the slides are done, her mobile phone allows her to access them from an online service while on the go. Coming to the conference, using wireless display technology, she would like to present her slides on the stage screen from her mobile phone. The phone's touch screen helps her to navigate slides and presents a slide preview, while the projector shows her slides to the audience.
Requirements: R1, R3, R4, R5, R7
Using an online video or image sharing service, a user would like to show memorable moments to her friends. Using a device with a small screen, it is impossible to show the content to a large group of people. Connecting an external TV screen or projector to her device - with a cable or wirelessly - the online sharing service now makes use of the connected display, allowing a wider audience to enjoy the content.
The web page shows UI elements that allow the user to trigger displaying content on the secondary display (e.g a "send to second screen" ) only if there is at least one secondary screen available.
Requirements: R1, R3, R4, R5, R7
Splitting the gaming experience into a near screen controller and a large screen visual experience, new gaming experiences can be created. Accessing the local display on the small screen device and an external larger display allows for richer web-based gaming experiences.
Requirements: R1, R3, R4, R5, R7
Requirements: R1, R3, R4, R5, R6, R7
Multi-Screen enumeration and named identification removed, after discussion on the mailing list, cmp. http://lists.w3.org/Archives/Public/public-webscreens/2014Feb/0021.html :
All diagrams, examples, and notes in this specification are non-normative, as are all sections explicitly marked non-normative. Everything else in this specification is normative.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119. For readability, these words do not appear in all uppercase letters in this specification. [RFC2119]
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 end 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 term presentation display refers to an external screen connected to the device that the user agent runs on.
The terms event handlers and event handler event types are defined in [HTML5].
This document provides interface definitions using the [WEBIDL] standard.
Running in a compliant user agent, code for presenting a page
http://example.org/presentation.html
on the presentation
display looks as follows:
/* controller.html */ <button disabled id=show>Show</button> <button disabled id=stop>Stop</button> <script> var presentation = navigator.presentation, showButton = document.getElementById('show'), stopButton = document.getElementById('stop'); var session = null, screenAvailable = false, presentationUrl = 'http://example.org/presentation.html', previousSessionId = localStorage['sessionId']; presentation.onavailablechange = function (e) { screenAvailable = e.available; updateButtons(); }; function tryJoin() { if (!previousSessionId) return; // Join an existing presentation if one exists. session = presentation.joinSession(presentationUrl, previousSessionId); console.log(session.state); // "unknown" session.onstatechange = handleSessionState; } function startPresent() { session = presentation.startSession(presentationUrl); console.log(session.state); // "unknown" session.onstatechange = handleSessionState; } function handleSessionState() { switch (session.state) { case 'connected': if (previousSessionId == session.id) { console.log("Joined existing session."); } else { console.log("New session opened."); localStorage['sessionId'] = session.id; } session.postMessage( /*...*/ ); session.onmessage = function () { /*...*/ }; break; case 'disconnected': // Session join/start failed, or session terminated. break; } updateButtons(); } function updateButtons() { var sessionConnected = session && session.state == "connected"; stopButton.disabled = !sessionConnected; stopButton.onClick = sessionConnected ? stopPresent : null; var sessionPendingOrConnected = sessionConnected || (session && session.state == "unknown"); showButton.disabled = !screenAvailable || sessionPendingOrConnected; showButton.onclick = screenAvailable && !sessionPendingOrConnected ? startPresent : null; } function stopPresent() { session.close(); } tryJoin(); </script>
The availability monitoring for secondary screens begins when the page
adds an event listener for the availablechange
event on the
navigator.presentation
object. If there are already
available screens when the page adds the first event listener for the
event, the UA synthesizes a single availablechange event to signal the
availability.
Do we want to fire an event immediately after the page registers for it? What's a best practice method for asynchronous notifications of this kind? See below in the Open Questions section.
It is an open issue whether to provide filter information as part of the request for notification of available screens. This could be useful when a particular application or capability is needed in order to display the contents of a presentation. One possible approach to this could be to provide the URL for the presentation and / or required options as part of the request for notification of available screens. If this was supported, only screens that satisfied the filter would trigger a notification.
The "Show" button's state (initially disabled) informs the user of the
availability of secondary screen(s), and the button's state is updated if
the availability changes. (The rationale of putting the actual boolean
information into a property of the event e.available
is to
allow the implementation to optimize power consumption for network
discovery of remote wireless screens. If this information was provided in
a globally accessible flag, the network discovery could never be
suspended for keeping the flag up to date.)
Clicking the "Show" button calls
navigator.presentation.startSession()
, which causes the user
agent to request from the user a screen to show the presentation. The
url
argument indicates the content to be presented.
If the user selects a screen with an existing presentation showing the
same url
under the same presentationId
, the
opener page is connected to that existing presentation.
If the user selects a screen without an existing presentation, or a
screen presenting a different url
or
presentationId
, the UA connects to the selected screen,
brings up a new presentation window on it, and starts to show the content
denoted by the url
argument. The UA then connects the opener
page to this new presentation and allows the opener page to exchange
messages with it.
navigator.presentation.startSession(url, presentationId)
returns a PresentationSession
object, initially in
"unknown"
state. Changes of the state
property
of the PresentationSession
object are signalled through the
onstatechange
event handler. If presentationId
is not specified, the UA generates one for the returned object.
Once the UA established the connection to the presentation page, the
state changes from "unknown"
to "connected"
. At
this point, the opener page can communicate with the presentation page
using the session's postMessage()
to send messages and its
onmessage
event handler to receive messages.
The presentation page will also have access to
PresentationSession
that it can use to send and receive
messages with the opener page (see Usage on Remote Screen).
If the user cancels screen selection when the UA brings up the selection
dialog, the state
property of the
PresentationSession
object remains at
"unknown"
. If the UA attempts and for technical reasons
fails at establishing a link with the presentation page, the
state
property transitions to "disconnected"
.
The opener page may wish to reconnect to an existing presentation without prompting the user to select a screen. For example, the site could allow media items from different pages to be shown on the same presentation page, and does not want to prompt the user on each page to reconnect to that presentation.
To reconnect, the page calls joinSession(url,
presentationId)
, which returns a PresentationSession
,
initially in "unknown"
state.
The presentationId
argument in this case is the value of the
session.id
property of a previously established
PresentationSession
.
If the UA finds an existing presenting instance that matches the
url
and presentationId
as was passed originally
into startSession
, the UA then transistions the state of the
returned PresentationSession
to "connected"
.
The requesting page can then communicate with the presentation as if the
user had manually connected to it via startSession
.
If no such instance exists, the state
of the returned
PresentationSession
transitions to
"disconnected"
.
Do we need to insert into the description an additional permission prompt to grant the page access to the "one ore more screens are available" Information?
Do we reload the presentation page after startSession() if the page was previously already shown on this screen?
If there are already connected screens when the page subscribes to the
onavailablechange
event, we can handle this in two ways: We
can synthesize one initial event to notify the page about available
screens as soon as the first event handler is installed (as described).
Or we can add another message like
navigator.presentation.getAvailable(function(available) { }
);
to notify the page about available screens using this one-time
asynchronous getter. Which way should we go?
Do we need an additional state like resumed in order to identify resumed
session? It seems that this could be handled on the page level. The
opener page could ask the presentation page whether it is
"new"
or "resumed"
.
If more than one presentation session exists with the same
This can be resolved by having the UA
generate different ids on different screens.
url
and presentationId
(on different screens)
then what is the behavior of joinSession(url,
presentationId)
?
If the page calls startSession(url)
and
joinSession(url, presentationId)
with the same
url
, and the latter call has not resolved, behavior is not
defined.
For addressing the requirement of communication between originating page
and presentation page/screen, the presenting page can now use the same
session
object. It accesses this object through the
navigator.presentation.session
property, which is only
non-null
for the page on the presentation screen.
if (navigator.presentation.session) { var session = navigator.presentation.session; // Communicate with opener page. session.postMessage(/*...*/); session.onmessage = function() {/*...*/}; session.onstatechange = function() { switch (this.state) { case "disconnected": // Handle disconnection from opener page. } }; };
When the content denoted by the url
argument in the
requestSession()
example above is loaded, the page on the
presentation screen will have its
navigator.presentation.session
property set to the session.
This session is a similar object as in the first example. Here, its
initial state is "connected"
, which means we can use it to
communicate with the opener page using postMessage()
and
onmessage
.
The presentation page can also monitor the connection state by listening
for statechange
events. When the state changes to
"disconnected"
the page is made aware of the fact that
communication with the opener page was lost, but it can continue to
display the current content. The communication can be re-established when
a statechange
event fires with a new state of
"connected"
.
The interfaces described herein address the requirements outlined in the Use Cases section, and specifically, also consider the Media Flinging to Multiple Screens use case unaddressed by the previous version of the Presentation API. This section describes the interfaces to the extend discussed in the Second Screen Presentation Community Group. Readers are encouraged to consult the Example and Algorithms sections together with this section for a more complete understanding of the technical parts of this specification.
Since we permit multiple opener pages to connect the same presentation page, we need to define how connection and disconnection of these pages is communicated to the presentation page (if at all).
NavigatorPresentation
interface NavigatorPresentation : EventTarget { readonly attribute PresentationSession? session; PresentationSession startSession(DOMString url, DOMString? presentationId); PresentationSession joinSession(DOMString url, DOMString? presentationId); attribute EventHandler onavailablechange; }; partial interface Navigator { readonly attribute NavigatorPresentation presentation; };
AvailableChangeEvent
Fired at the primary screen's NavigatorPresentation
object,
when screen availability changes.
[Constructor(DOMString type, optional AvailableChangeEventInit eventInitDict)] interface AvailableChangeEvent : Event { readonly attribute boolean available; }; dictionary AvailableChangeEventInit : EventInit { boolean available; };
PresentationSession
An object representing the established presentation session.
enum PresentationSessionState { "unknown", "connected", "disconnected" }; interface PresentationSession : EventTarget { readonly DOMString? id; readonly attribute PresentationSessionState state; void postMessage(DOMString message); void close(); attribute EventHandler onmessage; attribute EventHandler onstatechange; };
These algorithms are intended to define the behavior of the
NavigatorPresentation
and PresentationSession
interfaces declared in the Interfaces section.
Run when an event handler is added to onavailablechange
.
Run when startSession(url, presentationId)
is called.
Run when joinSession(url, presentationId)
is called.
Run when close()
is called on a
PresentationSession.
Run when a document opened by startSession()
is loaded.
Thanks to Wayne Carr, Louay Bassbous, Anssi Kostiainen, 闵洪波 (Hongbo Min), Anton Vayvod, and Mark Foltz for help with editing, reviews and feedback to this draft.