สตรีมมิงแบบสด

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.getCurrentMediaItemIndex และ 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 หรือออฟเซ็ตสดปัจจุบัน คุณสามารถ Fork 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: ค่านี้จะเพิ่มลงในออฟเซ็ตสดเป้าหมาย ทุกครั้งที่เกิดการบัฟเฟอร์ใหม่ เพื่อให้ดำเนินการอย่างระมัดระวังมากขึ้น คุณปิดใช้ฟีเจอร์นี้ได้โดยตั้งค่าเป็น 0
  • minPossibleLiveOffsetSmoothingFactor: ปัจจัยการปรับให้เรียบแบบเอ็กซ์โพเนนเชียลที่ใช้เพื่อติดตามออฟเซ็ตไลฟ์สดที่เป็นไปได้ขั้นต่ำตามสื่อที่บัฟเฟอร์อยู่ในปัจจุบัน ค่าที่ใกล้เคียงกับ 1 มากหมายความว่าการประมาณจะระมัดระวังมากขึ้นและอาจใช้เวลานานขึ้นในการปรับให้เข้ากับสภาพเครือข่ายที่ดีขึ้น ในขณะที่ค่าที่ต่ำกว่าหมายความว่าการประมาณจะปรับเร็วขึ้นโดยมีความเสี่ยงสูงขึ้นที่จะเกิดการบัฟเฟอร์ซ้ำ

BehindLiveWindowException และ ERROR_CODE_BEHIND_LIVE_WINDOW

ตำแหน่งการเล่นอาจช้ากว่าหน้าต่างสด เช่น หากผู้เล่น หยุดชั่วคราวหรือบัฟเฟอร์เป็นระยะเวลานานพอ หากเกิดกรณีเช่นนี้ การเล่นจะล้มเหลวและระบบจะรายงานข้อยกเว้นพร้อมรหัสข้อผิดพลาด ERROR_CODE_BEHIND_LIVE_WINDOW ผ่าน Player.Listener.onPlayerError โค้ดแอปพลิเคชันอาจต้องการจัดการข้อผิดพลาดดังกล่าว โดยการเล่นต่อที่ตำแหน่งเริ่มต้น PlayerActivity ของ แอปเดโมแสดงให้เห็นถึงแนวทางนี้

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
  }
}