Phát trực tiếp

ExoPlayer phát hầu hết các sự kiện phát trực tiếp thích ứng ngay từ đầu mà không cần bất kỳ cấu hình đặc biệt nào. Hãy xem trang Định dạng được hỗ trợ để biết thêm chi tiết.

Sự kiện phát trực tiếp thích ứng cung cấp một cửa sổ nội dung nghe nhìn có sẵn được cập nhật định kỳ để thay đổi theo thời gian thực hiện tại. Điều đó có nghĩa là vị trí phát sẽ luôn ở đâu đó trong cửa sổ này, trong hầu hết các trường hợp gần với thời gian thực hiện tại mà luồng đang được tạo. Sự chênh lệch giữa thời gian thực hiện tại và vị trí phát được gọi là độ lệch trực tiếp.

Phát hiện và giám sát các lượt phát trực tiếp

Mỗi khi một cửa sổ trực tiếp được cập nhật, các thực thể Player.Listener đã đăng ký sẽ nhận được một sự kiện onTimelineChanged. Bạn có thể truy xuất thông tin chi tiết về chế độ phát trực tiếp hiện tại bằng cách truy vấn nhiều phương thức PlayerTimeline.Window, như được liệt kê dưới đây và được minh hoạ trong hình sau.

Cửa sổ trực tiếp

  • Player.isCurrentWindowLive cho biết mục nội dung nghe nhìn đang phát có phải là sự kiện phát trực tiếp hay không. Giá trị này vẫn đúng ngay cả khi sự kiện phát trực tiếp đã kết thúc.
  • Player.isCurrentWindowDynamic cho biết mục nội dung nghe nhìn đang phát có đang được cập nhật hay không. Điều này thường đúng với các sự kiện phát trực tiếp chưa kết thúc. Xin lưu ý rằng cờ này cũng đúng với các sự kiện không phát trực tiếp trong một số trường hợp.
  • Player.getCurrentLiveOffset trả về độ lệch giữa thời gian thực hiện tại và vị trí phát (nếu có).
  • Player.getDuration trả về độ dài của cửa sổ trực tiếp hiện tại.
  • Player.getCurrentPosition trả về vị trí phát tương ứng với thời điểm bắt đầu cửa sổ trực tiếp.
  • Player.getCurrentMediaItem trả về mục nội dung đa phương tiện hiện tại, trong đó MediaItem.liveConfiguration chứa các cơ chế ghi đè do ứng dụng cung cấp cho các tham số điều chỉnh mức chênh lệch trực tiếp và mức chênh lệch trực tiếp mục tiêu.
  • Player.getCurrentTimeline trả về cấu trúc nội dung nghe nhìn hiện tại trong Timeline. Bạn có thể truy xuất Timeline.Window hiện tại từ Timeline bằng cách sử dụng Player.getCurrentWindowIndexTimeline.getWindow. Trong Window:
    • Window.liveConfiguration chứa các thông số điều chỉnh độ lệch cho sự kiện phát trực tiếp mục tiêu và thông số điều chỉnh độ lệch cho sự kiện phát trực tiếp. Các giá trị này dựa trên thông tin trong nội dung nghe nhìn và mọi chế độ ghi đè do ứng dụng cung cấp được đặt trong MediaItem.liveConfiguration.
    • Window.windowStartTimeMs là thời gian kể từ thời điểm Unix mà cửa sổ trực tiếp bắt đầu.
    • Window.getCurrentUnixTimeMs là thời gian kể từ Thời gian bắt đầu của Unix theo thời gian thực hiện tại. Giá trị này có thể được sửa bằng sự chênh lệch về xung nhịp đã biết giữa máy chủ và ứng dụng.
    • Window.getDefaultPositionMs là vị trí trong cửa sổ trực tiếp mà tại đó trình phát sẽ bắt đầu phát theo mặc định.

Tìm kiếm trong sự kiện phát trực tiếp

Bạn có thể tìm đến vị trí bất kỳ trong cửa sổ trực tiếp bằng Player.seekTo. Vị trí tìm kiếm đã truyền tương ứng với thời điểm bắt đầu cửa sổ trực tiếp. Ví dụ: seekTo(0) sẽ tìm cách bắt đầu cửa sổ trực tiếp. Người chơi sẽ cố gắng duy trì cùng một độ lệch trực tiếp như vị trí cần tìm sau khi tua.

Cửa sổ trực tiếp cũng có vị trí mặc định là nơi sẽ bắt đầu phát. Vị trí này thường ở một nơi nào đó gần cạnh trực tiếp. Bạn có thể tìm vị trí mặc định bằng cách gọi Player.seekToDefaultPosition.

Giao diện người dùng phát trực tiếp

Các thành phần trên giao diện người dùng mặc định của ExoPlayer cho thấy thời lượng của cửa sổ trực tiếp và vị trí phát hiện tại trong cửa sổ đó. Điều này có nghĩa là vị trí sẽ dường như nhảy lùi mỗi khi cửa sổ trực tiếp được cập nhật. Nếu cần hành vi khác, chẳng hạn như hiển thị thời gian Unix hoặc độ lệch trực tiếp hiện tại, bạn có thể phát triển PlayerControlView và sửa đổi cho phù hợp với nhu cầu của mình.

Định cấu hình các thông số phát trực tiếp

ExoPlayer sử dụng một số tham số để điều chỉnh độ lệch của vị trí phát so với cạnh trực tiếp và phạm vi tốc độ phát có thể dùng để điều chỉnh độ lệch này.

ExoPlayer nhận giá trị cho các tham số này từ ba vị trí, theo thứ tự ưu tiên giảm dần (sử dụng giá trị đầu tiên tìm thấy):

  • Trên mỗi MediaItem giá trị được chuyển đến MediaItem.Builder.setLiveConfiguration.
  • Giá trị mặc định chung được đặt trên DefaultMediaSourceFactory.
  • Các giá trị được đọc trực tiếp từ nội dung nghe nhìn.

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);

Các giá trị cấu hình hiện có là:

  • targetOffsetMs: Mức bù trừ cho sự kiện phát trực tiếp mục tiêu. Trình phát sẽ cố gắng đạt được độ lệch trực tiếp này trong quá trình phát nếu có thể.
  • minOffsetMs: Mức chênh lệch trực tiếp tối thiểu cho phép. Ngay cả khi điều chỉnh mức chênh lệch theo điều kiện mạng hiện tại, trình phát sẽ không tìm cách giảm xuống thấp hơn mức chênh lệch này trong quá trình phát.
  • maxOffsetMs: Mức chênh lệch trực tiếp tối đa cho phép. Ngay cả khi điều chỉnh mức chênh lệch theo điều kiện mạng hiện tại, trình phát sẽ không tìm cách vượt quá mức chênh lệch này trong quá trình phát.
  • minPlaybackSpeed: Tốc độ phát tối thiểu mà trình phát có thể sử dụng để quay lại khi cố gắng đạt được độ lệch trực tiếp mục tiêu.
  • maxPlaybackSpeed: Tốc độ phát tối đa mà trình phát có thể sử dụng để bắt kịp khi cố gắng đạt được độ lệch trực tiếp mục tiêu.

Điều chỉnh tốc độ phát

Khi phát một sự kiện phát trực tiếp có độ trễ thấp, ExoPlayer sẽ điều chỉnh độ lệch trực tiếp bằng cách thay đổi một chút tốc độ phát. Người chơi sẽ cố gắng khớp với độ lệch trực tiếp mục tiêu do phương tiện hoặc ứng dụng cung cấp, nhưng cũng sẽ cố gắng phản ứng với việc thay đổi điều kiện mạng. Ví dụ: nếu xảy ra tình trạng đệm lại trong khi phát, trình phát sẽ giảm tốc độ phát một chút để ra xa cạnh trực tiếp. Sau đó, nếu mạng trở nên đủ ổn định để hỗ trợ việc phát gần cạnh trực tiếp hơn nữa, thì trình phát sẽ tăng tốc độ phát để trở về độ lệch trực tiếp mục tiêu.

Nếu không muốn điều chỉnh tốc độ phát tự động, bạn có thể tắt tính năng này bằng cách đặt thuộc tính minPlaybackSpeedmaxPlaybackSpeed thành 1.0f. Tương tự, bạn có thể bật tính năng này cho sự kiện phát trực tiếp không có độ trễ thấp bằng cách đặt các giá trị này một cách rõ ràng thành các giá trị không phải là 1.0f. Xem phần cấu hình ở trên để biết thêm thông tin chi tiết về cách đặt các thuộc tính này.

Tuỳ chỉnh thuật toán điều chỉnh tốc độ phát

Nếu bạn bật tính năng điều chỉnh tốc độ, thì LivePlaybackSpeedControl sẽ xác định những mức điều chỉnh nào được thực hiện. Bạn cũng có thể triển khai LivePlaybackSpeedControl tuỳ chỉnh hoặc tuỳ chỉnh phương thức triển khai mặc định, đó là DefaultLivePlaybackSpeedControl. Trong cả hai trường hợp, bạn có thể đặt một thực thể khi tạo trình phát:

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();

Các tham số tuỳ chỉnh có liên quan của DefaultLivePlaybackSpeedControl là:

  • fallbackMinPlaybackSpeedfallbackMaxPlaybackSpeed: Tốc độ phát tối thiểu và tối đa có thể dùng để điều chỉnh nếu cả nội dung nghe nhìn và MediaItem do ứng dụng cung cấp đều không xác định các giới hạn.
  • proportionalControlFactor: Kiểm soát độ mượt mà quá trình điều chỉnh tốc độ. Giá trị cao sẽ khiến các hoạt động điều chỉnh đột ngột và phản ứng hơn, nhưng cũng có nhiều khả năng nghe thấy hơn. Giá trị nhỏ hơn dẫn đến quá trình chuyển đổi mượt mà hơn giữa các tốc độ, nhưng tốc độ sẽ chậm hơn.
  • targetLiveOffsetIncrementOnRebufferMs: Giá trị này được thêm vào độ lệch trực tiếp của mục tiêu mỗi khi xảy ra quá trình đệm lại để tiến hành một cách thận trọng hơn. Bạn có thể tắt tính năng này bằng cách đặt giá trị thành 0.
  • minPossibleLiveOffsetSmoothingFactor: Hệ số làm mượt hàm mũ dùng để theo dõi độ lệch trực tiếp tối thiểu có thể có dựa trên nội dung nghe nhìn hiện được lưu vào bộ đệm. Giá trị rất gần 1 có nghĩa là việc ước tính trở nên thận trọng hơn và có thể mất nhiều thời gian hơn để điều chỉnh cho phù hợp với điều kiện mạng được cải thiện, trong khi giá trị thấp hơn có nghĩa là giá trị ước tính sẽ điều chỉnh nhanh hơn và có nguy cơ cao hơn gặp phải bộ đệm lại.

BehindLiveWindowException và LỖI_CODE_BEHIND_LIVE_WINDOW

Vị trí phát có thể nằm sau cửa sổ trực tiếp, chẳng hạn như khi trình phát bị tạm dừng hoặc lưu vào bộ đệm trong một khoảng thời gian đủ dài. Nếu điều này xảy ra, thì quá trình phát sẽ không thành công và một trường hợp ngoại lệ có mã lỗi ERROR_CODE_BEHIND_LIVE_WINDOW sẽ được báo cáo qua Player.Listener.onPlayerError. Mã xử lý ứng dụng nên xử lý các lỗi như vậy bằng cách tiếp tục phát ở vị trí mặc định. PlayerActivity của ứng dụng minh hoạ minh hoạ phương pháp này.

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