隠居日録

隠居日録

2016年(世にいう平成28年)、発作的に会社を辞め、隠居生活に入る。日々を読書と散歩に費やす

perlとchromecast その4

perlとchromecast その3 - 隠居日録の続き。何とか動画を再生することができた。何が悪かったかというと、2度目のRECEIVER_STATUSがChromecastから送信されてきたら、そのメッセージ中のtransportIdをdestination_idにセットして、もう一度CONNECTを送らなければいけないようだ。この後にLOADをすると、動画が再生された。

LOAD後暫くすると、MEDIA_STATUSが送信されきて、playerStateがLOADINGになる。

$VAR1 = bless( {
                 'protocol_version' => 0,
                 'payload_utf8' => '{"type":"MEDIA_STATUS","status":[{"mediaSessionId":1,"playbackRate":1,"playerState":"IDLE","currentTime":0,"supportedMediaCommands":15,"volume":{"level":1,"muted":false},"media":{"contentId":"http://192.168.0.136/test01.mp4","streamType":"buffered","duration":290,"medadata":{},"contentType":"video/mp4"},"currentItemId":1,"extendedStatus":{"playerState":"LOADING","media":{"contentId":"http://192.168.0.136/test01.mp4","streamType":"buffered","duration":290,"medadata":{},"contentType":"video/mp4"}},"repeatMode":"REPEAT_OFF"}],"requestId":0}',
                 'namespace' => 'urn:x-cast:com.google.cast.media',
                 'payload_type' => 0,
                 'source_id' => '57849d91-2bd4-463c-bcd9-3324ae125401',
                 'destination_id' => '*'
               }, 'CastMessage' );

その後、RECEIVER_STATUSが送信されてきて、statusTextがNow Castingに変化する。

$VAR1 = bless( {
                 'payload_type' => 0,
                 'namespace' => 'urn:x-cast:com.google.cast.receiver',
                 'protocol_version' => 0,
                 'payload_utf8' => '{"requestId":0,"status":{"applications":[{"appId":"CC1AD845","displayName":"Default Media Receiver","isIdleScreen":false,"namespaces":[{"name":"urn:x-cast:com.google.cast.broadcast"},{"name":"urn:x-cast:com.google.cast.media"}],"sessionId":"57849d91-2bd4-463c-bcd9-3324ae125401","statusText":"Now Casting","transportId":"57849d91-2bd4-463c-bcd9-3324ae125401"}],"volume":"controlType":"attenuation","level":1.0,"muted":false,"stepInterval":0.05000000074505806}},"type":"RECEIVER_STATUS"}',
                 'destination_id' => '*',
                 'source_id' => 'receiver-0'
               }, 'CastMessage' );

そして、MEDIA_STATUSが送られてきて、playerStateがBUFFERINGに変化する。

$VAR1 = bless( {
                 'destination_id' => '*',
                 'source_id' => '57849d91-2bd4-463c-bcd9-3324ae125401',
                 'namespace' => 'urn:x-cast:com.google.cast.media',
                 'payload_type' => 0,
                 'payload_utf8' => '{"type":"MEDIA_STATUS","status":[{"mediaSessionId":1,"playbackRate":1,"playerState":"BUFFERING","currentTime":0,"supportedMediaCommands":15,"volume":"level":1,"muted":false},"videoInfo":{"width":320,"height":240,"hdrType":"sdr"},"currentItemId":1,"repeatMode":"REPEAT_OFF"}],"requestId":0}',
                 'protocol_version' => 0
               }, 'CastMessage' );

更にMEDIA_STATUSが送られてきて、動画の情報が追加されている。

$VAR1 = bless( {
                 'source_id' => '57849d91-2bd4-463c-bcd9-3324ae125401',
                 'destination_id' => '*',
                 'payload_utf8' => '{"type":"MEDIA_STATUS","status":[{"mediaSessionId":1,"playbackRate":1,"playerState":"BUFFERING","currentTime":0,"supportedMediaCommands":15,"volume":{"level":1,"muted":false},"videoInfo":{"width":320,"height":240,"hdrType":"sdr"},"media":{"contentId":"http://192.168.0.136/test01.mp4","streamType":"buffered","duration":290.783,"medadata":{},"contentType":"video/mp4"},"currentItemId":1,"items":{"itemId":1,"media":{"contentId":"http://192.168.0.136/test01.mp4","streamType":"buffered","duration":290.783,"medadata":{},"contentType":"video/mp4"},"autoplay":"true","customData":{}}],"repeatMode":"REPEAT_OFF"}],"requestId":6}',
                 'protocol_version' => 0,
                 'payload_type' => 0,
                 'namespace' => 'urn:x-cast:com.google.cast.media'
               }, 'CastMessage' );

その後playerStateがPLAYINGになり、

                 'protocol_version' => 0,
                 'payload_utf8' => '{"type":"MEDIA_STATUS","status":[{"mediaSessionId":1,"playbackRate":1,"playerState":"PLAYING","currentTime":0.133,"supportedMediaCommands":15,"volume":"level":1,"muted":false},"videoInfo":{"width":320,"height":240,"hdrType":"sdr"},"currentItemId":1,"repeatMode":"REPEAT_OFF"}],"requestId":0}',
                 'payload_type' => 0,
                 'namespace' => 'urn:x-cast:com.google.cast.media',
                 'source_id' => '57849d91-2bd4-463c-bcd9-3324ae125401',
                 'destination_id' => '*'
               }, 'CastMessage' );

動画の再生が終了すると、playStateがIDLEになる。

$VAR1 = bless( {
                 'source_id' => '57849d91-2bd4-463c-bcd9-3324ae125401',
                 'destination_id' => '*',
                 'payload_utf8' => '{"type":"MEDIA_STATUS","status":[{"mediaSessionId":1,"playbackRate":1,"playerState":"IDLE","currentTime":0,"supportedMediaCommands":15,"volume":"level":1,"muted":false},"currentItemId":1,"idleReason":"FINISHED"}],"requestId":0}',
                 'protocol_version' => 0,
                 'namespace' => 'urn:x-cast:com.google.cast.media',
                 'payload_type' => 0
               }, 'CastMessage' );

RECEVIER_STATUSも送信されてきて、statusTextもReady To Castになる。

$VAR1 = bless( {
                 'payload_type' => 0,
                 'namespace' => 'urn:x-cast:com.google.cast.receiver',
                 'protocol_version' => 0,
                 'payload_utf8' => '{"requestId":0,"status":{"applications":[{"appId":"CC1AD845","displayName":"Default Media eceiver","isIdleScreen":false,"namespaces":[{"name":"urn:x-cast:com.google.cast.broadcast"},{"name":"urn:x-cast:com.google.cast.media"}],"sessionId":"57849d91-2bd4-463c-bcd9-3324ae125401","statusText":"Ready To Cast","transportId":"57849d91-2bd4-463c-bcd9-3324ae125401"}],"volume":"controlType":"attenuation","level":1.0,"muted":false,"stepInterval":0.05000000074505806}},"type":"RECEIVER_STATUS"}',
                 'destination_id' => '*',
                 'source_id' => 'receiver-0'
               }, 'CastMessage' );

perlとchromecast その3

perlとchromecast その2 - 隠居日録の続き。ChromecastとProtocol Buffers over TLSでメッセージの送受信ができるようになったので、いろいろ試しているのだが、まだ動画の再生には至っていない。

ソケットで接続して、CONNECTを送信して、放っておくと、ChromecastからはPINGが送信されてくる。

$VAR1 = bless( {
                 'destination_id' => 'receiver-0',
                 'protocol_version' => 'CASTV2_1_0',
                 'source_id' => 'sender-0',
                 'namespace' => 'urn:x-cast:com.google.cast.tp.connection',
                 'payload_type' => 'STRING',
                 'payload_utf8' => '{ "type" : "CONNECT" }'
               }, 'CastMessage' );

こちらからPINGを送信すると、ChromecastからはPONGを送り返してくるが、PINGは送信しない。両方でPINGを投げるのかと思っていたので、意外だった。それと、CONNECTに対しても、何も返信してこないのも意外。

こちらからLAUNCHを送ると、

$VAR1 = bless( {
                 'namespace' => 'urn:x-cast:com.google.cast.receiver',
                 'source_id' => 'sender-0',
                 'payload_type' => 'STRING',
                 'protocol_version' => 'CASTV2_1_0',
                 'destination_id' => 'receiver-0',
                 'payload_utf8' => '{ "type" : "LAUNCH", "appId" : "CC1AD845", "requestId" : 5 }'
               }, 'CastMessage' );

TVの表示が変わる。

f:id:prozorec:20170607091708p:plain

そして、Chromecastからは、以下の応答が帰ってくる。一つ目。

$VAR1 = bless( {
                 'protocol_version' => 0,
                 'destination_id' => '*',
                 'source_id' => 'receiver-0',
                 'payload_type' => 0,
                 'namespace' => 'urn:x-cast:com.google.cast.receiver',
                 'payload_utf8' => '{"requestId":0,"status":{"volume":{"controlType":"attenuation","level":1.0,"muted":false,"stepInterval":0.05000000074505806}},"type":"RECEIVER_STATUS"}'
               }, 'CastMessage' );

二つ目。

$VAR1 = bless( {
                 'payload_utf8' => '{"requestId":5,"status":{"applications":[{"appId":"CC1AD845","displayName":"Default Media Receiver","isIdleScreen":false,"namespaces":[{"name":"urn:x-cast:com.google.cast.broadcast"},{"name":"urn:x-cast:com.google.cast.media"}],"sessionId":"3937fafb-45f1-4466-8b0c-0df186e25363","statusText":"Ready To Cast","transportId":"3937fafb-45f1-4466-8b0c-0df186e25363"}],"volume":"controlType":"attenuation","level":1.0,"muted":false,"stepInterval":0.05000000074505806}},"type":"RECEIVER_STATUS"}',
                 'namespace' => 'urn:x-cast:com.google.cast.receiver',
                 'payload_type' => 0,
                 'source_id' => 'receiver-0',
                 'destination_id' => '*',
                 'protocol_version' => 0
               }, 'CastMessage' );

それで、この後動画のLOADリクエストを送信すると、

$VAR1 = bless( {
                 'source_id' => 'sender-0',
                 'namespace' => 'urn:x-cast:com.google.cast.media',
                 'payload_type' => 'STRING',
                 'destination_id' => '3937fafb-45f1-4466-8b0c-0df186e25363',
                 'protocol_version' => 'CASTV2_1_0',
                 'payload_utf8' => '{ "type" : "LOAD", "requestId" : 6, "media": {  "contentId" : "http://192.168.0.136/test01.mp4",  "streamType" : "buffered",  "duration" : 290,  "medadata" : {},  "contentType" : "video/mp4" }, "autoplay" : "true", "customData" : {}, "sessionId" : "3937fafb-45f1-4466-8b0c-0df186e25363", "currentTime" : 0 }'
               }, 'CastMessage' );

なぜか、接続を終了させられる。

$VAR1 = bless( {
                 'payload_utf8' => '{"type":"CLOSE"}',
                 'namespace' => 'urn:x-cast:com.google.cast.tp.connection',
                 'payload_type' => 0,
                 'source_id' => '3937fafb-45f1-4466-8b0c-0df186e25363',
                 'protocol_version' => 0,
                 'destination_id' => 'sender-0'
               }, 'CastMessage' );

認証はオプショナルと書かれているのだが、必要なのかもしれない。道のりは長そうだ。