Analytics

ExoPlayer 支援各種播放分析需求。最後 Analytics 的用途是收集、解讀、匯總及匯總資料 播放次數。這類資料可以在裝置上使用,例如: 記錄、偵錯或告知日後的播放決定,或者 伺服器監控所有裝置上的播放次數。

分析系統通常必須先收集事件,然後處理事件 以便讓他們覺得具有意義

  • 事件收集: 只要在 ExoPlayer 上註冊 AnalyticsListener 即可 執行個體。已註冊的數據分析事件監聽器會在事件發生期間收到事件 。每個事件都會與對應的媒體建立關聯 播放清單中的項目,以及播放位置和時間戳記中繼資料。
  • 事件處理: 某些數據分析系統會將原始事件上傳至伺服器,且涵蓋所有事件 並在伺服器端執行您也可以處理 可能會比較簡單,或減少資訊量 必須上傳。ExoPlayer 提供 PlaybackStatsListener 可讓您執行以下處理步驟:
    1. 事件解讀:事件必須 會在單一播放時解讀。例如 玩家狀態變更至 STATE_BUFFERING 的事件,可能會與 自動緩衝處理、重新緩衝或緩衝處理;
    2. 狀態追蹤:此步驟會將事件轉換為計數器。例如: 狀態變更事件可轉換為計數器,以追蹤 。結果是一組基本的數據分析資料 則代表單次播放的值。
    3. 匯總:這個步驟會合併多個來源的 Analytics 資料 播放次數,通常是增加計數器。
    4. 摘要指標的計算方式:許多最實用的指標 並設定用來計算平均值或結合 。摘要指標可以計算一或多個項目 播放。

使用 AnalyticsListener 收集事件

系統會將播放器的原始播放事件回報給 AnalyticsListener 。您可以輕鬆新增自己的事件監聽器,並只覆寫 您感興趣的方法:

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 會將事件與媒體建立關聯 播放清單中的項目,以及播放位置和時間戳記中繼資料:

  • realtimeMs:事件的實際時鐘時間。
  • timelinewindowIndexmediaPeriodId:定義播放清單和 項目。mediaPeriodId 包含選擇性的其他資訊,例如指出 事件隸屬於商品內的廣告。
  • eventPlaybackPositionMs:事件發生時,項目中的播放位置 發生。
  • currentTimelinecurrentWindowIndexcurrentMediaPeriodIdcurrentPlaybackPositionMs:如上所述,但針對目前正在播放的項目。 目前正在播放的項目可能與事件的目標項目不同 例如,如果事件對應至下一個 要播放的項目。

使用 PlaybackStatsListener 處理事件

PlaybackStatsListener 是會在裝置端實作的 AnalyticsListener 事件處理。這個函式會計算 PlaybackStats,包括計數器和 指標包括:

  • 摘要指標,例如總播放時間。
  • 自動調整播放品質指標,例如平均影片解析度。
  • 轉譯品質指標,例如影格遺失率。
  • 資源用量指標,例如透過網路讀取的位元組數。

您可以前往「說明中心」查看可用次數和衍生指標的完整清單 PlaybackStats Javadoc

PlaybackStatsListener 會為每個媒體項目計算個別的 PlaybackStats 以及插入這些項目中的每則廣告。個人中心 可以提供對 PlaybackStatsListener 的回呼,以得知已完成 並透過傳遞至回呼的 EventTime 找出 播放完畢。您可匯總 Google Analytics 資料的 多次播放。此外,您也可以查詢 PlaybackStats 藉此隨時存取目前播放工作階段 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.
        }));

PlaybackStatsListener 建構函式提供選項,讓 包括已處理事件的歷史記錄請注意,這可能會產生不明的記憶體負擔 取決於播放長度和事件數量因此,您 建議您只在需要存取完整資料處理記錄時,才開啟這項功能 事件,而不只是最終 Analytics 資料

請注意,PlaybackStats 會使用延伸的狀態組合來指出不 媒體狀態、使用者想播放的內容,以及更詳細的資訊 其他資訊 (例如播放中斷或結束的原因):

播放狀態 使用者想要玩遊戲 沒有遊戲意圖
播放前 JOINING_FOREGROUND NOT_STARTEDJOINING_BACKGROUND
主動播放 PLAYING
中斷播放 BUFFERINGSEEKING PAUSEDPAUSED_BUFFERINGSUPPRESSEDSUPPRESSED_BUFFERINGINTERRUPTED_BY_AD
結束狀態 ENDEDSTOPPEDFAILEDABANDONED

使用者之所以想玩遊戲,是辨別使用者何時 主動等待播放,從被動等待時間繼續。例如: PlaybackStats.getTotalWaitTimeMs 會傳回 JOINING_FOREGROUNDBUFFERINGSEEKING 狀態,但不是 已暫停播放。同樣地,PlaybackStats.getTotalPlayAndWaitTimeMs 會 就會傳回使用者有意玩遊戲的總時間,也就是 等待時間和處於 PLAYING 狀態的總時間。

已處理及解讀的事件

您可以使用 PlaybackStatsListener 記錄已處理及解讀的事件 keepHistory=true。產生的 PlaybackStats 會包含 下列事件清單:

  • playbackStateHistory:已排序的擴充播放狀態清單, 開始套用的EventTime。您也可以使用 PlaybackStats.getPlaybackStateAtTime 可查詢特定牆上的狀態 。
  • mediaTimeHistory:實際的時間與媒體時間組合的歷史記錄。 就能重新建構當時播放媒體的哪些部分你可以 一併使用 PlaybackStats.getMediaTimeMsAtRealtimeMs 查詢播放內容 指定的實際執行位置
  • videoFormatHistoryaudioFormatHistory:已排序的影片清單和 與啟動的 EventTime 一併播放的音訊格式 。
  • fatalErrorHistorynonFatalErrorHistory:已排序的嚴重錯誤和已排序清單 發生在 EventTime 的非嚴重錯誤。嚴重錯誤 不過,其他一般錯誤或許也能復原。

單一播放數據分析資料

如果您使用「PlaybackStatsListener」,系統會自動收集這項資料, keepHistory=false。最終值是公開欄位 可在 PlaybackStats Javadoc 中找到,以及播放狀態持續時間 getPlaybackStateDurationMs 會傳回 值。為了方便起見 例如 getTotalPlayTimeMsgetTotalWaitTimeMs 等方法 特定播放狀態組合的時間長度。

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

匯總多次播放的數據分析資料

你可以使用以下方式結合多個PlaybackStatsPlaybackStats.merge。產生的 PlaybackStats 會包含匯總值 所有資料。請注意,其中不包含 因為這類事件無法彙整。

PlaybackStatsListener.getCombinedPlaybackStats 可用於取得 您可以查看整個 YouTube 平台中收集的所有數據分析資料 PlaybackStatsListener

計算的摘要指標

除了基本數據分析資料以外,PlaybackStats 還提供許多方法 計算摘要指標

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

進階主題

將數據分析資料與播放中繼資料建立關聯

收集個別播放內容的數據分析資料時,建議您 將播放數據分析資料與正在傳輸的媒體相關中繼資料建立關聯 。

建議使用 MediaItem.Builder.setTag 設定媒體專屬的中繼資料。 媒體代碼是原始事件回報的 EventTime 的一部分,以及 PlaybackStats 已完成,因此可以在處理 對應的數據分析資料:

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

回報自訂數據分析事件

如需在數據分析資料中加入自訂事件,您必須儲存 並在您自己的資料結構中納入這些事件 PlaybackStats後。必要時,您可以擴充 DefaultAnalyticsCollector 才能為自訂事件產生 EventTime 例項,並傳送 並連結到已註冊的事件監聽器,如以下範例所示。

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