8 votes

Comment ajouter des contrôles médias standard à l'application Google Cast ?

Je développe une application de réception personnalisée Google Cast en utilisant WebTorrent ( https://webtorrent.io , https://github.com/feross/webtorrent ) et l'application Google Cast sender utilisant le SDK JavaScript (Chrome).

L'idée de mon application est l'envoi de torrent id (magnet URI comme magnet:?xt=urn:btih:6a9759bffd5c0af65319979fb7832189f4f3c35d ou l'URL HTTP/HTTPS vers un fichier *.torrent comme https://webtorrent.io/torrents/sintel.torrent ) de l'émetteur Google Cast au récepteur Google Cast, et en utilisant WebTorrent dans le récepteur Google Cast pour afficher le média (vidéo ou audio) du torrent.

Notez que l'identifiant du torrent n'est pas une URL directe vers le fichier multimédia.

Maintenant, j'utilise l'espace de noms Google Cast et messageBus pour envoyer et recevoir l'identifiant du torrent.

L'API WebTorrent propose deux façons d'afficher les médias :

Voici le code de mon récepteur :

<html>
  <head>
    <script src="https://www.gstatic.com/cast/sdk/libs/receiver/2.0.0/cast_receiver.js"></script>
    <script src="https://cdn.jsdelivr.net/webtorrent/latest/webtorrent.min.js"></script>
  </head>
  <body>
    <video autoplay id='media' />
    <script>
      window.mediaElement = document.getElementById('media');
      window.mediaManager = new cast.receiver.MediaManager(window.mediaElement);
      window.castReceiverManager = cast.receiver.CastReceiverManager.getInstance();
      window.messageBus = window.castReceiverManager.getCastMessageBus('urn:x-cast:com.google.cast.sample.helloworld');
      window.messageBus.onMessage = function(event) {
        displayVideo(event.data);
        // Inform all senders on the CastMessageBus of the incoming message event
        // sender message listener will be invoked
        window.messageBus.send(event.senderId, event.data);
      };
      function displayVideo(torrentId) {
        var client = new WebTorrent();
        client.add(torrentId, function (torrent) {
          var file = torrent.files[0];
          file.renderTo('video');
        });
      }
      window.castReceiverManager.start();
    </script>
  </body>
</html>

Voici le code de mon expéditeur :

<!--
Copyright (C) 2014 Google Inc. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<html>
<head>
<style type="text/css">
html, body, #wrapper {
   height:100%;
   width: 100%;
   margin: 0;
   padding: 0;
   border: 0;
}
#wrapper td {
   vertical-align: middle;
   text-align: center;
}
input {
  font-family: "Arial", Arial, sans-serif;
  font-size: 40px;
  font-weight: bold;
}
.border {
    border: 2px solid #cccccc;
    border-radius: 5px;
}
.border:focus { 
    outline: none;
    border-color: #8ecaed;
    box-shadow: 0 0 5px #8ecaed;
}
</style>
<script type="text/javascript" src="https://www.gstatic.com/cv/js/sender/v1/cast_sender.js"></script>
<script type="text/javascript">
var applicationID = 'F5304A3D';
var namespace = 'urn:x-cast:com.google.cast.sample.helloworld';
var session = null;

/**
 * Call initialization for Cast
 */
if (!chrome.cast || !chrome.cast.isAvailable) {
  setTimeout(initializeCastApi, 1000);
}

/**
 * initialization
 */
function initializeCastApi() {
  var sessionRequest = new chrome.cast.SessionRequest(applicationID);
  var apiConfig = new chrome.cast.ApiConfig(sessionRequest,
    sessionListener,
    receiverListener);

  chrome.cast.initialize(apiConfig, onInitSuccess, onError);
};

/**
 * initialization success callback
 */
function onInitSuccess() {
  appendMessage("onInitSuccess");
}

/**
 * initialization error callback
 */
function onError(message) {
  appendMessage("onError: "+JSON.stringify(message));
}

/**
 * generic success callback
 */
function onSuccess(message) {
  appendMessage("onSuccess: "+message);
}

/**
 * callback on success for stopping app
 */
function onStopAppSuccess() {
  appendMessage('onStopAppSuccess');
}

/**
 * session listener during initialization
 */
function sessionListener(e) {
  appendMessage('New session ID:' + e.sessionId);
  session = e;
  session.addUpdateListener(sessionUpdateListener);
  session.addMessageListener(namespace, receiverMessage);
}

/**
 * listener for session updates
 */
function sessionUpdateListener(isAlive) {
  var message = isAlive ? 'Session Updated' : 'Session Removed';
  message += ': ' + session.sessionId;
  appendMessage(message);
  if (!isAlive) {
    session = null;
  }
};

/**
 * utility function to log messages from the receiver
 * @param {string} namespace The namespace of the message
 * @param {string} message A message string
 */
function receiverMessage(namespace, message) {
  appendMessage("receiverMessage: "+namespace+", "+message);
};

/**
 * receiver listener during initialization
 */
function receiverListener(e) {
  if( e === 'available' ) {
    appendMessage("receiver found");
  }
  else {
    appendMessage("receiver list empty");
  }
}

/**
 * stop app/session
 */
function stopApp() {
  session.stop(onStopAppSuccess, onError);
}

/**
 * send a message to the receiver using the custom namespace
 * receiver CastMessageBus message handler will be invoked
 * @param {string} message A message string
 */
function sendMessage(message) {
  if (session!=null) {
    session.sendMessage(namespace, message, onSuccess.bind(this, "Message sent: " + message), onError);
  }
  else {
    chrome.cast.requestSession(function(e) {
        session = e;
        session.sendMessage(namespace, message, onSuccess.bind(this, "Message sent: " + message), onError);
      }, onError);
  }
}

/**
 * append message to debug message window
 * @param {string} message A message string
 */
function appendMessage(message) {
  console.log(message);
  var dw = document.getElementById("debugmessage");
  dw.innerHTML += '\n' + JSON.stringify(message);
};

/**
 * utility function to handle text typed in by user in the input field
 */
function update() {
  sendMessage(document.getElementById("input").value);
}

/**
 * handler for the transcribed text from the speech input
 * @param {string} words A transcibed speech string
 */
function transcribe(words) {
  sendMessage(words);
}
</script>
</head>
<body>
  <table id="wrapper">
    <tr>
        <td>
            <form method="get" action="JavaScript:update();">
                <input id="input" class="border" type="text" size="30" onwebkitspeechchange="transcribe(this.value)" x-webkit-speech/>
            </form>
        </td>
    </tr>
  </table>

  <!-- Debbugging output -->
  <div style="margin:10px; visibility:hidden;">
    <textarea rows="20" cols="70" id="debugmessage">
    </textarea>
  </div>

<script type="text/javascript">
  document.getElementById("input").focus();
</script>
</body>
</html>

Le problème : le récepteur gère l'identifiant du torrent de l'expéditeur et la vidéo est lue comme prévu. Mais l'application Google Cast officielle ou l'extension Google Cast officielle pour Chrome n'affichent pas les commandes multimédia standard pour la lecture de la vidéo (pause, arrêt, recherche, etc.).

Voici ce que j'ai (il s'agit d'une capture d'écran de la boîte de dialogue modale standard intégrée pour Google Cast dans la dernière version de Google Chrome) :

Screenshot of standard built-in modal dialog for Google Cast in the latest version of Google Chrome

Voici ce que je souhaite réaliser (il s'agit d'une capture d'écran de la boîte de dialogue modale standard intégrée pour Google Cast dans la dernière version de Google Chrome) :

Screenshot of standard built-in modal dialog for Google Cast in the latest version of Google Chrome

Ajout de

window.mediaElement = document.getElementById('media');
window.mediaManager = new cast.receiver.MediaManager(window.mediaElement);

pour

<video autoplay id='media' />

Les éléments n'aident pas.

Dois-je ajouter quelque chose à l'expéditeur et/ou au destinataire pour ajouter des contrôles standard de médias pour <video autoplay id='media' /> sur tous les expéditeurs ?

Peut-être existe-t-il un autre moyen d'envoyer et de recevoir l'identifiant du torrent sans utiliser l'espace de noms Google Cast et le messageBus ?

UPD

On dirait que j'ai trouvé la racine de mon problème...

Comment activer les contrôles média par défaut pour les vidéos en cours de lecture dans le récepteur ?

Par exemple, l'application du récepteur est déjà en train de lire une vidéo :

<video autoplay id='media'
src='https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4'
/>

Comment activer les contrôles multimédias par défaut - boutons "Play/Pause" et barre de progression (sur tous les expéditeurs comme l'extension officielle Google Cast pour Chrome) pour cette vidéo en cours de lecture ?

Il semble que l'ajout du code suivant n'aide pas :

window.mediaElement = document.getElementById('media');
window.mediaManager = new cast.receiver.MediaManager(window.mediaElement);
window.castReceiverManager = cast.receiver.CastReceiverManager.getInstance();
window.castReceiverManager.start();

Voici le code source complet du récepteur :

<html>
<head>
<script src="https://www.gstatic.com/cast/sdk/libs/receiver/2.0.0/cast_receiver.js"></script>
</head>
<body>
<video autoplay id='media'
src='https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4'
/>
<script>
window.mediaElement = document.getElementById('media');
window.mediaManager = new cast.receiver.MediaManager(window.mediaElement);
window.castReceiverManager = cast.receiver.CastReceiverManager.getInstance();
window.castReceiverManager.start();
</script>
</body>
</html>

UPD2 :

Il semble qu'il soit possible d'utiliser n'importe quelle chaîne de texte (l'id du torrent dans mon cas) à la place de l'URL du média dans le champ chrome.cast.media.MediaInfo et utiliser l'espace de noms des médias au lieu d'utiliser un espace de noms personnalisé et un bus de messages personnalisé (c'est-à-dire sans utiliser l'option https://developers.google.com/cast/docs/reference/receiver/cast.receiver.CastReceiverManager#getCastMessageBus et https://developers.google.com/cast/docs/reference/receiver/cast.receiver.CastMessageBus et https://developers.google.com/cast/docs/reference/chrome/chrome.cast.Session#sendMessage ):

function cast() {
  url = 'magnet:?xt=urn:btih:6a9759bffd5c0af65319979fb7832189f4f3c35d';
  chrome.cast.requestSession(function(session) {
    var mediaInfo = new chrome.cast.media.MediaInfo(url);
    //mediaInfo.contentType = 'video/mp4';
    //mediaInfo.contentType = 'audio/mpeg';
    //mediaInfo.contentType = 'image/jpeg';
    var request = new chrome.cast.media.LoadRequest(mediaInfo);
    request.autoplay = true;
    session.loadMedia(request, function() {}, onError);
  }, onError);
}

Mais comment le gérer sur le récepteur dans ce cas ?

1voto

Teyam Points 4452

Il existe en fait une directive UX de Google Cast qui stipule que l'application émettrice doit fournir un bouton Cast de premier niveau. Il existe trois façons de prendre en charge un bouton Cast, qui ont fait l'objet d'une discussion approfondie dans le document suivant Développement de l'application Android Sender

  • Utilisation du fournisseur MediaRouter ActionBar : Android.support.v7.app.MediaRouteActionProvider
  • Utilisation du bouton Cast du MediaRouter : Android.support.v7.app.MediaRouteButton
  • Développement d'une interface utilisateur personnalisée à l'aide des API de MediaRouter et de MediaRouter.Callback

Pour afficher les contrôles de média standard une fois que le média est lu, l'application expéditrice peut contrôler la lecture du média à l'aide de l'instance RemoteMediaPlayer. Des étapes et des exemples sont disponibles dans la documentation.

Pour obtenir une liste exhaustive de toutes les classes, méthodes et événements du kit SDK Android Google Cast, consultez la page Référence de l'API Android pour Google Cast .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X