เปิดใช้เว็บแอป

1. ภาพรวม

โลโก้ Google Cast

Codelab นี้จะสอนวิธีแก้ไขแอปวิดีโอบนเว็บที่มีอยู่เพื่อแคสต์เนื้อหาไปยังอุปกรณ์ที่พร้อมใช้งาน Google Cast

Google Cast คืออะไร

Google Cast ช่วยให้ผู้ใช้แคสต์เนื้อหาจากอุปกรณ์เคลื่อนที่ไปยังทีวีได้ จากนั้นผู้ใช้จะใช้อุปกรณ์เคลื่อนที่เป็นรีโมตคอนโทรลในการเล่นสื่อบนทีวีได้

Google Cast SDK ช่วยให้คุณขยายแอปเพื่อควบคุมทีวีหรือระบบเสียงได้ Cast SDK ช่วยให้คุณเพิ่มคอมโพเนนต์ UI ที่จำเป็นได้ตามรายการตรวจสอบการออกแบบของ Google Cast

รายการตรวจสอบการออกแบบของ Google Cast มีไว้เพื่อมอบประสบการณ์ของผู้ใช้ Cast ที่เรียบง่ายและคาดการณ์ได้ในทุกแพลตฟอร์มที่รองรับ

เรากำลังจะสร้างอะไร

เมื่อคุณทำ Codelab นี้เสร็จแล้ว คุณจะมีแอปวิดีโอบนเว็บของ Chrome ที่สามารถแคสต์วิดีโอไปยังอุปกรณ์ Google Cast

สิ่งที่คุณจะได้เรียนรู้

  • วิธีเพิ่ม Google Cast SDK ลงในแอปวิดีโอตัวอย่าง
  • วิธีเพิ่มปุ่ม "แคสต์" สำหรับเลือกอุปกรณ์ Google Cast
  • วิธีเชื่อมต่อกับอุปกรณ์แคสต์และเปิดใช้เครื่องรับสื่อ
  • วิธีแคสต์วิดีโอ
  • วิธีผสานรวม Cast Connect

สิ่งที่ต้องมี

  • เบราว์เซอร์ Google Chrome เวอร์ชันล่าสุด
  • บริการโฮสติ้ง HTTPS เช่น โฮสติ้งของ Firebase หรือ ngrok
  • อุปกรณ์ Google Cast เช่น Chromecast หรือ Android TV ที่กำหนดค่าด้วยการเข้าถึงอินเทอร์เน็ต
  • ทีวีหรือจอภาพที่มีอินพุต HDMI
  • โดยจะต้องใช้ Chromecast ที่มี Google TV เพื่อทดสอบการผสานรวม Cast Connect แต่ไม่บังคับสำหรับการใช้งาน Codelab ที่เหลือ หากไม่มี ให้ข้ามขั้นตอนเพิ่มการสนับสนุน Cast Connect ที่อยู่ท้ายบทแนะนำนี้

ประสบการณ์การใช้งาน

  • คุณจะต้องมีความรู้ด้านการพัฒนาเว็บมาก่อน
  • คุณต้องมีความรู้เรื่องการดูทีวีมาก่อนด้วย :)

คุณจะใช้บทแนะนำนี้อย่างไร

อ่านเท่านั้น อ่านและทำแบบฝึกหัด

คุณจะให้คะแนนประสบการณ์การสร้างเว็บแอปอย่างไร

ผู้ฝึกหัด ระดับกลาง ผู้ชำนาญ

คุณจะให้คะแนนประสบการณ์ในการดูทีวีอย่างไร

ผู้ฝึกหัด ระดับกลาง ผู้ชำนาญ

2. รับโค้ดตัวอย่าง

คุณสามารถดาวน์โหลดโค้ดตัวอย่างทั้งหมดลงในคอมพิวเตอร์...

และคลายการบีบอัดไฟล์ ZIP ที่ดาวน์โหลด

3. เรียกใช้แอปตัวอย่าง

โลโก้ Google Chrome

ก่อนอื่น เรามาดูกันว่าแอปตัวอย่างที่สมบูรณ์มีลักษณะอย่างไร แอปนี้เป็นโปรแกรมเล่นวิดีโอพื้นฐาน ผู้ใช้สามารถเลือกวิดีโอจากรายการแล้วเล่นวิดีโอในอุปกรณ์หรือแคสต์ไปยังอุปกรณ์ Google Cast

หากต้องการใช้ไฟล์ที่สมบูรณ์ ต้องโฮสต์ก่อน

หากไม่มีเซิร์ฟเวอร์ที่พร้อมให้บริการ ให้ใช้โฮสติ้งของ Firebase หรือ ngrok

เรียกใช้เซิร์ฟเวอร์

เมื่อตั้งค่าบริการที่เลือกแล้ว ให้ไปที่ app-done แล้วเริ่มต้นเซิร์ฟเวอร์

ในเบราว์เซอร์ ให้ไปที่ URL ของ https เพื่อดูตัวอย่างที่คุณโฮสต์ไว้

  1. จากนั้นแอปวิดีโอจะปรากฏขึ้น
  2. คลิกปุ่ม "แคสต์" และเลือกอุปกรณ์ Google Cast ของคุณ
  3. เลือกวิดีโอ แล้วคลิกปุ่มเล่น
  4. วิดีโอจะเริ่มเล่นบนอุปกรณ์ Google Cast

รูปภาพวิดีโอที่กำลังเล่นในอุปกรณ์แคสต์

คลิกปุ่มหยุดชั่วคราวในองค์ประกอบวิดีโอเพื่อหยุดวิดีโอชั่วคราวบนรีซีฟเวอร์ คลิกปุ่มเล่นในองค์ประกอบวิดีโอเพื่อเล่นวิดีโอดังกล่าวอีกครั้ง

คลิกปุ่ม "แคสต์" เพื่อหยุดแคสต์ไปยังอุปกรณ์ Google Cast

ก่อนจะไปต่อ ให้หยุดการทำงานของเซิร์ฟเวอร์

4. เตรียมการเริ่มโปรเจ็กต์

รูปภาพวิดีโอที่กำลังเล่นในอุปกรณ์แคสต์

เราต้องเพิ่มการรองรับ Google Cast ให้กับแอปเริ่มต้นที่คุณดาวน์โหลดมา ต่อไปนี้คือคำศัพท์ของ Google Cast ที่เราจะใช้ใน Codelab

  • แอปของผู้ส่งทำงานบนอุปกรณ์เคลื่อนที่หรือแล็ปท็อป
  • แอปตัวรับจะทำงานในอุปกรณ์ Google Cast

ตอนนี้คุณพร้อมที่จะสร้างโครงการเริ่มต้นเพิ่มเติมโดยใช้โปรแกรมแก้ไขข้อความที่คุณชื่นชอบแล้ว:

  1. เลือกไดเรกทอรี ไอคอนโฟลเดอร์app-start จากการดาวน์โหลดโค้ดตัวอย่าง
  2. เรียกใช้แอปโดยใช้เซิร์ฟเวอร์ของคุณและสำรวจ UI

โปรดทราบว่าในขณะที่ใช้ Codelab นี้ คุณจะต้องฝากตัวอย่างไว้ในเซิร์ฟเวอร์อีกครั้งโดยขึ้นอยู่กับบริการ

การออกแบบแอป

แอปจะดึงข้อมูลรายการวิดีโอจากเว็บเซิร์ฟเวอร์ระยะไกลและแสดงรายการให้ผู้ใช้เรียกดู ผู้ใช้สามารถเลือกวิดีโอเพื่อดูรายละเอียดหรือเล่นวิดีโอบนอุปกรณ์เคลื่อนที่ก็ได้

แอปประกอบด้วยมุมมองหลัก 1 มุมมอง ซึ่งกำหนดไว้ใน index.html และตัวควบคุมหลัก CastVideos.js.

index.html

ไฟล์ HTML นี้ประกาศ UI เกือบทั้งหมดของเว็บแอป

ยอดดูแบ่งเป็น 2-3 ส่วน เรามี div#main_video ซึ่งมีองค์ประกอบวิดีโอ ที่เกี่ยวข้องกับ div วิดีโอของเรา เรามี div#media_control ซึ่งกำหนดการควบคุมทั้งหมดสำหรับองค์ประกอบวิดีโอ ด้านล่างคือ media_info ซึ่งจะแสดงรายละเอียดของวิดีโอในมุมมอง สุดท้าย div carousel จะแสดงรายการวิดีโอใน div

ไฟล์ index.html จะเริ่มต้นการทำงานของ Cast SDK และบอกให้ฟังก์ชัน CastVideos โหลดด้วย

เนื้อหาส่วนใหญ่ที่จะสร้างองค์ประกอบเหล่านี้จะได้รับการกำหนด แทรก และควบคุมใน CastVideos.js เรามาดูเรื่องนี้กัน

CastVideos.js

สคริปต์นี้จัดการตรรกะทั้งหมดสำหรับเว็บแอปของวิดีโอแคสต์ รายการวิดีโอและข้อมูลเมตาที่เกี่ยวข้องซึ่งกำหนดไว้ใน CastVideos.js อยู่ในออบเจ็กต์ชื่อ mediaJSON

มีส่วนหลักๆ 2-3 ส่วนที่ร่วมกันรับผิดชอบและเล่นวิดีโอทั้งในเครื่องและจากระยะไกล โดยรวมแล้ว เว็บแอปพลิเคชันนี้เป็นเว็บแอปพลิเคชันที่ค่อนข้างตรงไปตรงมา

CastPlayer เป็นคลาสหลักที่จัดการทั้งแอป ตั้งค่าโปรแกรมเล่น เลือกสื่อ และเชื่อมโยงเหตุการณ์กับ PlayerHandler เพื่อเล่นสื่อ CastPlayer.prototype.initializeCastPlayer คือวิธีตั้งค่าฟังก์ชันการแคสต์ทั้งหมด CastPlayer.prototype.switchPlayer จะสลับสถานะระหว่างโปรแกรมเล่นในเครื่องและโปรแกรมเล่นระยะไกล CastPlayer.prototype.setupLocalPlayer และ CastPlayer.prototype.setupRemotePlayer จะเริ่มต้นโปรแกรมเล่นภายในและระยะไกล

PlayerHandler เป็นชั้นเรียนที่มีหน้าที่รับผิดชอบในการจัดการการเล่นสื่อ ยังมีวิธีอื่นๆ อีกมากมายที่มีผลต่อรายละเอียดในการจัดการสื่อและการเล่น

คำถามที่พบบ่อย

5. การเพิ่มปุ่ม "แคสต์"

รูปภาพของแอปที่พร้อมใช้งาน Cast

แอปพลิเคชันที่พร้อมใช้งาน Cast จะแสดงปุ่ม "แคสต์" ในองค์ประกอบวิดีโอ การคลิกปุ่ม "แคสต์" จะแสดงรายการอุปกรณ์แคสต์ที่ผู้ใช้สามารถเลือกได้ หากผู้ใช้เล่นเนื้อหาในอุปกรณ์ของผู้ส่ง การเลือกอุปกรณ์แคสต์จะเริ่มเล่นหรือเล่นต่อในอุปกรณ์แคสต์นั้น ผู้ใช้สามารถคลิกปุ่ม "แคสต์" และหยุดแคสต์แอปพลิเคชันไปยังอุปกรณ์แคสต์ได้ทุกเมื่อในระหว่างเซสชันการแคสต์ ผู้ใช้จะต้องสามารถเชื่อมต่อหรือยกเลิกการเชื่อมต่ออุปกรณ์ Cast ได้ขณะอยู่ในหน้าจอใดๆ ของแอปพลิเคชัน ดังที่อธิบายไว้ในรายการตรวจสอบการออกแบบ Google Cast

การกำหนดค่า

โปรเจ็กต์เริ่มต้นต้องใช้ทรัพยากร Dependency และการตั้งค่าเหมือนกับแอปตัวอย่างที่สมบูรณ์ แต่ครั้งนี้โฮสต์เนื้อหาของ app-start

ในเบราว์เซอร์ ให้ไปที่ URL https ของตัวอย่างที่โฮสต์ไว้

โปรดทราบว่าในขณะที่ทำการเปลี่ยนแปลง คุณจะต้องฝากตัวอย่างไว้ในเซิร์ฟเวอร์อีกครั้งโดยขึ้นอยู่กับบริการนั้นๆ

การเริ่มต้น

เฟรมเวิร์กแคสต์มีออบเจ็กต์ Singleton ส่วนกลาง ซึ่งก็คือ CastContext ซึ่งประสานรวมกิจกรรมทั้งหมดของเฟรมเวิร์ก ออบเจ็กต์นี้ต้องเริ่มต้นตั้งแต่เนิ่นๆ ในวงจรของแอปพลิเคชัน ซึ่งโดยปกติจะเรียกจากโค้ดเรียกกลับที่กำหนดให้กับ window['__onGCastApiAvailable'] ซึ่งจะเรียกใช้หลังจากโหลด Cast SDK แล้วและพร้อมใช้งาน ในกรณีนี้ CastContext จะถูกเรียกใน CastPlayer.prototype.initializeCastPlayer ซึ่งเรียกจากโค้ดเรียกกลับที่กล่าวไว้ข้างต้น

ต้องระบุออบเจ็กต์ JSON options เมื่อเริ่มต้น CastContext คลาสนี้มีตัวเลือกที่มีผลต่อลักษณะการทำงานของเฟรมเวิร์ก สิ่งสำคัญที่สุดคือรหัสแอปพลิเคชันตัวรับ ซึ่งใช้เพื่อกรองรายการอุปกรณ์แคสต์ที่พร้อมใช้งานเพื่อแสดงเฉพาะอุปกรณ์ที่เรียกใช้แอปที่ระบุได้และเปิดแอปพลิเคชันตัวรับเมื่อเซสชันการแคสต์เริ่มขึ้น

เมื่อพัฒนาแอปที่พร้อมใช้งาน Cast ของคุณเอง คุณต้องลงทะเบียนเป็นนักพัฒนาซอฟต์แวร์ Cast แล้วรับรหัสแอปพลิเคชันสำหรับแอป สำหรับ Codelab นี้ เราจะใช้รหัสแอปตัวอย่าง

เพิ่มโค้ดต่อไปนี้ลงใน index.html ที่ส่วนท้ายสุดของส่วน body:

<script type="text/javascript" src="https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1"></script>

เพิ่มโค้ดต่อไปนี้ลงใน index.html เพื่อเริ่มต้นแอป CastVideos รวมถึงเริ่มต้น CastContext

<script src="CastVideos.js"></script>
<script type="text/javascript">
var castPlayer = new CastPlayer();
window['__onGCastApiAvailable'] = function(isAvailable) {
  if (isAvailable) {
    castPlayer.initializeCastPlayer();
  }
};
</script>

คราวนี้เราต้องเพิ่มเมธอดใหม่ใน CastVideos.js ซึ่งสอดคล้องกับเมธอดที่เพิ่งใช้ไปใน index.html มาเพิ่มเมธอดใหม่ที่เรียกว่า initializeCastPlayer ซึ่งตั้งค่าตัวเลือกใน CastContext และเริ่มต้น RemotePlayer และ RemotePlayerControllers ใหม่กัน

/**
 * This method sets up the CastContext, and a few other members
 * that are necessary to play and control videos on a Cast
 * device.
 */
CastPlayer.prototype.initializeCastPlayer = function() {

    var options = {};

    // Set the receiver application ID to your own (created in
    // the Google Cast Developer Console), or optionally
    // use the chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID
    options.receiverApplicationId = 'C0868879';

    // Auto join policy can be one of the following three:
    // ORIGIN_SCOPED - Auto connect from same appId and page origin
    // TAB_AND_ORIGIN_SCOPED - Auto connect from same appId, page origin, and tab
    // PAGE_SCOPED - No auto connect
    options.autoJoinPolicy = chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED;

    cast.framework.CastContext.getInstance().setOptions(options);

    this.remotePlayer = new cast.framework.RemotePlayer();
    this.remotePlayerController = new cast.framework.RemotePlayerController(this.remotePlayer);
    this.remotePlayerController.addEventListener(
        cast.framework.RemotePlayerEventType.IS_CONNECTED_CHANGED,
        this.switchPlayer.bind(this)
    );
};

สุดท้าย เราต้องสร้างตัวแปรสำหรับ RemotePlayer และ RemotePlayerController ดังนี้

var CastPlayer = function() {
  //...
  /* Cast player variables */
  /** @type {cast.framework.RemotePlayer} */
  this.remotePlayer = null;
  /** @type {cast.framework.RemotePlayerController} */
  this.remotePlayerController = null;
  //...
};

ปุ่ม "แคสต์"

เมื่อเริ่มต้น CastContext แล้ว เราต้องเพิ่มปุ่ม "แคสต์" เพื่ออนุญาตให้ผู้ใช้เลือกอุปกรณ์แคสต์ได้ SDK แคสต์มีคอมโพเนนต์ปุ่ม "แคสต์" ชื่อ google-cast-launcher ที่มีรหัส "castbutton"" คุณสามารถเพิ่มคอมโพเนนต์ดังกล่าวไปยังองค์ประกอบวิดีโอของแอปพลิเคชันได้ง่ายๆ เพียงเพิ่ม button ในส่วน media_control

องค์ประกอบของปุ่มจะมีลักษณะดังต่อไปนี้

<google-cast-launcher id="castbutton"></google-cast-launcher>

เพิ่มโค้ดต่อไปนี้ลงใน index.html ในส่วน media_control

<div id="media_control">
  <div id="play"></div>
  <div id="pause"></div>
  <div id="progress_bg"></div>
  <div id="progress"></div>
  <div id="progress_indicator"></div>
  <div id="fullscreen_expand"></div>
  <div id="fullscreen_collapse"></div>
  <google-cast-launcher id="castbutton"></google-cast-launcher>
  <div id="audio_bg"></div>
  <div id="audio_bg_track"></div>
  <div id="audio_indicator"></div>
  <div id="audio_bg_level"></div>
  <div id="audio_on"></div>
  <div id="audio_off"></div>
  <div id="duration">00:00:00</div>
</div>

ตอนนี้ให้รีเฟรชหน้าในเบราว์เซอร์ Chrome คุณควรเห็นปุ่ม "แคสต์" ในองค์ประกอบวิดีโอและเมื่อคลิกปุ่มดังกล่าว ปุ่ม "แคสต์" จะแสดงอุปกรณ์แคสต์ในเครือข่ายภายในของคุณ การค้นหาอุปกรณ์ได้รับการจัดการโดยอัตโนมัติโดยเบราว์เซอร์ Chrome เลือกอุปกรณ์แคสต์ แล้วแอปตัวรับตัวอย่างจะโหลดในอุปกรณ์แคสต์

เรายังไม่ได้ให้การสนับสนุนการเล่นสื่อ คุณจึงยังไม่สามารถเล่นวิดีโอบนอุปกรณ์แคสต์ได้ คลิกปุ่ม "แคสต์" เพื่อหยุดแคสต์

6. กำลังแคสต์เนื้อหาวิดีโอ

รูปภาพแอปที่พร้อมใช้งาน Cast ที่มีเมนูการเลือกอุปกรณ์แคสต์

เราจะขยายตัวอย่างแอปให้เล่นวิดีโอจากระยะไกลบนอุปกรณ์แคสต์ด้วย ในการทำเช่นนั้น เราต้องรับฟังเหตุการณ์ต่างๆ ที่สร้างขึ้นโดยเฟรมเวิร์กของ Cast

กำลังแคสต์สื่อ

หากต้องการเล่นสื่อในอุปกรณ์แคสต์ในระดับสูง คุณต้องมีคุณสมบัติต่อไปนี้

  1. สร้างออบเจ็กต์ MediaInfo JSON จาก Cast SDK ที่จำลองรายการสื่อ
  2. ผู้ใช้จะเชื่อมต่อกับอุปกรณ์ Cast เพื่อเปิดแอปพลิเคชันตัวรับสัญญาณ
  3. โหลดออบเจ็กต์ MediaInfo ลงในตัวรับและเล่นเนื้อหา
  4. ติดตามสถานะสื่อ
  5. ส่งคำสั่งการเล่นไปยังเครื่องรับตามการโต้ตอบของผู้ใช้

ขั้นตอนที่ 1 มีหน้าที่จับคู่ออบเจ็กต์หนึ่งกับอีกออบเจ็กต์หนึ่ง MediaInfo เป็นข้อมูลที่ Cast SDK เข้าใจ และ mediaJSON เป็นการห่อหุ้มรายการสื่อของแอป เราแมป mediaJSON กับ MediaInfo ได้อย่างง่ายดาย เราทําตามขั้นตอนที่ 2 ในส่วนก่อนหน้าไปแล้ว ขั้นตอนที่ 3 ง่ายๆ ด้วย Cast SDK

แอปตัวอย่าง CastPlayer แยกระหว่างการเล่นในเครื่องและการเล่นระยะไกลในเมธอด switchPlayer อยู่แล้ว ดังนี้

if (cast && cast.framework) {
  if (this.remotePlayer.isConnected) {
    //...

ใน Codelab นี้จะไม่จำเป็นต้องทำความเข้าใจให้แน่ชัดว่าตรรกะของโปรแกรมเล่นตัวอย่างทั้งหมดทำงานอย่างไร อย่างไรก็ตาม คุณต้องเข้าใจว่าจะต้องแก้ไขโปรแกรมเล่นสื่อของแอปเพื่อให้รับรู้ทั้งการเล่นในเครื่องและการเล่นระยะไกล

ขณะนี้โปรแกรมเล่นในเครื่องจะอยู่ในสถานะการเล่นในเครื่องเสมอ เนื่องจากยังไม่ทราบข้อมูลเกี่ยวกับสถานะการแคสต์ เราจำเป็นต้องอัปเดต UI ตามการเปลี่ยนสถานะที่เกิดขึ้นในเฟรมเวิร์กของ Cast ตัวอย่างเช่น หากเราเริ่มแคสต์ เราต้องหยุดการเล่นในเครื่องและปิดใช้การควบคุมบางอย่าง ในทำนองเดียวกัน หากเราหยุดแคสต์เมื่ออยู่ในตัวควบคุมมุมมองนี้ เราก็จำเป็นต้องเปลี่ยนไปเล่นในเครื่อง เราต้องจัดการเหตุการณ์ต่างๆ ที่เฟรมเวิร์กของ Cast สร้างขึ้นเพื่อรับมือกับสถานการณ์ดังกล่าว

การจัดการเซสชันการแคสต์

สำหรับเฟรมเวิร์ก Cast เซสชัน Cast จะรวมขั้นตอนการเชื่อมต่ออุปกรณ์ การเปิด (หรือเข้าร่วมเซสชันที่มีอยู่) การเชื่อมต่อกับแอปพลิเคชันตัวรับสัญญาณ และการเริ่มต้นช่องควบคุมสื่อตามความเหมาะสม ช่องควบคุมสื่อคือวิธีที่เฟรมเวิร์ก Cast ส่งและรับข้อความที่เกี่ยวข้องกับการเล่นสื่อจากเครื่องรับ

เซสชันการแคสต์จะเริ่มต้นโดยอัตโนมัติเมื่อผู้ใช้เลือกอุปกรณ์จากปุ่ม "แคสต์" และจะหยุดโดยอัตโนมัติเมื่อผู้ใช้ยกเลิกการเชื่อมต่อ การเชื่อมต่อกับเซสชันตัวรับสัญญาณอีกครั้งเนื่องจากปัญหาเครือข่ายได้รับการจัดการโดยอัตโนมัติด้วยเฟรมเวิร์ก Cast ด้วยเช่นกัน

เซสชันการแคสต์ได้รับการจัดการโดย CastSession ซึ่งเข้าถึงได้ผ่าน cast.framework.CastContext.getInstance().getCurrentSession() โค้ดเรียกกลับของ EventListener สามารถใช้เพื่อตรวจสอบเหตุการณ์ของเซสชัน เช่น การสร้าง การระงับ การกลับมาทำงานอีกครั้ง และการสิ้นสุด

ในแอปพลิเคชันปัจจุบัน ระบบจะจัดการเซสชันและการจัดการสถานะทั้งหมดให้เราในเมธอด setupRemotePlayer มาเริ่มกำหนดค่าดังกล่าวในแอปโดยการเพิ่มโค้ดต่อไปนี้ลงใน CastVideos.js กัน

/**
 * Set the PlayerHandler target to use the remote player
 */
CastPlayer.prototype.setupRemotePlayer = function () {
    var castSession = cast.framework.CastContext.getInstance().getCurrentSession();

    this.playerHandler.setTarget(playerTarget);

    // Setup remote player volume right on setup
    // The remote player may have had a volume set from previous playback
    if (this.remotePlayer.isMuted) {
        this.playerHandler.mute();
    }
    var currentVolume = this.remotePlayer.volumeLevel * FULL_VOLUME_HEIGHT;
    var p = document.getElementById('audio_bg_level');
    p.style.height = currentVolume + 'px';
    p.style.marginTop = -currentVolume + 'px';

    this.hideFullscreenButton();

    this.playerHandler.play();
};

เรายังจำเป็นต้องเชื่อมโยงเหตุการณ์ทั้งหมดจากโค้ดเรียกกลับและจัดการกับเหตุการณ์ทั้งหมดที่เข้ามา ขั้นตอนนี้ค่อนข้างตรงไปตรงมา เราจึงมาแก้ปัญหาดังกล่าวตั้งแต่ตอนนี้

/**
 * Set the PlayerHandler target to use the remote player
 */
CastPlayer.prototype.setupRemotePlayer = function () {
    var castSession = cast.framework.CastContext.getInstance().getCurrentSession();

    // Add event listeners for player changes which may occur outside sender app
    this.remotePlayerController.addEventListener(
        cast.framework.RemotePlayerEventType.IS_PAUSED_CHANGED,
        function() {
            if (this.remotePlayer.isPaused) {
                this.playerHandler.pause();
            } else {
                this.playerHandler.play();
            }
        }.bind(this)
    );

    this.remotePlayerController.addEventListener(
        cast.framework.RemotePlayerEventType.IS_MUTED_CHANGED,
        function() {
            if (this.remotePlayer.isMuted) {
                this.playerHandler.mute();
            } else {
                this.playerHandler.unMute();
            }
        }.bind(this)
    );

    this.remotePlayerController.addEventListener(
        cast.framework.RemotePlayerEventType.VOLUME_LEVEL_CHANGED,
        function() {
            var newVolume = this.remotePlayer.volumeLevel * FULL_VOLUME_HEIGHT;
            var p = document.getElementById('audio_bg_level');
            p.style.height = newVolume + 'px';
            p.style.marginTop = -newVolume + 'px';
        }.bind(this)
    );

    // This object will implement PlayerHandler callbacks with
    // remotePlayerController, and makes necessary UI updates specific
    // to remote playback
    var playerTarget = {};

    playerTarget.play = function () {
        if (this.remotePlayer.isPaused) {
            this.remotePlayerController.playOrPause();
        }

        var vi = document.getElementById('video_image');
        vi.style.display = 'block';
        var localPlayer = document.getElementById('video_element');
        localPlayer.style.display = 'none';
    }.bind(this);

    playerTarget.pause = function () {
        if (!this.remotePlayer.isPaused) {
            this.remotePlayerController.playOrPause();
        }
    }.bind(this);

    playerTarget.stop = function () {
         this.remotePlayerController.stop();
    }.bind(this);

    playerTarget.getCurrentMediaTime = function() {
        return this.remotePlayer.currentTime;
    }.bind(this);

    playerTarget.getMediaDuration = function() {
        return this.remotePlayer.duration;
    }.bind(this);

    playerTarget.updateDisplayMessage = function () {
        document.getElementById('playerstate').style.display = 'block';
        document.getElementById('playerstatebg').style.display = 'block';
        document.getElementById('video_image_overlay').style.display = 'block';
        document.getElementById('playerstate').innerHTML =
            this.mediaContents[ this.currentMediaIndex]['title'] + ' ' +
            this.playerState + ' on ' + castSession.getCastDevice().friendlyName;
    }.bind(this);

    playerTarget.setVolume = function (volumeSliderPosition) {
        // Add resistance to avoid loud volume
        var currentVolume = this.remotePlayer.volumeLevel;
        var p = document.getElementById('audio_bg_level');
        if (volumeSliderPosition < FULL_VOLUME_HEIGHT) {
            var vScale =  this.currentVolume * FULL_VOLUME_HEIGHT;
            if (volumeSliderPosition > vScale) {
                volumeSliderPosition = vScale + (pos - vScale) / 2;
            }
            p.style.height = volumeSliderPosition + 'px';
            p.style.marginTop = -volumeSliderPosition + 'px';
            currentVolume = volumeSliderPosition / FULL_VOLUME_HEIGHT;
        } else {
            currentVolume = 1;
        }
        this.remotePlayer.volumeLevel = currentVolume;
        this.remotePlayerController.setVolumeLevel();
    }.bind(this);

    playerTarget.mute = function () {
        if (!this.remotePlayer.isMuted) {
            this.remotePlayerController.muteOrUnmute();
        }
    }.bind(this);

    playerTarget.unMute = function () {
        if (this.remotePlayer.isMuted) {
            this.remotePlayerController.muteOrUnmute();
        }
    }.bind(this);

    playerTarget.isMuted = function() {
        return this.remotePlayer.isMuted;
    }.bind(this);

    playerTarget.seekTo = function (time) {
        this.remotePlayer.currentTime = time;
        this.remotePlayerController.seek();
    }.bind(this);

    this.playerHandler.setTarget(playerTarget);

    // Setup remote player volume right on setup
    // The remote player may have had a volume set from previous playback
    if (this.remotePlayer.isMuted) {
        this.playerHandler.mute();
    }
    var currentVolume = this.remotePlayer.volumeLevel * FULL_VOLUME_HEIGHT;
    var p = document.getElementById('audio_bg_level');
    p.style.height = currentVolume + 'px';
    p.style.marginTop = -currentVolume + 'px';

    this.hideFullscreenButton();

    this.playerHandler.play();
};

กำลังโหลดสื่อ

ใน Cast SDK RemotePlayer และ RemotePlayerController จะมีชุด API ที่ใช้งานง่ายสำหรับการจัดการการเล่นสื่อระยะไกลบนตัวรับ สำหรับ CastSession ที่รองรับการเล่นสื่อ SDK จะสร้างอินสแตนซ์ของ RemotePlayer และ RemotePlayerController โดยอัตโนมัติ ซึ่งเข้าถึงได้โดยการสร้างอินสแตนซ์ของ cast.framework.RemotePlayer และ cast.framework.RemotePlayerController ตามลำดับ ดังที่แสดงไว้ก่อนหน้านี้ใน Codelab

ต่อไป เราต้องโหลดวิดีโอที่เลือกไว้บนรีซีฟเวอร์โดยสร้างออบเจ็กต์ MediaInfo เพื่อให้ SDK ประมวลผลและส่งต่อคำขอ เพิ่มรหัสต่อไปนี้ลงใน setupRemotePlayer เพื่อดำเนินการ

/**
 * Set the PlayerHandler target to use the remote player
 */
CastPlayer.prototype.setupRemotePlayer = function () {
    //...

    playerTarget.load = function (mediaIndex) {
        console.log('Loading...' + this.mediaContents[mediaIndex]['title']);
        var mediaInfo = new chrome.cast.media.MediaInfo(
            this.mediaContents[mediaIndex]['sources'][0], 'video/mp4');

        mediaInfo.metadata = new chrome.cast.media.GenericMediaMetadata();
        mediaInfo.metadata.metadataType = chrome.cast.media.MetadataType.GENERIC;
        mediaInfo.metadata.title = this.mediaContents[mediaIndex]['title'];
        mediaInfo.metadata.images = [
            {'url': MEDIA_SOURCE_ROOT + this.mediaContents[mediaIndex]['thumb']}];

        var request = new chrome.cast.media.LoadRequest(mediaInfo);
        castSession.loadMedia(request).then(
            this.playerHandler.loaded.bind(this.playerHandler),
            function (errorCode) {
                this.playerState = PLAYER_STATE.ERROR;
                console.log('Remote media load error: ' +
                    CastPlayer.getErrorMessage(errorCode));
            }.bind(this));
    }.bind(this);

    //...
};

ตอนนี้ให้เพิ่มวิธีการสลับระหว่างการเล่นในเครื่องและระยะไกล:

/**
 * This is a method for switching between the local and remote
 * players. If the local player is selected, setupLocalPlayer()
 * is run. If there is a cast device connected we run
 * setupRemotePlayer().
 */
CastPlayer.prototype.switchPlayer = function() {
    this.stopProgressTimer();
    this.resetVolumeSlider();
    this.playerHandler.stop();
    this.playerState = PLAYER_STATE.IDLE;
    if (cast && cast.framework) {
        if (this.remotePlayer.isConnected) {
            this.setupRemotePlayer();
            return;
        }
    }
    this.setupLocalPlayer();
};

ขั้นตอนสุดท้าย ให้เพิ่มวิธีการจัดการข้อความแสดงข้อผิดพลาดของ Cast ดังนี้

/**
 * Makes human-readable message from chrome.cast.Error
 * @param {chrome.cast.Error} error
 * @return {string} error message
 */
CastPlayer.getErrorMessage = function(error) {
  switch (error.code) {
    case chrome.cast.ErrorCode.API_NOT_INITIALIZED:
      return 'The API is not initialized.' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.CANCEL:
      return 'The operation was canceled by the user' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.CHANNEL_ERROR:
      return 'A channel to the receiver is not available.' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.EXTENSION_MISSING:
      return 'The Cast extension is not available.' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.INVALID_PARAMETER:
      return 'The parameters to the operation were not valid.' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.RECEIVER_UNAVAILABLE:
      return 'No receiver was compatible with the session request.' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.SESSION_ERROR:
      return 'A session could not be created, or a session was invalid.' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.TIMEOUT:
      return 'The operation timed out.' +
        (error.description ? ' :' + error.description : '');
  }
};

เรียกใช้แอป เชื่อมต่อกับเครื่องส่งและเริ่มเล่นวิดีโอ คุณควรเห็นวิดีโอเล่นบนตัวรับสัญญาณ

7. เพิ่มการสนับสนุน Cast Connect

ไลบรารี Cast Connect ช่วยให้แอปพลิเคชันของผู้ส่งที่มีอยู่สามารถสื่อสารกับแอปพลิเคชัน Android TV ผ่านโปรโตคอล Cast Cast Connect สร้างขึ้นบนโครงสร้างพื้นฐานของ Cast โดยมีแอป Android TV ทำหน้าที่เป็นตัวรับสัญญาณ

การอ้างอิง

  • เบราว์เซอร์ Chrome เวอร์ชัน M87 ขึ้นไป

ตั้งค่าให้ใช้งานร่วมกับตัวรับสัญญาณ Android

ในการเปิดใช้งานแอปพลิเคชัน Android TV หรือที่เรียกว่า Android Receiver เราต้องตั้งค่าแฟล็ก androidReceiverCompatible เป็น "จริง" ในออบเจ็กต์ CastOptions

เพิ่มโค้ดต่อไปนี้ลงใน CastVideos.js ในฟังก์ชัน initializeCastPlayer

var options = {};
...
options.androidReceiverCompatible = true;

cast.framework.CastContext.getInstance().setOptions(options);

ตั้งค่าข้อมูลเข้าสู่ระบบการเปิดตัว

ในฝั่งผู้ส่ง คุณสามารถระบุ CredentialsData เพื่อแทนผู้ที่เข้าร่วมเซสชันได้ credentials เป็นสตริงที่ผู้ใช้กำหนดได้ ตราบใดที่แอป ATV เข้าใจได้ ระบบจะส่งCredentialsDataไปยังแอป Android TV ในช่วงเปิดตัวหรือเข้าร่วมเท่านั้น หากคุณตั้งค่าอีกครั้งขณะเชื่อมต่อ ระบบจะไม่ส่งข้อมูลนี้ไปยังแอป Android TV

หากต้องการตั้งค่าข้อมูลเข้าสู่ระบบการเปิดใช้งาน คุณต้องกำหนด CredentialsData ได้ทุกเมื่อหลังจากตั้งค่าตัวเลือกการเปิดใช้งานแล้ว

เพิ่มโค้ดต่อไปนี้ไปยังชั้นเรียน CastVideos.js ภายใต้ฟังก์ชัน initializeCastPlayer

cast.framework.CastContext.getInstance().setOptions(options);
...
let credentialsData = new chrome.cast.CredentialsData("{\"userId\": \"abc\"}");
cast.framework.CastContext.getInstance().setLaunchCredentialsData(credentialsData);
...

ตั้งค่าข้อมูลเข้าสู่ระบบในคำขอโหลด

ในกรณีที่แอป Web Receiver และแอป Android TV จัดการ credentials แตกต่างกัน คุณอาจต้องกำหนดข้อมูลเข้าสู่ระบบแยกกันสำหรับแต่ละรายการ เพื่อแก้ปัญหาดังกล่าว ให้เพิ่มโค้ดต่อไปนี้ใน CastVideos.js ใต้ playerTarget.load ในฟังก์ชัน setupRemotePlayer

...
var request = new chrome.cast.media.LoadRequest(mediaInfo);
request.credentials = 'user-credentials';
request.atvCredentials = 'atv-user-credentials';
...

SDK จะจัดการข้อมูลเข้าสู่ระบบที่จะใช้สำหรับเซสชันปัจจุบันโดยอัตโนมัติ ทั้งนี้ขึ้นอยู่กับแอปผู้รับที่ผู้ส่งของคุณแคสต์ไป

กำลังทดสอบ Cast Connect

ขั้นตอนการติดตั้ง APK ของ Android TV บน Chromecast พร้อม Google TV มีดังนี้

  1. ค้นหาที่อยู่ IP ของอุปกรณ์ Android TV ซึ่งโดยปกติจะอยู่ในการตั้งค่า > เครือข่ายและอินเทอร์เน็ต > (ชื่อเครือข่ายที่อุปกรณ์เชื่อมต่ออยู่) ทางด้านขวาจะแสดงรายละเอียดและ IP ของอุปกรณ์ในเครือข่าย
  2. ใช้ที่อยู่ IP ของอุปกรณ์เพื่อเชื่อมต่อผ่าน ADB โดยใช้เทอร์มินัล โดยทำดังนี้
$ adb connect <device_ip_address>:5555
  1. จากหน้าต่างเทอร์มินัล ไปที่โฟลเดอร์ระดับบนสุดของตัวอย่าง Codelab ที่คุณดาวน์โหลดเมื่อเริ่มต้น Codelab นี้ เช่น
$ cd Desktop/chrome_codelab_src
  1. ติดตั้งไฟล์ .apk ในโฟลเดอร์นี้ไปยัง Android TV โดยเรียกใช้
$ adb -s <device_ip_address>:5555 install android-tv-app.apk
  1. ตอนนี้คุณควรเห็นแอปตามชื่อแคสต์วิดีโอในเมนูแอปของคุณบนอุปกรณ์ Android TV แล้ว
  2. เรียกใช้รหัสผู้ส่งเว็บที่อัปเดตแล้วและสร้างเซสชันการแคสต์กับอุปกรณ์ Android TV โดยใช้ไอคอนแคสต์ หรือเลือก Cast.. จากเมนูแบบเลื่อนลงในเบราว์เซอร์ Chrome การดำเนินการนี้จะเปิดแอป Android TV บนตัวรับสัญญาณ Android และให้คุณควบคุมการเล่นโดยใช้รีโมต Android TV ได้

8. ขอแสดงความยินดี

ตอนนี้คุณรู้วิธีเปิดใช้แอปวิดีโอแล้วโดยใช้วิดเจ็ต Cast SDK ในเว็บแอป Chrome

สำหรับรายละเอียดเพิ่มเติม โปรดดูคู่มือนักพัฒนาซอฟต์แวร์ Web Sender