Chrome 66 permite que las páginas web usen una pantalla secundaria conectada a través de la API de Presentation y que controlen su contenido a través de la API de Presentation Receiver.
Segundo plano
Hasta ahora, los desarrolladores web podían crear experiencias en las que un usuario veía en Chrome contenido local diferente 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 se reproducen videos en la TV, o ver una presentación de diapositivas con notas del orador en una laptop mientras la presentación en pantalla completa se muestra en una sesión de Hangout.
Sin embargo, hay situaciones en las que los usuarios solo quieren presentar contenido en una segunda pantalla adjunta. Por ejemplo, imagina un usuario en una sala de conferencias con un proyector al que se conecta a través 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, dejando 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 debe arrastrar manualmente a la pantalla secundaria y maximizar en pantalla completa), es engorroso y proporciona una experiencia incoherente entre la presentación local y la remota.
Presenta una página
Te explicaré cómo usar la API de Presentation para presentar una página web en la pantalla secundaria conectada. 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 mostrar en la pantalla secundaria conectada.
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, se requiere un gesto del usuario, como hacer clic en un botón. Por lo tanto, llamemos a presentationRequest.start()
cuando se haga clic en un botón y esperemos a que se resuelva la promesa una vez que el usuario haya seleccionado 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.
Cuando se resuelve la promesa, la página web en la URL del objeto PresentationRequest
se muestra en la pantalla elegida. ¡Y listo!
Ahora podemos ir más allá 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
Ahora te preguntarás: "Eso está bien, pero ¿cómo paso mensajes entre mi página de controlador (la que acabamos de crear) y la página receptora (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);
});
}
Una conexión que recibe un mensaje activa un evento "message" que puedes escuchar.
El mensaje puede ser una cadena, un Blob, un ArrayBuffer o un ArrayBufferView.
Para enviarlo, solo debes llamar a connection.send(message)
desde la página del controlador o la página del receptor.
// Controller page
function onSendMessageButtonClick() {
presentationConnection.send('Hello!');
}
presentationConnection.addEventListener('message', function(event) {
console.log('I just received ' + event.data + ' from the receiver.');
});
Juega con la muestra en https://googlechrome.github.io/samples/presentation-api/ para tener una idea de cómo funciona. Estoy seguro de que lo disfrutarás tanto como yo.
Ejemplos y demostraciones
Consulta la muestra oficial de Chrome que usamos para este artículo.
También te recomiendo la demostración interactiva de Photowall. Esta app web permite que varios controladores presenten de forma colaborativa una presentación de diapositivas de fotos en una pantalla de presentación. El código está disponible en https://github.com/GoogleChromeLabs/presentation-api-samples.
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 que hayas 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.
También te recomendamos que consultes la página interna chrome://media-router-internals
para profundizar en 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
- Estado de las funciones de Chrome: https://www.chromestatus.com/features#presentation%20api
- Errores de implementación: https://crbug.com/?q=component:Blink>PresentationAPI
- Especificaciones de la API de presentación: https://w3c.github.io/presentation-api/
- Problemas de especificaciones: https://github.com/w3c/presentation-api/issues