Présenter des pages Web sur des écrans associés secondaires

François Beaufort
François Beaufort

Chrome 66 permet aux pages Web d'utiliser un écran associé secondaire via l'API Presentation et de contrôler son contenu via l'API Presentation Receiver.

1/2. L'utilisateur choisit un écran connecté secondaire
1/2. L'utilisateur choisit un écran secondaire associé
2/2. Une page Web s'affiche automatiquement sur l'écran sélectionné précédemment
2/2. Une page Web s'affiche automatiquement sur l'écran précédemment sélectionné.

Contexte

Jusqu'à présent, les développeurs Web pouvaient créer des expériences dans lesquelles un utilisateur verrait dans Chrome un contenu local différent de celui affiché sur un écran distant, tout en pouvant le contrôler localement. Par exemple, vous pouvez gérer une file d'attente de lecture sur youtube.com pendant que les vidéos sont diffusées sur le téléviseur, ou visionner une bobine de diapositives avec des commentaires du présentateur sur un ordinateur portable alors que la présentation en plein écran est affichée dans une session Hangouts.

Il existe cependant des cas où les utilisateurs peuvent souhaiter simplement présenter du contenu sur un second écran connecté. Par exemple, imaginez un utilisateur dans une salle de conférence équipée d'un projecteur auquel il est connecté via un câble HDMI. Plutôt que de dupliquer la présentation sur un point de terminaison distant, l'utilisateur souhaite vraiment présenter les diapositives en plein écran sur le projecteur, ce qui laisse l'écran de l'ordinateur portable disponible pour les commentaires du présentateur et le contrôle des diapositives. Bien que l'auteur du site puisse prendre cela en charge de manière très rudimentaire (par exemple, en affichant une nouvelle fenêtre, que l'utilisateur doit faire glisser manuellement sur l'écran secondaire et l'optimiser en plein écran), la tâche est fastidieuse et offre une expérience incohérente entre la présentation locale et à distance.

Présenter une page

Je vais vous expliquer comment utiliser l'API Presentation pour présenter une page Web sur votre écran secondaire associé. Le résultat final est disponible à l'adresse https://googlechrome.github.io/samples/presentation-api/.

Tout d'abord, nous allons créer un objet PresentationRequest qui contiendra l'URL que nous souhaitons présenter sur l'écran secondaire associé.

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);
  });

L'affichage d'une invite d'affichage de présentation nécessite un geste de l'utilisateur, par exemple un clic sur un bouton. Appelons donc presentationRequest.start() lors d'un clic sur un bouton et attendez que la promesse soit résolue une fois que l'utilisateur a sélectionné un affichage de présentation (par exemple, un affichage secondaire associé dans notre cas d'utilisation).

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

La liste présentée à l'utilisateur peut également inclure des points de terminaison distants, tels que les appareils Chromecast si vous êtes connecté à un réseau qui en fait la promotion. Notez que les écrans mis en miroir ne figurent pas dans la liste. Consultez la page http://crbug.com/840466.

Sélecteur d&#39;affichage des présentations
Sélecteur d'affichage des présentations

Lorsque la promesse est résolue, la page Web à l'URL de l'objet PresentationRequest est présentée à l'écran choisi. Et voilà!

Nous pouvons maintenant aller plus loin et surveiller les événements de fermeture et d'arrêt, comme indiqué ci-dessous. Notez qu'il est possible de se reconnecter à un presentationConnection "fermé" avec presentationRequest.reconnect(presentationId), où presentationId correspond à l'ID de l'objet presentationRequest précédent.

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.');
});

Communiquer avec la page

Vous vous demandez si c'est bien, mais comment transmettre des messages entre ma page de contrôleur (celle que nous venons de créer) et la page destinataire (celle que nous avons transmise à l'objet PresentationRequest) ?

Tout d'abord, récupérons les connexions existantes sur la page du récepteur avec navigator.presentation.receiver.connectionList et écoutons les connexions entrantes comme indiqué ci-dessous.

// 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);
  });
}

Lorsqu'une connexion reçoit un message, elle déclenche un événement "message" que vous pouvez écouter. Le message peut être une chaîne, un Blob, un ArrayBuffer ou un ArrayBufferView. Pour l'envoyer, il vous suffit d'appeler connection.send(message) à partir de la page de la manette ou de la page du récepteur.

// Controller page

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

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

Jouez avec l'exemple disponible à l'adresse https://googlechrome.github.io/samples/presentation-api/ pour vous faire une idée de son fonctionnement. Je suis sûr que vous apprécierez cet événement autant que moi.

Exemples et démonstrations

Consultez l'exemple Chrome officiel que nous avons utilisé pour cet article.

Je vous recommande également la démonstration interactive Photowall. Cette application Web permet à plusieurs contrôleurs de présenter de manière collaborative un diaporama photo sur un écran de présentation. Le code est disponible à l'adresse https://github.com/GoogleChromeLabs/presentation-api-samples.

Capture d&#39;écran de la démo Photowall
Photo de José Luis Mieza / CC BY-NC-SA 2.0

Encore une chose

Chrome dispose d'un menu de navigation "Cast" que les utilisateurs peuvent appeler à tout moment lorsqu'ils consultent un site Web. Si vous souhaitez contrôler la présentation par défaut de ce menu, attribuez navigator.presentation.defaultRequest à un objet presentationRequest personnalisé créé précédemment.

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

Conseils de développement

Pour inspecter la page du récepteur et la déboguer, accédez à la page chrome://inspect interne, sélectionnez "Autre", puis cliquez sur le lien "Inspecter" à côté de l'URL actuellement présentée.

Inspecter les pages réceptrices de la présentation
Inspecter les pages réceptrices de la présentation

Vous pouvez également consulter la page chrome://media-router-internals interne pour explorer les processus internes de découverte/disponibilité.

Étapes suivantes

À partir de Chrome 66, les plates-formes ChromeOS, Linux et Windows sont compatibles. La compatibilité avec Mac sera disponible ultérieurement.

Ressources