ChromecastのPreview SDKでChromecastDemoを動かすまで (iOS)

Googleのドキュメントは [https://developers.google.com/cast/](https://developers.google.com/cast/)にある。

**Cast SDK 1.0.0の情報。2013/8時点ではGoogle Cast SDKはPreview版であってこれから変更があるかもしれないから製品にはまだ組み込まないでねとある**

ChromecastにはSenderアプリとReceiverアプリの２つの概念があり、iOSアプリはSenderアプリになれる。Receiverアプリはウェブ上に存在しHTML/CSS/Javascriptで構成されChromecast(Chrome)側が実行する、要するにウェブアプリ。

SenderアプリがReceiverアプリ(ウェブアプリ)のホスト先をChromecast(Chrome)に伝えてそこでReceiverアプリを表示してもらい、Receiverアプリとメッセージをやりとりするので双方の開発が必要となる。

技術的にはiOSアプリの内部でWebサーバを実行し、Receiverアプリを配信できると思うが現状のPreview SDKでは後に記述するホワイトリストの制限がある。

## ホワイトリスト申請

デフォルトではChromecastは開発モードになっておらずChromecast上で実行されるReceiverアプリがPreview SDKのReceiver APIを使ったり、リモートデバッグするためにはホワイトリストに登録する必要がある。

ホワイトリストに登録するにはGoogleに以下の情報を[フォーム](https://docs.google.com/forms/d/1E-vka5QP8LkF0nbfz-omN1DjNSX1uLGyqHdbpEFh6zg/viewform)から送信する。

* メールアドレス
* デバイスのシリアルナンバー
* レシーバーアプリのURL(検証用と本番用)

48時間以内に返事が来るとあるが基本的に24時間以内にはAppIDが発行された。


最初に申請リクエストを投げるとAppID -> URL というキーバリューで発行される。次からはデバイスを追加する場合はAppIDだけでも済む。AppIDはUUIDのようなものが発行され、iOS/AndroidのFQDNを逆にしたIDなどをこちらから指定することはできない。

なおChromecastはGoogleのDNSサーバを直接参照するため、ローカルネットワークのDNSサーバを使って内部用のURLのホスト名を名前解決することができない。従ってローカル内で開発する場合は http://192.168.1.2/receiver/receiver.html などIPアドレスを指定したURLを申請する。ちなみにローカルのIPアドレスでport:3000でも問題なく動作した。

## Chromecastの開発の準備

[セットアップ](https://cast.google.com/chromecast/setup)時にインストールしたChromecastアプリを起動し、Chromecastの設定で **Send serial number when Checking for updates** にチェックを入れ、念の為に Reboot しておく。

ホワイトリスト申請がうまく行っていれば ChromecastのIPアドレス:9222　がリモートデバッグURLとして開ける。

## ChromecastDemo + SDKのセットアップ

ChromecastDemoはGitHub googlecast/cast-ios-sampleで公開されていたがCast SDK 1.0.1で新しいサンプルが公開されて削除されてしまった。Apacheライセンスだったので[コピー](https://dl.dropboxusercontent.com/u/8932138/downloads/chromecast/cast-ios-sample.zip)を置いた。cast-ios-sampleにはSDKは含まれておらず、[Google Cast Downloads](https://developers.google.com/cast/downloads/)の **Download the iOS Sender API libraries** よりダウンロードできる。

SDKはFrameworkとして提供されており任意の場所に置き、サンプルプロジェクトのTARGET > Build Phases > Link Binary With Librariesからフォルダを指定して追加することができる。

実際のChromecastとの連携は実機で動作する必要があるが、起動自体はシミュレータおよびChromecastなしでも可能なので、ビルドが通るか、アプリが実行できるかどうかまではここで確認することができる。

このサンプルはiOSアプリであるChromecastDemoがSenderアプリとして動画のURLをReceiverアプリに送信し、Receiverアプリがその動画をvideoタグで再生するというものになっている。動画の再生のサポートについては以下に記載がある。

https://developers.google.com/cast/supported_media_types

* Video codecs: H.264 High Profile Level 4.1, 4.2 and 5, VP8
* Audio decoding: HE-AAC, LC-AAC, CELT/OPUS, MP3
* Containers: MP4/CENC, WebM, MPEG-DASH, SmoothStreaming
* Level 1 DRM support: Widevine, Playready

## SenderアプリとRecieverアプリの修正

サンプルプロジェクトを動かすにはホワイトリスト申請で取得したAppIDをSenderアプリとRecieverアプリに埋め込み、Recieverアプリ(htmlファイル)を申請したURLに配置する。

Senderアプリ側はChoromecastDemoプロジェクトの **GCKViewController.m** ファイルの114行目あたりの **YOUR_APP_ID** をAppIDに置き換える。

```objectivec:GCKViewController.m
    NSLog(@"Starting session.");
    [self.mSession startSessionWithApplication:@"YOUR_APP_ID"
                                      argument:self.applicationArgument];
```

iOSのSenderアプリであるChromecastDemoでは、GCKAppDelegate.m にてRecieverアプリのURLを設定する箇所があるのだが、AndroidのDemoプロジェクトではこのような設定はなく、iOSアプリでも設定しなくても動作した。ChromecastはAppIDをキーにしてURLを取得する。

Recieverアプリ側は **receiver/receiver.html** ファイルの25行目あたりの **GoogleCastSampleApp** をAppIDに置き換える。

```html:receiver/receiver.html
var receiver = new cast.receiver.Receiver(
  'GoogleCastSampleApp', 
  [cast.receiver.RemoteMedia.NAMESPACE],
  "",
  5);
```

## 実行

ChromecastおよびiOSデバイスを同じネットワークに接続させ、ChromecastDemoを実行する。実機の動作はXcodeからのデバッグ実行でも問題なかった。

ChromecastDemoがChromecastを発見すると右上にテレビアイコンが表示されるのでそれを押してChromecastを選択肢、動画のリストを選択すると動画がChromecastに接続したディスプレイに表示される。

## トラブルシューティング

### セッションができず画面にAbortが表示される 1

**GCK Session failed to start: Error Domain=com.google.GCKFramework.GCKApplicationSessionError Code=1 "failed to start application (com.google.GCKFramework.GCKApplicationSessionError)** が出力される時は指定したReceiverアプリがホワイトリスト対応できていない。確認すべきポイントはAppIDを正しく指定できているか、申請したシリアル番号が正しいか、Chromecastの開発の準備で更新時にシリアル番号を送信する設定にしているかを確認すること。

切り分けとしてChromecastのIPアドレス:9222を開けない場合はリモートデバッグができていないので申請または設定がうまく行っていない。

### セッションができず画面にAbortが表示される 2

**GCK Session failed to start: Error Domain=com.google.GCKFramework.GCKApplicationSessionError Code=3 "application stopped unexpectedly (com.google.GCKFramework.GCKApplicationSessionError)** が出力される場合はReceiverアプリは登録されているが、ReceiverアプリのURLにアクセスができていない。ChromecastはGoogleのDNSサーバを直接参照するためLAN内のURLの場合を使う場合は注意すること。受け取ったAppIDとレシーバーアプリのURLを再申請すればURLを更新することができる。

### 画面が真っ暗のまま動画が再生されない。

セッションは開始できるが、動画が再生できない場合はSenderアプリとReceiverアプリがメッセージのやりとりを行えていないおそれがある。Receiverアプリ(receiver.html)に設定したAppIDがSenderアプリと同じものかを確認すること。

## その他

* ChromecastのChrome ExtensionをGoogle Chromeにインストールするにはバージョンが28以降が必要
* [Chromecast “StartApplicationRequest failed with status: -4”](http://stackoverflow.com/questions/17914645/chromecast-startapplicationrequest-failed-with-status-4) iOSサンプルのトラップはここで判明
* [Chromecast in Canada!](http://forum.xda-developers.com/showthread.php?p=44070932) DNSサーバのトラップはここで判明