Presentation API polyfill

This page presents a JavaScript polyfill of the Presentation API specification under standardisation within the Second Screen Working Group at W3C.

The polyfill is not intended for use in production. It explores various discovery and launch mechanisms that the Presentation API could be built upon, with a view to providing concrete feedback on the specification to the Second Screen Working Group.

The polyfill explores discovery-based mechanisms (the controlling device discovers and controls the second device) and invitation-based mechanisms (the controlling device invites nearby devices to launch a URL). Presentation mechanisms that are currently supported are:

Cast
Supports presenting to a Chromecast device. This mechanism only runs in Google Chrome with the Google Cast extension and a Chromecast device connected to the same wireless network as the controlling device.
Also note that receiving applications must be registered with Google for the Chromecast device to be able to load them.
DIAL
Supports discovery of DIAL devices and of a specific set of DIAL applications that can load and render a URL on some second screen. A Node.js DIAL backend server running on the controlling machine on port 3001 is required for the polyfill to be able to discover and control DIAL devices.
To start the local backend server, run npm install and node Server/dial-proxy.js. The local backend server should work well across platforms.
HbbTV 2.0
Supports discovery of HbbTV 2.0 devices and starting a URL on a user-selected HbbTV device.
The HbbTV 2.0 mechanism is a specific case of the DIAL mechanism that uses the "HbbTV" DIAL application and an XML AIT to load the URL to present. The same backend server as for the DIAL mechanism is required to enable that mechanism.
QR Code
Generates and displays a QR code that represents the URL as an overlay.
Physical Web
Supports broadcasting the URL to present through a Bluetooth Low-Energy (BLE) device. This mechanism heavily constrains the size of the URL that may be requested, since it must be less than 21 bytes long. A Node.js backend server running on the controlling machine on port 3000 is required for the polyfill to be able to communnicate with the BLE device.
To start the local backend server, run npm install and node Server/ble-beacon.js. The local backend server has been tested successfully on Linux. It may not run on other platforms.
Window
Opens the presentation in a separate browser window. This mechanism is meant as a fallback that runs everywhere. This fallback would not be an appropriate implementation of the Presentation API though: a Web application calling the Presentation API requests that this content be rendered on a separate display, not in a separate window.
The window presentation mechanism is unusable on mobile browsers where two tabs cannot be displayed on screen at the same time.
The window presentation mechanism will most likely fail the first time it is used due to the Web browsing blocking pop-up windows. Allow the controlling app to open pop-up window and try again to fix the problem.

Important: The establishment of a communication channel between the peers is either not fully implemented (Cast, Window) or simply not available at all when it cannot be established automatically (DIAL, HbbTV, QR Code). The polyfill uses an isChannelOptional presentation request option flag to let the calling app specify whether it needs a communication channel (the default) or will handle the communication on its own. Advanced features such as reconnection to running presentations or even terminating a presentation is not supported either. The polyfill will be improved over time.

Examples

Usage

NB: The polyfill uses a w3c prefix to avoid collisions with native implementations of the Presentation API.

The Presentation API polyfill is a standalone JavaScript file, available at:
https://mediascape.github.io/presentation-api-polyfill/API/presentation-api-polyfill.js

Additional dependencies need to be included to enable some of the presentation mechanisms supported by the polyfill.

Controlling code

On the controlling side, the Presentation API polyfill must be included together with the Cast sender library to support the Cast presentation mechanism and the QRCode.js library for the QR code presentation mechanism. The application may then create a w3cPresentationRequest instance and call start() on that instance to effectively start the presentation and try to establish a communication channel with the receiving side.

<script src="https://davidshimjs.github.io/qrcodejs/qrcode.min.js"></script>
<script src="https://www.gstatic.com/cv/js/sender/v1/cast_sender.js"></script>
<script src="https://mediascape.github.io/presentation-api-polyfill/API/presentation-api-polyfill.js"></script>
<script type="text/javascript">
  // Start new session.
  var request = new w3cPresentationRequest(
    'http://mediascapeproject.eu/', { isChannelOptional: true });
  request
    .start()
    .then(function (connection) {
      connection.onstatechange = function () {
        if (connection.state === 'connected') {
          console.log('data channel is available');
          connection.send('hello receiving side!');
        }
        else if (connection.state === 'closed') {
          console.log('data channel is closed, presentation may still be running');
        }
        else {
          console.log('presentation terminated');
        }
      };
      connection.onmessage = function (event) {
        console.log('received message from receiving side', event.data);
      };
    })
    .catch(function (error) {
      console.log('could not create presentation', error);
    });
</script>

Mechanisms that cannot be fully implemented within the Web runtime make use of a local Node.js backends to accomplish the tasks that they cannot achieve on their own. To launch these backends, first fetch the required code:

git clone https://github.com/mediascape/presentation-api-polyfill.git
cd presentation-api-polyfill
npm install

Then run each backend server in its own command-line window. To enable the Physical Web mechanism, run:

node Server/ble-beacon.js

To enable the DIAL and HbbTV 2.0 mechanisms, run:

node Server/dial-proxy.js

Receiving code

On the receiving side, the Presentation API polyfill must be included together with the Cast receiver library to support the Cast presentation mechanism, although note that the polyfill is useless when invitation-based mechanisms are used (such mechanisms do not know anything about the receiving so cannot connect with them). The receiving application may then monitor incoming presentation connections to be able to exchange messages with the controlling side.

<script src="https://www.gstatic.com/cast/sdk/libs/receiver/2.0.0/cast_receiver.js"></script>
<script src="https://mediascape.github.io/presentation-api-polyfill/API/presentation-api-polyfill.js"></script>
<script type="text/javascript">
  navigator.w3cPresentation.receiver.getSession().then(function (connection) {
    connection.onstatechange = function () {
      if (connection.state === 'connected') {
        connection.send('hello controlling side!');
      }
      else if (connection.state === 'closed') {
        console.log('data channel is closed');
      }
      else {
        console.log('controlling side terminated the presentation');
      }
    };
    connection.onmessage = function (event) {
      console.log('received message from controlling side', event.data);
    };
  });
</script>

Implementation details

The source code of the Presentation API polyfill is available on GitHub under a W3C Software and Document License.

The Presentation API JS polyfill closely follows the interfaces and algorithms defined in the latest draft of the Presentation API specification. On top of these interfaces, the Presentation API polyfill exposes a small set of interfaces that may be used to implement new presentation mechanisms. These classes are exposed in the navigator.w3cPresentation.extend namespace. They are:

log
Short helper function to log things to the console.
_DOMException
Custom implementation of DOMException (pending support from browser vendors)
DataChannel
Represents a communication channel that exposes a send() method and message events.
RemoteController
Represents a remote controller as seen by the receiving application. This interface mostly only exposes a createDataChannel() method that the Presentation API polyfill running on the receiving side uses to establish the communication channel.
Display
Represents a display that is available for presentation. In fact, in the polyfill, classes of displays are also represented as a display. A display can be navigated to a specific URL thanks to the navigate() method it must implement.
PresentationMechanism
Main class that additional presentation mechanisms must implement. The getAvailableDisplays() method returns the promise to get a list of available displays. The monitorIncomingControllers() method starts the monitoring of incoming controllers on the receiving side.
registerPresentationMechanism()
The method that presentation mechanism must call with a PresentationMechanism instance to register themselves with the polyfill.

Contact

For feedback on the polyfill, use GitHub issues or get in touch with Francois Daoust if you do not wish your comment to appear in public.

Feedback on the Presentation API itself should be sent to the public mailing-list of the Second Screen Working Group.

Acknowledgements

This work was done with support from the European Commission under grant agreement no: 610404 (MediaScape).