Presentar las páginas web en pantallas secundarias adjuntas

François Beaufort
François Beaufort

En Chrome 66, las páginas web pueden usar una pantalla secundaria adjunta a través de la API de Presentation y controlar su contenido con la API de Presentation Receiver.

2/1. El usuario elige una pantalla secundaria conectada.
2/1. El usuario elige una pantalla secundaria conectada.
2/2. Se presenta automáticamente una página web en la pantalla seleccionada anteriormente
2/2. Se presenta automáticamente una página web en la pantalla seleccionada anteriormente

Información general

Hasta ahora, los desarrolladores web podían crear experiencias en las que un usuario veía contenido local en Chrome distinto del que vería en una pantalla remota y, al mismo tiempo, podía controlar esa experiencia de manera local. Por ejemplo, puedes administrar una fila de reproducción en youtube.com mientras los videos se reproducen en la TV o ver un reel de diapositivas con notas del orador en una laptop mientras la presentación en pantalla completa se muestra en una sesión de Hangouts.

Sin embargo, hay situaciones en las que los usuarios pueden simplemente querer presentar contenido en una segunda pantalla adjunta. Por ejemplo, imagina a un usuario en una sala de conferencias equipado con un proyector al que se conecta por medio de un cable HDMI. En lugar de duplicar la presentación en un extremo remoto, el usuario realmente quiere presentar las diapositivas en pantalla completa en el proyector y dejar la pantalla de la laptop disponible para las notas del orador y el control de diapositivas. Si bien el autor del sitio podría admitir esto de una manera muy rudimentaria (p.ej., abrir una ventana nueva, que el usuario tiene que arrastrar manualmente a la pantalla secundaria y maximizarla a pantalla completa), es engorroso y proporciona una experiencia inconsistente entre la presentación local y la remota.

Cómo presentar una página

Te explicaré cómo usar la API de Presentation para presentar una página web en la pantalla secundaria adjunta. El resultado final está disponible en https://googlechrome.github.io/samples/presentation-api/.

Primero, crearemos un nuevo objeto PresentationRequest que contendrá la URL que queremos presentar en la pantalla secundaria adjunta.

const presentationRequest = new PresentationRequest('receiver.html');

In this article, I won’t cover use cases where the parameter passed to
`PresentationRequest` can be an array like `['cast://foo’, 'apple://foo',
'https://example.com']` as this is not relevant there.

We can now monitor presentation display availability and toggle a "Present"
button visibility based on presentation displays availability. Note that we can
also decide to always show this button.

<aside class="caution"><b>Caution:</b> The browser may use more energy while the <code>availability</code> object is alive
and actively listening for presentation display availability changes. Please
use it with caution in order to save energy on mobile.</aside>

```js
presentationRequest.getAvailability()
  .then(availability => {
    console.log('Available presentation displays: ' + availability.value);
    availability.addEventListener('change', function() {
      console.log('> Available presentation displays: ' + availability.value);
    });
  })
  .catch(error => {
    console.log('Presentation availability not supported, ' + error.name + ': ' +
        error.message);
  });

Para mostrar un mensaje de presentación de presentación, se requiere un gesto del usuario, como un clic en un botón. Por lo tanto, llamemos a presentationRequest.start() con un clic en un botón y esperemos a que se resuelva la promesa una vez que el usuario seleccione una pantalla de presentación (p. ej., una pantalla secundaria adjunta en nuestro caso de uso).

function onPresentButtonClick() {
  presentationRequest.start()
  .then(connection => {
    console.log('Connected to ' + connection.url + ', id: ' + connection.id);
  })
  .catch(error => {
    console.log(error);
  });
}

La lista que se presenta al usuario también puede incluir extremos remotos, como dispositivos Chromecast, si estás conectado a una red que los anuncia. Ten en cuenta que las pantallas duplicadas no aparecen en la lista. Consulta http://crbug.com/840466.

Selector de exhibidor para presentación
Selector de pantalla para la presentación

Cuando se resuelve la promesa, la página web en la URL del objeto PresentationRequest se presenta a la pantalla elegida. ¡Y listo!

Ahora, podemos profundizar más y supervisar los eventos de “cerrar” y “finalizar” como se muestra a continuación. Ten en cuenta que es posible volver a conectarse a un presentationConnection "cerrado" con presentationRequest.reconnect(presentationId), en el que presentationId es el ID del objeto presentationRequest anterior.

function onCloseButtonClick() {
  // Disconnect presentation connection but will allow reconnection.
  presentationConnection.close();
}

presentationConnection.addEventListener('close', function() {
  console.log('Connection closed.');
});


function onTerminateButtonClick() {
  // Stop presentation connection for good.
  presentationConnection.terminate();
}

presentationConnection.addEventListener('terminate', function() {
  console.log('Connection terminated.');
});

Cómo comunicarse con la página

Te preguntaste que está bien, pero ¿cómo puedo pasar mensajes entre la página del controlador (la que acabamos de crear) y la página del receptor (la que pasamos al objeto PresentationRequest)?

Primero, recuperemos las conexiones existentes en la página del receptor con navigator.presentation.receiver.connectionList y escuchemos las conexiones entrantes como se muestra a continuación.

// Receiver page

navigator.presentation.receiver.connectionList
.then(list => {
  list.connections.map(connection => addConnection(connection));
  list.addEventListener('connectionavailable', function(event) {
    addConnection(event.connection);
  });
});

function addConnection(connection) {

  connection.addEventListener('message', function(event) {
    console.log('Message: ' + event.data);
    connection.send('Hey controller! I just received a message.');
  });

  connection.addEventListener('close', function(event) {
    console.log('Connection closed!', event.reason);
  });
}

Cuando una conexión recibe un mensaje, se activa un evento "message" que puedes escuchar. El mensaje puede ser una string, un Blob, un ArrayBuffer o una ArrayBufferView. Para enviarlo, solo tienes que llamar a connection.send(message) desde la página del controlador o la del receptor.

// Controller page

function onSendMessageButtonClick() {
  presentationConnection.send('Hello!');
}

presentationConnection.addEventListener('message', function(event) {
  console.log('I just received ' + event.data + ' from the receiver.');
});

Experimenta con la muestra que se encuentra en https://googlechrome.github.io/samples/presentation-api/ para tener una idea de cómo funciona. Estoy seguro de que disfrutarás este contenido tanto como yo.

Ejemplos y demostraciones

Echa un vistazo a la muestra oficial de Chrome que usamos en este artículo.

También te recomiendo la demostración interactiva de Photowall. Esta app web permite que varios controles presenten de forma colaborativa una presentación de diapositivas de fotos en una pantalla. El código está disponible en https://github.com/GoogleChromeLabs/presentation-api-samples.

Captura de pantalla de demostración de Photowall
Foto de José Luis Mieza/CC BY-NC-SA 2.0

Una cosa más

Chrome tiene un menú del navegador "Transmitir" que los usuarios pueden invocar en cualquier momento cuando visitan un sitio web. Si deseas controlar la presentación predeterminada de este menú, asigna navigator.presentation.defaultRequest a un objeto presentationRequest personalizado creado antes.

// Make this presentation the default one when using the "Cast" browser menu.
navigator.presentation.defaultRequest = presentationRequest;

Sugerencias para desarrolladores

Para inspeccionar la página del receptor y depurarla, ve a la página interna chrome://inspect, selecciona "Otro" y haz clic en el vínculo "Inspeccionar" junto a la URL que se presenta actualmente.

Inspecciona páginas de receptor de presentación
Inspecciona las páginas del receptor de presentación

También te recomendamos consultar la página interna de chrome://media-router-internals para conocer los procesos internos de descubrimiento y disponibilidad.

¿Qué sigue?

A partir de Chrome 66, se admiten las plataformas ChromeOS, Linux y Windows. La compatibilidad con Mac llegará más adelante.

Recursos