8

我正在使用 WebTorrent ( https://webtorrent.io , https://github.com/feross/webtorrent ) 和使用 JavaScript (Chrome) SDK 的 Google Cast 发件人应用程序开发 Google Cast 自定义接收器应用程序。

我的应用程序的想法是从 Google Cast 发送器向 Google Cast 接收器发送 torrent id(类似磁铁 URImagnet:?xt=urn:btih:6a9759bffd5c0af65319979fb7832189f4f3c35d或 HTTP/HTTPS URL 到 *.torrent 文件https://webtorrent.io/torrents/sintel.torrent),并在 Google Cast 接收器中使用 WebTorrent 来显示媒体(视频或音频) 来自洪流。

请注意,torrent id 不是媒体文件的直接 URL。

现在我使用 Google Cast 命名空间和 messageBus 来发送和接收 torrent id。

WebTorrent API 提供了两种媒体显示方式:

这是我的接收器的代码:

<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>

这是我的发件人的代码:

<!--
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>

问题:接收方按预期处理来自发送方的种子 ID 和视频播放。但是官方的 Google Cast 应用程序或 Chrome 的官方 Google Cast 扩展程序没有显示用于播放视频以暂停、停止、搜索等的标准媒体控件。

这就是我所拥有的(这是最新版 Google Chrome 中 Google Cast 的标准内置模式对话框的屏幕截图):

最新版 Google Chrome 中 Google Cast 标准内置模态对话框的屏幕截图

这就是我想要实现的(这是最新版 Google Chrome 中 Google Cast 的标准内置模态对话框的屏幕截图):

最新版 Google Chrome 中 Google Cast 标准内置模态对话框的屏幕截图

添加

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

为了

<video autoplay id='media' />

元素没有帮助。

我是否应该向发送者和/或接收者添加一些内容以为<video autoplay id='media' />所有发送者添加标准媒体控件?

也许还有另一种方法可以在不使用 Google Cast 命名空间和 messageBus 的情况下发送和接收 torrent id?

UPD

看来我找到了问题的根源...

如何为接收器中现有的播放视频启用默认媒体控件?

例如,接收方应用程序已经有播放视频:

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

如何启用默认媒体控件 - 此播放视频的工作按钮“播放/暂停”、工作进度条(在所有发件人上,如 Chrome 的官方 Google Cast 扩展程序)?

看起来添加以下代码无济于事:

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

这是接收器的完整源代码:

<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:

看起来可以使用任何文本字符串(在我的情况下为 torrent id)而不是媒体 URL,chrome.cast.media.MediaInfo并使用媒体名称空间而不是使用自定义名称空间和自定义消息总线(即不使用https://developers.google.com /cast/docs/reference/receiver/cast.receiver.CastReceiverManager#getCastMessageBushttps://developers.google.com/cast/docs/reference/receiver/cast.receiver.CastMessageBushttps://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);
}

但是在这种情况下如何在接收器上处理它呢?

4

2 回答 2

1

实际上有一个现有的 Google Cast UX 指南,它指出发送者应用程序必须提供一个顶级 Cast 按钮。支持 Cast 按钮的三种方法已在Android Sender 应用程序开发中进行了充分讨论

  • 使用 MediaRouter ActionBar 提供程序:android.support.v7.app.MediaRouteActionProvider
  • 使用 MediaRouter Cast 按钮:android.support.v7.app.MediaRouteButton
  • 使用 MediaRouter API 和 MediaRouter.Callback 开发自定义 UI

为了在媒体播放后显示标准媒体控件,发送方应用程序可以使用 RemoteMediaPlayer 实例控制媒体播放。步骤和示例可以在文档中找到。

有关 Google Cast Android SDK 中所有类、方法和事件的完整列表,请参阅Google Cast Android API 参考

于 2016-04-27T15:12:43.250 回答
0

我意识到已经 3 年了,但让我大吃一惊的是您缺少视频标签上的“控件”属性!如果没有该属性,播放器将呈现视频但不提供用于控制播放的 ui....

语法与自动播放相同:controls 属性是独立的并且没有值。要么全有,要么全无 - 一组具有默认样式的标准控件,或者根本没有...页。但是根据您分享的屏幕截图,没有必要(并且它可能无法在 chromecast 接收器环境中工作)

正确的 html 如下,这应该就是你所需要的 :)

https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4' />

请让我们知道您是否以及如何最终解决了您的问题(并向我发送 DM...我有几个问题。谢谢!)

于 2019-12-23T09:56:38.663 回答