Ad Breaks API のサポートをウェブレシーバーに追加する

1. 概要

Google Cast ロゴ

この Codelab では、Cast Ad Breaks API を使用するカスタム ウェブレシーバー アプリの作成方法について説明します。

Google Cast とは

Google Cast では、ユーザーはモバイル デバイスからテレビにコンテンツをキャストできます。ユーザーは自分のモバイル デバイスをリモコンとして使い、テレビでのメディア再生を行うことが可能です。

Google Cast SDK を使うと、アプリを拡張してテレビやサウンド システムを制御できます。Cast SDK を使用すると、Google Cast デザイン チェックリストに基づいて必要な UI コンポーネントを追加できます。

Google Cast デザイン チェックリストは、サポートされているすべてのプラットフォームにわたって、Cast ユーザー エクスペリエンスをシンプルで予測可能なものにするために使用します。

達成目標

この Codelab を修了すると、新しい Break API を利用するキャスト レシーバが構築されます。

学習内容

  • キャストのコンテンツに VMAP と VAST ブレークを追加する方法
  • ブレーク クリップをスキップする方法
  • シークのデフォルトのブレーク動作をカスタマイズする方法

必要なもの

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

テスト

  • ウェブ開発に関する経験が必要です。
  • キャスト センダーとレシーバのアプリケーションを構築した経験

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

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

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

初心者 中級 上級

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

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

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

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

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

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

サーバーを実行する

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

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

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

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

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

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

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

[Custom Receiver] を選択します。これが構築されます。

[受信者のアプリケーションの URL] 欄に入力している 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. Start プロジェクトを準備する

この Codelab を開始する前に、広告デベロッパー ガイドを確認して、新しい広告機能の概要を確認することをおすすめします。

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

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

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

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

この Codelab では、http-server が行った変更を取得するはずです。表示されない場合は、強制終了してから再起動してみてください。http-server

送信者の場合は、CAF Receiver デバッグツールを使用してキャスト セッションを開始します。レシーバーは、ストリームの再生を自動的に開始するように設計されています。

アプリの設計

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

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

index.html

この HTML ファイルには、レシーバ アプリの UI がすべて含まれています。現時点では、基本的に空です。

Receiver.js

このスクリプトは、レシーバー アプリのすべてのロジックを管理します。現在のところ、これには基本的な CAF レシーバーが含まれています。

6. コンテンツに VMAP を追加する

まず、Chrome でウェブ送信者を開きます。Cast SDK Developer Console で指定したレシーバー アプリケーション ID を入力し、[設定] をクリックします。

レシーバーには、コンテンツに広告を表示するためのロジックを追加する必要があります。

次の行を js/receiver.js ファイルにコピーします。これには、DoubleClick の VMAP タグのサンプル リンクとランダム化が含まれています。

const vmapUrl = "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/ad_rule_samples&ciu_szs=300x250&ad_rule=1&impl=s&gdfp_req=1&env=vp&output=vmap&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ar%3Dpremidpost&cmsid=496&vid=short_onecue&correlator=" + Math.floor(Math.random() * Math.pow(10, 10));

js/receiver.js fileplayerManager.setMessageInterceptor 関数を見つけ、関数の最後の return request; 行の前に次のコードを追加します。

request.media.vmapAdsRequest = {
    adTagUrl: vmapUrl,
};

注: 上記の vmapAdsRequest に割り当てられているオブジェクトは、VastAdsRequest オブジェクトの簡略版です。

変更を js/receiver.js に保存し、ページの任意の場所を右クリックして [キャスト] を選択して、ウェブの送信者でキャスト セッションを開始します。広告ストリームの再生はすぐに開始されます。

7. VAST をコンテンツに追加する

上記の VMAP コードを実装した場合は、そのコメントをコメントアウトしてください。以下では、このコンテンツに VAST 広告を実装する方法をご説明します。

次の内容を js/receiver.js ファイルにコピーします。これには、DoubleClick の 6 つの VAST ブレーク クリップとランダム文字列が含まれます。これらのブレーク クリップは 5 つのブレークに割り当てられます。また、各ブレークの位置も指定されています。

const addVASTBreaksToMedia = (mediaInformation) => {
    mediaInformation.breakClips = [
        {
            id: "bc1",
            title: "bc1 (Pre-roll)",
            vastAdsRequest: {
                adTagUrl: 'https://pubads.g.doubleclick.net/gampad/ads?slotname=/124319096/external/ad_rule_samples&sz=640x480&ciu_szs=300x250&cust_params=deployment%3Ddevsite%26sample_ar%3Dpremidpost&url=&unviewed_position_start=1&output=xml_vast3&impl=s&env=vp&gdfp_req=1&ad_rule=0&vad_type=linear&vpos=preroll&pod=1&ppos=1&lip=true&min_ad_duration=0&max_ad_duration=30000&vrid=6256&correlator=' + Math.floor(Math.random() * Math.pow(10, 10)) + '&video_doc_id=short_onecue&cmsid=496&kfa=0&tfcd=0'
            }
        },
        {
            id: "bc2",
            title: "bc2 (Mid-roll)",
            vastAdsRequest: {
                adTagUrl: 'https://pubads.g.doubleclick.net/gampad/ads?slotname=/124319096/external/ad_rule_samples&sz=640x480&ciu_szs=300x250&cust_params=deployment%3Ddevsite%26sample_ar%3Dpremidpost&url=&unviewed_position_start=1&output=xml_vast3&impl=s&env=vp&gdfp_req=1&ad_rule=0&cue=15000&vad_type=linear&vpos=midroll&pod=2&mridx=1&rmridx=1&ppos=1&lip=true&min_ad_duration=0&max_ad_duration=30000&vrid=6256&correlator=' + Math.floor(Math.random() * Math.pow(10, 10)) + '&video_doc_id=short_onecue&cmsid=496&kfa=0&tfcd=0'
            }
        },
        {
            id: "bc3",
            title: "bc3 (Mid-roll)",
            vastAdsRequest: {
                adTagUrl: 'https://pubads.g.doubleclick.net/gampad/ads?slotname=/124319096/external/ad_rule_samples&sz=640x480&ciu_szs=300x250&cust_params=deployment%3Ddevsite%26sample_ar%3Dpremidpost&url=&unviewed_position_start=1&output=xml_vast3&impl=s&env=vp&gdfp_req=1&ad_rule=0&cue=15000&vad_type=linear&vpos=midroll&pod=2&mridx=1&rmridx=1&ppos=1&lip=true&min_ad_duration=0&max_ad_duration=30000&vrid=6256&correlator=' + Math.floor(Math.random() * Math.pow(10, 10)) + '&video_doc_id=short_onecue&cmsid=496&kfa=0&tfcd=0'
            }
        },
        {
            id: "bc4",
            title: "bc4 (Mid-roll)",
            vastAdsRequest: {
                adTagUrl: 'https://pubads.g.doubleclick.net/gampad/ads?slotname=/124319096/external/ad_rule_samples&sz=640x480&ciu_szs=300x250&cust_params=deployment%3Ddevsite%26sample_ar%3Dpremidpost&url=&unviewed_position_start=1&output=xml_vast3&impl=s&env=vp&gdfp_req=1&ad_rule=0&cue=15000&vad_type=linear&vpos=midroll&pod=2&mridx=1&rmridx=1&ppos=1&lip=true&min_ad_duration=0&max_ad_duration=30000&vrid=6256&correlator=' + Math.floor(Math.random() * Math.pow(10, 10)) + '&video_doc_id=short_onecue&cmsid=496&kfa=0&tfcd=0'
            }
        },
        {
            id: "bc5",
            title: "bc5 (Mid-roll)",
            vastAdsRequest: {
                adTagUrl: 'https://pubads.g.doubleclick.net/gampad/ads?slotname=/124319096/external/ad_rule_samples&sz=640x480&ciu_szs=300x250&cust_params=deployment%3Ddevsite%26sample_ar%3Dpremidpost&url=&unviewed_position_start=1&output=xml_vast3&impl=s&env=vp&gdfp_req=1&ad_rule=0&cue=15000&vad_type=linear&vpos=midroll&pod=2&mridx=1&rmridx=1&ppos=1&lip=true&min_ad_duration=0&max_ad_duration=30000&vrid=6256&correlator=' + Math.floor(Math.random() * Math.pow(10, 10)) + '&video_doc_id=short_onecue&cmsid=496&kfa=0&tfcd=0'
            }
        },
        {
            id: "bc6",
            title: "bc6 (Post-roll)",
            vastAdsRequest: {
                adTagUrl: 'https://pubads.g.doubleclick.net/gampad/ads?slotname=/124319096/external/ad_rule_samples&sz=640x480&ciu_szs=300x250&cust_params=deployment%3Ddevsite%26sample_ar%3Dpremidpost&url=&unviewed_position_start=1&output=xml_vast3&impl=s&env=vp&gdfp_req=1&ad_rule=0&vad_type=linear&vpos=postroll&pod=3&ppos=1&lip=true&min_ad_duration=0&max_ad_duration=30000&vrid=6256&correlator=' + Math.floor(Math.random() * Math.pow(10, 10)) + '&video_doc_id=short_onecue&cmsid=496&kfa=0&tfcd=0'
            }
        }
    ];
    mediaInformation.breaks = [
        {
            id: "b1",
            breakClipIds: ["bc1"],
            position: 0
        },
        {
            id: "b2",
            breakClipIds: ["bc2"],
            position: 15
        },
        {
            id: "b3",
            breakClipIds: ["bc3","bc4"],
            position: 60
        },
        {
            id: "b4",
            breakClipIds: ["bc5"],
            position: 100
        },
        {
            id: "b5",
            breakClipIds: ["bc6"],
            position: -1
        }
    ];
};

注: 改行の breakClipIds プロパティは配列です。つまり、各ブレークに複数のブレーク クリップを割り当てることができます。

js/receiver.js file で、LOAD メッセージ インターセプター(playerManager.setMessageInterceptor で始まる行)を見つけ、関数の最後の return request; 行の前に次のコードを追加します。

addVASTBreaksToMedia(request.media);

変更を js/receiver.js に保存し、ページの任意の場所を右クリックして [キャスト] を選択して、ウェブの送信者でキャスト セッションを開始します。広告ストリームの再生はすぐに開始されます。

8. 広告ブレークをスキップする

CAF には BreakManager という新しいクラスがあり、広告の動作に関するカスタム ビジネスルールの実装をサポートします。一定の期間が経過した広告はスキップできるように猶予期間を設定したいとします。

この例では、送信者にメディア コントロールはありません。プレロール 15 秒の時点から最初のミッドロール挿入点が再生される前に再生が開始するように、開始オフセットを 10 秒に設定します。

playerManager.setMessageInterceptor を見つけて、return request の前に次の行を追加します。

request.currentTime = 10;

receiver.js ファイルを保存し、キャスト セッションを開始します。10 秒後にコンテンツが読み込まれ、5 秒後に広告が再生されます。

次に、ミッドロールを 15 秒の間隔でスキップするルールを追加します。

ブレーク読み込みのインターセプタを設定するには、BreakManager のインスタンスが必要です。js/receiver.js ファイルの context 変数と playerManager 変数を含む行の後に、次の行をコピーします。

const breakManager = playerManager.getBreakManager();

次に、30 秒より前に発生した広告ブレークを無視するルールを持つインターセプタを設定します。このインターセプタは、PlayerManager の LOAD インターセプタと同じように機能しますが、BreakClips の読み込みに固有のものです。

次の内容を js/receiver.js ファイルにコピーします。

breakManager.setBreakClipLoadInterceptor((breakClip, breakCtx) => {
  /** Below code will skip playback of break clips if the break position is less than 30 **/
  let breakObj = breakCtx.break;
  if(breakObj.position < 30)
    return null;
  else
    return breakClip;
});

注: スキップする必要のある BreakClips には、null が返されます。

変更を js/receiver.js に保存し、ページの任意の場所を右クリックして [キャスト] を選択して、ウェブの送信者でキャスト セッションを開始します。

ストリームの再生が開始されますが、15 秒前に見た広告ブロックはスキップされます。

9. Break Seek の動作をカスタマイズする

ユーザーが早送りすると、コンテンツ再生がシーク開始位置から再生される前に、seeFrom と SeeTo の最後の未再生のブレークが再生されます。ユーザーがシーク再生をすると、ブレークは再生されません。これはデフォルトのブレーク動作です。

シークで再生するブレークをカスタマイズするには、BreakManager を使用します。必要なカスタム動作を指定するには、BreakManager の setBreakSeekInterceptor を使用します。シーク操作が実行されるたびに setBreakSeekInterceptor が呼び出されます。

コールバック関数を setBreakSeekInterceptor に渡します。コールバック関数には、シーク位置とシーク位置の間のすべてのブレークを含むオブジェクトが渡されます。

次に、seeFrom 位置と SeeTo 位置の間でまだ監視されていないブレークを再生するルールを持つインターセプタを設定しましょう。

次の内容を js/receiver.js ファイルにコピーします。

breakManager.setBreakSeekInterceptor(function(breakSeekData) {
     /**
     *
     * Below code will play an unwatched break between seekFrom and seekTo position
     * Note: If the position of a break is less than 30 then it will be skipped due to the setBreakClipLoadInterceptor code
     */

    let breakToPlay;
    for (let i = 0; i < breakSeekData.breaks.length; i++) {
        if (!breakSeekData.breaks[i].isWatched) {
            breakToPlay = breakSeekData.breaks[i];
        }
    }
    if (breakToPlay){
        breakSeekData.breaks = [breakToPlay];
        return breakSeekData;
    }
});

注: null や null が返された場合は、何も表示されません。breakSeekData をそのまま返すと、seeFrom と SeeTo の間のブレークがすべて再生されます。

変更を js/receiver.js に保存し、ページの任意の場所を右クリックして [キャスト] を選択して、ウェブの送信者でキャスト セッションを開始します。広告ストリームの再生はすぐに開始されます。

10. 完了

最新の Cast Receiver SDK を使用してレシーバー アプリに広告を追加する方法を学習しました。

詳しくは、ミッドロール挿入点に関するデベロッパー ガイドをご覧ください。