カスタムのウェブレシーバーを作成する

1. 概要

Google Cast ロゴ

この Codelab では、カスタム ウェブ レシーバー アプリを作成して、Cast 対応デバイスでコンテンツを再生する方法について説明します。

Google Cast とは

Google Cast では、ユーザーはモバイル デバイスからテレビにコンテンツをキャストできます。モバイル デバイスやパソコンの Chrome ブラウザをリモコンとして使い、テレビでメディアを再生できます。

Google Cast SDK を使用すると、アプリで Google Cast 対応デバイス(テレビ、サウンド システムなど)を操作できます。Cast SDK には、Google Cast デザイン チェックリストに基づいて、必要な UI コンポーネントが用意されています。

Google Cast のデザイン チェックリストは、サポートされているすべてのプラットフォームでキャストのユーザー エクスペリエンスをシンプルで予測可能なものにするために用意されています。詳しくはこちらをご覧ください。

達成目標

この Codelab を完了すると、Cast 対応デバイスに動画コンテンツを表示できる独自のカスタム レシーバーとして機能する HTML5 アプリが完成します。

学習内容

  • レシーバー開発のセットアップ方法
  • Cast Application Framework に基づく Cast 対応レシーバーの基本。
  • キャストされた動画を受信する方法。
  • Debug Logger を統合する方法
  • スマートディスプレイ用にレシーバーを最適化する方法

必要なもの

  • 最新の Google Chrome ブラウザ
  • HTTPS ホスティング サービス(Firebase Hostingngrok など)
  • インターネットにアクセスできる Google Cast デバイス(ChromecastAndroid TV など)。
  • HDMI 入力対応のテレビまたはモニター

エクスペリエンス

  • ウェブ開発についての予備知識が必要です。
  • 一般的なテレビの視聴経験も必要です。

このチュートリアルの利用方法をお選びください。

通読するのみ 通読し、演習を行う

ウェブアプリの構築経験をどのように評価されますか。

初心者 中級者 上級者

テレビ視聴のご経験についてお答えください。

初心者 中級者 上級者

2. サンプルコードを取得する

サンプルコードはすべてパソコンにダウンロードできます。

ダウンロードした ZIP ファイルを解凍します。

3. レシーバーをローカルでデプロイする

キャスト デバイスでウェブ レシーバーを使用するには、キャスト デバイスからアクセスできる場所にホストする必要があります。https 対応のサーバーがすでにある場合は、以降の手順をスキップして、URL をメモします。これは次のセクションで必要になります。

使用できるサーバーがない場合は、Firebase Hosting または ngrok を使用できます。

サーバーを実行する

選択したサービスを設定したら、app-start に移動してサーバーを起動します。

ホストされているレシーバーの URL をメモします。これは次のセクションで使用します。

4. Cast のデベロッパー コンソールでアプリを登録する

この Codelab で作成したカスタム レシーバーを Chromecast デバイスで実行できるようにするには、アプリを登録する必要があります。アプリケーションを登録すると、送信側アプリケーションが API 呼び出し(受信側アプリケーションの起動など)を行うために使用する必要のあるアプリケーション ID が届きます。

[Add New Application] ボタンがハイライト表示されている Google Cast SDK デベロッパー コンソールの画像

[新しいアプリケーションを追加] をクリックします

[Custom Receiver] オプションがハイライト表示された [New Receiver Application] 画面の画像

[カスタム レシーバー] を選択します。これが開発中です。

[Receiver Application URL] フィールドに URL を入力している [New Custom Receiver] 画面の画像

新しいレシーバーの詳細を入力します。その際、

示しています。新しい受信者に割り当てられたアプリケーション ID をメモします。

また、Google Cast デバイスを登録して、公開前にレシーバー アプリにアクセスできるようにする必要があります。レシーバー アプリを公開すると、すべての Google Cast デバイスで利用できるようになります。この Codelab では、非公開のレシーバー アプリを使用することをおすすめします。

[新しいデバイスを追加] ボタンがハイライト表示されている Google Cast SDK デベロッパー コンソールの画像

[Add new Device] をクリックします。

[キャスト レシーバー デバイスの追加] ダイアログの画像

キャスト デバイスの背面に記載されているシリアル番号を入力し、わかりやすい名前を付けます。シリアル番号は、Google Cast SDK デベロッパー コンソールにアクセスする際に Chrome で画面をキャストして確認することもできます。

レシーバーとデバイスのテスト準備が整うまでに 5 ~ 15 分かかります。5 ~ 15 分待ってから、キャスト デバイスを再起動する必要があります。

5. サンプルアプリを実行する

Google Chrome のロゴ

新しいレシーバー アプリケーションのテスト準備が整うまで待つ間、完成したレシーバー アプリのサンプルがどのようなものになるかを見てみましょう。これから作成するレシーバーでは、アダプティブ ビットレート ストリーミングを使用してメディアを再生できるようになります(HTTP 経由の Dynamic Adaptive Streaming(DASH)用にエンコードされたサンプル コンテンツを使用します)。

ブラウザで、コマンド アンド コントロール(CaC)ツールを開きます。

コマンド アンド コントロール(CaC)ツールの [Cast Connect & Logger Controls] タブの画像

  1. CaC ツールが表示されます。
  2. デフォルトの「CC1AD845」サンプル レシーバー ID を使用し、[Set App ID] ボタンをクリックします。
  3. 左上のキャスト アイコンをクリックして Google Cast デバイスを選択します。

レシーバー アプリに接続されているコマンド アンド コントロール(CaC)ツールの [Cast Connect & Logger Controls] タブの画像

  1. 上部の [Load Media(メディアの読み込み)] タブに移動します。

コマンド アンド コントロール(CaC)ツールの [メディアの読み込み] タブの画像

  1. [コンテンツ別に読み込む] ボタンをクリックして、サンプル動画を再生します。
  2. Google Cast デバイスで動画の再生が開始され、デフォルトのレシーバーを使用した基本的なレシーバー機能が表示されます。

6. 開始プロジェクトを準備する

ダウンロードした開始用アプリに Google Cast のサポートを追加する必要があります。この Codelab では、以下の Google Cast の用語を使用します。

  • 送信側アプリはモバイル デバイスやノートパソコンで動作します。
  • レシーバー アプリは Google Cast デバイスで動作します。

これで、お好みのテキスト エディタを使用して、スターター プロジェクトを基にビルドする準備が整いました。

  1. ダウンロードしたサンプルコードから フォルダ アイコンapp-start ディレクトリを選択します。
  2. js/receiver.jsindex.html を開く

この Codelab の学習を進めると、http-server は加えた変更を受け取るようになります。起動しないのであれば、http-server を強制終了して再起動してみてください。

アプリの設計

レシーバー アプリはキャスト セッションを初期化し、センダーからの LOAD リクエスト(メディアを再生するコマンド)が届くまで待機します。

このアプリは、index.html で定義された 1 つのメインビューと、レシーバを機能させるためのすべてのロジックを含む js/receiver.js という JavaScript ファイルで構成されます。

index.html

この html ファイルには、レシーバー アプリの UI が含まれます。今のところ空です。Codelab 全体を通してこれを追加します。

receiver.js

このスクリプトは、レシーバー アプリのすべてのロジックを管理します。現時点では空のファイルですが、次のセクションでは、数行のコードで完全に機能するキャスト レシーバーに変えます。

7. 基本的なキャスト レシーバー

基本的なキャスト レシーバーが、起動時にキャスト セッションを初期化します。これは、接続されているすべての送信側アプリケーションに、受信側の起動が成功したことを通知するために必要です。さらに、新しい SDK は、DASH、HLS、Smooth Streaming を使用するアダプティブ ビットレート ストリーミング メディアと、そのままの MP4 ファイルを処理するよう事前構成されています。試してみましょう。

初期化

ヘッダーの index.html に次のコードを追加します。

<head>
  ...

  <script src="//www.gstatic.com/cast/sdk/libs/caf_receiver/v3/cast_receiver_framework.js"></script>
</head>

以下のコードを index.html <body> 内の footer> を読み込む <footer> の前に追加して、先ほど追加したスクリプトとともに配信されるデフォルトのレシーバー UI を表示するスペースをレシーバー SDK に与えます。receiver.js,

<cast-media-player></cast-media-player>

次に、以下で構成される js/receiver.js で SDK を初期化する必要があります。

  • Receiver SDK 全体への主要なエントリ ポイントである CastReceiverContext への参照を取得する
  • PlayerManager(再生を処理するオブジェクト)への参照を保存し、独自のカスタム ロジックのプラグインに必要なすべてのフックを提供する
  • CastReceiverContext に対して start() を呼び出して SDK を初期化する

js/receiver.js に以下を追加します。

const context = cast.framework.CastReceiverContext.getInstance();
const playerManager = context.getPlayerManager();

context.start();

8. 「基本的な」動画コンテンツのキャスト

この Codelab では、CaC ツールを使用してまったく新しいレシーバーを試します。

ウェブブラウザでコマンド&コントロール(CaC)ツールにアクセスします。

コマンド アンド コントロール(CaC)ツールの [Cast Connect & Logger Controls] タブの画像

この欄で以前に登録したアプリ ID をご自身のアプリ ID に置き換えて、[アプリ ID を設定] をクリックしてください。これにより、キャスト セッションの開始時にレシーバーを使用するようになります。

メディアのキャスト

キャスト デバイスでメディアを再生するには、おおまかに次の処理を行う必要があります。

  1. センダーは、メディア アイテムをモデル化する MediaInfo JSON オブジェクトを Cast SDK から作成します。
  2. センダーはキャスト デバイスに接続してレシーバー アプリを起動します。
  3. レシーバは、LOAD リクエストを通じて MediaInfo オブジェクトを読み込み、コンテンツを再生します。
  4. レシーバーはメディア ステータスをモニタリングしてトラッキングします。
  5. センダーはレシーバに再生コマンドを送信し、センダーアプリとユーザーの操作に基づいて再生を制御します。

最初の基本的な試みでは、MediaInfo にプレイアブル アセットの URL(MediaInfo.contentUrl に格納されている)を入力します。

実際のセンダーは、MediaInfo.contentId でアプリ固有のメディア識別子を使用します。レシーバーは、contentId を識別子として使用して適切なバックエンド API 呼び出しを行い、実際のアセット URL を解決し、これを MediaInfo.contentUrl. に設定します。レシーバーは、DRM ライセンスの取得や広告ブレークに関する情報の挿入などのタスクも処理します。

次のセクションで行うように、レシーバーを拡張します。現時点では、キャスト アイコンをクリックしてデバイスを選択し、レシーバーを開いてください。

レシーバー アプリに接続されているコマンド アンド コントロール(CaC)ツールの [Cast Connect & Logger Controls] タブの画像

[Load Media(メディアを読み込む)] タブに移動し、[Load by Content(コンテンツ別に読み込む)] ボタンをクリックします。レシーバーがサンプル コンテンツの再生を開始します。

コマンド アンド コントロール(CaC)ツールの [メディアの読み込み] タブの画像

そのため、Receiver SDK はすぐに次の処理を行います。

  • キャスト セッションの初期化
  • 再生可能なアセットを含むセンダーから受信した LOAD リクエストを処理する
  • 大画面に表示できる基本的なプレーヤー UI を提供します。

次のセクションに進む前に、CaC ツールとそのコードを自由に確認します。次のセクションでは、レシーバーを拡張してシンプルなサンプル API と通信し、送信者から受信した LOAD リクエストを処理します。

9. 外部 API と統合する

多くのデベロッパーが実際のアプリでキャスト レシーバーを操作する方法に合わせて、プレイアブル アセットの URL で送信するのではなく、目的のメディア コンテンツを API キーで参照する LOAD リクエストを処理するようにレシーバーを変更します。

通常、これは次のような理由から行われます。

  • 送信者はコンテンツの URL を知らない可能性があります。
  • キャスト アプリは、認証、その他のビジネス ロジック、API 呼び出しをレシーバで直接処理するように設計されています。

この機能は、主に PlayerManager setMessageInterceptor() メソッドに実装されます。これにより、受信メッセージをタイプ別にインターセプトし、SDK の内部メッセージ ハンドラに到達する前にメッセージを変更できます。このセクションでは、LOAD リクエストを次のように処理します。

  • 受信した LOAD リクエストとそのカスタム contentId を読み取ります。
  • ストリーミング可能なアセットを contentId で参照するには、API への GET 呼び出しを行います。
  • ストリームの URL を指定して LOAD リクエストを変更します。
  • MediaInformation オブジェクトを変更して、ストリーム タイプのパラメータを設定します。
  • リクエストを再生のために SDK に渡すか、リクエストされたメディアを Google が検索できない場合はコマンドを拒否します。

用意されているサンプル API は、一般的なレシーバ タスクをカスタマイズするための SDK のフックを示すものですが、ほぼそのまますぐに使用できます。

サンプル API

ブラウザで https://storage.googleapis.com/cpe-sample-media/content.json にアクセスして、サンプル動画カタログをご覧ください。コンテンツには、PNG 形式のポスター画像の URL と、DASH ストリームと HLS ストリームの両方が含まれています。DASH ストリームと HLS ストリームは、断片化された mp4 コンテナに保存された動画ソースとオーディオ ソースを分離します。

{
  "bbb": {
    "author": "The Blender Project",
    "description": "Grumpy Bunny is grumpy",
    "poster": "https://[...]/[...]/BigBuckBunny/images/screenshot1.png",
    "stream": {
      "dash": "https://[...]/[...]/BigBuckBunny/BigBuckBunny_master.mpd",
      "hls": "https://[...]/[...]/BigBuckBunny/BigBuckBunny_master.m3u8",
    "title": "Big Buck Bunny"
  },
  "fbb_ad": {
    "author": "Google Inc.",
    "description": "Introducing Chromecast. The easiest way to enjoy [...]",
    "poster": "https://[...]/[...]/ForBiggerBlazes/images/screenshot8.png",
    "stream": {
      "dash": "https://[...]/[...]/ForBiggerBlazes/ForBiggerBlazes.mpd",
      "hls": "https://[...]/[...]/ForBiggerBlazes/ForBiggerBlazes.m3u8",
    "title": "For Bigger Blazes"
  },

  [...]

}

次のステップでは、LOAD リクエストでレシーバが呼び出された後、各エントリのキー(bbb, fbb_ad など)をストリームの URL にマッピングします。

LOAD リクエストをインターセプトする

このステップでは、ホストされた JSON ファイルに対して XHR リクエストを行う関数を使用して、読み込みインターセプタを作成します。JSON ファイルを取得したら、コンテンツを解析してメタデータを設定します。以降のセクションでは、MediaInformation パラメータをカスタマイズしてコンテンツ タイプを指定します。

js/receiver.js ファイルで、context.start() を呼び出す直前に次のコードを追加します。

function makeRequest (method, url) {
  return new Promise(function (resolve, reject) {
    let xhr = new XMLHttpRequest();
    xhr.open(method, url);
    xhr.onload = function () {
      if (this.status >= 200 && this.status < 300) {
        resolve(JSON.parse(xhr.response));
      } else {
        reject({
          status: this.status,
          statusText: xhr.statusText
        });
      }
    };
    xhr.onerror = function () {
      reject({
        status: this.status,
        statusText: xhr.statusText
      });
    };
    xhr.send();
  });
}

playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.LOAD,
    request => {
      return new Promise((resolve, reject) => {
        // Fetch content repository by requested contentId
        makeRequest('GET', 'https://storage.googleapis.com/cpe-sample-media/content.json').then(function (data) {
          let item = data[request.media.contentId];
          if(!item) {
            // Content could not be found in repository
            reject();
          } else {
            // Add metadata
            let metadata = new
               cast.framework.messages.GenericMediaMetadata();
            metadata.title = item.title;
            metadata.subtitle = item.author;

            request.media.metadata = metadata;

            // Resolve request
            resolve(request);
          }
        });
      });
    });

次のセクションでは、DASH コンテンツ用に読み込みリクエストの media プロパティを構成する方法の概要を説明します。

サンプル API の DASH コンテンツを使用する

読み込みインターセプタを準備したので、次にコンテンツ タイプをレシーバーに指定します。この情報により、レシーバーにはマスター プレイリストの URL とストリームの MIME タイプが提供されます。js/receiver.js ファイルの LOAD インターセプタの Promise() に次のコードを追加します。

...
playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.LOAD,
    request => {
      return new Promise((resolve, reject) => {
          ...
          } else {
            // Adjusting request to make requested content playable
            request.media.contentUrl = item.stream.dash;
            request.media.contentType = 'application/dash+xml';
            ...
          }
        });
      });
    });

この手順を完了したら、「テスト」に進んで DASH コンテンツの読み込みを試すことができます。HLS コンテンツでの読み込みをテストする場合は、次の手順に進んでください。

サンプル API の HLS コンテンツを使用する

サンプル API には HLS コンテンツと DASH が含まれています。サンプル API の HLS URL を使用するには、前の手順で行った contentType の設定に加えて、読み込みリクエストで追加のプロパティが必要になります。HLS ストリームを再生するようレシーバーが設定されている場合、想定されるデフォルトのコンテナタイプはトランスポート ストリーム(TS)です。そのため、contentUrl プロパティのみが変更された場合、レシーバーは TS 形式のサンプル MP4 ストリームを開くことを試みます。読み込みリクエストで MediaInformation オブジェクトにプロパティを追加して、コンテンツが TS ではなく MP4 タイプであることをレシーバーが認識できるようにする必要があります。js/receiver.js ファイルの読み込みインターセプタに次のコードを追加して、contentUrl プロパティと contentType プロパティを変更します。さらに、HlsSegmentFormat プロパティと HlsVideoSegmentFormat プロパティを追加します。

...
playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.LOAD,
    request => {
      return new Promise((resolve, reject) => {
          ...
          } else {
            // Adjusting request to make requested content playable
            request.media.contentUrl = item.stream.hls;
            request.media.contentType = 'application/x-mpegurl';
            request.media.hlsSegmentFormat = cast.framework.messages.HlsSegmentFormat.FMP4;
            request.media.hlsVideoSegmentFormat = cast.framework.messages.HlsVideoSegmentFormat.FMP4;
            ...
          }
        });
      });
    });

テスト

もう一度、コマンド アンド コントロール(CaC)ツールを開き、アプリ ID をレシーバーのアプリ ID に設定します。キャスト ボタンを使用してデバイスを選択します。

[Load Media(メディアの読み込み)] タブに移動します。今回は、[Load by Content] ボタンの横にある [Content URL] フィールドのテキストを削除します。これにより、メディアへの contentId 参照のみを含む LOAD リクエストがアプリケーションによって送信されます。

コマンド アンド コントロール(CaC)ツールの [メディアの読み込み] タブの画像

レシーバの変更ですべてが問題なく動作すれば、インターセプタは MediaInfo オブジェクトを SDK が画面上で再生できる形に整形する必要があります。

[コンテンツ別に読み込む] ボタンをクリックして、メディアが正常に再生されるかどうかを確認します。Content ID は、content.json ファイル内の別の ID に自由に変更してください。

10. スマートディスプレイ向けに最適化する

スマートディスプレイは、レシーバー アプリがタップ操作をサポートするタッチ機能付きデバイスです。

このセクションでは、スマートディスプレイで起動したときにレシーバー アプリを最適化する方法と、プレーヤー コントロールをカスタマイズする方法について説明します。

UI コントロールへのアクセス

スマートディスプレイの UI コントロール オブジェクトには、cast.framework.ui.Controls.GetInstance() を使用してアクセスできます。context.start() の上の js/receiver.js ファイルに次のコードを追加します。

...

// Optimizing for smart displays
const touchControls = cast.framework.ui.Controls.getInstance();

context.start();

<cast-media-player> 要素を使用しない場合は、CastReceiverOptionstouchScreenOptimizedApp を設定する必要があります。この Codelab では、<cast-media-player> 要素を使用します。

context.start({ touchScreenOptimizedApp: true });

デフォルトのコントロール ボタンは、MetadataTypeMediaStatus.supportedMediaCommands に基づいて各スロットに割り当てられます。

動画コントロール

MetadataType.MOVIEMetadataType.TV_SHOWMetadataType.GENERIC の場合、スマートディスプレイの UI コントロール オブジェクトは次の例のように表示されます。

UI コントロールが上に重ねて再生されている動画の画像

  1. --playback-logo-image
  2. MediaMetadata.subtitle
  3. MediaMetadata.title
  4. MediaStatus.currentTime
  5. MediaInformation.duration
  6. ControlsSlot.SLOT_SECONDARY_1: ControlsButton.QUEUE_PREV
  7. ControlsSlot.SLOT_PRIMARY_1: ControlsButton.SEEK_BACKWARD_30
  8. PLAY/PAUSE
  9. ControlsSlot.SLOT_PRIMARY_2: ControlsButton.SEEK_FORWARD_30
  10. ControlsSlot.SLOT_SECONDARY_2: ControlsButton.QUEUE_NEXT

音声コントロール

MetadataType.MUSIC_TRACK の場合、スマートディスプレイの UI コントロール オブジェクトは次のように表示されます。

UI コントロールが上に重なって再生されている音楽の画像

  1. --playback-logo-image
  2. MusicTrackMediaMetadata.albumName
  3. MusicTrackMediaMetadata.title
  4. MusicTrackMediaMetadata.albumArtist
  5. MusicTrackMediaMetadata.images[0]
  6. MediaStatus.currentTime
  7. MediaInformation.duration
  8. ControlsSlot.SLOT_SECONDARY_1: ControlsButton.NO_BUTTON
  9. ControlsSlot.SLOT_PRIMARY_1: ControlsButton.QUEUE_PREV
  10. PLAY/PAUSE
  11. ControlsSlot.SLOT_PRIMARY_2: ControlsButton.QUEUE_NEXT
  12. ControlsSlot.SLOT_SECONDARY_2: ControlsButton.NO_BUTTON

サポートされているメディア コマンドのアップデート

UI コントロール オブジェクトは、MediaStatus.supportedMediaCommands に基づいて ControlsButton を表示するかどうかも決定します。

supportedMediaCommands の値が ALL_BASIC_MEDIA と等しい場合、デフォルトのコントロール レイアウトは次のようになります。

メディア プレーヤーのコントロール: 進行状況バー、[再生] ボタン、[早送り]、[巻き戻し] ボタンが有効になった画像

supportedMediaCommands の値が ALL_BASIC_MEDIA | QUEUE_PREV | QUEUE_NEXT と等しい場合、デフォルトのコントロール レイアウトは次のようになります。

メディア プレーヤーのコントロール: 進行状況バー、[再生] ボタン、[早送りする] ボタンと [巻き戻し] ボタン、[前のキューに入れる] ボタンと [次のキューに入れる] ボタンが有効である

supportedMediaCommands の値が PAUSE | QUEUE_PREV | QUEUE_NEXT と等しい場合、デフォルトのコントロール レイアウトは次のようになります。

メディア プレーヤーのコントロール: 進行状況バー、[再生] ボタン、[キューの前にキューに入れる] ボタン、[次のキューをキューに追加] ボタンが有効になった画像

テキスト トラックが利用可能な場合、字幕ボタンは常に SLOT_1 に表示されます。

メディア プレーヤー コントロールの画像: 進行状況バー、[再生] ボタン、[早送り]、[巻き戻し] ボタン、[次のキューに入れる] ボタン、[次のキューをキューに追加] ボタン、[字幕] ボタンが有効である

レシーバー コンテキストの開始後に supportedMediaCommands の値を動的に変更するには、PlayerManager.setSupportedMediaCommands を呼び出して値をオーバーライドします。また、addSupportedMediaCommands を使用して新しいコマンドを追加したり、removeSupportedMediaCommands を使用して既存のコマンドを削除したりすることもできます。

コントロール ボタンのカスタマイズ

PlayerDataBinder を使用してコントロールをカスタマイズできます。js/receiver.js ファイルで、TouchControls の下に次のコードを追加して、コントロールの最初のスロットを設定します。

...

// Optimizing for smart displays
const touchControls = cast.framework.ui.Controls.getInstance();
const playerData = new cast.framework.ui.PlayerData();
const playerDataBinder = new cast.framework.ui.PlayerDataBinder(playerData);

playerDataBinder.addEventListener(
  cast.framework.ui.PlayerDataEventType.MEDIA_CHANGED,
  (e) => {
    if (!e.value) return;

    // Clear default buttons and re-assign
    touchControls.clearDefaultSlotAssignments();
    touchControls.assignButton(
      cast.framework.ui.ControlsSlot.SLOT_PRIMARY_1,
      cast.framework.ui.ControlsButton.SEEK_BACKWARD_30
    );
  });

context.start();

11. スマートディスプレイへのメディア ブラウジングの実装

メディア ブラウズは、ユーザーがタッチデバイスで追加コンテンツを探索できるようにする CAF Receiver 機能です。これを実装するには、PlayerDataBinder を使用して BrowseContent UI を設定します。次に、表示するコンテンツに応じて BrowseItems を入力します。

BrowseContent

BrowseContent UI とそのプロパティの例を次に示します。

2 つの動画のサムネイルと 3 つ目のサムネイルの一部が表示されている BrowseContent UI の画像

  1. BrowseContent.title
  2. BrowseContent.items

アスペクト比

targetAspectRatio property を使用して、画像アセットに最適なアスペクト比を選択します。CAF Receiver SDK では、SQUARE_1_TO_1PORTRAIT_2_TO_3LANDSCAPE_16_TO_9 の 3 つのアスペクト比がサポートされています。

BrowseItem

BrowseItem を使用して、各アイテムのタイトル、サブタイトル、再生時間、画像を表示します。

2 つの動画のサムネイルと 3 つ目のサムネイルの一部が表示されている BrowseContent UI の画像

  1. BrowseItem.image
  2. BrowseItem.duration
  3. BrowseItem.title
  4. BrowseItem.subtitle

メディア ブラウズ データを設定する

ブラウジングするメディア コンテンツのリストを指定するには、setBrowseContent を呼び出します。次のコードを、playerDataBinder の下の js/receiver.js ファイルに追加し、MEDIA_CHANGED イベント リスナーで「次の動画」というタイトルでブラウジング アイテムを設定します。

// Optimizing for smart displays
const touchControls = cast.framework.ui.Controls.getInstance();
const playerData = new cast.framework.ui.PlayerData();
const playerDataBinder = new cast.framework.ui.PlayerDataBinder(playerData);

...

let browseItems = getBrowseItems();

function getBrowseItems() {
  let browseItems = [];
  makeRequest('GET', 'https://storage.googleapis.com/cpe-sample-media/content.json')
  .then(function (data) {
    for (let key in data) {
      let item = new cast.framework.ui.BrowseItem();
      item.entity = key;
      item.title = data[key].title;
      item.subtitle = data[key].description;
      item.image = new cast.framework.messages.Image(data[key].poster);
      item.imageType = cast.framework.ui.BrowseImageType.MOVIE;
      browseItems.push(item);
    }
  });
  return browseItems;
}

let browseContent = new cast.framework.ui.BrowseContent();
browseContent.title = 'Up Next';
browseContent.items = browseItems;
browseContent.targetAspectRatio = cast.framework.ui.BrowseImageAspectRatio.LANDSCAPE_16_TO_9;

playerDataBinder.addEventListener(
  cast.framework.ui.PlayerDataEventType.MEDIA_CHANGED,
  (e) => {
    if (!e.value) return;

    ....

    // Media browse
    touchControls.setBrowseContent(browseContent);
  });

メディア ブラウズ アイテムをクリックすると、LOAD インターセプタがトリガーされます。次のコードを LOAD インターセプタに追加して、request.media.contentId をメディア ブラウズ アイテムの request.media.entity にマッピングします。

playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.LOAD,
    request => {
      ...

      // Map contentId to entity
      if (request.media && request.media.entity) {
        request.media.contentId = request.media.entity;
      }

      return new Promise((resolve, reject) => {
            ...
        });
    });

BrowseContent オブジェクトを null に設定して、メディア ブラウズ UI を削除することもできます。

12. レシーバー アプリのデバッグ

Cast Receiver SDK には、CastDebugLogger API とコンパニオンのコマンド&コントロール(CaC)ツールを使用してログをキャプチャすることで、レシーバ アプリを簡単にデバッグできるという選択肢もあります。

初期化

API を組み込むには、CastDebugLogger ソース スクリプトを index.html ファイルに追加します。ソースは、Cast Receiver SDK の宣言の後、<head> タグ内で宣言する必要があります。

<head>
  ...
  <script src="//www.gstatic.com/cast/sdk/libs/caf_receiver/v3/cast_receiver_framework.js"></script>
  <!-- Cast Debug Logger -->
  <script src="//www.gstatic.com/cast/sdk/libs/devtools/debug_layer/caf_receiver_logger.js"></script>
</head>

js/receiver.js のファイルの先頭と playerManager の下に、次のコードを追加して CastDebugLogger インスタンスを取得し、ロガーを有効にします。

const context = cast.framework.CastReceiverContext.getInstance();
const playerManager = context.getPlayerManager();

// Debug Logger
const castDebugLogger = cast.debug.CastDebugLogger.getInstance();
const LOG_TAG = 'MyAPP.LOG';

// Enable debug logger and show a 'DEBUG MODE' overlay at top left corner.
context.addEventListener(cast.framework.system.EventType.READY, () => {
  if (!castDebugLogger.debugOverlayElement_) {
      castDebugLogger.setEnabled(true);
  }
});

デバッグロガーを有効にすると、DEBUG MODE というオーバーレイがレシーバーに表示されます。

フレームの左上隅の赤い背景に「DEBUG MODE」というメッセージが表示されている再生中の動画の画像

動画プレーヤー イベント

CastDebugLogger を使用すると、CAF Receiver SDK によって発生したプレーヤー イベントを簡単にログに記録でき、さまざまなロガーレベルでイベントデータを記録できます。loggerLevelByEvents 構成では、cast.framework.events.EventTypecast.framework.events.category を使用して、ログに記録するイベントを指定します。

castDebugLogger 宣言の下に次のコードを追加して、プレーヤーの CORE イベントがトリガーされたとき、または mediaStatus の変更がブロードキャストされたときにログに記録します。

// Debug Logger
const castDebugLogger = cast.debug.CastDebugLogger.getInstance();

// Enable debug logger and show a 'DEBUG MODE' overlay at top left corner.
context.addEventListener(cast.framework.system.EventType.READY, () => {
  if (!castDebugLogger.debugOverlayElement_) {
      castDebugLogger.setEnabled(true);
  }
});

// Set verbosity level for Core events.
castDebugLogger.loggerLevelByEvents = {
  'cast.framework.events.category.CORE': cast.framework.LoggerLevel.INFO,
  'cast.framework.events.EventType.MEDIA_STATUS': cast.framework.LoggerLevel.DEBUG
}

ログ メッセージとカスタムタグ

CastDebugLogger API を使用すると、レシーバーのデバッグ オーバーレイに表示されるログメッセージをさまざまな色で作成できます。以下のログメソッドを使用できます。優先度が高い順に示します。

  • castDebugLogger.error(custom_tag, message);
  • castDebugLogger.warn(custom_tag, message);
  • castDebugLogger.info(custom_tag, message);
  • castDebugLogger.debug(custom_tag, message);

各ログメソッドの最初のパラメータはカスタムタグです。意味のある任意の識別文字列を指定できます。CastDebugLogger は、タグを使用してログをフィルタします。タグの使用については、以降で詳しく説明します。2 つ目のパラメータはログ メッセージです。

実際のログを表示するには、LOAD インターセプタにログを追加します。

playerManager.setMessageInterceptor(
  cast.framework.messages.MessageType.LOAD,
  request => {
    castDebugLogger.info(LOG_TAG, 'Intercepting LOAD request');

    // Map contentId to entity
    if (request.media && request.media.entity) {
      request.media.contentId = request.media.entity;
    }

    return new Promise((resolve, reject) => {
      // Fetch content repository by requested contentId
      makeRequest('GET', 'https://storage.googleapis.com/cpe-sample-media/content.json')
        .then(function (data) {
          let item = data[request.media.contentId];
          if(!item) {
            // Content could not be found in repository
            castDebugLogger.error(LOG_TAG, 'Content not found');
            reject();
          } else {
            // Adjusting request to make requested content playable
            request.media.contentUrl = item.stream.dash;
            request.media.contentType = 'application/dash+xml';
            castDebugLogger.warn(LOG_TAG, 'Playable URL:', request.media.contentUrl);

            // Add metadata
            let metadata = new cast.framework.messages.MovieMediaMetadata();
            metadata.metadataType = cast.framework.messages.MetadataType.MOVIE;
            metadata.title = item.title;
            metadata.subtitle = item.author;

            request.media.metadata = metadata;

            // Resolve request
            resolve(request);
          }
      });
    });
  });

デバッグ オーバーレイに表示するメッセージを制御するには、カスタムタグごとに loggerLevelByTags でログレベルを設定します。たとえば、ログレベル cast.framework.LoggerLevel.DEBUG のカスタムタグを有効にすると、追加されたすべてのメッセージに error、warn、info、デバッグのログメッセージが表示されます。WARNING レベルのカスタムタグを有効にすると、エラーと警告メッセージのみが表示されます。

loggerLevelByTags 構成は省略可能です。カスタムタグがロガーレベルで設定されていない場合は、すべてのログメッセージがデバッグ オーバーレイに表示されます。

CORE イベントロガーの下に次のコードを追加します。

// Set verbosity level for Core events.
castDebugLogger.loggerLevelByEvents = {
  'cast.framework.events.category.CORE': cast.framework.LoggerLevel.INFO,
  'cast.framework.events.EventType.MEDIA_STATUS': cast.framework.LoggerLevel.DEBUG
}

// Set verbosity level for custom tags.
castDebugLogger.loggerLevelByTags = {
    [LOG_TAG]: cast.framework.LoggerLevel.DEBUG,
};

デバッグ オーバーレイ

Cast Debug Logger は、レシーバー上にデバッグ オーバーレイを提供し、キャスト デバイスにカスタム ログメッセージを表示します。デバッグ オーバーレイを切り替えるには showDebugLogs を使用し、オーバーレイのログメッセージを消去するには clearDebugLogs を使用します。

次のコードを追加して、レシーバーでデバッグ オーバーレイをプレビューします。

context.addEventListener(cast.framework.system.EventType.READY, () => {
  if (!castDebugLogger.debugOverlayElement_) {
      // Enable debug logger and show a 'DEBUG MODE' overlay at top left corner.
      castDebugLogger.setEnabled(true);

      // Show debug overlay
      castDebugLogger.showDebugLogs(true);

      // Clear log messages on debug overlay
      castDebugLogger.clearDebugLogs();
  }
});

デバッグ オーバーレイ(動画フレームの上にある半透明の背景にデバッグ ログメッセージのリスト)が表示された画像

13. 完了

ここでは、Cast Web Receiver SDK を使用してカスタムのウェブ レシーバー アプリを作成する方法を学習しました。

詳しくは、Web Receiver のデベロッパー ガイドをご覧ください。