Phát trực tiếp

ExoPlayer phát hầu hết các luồng 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 thông tin 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 theo các khoảng thời gian đều đặn để phù hợp với thời gian thực hiện tại. Điều đó có nghĩa là vị trí phát sẽ luôn nằm ở đâ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ự khác biệt 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 chế độ 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ề quá trình 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ê bên dưới và hiển thị trong hình sau.

Cửa sổ trực tiếp

  • Player.isCurrentWindowLive cho biết liệu 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 liệu mục nội dung nghe nhìn đang phát có vẫn đ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 áp dụng cho các sự kiện phát trực tiếp không phải sự kiện 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ổ hiện tại đang hoạt động.
  • Player.getCurrentPosition trả về vị trí phát tương ứng với vị trí bắt đầu của cửa sổ phát 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 chế độ ghi đè do ứng dụng cung cấp đối với các tham số điều chỉnh độ lệch trực tiếp mục tiêu và điều chỉnh chênh lệch trực tiếp.
  • Player.getCurrentTimeline trả về cấu trúc nội dung đa phương tiệ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.getCurrentMediaItemIndexTimeline.getWindow. Trong Window:
    • Window.liveConfiguration chứa các tham số điều chỉnh độ lệch trực tiếp và độ lệch trực tiếp mục tiêu. Các giá trị này dựa trên thông tin trong nội dung nghe nhìn và mọi giá trị ghi đè do ứng dụng cung cấp được đặt trong MediaItem.liveConfiguration.
    • Window.windowStartTimeMs là thời gian kể từ thời gian bắt đầu của hệ thống 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 hệ thống Unix của thời gian thực hiện tại. Giá trị này có thể được điều chỉnh bằng độ lệch đồng hồ đã biết giữa máy chủ và ứng dụng khách.
    • Window.getDefaultPositionMs là vị trí trong cửa sổ phát trực tiếp mà 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ể tua đến vị trí bất kỳ trong cửa sổ phát 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. Trình phát sẽ cố gắng giữ nguyên độ lệch trực tiếp như vị trí đã tua đến sau khi tua.

Cửa sổ phát trực tiếp cũng có vị trí mặc định mà tại đó quá trình phát sẽ bắt đầu. Vị trí này thường nằm gần cạnh sống. Bạn có thể tìm đến 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 giao diện người dùng mặc định của ExoPlayer cho biết thời lượng của cửa sổ phát 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ẽ có vẻ 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ân nhánh PlayerControlView và sửa đổi để 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ố thông số để kiểm soát độ lệch của vị trí phát từ cạnh phát 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 lấy giá trị cho các tham số này từ 3 vị trí, theo thứ tự ưu tiên giảm dần (giá trị đầu tiên được tìm thấy sẽ được sử dụng):

  • Trên mỗi MediaItem giá trị được truyền đến MediaItem.Builder.setLiveConfiguration.
  • Giá trị mặc định chung được đặt trên DefaultMediaSourceFactory.
  • 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: Độ lệch 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 khi phát nếu có thể.
  • minOffsetMs: Độ lệch trực tiếp tối thiểu được phép. Ngay cả khi điều chỉnh độ trễ theo điều kiện mạng hiện tại, trình phát sẽ không cố gắng giảm xuống dưới độ trễ này trong khi phát.
  • maxOffsetMs: Độ lệch trực tiếp tối đa được phép. Ngay cả khi điều chỉnh độ lệch theo điều kiện mạng hiện tại, trình phát sẽ không cố gắng vượt quá độ lệch này trong khi 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 đến độ 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 độ trễ phát trực tiếp mục tiêu.

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

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

Nếu không muốn tự động điều chỉnh tốc độ phát, 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 các 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 thành các giá trị khác với 1.0f. Vui lòng 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 độ, LivePlaybackSpeedControl sẽ xác định những điều chỉnh được thực hiện. Bạn có thể triển khai một LivePlaybackSpeedControl tuỳ chỉnh hoặc tuỳ chỉnh cách 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 thông 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 hoặc MediaItem do ứng dụng cung cấp đều không xác định giới hạn.
  • proportionalControlFactor: Kiểm soát độ mượt mà của việc điều chỉnh tốc độ. Giá trị cao sẽ giúp việc điều chỉnh trở nên đột ngột và phản ứng nhanh hơn, nhưng cũng có nhiều khả năng sẽ nghe được. Giá trị nhỏ hơn sẽ giúp quá trình chuyển đổi giữa các tốc độ diễn ra mượt mà hơn, 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 mục tiêu bất cứ khi nào xảy ra tình trạng phải tải lại để tiến hành 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 mũ được 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 đang được lưu vào vùng đệm. Giá trị rất gần với 1 có nghĩa là giá trị ước tính sẽ thận trọng hơn và có thể mất nhiều thời gian hơn để điều chỉnh theo tình trạng 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ới nguy cơ cao hơn là phải lưu vào bộ đệm lại.

BehindLiveWindowException và ERROR_CODE_BEHIND_LIVE_WINDOW

Vị trí phát có thể bị trễ so với cửa sổ phát trực tiếp, ví dụ: nếu trình phát bị tạm dừng hoặc lưu vào bộ nhớ đệm trong một khoảng thời gian đủ dài. Nếu điều này xảy ra, quá trình phát sẽ không thành công và một ngoại lệ có mã lỗi ERROR_CODE_BEHIND_LIVE_WINDOW sẽ được báo cáo qua Player.Listener.onPlayerError. Mã ứng dụng có thể 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
  }
}