Google Cast SDKを使ったAndroid/iOSアプリの作り方と注意点:Chromecastアプリ開発入門(終)(3/6 ページ)
メディアストリーミングデバイス「Chromecast」用アプリの開発方法を一から解説する連載。今回は、テレビ側のReceiverアプリにつなげるスマホのSenderアプリの概要と作り方、注意点、Cast Companion Libraryの使い方などを解説します。
MediaRouteActionBarによるCastアイコンの表示
前節までの実装方法のようにCastアイコンの表示やCastメニューのUIを自作するのは、自由度は高いですが面倒です。冒頭で紹介したMediaRouteActionBarやMediaRouteButtonを使えばUIの作成をライブラリに任せることができます。
ここではMediaRouteActionBarの使い方を説明します。MediaRouteActionBarを使う場合でも、ここまでに説明した実装は一部を除いて必要です。ここではMediaRouteActionBarを使う場合の追加部分と、実装が一部省略できる部分について述べます。
MediaRouteActionBarを使うと、Castアイコン表示機能を持ったActionBarを生成できます。
まず、アプリケーションのメニューを定義するXMLファイルに、MediaRouteActionProviderを追加します(コード10)。
<menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" > <item android:id="@+id/media_route_menu_item" android:title="@string/media_route_menu_title" app:actionProviderClass="android.support.v7.app.MediaRouteActionProvider" app:showAsAction="always"/> ... </menu>
また、MediaRouteActionProviderを適用するActivityはActionBarActivity を継承する必要があります(コード11)。
public class MainActivity extends ActionBarActivity { // 省略 }
ActivityのonCreateOptionsMenu()メソッドにて、MediaRouteActonProviderとMediaRouteSelectorの関連付けをします(コード12)。
@Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); // MediaRouteActonProviderとMediaRouteSelectorを関連付ける MenuItem mediaRouteMenuItem = menu.findItem(R.id.media_route_menu_item); MediaRouteActionProvider mediaRouteActionProvider = (MediaRouteActionProvider) MenuItemCompat .getActionProvider(mediaRouteMenuItem); mediaRouteActionProvider.setRouteSelector(mMediaRouteSelector); return true; }
以上により、次の機能を組み込んだActionBarが表示されるようになりました。
- Castアイコンの表示制御
Receiverを検出したら表示、非検出時は非表示、接続・非接続に応じてアイコン画像を変更するなど - Castアイコンをタップしたときに標準的なCastメニューを表示
このため、UIを自作するときに必要だった次の実装は不要になります。
- コード5のmMediaRouter.selectRoute(info)メソッドの呼び出し
この実装がなくても、ユーザーがダイアログでデバイスを選択したら、コード4のMediaRouter.CallbackのonRouteSelected()メソッドがコールバックされる - コード4のMediaRouter.CallbackのonRouteAdded()、onRouteRemoved()メソッドの実装
この実装がなくても、検出済みのChromecastデバイスがCastメニューに表示される
Receiverアプリとの通信
次にReceiverアプリと通信について説明します。
Receiverアプリとの通信にはチャンネルを用います。ここで言う「チャンネル」とは、Google Cast SDKが定義するSender-Receiver間の通信経路を指します。チャンネルには次のような特徴があります。
- チャンネルには、動画再生に関する情報や命令を送受信するチャンネル(メディアチャンネル)と、テキストデータ送受信のためのチャンネル(カスタムチャンネル)がある
- チャンネルの識別子は「urn:x-cast:」で始まる文字列で表す
- メディアチャンネルの識別子はあらかじめ決められた「urn:x-cast:com.google.cast.media」である
- カスタムチャンネルの識別子は「urn:x-cast:」で始まる文字列であれば、アプリ開発者が任意に設定できる(例「urn:x-cast:com.example.custom」)
- カスタムチャンネルは識別子を変えることで複数作成できる
今回はメディアチャンネルによる動画再生について実装方法を示します。
メディアチャンネルによる動画再生
中心となるクラスはRemoteMediaPlayerクラスで、Receiverアプリ上のメディアプレーヤーの操作や状態取得をつかさどります。まずは、RemoteMediaPlayer のインスタンスを生成します(コード13)。
mRemoteMediaPlayer = new RemoteMediaPlayer(); mRemoteMediaPlayer .setOnStatusUpdatedListener(new RemoteMediaPlayer.OnStatusUpdatedListener() { @Override public void onStatusUpdated() { // メディアプレーヤーの状態が変わったときに呼ばれる Log.d(TAG, "onStatusUpdated"); // 状態の取得 MediaStatus mediaStatus = mRemoteMediaPlayer .getMediaStatus(); boolean isPlaying = mediaStatus.getPlayerState() == MediaStatus.PLAYER_STATE_PLAYING; } }); mRemoteMediaPlayer .setOnMetadataUpdatedListener(new RemoteMediaPlayer.OnMetadataUpdatedListener() { @Override public void onMetadataUpdated() { // メディアプレーヤーが保持している動画のメタデータが変わったときに呼ばれる Log.d(TAG, "onMetadataUpdated"); // メタデータの取得 MediaInfo mediaInfo = mRemoteMediaPlayer.getMediaInfo(); MediaMetadata metadata = mediaInfo.getMetadata(); } });
RemoteMediaPlayerには、状態が変わったときの通知を受け取るOnStatusUpdatedListener、動画のメタデータが変わった時の通知を受け取るOnMetadataUpdatedListenerをセットします。
RemoteMediaPlayerのインスタンスを生成したら、メディアチャンネルを確立します(コード14)。
try { Cast.CastApi.setMessageReceivedCallbacks(mApiClient, mRemoteMediaPlayer.getNamespace(), mRemoteMediaPlayer); } catch (IOException e) { Log.e(TAG, "Exception while creating media channel", e); }
チャンネル確立ときにmRemoteMediaPlayer.getNamespace()で得た文字列を渡していますが、この文字列がメディアチャンネルの識別子である「urn:x-cast:com.google.cast.media」となっています。
チャンネルを確立したら、まずはRemoteMediaPlayerのrequestStatus()メソッド を呼び出して現在の状態を取得します。後にコード13のonStatusUpdated()メソッドが呼ばれるのでそのタイミングで現在の状態を取得できます(コード15)。
mRemoteMediaPlayer.requestStatus(mApiClient).setResultCallback( new ResultCallback<RemoteMediaPlayer.MediaChannelResult>() { @Override public void onResult(MediaChannelResult result) { if (!result.getStatus().isSuccess()) { Log.e(TAG, "Failed to request status."); } } });
以上でReceiverアプリのメディアプレーヤーを制御する準備ができました。動画をロードして再生を開始するには、次のように実装します(コード16)。
MediaMetadata mediaMetadata = new MediaMetadata( MediaMetadata.MEDIA_TYPE_MOVIE); mediaMetadata.putString(MediaMetadata.KEY_TITLE, "My video"); MediaInfo mediaInfo = new MediaInfo.Builder( "http://your.server.com/video.mp4").setContentType("video/mp4") .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED) .setMetadata(mediaMetadata).setCustomData(customDataJson) .build(); try { mRemoteMediaPlayer .load(mApiClient, mediaInfo, true) .setResultCallback( new ResultCallback<RemoteMediaPlayer.MediaChannelResult>() { @Override public void onResult(MediaChannelResult result) { if (result.getStatus().isSuccess()) { Log.d(TAG, "Media loaded successfully"); } } }); } catch (IllegalStateException e) { Log.e(TAG, "Problem occurred with media during loading", e); } catch (Exception e) { Log.e(TAG, "Problem opening media during loading", e); }
ロードするコンテンツに関する情報をセットしたMediaInfoインスタンスを生成し、RemoteMediaPlayerのload()メソッドを呼び出します。メタデータに関する情報はMediaMetadataクラスのインスタンスに設定します。コンテンツのURLはMediaInfoのBuilder()メソッドの引数に指定します。また、setCustomData()メソッドでアプリに固有な付加情報を設定し、Receiverアプリに受け渡すことも可能です。
なお、カスタムデータを送信する際の注意点として、送信できるデータサイズは64KBまでという制約があります。それを超えるデータはメディアチャンネルではなくカスタムチャンネルを使って送信する必要がありますが、カスタムチャンネルも一度に送信できるデータサイズは64KBまでの制約があるため、いくつかに分割して送信するようプログラミングしなければなりません。
動画の再生が始まると、RemoteMediaPlayerのインスタンスを使用して一時停止やシークといったメディアプレーヤーの操作ができるようになります(コード17)。
// 一時停止 mRemoteMediaPlayer.pause(mApiClient).setResultCallback( new ResultCallback<MediaChannelResult>() { @Override public void onResult(MediaChannelResult result) { // 省略 } }); // シーク mRemoteMediaPlayer.seek(mApiClient, seekPosition).setResultCallback( new ResultCallback<MediaChannelResult>() { @Override public void onResult(MediaChannelResult result) { // 省略 } });
メディアプレーヤーの操作が行われると、Receiverアプリのメディアプレーヤーの状態が変わり、コード13のOnStatusUpdatedListenerクラスのメソッドが呼ばれます。なお、コード13のOnStatusUpdatedListenerクラスのメソッドは、同じChromecastデバイスにつながっている他のSenderアプリが操作した場合や、Receiverアプリ自身の制御により状態が変わったときにも呼ばれます。
Copyright © ITmedia, Inc. All Rights Reserved.
関連記事
- Windows OS/Androidの画面をChromecast経由でテレビに表示する
会議室のテレビにWindows OSの画面を映してプレゼンテーションしたい。でもケーブルをつなぐのはスマートではない。こんなとき、テレビにChromecastを接続し、Windows OSにGoogle Chromeをインストールすれば、画面をWi-Fi経由でテレビに表示できるようになる。 - 米グーグルがChromecastのSDKを公開
モバイル端末とTVの垣根を超えるChromecast用のSDKをGoogleが公開。Chromeの拡張機能とiOS向けのGoogle Cast SDKは即日提供を開始、Android版も数日中にリリース予定だという。 - グーグルのプレスイベントで見るグーグル新時代の幕開け
新型Nexus 7タブレットやAndroid 4.3、さらには新デバイスChromecastの発表から、グーグルの新世代戦略を読み解きます。 - YouTube動画を家中のディスプレイで再生できたら
YouTubeビデオを、ブラウザからリビングのテレビやタブレットに飛ばせたら。HTML5のPlayコマンドをテレビに送信して再生する方法を紹介します - Android L、Android Wear、Android TV、Android Autoの開発者向け現状まとめ
米グーグルが「Google I/O 2014」で発表した次期Android「Android L」「Android TV」「Android Auto」の開発者プレビュー、そして「Android Wear」の正式版。これらに対応したアプリを開発するには、どこを見ればいいのか。概要とともに簡単にまとめてみた。 - 第17回 iPhoneの画面をApple TVでテレビに表示する
iPhoneの画面をテレビに映してプレゼンしたい。こんなとき、会議室にApple TVを用意しておくと便利。たった3ステップでiPhoneの画面をテレビに映せるようになる。 - Windows OSの画面をApple TV経由でテレビに表示する
会議室のテレビにWindows OSの画面を映してプレゼンテーションしたい。でもケーブルをつなげるのは少々スマートではない。こんなとき、テレビにApple TVを接続し、Windows OSに「AirParrot」をインストールすれば、画面をWi-Fi経由でテレビに表示できるようになる。 - WebSocketでスマートテレビをリアル接続するぷらら
ひかりTV独自のスマートテレビリモコンの接続方法はWebSocketを用いた常時接続だ。その仕組みと開発意図を聞いた。 - さまざまなデバイスがWebと結び付いていく
テレビやカーナビ、家電とWebが連携していく「Web of Things」。NHKなど、最前線の取り組みが語られたカンファレンスをレポートする - テレビのスマート化とYouTubeのテレビ化
YouTubeなどネットの攻勢に対し、何もしないと「テレビは死ぬ」。それは明らかだ。テレビ局がよいサービスを開発できるかどうかが要となる。 - スマートテレビはチャンスだぞ
テレビもスマート、なんだと。アメリカからGoogle TVやApple TVがやってくる。米テレビ局の映像配信Huluも上陸している。もちろん、日本だって手を打っている - 今度こそテレビとWebの統合なるか:「Google TV」は従来のWebテレビと何が違うのか?
- 頭脳放談第120回:Google TVがVIA Technologiesも救う?
- WebとUIをつなぐトリックスター(2):テレビでYahoo!デバイスが変わればUIデザインも変わる
制作の要となるエンジニアとデザイナのチームワークのツボを探る連載。今回はヤフーのテレビ向けサービスのデザイン担当に話を聞いた