Analytics

ExoPlayer hỗ trợ nhiều nhu cầu phân tích quá trình phát. Cuối cùng, phân tích liên quan đến việc thu thập, diễn giải, tổng hợp và tóm tắt dữ liệu khỏi các lượt phát. Bạn có thể dùng dữ liệu này trên thiết bị, ví dụ: ghi nhật ký, gỡ lỗi hoặc để thông báo các quyết định phát lại trong tương lai—hoặc báo cáo cho máy chủ để theo dõi lượt phát trên tất cả thiết bị.

Hệ thống phân tích thường cần thu thập sự kiện trước rồi mới xử lý các sự kiện đó để chúng có ý nghĩa:

  • Thu thập sự kiện: Bạn có thể thực hiện việc này bằng cách đăng ký AnalyticsListener trên ExoPlayer thực thể. Trình nghe số liệu phân tích đã đăng ký sẽ nhận được các sự kiện xảy ra trong khoảng thời gian mức sử dụng trình phát. Mỗi sự kiện được liên kết với nội dung nghe nhìn tương ứng trong danh sách phát, cũng như vị trí phát và siêu dữ liệu về dấu thời gian.
  • Xử lý sự kiện: Một số hệ thống phân tích tải sự kiện thô lên máy chủ, trong đó chứa tất cả các sự kiện quá trình xử lý được thực hiện ở phía máy chủ. Bạn cũng có thể xử lý các sự kiện trên thiết bị của bạn và làm như vậy có thể đơn giản hơn hoặc giảm lượng thông tin mà cần được tải lên. ExoPlayer cung cấp PlaybackStatsListener cho phép bạn thực hiện các bước xử lý sau:
    1. Diễn giải sự kiện: Để hữu ích cho mục đích phân tích, các sự kiện cần phải có cần được diễn giải trong ngữ cảnh của một lần phát. Ví dụ: dữ liệu thô sự kiện thay đổi trạng thái của người chơi thành STATE_BUFFERING có thể tương ứng với lưu vào bộ đệm ban đầu, tạo bộ đệm lại hoặc lưu vào bộ đệm xảy ra sau khi tua.
    2. Theo dõi trạng thái: Bước này chuyển đổi sự kiện thành bộ đếm. Ví dụ: các sự kiện thay đổi trạng thái có thể được chuyển đổi thành bộ đếm theo dõi thời gian dành cho mỗi trạng thái phát. Kết quả là tập hợp dữ liệu phân tích cơ bản cho một lần phát.
    3. Tổng hợp: Bước này kết hợp dữ liệu phân tích trên nhiều lượt phát, thường bằng cách thêm bộ đếm.
    4. Tính toán các chỉ số tóm tắt: Nhiều chỉ số hữu ích nhất là tính toán giá trị trung bình hoặc kết hợp các giá trị dữ liệu phân tích cơ bản trong những cách khác. Bạn có thể tính các chỉ số tóm tắt cho một hoặc nhiều chỉ số lượt phát.

Thu thập sự kiện bằng AnalyticsListener

Các sự kiện phát nội dung thô từ trình phát sẽ được báo cáo cho AnalyticsListener thực tế. Bạn có thể dễ dàng thêm trình nghe của riêng mình và chỉ ghi đè mà bạn quan tâm:

Kotlin

exoPlayer.addAnalyticsListener(
  object : AnalyticsListener {
    override fun onPlaybackStateChanged(
      eventTime: EventTime, @Player.State state: Int
    ) {}

    override fun onDroppedVideoFrames(
      eventTime: EventTime,
      droppedFrames: Int,
      elapsedMs: Long,
    ) {}
  }
)

Java

exoPlayer.addAnalyticsListener(
    new AnalyticsListener() {
      @Override
      public void onPlaybackStateChanged(
          EventTime eventTime, @Player.State int state) {}

      @Override
      public void onDroppedVideoFrames(
          EventTime eventTime, int droppedFrames, long elapsedMs) {}
    });

EventTime được truyền đến mỗi lệnh gọi lại sẽ liên kết sự kiện với một nội dung nghe nhìn mục trong danh sách phát, cũng như siêu dữ liệu về vị trí phát và dấu thời gian:

  • realtimeMs: Thời gian trên đồng hồ treo tường của sự kiện.
  • timeline, windowIndexmediaPeriodId: Xác định danh sách phát và mục trong danh sách phát có chứa sự kiện. mediaPeriodId chứa thông tin bổ sung không bắt buộc, ví dụ: cho biết liệu sự kiện thuộc về một quảng cáo trong mục.
  • eventPlaybackPositionMs: Vị trí phát trong mục khi sự kiện đã xảy ra.
  • currentTimeline, currentWindowIndex, currentMediaPeriodIdcurrentPlaybackPositionMs: Như trên nhưng dành cho nội dung hiện đang phát. Chiến lược phát hành đĩa đơn nội dung đang phát có thể khác với nội dung mà sự kiện chuyển đến chẳng hạn như nếu sự kiện tương ứng với việc lưu vào bộ đệm trước của mục được phát.

Xử lý sự kiện bằng PlaybackStatsListener

PlaybackStatsListener là một AnalyticsListener triển khai trên thiết bị xử lý sự kiện. Hàm này tính PlaybackStats, cùng với bộ đếm và kết quả các chỉ số bao gồm:

  • Các chỉ số tóm tắt, ví dụ như tổng thời gian phát.
  • Chỉ số chất lượng phát thích ứng, ví dụ như độ phân giải trung bình của video.
  • Chỉ số chất lượng kết xuất hình ảnh, ví dụ như tỷ lệ khung hình bị rớt.
  • Chỉ số sử dụng tài nguyên, ví dụ như số byte đọc qua mạng.

Bạn sẽ thấy danh sách đầy đủ các chỉ số phát sinh và số lượng hiện có trong PlaybackStats Javadoc.

PlaybackStatsListener tính toán PlaybackStats riêng cho từng mục nội dung đa phương tiện trong danh sách phát và cả quảng cáo phía máy khách được chèn trong các mục này. Bạn có thể thực hiện lệnh gọi lại đến PlaybackStatsListener để được thông báo về việc đã hoàn tất lượt phát lại và sử dụng EventTime được truyền đến lệnh gọi lại để xác định đã phát xong. Bạn có thể tổng hợp dữ liệu phân tích để nhiều lần phát. Bạn cũng có thể truy vấn PlaybackStats cho phiên phát hiện tại bất kỳ lúc nào bằng cách sử dụng PlaybackStatsListener.getPlaybackStats()

Kotlin

exoPlayer.addAnalyticsListener(
  PlaybackStatsListener(/* keepHistory= */ true) {
    eventTime: EventTime?,
    playbackStats: PlaybackStats?,
    -> // Analytics data for the session started at `eventTime` is ready.
  }
)

Java

exoPlayer.addAnalyticsListener(
    new PlaybackStatsListener(
        /* keepHistory= */ true,
        (eventTime, playbackStats) -> {
          // Analytics data for the session started at `eventTime` is ready.
        }));

Hàm khởi tạo của PlaybackStatsListener cung cấp lựa chọn để giữ lại toàn bộ nhật ký của các sự kiện được xử lý. Xin lưu ý rằng việc này có thể gây hao tổn bộ nhớ không xác định tuỳ thuộc vào thời lượng phát và số lượng sự kiện. Do đó, bạn chỉ nên bật chế độ này nếu bạn cần truy cập vào toàn bộ nhật ký xử lý thay vì chỉ dựa vào dữ liệu phân tích cuối cùng.

Lưu ý PlaybackStats sử dụng một nhóm trạng thái mở rộng để cho biết không chỉ trạng thái của nội dung đa phương tiện, cũng như ý định phát của người dùng và chẳng hạn như lý do vì sao quá trình phát bị gián đoạn hoặc kết thúc:

Trạng thái phát Ý định chơi của người dùng Không có ý định chơi
Trước khi phát JOINING_FOREGROUND NOT_STARTED, JOINING_BACKGROUND
Đang phát PLAYING
Quá trình phát bị gián đoạn BUFFERING, SEEKING PAUSED, PAUSED_BUFFERING, SUPPRESSED, SUPPRESSED_BUFFERING, INTERRUPTED_BY_AD
Trạng thái kết thúc ENDED, STOPPED, FAILED, ABANDONED

Ý định chơi của người dùng là yếu tố quan trọng để phân biệt thời điểm người dùng chủ động đợi tiếp tục phát từ thời gian chờ thụ động. Ví dụ: PlaybackStats.getTotalWaitTimeMs trả về tổng thời gian dành cho Các trạng thái JOINING_FOREGROUND, BUFFERINGSEEKING, nhưng không phải thời điểm khi đã tạm dừng phát. Tương tự, PlaybackStats.getTotalPlayAndWaitTimeMs sẽ trả về tổng thời gian mà người dùng có ý định chơi, tức là tổng thời gian hoạt động thời gian chờ và tổng thời gian ở trạng thái PLAYING.

Sự kiện đã xử lý và diễn giải

Bạn có thể ghi lại các sự kiện đã xử lý và diễn giải bằng cách dùng PlaybackStatsListener cùng với keepHistory=true. PlaybackStats thu được sẽ chứa danh sách sự kiện sau:

  • playbackStateHistory: Danh sách theo thứ tự các trạng thái phát mở rộng với EventTime mà họ bắt đầu đăng ký. Bạn cũng có thể sử dụng PlaybackStats.getPlaybackStateAtTime để tra cứu trạng thái của một bức tường cụ thể giờ đồng hồ.
  • mediaTimeHistory: Lịch sử các cặp thời gian nội dung đa phương tiện và thời gian theo đồng hồ treo tường cho phép bạn muốn tạo lại phần nào của nội dung đa phương tiện đã được phát vào thời điểm đó. Bạn có thể Bạn cũng có thể dùng PlaybackStats.getMediaTimeMsAtRealtimeMs để tra cứu nội dung phát tại một thời điểm nhất định trên đồng hồ treo tường.
  • videoFormatHistoryaudioFormatHistory: Danh sách video và video theo thứ tự các định dạng âm thanh được dùng trong quá trình phát bằng EventTime lúc chúng bắt đầu phát. để sử dụng.
  • fatalErrorHistorynonFatalErrorHistory: Danh sách theo thứ tự các mục quan trọng và lỗi không nghiêm trọng với EventTime nơi sự cố xảy ra. Lỗi nghiêm trọng là những lỗi đã kết thúc phát lại, trong khi các lỗi không nghiêm trọng có thể khôi phục được.

Dữ liệu phân tích một lượt phát

Dữ liệu này sẽ tự động được thu thập nếu bạn sử dụng PlaybackStatsListener, thậm chí cùng với keepHistory=false. Giá trị cuối cùng là các trường công khai mà bạn có thể tìm trong PlaybackStats Javadoc và thời lượng trạng thái phát được trả về bởi getPlaybackStateDurationMs. Để thuận tiện, bạn cũng sẽ tìm thấy các phương thức như getTotalPlayTimeMsgetTotalWaitTimeMs trả về thời lượng của các tổ hợp trạng thái phát cụ thể.

Kotlin

Log.d(
  "DEBUG",
  "Playback summary: " +
    "play time = " +
    playbackStats.totalPlayTimeMs +
    ", rebuffers = " +
    playbackStats.totalRebufferCount
)

Java

Log.d(
    "DEBUG",
    "Playback summary: "
        + "play time = "
        + playbackStats.getTotalPlayTimeMs()
        + ", rebuffers = "
        + playbackStats.totalRebufferCount);

Dữ liệu phân tích tổng hợp về nhiều lần phát

Bạn có thể kết hợp nhiều PlaybackStats với nhau bằng cách gọi PlaybackStats.merge PlaybackStats thu được sẽ chứa dữ liệu tổng hợp dữ liệu của tất cả các lượt phát đã hợp nhất. Lưu ý rằng tài khoản này sẽ không chứa lịch sử của sự kiện phát riêng lẻ vì hệ thống không thể tổng hợp những sự kiện này.

Bạn có thể dùng PlaybackStatsListener.getCombinedPlaybackStats để lấy chế độ xem tổng hợp của tất cả dữ liệu phân tích được thu thập trong toàn bộ thời gian PlaybackStatsListener

Các chỉ số tóm tắt được tính toán

Ngoài dữ liệu phân tích cơ bản, PlaybackStats còn cung cấp nhiều phương thức để tính toán các chỉ số tóm tắt.

Kotlin

Log.d(
  "DEBUG",
  "Additional calculated summary metrics: " +
    "average video bitrate = " +
    playbackStats.meanVideoFormatBitrate +
    ", mean time between rebuffers = " +
    playbackStats.meanTimeBetweenRebuffers
)

Java

Log.d(
    "DEBUG",
    "Additional calculated summary metrics: "
        + "average video bitrate = "
        + playbackStats.getMeanVideoFormatBitrate()
        + ", mean time between rebuffers = "
        + playbackStats.getMeanTimeBetweenRebuffers());

Chủ đề nâng cao

Liên kết dữ liệu phân tích với siêu dữ liệu phát

Khi thu thập dữ liệu phân tích cho từng lượt phát riêng lẻ, bạn nên: liên kết dữ liệu phân tích phát lại với siêu dữ liệu về phương tiện đang được đã phát.

Bạn nên đặt siêu dữ liệu dành riêng cho nội dung nghe nhìn bằng MediaItem.Builder.setTag. Thẻ nội dung đa phương tiện nằm trong EventTime được báo cáo cho các sự kiện thô và thời điểm PlaybackStats đã hoàn tất nên có thể dễ dàng truy xuất khi xử lý dữ liệu phân tích tương ứng:

Kotlin

PlaybackStatsListener(/* keepHistory= */ false) {
  eventTime: EventTime,
  playbackStats: PlaybackStats ->
  val mediaTag =
    eventTime.timeline
      .getWindow(eventTime.windowIndex, Timeline.Window())
      .mediaItem
      .localConfiguration
      ?.tag
    // Report playbackStats with mediaTag metadata.
}

Java

new PlaybackStatsListener(
    /* keepHistory= */ false,
    (eventTime, playbackStats) -> {
      Object mediaTag =
          eventTime.timeline.getWindow(eventTime.windowIndex, new Timeline.Window())
              .mediaItem
              .localConfiguration
              .tag;
      // Report playbackStats with mediaTag metadata.
    });

Báo cáo sự kiện phân tích tuỳ chỉnh

Trong trường hợp cần thêm sự kiện tuỳ chỉnh vào dữ liệu phân tích, bạn cần lưu những sự kiện này trong cấu trúc dữ liệu của riêng bạn và kết hợp chúng với dữ liệu được báo cáo Sau PlaybackStats. Nếu việc này hữu ích, bạn có thể mở rộng DefaultAnalyticsCollector để có thể tạo EventTime phiên bản cho các sự kiện tùy chỉnh và gửi chúng cho trình nghe đã đăng ký như trong ví dụ sau.

Kotlin

private interface ExtendedListener : AnalyticsListener {
  fun onCustomEvent(eventTime: EventTime)
}

private class ExtendedCollector : DefaultAnalyticsCollector(Clock.DEFAULT) {
  fun customEvent() {
    val eventTime = generateCurrentPlayerMediaPeriodEventTime()
    sendEvent(eventTime, CUSTOM_EVENT_ID) { listener: AnalyticsListener ->
      if (listener is ExtendedListener) {
        listener.onCustomEvent(eventTime)
      }
    }
  }
}

// Usage - Setup and listener registration.
val player = ExoPlayer.Builder(context).setAnalyticsCollector(ExtendedCollector()).build()
player.addAnalyticsListener(
  object : ExtendedListener {
    override fun onCustomEvent(eventTime: EventTime?) {
      // Save custom event for analytics data.
    }
  }
)
// Usage - Triggering the custom event.
(player.analyticsCollector as ExtendedCollector).customEvent()

Java

private interface ExtendedListener extends AnalyticsListener {
  void onCustomEvent(EventTime eventTime);
}

private static class ExtendedCollector extends DefaultAnalyticsCollector {
  public ExtendedCollector() {
    super(Clock.DEFAULT);
  }

  public void customEvent() {
    AnalyticsListener.EventTime eventTime = generateCurrentPlayerMediaPeriodEventTime();
    sendEvent(
        eventTime,
        CUSTOM_EVENT_ID,
        listener -> {
          if (listener instanceof ExtendedListener) {
            ((ExtendedListener) listener).onCustomEvent(eventTime);
          }
        });
  }
}

// Usage - Setup and listener registration.
ExoPlayer player =
    new ExoPlayer.Builder(context).setAnalyticsCollector(new ExtendedCollector()).build();
player.addAnalyticsListener(
    (ExtendedListener) eventTime -> {
      // Save custom event for analytics data.
    });
// Usage - Triggering the custom event.
((ExtendedCollector) player.getAnalyticsCollector()).customEvent();