เปิดใช้เว็บแคสต์

1. ภาพรวม

โลโก้ Google Cast

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

Google Cast คืออะไร

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

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

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

สิ่งที่เรากําลังจะสร้าง

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

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

  • วิธีเพิ่ม Google Cast SDK ลงในตัวอย่างแอปวิดีโอ
  • วิธีการเพิ่มปุ่ม "แคสต์" เพื่อเลือกอุปกรณ์ Google Cast
  • วิธีเชื่อมต่ออุปกรณ์ 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 Hosting หรือ ngrok ได้

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

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

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

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

รูปภาพกําลังเล่นบนอุปกรณ์ Cast

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

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

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

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

รูปภาพกําลังเล่นบนอุปกรณ์ Cast

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

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

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

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

โปรดทราบว่าขณะทํางานผ่าน Codelab นี้ คุณจะต้องโฮสต์ตัวอย่างบนเซิร์ฟเวอร์ของคุณใหม่โดยขึ้นอยู่กับบริการ

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

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

แอปประกอบด้วยมุมมองหลัก 1 มุมมองที่กําหนดไว้ใน index.html และตัวควบคุมหลักคือ CastVideos.js.

index.html

ไฟล์ HTML นี้แสดง UI ของแอปพลิเคชันเว็บเกือบทั้งหมด

เรามีมุมมองบางส่วน ซึ่งประกอบด้วย 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

การกำหนดค่า

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

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

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

การเริ่มต้น

เฟรมเวิร์กแคสต์มีออบเจ็กต์ Singleton ทั่วโลก นั่นคือ CastContext ซึ่งจะประสานงานกิจกรรมของเฟรมเวิร์กทั้งหมด ออบเจ็กต์นี้ต้องมีการเริ่มต้นในช่วงต้นของวงจรแอปพลิเคชัน ซึ่งมักจะถูกเรียกจากโค้ดเรียกกลับที่กําหนดให้กับ window['__onGCastApiAvailable'] ซึ่งเรียกใช้หลังจากที่โหลด SDK ของ Cast แล้วและพร้อมใช้งานแล้ว ในกรณีนี้ ระบบจะเรียก 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 ได้เริ่มต้นทํางานแล้ว เราจึงต้องเพิ่มปุ่ม "แคสต์" เพื่อให้ผู้ใช้สามารถเลือกอุปกรณ์แคสต์ได้ Cast 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 เลือกอุปกรณ์ Cast และแอปตัวรับสัญญาณตัวอย่างจะโหลดในอุปกรณ์ Cast

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

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

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

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

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

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

  1. สร้างออบเจ็กต์ MediaInfo JSON จาก Cast SDK ที่สร้างแบบจําลองรายการสื่อ
  2. ผู้ใช้เชื่อมต่อกับอุปกรณ์แคสต์เพื่อเริ่มใช้งานแอปพลิเคชันตัวรับสัญญาณ
  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) {
    //...

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

ตอนนี้โปรแกรมเล่นในพื้นที่จะอยู่ในสถานะการเล่นในเครื่องอยู่เสมอ เนื่องจากยังไม่ไม่ทราบสถานะของการแคสต์ เราจําเป็นต้องอัปเดต UI ตามการเปลี่ยนแปลงสถานะที่เกิดขึ้นในกรอบการทํางาน 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 : '');
  }
};

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

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

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

การอ้างอิง

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

ตั้ง Android Receiver ที่ใช้ร่วมกันได้

ในการเปิดใช้แอปพลิเคชัน Android TV หรือเรียกอีกอย่างว่า Android Receiver เราจําเป็นต้องตั้งค่าสถานะของ androidReceiverCompatible เป็น true ในออบเจ็กต์ 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 Receiver ของคุณ และให้คุณควบคุมการเล่นโดยใช้รีโมต Android TV ของคุณ

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

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

สําหรับรายละเอียดเพิ่มเติม โปรดดูคู่มือนักพัฒนาซอฟต์แวร์ผู้ส่งเว็บ