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

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 対応レシーバーの基本。
  • キャストされた動画を受け取る方法
  • Debug Logger を統合する方法
  • スマートディスプレイ用にレシーバーを最適化する方法。

必要なもの

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

テスト

  • 事前にウェブ開発に関する知識が必要です。
  • 一般的なテレビの視聴経験も必要です。

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

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

ウェブアプリの構築について評価してください。

初心者 中級者 上級者

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

初級 中級 上級

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

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

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

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

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

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

サーバーを実行する

ご希望のサービスを設定したら、app-start に移動してサーバーを起動します。

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

4. Cast Developer Console でアプリを登録する

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

[Add New Application] ボタンがハイライト表示された Google Cast SDK Developer Console の画像

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

[New Receiver Application] 画面の画像。カスタム レシーバー オプションがハイライト表示されている

[カスタム レシーバー] を選択します。これで構築します。

[新しいカスタム レシーバ] 画面の画像。ユーザーが [レシーバー アプリケーション URL] フィールドに入力している URL が表示されます。

新しいレシーバーの詳細を入力します。その際には、最終的に指定した URL を使用してください

最後のセクションで確認できます。新しいレシーバーに割り当てられたアプリケーション ID をメモします

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

[Add New Device] ボタンがハイライト表示された Google Cast SDK Developer Console の画像

[Add new Device(新しいデバイスを追加)] をクリックします。

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

キャスト デバイスの背面に印字されているシリアル番号を入力し、わかりやすい名前を付けます。シリアル番号は、Google Cast SDK Developer Console にアクセスする際に Chrome で画面をキャストすることによって確認することもできます。

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

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

Google Chrome のロゴ

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

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

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

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

コマンド アンド コントロール(CaC)ツールの [Cast Connect と Logger Controls] タブのイメージがレシーバー アプリに接続されていることを示す

  1. 上部にある [メディアの読み込み] タブに移動します。

Command and Control(CaC)ツールの [Load Media] タブの画像

  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 という 1 つの JavaScript ファイルで構成されています。

index.html

この HTML ファイルには、レシーバアプリの UI が格納されています。現時点では空白です。この Codelab ではこれをコード全体に追加します。

レシーバー

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

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

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

初期化

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

<head>
  ...

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

<footer> を読み込む receiver.js, の前の index.html<body> に次のコードを追加して、追加したスクリプトに付属するデフォルトのレシーバ UI を表示するためのスペースをレシーバ SDK に提供します。

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

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

  • Receiver SDK 全体へのメインのエントリ ポイントである CastReceiverContext への参照を取得する
  • 再生を処理するオブジェクト PlayerManager への参照を保存し、独自のカスタム ロジックをプラグインするために必要なすべてのフックを提供します。
  • CastReceiverContextstart() を呼び出して 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 を設定] をクリックします。キャスト セッションの開始時にレシーバーを使用するようにツールに指示します。

メディアのキャスト

キャスト デバイスでメディアを再生する大まかな流れは次のとおりです。

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

この最初の基本的な試行では、再生可能なアセット URL(MediaInfo.contentUrl に格納されている)を MediaInfo に入力します。

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

次のセクションでは、レシーバーを拡張して、同様の処理を行います。今回は、キャスト アイコンをクリックし、デバイスを選択してレシーバーを開きます。

コマンド アンド コントロール(CaC)ツールの [Cast Connect と Logger Controls] タブのイメージがレシーバー アプリに接続されていることを示す

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

Command and Control(CaC)ツールの [Load Media] タブの画像

Receiver SDK は以下の機能をすぐに利用できます。

  • キャスト セッションの初期化
  • 体験プレイ アセットを含む送信者からの LOAD リクエストの処理
  • 大画面に表示できる基本的なプレーヤー UI を用意します。

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

9. 外部 API との統合

ほとんどのデベロッパーが実際のアプリケーションでキャスト レシーバとやり取りする方法に従って、再生可能なアセットの URL を送信するのではなく、API キーにより目的のメディア コンテンツを参照する LOAD リクエストを処理するようにレシーバを変更します。

アプリケーションがこれを実現するための一般的な理由は次のとおりです。

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

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

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

提供されているサンプル 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 パラメータをカスタマイズして、コンテンツ タイプを指定します。

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

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 タイプを提供します。LOAD インターセプタの Promise() の js/receiver.js ファイルに次のコードを追加します。

...
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';
            ...
          }
        });
      });
    });

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

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

サンプル API には、HLS コンテンツと DASH が含まれています。前のステップと同様に、contentType を設定するだけでなく、読み込みリクエストでは、サンプル API の HLS URL を使用するために追加のプロパティが必要になります。レシーバが HLS ストリームを再生するように構成されている場合、想定されるデフォルトのコンテナタイプはトランスポート ストリーム(TS)です。そのため、contentUrl プロパティのみが変更された場合、レシーバーはサンプル MP4 ストリームを TS 形式で開こうとします。読み込みリクエストで、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;
            ...
          }
        });
      });
    });

テストする

もう一度 Command and Control (CaC) ツールを開き、アプリ ID を受信側のアプリ ID に設定します。キャスト ボタンを使用してデバイスを選択します。

[メディアの読み込み] タブに移動します。今度は、[Load by Content] ボタンの横にある [Content URL] 欄のテキストを削除します。これにより、アプリは contentId 参照のみを含む LOAD リクエストをメディアに送信するよう求められます。

Command and Control(CaC)ツールの [Load Media] タブの画像

レシーバーに対する変更に問題がなければ、インターセプターは SDK が画面上で再生できるものに MediaInfo オブジェクトをシェーピングする必要があります。

[コンテンツごとに読み込む] ボタンをクリックして、メディアが適切に再生されているかどうかを確認します。必要に応じて、content.json ファイル内の Content ID を別の ID に変更できます。

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

スマートディスプレイはタップ機能を備えたデバイスで、レシーバー アプリがタップ操作に対応できます。

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

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

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

...

// 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 Controls オブジェクトは、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 レシーバー機能です。これを実装するには、PlayerDataBinder を使用して BrowseContent UI を設定します。その後、表示するコンテンツに基づいて BrowseItems に入力できます。

コンテンツの閲覧

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

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

  1. BrowseContent.title
  2. BrowseContent.items

アスペクト比

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

BrowseItem

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

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

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

メディア ブラウズ データの設定

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

// 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 インターセプトがトリガーされます。メディア ブラウズ項目の request.media.contentIdrequest.media.entity にマッピングするには、次のコードを LOAD インターセプターに追加します。

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 とコンパニオン Command and Control(CaC)ツールを使用してログを取得することで、レシーバー アプリを簡単にデバッグするためのオプションが用意されています。

初期化

API を組み込むには、index.html ファイルに CastDebugLogger ソース スクリプトを追加します。ソースは、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 を表示するオーバーレイがレシーバに表示されます。

フレームの左上に赤い背景で「デバッグモード」のメッセージが表示された動画の再生画像

プレーヤー イベントをロギングする

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

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

// 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 のカスタムタグを有効にすると、エラー、警告、情報、デバッグのログ メッセージで追加されたすべてのメッセージが表示されます。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 デベロッパー ガイドをご覧ください。