ExoPlayer เล่นสตรีมแบบสดที่ปรับเปลี่ยนให้เหมาะกับผู้ใช้มากที่สุดได้ทันทีตั้งแต่แกะกล่องโดยไม่มีอะไรพิเศษ การกำหนดค่า ดูรายละเอียดเพิ่มเติมในหน้ารูปแบบที่รองรับ
สตรีมแบบสดแบบปรับอัตโนมัติมีหน้าต่างสื่อที่พร้อมใช้งานที่อัปเดตใน ช่วงเวลาปกติที่จะเคลื่อนไหวตามเรียลไทม์ปัจจุบัน ซึ่งหมายความว่าการเล่น จะอยู่ไหนสักแห่งในหน้าต่างนี้เสมอ ซึ่งในกรณีส่วนใหญ่ แบบเรียลไทม์ในปัจจุบันที่มีการผลิตสตรีมอยู่ ความแตกต่างระหว่าง เรียลไทม์ปัจจุบันและตำแหน่งการเล่นเรียกว่าออฟเซ็ตแบบเรียลไทม์
การตรวจหาและการตรวจสอบการเล่นแบบสด
ทุกครั้งที่อัปเดตกรอบเวลาที่เผยแพร่อยู่ ระบบจะลงทะเบียนอินสแตนซ์ Player.Listener
รายการ
จะได้รับเหตุการณ์ onTimelineChanged
คุณสามารถดูรายละเอียดเกี่ยวกับ
การเล่นสตรีมแบบสดในปัจจุบันโดยค้นหา Player
และ Timeline.Window
ต่างๆ
วิธีการตามที่ระบุไว้ด้านล่างและแสดงในรูปต่อไปนี้
Player.isCurrentWindowLive
ระบุว่าสื่อที่เล่นอยู่ในขณะนี้หรือไม่ คือสตรีมแบบสด ค่านี้ยังคงเป็นจริง แม้ว่าสตรีมแบบสดจะมี สิ้นสุดแล้วPlayer.isCurrentWindowDynamic
ระบุว่าสื่อที่เล่นอยู่ในขณะนี้หรือไม่ กำลังอัปเดตรายการ ซึ่งมักจะเป็นเช่นนี้สำหรับสตรีมแบบสดที่ ยังไม่สิ้นสุด โปรดทราบว่าการตั้งค่าสถานะจะเป็นจริงสำหรับสตรีมที่ไม่ใช่สตรีมแบบสดในบางกรณี กรณีPlayer.getCurrentLiveOffset
แสดงค่าออฟเซ็ตระหว่างค่าจริงปัจจุบัน เวลาและตำแหน่งการเล่น (หากมี)Player.getDuration
แสดงความยาวของกรอบเวลาที่เผยแพร่อยู่ในขณะนั้นPlayer.getCurrentPosition
คืนตำแหน่งการเล่นที่สัมพันธ์กับ ที่เริ่มต้นหน้าต่างแบบสดPlayer.getCurrentMediaItem
จะแสดงรายการสื่อปัจจุบัน โดยที่MediaItem.liveConfiguration
มีการลบล้างที่แอปให้ไว้สำหรับเป้าหมาย พารามิเตอร์การปรับออฟเซ็ตแบบเรียลไทม์และพารามิเตอร์การปรับออฟเซ็ตแบบเรียลไทม์Player.getCurrentTimeline
จะแสดงผลโครงสร้างสื่อปัจจุบันในTimeline
สามารถดึงข้อมูลTimeline.Window
ปัจจุบันได้จากTimeline
โดยใช้Player.getCurrentWindowIndex
และTimeline.getWindow
ภายในWindow
:Window.liveConfiguration
มีออฟเซ็ตแบบเรียลไทม์เป้าหมายและออฟเซ็ตแบบเรียลไทม์ พารามิเตอร์การปรับ ค่าเหล่านี้ขึ้นอยู่กับข้อมูลในสื่อ และการลบล้างที่แอปมีให้ที่ตั้งค่าไว้ในMediaItem.liveConfiguration
Window.windowStartTimeMs
เป็นเวลานับตั้งแต่ Unix Epoch ซึ่งมีเหตุการณ์ ช่วงถ่ายทอดสดเริ่มต้นWindow.getCurrentUnixTimeMs
เป็นเวลานับตั้งแต่ Unix Epoch ของ แบบเรียลไทม์ในปัจจุบัน ค่านี้อาจแก้ไขได้โดยความแตกต่างของนาฬิกาที่รู้จัก ระหว่างเซิร์ฟเวอร์และไคลเอ็นต์Window.getDefaultPositionMs
คือตำแหน่งในหน้าต่างถ่ายทอดสดที่ โปรแกรมเล่นจะเริ่มเล่นโดยค่าเริ่มต้น
การค้นหาในสตรีมแบบสด
คุณสามารถค้นหาไปยังที่ใดก็ได้ภายในกรอบเวลาสดโดยใช้ Player.seekTo
การค้นหา
ตำแหน่งที่ผ่านไปจะสัมพันธ์กับจุดเริ่มต้นของหน้าต่างที่เผยแพร่อยู่ ตัวอย่างเช่น
seekTo(0)
จะกรอไปยังจุดเริ่มต้นของหน้าต่างที่เผยแพร่อยู่ โปรแกรมเล่นจะพยายาม
ให้ออฟเซ็ตแบบเรียลไทม์เหมือนกันกับตำแหน่งสำหรับ "ค้นหา" หลังการกรอ
หน้าต่างถ่ายทอดสดยังมีตำแหน่งเริ่มต้นที่ควรเล่นวิดีโอ
เริ่ม ตำแหน่งนี้มักจะอยู่ใกล้ขอบที่มีการใช้งานจริง คุณสามารถกรอวิดีโอ
ไปยังตำแหน่งเริ่มต้นโดยเรียกใช้ Player.seekToDefaultPosition
UI การเล่นแบบสด
คอมโพเนนต์ UI เริ่มต้นของ ExoPlayer จะแสดงระยะเวลาของกรอบเวลาที่เผยแพร่อยู่และ
ตำแหน่งการเล่นปัจจุบันภายในตำแหน่งนั้น ซึ่งหมายความว่าตำแหน่งจะปรากฏเป็น
ย้อนกลับเมื่อมีการอัปเดตกรอบเวลาในการถ่ายทอดสด หากต้องการ
ตัวอย่างเช่น แสดงเวลา Unix หรือออฟเซ็ตแบบเรียลไทม์ในปัจจุบัน คุณสามารถ
แยก PlayerControlView
และแก้ไขให้เหมาะกับความต้องการของคุณ
การกำหนดค่าพารามิเตอร์การเล่นสด
ExoPlayer ใช้พารามิเตอร์บางอย่างเพื่อควบคุมออฟเซ็ตของตำแหน่งการเล่น จากขอบสตรีมแบบสด และช่วงความเร็วในการเล่นที่สามารถนำไปใช้เพื่อ ให้ปรับออฟเซ็ตนี้
ExoPlayer จะได้รับค่าของพารามิเตอร์เหล่านี้จาก 3 ตำแหน่งจากมากไปน้อย ลำดับความสำคัญ (ใช้ค่าแรกที่พบ):
- ตาม
MediaItem
ค่าที่ส่งไปยังMediaItem.Builder.setLiveConfiguration
- ค่าเริ่มต้นส่วนกลางที่ตั้งค่าใน
DefaultMediaSourceFactory
- ค่าจะอ่านจากสื่อโดยตรง
Kotlin
// Global settings. val player = ExoPlayer.Builder(context) .setMediaSourceFactory(DefaultMediaSourceFactory(context).setLiveTargetOffsetMs(5000)) .build() // Per MediaItem settings. val mediaItem = MediaItem.Builder() .setUri(mediaUri) .setLiveConfiguration( MediaItem.LiveConfiguration.Builder().setMaxPlaybackSpeed(1.02f).build() ) .build() player.setMediaItem(mediaItem)
Java
// Global settings. ExoPlayer player = new ExoPlayer.Builder(context) .setMediaSourceFactory( new DefaultMediaSourceFactory(context).setLiveTargetOffsetMs(5000)) .build(); // Per MediaItem settings. MediaItem mediaItem = new MediaItem.Builder() .setUri(mediaUri) .setLiveConfiguration( new MediaItem.LiveConfiguration.Builder().setMaxPlaybackSpeed(1.02f).build()) .build(); player.setMediaItem(mediaItem);
ค่าของการกำหนดค่าที่ใช้ได้มีดังนี้
targetOffsetMs
: ออฟเซ็ตแบบเรียลไทม์เป้าหมาย โปรแกรมเล่นจะพยายาม ใกล้กับออฟเซ็ตแบบเรียลไทม์นี้ระหว่างการเล่นหากเป็นไปได้minOffsetMs
: ออฟเซ็ตแบบเรียลไทม์ขั้นต่ำที่อนุญาต แม้ในขณะที่กำลังปรับ หักลบกับสภาพเครือข่ายปัจจุบัน โปรแกรมเล่นจะไม่พยายามไปที่ระดับล่าง ของออฟเซ็ตนี้ระหว่างการเล่นmaxOffsetMs
: ออฟเซ็ตแบบเรียลไทม์สูงสุดที่อนุญาต แม้ในขณะที่กำลังปรับ ชดเชยสภาพเครือข่ายปัจจุบัน โปรแกรมเล่นจะไม่พยายามทำให้อยู่เหนือ ของออฟเซ็ตนี้ระหว่างการเล่นminPlaybackSpeed
: ความเร็วขั้นต่ำในการเล่นที่โปรแกรมเล่นใช้ในการย้อนกลับได้ เมื่อพยายามไปให้ถึงออฟเซ็ตแบบสดเป้าหมายmaxPlaybackSpeed
: ความเร็วในการเล่นสูงสุดที่โปรแกรมเล่นใช้ติดตามได้ เมื่อพยายามไปให้ถึงออฟเซ็ตแบบสดเป้าหมาย
การปรับความเร็วในการเล่น
เมื่อเล่นสตรีมแบบสดที่มีเวลาในการตอบสนองต่ำ ExoPlayer จะปรับออฟเซ็ตการถ่ายทอดสดตาม การเปลี่ยนความเร็วในการเล่นเล็กน้อย ผู้เล่นจะพยายามจับคู่ให้ตรงเป้าหมาย ออฟเซ็ตแบบสดที่สื่อหรือแอปกำหนด แต่จะพยายามตอบสนองต่อ การเปลี่ยนเงื่อนไขของเครือข่าย เช่น หากเกิดบัฟเฟอร์ซ้ำระหว่างการเล่น โปรแกรมเล่นจะชะลอการเล่นลงเล็กน้อยเพื่อออกห่างจากการถ่ายทอดสด หากเครือข่ายเสถียรพอที่จะรองรับการเล่นในระยะใกล้ ขอบสดอีกครั้ง โปรแกรมเล่นจะเร่งการเล่นเพื่อย้อนกลับไปยัง การชดเชยแบบเรียลไทม์เป้าหมาย
หากไม่ต้องการปรับความเร็วในการเล่นอัตโนมัติ ก็สามารถปิดใช้ได้โดย
กำลังตั้งค่าพร็อพเพอร์ตี้ minPlaybackSpeed
และ maxPlaybackSpeed
เป็น 1.0f
ในทำนองเดียวกัน คุณเปิดใช้สตรีมแบบสดที่มีเวลาในการตอบสนองต่ำได้โดยการตั้งค่า
เป็นค่าอื่นที่ไม่ใช่ 1.0f
อย่างชัดเจน โปรดดู
ส่วนการกำหนดค่าด้านบนสำหรับ
รายละเอียดเพิ่มเติมเกี่ยวกับวิธีการตั้งค่าคุณสมบัติเหล่านี้
การปรับแต่งอัลกอริทึมการปรับความเร็วในการเล่น
หากเปิดใช้การปรับความเร็ว LivePlaybackSpeedControl
จะกำหนดสิ่งต่อไปนี้
ที่มีการปรับค่าใช้จ่าย คุณสามารถใช้
LivePlaybackSpeedControl
หรือเพื่อปรับแต่งการใช้งานเริ่มต้น ซึ่งก็คือ
DefaultLivePlaybackSpeedControl
ในทั้ง 2 กรณี อินสแตนซ์จะตั้งค่าได้เมื่อ
การสร้างโปรแกรมเล่น:
Kotlin
val player = ExoPlayer.Builder(context) .setLivePlaybackSpeedControl( DefaultLivePlaybackSpeedControl.Builder().setFallbackMaxPlaybackSpeed(1.04f).build() ) .build()
Java
ExoPlayer player = new ExoPlayer.Builder(context) .setLivePlaybackSpeedControl( new DefaultLivePlaybackSpeedControl.Builder() .setFallbackMaxPlaybackSpeed(1.04f) .build()) .build();
พารามิเตอร์การปรับแต่งที่เกี่ยวข้องของ DefaultLivePlaybackSpeedControl
ได้แก่
fallbackMinPlaybackSpeed
และfallbackMaxPlaybackSpeed
: ค่าต่ำสุดและ ความเร็วในการเล่นสูงสุดที่สามารถใช้ปรับได้หากไม่มีทั้งสื่อ และMediaItem
ที่ได้จากแอปจะเป็นตัวกำหนดขีดจำกัดproportionalControlFactor
: ควบคุมความลื่นไหลของการปรับความเร็ว ต ค่าที่สูงจะทำให้การปรับเปลี่ยนนั้นกระทันหันและตอบสนองได้ไวขึ้น และมีแนวโน้มมากขึ้นที่จะ ได้ฟังเสียง ค่าที่น้อยกว่าจะทำให้การเปลี่ยนความเร็วเป็นไปอย่างราบรื่นมากขึ้น แต่ทำงานช้าลงtargetLiveOffsetIncrementOnRebufferMs
: ระบบจะเพิ่มค่านี้ลงในเป้าหมาย สดใหม่ทุกครั้งที่เกิดการบัฟเฟอร์ซ้ำเพื่อดำเนินการด้วยความระมัดระวังมากขึ้น คุณปิดฟีเจอร์นี้ได้โดยตั้งค่าเป็น 0minPossibleLiveOffsetSmoothingFactor
: ปัจจัยการปรับให้เรียบแบบเอ็กซ์โปเนนเชียลที่ จะใช้เพื่อติดตามค่าชดเชยขั้นต่ำที่เป็นไปได้สำหรับปัจจุบัน โดยพิจารณาจาก สื่อที่บัฟเฟอร์ ค่าที่ใกล้ 1 มากหมายความว่าค่าประมาณมีค่ามากกว่า อย่างระมัดระวังและอาจใช้เวลานานขึ้นในการปรับสภาพเครือข่ายให้ดีขึ้น ในขณะที่ ค่าที่ต่ำกว่าหมายความว่าการประมาณการจะปรับเร็วขึ้นและมีความเสี่ยงมากขึ้น เจอการบัฟเฟอร์ซ้ำ
BehindLiveWindowException และ ERROR_CODE_BEHIND_LIVE_WINDOW
ตำแหน่งการเล่นอาจอยู่หลังหน้าต่างถ่ายทอดสด ตัวอย่างเช่น หากโปรแกรมเล่น
หยุดชั่วคราวหรือบัฟเฟอร์เป็นระยะเวลานานพอ หากเกิดกรณีเช่นนี้
การเล่นจะล้มเหลวและข้อยกเว้นที่มีรหัสข้อผิดพลาด
ERROR_CODE_BEHIND_LIVE_WINDOW
จะได้รับการรายงานผ่าน
Player.Listener.onPlayerError
โค้ดของแอปพลิเคชันอาจต้องจัดการ
โดยเล่นต่อที่ตำแหน่งเริ่มต้น กิจกรรมโปรแกรมเล่นของ
แอปเดโมยกตัวอย่างวิธีการนี้
Kotlin
override fun onPlayerError(error: PlaybackException) { if (error.errorCode == PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW) { // Re-initialize player at the live edge. player.seekToDefaultPosition() player.prepare() } else { // Handle other errors } }
Java
@Override public void onPlayerError(PlaybackException error) { if (error.errorCode == PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW) { // Re-initialize player at the live edge. player.seekToDefaultPosition(); player.prepare(); } else { // Handle other errors } }