Cast SDK をウェブ センダー アプリに統合する

このデベロッパー ガイドでは、Cast SDK を使用して Web Sender アプリに Google Cast のサポートを追加する方法について説明します。

用語

モバイル デバイスまたはブラウザは、再生を制御するセンダーであり、Google Cast デバイスは、再生のために画面にコンテンツを表示するレシーバーです。

Web Sender SDK は、Framework API(cast.framework)と Base API(chrome.cast)の 2 つの部分で構成されています。一般的に、よりシンプルな上位レベルの Framework API で呼び出しを行い、その後、下位レベルの Base API によって処理されます。

センダー フレームワークとは、下位レベルの機能のラッパーを提供するフレームワーク API、モジュール、関連リソースを指します。送信側アプリまたは Google Cast Chrome アプリは、送信側のデバイスの Chrome ブラウザ内で実行されるウェブ(HTML/JavaScript)アプリを指します。ウェブ レシーバー アプリとは、Chromecast または Google Cast デバイスで動作する HTML/JavaScript アプリを指します。

センダー フレームワークは非同期コールバック設計を使用して、センダーアプリにイベントを通知し、キャストアプリのライフサイクルのさまざまな状態間を遷移します。

ライブラリを読み込む

アプリで Google Cast の機能を実装するには、以下に示すように、Google Cast Web Sender SDK の場所を把握している必要があります。loadCastFramework URL クエリ パラメータを追加して、Web Sender Framework API も読み込みます。アプリのすべてのページは、次のようにライブラリを参照する必要があります。

<script src="https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1"></script>

フレームワーク

Web Sender SDK は cast.framework.* 名前空間を使用します。この名前空間は次のものを表します。

  • API でオペレーションを呼び出すメソッドまたは関数
  • API のリスナー関数のイベント リスナー

フレームワークは次の主要コンポーネントで構成されています。

  • CastContext は、現在のキャスト状態に関する情報を提供し、キャスト状態とキャスト セッション状態の変化のイベントをトリガーするシングルトン オブジェクトです。
  • CastSession オブジェクトはセッションを管理します。状態情報を提供し、デバイスの音量の変更、ミュート状態、アプリのメタデータなどのイベントをトリガーします。
  • キャスト ボタン要素。HTML ボタンを拡張するシンプルな HTML カスタム要素です。提供されているキャストボタンでは不十分な場合は、キャスト状態を使用してキャストボタンを実装できます。
  • RemotePlayerController は、リモート プレーヤーの実装を簡素化するためのデータ バインディングを提供します。

名前空間について詳しくは、Google Cast Web Sender API リファレンスをご覧ください。

キャスト アイコン

アプリ内のキャスト アイコン コンポーネントは、すべてフレームワークによって処理されます。これには、公開設定の管理やクリック イベントの処理が含まれます。

<google-cast-launcher></google-cast-launcher>

または、プログラムでボタンを作成することもできます。

document.createElement("google-cast-launcher");

必要に応じて、サイズや位置などのスタイルを追加で要素に適用できます。--connected-color 属性を使用して、接続済みのウェブ レシーバーの状態を表す色を選択し、--disconnected-color 属性を使用して切断状態を表す色を選択します。

初期化

フレームワーク API を読み込んだ後、アプリはハンドラ window.__onGCastApiAvailable を呼び出します。センダー ライブラリを読み込む前に、アプリでこのハンドラを window に設定してください。

このハンドラ内で、CastContextsetOptions(options) メソッドを呼び出して、Cast インタラクションを初期化します。

次に例を示します。

<script>
window['__onGCastApiAvailable'] = function(isAvailable) {
  if (isAvailable) {
    initializeCastApi();
  }
};
</script>

次に、API を次のように初期化します。

initializeCastApi = function() {
  cast.framework.CastContext.getInstance().setOptions({
    receiverApplicationId: applicationId,
    autoJoinPolicy: chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED
  });
};

まず、アプリはフレームワークが提供する CastContext オブジェクトのシングルトン インスタンスを取得します。次に、CastOptions オブジェクトを使用する setOptions(options) を使用して、applicationID を設定します。

登録を必要としないデフォルトのメディア レシーバーを使用している場合は、applicationID の代わりに、以下に示すように Web Sender SDK によって事前定義された定数を使用します。

cast.framework.CastContext.getInstance().setOptions({
  receiverApplicationId: chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID
});

メディア コントロール

CastContext が初期化されると、アプリは getCurrentSession() を使用していつでも現在の CastSession を取得できます。

var castSession = cast.framework.CastContext.getInstance().getCurrentSession();

CastSession を使用すると、loadMedia(loadRequest) を使用して、接続されたキャスト デバイスにメディアを読み込むことができます。まず、contentIdcontentType、およびコンテンツに関連するその他の情報を使用して、MediaInfo を作成します。次に、そこから LoadRequest を作成し、リクエストに関連するすべての情報を設定します。最後に、CastSession に対して loadMedia(loadRequest) を呼び出します。

var mediaInfo = new chrome.cast.media.MediaInfo(currentMediaURL, contentType);
var request = new chrome.cast.media.LoadRequest(mediaInfo);
castSession.loadMedia(request).then(
  function() { console.log('Load succeed'); },
  function(errorCode) { console.log('Error code: ' + errorCode); });

loadMedia メソッドは Promise を返します。これを使用して、正常な結果を得るために必要なオペレーションを実行できます。Promise が拒否された場合、関数の引数は chrome.cast.ErrorCode になります。

プレーヤーの状態変数には RemotePlayer でアクセスできます。メディア イベントのコールバックやコマンドを含め、RemotePlayer とのすべてのやり取りは RemotePlayerController で処理されます。

var player = new cast.framework.RemotePlayer();
var playerController = new cast.framework.RemotePlayerController(player);

RemotePlayerController は、読み込まれたメディアの再生、一時停止、停止、SEEK の完全なメディア コントロールをアプリに与えます。

  • 再生/一時停止: playerController.playOrPause();
  • 停止: playerController.stop();
  • シーク: playerController.seek();

RemotePlayerRemotePlayerController を Polymer や Angular などのデータ バインディング フレームワークとともに使用して、リモート プレーヤーを実装できます。

Angular のコード スニペットは次のとおりです。

<button id="playPauseButton" class="playerButton"
  ng-disabled="!player.canPause"
  ng-click="controller.playOrPause()">
    {{player.isPaused ? 'Play' : 'Pause'}}
</button>
<script>
var player = new cast.framework.RemotePlayer();
var controller = new cast.framework.RemotePlayerController(player);
// Listen to any player update, and trigger angular data binding
update.controller.addEventListener(
  cast.framework.RemotePlayerEventType.ANY_CHANGE,
  function(event) {
    if (!$scope.$$phase) $scope.$apply();
  });
</script>

メディア ステータス

メディアの再生中に、RemotePlayerController オブジェクトのさまざまな cast.framework.RemotePlayerEventType イベントのリスナーを設定することでキャプチャできるさまざまなイベントが発生します。

メディア ステータス情報を取得するには、cast.framework.RemotePlayerEventType.MEDIA_INFO_CHANGED イベントを使用します。このイベントは、再生が変更されたときと CastSession.getMediaSession().media が変更されたときにトリガーされます。

playerController.addEventListener(
  cast.framework.RemotePlayerEventType.MEDIA_INFO_CHANGED, function() {
    // Use the current session to get an up to date media status.
    let session = cast.framework.CastContext.getInstance().getCurrentSession();

    if (!session) {
        return;
    }

    // Contains information about the playing media including currentTime.
    let mediaStatus = session.getMediaSession();
    if (!mediaStatus) {
        return;
    }

    // mediaStatus also contains the mediaInfo containing metadata and other
    // information about the in progress content.
    let mediaInfo = mediaStatus.media;
  });

一時停止、再生、再開、シークなどのイベントが発生した場合、アプリはそれらに対処し、キャスト デバイス上のウェブ レシーバー アプリとの同期を行う必要があります。詳しくは、ステータスの更新をご覧ください。

セッション管理の仕組み

Cast SDK ではキャスト セッションの概念が導入されています。キャスト セッションの確立は、デバイスへの接続、ウェブ レシーバー アプリの起動(または参加)、そのアプリへの接続、メディア コントロール チャンネルの初期化の各ステップを組み合わせて確立されます。キャスト セッションとウェブ レシーバーのライフサイクルについて詳しくは、ウェブ レシーバーのアプリケーション ライフサイクル ガイドをご覧ください。

セッションは CastContext クラスによって管理され、アプリは cast.framework.CastContext.getInstance() を介してこのクラスを取得できます。個々のセッションは、Session クラスのサブクラスで表されます。たとえば、CastSession はキャスト デバイスを含むセッションを表します。アプリは CastContext.getCurrentSession() を介して、現在アクティブなキャスト セッションにアクセスできます。

セッション状態をモニタリングするには、CastContextEventType.SESSION_STATE_CHANGED イベントタイプの CastContext にリスナーを追加します。

var context = cast.framework.CastContext.getInstance();
context.addEventListener(
  cast.framework.CastContextEventType.SESSION_STATE_CHANGED,
  function(event) {
    switch (event.sessionState) {
      case cast.framework.SessionState.SESSION_STARTED:
      case cast.framework.SessionState.SESSION_RESUMED:
        break;
      case cast.framework.SessionState.SESSION_ENDED:
        console.log('CastContext: CastSession disconnected');
        // Update locally as necessary
        break;
    }
  })

接続の解除(ユーザーがキャスト ダイアログで [キャストを停止] ボタンをクリックしたときなど)については、リスナーに RemotePlayerEventType.IS_CONNECTED_CHANGED イベントタイプのリスナーを追加できます。リスナーで、RemotePlayer が切断されているかどうかを確認します。ローカル プレーヤーの状態を必要に応じて更新します。次に例を示します。

playerController.addEventListener(
  cast.framework.RemotePlayerEventType.IS_CONNECTED_CHANGED, function() {
    if (!player.isConnected) {
      console.log('RemotePlayerController: Player disconnected');
      // Update local player to disconnected state
    }
  });

ユーザーはフレームワークのキャスト アイコンからキャストの終了を直接制御できますが、センダー自体は現在の CastSession オブジェクトを使用してキャストを停止できます。

function stopCasting() {
  var castSession = cast.framework.CastContext.getInstance().getCurrentSession();
  // End the session and pass 'true' to indicate
  // that Web Receiver app should be stopped.
  castSession.endSession(true);
}

ストリーミング転送

セッション状態の保持はストリーム転送の基礎となります。ユーザーは、音声コマンド、Google Home アプリ、スマートディスプレイを使用して、既存の音声ストリームや動画ストリームをデバイス間で移動できます。メディアの再生が一方のデバイス(ソース)で停止し、別のデバイス(宛先)で続行されます。最新のファームウェアを搭載したキャスト デバイスは、ストリーム転送のソースまたは宛先として機能します。

ストリーム転送中に新しい宛先デバイスを取得するには、cast.framework.SessionState.SESSION_RESUMED イベントが呼び出されたときに CastSession#getCastDevice() を呼び出します。

詳しくは、ウェブ レシーバーでのストリーム転送をご覧ください。