WebTorrent ( https://webtorrent.io、https://github.com/feross/webtorrent ) を使用した Google Cast カスタム レシーバー アプリと、JavaScript (Chrome) SDK を使用した Google Cast センダー アプリを開発しています。
私のアプリのアイデアは、Google Cast 送信者から Google Cast 受信者に torrent id (マグネット URI のようなmagnet:?xt=urn:btih:6a9759bffd5c0af65319979fb7832189f4f3c35d
または HTTP/HTTPS URL のような *.torrent ファイルへhttps://webtorrent.io/torrents/sintel.torrent
) を送信し、Google Cast 受信者で WebTorrent を使用してメディア (ビデオまたはオーディオ) を表示することです。 )急流から。
トレント ID は、メディア ファイルへの直接の URL ではないことに注意してください。
現在、Google Cast 名前空間と messageBus を使用して torrent ID を送受信しています。
WebTorrent API は、メディアを表示する 2 つの方法を提供します。
- 次を使用して DOM に追加します
file.appendTo
: https://webtorrent.io/docs#-file-appendto-rootelem-function-callback-err-elem- - https://webtorrent.io/docs#-file-renderto-elem-function-callback-err-elem-を使用して、特定の要素 (または CSS セレクター) に直接レンダリングし
file.renderTo
ます。
これが私の受信機のコードです:
<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 の標準の組み込みモーダル ダイアログのスクリーンショットです):
追加する
window.mediaElement = document.getElementById('media');
window.mediaManager = new cast.receiver.MediaManager(window.mediaElement);
為に
<video autoplay id='media' />
要素は役に立ちません。
<video autoplay id='media' />
すべての送信者に標準のメディア コントロールを追加するには、送信者および/または受信者に何かを追加する必要がありますか?
Google Cast 名前空間と messageBus を使用せずにトレント 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:
chrome.cast.media.MediaInfo
カスタム名前空間とカスタム メッセージ バスを使用する代わりに (つまり、https://developers.google.comを使用せずに) メディア URL の代わりに任意のテキスト文字列 (私の場合はトレント ID) を使用し、メディア名前空間を使用することが可能であるように見えます。 /cast/docs/reference/receiver/cast.receiver.CastReceiverManager#getCastMessageBusおよびhttps://developers.google.com/cast/docs/reference/receiver/cast.receiver.CastMessageBusおよび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);
}
しかし、この場合、受信機でそれを処理する方法は?