この記事はファーストサーバのAdvent Calendar 2015の17日目として書きました。
http://qiita.com/advent-calendar/2015/firstserver
内容は16日目の続きです。
http://qiita.com/vanx2/items/00dcad135b9706d199a7
前回ざっくりとしたChromecastアプリの概要を書いたので、今回は実際にアプリを作ってみようと思います。いいぞもっとやれと大変不評だったので図をやめました。
#やること
第一回で述べたとおり、スレート端末を使わずに複数台のChromecastへキャストをするためにはSDKを使わずに独自で実装する必要があります。1台のChromecastにキャストするだけなら提供されているSDKを使ったサンプルアプリを動かしてみてください。
https://developers.google.com/cast/docs/downloads
今回はSenderアプリをNode.jsで実装して、Default Media Receiverで動画を再生してみます。
#Senderアプリ
###■mDNSでChromecastを見つける
まずはネットワークに参加しているChromecastを見つけます。ChroemcastはAppleのBonjour(Zero-configuration networking)で利用されているmDNSという技術を利用しています。
mDNSはローカルネットワーク上の機器同士がサーバーを介さずにIPマルチキャストを使って名前とアドレスを交換しあう技術です。マルチキャストIPアドレス224.0.0.251
の5353
ポートにUDPでクエリを投げると、同じローカルネットワーク内に接続されたmDNSに対応した機器がDNSのようなレコードを返します。
それでは実際にmDNSにqueryを投げて、返って来たresponseから必要な情報を抜き出してみましょう。
Node.jsのパッケージではmdns
が人気なようですが、
https://www.npmjs.com/package/mdns
外部モジュール(LinuxのmDNS実装であるAvahiやmDNSResponderなど)に依存していたので、私はpure javascriptだったmulticast-dns
を利用しました。
https://www.npmjs.com/package/multicast-dns
インストールしてー
$ npm i multicast-dns
name
が_googlecast._tcp.local
なPTR
レコードをリクエストするクエリ投げるスクリプト書いてー
var mdns = require('multicast-dns')()
mdns.on('response', function(response) {
console.log('got a response packet:', response)
})
// lets query for an PTR record for '_googlecast._tcp.local'
mdns.query({
questions:[{
name: '_googlecast._tcp.local',
type: 'PTR'
}]
})
実行するとー
$ node detect.js
got a response packet: { type: 'response',
qdcount: 0,
ancount: 1,
nscount: 0,
arcount: 3,
questions: [],
answers:
[ { name: '_googlecast._tcp.local',
type: 'PTR',
class: 1,
ttl: 120,
data: 'signage@ajito._googlecast._tcp.local' } ],
authorities: [],
additionals:
[ { name: 'signage@ajito._googlecast._tcp.local',
type: 'TXT',
class: 99999,
ttl: 4500,
data: 'id=6b2e9253d1d818dd2f2436677a98b19a' },
{ name: 've=04.md=Chromecast.ic=/setup/icon.png.fn=signage@ajito.ca=5.st=1.bs=FA8FCA57FB52.rs=signage.signage@ajito._googlecast._tcp.local',
type: 'SRV',
class: 99999,
ttl: 120,
data: [Object] },
{ name: 'signage@ajito.local',
type: 'A',
class: 99999,
ttl: 120,
data: '192.168.xxx.51' } ] }
Chromecastがこんなレコードを返してきます。他の機器もクエリを投げるので実行し続けているとChromecast以外のmDNSに対応した機器もレコードを返してきます。
返してきたPTR
レコードにのりづけされたadditionals
セクションのtype
がA
のレコードのdata
からIPアドレスが、name
からは名前が取得できます。
この例ではsignage@ajito
という名前をつけたChromecastのIPアドレスが192.168.xxx.51
だということがわかります。
###■Senderアプリの実装
見つけたChromecastのIPアドレスに対してcastv2プロトコルで接続し、標準で提供されているDefault media receiverを起動して動画を再生させてみます。
node-castv2-clientを利用します。
https://github.com/thibauts/node-castv2-client
インストールしてー
$ npm i castv2-client
# Windowsの場合は
C:> npm install castv2-client --no-optional
# らしい
ほぼほぼExamplesに書いてある通りですが、動画を再生して5秒後に再生時間2:00時点へと動画をスキップするように書いてみます。時代はES6だというのに牧歌的な書き方をしておりますが。。。
var Client = require('castv2-client').Client;
var DefaultMediaReceiver = require('castv2-client').DefaultMediaReceiver;
var content = 'http://commondatastorage.googleapis.com/gtv-videos-bucket/big_buck_bunny_1080p.mp4';
var host='192.168.1.96'; // your IP address of chromecast
var client = new Client();
// connect to Chromecast
client.connect(host, function() {
console.log('connected! Launching DefaultMediaReceiver ...');
// launch Default Media Receiver app
client.launch(DefaultMediaReceiver, function(err, player) {
if(err) {console.log(err);return;}
console.log('app "%s" launched, loading media %s ...', player.session.displayName, content);
player.on('status', function(status) {
console.log('status broadcast playerState=%s', status.playerState);
});
// play a video
player.load({contentId: content}, { autoplay: true }, function(err, status) {
console.log('media loaded playerState=%s', status.playerState);
// Seek to 2 minutes after 5 seconds playing
setTimeout(function() {
player.seek(2*60, function(err, status) {
if(err) {console.log(err);return;}
console.log('skip to 2:00 playerState=%s', status.playerState);
});
}, 5000);
});
});
});
client.on('error', function(err) {
console.log('Error: %s', err.message);
client.close();
});
実行するとー
$ node sender.js
connected! Launching DefaultMediaReceiver ...
app "Default Media Receiver" launched, loading media http://commondatastorage.googleapis.com/gtv-videos-bucket/big_buck_bunny_1080p.mp4 ...
status broadcast playerState=IDLE
status broadcast playerState=BUFFERING
media loaded playerState=BUFFERING
status broadcast playerState=PLAYING
skip to 2:00 playerState=BUFFERING
status broadcast playerState=BUFFERING
status broadcast playerState=PLAYING
:
てな具合に ええ いきたいッスね いッスねー!イェー(以下略
Chromecastで動画は流れましたでしょうか。ネットワーク環境によってはバッファリングで時間がかかり、5秒以上経ってからスキップされるかもしれません。
というわけで。。。やっとmDNS触ってみましたが。。。Advent calenderの公開時間になってしまいそうなので今回はここまでとしてcastv2の詳細に関しては次回書いてみようと思います。