1. ภาพรวม
Codelab นี้จะสอนวิธีแก้ไขแอป Android TV ที่มีอยู่เพื่อรองรับการแคสต์และการสื่อสารจากแอปตัวส่ง Cast ที่มีอยู่
Google Cast และ Cast Connect คืออะไร
Google Cast ช่วยให้ผู้ใช้แคสต์เนื้อหาจากอุปกรณ์เคลื่อนที่ไปยังทีวีได้ เซสชัน Google Cast ทั่วไปประกอบด้วย 2 องค์ประกอบ ได้แก่ แอปพลิเคชันผู้ส่งและแอปพลิเคชันผู้รับ แอปพลิเคชันสำหรับผู้ส่ง เช่น แอปหรือเว็บไซต์บนอุปกรณ์เคลื่อนที่ เช่น YouTube.com จะเริ่มต้นและควบคุมการเล่นแอปพลิเคชันตัวรับการแคสต์ แอปพลิเคชันตัวรับการแคสต์เป็นแอป HTML 5 ที่ทำงานในอุปกรณ์ Chromecast และ Android TV
ระบบจะจัดเก็บสถานะเกือบทั้งหมดในเซสชัน Cast ไว้ในแอปพลิเคชันผู้รับ เมื่อสถานะอัปเดต เช่น มีการโหลดรายการสื่อใหม่ ระบบจะกระจายสถานะสื่อไปยังผู้ส่งทุกคน การออกอากาศเหล่านี้มีสถานะปัจจุบันของเซสชันการแคสต์ แอปพลิเคชันผู้ส่งใช้สถานะสื่อนี้เพื่อแสดงข้อมูลการเล่นใน UI
Cast Connect สร้างขึ้นจากโครงสร้างพื้นฐานนี้ โดยมีแอป Android TV ทำหน้าที่เป็นตัวรับ คลัง Cast Connect ช่วยให้แอป Android TV ของคุณรับข้อความและออกอากาศสถานะสื่อได้ราวกับเป็นแอปพลิเคชันตัวรับ Cast
เราจะสร้างอะไร
เมื่อทำ Codelab นี้เสร็จแล้ว คุณจะใช้แอปตัวส่ง Cast เพื่อแคสต์วิดีโอไปยังแอป Android TV ได้ นอกจากนี้ แอป Android TV ยังสื่อสารกับแอปตัวส่งผ่านโปรโตคอล Cast ได้ด้วย
สิ่งที่คุณจะได้เรียนรู้
- วิธีเพิ่มคลัง Cast Connect ลงในแอป ATV ตัวอย่าง
- วิธีเชื่อมต่ออุปกรณ์ส่งสัญญาณแคสต์และเปิดแอป ATV
- วิธีเริ่มเล่นสื่อในแอป ATV จากแอปตัวส่ง Cast
- วิธีส่งสถานะสื่อจากแอป ATV ไปยังแอปผู้ส่ง Cast
สิ่งที่คุณต้องมี
- Android SDK เวอร์ชันล่าสุด
- Android Studio เวอร์ชันล่าสุด โดยต้องเป็นเวอร์ชัน
Chipmunk | 2021.2.1
ขึ้นไป - อุปกรณ์ Android TV ที่เปิดใช้ตัวเลือกสำหรับนักพัฒนาแอปและการแก้ไขข้อบกพร่องผ่าน USB
- โทรศัพท์ Android ที่เปิดใช้ตัวเลือกสำหรับนักพัฒนาแอปและการแก้ไขข้อบกพร่อง USB
- สาย USB สำหรับเชื่อมต่อโทรศัพท์ Android และอุปกรณ์ Android TV กับคอมพิวเตอร์สำหรับพัฒนาซอฟต์แวร์
- ความรู้พื้นฐานเกี่ยวกับการพัฒนาแอปพลิเคชัน Android โดยใช้ Kotlin
2. รับโค้ดตัวอย่าง
คุณสามารถดาวน์โหลดโค้ดตัวอย่างทั้งหมดลงในคอมพิวเตอร์ได้...
และแตกไฟล์ ZIP ที่ดาวน์โหลด
3. เรียกใช้แอปตัวอย่าง
ก่อนอื่น มาดูกันว่าแอปตัวอย่างที่เสร็จสมบูรณ์มีลักษณะเป็นอย่างไร แอป Android TV ใช้ UI ของ Leanback และโปรแกรมเล่นวิดีโอพื้นฐาน ผู้ใช้สามารถเลือกวิดีโอจากรายการซึ่งจะเล่นบนทีวีเมื่อเลือก ผู้ใช้ยังแคสต์วิดีโอไปยังแอป Android TV ได้ด้วยแอปส่งบนอุปกรณ์เคลื่อนที่ที่มาพร้อมแอปนี้
ลงทะเบียนอุปกรณ์ของนักพัฒนาซอฟต์แวร์
หากต้องการเปิดใช้ความสามารถของ Cast Connect สําหรับการพัฒนาแอปพลิเคชัน คุณต้องลงทะเบียนหมายเลขซีเรียลของ Chromecast ในตัวอุปกรณ์ Android TV ที่คุณจะใช้ใน Cast Developer Console คุณดูหมายเลขซีเรียลได้โดยไปที่การตั้งค่า > ค่ากำหนดอุปกรณ์ > Chromecast Built-In > หมายเลขซีเรียลบน Android TV โปรดทราบว่าหมายเลขนี้แตกต่างจากหมายเลขซีเรียลของอุปกรณ์จริง และต้องได้รับจากวิธีการที่อธิบายไว้ข้างต้น
หากไม่ได้ลงทะเบียน Cast Connect จะใช้งานได้กับแอปที่ติดตั้งจาก Google Play Store เท่านั้นเนื่องจากเหตุผลด้านความปลอดภัย หลังจากเริ่มกระบวนการลงทะเบียนไปแล้ว 15 นาที ให้รีสตาร์ทอุปกรณ์
ติดตั้งแอปผู้ส่งสำหรับ Android
ในการทดสอบการส่งคำขอจากอุปกรณ์เคลื่อนที่ เราได้จัดเตรียมแอปพลิเคชันผู้ส่งแบบง่ายที่เรียกว่า "แคสต์วิดีโอ" เป็นไฟล์ mobile-sender-0629.apk
ไว้ในการดาวน์โหลดรหัสไปรษณีย์ของซอร์สโค้ด เราจะใช้ ADB เพื่อติดตั้ง APK หากคุณติดตั้งวิดีโอแคสต์เวอร์ชันอื่นไว้แล้ว โปรดถอนการติดตั้งเวอร์ชันนั้นจากโปรไฟล์ทั้งหมดในอุปกรณ์ก่อนดำเนินการต่อ
- เปิดใช้ตัวเลือกสำหรับนักพัฒนาแอปและการแก้ไขข้อบกพร่อง USB ในโทรศัพท์ Android
- เสียบสายข้อมูล USB เพื่อเชื่อมต่อโทรศัพท์ Android กับคอมพิวเตอร์สำหรับการพัฒนา
- ติดตั้ง
mobile-sender-0629.apk
ในโทรศัพท์ Android
- คุณจะเห็นแอปส่งวิดีโอแคสต์ในโทรศัพท์ Android
ติดตั้งแอป Android TV
วิธีการต่อไปนี้อธิบายวิธีเปิดและเรียกใช้แอปตัวอย่างที่เสร็จสมบูรณ์ใน Android Studio
- เลือกนําเข้าโปรเจ็กต์ในหน้าจอต้อนรับหรือตัวเลือกเมนูไฟล์ > ใหม่ > นําเข้าโปรเจ็กต์...
- เลือกไดเรกทอรี
app-done
จากโฟลเดอร์โค้ดตัวอย่าง แล้วคลิก "ตกลง" - คลิก File > Sync Project with Gradle Files
- เปิดใช้ตัวเลือกสำหรับนักพัฒนาแอปและการแก้ไขข้อบกพร่อง USB ในอุปกรณ์ Android TV
- ADB เชื่อมต่อกับอุปกรณ์ Android TV ของคุณ อุปกรณ์ดังกล่าวควรจะแสดงใน Android Studio
- คลิกปุ่ม Run คุณควรเห็นแอป ATV ชื่อ Cast Connect Codelab ปรากฏขึ้นหลังจากผ่านไป 2-3 วินาที
มาเล่น Cast Connect ด้วยแอป ATV
- ไปที่หน้าจอหลักของ Android TV
- เปิดแอปส่งวิดีโอแคสต์จากโทรศัพท์ Android คลิกปุ่มแคสต์ แล้วเลือกอุปกรณ์ ATV
- แอป Cast Connect Codelab ATV จะเปิดขึ้นใน ATV และปุ่มแคสต์ในอุปกรณ์ส่งจะระบุว่าเชื่อมต่อแล้ว
- เลือกวิดีโอจากแอป ATV แล้ววิดีโอจะเริ่มเล่นบน ATV
- ตอนนี้คุณจะเห็นตัวควบคุมขนาดเล็กที่ด้านล่างของแอปผู้ส่งในโทรศัพท์มือถือ คุณสามารถใช้ปุ่มเล่น/หยุดชั่วคราวเพื่อควบคุมการเล่นได้
- เลือกวิดีโอจากโทรศัพท์มือถือแล้วเล่น วิดีโอจะเริ่มเล่นบนรถ ATV และตัวควบคุมที่ขยายจะแสดงบนผู้ส่งบนอุปกรณ์เคลื่อนที่
- ล็อกโทรศัพท์ และเมื่อปลดล็อกแล้ว คุณควรเห็นการแจ้งเตือนบนหน้าจอล็อกเพื่อควบคุมการเล่นสื่อหรือหยุดการแคสต์
4. เตรียมโปรเจ็กต์เริ่มต้น
เมื่อยืนยันการผสานรวม Cast Connect ของแอปที่เสร็จสมบูรณ์แล้ว เราจะต้องเพิ่มการรองรับ Cast Connect ลงในแอปเริ่มต้นที่คุณดาวน์โหลด ตอนนี้คุณพร้อมที่จะต่อยอดจากโปรเจ็กต์เริ่มต้นโดยใช้ Android Studio แล้ว โดยทำดังนี้
- เลือกนําเข้าโปรเจ็กต์ในหน้าจอต้อนรับหรือตัวเลือกเมนูไฟล์ > ใหม่ > นําเข้าโปรเจ็กต์...
- เลือกไดเรกทอรี
app-start
จากโฟลเดอร์โค้ดตัวอย่าง แล้วคลิก "ตกลง" - คลิก File > Sync Project with Gradle Files
- เลือกอุปกรณ์ ATV แล้วคลิกปุ่ม Run เพื่อเรียกใช้แอปและสำรวจ UI
การออกแบบแอป
แอปแสดงรายการวิดีโอให้ผู้ใช้เลือกดู ผู้ใช้สามารถเลือกวิดีโอที่จะเล่นบน Android TV ได้ แอปประกอบด้วยกิจกรรมหลัก 2 รายการ ได้แก่ MainActivity
และ PlaybackActivity
กิจกรรมหลัก
กิจกรรมนี้มีส่วนย่อย (MainFragment
) รายการวิดีโอและข้อมูลเมตาที่เกี่ยวข้องจะได้รับการกำหนดค่าในคลาส MovieList
และจะเรียกใช้เมธอด setupMovies()
เพื่อสร้างรายการออบเจ็กต์ Movie
ออบเจ็กต์ Movie
แสดงถึงเอนทิตีวิดีโอที่มีชื่อ คำอธิบาย ภาพขนาดย่อของรูปภาพ และ URL ของวิดีโอ ออบเจ็กต์ Movie
แต่ละรายการจะเชื่อมโยงกับ CardPresenter
เพื่อแสดงภาพปกวิดีโอพร้อมชื่อและสตูดิโอ และส่งไปยัง ArrayObjectAdapter
เมื่อเลือกรายการ ระบบจะส่งผ่านออบเจ็กต์ Movie
ที่เกี่ยวข้องไปยัง PlaybackActivity
PlaybackActivity
กิจกรรมนี้มี Fregment (PlaybackVideoFragment
) ซึ่งโฮสต์ VideoView
ที่มี ExoPlayer
, ตัวควบคุมสื่อบางรายการ และพื้นที่ข้อความเพื่อแสดงคำอธิบายของวิดีโอที่เลือก และอนุญาตให้ผู้ใช้เล่นวิดีโอบน Android TV ผู้ใช้สามารถใช้รีโมตคอนโทรลเพื่อเล่น/หยุดชั่วคราว หรือกรอวิดีโอเพื่อเล่นวิดีโอ
ข้อกำหนดเบื้องต้นของ Cast Connect
Cast Connect ใช้บริการ Google Play เวอร์ชันใหม่ที่กำหนดให้แอป ATV ของคุณต้องอัปเดตเพื่อใช้เนมสเปซ AndroidX
หากต้องการรองรับ Cast Connect ในแอป Android TV คุณต้องสร้างและรองรับเหตุการณ์จากเซสชันสื่อ ไลบรารี Cast Connect จะสร้างสถานะสื่อตามสถานะของเซสชันสื่อ คลัง Cast Connect ยังใช้เซสชันสื่อเพื่อส่งสัญญาณเมื่อได้รับข้อความบางอย่างจากผู้ส่ง เช่น ข้อความหยุดชั่วคราว
5. การกำหนดค่าการรองรับ Cast
การอ้างอิง
อัปเดตแอป build.gradle
เพื่อรวมทรัพยากร Dependency ของไลบรารีที่จำเป็น
dependencies {
....
// Cast Connect libraries
implementation 'com.google.android.gms:play-services-cast-tv:20.0.0'
implementation 'com.google.android.gms:play-services-cast:21.1.0'
}
ซิงค์โปรเจ็กต์เพื่อยืนยันว่าโปรเจ็กต์สร้างโดยไม่มีข้อผิดพลาด
การเริ่มต้น
CastReceiverContext
เป็นออบเจ็กต์เดี่ยวเพื่อประสานงานการโต้ตอบกับแคสต์ทั้งหมด คุณต้องติดตั้งใช้งานอินเทอร์เฟซ ReceiverOptionsProvider
เพื่อระบุ CastReceiverOptions
เมื่อเริ่มต้น CastReceiverContext
สร้างไฟล์ CastReceiverOptionsProvider.kt
และเพิ่มคลาสต่อไปนี้ลงในโปรเจ็กต์
package com.google.sample.cast.castconnect
import android.content.Context
import com.google.android.gms.cast.tv.ReceiverOptionsProvider
import com.google.android.gms.cast.tv.CastReceiverOptions
class CastReceiverOptionsProvider : ReceiverOptionsProvider {
override fun getOptions(context: Context): CastReceiverOptions {
return CastReceiverOptions.Builder(context)
.setStatusText("Cast Connect Codelab")
.build()
}
}
จากนั้นระบุผู้ให้บริการตัวเลือกผู้รับภายในแท็ก <application>
ของไฟล์ AndroidManifest.xml
ของแอป
<application>
...
<meta-data
android:name="com.google.android.gms.cast.tv.RECEIVER_OPTIONS_PROVIDER_CLASS_NAME"
android:value="com.google.sample.cast.castconnect.CastReceiverOptionsProvider" />
</application>
หากต้องการเชื่อมต่อกับแอป ATV จากอุปกรณ์ส่ง Cast ให้เลือกกิจกรรมที่ต้องการเปิด ในโค้ดแล็บนี้ เราจะเปิดMainActivity
ของแอปเมื่อเริ่มเซสชัน Cast ในไฟล์ AndroidManifest.xml
ให้เพิ่มตัวกรอง Intent การเปิดตัวใน MainActivity
<activity android:name=".MainActivity">
...
<intent-filter>
<action android:name="com.google.android.gms.cast.tv.action.LAUNCH" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
วงจรชีวิตของบริบทของอุปกรณ์รับการแคสต์
คุณควรเริ่มใช้งาน CastReceiverContext
เมื่อเปิดแอป และหยุด CastReceiverContext
เมื่อย้ายแอปไปที่เบื้องหลัง เราขอแนะนำให้คุณใช้ LifecycleObserver
จากไลบรารี androidx.lifecycle เพื่อจัดการการโทร CastReceiverContext.start()
และ CastReceiverContext.stop()
เปิดไฟล์ MyApplication.kt
และเริ่มต้นบริบทการแคสต์โดยเรียกใช้ initInstance()
ในเมธอด onCreate
ของแอปพลิเคชัน ในคลาส AppLifeCycleObserver
start()
CastReceiverContext
เมื่อแอปพลิเคชันกลับมาทำงานต่อ และ stop()
เมื่อแอปพลิเคชันหยุดชั่วคราว
package com.google.sample.cast.castconnect
import com.google.android.gms.cast.tv.CastReceiverContext
...
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
CastReceiverContext.initInstance(this)
ProcessLifecycleOwner.get().lifecycle.addObserver(AppLifecycleObserver())
}
class AppLifecycleObserver : DefaultLifecycleObserver {
override fun onResume(owner: LifecycleOwner) {
Log.d(LOG_TAG, "onResume")
CastReceiverContext.getInstance().start()
}
override fun onPause(owner: LifecycleOwner) {
Log.d(LOG_TAG, "onPause")
CastReceiverContext.getInstance().stop()
}
}
}
การเชื่อมต่อ MediaSession กับ MediaManager
MediaManager
เป็นพร็อพเพอร์ตี้ของ CastReceiverContext
แบบ Singleton ซึ่งจะจัดการสถานะสื่อ จัดการ Intent การโหลด แปลข้อความเนมสเปซสื่อจากผู้ส่งเป็นคําสั่งสื่อ และส่งสถานะสื่อกลับไปยังผู้ส่ง
เมื่อสร้าง MediaSession
คุณจะต้องระบุโทเค็น MediaSession
ปัจจุบันให้กับ MediaManager
ด้วยเพื่อให้ทราบว่าต้องส่งคำสั่งไปที่ไหนและดึงข้อมูลสถานะการเล่นสื่อ ในไฟล์ PlaybackVideoFragment.kt
ให้ตรวจสอบว่า MediaSession
ได้รับการเริ่มต้นก่อนที่จะตั้งค่าโทเค็นเป็น MediaManager
import com.google.android.gms.cast.tv.CastReceiverContext
import com.google.android.gms.cast.tv.media.MediaManager
...
class PlaybackVideoFragment : VideoSupportFragment() {
private var castReceiverContext: CastReceiverContext? = null
...
private fun initializePlayer() {
if (mPlayer == null) {
...
mMediaSession = MediaSessionCompat(getContext(), LOG_TAG)
...
castReceiverContext = CastReceiverContext.getInstance()
if (castReceiverContext != null) {
val mediaManager: MediaManager = castReceiverContext!!.getMediaManager()
mediaManager.setSessionCompatToken(mMediaSession!!.getSessionToken())
}
}
}
}
เมื่อคุณเผยแพร่ MediaSession
เนื่องจากไม่มีการเล่น คุณควรตั้งค่าโทเค็น Null ใน MediaManager
ดังนี้
private fun releasePlayer() {
mMediaSession?.release()
castReceiverContext?.mediaManager?.setSessionCompatToken(null)
...
}
มาเรียกใช้แอปตัวอย่างกัน
คลิกปุ่ม Run เพื่อติดตั้งใช้งานแอปในอุปกรณ์ ATV, ปิดแอป แล้วกลับไปที่หน้าจอหลักของ ATV จากอุปกรณ์ที่ส่ง ให้คลิกปุ่มแคสต์ แล้วเลือกอุปกรณ์ ATV คุณจะเห็นแอป ATV เปิดขึ้นในอุปกรณ์ ATV และสถานะปุ่มแคสต์เชื่อมต่ออยู่
6. กำลังโหลดสื่อ
ระบบจะส่งคําสั่งโหลดผ่าน Intent ที่มีชื่อแพ็กเกจที่คุณกําหนดไว้ในคอนโซลนักพัฒนาซอฟต์แวร์ คุณต้องเพิ่มตัวกรอง Intent ที่กําหนดไว้ล่วงหน้าต่อไปนี้ในแอป Android TV เพื่อระบุกิจกรรมเป้าหมายที่จะรับ Intent นี้ ในไฟล์ AndroidManifest.xml
ให้เพิ่มตัวกรอง Intent ของโหลดลงใน PlayerActivity
<activity android:name="com.google.sample.cast.castconnect.PlaybackActivity"
android:launchMode="singleTask"
android:exported="true">
<intent-filter>
<action android:name="com.google.android.gms.cast.tv.action.LOAD"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
การจัดการคําขอโหลดใน Android TV
เมื่อมีการกำหนดค่าให้กิจกรรมรับ Intent ที่มีคำขอโหลด เราจึงจะต้องจัดการต่อไป
แอปเรียกเมธอดส่วนตัวชื่อ processIntent
เมื่อกิจกรรมเริ่มต้น เมธอดนี้มีตรรกะในการประมวลผล Intent ที่เข้ามา หากต้องการจัดการคําขอโหลด เราจะแก้ไขเมธอดนี้และส่ง Intent เพื่อประมวลผลเพิ่มเติมโดยการเรียกเมธอด onNewIntent
ของอินสแตนซ์ MediaManager
หาก MediaManager
ตรวจพบว่า Intent เป็นคำขอโหลด ระบบจะดึงออบเจ็กต์ MediaLoadRequestData
ออกจาก Intent และเรียกใช้ MediaLoadCommandCallback.onLoad()
แก้ไขเมธอด processIntent
ในไฟล์ PlaybackVideoFragment.kt
เพื่อจัดการ Intent ที่มีคำขอโหลด ดังนี้
fun processIntent(intent: Intent?) {
val mediaManager: MediaManager = CastReceiverContext.getInstance().getMediaManager()
// Pass intent to Cast SDK
if (mediaManager.onNewIntent(intent)) {
return
}
// Clears all overrides in the modifier.
mediaManager.getMediaStatusModifier().clear()
// If the SDK doesn't recognize the intent, handle the intent with your own logic.
...
}
ต่อไปเราจะขยายคลาสนามธรรม MediaLoadCommandCallback
ซึ่งจะลบล้างเมธอด onLoad()
ที่ MediaManager
เรียกใช้ เมธอดนี้จะรับข้อมูลของคำขอโหลดและแปลงเป็นออบเจ็กต์ Movie
เมื่อแปลงแล้ว ภาพยนตร์จะเล่นโดยโปรแกรมเล่นในเครื่อง จากนั้น MediaManager
จะอัปเดตด้วย MediaLoadRequest
และออกอากาศ MediaStatus
ไปยังผู้ส่งที่เชื่อมต่ออยู่ สร้างคลาสส่วนตัวที่ฝังอยู่ชื่อ MyMediaLoadCommandCallback
ในไฟล์ PlaybackVideoFragment.kt
import com.google.android.gms.cast.MediaLoadRequestData
import com.google.android.gms.cast.MediaInfo
import com.google.android.gms.cast.MediaMetadata
import com.google.android.gms.cast.MediaError
import com.google.android.gms.cast.tv.media.MediaException
import com.google.android.gms.cast.tv.media.MediaCommandCallback
import com.google.android.gms.cast.tv.media.QueueUpdateRequestData
import com.google.android.gms.cast.tv.media.MediaLoadCommandCallback
import com.google.android.gms.tasks.Task
import com.google.android.gms.tasks.Tasks
import android.widget.Toast
...
private inner class MyMediaLoadCommandCallback : MediaLoadCommandCallback() {
override fun onLoad(
senderId: String?, mediaLoadRequestData: MediaLoadRequestData): Task<MediaLoadRequestData> {
Toast.makeText(activity, "onLoad()", Toast.LENGTH_SHORT).show()
return if (mediaLoadRequestData == null) {
// Throw MediaException to indicate load failure.
Tasks.forException(MediaException(
MediaError.Builder()
.setDetailedErrorCode(MediaError.DetailedErrorCode.LOAD_FAILED)
.setReason(MediaError.ERROR_REASON_INVALID_REQUEST)
.build()))
} else Tasks.call {
play(convertLoadRequestToMovie(mediaLoadRequestData)!!)
// Update media metadata and state
val mediaManager = castReceiverContext!!.mediaManager
mediaManager.setDataFromLoad(mediaLoadRequestData)
mediaLoadRequestData
}
}
}
private fun convertLoadRequestToMovie(mediaLoadRequestData: MediaLoadRequestData?): Movie? {
if (mediaLoadRequestData == null) {
return null
}
val mediaInfo: MediaInfo = mediaLoadRequestData.getMediaInfo() ?: return null
var videoUrl: String = mediaInfo.getContentId()
if (mediaInfo.getContentUrl() != null) {
videoUrl = mediaInfo.getContentUrl()
}
val metadata: MediaMetadata = mediaInfo.getMetadata()
val movie = Movie()
movie.videoUrl = videoUrl
movie.title = metadata?.getString(MediaMetadata.KEY_TITLE)
movie.description = metadata?.getString(MediaMetadata.KEY_SUBTITLE)
if(metadata?.hasImages() == true) {
movie.cardImageUrl = metadata.images[0].url.toString()
}
return movie
}
เมื่อกำหนด Callback แล้ว เราจำเป็นต้องลงทะเบียน Callback กับ MediaManager
ต้องลงทะเบียน Callback ก่อนที่จะเรียกใช้ MediaManager.onNewIntent()
เพิ่ม setMediaLoadCommandCallback
เมื่อเริ่มต้นผู้เล่น
private fun initializePlayer() {
if (mPlayer == null) {
...
mMediaSession = MediaSessionCompat(getContext(), LOG_TAG)
...
castReceiverContext = CastReceiverContext.getInstance()
if (castReceiverContext != null) {
val mediaManager: MediaManager = castReceiverContext.getMediaManager()
mediaManager.setSessionCompatToken(mMediaSession.getSessionToken())
mediaManager.setMediaLoadCommandCallback(MyMediaLoadCommandCallback())
}
}
}
มาเรียกใช้แอปตัวอย่างกัน
คลิกปุ่ม Run เพื่อทำให้แอปใช้งานได้ในอุปกรณ์ ATV จากผู้ส่ง ให้คลิกปุ่ม "แคสต์" แล้วเลือกอุปกรณ์ ATV แอป ATV จะเปิดขึ้นในอุปกรณ์ ATV เลือกวิดีโอบนอุปกรณ์เคลื่อนที่ แล้ววิดีโอจะเริ่มเล่นบน ATV ตรวจสอบว่าคุณได้รับการแจ้งเตือนในโทรศัพท์ที่มีการควบคุมการเล่นหรือไม่ ลองใช้ตัวควบคุม เช่น หยุดชั่วคราว วิดีโอในอุปกรณ์ ATV ควรหยุดชั่วคราว
7. การรองรับคำสั่งควบคุมการแคสต์
ตอนนี้แอปพลิเคชันปัจจุบันรองรับคำสั่งพื้นฐานที่ใช้ได้กับเซสชันสื่อ เช่น เล่น หยุดชั่วคราว และกรอวิดีโอ อย่างไรก็ตาม คำสั่งการควบคุม Cast บางรายการจะใช้ไม่ได้ในเซสชันสื่อ คุณต้องลงทะเบียน MediaCommandCallback
เพื่อรองรับคำสั่งควบคุม Cast เหล่านั้น
เพิ่ม MyMediaCommandCallback
ลงในอินสแตนซ์ MediaManager
โดยใช้ setMediaCommandCallback
เมื่อเริ่มต้นโปรแกรมเล่น
private fun initializePlayer() {
...
castReceiverContext = CastReceiverContext.getInstance()
if (castReceiverContext != null) {
val mediaManager = castReceiverContext!!.mediaManager
...
mediaManager.setMediaCommandCallback(MyMediaCommandCallback())
}
}
สร้างคลาส MyMediaCommandCallback
เพื่อลบล้างเมธอด เช่น onQueueUpdate()
เพื่อรองรับคำสั่งควบคุม Cast ดังต่อไปนี้
private inner class MyMediaCommandCallback : MediaCommandCallback() {
override fun onQueueUpdate(
senderId: String?,
queueUpdateRequestData: QueueUpdateRequestData
): Task<Void> {
Toast.makeText(getActivity(), "onQueueUpdate()", Toast.LENGTH_SHORT).show()
// Queue Prev / Next
if (queueUpdateRequestData.getJump() != null) {
Toast.makeText(
getActivity(),
"onQueueUpdate(): Jump = " + queueUpdateRequestData.getJump(),
Toast.LENGTH_SHORT
).show()
}
return super.onQueueUpdate(senderId, queueUpdateRequestData)
}
}
8. การทำงานกับสถานะสื่อ
การแก้ไขสถานะสื่อ
Cast Connect จะได้รับสถานะสื่อพื้นฐานจากเซสชันสื่อ หากต้องการรองรับฟีเจอร์ขั้นสูง แอป Android TV สามารถระบุและลบล้างพร็อพเพอร์ตี้สถานะเพิ่มเติมผ่าน MediaStatusModifier
MediaStatusModifier
จะทำงานกับ MediaSession
ที่คุณตั้งค่าไว้ใน CastReceiverContext
เสมอ
ตัวอย่างเช่น หากต้องการระบุ setMediaCommandSupported
เมื่อทริกเกอร์การเรียกกลับ onLoad
ให้ทำดังนี้
import com.google.android.gms.cast.MediaStatus
...
private class MyMediaLoadCommandCallback : MediaLoadCommandCallback() {
fun onLoad(
senderId: String?,
mediaLoadRequestData: MediaLoadRequestData
): Task<MediaLoadRequestData> {
Toast.makeText(getActivity(), "onLoad()", Toast.LENGTH_SHORT).show()
...
return Tasks.call({
play(convertLoadRequestToMovie(mediaLoadRequestData)!!)
...
// Use MediaStatusModifier to provide additional information for Cast senders.
mediaManager.getMediaStatusModifier()
.setMediaCommandSupported(MediaStatus.COMMAND_QUEUE_NEXT, true)
.setIsPlayingAd(false)
mediaManager.broadcastMediaStatus()
// Return the resolved MediaLoadRequestData to indicate load success.
mediaLoadRequestData
})
}
}
การสกัดกั้น MediaStatus ก่อนส่ง
คุณสามารถระบุ MediaStatusWriter
ใน MediaManager
เพื่อทำการแก้ไขเพิ่มเติมใน MediaStatus
ก่อนที่จะออกอากาศไปยังผู้ส่งที่เชื่อมต่อได้ ซึ่งคล้ายกับ MessageInterceptor
ของ Web Receiver SDK
ตัวอย่างเช่น คุณสามารถตั้งค่าข้อมูลที่กําหนดเองใน MediaStatus
ก่อนส่งไปยังผู้ส่งที่ใช้อุปกรณ์เคลื่อนที่ได้ ดังนี้
import com.google.android.gms.cast.tv.media.MediaManager.MediaStatusInterceptor
import com.google.android.gms.cast.tv.media.MediaStatusWriter
import org.json.JSONObject
import org.json.JSONException
...
private fun initializePlayer() {
if (mPlayer == null) {
...
if (castReceiverContext != null) {
...
val mediaManager: MediaManager = castReceiverContext.getMediaManager()
...
// Use MediaStatusInterceptor to process the MediaStatus before sending out.
mediaManager.setMediaStatusInterceptor(
MediaStatusInterceptor { mediaStatusWriter: MediaStatusWriter ->
try {
mediaStatusWriter.setCustomData(JSONObject("{myData: 'CustomData'}"))
} catch (e: JSONException) {
Log.e(LOG_TAG,e.message,e);
}
})
}
}
}
9. ขอแสดงความยินดี
ตอนนี้คุณทราบวิธีเปิดใช้แอป Android TV โดยใช้ไลบรารี Cast Connect แล้ว
ดูรายละเอียดเพิ่มเติมได้ที่คู่มือนักพัฒนาแอป /cast/docs/android_tv_receiver