Copyright © 2014 W3C® (MIT, ERCIM, Keio, Beihang), All Rights Reserved. W3C liability, trademark and document use rules apply.
This specification defines an API to enable web content to access external presentation-type displays and use them for presenting web content.
This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at http://www.w3.org/TR/.
This document was published by the Second Screen Presentation Working Group as an Editor's Draft. If you wish to make comments regarding this document, please send them to public-secondscreen@w3.org (subscribe, archives). All comments are welcome.
Publication as an Editor's Draft does not imply endorsement by the W3C Membership. This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.
This document was produced by a group operating under the 5 February 2004 W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.
This document is governed by the 1 August 2014 W3C Process Document.
PresentationSession
    
    NavigatorPresentation
    
    AvailableChangeEvent
    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 terms browsing context, event handlers, event handler event types, firing an event, navigate, queing a task are defined in [HTML5].
The term Promise is defined in [ES6]. 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].
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;
var screenAvailable = false;
var presentationUrl = 'http://example.org/presentation.html';
var presentationId = localStorage['presentationId'] ||
    new String((Math.random() * 10000).toFixed(0));
// Join an existing presentation if one exists.
presentation.joinSession(presentationUrl, presentationId).then(
    function(existingSession) {
      setSession(existingSession);
      updateButtons();
    },
    function() {
      // No session to join.
    });
presentation.onavailablechange = function(e) {
  screenAvailable = e.available;
  updateButtons();
};
function updateButtons() {
  stopButton.disabled = !session;
  stopButton.onClick = session ? stopPresent : null;
  showButton.disabled = !screenAvailable;
  showButton.onclick = screenAvailable ? startPresent : null;
};
function startPresent() {
  presentation.startSession(presentationUrl, presentationId).then(
      function(newSession) {
        setSession(newSession);
        updateButtons();
      },
      function() {
        // User cancelled, etc.
      });
};
function stopPresent() {
  if (!session) return;
  session.close();
  delete localStorage['presentationId'];
};
function setSession(theSession) {
  // NOTE: We could instead close the current session.
  if (session) return;
  session = theSession;
  localStorage['presentationId'] = session.id;
  session.onstatechange = function() {
    switch (session.state) {
      case 'connected':
        session.postMessage(/*...*/);
        session.onmessage = function() { /*...*/ };
        break;
      case 'disconnected':
        console.log('Disconnected.');
        break;
    }
  };
}
</script>
    We could simplify the example, and perhaps remove UI button state management for the sake of clarity.
      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. The
      presentationId argument (optional) allows the page to
      identify this presentation instance, and control which other pages may
      connect to it by setting a hard-to-guess id.
    
As previously discussed on the mailing list - we can add convenience here by default-generating an ID.
      If the user selects a screen with an existing presentation showing the
      same url under the same presentationId, the
      opening browsing context 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
      opening browsing context to this new presentation and allows
      the opening browsing context to exchange messages with it.
    
      navigator.presentation.startSession(url, presentationId)
      returns a Promise to the opening browsing
      context. When the user selects a screen, the presentation page is
      shown and a communication channel has been established the
      Promise resolves to a PresentationSession
      object, which acts as a handle to the presentation for communication and
      state handling. Initially, the state of the
      PresentationSession is "connected". At this
      point, the opening browsing context 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 opening browsing context (see Usage on remote screen).
    
      If the user cancels screen selection, the Promise returned
      by startSession(url, presentationId) remains unresolved.
    
      While there is a pending call to startSession asking the
      user to select a screen (that the user has not yet accepted or canceled),
      the browser may choose to reject subsequent calls to
      startSession from the same page, by returning a
      Promise that never resolves. This will prevent the browser
      from needing to 'queue up' requests to present to the user.
    
      The opening browsing context 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
      automatically, the page may call joinSession(url,
      presentationId), which returns a Promise that
      resolves to an existing PresentationSession if one exists
      that is presenting the same url with the same
      presentationId as was passed originally into
      startSession. The opening browsing context can
      then communicate with the presentation as if the user had manually
      connected to it via startSession.
    
      At the time joinSession(url, presentationId) is called, if
      the browser is not aware of any PresentationSession with a
      matching url and presentationId, the
      Promise should remain unresolved. The browser may become
      aware of such a session at a later time (for example, by switching to a
      WiFi network that has a screen showing that URL). In this case, the
      browser may resolve the Promise to allow the page to connect to the
      running session.
    
Do we want to keep the Promise in pending state?
      If the browser knows of multiple matching sessions, it should connect the
      page to the session that was most recently connected to; if that cannot
      be determined by the browser (for example, if the matching sessions have
      never been connected), then the Promise should remain
      unresolved.
    
      If the page calls startSession(url, presentationId) and
      there is a pending Promise from a call to
      joinSession(url, presentationId) (with the same
      url and presentationId, and the user selects a
      screen in response to startSession, then the
      Promise from startSession will be resolved and
      the Promise from joinSession will not.
    
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?
      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
      opening browsing context could ask the presentation page
      whether it is "new" or "resumed".
    
      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 opening browsing context
  session.postMessage(/*...*/);
  session.onmessage = function() {/*...*/};
  session.onstatechange = function() {
    switch (this.state) {
      case "disconnected":
        // Handle disconnection from opening browsing context
    }
  };
};
    
      When the content denoted by the url argument in the
      startSession() 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 opening browsing context 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 opening browsing context 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".
    
Since we permit multiple opening browsing context 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).
A presentation display refers to an external screen available to the user agent via an implementation specific connection technology.
A presentationis an active connection between a user agent and a presentation display for displaying web content on the latter at the request of the former.
A presentation session is an object relating an opening browsing context to its presentation display and enabling two-way-messaging between them. Each such object has a presentation session state and a presentation session identifier to distinguish it from other presentation sessions.
An opening browsing context is a browsing context that has initiated or resumed a presentation session by calling startSession or joinSession.
      Let D be the set of presentations that are currently known to
      the user agent (regardles of their state). D is represented as a
      set of tuples (U, I, S) where U is the
      URL that is being presented;
      I is an alphanumeric identifier for the presentation; and
      S is the user agent's PresentationSession for the
      presentation. U and I together uniquely identify the
      PresentationSession of the corresponding presentation.
    
PresentationSession
    
      Each presentation
      session is represented by a PresentationSession
      object.
    
enum PresentationSessionState { "connected", "disconnected" /*, "resumed" */ };
interface PresentationSession : EventTarget {
  readonly DOMString? id;
  readonly attribute PresentationSessionState state;
  void postMessage(DOMString message);
  void close();
  attribute EventHandler onmessage;
  attribute EventHandler onstatechange;
};
    
      The id attribute holds the alphanumeric
      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 postMessage() method is called on a
      PresentationSession object with a message, the
      user agent must run the algorithm to post 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.
    
PresentationSession
    
      When the user agent is to post a
      message through a PresentationSession S, it must run
      the following steps:
    
      Needs algorithm for send message and more fine-grained definition of data
      types for sending. Candidates, similar interfaces, are found in the
      
      WHATWG HTML spec's MessageEvent section, or the WebRTC's spec
      RPCDataChannel.
    
PresentationSession
    When the user agent is to close a presentation session S, it must run the following steps:
connected, then:
        disconnected.
      statechange at s.onstatechange.
                  
      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 | 
NavigatorPresentation
    partial interface Navigator {
  readonly attribute NavigatorPresentation presentation;
};
    
      The presentation attribute is used to retrieve an
      instance of the NavigatorPresentation interface, the main
      interface of Presentation API.
    
interface NavigatorPresentation : EventTarget {
  readonly attribute PresentationSession? session;
  Promise<PresentationSession> startSession(DOMString url, DOMString? presentationId);
  Promise<PresentationSession> joinSession(DOMString url, DOMString? presentationId);
  attribute EventHandler onavailablechange;
};
    
      TODO: Define contents of session attribute. Clarification:
      The purpose of the session attribute is to provide the presented page
      with access to the PresentationSession without allowing a potential race
      condition between the registration of an event handler and the firing of
      an event, or complicating the browser implementation to fix this case. It
      should be null in an opening context and non-null in a presented
      document.
    
      When startSession(presentationUrl,
      presentationId) is called, the user agent must run the following
      steps:
    
presentationUrl, the URL of the document to be presented
      presentationId, an optional identifier for the
        presentation
      presentationId is not undefined,
              assign I to that that presentationId.
              presentationId is undefined, let
              I be a random alphanumeric value of at least 16
              characters drawn from the characters [A-Za-z0-9].
              PresentationSession S.
              S.url to presentationUrl, set
              S.id to I, and set S.state to
              disconnected.
              presentationUrl in it.
                The details of implementing the permission request and display selection are left to the user agent; for example it may show the user a dialog and allow the user to select an available screen (granting permission), or cancel the selection (denying permission).
      Do we want to distinguish the permission-denied outcome from the
      no-screens-available outcome? Developers would be able to infer it anyway
      from onavailablechange.
    
      When joinSession(presentationUrl, presentationId)
      is called, the user agent must run the following steps:
    
presentationUrl, the URL of the document being presented
      presentationId, the identifier for the presentation
      presentationUrl and
              i is equal to presentationId, run the
              following steps:
                If no matching presentation is found, we could leave the Promise pending in case a matching presentation is started in the future.
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.onstatechange.
                      
      The mechanism that is used to present on the remote display and connect
      the opening browsing context with the presented document is
      an implementation choice of the user agent. The connection must provide a
      two-way messaging abstraction capable of carrying DOMString
      payloads in a reliable and in-order fashion as described in the Send
      Message and Receive Message steps below.
    
If T does not complete successfully, the user agent may choose to re-execute the Presentation Connection algorithm at a later time.
Do we want to notify the caller of a failure to connect, i.e. with an "error" onstatechange?
Do we want to pass the new state as a property of the statechange event?
Need to further specify the semantics of the messaging channel (using WebSockets or MessagePort as a reference).
onavailablechange EventHandler
    
      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 | 
|---|---|
| onavailablechange | availablechange | 
      In order to satisfy the power
      saving non-functionional requirements the user agent must keep
      track of the number of EventHandlers registered to the
      onavailable event. Using this information, implementation
      specific discovery of presentation
      displays can be resumed or suspended, in order to save power.
    
onavailablechange, the user agent must also keep the list up
    to date by running the algorithm for monitoring the list of available presentation
    displays.
    EventHandler to onavailablechange
    
      When an event handler is added to the list of event handlers registered
      for the onavailablechange event, the user agent must run the
      algorithm to monitor the list
      of available presentation displays.
    
EventHandler
    
      When an event handler is removed from the list of event handlers
      registered to the onavailablechange event, the user agent
      must run the following steps:
    
When the user agent is to monitor the list of available presentation displays, it must run the following steps:
While there are event handlers added to NavigatorPresentation.onavailablechange, the user agent must continuously keep track the list of available presentation displays and repeat the following steps:
availablechange at with the
            event's available property set to true.
          availablechange with the event's
            available property set to false.
          Do we want to fire the event at all handlers, or only the newly added one?
      The mechanism used to monitor presention
      displays availability is left to the user agent. The user agent may
      choose search for screens at any time, not just when event handlers are
      added to NavigatorPresentation.onavailablechange.
    
When the user agent is to cancel monitoring the list of available presentation displays, it must run the following steps:
availablechange at E (and only
        E) with the event's available property set to
        false.
      AvailableChangeEvent
    [Constructor(DOMString type, optional AvailableChangeEventInit eventInitDict)]
interface AvailableChangeEvent : Event {
  readonly attribute boolean available;
};
dictionary AvailableChangeEventInit : EventInit {
  boolean available;
};
    
      An event named availablechange is fired during the execution
      of the monitoring presentation display availability
      algorithm when the presentation display availability changes.
      It is fired at the PresentationSession object,
      using the AvailableChangeEvent interface, with the
      available attribute set to the boolean value that the
      algorithm determined.
    
Need algorithm for receive message
Need algorithm for initialization of the presented document
We could write this spec in a way that distinguished the state of the presentation (owned by the user agent) from the state of the PresentationSession (owned by a specific document); however these should always be sync and it would likely result in more confusion than clarity.
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.