建立自訂的網路接收器

透過集合功能整理內容 你可以依據偏好儲存及分類內容。

1. 總覽

Google Cast 標誌

本程式碼研究室會說明如何建構自訂的網頁接收器應用程式,以便在支援 Cast 的裝置上播放內容。

什麼是 Google Cast?

Google Cast 可讓使用者將行動裝置的內容投放到電視上。這樣一來,使用者就可以使用行動裝置或電腦的 Chrome 瀏覽器做為電視媒體的遙控器。

Google Cast SDK 可讓應用程式控制支援 Google Cast 的裝置 (例如電視或音響系統)。Cast SDK 會根據 Google Cast 設計檢查清單,提供必要的 UI 元件。

提供 Google Cast 設計檢查清單,以便在所有支援的平台上提供簡單且可預測的 Cast 使用者體驗。請按這裡瞭解詳情。

我們要建構的是什麼?

完成本程式碼研究室後,您將擁有 HTML5 應用程式,做為您自己的自訂接收器,可在支援 Cast 的裝置上顯示影片內容。

課程內容

  • 如何設定接收器開發服務。
  • 以 Cast App 架構為基礎的支援 Cast 接收器的基本概念。
  • 如何接收投放影片。
  • 如何整合偵錯記錄工具。
  • 如何為智慧螢幕最佳化接收器。

軟硬體需求

  • 最新的 Google Chrome 瀏覽器。
  • node.js、npm、http-serverngrok 模組。
  • Google Cast 裝置,例如已設定網路連線的 ChromecastAndroid TV
  • 具備 HDMI 輸入端的電視或螢幕。

功能

  • 您必須先具備之前的網站開發知識。
  • 您也需要具備先前觀看電視節目的知識 :)

您如何使用這個教學課程?

唯讀閱讀 閱讀並完成練習

你對建構網頁應用程式體驗的體驗如何?

新手 中級 專業知識

針對觀看電視的體驗,你會給予什麼評價?

新手 中級 專業知識

2. 取得程式碼範例

您可以將所有程式碼範例下載至電腦上...

將下載的 ZIP 檔案解壓縮。

3. 在本機部署接收器

如要透過投放裝置使用接收器,你必須將 Cast 託管在 Cast 裝置所在的位置。如果你已備妥支援 https 的伺服器,請略過下列操作說明並記下網址,因為下一節將會用到。

如果你沒有可用的伺服器,也請不要擔心。您可以安裝 node.jshttp-serverngrok 節點模組。

npm install -g http-server
npm install -g ngrok

執行伺服器

如果你使用 http-server,請前往主控台並執行以下操作:

cd app-start
http-server

畫面應如下所示:

Starting up http-server, serving ./
Available on:
  http://127.0.0.1:8080
  http://172.19.17.192:8080
Hit CTRL-C to stop the server

請注意使用的本機通訊埠,然後在新的終端機中執行下列操作,以使用 ngrok 透過 HTTPS 公開本機接收器:

ngrok http 8080

這項操作會將本機 HTTP 伺服器設為 ngrok 通道,並指派給可在下一個步驟使用的 HTTPS 安全端點 (https://116ec943.eu.ngrok.io):

ngrok by @inconshreveable                                                                                                                                                                                                                                     (Ctrl+C to quit)

Session Status         online
Version                2.2.4
Web Interface          http://127.0.0.1:8080
Forwarding             http://116ec943.eu.ngrok.io -> localhost:8080
Forwarding             https://116ec943.eu.ngrok.io -> localhost:8080

在程式碼研究室期間,您應讓 ngrokhttp-server 保持執行。您所做的本機變更會立即生效。

4. 在 Cast Developer Console 中註冊應用程式

您必須註冊應用程式,才能在 Chromecast 裝置上執行本程式碼研究室內建的自訂接收器。註冊應用程式後,您會收到應用程式 ID 傳送的應用程式 ID,以便啟動 API 呼叫 (例如啟動接收器應用程式)。

Google Cast SDK Developer Console 的圖片,以方框特別標出「##9; New New Application'」按鈕

按一下「新增應用程式」

'新增接收端應用程式'畫面,以 '自訂接收器'選項醒目顯示

選取「自訂接收器」,也就是我們正在建構的內容。

'新增自訂接收器'畫面:使用者輸入「#39;Receiver 應用程式網址'」欄位的網址

輸入新收件者的詳細資料,請務必使用您最終接收的網址

一節。記下指派給新接收者的申請 ID

你必須先註冊 Google Cast 裝置,才能讓裝置存取接收器應用程式。發布應用程式後,該應用程式將適用於所有 Google Cast 裝置。在這個程式碼研究室中,建議您與未發布的接收端應用程式搭配使用。

Google Cast SDK Developer Console 的圖片,以方框特別標出「' Add Device」' 按鈕

按一下「新增裝置」。

「新增投放接收裝置」'「對話方塊」圖片

輸入顯示在投放裝置背面的序號,並輸入描述性名稱。在存取 Google Cast SDK Developer Console 時,您也可以在 Chrome 中投放螢幕,藉此找出序號

接收器和裝置需要 5 至 15 分鐘才能完成測試。等候 5 至 15 分鐘後,你必須重新啟動投放裝置。

5. 執行範例應用程式

Google Chrome 標誌

我們等待新版接收端應用程式準備進行測試,接著來看看已完成的接收器應用程式範例。我們將要建構的接收端將能使用自動調整位元率串流功能播放媒體 (我們會使用透過 HTTP 進行動態自動調整串流的編碼內容範例 (DASH)。

在瀏覽器中開啟 Command and Control (CaC) 工具

The#39;Cast Connect & Logger Controls' Command and Control (CaC) 工具分頁的圖片

  1. 您應該會看到我們的 CaC 工具。
  2. 使用預設的「CC1AD845」範例接收器 ID,然後按一下 [設定應用程式 ID] 按鈕。
  3. 按一下左上方的「投放」按鈕,然後選取你的 Google Cast 裝置。

'Cast Connect 展示工具記錄器控制項'指令與控制 (CaC) 工具分頁指示已連接至接收器應用程式

  1. 前往頂端的「載入媒體」分頁。

'Load Media' 指令與控制 (CaC) 工具分頁的圖片

  1. 按一下 [依內容載入] 按鈕以播放範例影片。
  2. 影片隨即會在 Google Cast 裝置上開始播放,以顯示預設接收器的基本基本功能。

6. 準備起始專案

我們需要針對你下載的啟動應用程式新增 Google Cast 支援。我們在本程式碼研究室中會使用以下 Google Cast 術語:

  • 寄件者應用程式位於行動裝置或筆記型電腦上執行
  • 接收端應用程式會在 Google Cast 裝置上執行。

您現在可以使用喜愛的文字編輯器,在範例專案上進行建構:

  1. 從下載的程式碼範例中選取 資料夾圖示app-start 目錄。
  2. 開啟 js/receiver.jsindex.html

請注意,當您逐步完成本程式碼研究室時,http-server 應挑選您進行的變更。如果發現不符合狀況,請嘗試終止並重新啟動 http-server

應用程式設計

接收器應用程式會初始化 Cast 工作階段,並待命,直到收到傳送者的 LOAD 要求 (也就是播放媒體的指令) 時。

此應用程式包含一個主要檢視畫面,定義於 index.html 中,以及一個名為 js/receiver.js 的 JavaScript 檔案,此檔案內含所有邏輯,讓接收器得以正常運作。

index.html

這個 HTML 檔案將包含接收者應用程式的使用者介面。目前暫無任何內容,我們會在程式碼研究室中將其加入。

接收器.js

這個指令碼會管理接收器應用程式的所有邏輯。目前它只是一個空白檔案,但我們在下一節中將這行程式碼改為功能完善的 Cast 接收器。

7. 基本的 Cast 接收器

基本的 Cast 接收器會在啟動時初始化投放工作階段。所有要求傳送者的應用程式,才能順利接收接收器。此外,新的 SDK 也預先設定為處理自動調整位元率串流媒體 (使用 DASH、HLS 和流暢串流),並立即處理純 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>,以為接收器 SDK 提供空間,以便顯示您剛剛新增的指令碼所隨附的預設接收器 UI。

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

現在,我們需要在 js/receiver.js 中初始化 SDK,包括:

  • 取得 CastReceiverContext 的參照,這是整個 Receiver SDK 的主要進入點
  • 儲存 PlayerManager 的參照,此物件會處理播放作業,並提供為您提供自訂自訂邏輯所需的所有掛鉤
  • CastReceiverContext 上呼叫 start() 來初始化 SDK

將以下內容新增至 js/receiver.js

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

context.start();

8. 投放「基本」影片內容

為本程式碼研究室,請使用 CaC 工具試用全新接收者。

將網路瀏覽器設為指令與控制 (CaC) 工具

The#39;Cast Connect & Logger Controls&#39; Command and Control (CaC) 工具分頁的圖片

請務必以您在該欄位中的先前註冊表單取代自己的應用程式 ID,然後按一下「設定應用程式 ID」。這項功能會指示工具在開始投放工作階段時使用接收器。

投放媒體

整體而言,如要在投放裝置上播放媒體,必須發生以下情況:

  1. 傳送者會使用投放 SDK 的 MediaInfo JSON 物件建立媒體項目模型。
  2. 傳送者連線至投放裝置,以啟動接收器應用程式。
  3. 接收器透過 LOAD 要求載入 MediaInfo 物件以播放內容。
  4. 接收器會監控及追蹤媒體狀態。
  5. 傳送者會傳送播放指令給接收者,以根據使用者與寄件者應用程式的互動來控製播放作業。

第一次基本嘗試時,我們將使用可播放的素材資源網址 (儲存在 MediaInfo.contentUrl) 填入 MediaInfo

真實寄件者會使用 MediaInfo.contentId 中的應用程式專屬媒體 ID。接收端使用 contentId 做為 ID 發出適當的後端 API 呼叫,以解析實際資產網址並設為 MediaInfo.contentUrl.。接收端也會處理工作,例如取得數位版權管理授權,或插入廣告插播資訊。

我們會在下節中擴充接收器,以便執行類似動作。現階段,請按一下「投放」圖示,然後選取裝置以開啟接收器。

&#39;Cast Connect 展示工具記錄器控制項&#39;指令與控制 (CaC) 工具分頁指示已連接至接收器應用程式

前往「載入媒體」分頁,然後按一下「按內容載入」'接收器應該會開始播放範例內容。

&#39;Load Media&#39; 指令與控制 (CaC) 工具分頁的圖片

因此,接收器 SDK 可直接處理:

  • 正在初始化投放工作階段
  • 處理含有可播放資產的寄件者提出的 LOAD 要求
  • 提供基本播放器 UI,並可在大螢幕上顯示。

在前往下一個部分之前,建議您先探索 CaC 工具及其程式碼,我們會在擴充部分中加入接收器,說明簡單的 API 範例,以便處理來自寄件者的連入 LOAD 要求。

9. 與外部 API 整合

為配合大多數開發人員在實際應用程式中與 Cast Receiver 的互動方式,我們會修改接收器,以處理透過其 API 金鑰參照預期媒體內容的 LOAD 要求,而非傳送可播放的素材資源網址。

應用程式通常會採行下列行動:

  • 寄件者可能不知道內容網址。
  • Cast 應用程式可以直接在接收器上處理驗證、其他商業邏輯或 API 呼叫。

這項功能主要在 PlayerManager setMessageInterceptor() 方法中實作。如此一來,您就能依類型攔截傳入訊息,並在 SDK 內部訊息處理常式送達前加以修改。在本節中,我們處理了 LOAD 要求,以便執行下列操作:

  • 讀取收到的 LOAD 要求及其自訂 contentId
  • 對我們的 API 發出 GET 呼叫,藉此透過 contentId 查詢可串流資產。
  • 使用串流網址修改 LOAD 要求。
  • 修改 MediaInformation 物件以設定串流類型參數。
  • 將請求傳遞至 SDK 進行播放;如果我們無法查詢要求的媒體,請拒絕指令。

提供的範例 API 示範了 SDK 的掛鉤,以自訂常見的接收器工作,同時仍依賴大部分的立即可用的體驗。

範例 API

將瀏覽器指向 https://storage.googleapis.com/cpe-sample-media/content.json,並查看範例影片目錄。內容包括 png 格式的海報圖片網址,以及 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 ) 對應至串流的網址。

攔截 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 內容

我們已完成載入攔截器,接著會將通知內容類型指定為接收器。這項資訊會向接收器提供主要播放清單網址和串流 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。除了設定上一個步驟中的 contentType 外,載入要求也需要一些屬性,才能使用範例 API 和 HLS 網址範例。當接收器設為播放 HLS 串流時,所需的預設容器類型為傳輸串流 (TS)。因此,如果只修改 contentUrl 屬性,接收器會嘗試嘗試以 TS 格式開啟範例 MP4 串流。在載入要求中,您應使用額外屬性來修改 MediaInformation 物件,讓接收器瞭解內容屬於 MP4 類型,而不是 TS。將下列程式碼加進載入攔截器的 js/Receiver.js 檔案中,以便修改 contentUrlcontentType 屬性。此外,請再新增 HlsSegmentFormatHlsVideoSegmentFormat 屬性。

...
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」欄位中的文字值,這會強制要求應用程式傳送只包含 contentId 參照內容的 LOAD 要求。

&#39;Load Media&#39; 指令與控制 (CaC) 工具分頁的圖片

假設所有對接收器的修改方式都可以正常運作,攔截器應負責將 MediaInfo 物件形狀成 SDK 可在螢幕上播放的內容。

按一下「以內容載入」按鈕,即可查看媒體是否正常播放。請記得將 content.json 檔案中的 Content ID 變更為其他 ID。

10. 針對智慧螢幕進行最佳化調整

智慧螢幕是一種觸控功能,可讓接收器應用程式支援觸控觸控設定。

本節說明如何在智慧螢幕上啟動時提供接收端應用程式最佳化,以及如何自訂播放器控制項。

存取使用者介面控制項

你可以使用 cast.framework.ui.Controls.GetInstance() 存取智慧螢幕的 UI 控制項物件。將下列程式碼加進 context.start() 上方的 js/receiver.js 檔案:

...

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

context.start();

如果你不使用 <cast-media-player> 元素,就必須在 CastReceiverOptions 中設定 touchScreenOptimizedApp。在這個程式碼研究室中,我們使用 <cast-media-player> 元素。

context.start({ touchScreenOptimizedApp: true });

系統會根據 MetadataTypeMediaStatus.supportedMediaCommands,為每個運算單元指派預設控制按鈕。

影片控制選項

對於 MetadataType.MOVIEMetadataType.TV_SHOWMetadataType.GENERIC,智慧螢幕的 UI Control 物件將如以下範例所示。

影片播放畫面上方有 UI 控制項的圖片

  1. --playback-logo-image
  2. MediaMetadata.subtitle
  3. MediaMetadata.title
  4. MediaStatus.currentTime
  5. MediaInformation.duration
  6. ControlsSlot.SLOT_SECONDARY_1ControlsButton.QUEUE_PREV
  7. ControlsSlot.SLOT_PRIMARY_1ControlsButton.SEEK_BACKWARD_30
  8. PLAY/PAUSE
  9. ControlsSlot.SLOT_PRIMARY_2ControlsButton.SEEK_FORWARD_30
  10. ControlsSlot.SLOT_SECONDARY_2ControlsButton.QUEUE_NEXT

音訊控制

針對 MetadataType.MUSIC_TRACK,智慧螢幕的 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_1ControlsButton.NO_BUTTON
  9. ControlsSlot.SLOT_PRIMARY_1ControlsButton.QUEUE_PREV
  10. PLAY/PAUSE
  11. ControlsSlot.SLOT_PRIMARY_2ControlsButton.QUEUE_NEXT
  12. ControlsSlot.SLOT_SECONDARY_2ControlsButton.NO_BUTTON

更新支援的媒體指令

UI 控制項物件也會根據 MediaStatus.supportedMediaCommands 判斷是否要顯示 ControlsButton

supportedMediaCommands 的值等於 ALL_BASIC_MEDIA 時,預設控制項版面配置會顯示如下:

媒體播放器控制項的圖片:進度列、&#39;播放&#39;按鈕、#39;向前略過&#39; &#39;倒轉{1}&#39;按鈕啟用

supportedMediaCommands 的值等於 ALL_BASIC_MEDIA | QUEUE_PREV | QUEUE_NEXT 時,預設控制項版面配置會顯示如下:

媒體播放器控制項的圖片:進度列、&#39;播放&#39;按鈕、##99、向前和

如果 SupportMediaCommands 的值等於 PAUSE | QUEUE_PREV | QUEUE_NEXT,預設控製版面配置將如下所示:

媒體播放器控制項的圖片:進度列、&#39;播放&#39;按鈕、&#39;待處理上一頁&#39;和 ##9;佇列下一個&#39;按鈕啟用

有文字音軌可用時,隱藏式輔助字幕按鈕一律會顯示在 SLOT_1 中。

媒體播放器控制項的圖片:進度列、&#39;播放&#39;按鈕、&#39;向前略過&#39;和 ##9;向後略過&#39;按鈕、##9;排放佇列。##99; &#39;Queue Next&#39; 按鈕和 ##9;隱藏式輔助字幕&#39;按鈕已啟用

如要在啟動接收器結構定義後動態變更 supportedMediaCommands 的值,您可以呼叫 PlayerManager.setSupportedMediaCommands 以覆寫該值。此外,您可以使用 addSupportedMediaCommands 新增指令,也可以使用 removeSupportedMediaCommands 移除現有指令。

自訂控制按鈕

您可以使用 PlayerDataBinder 自訂控制項。請在下列程式碼的 js/receiver.js 檔案中加入以下程式碼,設定控制項的第一個版位:

...

// 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 及其屬性的範例:

BrowseContent UI 的圖片,其中顯示兩張影片縮圖,佔三分之一

  1. BrowseContent.title
  2. BrowseContent.items

長寬比

使用 targetAspectRatio property 為圖片素材資源選取最佳長寬比。CAF Receiver SDK 支援三種長寬比:SQUARE_1_TO_1PORTRAIT_2_TO_3LANDSCAPE_16_TO_9

瀏覽項目

使用 BrowseItem 顯示每個項目的標題、副標題、時間長度和圖片:

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 和隨附的 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.jsplayerManager 下方,新增下列程式碼來擷取 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

含有「&BU39」偵錯影片的圖片

記錄播放器事件

使用 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 會使用標記篩選記錄。下文會詳細說明標記的使用方式。第二個參數是記錄訊息

如要顯示記錄檔的實際操作記錄,請將記錄新增至 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,
};

偵錯疊加層

投放偵錯記錄器會在接收端提供偵錯重疊元素,以便在投放裝置上顯示自訂記錄訊息。使用 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 建立自訂網路接收器應用程式。

詳情請參閱網路接收器開發人員指南。