1. ภาพรวม
Codelab นี้จะสอนวิธีสร้างแอป Web Receiver ที่กำหนดเองเพื่อเล่นเนื้อหาบนอุปกรณ์ที่พร้อมใช้งาน Cast
Google Cast คืออะไร
Google Cast ช่วยให้ผู้ใช้แคสต์เนื้อหาจากอุปกรณ์เคลื่อนที่ไปยังทีวีได้ จากนั้นผู้ใช้ก็สามารถใช้อุปกรณ์เคลื่อนที่หรือเบราว์เซอร์ Chrome บนเดสก์ท็อปเป็นรีโมตคอนโทรลสำหรับการเล่นสื่อบนทีวี
Google Cast SDK ทำให้แอปของคุณสามารถควบคุมอุปกรณ์ที่รองรับ Google Cast ได้ (เช่น ทีวีหรือระบบเสียง) Cast SDK มอบคอมโพเนนต์ UI ที่จำเป็นให้คุณตามรายการตรวจสอบการออกแบบของ Google Cast
รายการตรวจสอบสำหรับการออกแบบของ Google Cast มีไว้เพื่อมอบประสบการณ์ของผู้ใช้ Cast ที่เรียบง่ายและคาดเดาได้ในทุกแพลตฟอร์มที่รองรับ ดูเพิ่มเติมที่นี่
เราจะสร้างอะไร
เมื่อเสร็จสิ้น Codelab นี้แล้ว คุณจะมีแอป HTML5 ซึ่งทำหน้าที่เป็นตัวรับสัญญาณที่กำหนดเองสำหรับแสดงเนื้อหาวิดีโอบนอุปกรณ์ที่พร้อมใช้งาน Cast
สิ่งที่คุณจะได้เรียนรู้
- วิธีตั้งค่าสำหรับการพัฒนาตัวรับสัญญาณ
- ข้อมูลเบื้องต้นเกี่ยวกับตัวรับสัญญาณที่พร้อมใช้งาน Cast โดยอิงตามเฟรมเวิร์กแอปพลิเคชัน Cast
- วิธีรับวิดีโอที่แคสต์
- วิธีผสานรวมตัวบันทึกการแก้ไขข้อบกพร่อง
- วิธีเพิ่มประสิทธิภาพตัวรับสัญญาณสำหรับจออัจฉริยะ
สิ่งที่คุณต้องมี
- เบราว์เซอร์ Google Chrome เวอร์ชันล่าสุด
- บริการโฮสติ้ง HTTPS เช่น โฮสติ้งของ Firebase หรือ ngrok
- อุปกรณ์ Google Cast เช่น Chromecast หรือ Android TV ที่กำหนดค่าการเข้าถึงอินเทอร์เน็ต
- ทีวีหรือจอภาพที่มีอินพุต HDMI
ประสบการณ์การใช้งาน
- คุณจะต้องมีความรู้ด้านการพัฒนาเว็บมาก่อน
- คุณจะต้องมีความรู้เบื้องต้นเกี่ยวกับการดูทีวีด้วย :)
คุณจะใช้บทแนะนำนี้อย่างไร
คุณจะให้คะแนนประสบการณ์การสร้างเว็บแอปอย่างไร
คุณจะให้คะแนนประสบการณ์ในการดูทีวีอย่างไร
2. รับโค้ดตัวอย่าง
คุณดาวน์โหลดโค้ดตัวอย่างทั้งหมดลงในคอมพิวเตอร์ได้...
แล้วแตกไฟล์ ZIP ที่ดาวน์โหลดมา
3. การทำให้เครื่องรับใช้งานได้ภายใน
อุปกรณ์แคสต์จะต้องโฮสต์ไว้ในที่ที่อุปกรณ์แคสต์สามารถเข้าถึงได้ จึงจะใช้เว็บรับสัญญาณกับอุปกรณ์แคสต์ได้ หากคุณมีเซิร์ฟเวอร์ที่รองรับ https อยู่แล้ว ให้ข้ามวิธีการต่อไปนี้และจดบันทึก URL ไว้ เนื่องจากคุณจะต้องใช้ในส่วนถัดไป
หากยังไม่มีเซิร์ฟเวอร์ ให้ใช้โฮสติ้งของ Firebase หรือ ngrok
เรียกใช้เซิร์ฟเวอร์
เมื่อตั้งค่าบริการที่ต้องการแล้ว ให้ไปที่ app-start
แล้วเริ่มต้นเซิร์ฟเวอร์
จด URL ของผู้รับที่โฮสต์ไว้ คุณจะได้ใช้ในส่วนถัดไป
4. ลงทะเบียนแอปพลิเคชันใน Cast Developer Console
คุณต้องลงทะเบียนแอปพลิเคชันเพื่อให้เรียกใช้ตัวรับสัญญาณที่กำหนดเองซึ่งติดตั้งใน Codelab ในอุปกรณ์ Chromecast ได้ หลังจากที่คุณลงทะเบียนแอปพลิเคชันแล้ว คุณจะได้รับรหัสแอปพลิเคชันที่แอปพลิเคชันผู้ส่งของคุณต้องใช้เพื่อทำการเรียก API เช่น เปิดใช้งานแอปพลิเคชันตัวรับ
คลิก "เพิ่มแอปพลิเคชันใหม่"
เลือก "ตัวรับแบบกำหนดเอง" นี่คือสิ่งที่เรากำลังสร้าง
ป้อนรายละเอียดของผู้รับใหม่ อย่าลืมใช้ URL ที่คุณได้
ในส่วนสุดท้าย จดบันทึกรหัสแอปพลิเคชันที่กำหนดให้กับผู้รับรายใหม่
นอกจากนี้ คุณต้องลงทะเบียนอุปกรณ์ Google Cast เพื่อให้อุปกรณ์สามารถเข้าถึงแอปพลิเคชันของเครื่องรับก่อนที่จะเผยแพร่ เมื่อคุณเผยแพร่แอปพลิเคชันตัวรับสัญญาณแล้ว แอปพลิเคชันนั้นจะพร้อมใช้งานบนอุปกรณ์ Google Cast ทุกเครื่อง สำหรับ Codelab นี้ขอแนะนำให้ทำงานกับแอปพลิเคชันตัวรับที่ยังไม่ได้เผยแพร่
คลิก "เพิ่มอุปกรณ์ใหม่"
ป้อนหมายเลขซีเรียลที่พิมพ์อยู่ด้านหลังอุปกรณ์ Cast แล้วตั้งชื่อที่สื่อความหมาย คุณยังสามารถค้นหาหมายเลขซีเรียลได้โดยการแคสต์หน้าจอใน Chrome เมื่อเข้าถึงแผงควบคุมสำหรับนักพัฒนาซอฟต์แวร์ Google Cast SDK
โดยจะใช้เวลา 5-15 นาทีก่อนที่เครื่องรับและอุปกรณ์จะพร้อมสำหรับการทดสอบ หลังจากรอ 5-15 นาที คุณต้องรีบูตอุปกรณ์แคสต์
5. เรียกใช้แอปตัวอย่าง
ในขณะที่เรารอใบสมัครตัวรับสัญญาณใหม่จะพร้อมสำหรับการทดสอบ มาดูกันว่าตัวอย่างแอปตัวรับสัญญาณที่สมบูรณ์ตัวอย่างมีลักษณะอย่างไร ตัวรับสัญญาณที่เรากำลังจะสร้างจะสามารถเล่นสื่อโดยใช้สตรีมมิงแบบบิตเรตที่ปรับเปลี่ยนได้ (เราจะใช้เนื้อหาตัวอย่างที่เข้ารหัสสำหรับ Dynamic Adaptive Streaming ผ่าน HTTP (DASH))
เปิดเครื่องมือ Command and Control (CaC) ในเบราว์เซอร์
- คุณควรเห็นเครื่องมือ CaC ของเรา
- ใช้ "CC1AD845" เริ่มต้น รหัสผู้รับตัวอย่าง แล้วคลิก "ตั้งค่ารหัสแอป"
- คลิกปุ่ม "แคสต์" ที่ด้านซ้ายบน แล้วเลือกอุปกรณ์ Google Cast
- ไปที่ "โหลดสื่อ" แท็บที่ด้านบน
- คลิกลิงก์ "โหลดตามเนื้อหา" เพื่อเล่นวิดีโอตัวอย่าง
- วิดีโอจะเริ่มเล่นในอุปกรณ์ Google Cast เพื่อแสดงฟังก์ชันการทำงานของตัวรับสัญญาณพื้นฐานเมื่อใช้ตัวรับเริ่มต้น
6. เตรียมเริ่มโปรเจ็กต์
เราต้องเพิ่มการรองรับ Google Cast ในแอปเริ่มต้นที่คุณดาวน์โหลด ต่อไปนี้คือคำศัพท์ของ Google Cast บางส่วนที่เราจะใช้ใน Codelab นี้
- แอปผู้ส่งทำงานบนอุปกรณ์เคลื่อนที่หรือแล็ปท็อป
- แอปตัวรับทำงานบนอุปกรณ์ Google Cast
ตอนนี้คุณก็พร้อมที่จะต่อยอดจากโปรเจ็กต์เริ่มต้นโดยใช้เครื่องมือแก้ไขข้อความที่คุณชอบแล้ว
- เลือกไดเรกทอรี
app-start
จากการดาวน์โหลดโค้ดตัวอย่าง - เปิด
js/receiver.js
และindex.html
โปรดทราบว่า http-server
น่าจะกำลังรับการเปลี่ยนแปลงที่คุณทำขณะทำงานผ่าน Codelab นี้ หากไม่เห็น ให้ลองปิดและรีสตาร์ท http-server
การออกแบบแอป
แอปตัวรับจะเริ่มต้นเซสชันการแคสต์ และจะสแตนด์บายจนกว่าคำขอ LOAD (หรืออีกนัยหนึ่งคือคำสั่งให้เล่นสื่อ) จากผู้ส่งมาถึง
แอปนี้ประกอบด้วยมุมมองหลัก 1 มุมมองที่กำหนดไว้ใน index.html
และไฟล์ JavaScript 1 ไฟล์ชื่อ js/receiver.js
ซึ่งมีตรรกะทั้งหมดที่จะทำให้ตัวรับของเราทำงานได้
index.html
ไฟล์ HTML นี้จะมี UI สำหรับแอปตัวรับสัญญาณของเรา ตอนนี้ยังไม่มีรายการใดเลย และเราจะเพิ่มฟีเจอร์ดังกล่าวทั่วทั้ง Code Lab
receiver.js
สคริปต์นี้จะจัดการตรรกะทั้งหมดสำหรับแอปตัวรับสัญญาณของเรา ในขณะนี้ ไฟล์นี้เป็นเพียงไฟล์เปล่า แต่เรากำลังจะเปลี่ยนไฟล์นี้ให้เป็นเครื่องรับการแคสต์ที่ทำงานได้เต็มรูปแบบด้วยโค้ดเพียงไม่กี่บรรทัดในส่วนถัดไป
7. เครื่องรับการแคสต์พื้นฐาน
ตัวรับการแคสต์พื้นฐานจะเริ่มต้นเซสชันการแคสต์เมื่อเริ่มต้นระบบ ซึ่งจำเป็นต้องแจ้งแอปพลิเคชันของผู้ส่งที่เชื่อมต่อทั้งหมดว่าการเปิดตัวรับนั้นสำเร็จแล้ว นอกจากนี้ SDK ใหม่ยังกำหนดค่าไว้ล่วงหน้าเพื่อจัดการการสตรีมสื่อที่มีอัตราบิตที่ปรับเปลี่ยนได้ (โดยใช้ DASH, HLS และ Smooth Streaming) และไฟล์ MP4 แบบธรรมดาซึ่งพร้อมใช้งานได้ทันที มาลองกันเลย
การเริ่มต้น
เพิ่มโค้ดต่อไปนี้ลงใน index.html
ในส่วนหัว
<head>
...
<script src="//www.gstatic.com/cast/sdk/libs/caf_receiver/v3/cast_receiver_framework.js"></script>
</head>
เพิ่มโค้ดต่อไปนี้ลงใน index.html
<body>
ก่อน <footer>
กำลังโหลด receiver.js,
เพื่อให้ SDK ตัวรับมีพื้นที่ว่างเพื่อแสดง UI ตัวรับเริ่มต้นซึ่งจัดส่งพร้อมกับสคริปต์ที่คุณเพิ่งเพิ่ม
<cast-media-player></cast-media-player>
ตอนนี้เราจำเป็นต้องเริ่มต้น SDK ใน js/receiver.js
ซึ่งประกอบด้วย
- การรับการอ้างอิงไปยัง
CastReceiverContext
ซึ่งเป็นจุดแรกเข้าหลักของคุณไปยัง SDK ของตัวรับสัญญาณทั้งหมด - การจัดเก็บการอ้างอิงไปยัง
PlayerManager
ออบเจ็กต์ที่จัดการการเล่น และให้ Hook ทั้งหมดที่คุณต้องการเพื่อปลั๊กอินตรรกะที่กำหนดเองของคุณเอง - กำลังเริ่มต้น SDK โดยเรียกใช้
start()
ในCastReceiverContext
เพิ่มข้อมูลต่อไปนี้ใน js/receiver.js
const context = cast.framework.CastReceiverContext.getInstance();
const playerManager = context.getPlayerManager();
context.start();
8. การแคสต์ "พื้นฐาน" เนื้อหาวิดีโอ
สำหรับ Codelab นี้ ให้ใช้เครื่องมือ CaC เพื่อลองใช้รีซีฟเวอร์เครื่องใหม่
ชี้เว็บเบราว์เซอร์ไปที่เครื่องมือ Command and Control (CaC)
โปรดแทนที่รหัสแอปของคุณเองตามที่จดทะเบียนไว้ก่อนหน้าในช่อง และคลิก "ตั้งค่ารหัสแอป" ซึ่งจะเป็นการสั่งให้เครื่องมือใช้อุปกรณ์รับเมื่อเริ่มเซสชันการแคสต์
กำลังแคสต์สื่อ
หากต้องการเล่นสื่อในอุปกรณ์แคสต์ในระดับสูง คุณจะต้องดำเนินการต่อไปนี้
- ผู้ส่งสร้างออบเจ็กต์
MediaInfo
JSON
จาก Cast SDK ที่จำลองรายการสื่อ - ผู้ส่งเชื่อมต่อกับอุปกรณ์แคสต์เพื่อเปิดใช้งานแอปพลิเคชันของเครื่องรับ
- ผู้รับจะโหลดออบเจ็กต์
MediaInfo
ผ่านคำขอLOAD
เพื่อเล่นเนื้อหา - ตัวรับสัญญาณจะตรวจสอบและติดตามสถานะสื่อ
- ผู้ส่งจะส่งคำสั่งการเล่นไปยังผู้รับเพื่อควบคุมการเล่นตามการโต้ตอบของผู้ใช้กับแอปของผู้ส่ง
ในความพยายามขั้นพื้นฐานเบื้องต้นนี้ เราจะป้อนข้อมูล MediaInfo
ด้วย URL ของเนื้อหาที่เล่นได้ (จัดเก็บไว้ใน MediaInfo.contentUrl
)
ผู้ส่งในชีวิตจริงใช้ตัวระบุสื่อเฉพาะแอปพลิเคชันใน MediaInfo.contentId
ผู้รับใช้ contentId
เป็นตัวระบุเพื่อทำการเรียก API แบ็กเอนด์ที่เหมาะสมเพื่อแก้ไข URL ของชิ้นงานจริงและตั้งค่าเป็น MediaInfo.contentUrl.
โดยผู้รับจะจัดการงานต่างๆ เช่น การขอใบอนุญาต DRM หรือการแทรกข้อมูลเกี่ยวกับช่วงพักโฆษณาด้วย
เราจะขยายตัวรับของคุณให้ทำแบบนี้ในส่วนถัดไป สำหรับตอนนี้ ให้คลิกไอคอน "แคสต์" แล้วเลือกอุปกรณ์เพื่อเปิดเครื่องรับ
ไปที่ "โหลดสื่อ" และคลิก "โหลดตามเนื้อหา'' ผู้รับควรเริ่มเล่นเนื้อหาตัวอย่าง
SDK ตัวรับจึงจัดการได้ทันทีดังนี้
- กำลังเริ่มต้นเซสชันการแคสต์
- จัดการคำขอของ
LOAD
ที่ส่งเข้ามาจากผู้ส่งที่มีเนื้อหาที่เล่นได้ - จัดให้มี UI โปรแกรมเล่นพื้นฐานที่พร้อมแสดงบนหน้าจอขนาดใหญ่
คุณอาจสำรวจเครื่องมือ CaC และโค้ดของเครื่องมือก่อนไปยังส่วนถัดไป ซึ่งเราจะขยายตัวรับเพื่อพูดคุยถึง API ตัวอย่างง่ายๆ เพื่อดำเนินการตามคำขอ LOAD
ขาเข้าจากผู้ส่ง
9. ผสานรวมกับ API ภายนอก
เราจะแก้ไขรีซีฟเวอร์ให้รองรับคำขอ LOAD
ที่อ้างอิงเนื้อหาสื่อที่ต้องการด้วยคีย์ API แทนการส่ง URL เนื้อหาที่เล่นได้ เพื่อให้สอดคล้องกับวิธีที่นักพัฒนาซอฟต์แวร์ส่วนใหญ่โต้ตอบกับเครื่องรับการแคสต์ในแอปพลิเคชันที่ใช้งานจริง
โดยทั่วไปแอปพลิเคชันจะทำงานนี้เนื่องจากสาเหตุต่อไปนี้
- ผู้ส่งอาจไม่ทราบ URL ของเนื้อหา
- แอปพลิเคชัน Cast ออกแบบมาเพื่อจัดการการตรวจสอบสิทธิ์ ตรรกะทางธุรกิจอื่นๆ หรือการเรียก API ในตัวรับโดยตรง
ฟังก์ชันนี้จะใช้ในเมธอด PlayerManager
setMessageInterceptor()
เป็นหลัก วิธีนี้ช่วยให้คุณสกัดกั้นข้อความขาเข้าตามประเภทและแก้ไขก่อนที่จะไปถึงเครื่องจัดการข้อความภายในของ SDK ได้ ในส่วนนี้ เราจะดําเนินการกับคําขอ LOAD
ซึ่งเราจะดำเนินการต่อไปนี้
- อ่านคำขอ
LOAD
ที่เข้ามาและcontentId
ที่กำหนดเองของคำขอ - เรียกใช้
GET
ไปยัง API ของเราเพื่อค้นหาเนื้อหาที่สตรีมได้ผ่านทางcontentId
- แก้ไขคำขอ
LOAD
โดยใช้ URL ของสตรีม - แก้ไขออบเจ็กต์
MediaInformation
เพื่อตั้งค่าพารามิเตอร์ประเภทสตรีม - ส่งคำขอไปยัง SDK เพื่อเล่น หรือปฏิเสธคำสั่งหากเราค้นหาสื่อที่ขอไม่ได้
API ตัวอย่างที่ให้มาจะแสดง Hook ของ SDK สำหรับการปรับแต่งงานตัวรับทั่วไป โดยที่ยังคงใช้งานที่พร้อมใช้งานได้ทันที
API ตัวอย่าง
เปิดเบราว์เซอร์และไปที่ https://storage.googleapis.com/cpe-sample-media/content.json และดูตัวอย่างแคตตาล็อกวิดีโอของเรา เนื้อหาประกอบด้วย URL สำหรับภาพโปสเตอร์ในรูปแบบ 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"
},
[...]
}
ในขั้นตอนถัดไป เราจะแมปคีย์ของแต่ละรายการ (เช่น bbb, fbb_ad
) กับ URL ของสตรีมหลังจากที่เรียกผู้รับด้วยคำขอ LOAD
สกัดกั้นคำขอ LOAD
ในขั้นตอนนี้ เราจะสร้างตัวตัดโหลดที่มีฟังก์ชันที่ส่งคำขอ XHR
ไปยังไฟล์ JSON
ที่โฮสต์ไว้ เมื่อได้รับไฟล์ 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);
}
});
});
});
ส่วนถัดไปจะอธิบายถึงวิธีกำหนดค่าพร็อพเพอร์ตี้ media
ของคำขอโหลดสำหรับเนื้อหา DASH
การใช้เนื้อหา DASH ตัวอย่างสำหรับ API
เมื่อเราเตรียมตัวตรวจจับโหลดแล้ว เราจะระบุประเภทเนื้อหาให้กับตัวรับ ข้อมูลนี้จะให้ URL ของเพลย์ลิสต์หลักและประเภท MIME ของสตรีมแก่ผู้รับ เพิ่มโค้ดต่อไปนี้ลงในไฟล์ js/receiver.js ใน Promise()
ของตัวสกัดกั้น LOAD
:
...
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 แทน โปรดดูขั้นตอนถัดไป
การใช้เนื้อหา HLS ของ API ตัวอย่าง
API ตัวอย่างมีเนื้อหา HLS และ DASH นอกจากการตั้งค่า contentType
อย่างเช่นที่เราทำในขั้นตอนก่อนหน้า คำขอโหลดจะต้องมีพร็อพเพอร์ตี้เพิ่มเติมบางอย่างเพื่อใช้ URL HLS ของตัวอย่าง API เมื่อกำหนดค่าให้ตัวรับสัญญาณเล่นสตรีม HLS ประเภทคอนเทนเนอร์เริ่มต้นที่คาดไว้คือ Transport Stream (TS) ด้วยเหตุนี้ ผู้รับจะพยายามเปิดตัวอย่างสตรีม MP4 ในรูปแบบ TS หากแก้ไขเฉพาะพร็อพเพอร์ตี้ contentUrl
ในคำขอโหลด ควรแก้ไขออบเจ็กต์ MediaInformation
ด้วยคุณสมบัติเพิ่มเติมเพื่อให้เครื่องรับรู้ว่าเนื้อหาเป็นประเภท MP4 ไม่ใช่ TS เพิ่มโค้ดต่อไปนี้ลงในไฟล์ 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;
...
}
});
});
});
การทดสอบ
เปิดเครื่องมือ Command and Control (CaC) อีกครั้ง แล้วตั้งรหัสแอปเป็นรหัสแอปของผู้รับ เลือกอุปกรณ์โดยใช้ปุ่ม "แคสต์"
ไปที่ "โหลดสื่อ" ตอนนี้ให้ลบข้อความใน "URL เนื้อหา" ฟิลด์ "โหลดตามเนื้อหา" ซึ่งจะบังคับให้แอปพลิเคชันของเราส่งคำขอ LOAD
ที่มีเฉพาะการอ้างอิง contentId
ไปยังสื่อของเรา
สมมติว่าทุกอย่างทำงานได้ดีกับการแก้ไขตัวรับ เครื่องมือดักจับควรจัดการรูปร่างออบเจ็กต์ MediaInfo
เป็นสิ่งที่ SDK เล่นบนหน้าจอได้
คลิกลิงก์ "โหลดตามเนื้อหา" เพื่อดูว่าสื่อของคุณเล่นอย่างถูกต้องหรือไม่ คุณจะเปลี่ยน Content ID เป็นรหัสอื่นในไฟล์ content.json ได้
10. การเพิ่มประสิทธิภาพสำหรับจออัจฉริยะ
จออัจฉริยะเป็นอุปกรณ์ที่มีฟังก์ชันการแตะ ซึ่งช่วยให้แอปพลิเคชันตัวรับสัญญาณสามารถรองรับการควบคุมที่เปิดใช้ระบบสัมผัส
ส่วนนี้จะอธิบายวิธีเพิ่มประสิทธิภาพแอปพลิเคชันตัวรับสัญญาณเมื่อเปิดบนจออัจฉริยะ และวิธีปรับแต่งตัวควบคุมวิดีโอเพลเยอร์
การเข้าถึงการควบคุม UI
คุณเข้าถึงออบเจ็กต์การควบคุม UI ของ Smart Display ได้โดยใช้ 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> คุณจะต้องตั้งค่า touchScreenOptimizedApp
ใน CastReceiverOptions
ใน Codelab นี้ เราใช้ <cast-media-player>
context.start({ touchScreenOptimizedApp: true });
ระบบจะกำหนดปุ่มควบคุมเริ่มต้นให้กับช่องแต่ละช่องตาม MetadataType
และ MediaStatus.supportedMediaCommands
การควบคุมวิดีโอ
สำหรับ MetadataType.MOVIE
, MetadataType.TV_SHOW
และ MetadataType.GENERIC
ออบเจ็กต์การควบคุม UI สำหรับจออัจฉริยะจะแสดงตามตัวอย่างด้านล่าง
--playback-logo-image
MediaMetadata.subtitle
MediaMetadata.title
MediaStatus.currentTime
MediaInformation.duration
ControlsSlot.SLOT_SECONDARY_1
:ControlsButton.QUEUE_PREV
ControlsSlot.SLOT_PRIMARY_1
:ControlsButton.SEEK_BACKWARD_30
PLAY/PAUSE
ControlsSlot.SLOT_PRIMARY_2
:ControlsButton.SEEK_FORWARD_30
ControlsSlot.SLOT_SECONDARY_2
:ControlsButton.QUEUE_NEXT
การควบคุมเสียง
สำหรับ MetadataType.MUSIC_TRACK
ออบเจ็กต์การควบคุม UI สำหรับจออัจฉริยะจะแสดงดังนี้
--playback-logo-image
MusicTrackMediaMetadata.albumName
MusicTrackMediaMetadata.title
MusicTrackMediaMetadata.albumArtist
MusicTrackMediaMetadata.images[0]
MediaStatus.currentTime
MediaInformation.duration
ControlsSlot.SLOT_SECONDARY_1
:ControlsButton.NO_BUTTON
ControlsSlot.SLOT_PRIMARY_1
:ControlsButton.QUEUE_PREV
PLAY/PAUSE
ControlsSlot.SLOT_PRIMARY_2
:ControlsButton.QUEUE_NEXT
ControlsSlot.SLOT_SECONDARY_2
:ControlsButton.NO_BUTTON
การอัปเดตคำสั่งสื่อที่รองรับ
ออบเจ็กต์ตัวควบคุม UI จะกำหนดด้วยว่า ControlsButton
จะแสดงหรือไม่โดยอิงตาม MediaStatus.supportedMediaCommands
เมื่อค่าของ 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. การใช้การเรียกดูสื่อใน Smart Display
การเรียกดูสื่อคือฟีเจอร์ตัวรับสัญญาณ CAF ที่ช่วยให้ผู้ใช้สำรวจเนื้อหาเพิ่มเติมในอุปกรณ์ระบบสัมผัสได้ หากต้องการนําไปใช้ คุณจะใช้ PlayerDataBinder
ตั้งค่า UI ของ BrowseContent
จากนั้นคุณจะป้อนข้อมูลใน BrowseItems
โดยอิงตามเนื้อหาที่ต้องการแสดงได้
BrowseContent
ด้านล่างเป็นตัวอย่างของ UI และพร็อพเพอร์ตี้ของ BrowseContent
BrowseContent.title
BrowseContent.items
สัดส่วนภาพ
ใช้ targetAspectRatio property
เพื่อเลือกสัดส่วนภาพที่ดีที่สุดสําหรับชิ้นงานรูปภาพ SDK ตัวรับสัญญาณ CAF รองรับสัดส่วนภาพ 3 แบบ ได้แก่ SQUARE_1_TO_1
, PORTRAIT_2_TO_3
และ LANDSCAPE_16_TO_9
BrowseItem
ใช้ BrowseItem
เพื่อแสดงชื่อ ชื่อรอง ระยะเวลา และรูปภาพสำหรับแต่ละรายการ
BrowseItem.image
BrowseItem.duration
BrowseItem.title
BrowseItem.subtitle
ตั้งค่าข้อมูลการเรียกดูสื่อ
คุณสามารถระบุรายการเนื้อหาสื่อสำหรับการเรียกดูได้โดยโทรหา setBrowseContent
เพิ่มโค้ดต่อไปนี้ลงในไฟล์ js/receiver.js
ด้านล่าง playerDataBinder
และใน Listener กิจกรรม 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. การแก้ไขข้อบกพร่องของแอปตัวรับสัญญาณ
SDK ตัวรับการแคสต์เป็นอีกตัวเลือกหนึ่งที่ช่วยให้นักพัฒนาซอฟต์แวร์แก้ไขข้อบกพร่องของแอปตัวรับสัญญาณได้ง่ายๆ โดยใช้ CastDebugLogger API และเครื่องมือ Command and Control (CaC) ที่ใช้ร่วมกันเพื่อเก็บบันทึก
การเริ่มต้น
ในการรวม API เข้าด้วยกัน ให้เพิ่มสคริปต์ต้นทาง CastDebugLogger
ในไฟล์ index.html ของคุณ ควรระบุแหล่งที่มาใน <head> หลังการประกาศ Cast Receiver SDK
<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.EventType
และ cast.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,
};
การวางซ้อนการแก้ไขข้อบกพร่อง
ตัวบันทึกการแก้ไขข้อบกพร่องของแคสต์จะให้การวางซ้อนการแก้ไขข้อบกพร่องบนตัวรับสัญญาณเพื่อแสดงข้อความบันทึกที่กำหนดเองบนอุปกรณ์แคสต์ ใช้ 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 แล้ว
สำหรับรายละเอียดเพิ่มเติม โปรดดูคู่มือนักพัฒนาซอฟต์แวร์เว็บรีซีฟเวอร์