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

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 ブラウザ
  • Firebase Hostingngrok などの HTTPS ホスティング サービス。
  • インターネットに接続するように設定された ChromecastAndroid TV などの Google Cast デバイス。
  • HDMI 入力対応のテレビまたはモニター

経験

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

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

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

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

初心者 中級者 上級者

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

<ph type="x-smartling-placeholder"></ph> 初心者 中級 上達 をご覧ください。

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

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

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

3. レシーバーのローカルでのデプロイ

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

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

サーバーを実行する

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

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

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

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

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

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

「New Receiver Application」の画像[カスタム レシーバー] オプションがハイライト表示されたオプション

[カスタムレシーバー]を選択してこれが私たちが構築するものです。

「新しいカスタムのレシーバー」の画像[Receiver Application URL] に URL が入力されていることを示す画面フィールド

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

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

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

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

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

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

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

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

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

Google Chrome のロゴ

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

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

「Cast Connect とロガーコントロールCommand and Control(CaC)ツールの

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

「Cast Connect とロガーコントロールReceiver App に接続されていることを示す Command and Control(CaC)ツールのタブ

  1. [メディアの読み込み]に移動しますタブを使用します。

[Load Media] オプションの画像Command and Control(CaC)ツールの

  1. [Load by Content] をクリックします。サンプル動画を再生します。
  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 全体を通して追加します。

receiver.js

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

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

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

初期化

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

<head>
  ...

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

index.html<body> で、receiver.js, を読み込む <footer> の前に次のコードを追加して、追加したスクリプトと一緒に出荷されるデフォルトのレシーバー 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)ツールを開きます。

「Cast Connect とロガーコントロールCommand and Control(CaC)ツールの

先ほどフィールドで登録したご自身のアプリ ID を必ず置き換えて、[アプリ ID を設定] をクリックしてください。こうすることで、キャスト セッションの開始時にレシーバーを使用するようツールに指示できます。

メディアのキャスト

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

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

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

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

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

「Cast Connect とロガーコントロールReceiver App に接続されていることを示す Command and Control(CaC)ツールのタブ

[メディアの読み込み]に移動します[Load by Content] タブを] ボタンを離します。レシーバーでサンプル コンテンツの再生が開始されます。

[Load Media] オプションの画像Command and Control(CaC)ツールの

そのため、Receiver SDK はすぐに使用できる次のような処理を行います。

  • キャスト セッションの初期化
  • プレイアブル アセットを含む送信者から受信した LOAD リクエストを処理する
  • 大画面に表示される基本的なプレーヤー UI を提供します。

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

9. 外部 API と統合する

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

通常、アプリケーションは次の理由からこれを行います。

  • 送信者がコンテンツの 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 パラメータをカスタマイズして、コンテンツ タイプを指定します。

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 タイプが提供されます。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';
            ...
          }
        });
      });
    });

この手順を完了したら、「テストする」に進み、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 に設定します。キャスト ボタンを使用してデバイスを選択します。

[メディアの読み込み]に移動しますタブ今度は、[Content URL] のテキストを削除します。フィールドの横に [Load by Content] が表示されます。] ボタンを押すと、メディアへの contentId 参照のみを含む LOAD リクエストがアプリから強制的に送信されます。

[Load Media] オプションの画像Command and Control(CaC)ツールの

レシーバへの変更ですべてが問題なく動作したと仮定すると、インターセプタは MediaInfo オブジェクトを、SDK が画面上で再生できるものに整形します。

[Load by Content] をクリックします。] ボタンをクリックし、メディアが正常に再生されるかどうかを確認します。Content ID は、content.json ファイルで必要に応じて別の ID に変更してください。

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

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

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

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

スマートディスプレイの UI コントロール オブジェクトには、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 コントロール オブジェクトは、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 を呼び出します。次のコードを js/receiver.js ファイルの playerDataBinder の下と 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 を組み込むには、index.html ファイルに CastDebugLogger ソース スクリプトを追加します。ソースは <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 を使用して、ログに記録するイベントを指定します。

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 でカスタムタグを有効にすると、エラー、警告、情報、デバッグのログメッセージとともに追加されたすべてのメッセージが表示されます。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 デバッグロガーは、レシーバー上にデバッグ オーバーレイを提供し、キャスト デバイスにカスタム ログメッセージを表示します。デバッグ オーバーレイを切り替えるには 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 デベロッパー ガイドをご覧ください。