Analytics

ExoPlayer obsługuje szeroki zakres potrzeb w zakresie analiz odtwarzania. Ostatecznie Analytics polega na gromadzeniu, interpretowaniu, agregowaniu i podsumowywaniu danych od odtworzeń. Tych danych można używać na urządzeniu, na przykład w przypadku: rejestrowania, debugowania ani na potrzeby podejmowania przyszłych decyzji dotyczących odtwarzania do monitorowania odtworzeń na wszystkich urządzeniach.

System analityczny zwykle najpierw musi zebrać zdarzenia, a potem je przetworzyć nadając im sens:

  • Kolekcja zdarzeń: Możesz to zrobić, rejestrując AnalyticsListener na ExoPlayer instancji. Zarejestrowani detektory statystyk odbierają zdarzenia w momencie, w którym występują korzystania z odtwarzacza. Każde zdarzenie jest powiązane z odpowiednimi multimediami pozycję na playliście, a także metadane pozycji odtwarzania i sygnatury czasowej.
  • Przetwarzanie zdarzeń: Niektóre systemy analityczne przesyłają na serwer nieprzetworzone zdarzenia ze wszystkimi po stronie serwera. Można również przetwarzać zdarzenia na urządzeń, co może być prostsze lub zmniejszyć ilość informacji musi zostać przesłany. ExoPlayer udostępnia pakiet PlaybackStatsListener, który umożliwia wykonanie tych czynności:
    1. Interpretacja zdarzeń: aby zdarzenia były przydatne w celach analitycznych, należy interpretować w kontekście pojedynczego odtworzenia. Na przykład surowe zdarzenie zmiany stanu odtwarzacza na STATE_BUFFERING może odpowiadać początkowym buforowaniu, ponownym buforowaniu lub buforowaniu, które mają miejsce po wyszukiwaniu.
    2. Śledzenie stanu: ten krok przekształca zdarzenia na liczniki. Przykład: zdarzenia zmiany stanu można przekonwertować na liczniki śledzące, w każdym stanie odtwarzania. W efekcie powstaje podstawowy zbiór danych analitycznych dla pojedynczego odtworzenia.
    3. Agregacja: ten krok łączy dane analityczne z różnych źródeł. do odtwarzania strumieniowego, zwykle przez zsumowanie liczników zdarzeń.
    4. Obliczanie danych podsumowujących: wiele najbardziej przydatnych danych to: które obliczają średnie lub łączą podstawowe wartości danych analitycznych w w inny sposób. Podsumowanie danych można obliczać dla pojedynczych lub wielu odtworzeniach.

Zbieranie zdarzeń za pomocą AnalyticsListener

Nieprzetworzone zdarzenia odtwarzania pochodzące z odtwarzacza są zgłaszane do AnalyticsListener implementacji. Możesz łatwo dodać własnego detektora i zastąpić tylko Interesujące Cię metody:

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

Pole EventTime przekazywane do każdego wywołania zwrotnego wiąże zdarzenie z mediami elementu na playliście oraz metadanych pozycji odtwarzania i sygnatury czasowej:

  • realtimeMs: zegar zegarowy zdarzenia.
  • timeline, windowIndex i mediaPeriodId: definiuje playlistę oraz elementu playlisty, do której należy wydarzenie. mediaPeriodId zawiera opcjonalne informacje dodatkowe, wskazujące na przykład, czy należy do reklamy w danym elemencie.
  • eventPlaybackPositionMs: pozycja odtwarzania w elemencie, gdy zdarzenie .
  • currentTimeline, currentWindowIndex, currentMediaPeriodId i currentPlaybackPositionMs: jak wyżej, ale z odtwarzanym elementem. obecnie odtwarzany element może się różnić od elementu, na którym jest powiązane zdarzenie na przykład gdy zdarzenie odpowiada wstępnemu buforowaniu kolejnego element, który ma zostać odtworzony.

Przetwarzanie zdarzeń za pomocą funkcji OdtwarzanieStatsListener

PlaybackStatsListener to AnalyticsListener, który implementuje na urządzeniu Przetwarzanie zdarzeń. Oblicza ono wartość PlaybackStats, korzystając z liczników i wyprowadzonych dane, w tym:

  • Dane podsumowujące, np. łączny czas odtwarzania.
  • Wskaźniki jakości odtwarzania adaptacyjnego, np. średnia rozdzielczość wideo.
  • dane o jakości renderowania, np. liczba pominiętych klatek.
  • Wskaźniki wykorzystania zasobów, na przykład liczba bajtów odczytanych przez sieć.

Pełną listę dostępnych liczników i wygenerowanych danych znajdziesz w sekcji PlaybackStats Javadoc.

PlaybackStatsListener oblicza osobne wartości PlaybackStats dla każdego elementu multimedialnego oraz wszystkich reklam po stronie klienta wstawionych do tych produktów. Ty może oddzwonić do PlaybackStatsListener, by otrzymać informację o zakończeniu i użyj parametru EventTime przekazanego do wywołania zwrotnego, aby określić, Zakończono odtwarzanie. Możesz zagregować dane analityczne dotyczące: wiele odtworzeń. Możesz też wysłać zapytanie do parametru PlaybackStats, aby bieżącej sesji odtwarzania w dowolnym momencie przy użyciu 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.
        }));

Konstruktor PlaybackStatsListener umożliwia zachowanie pełnej historii przetworzonych zdarzeń. Pamiętaj, że może to spowodować nieznane obciążenie pamięci. w zależności od czasu trwania odtwarzania i liczby zdarzeń. Dlatego warto należy włączać tylko wtedy, gdy potrzebujesz dostępu do pełnej historii przetworzonych plików zdarzeń, a nie tylko ostatecznych danych analitycznych.

Zwróć uwagę, że PlaybackStats używa rozszerzonego zestawu stanów, aby wskazać, że nie tylko od stanu multimediów, ale także od intencji użytkownika, informacje o przyczynach przerwania lub zakończenia odtwarzania:

Stan odtwarzania Zamiar użytkownika chcący zagrać Brak zamiaru grania
Przed rozpoczęciem odtwarzania JOINING_FOREGROUND NOT_STARTED, JOINING_BACKGROUND
Aktywne odtwarzanie PLAYING
Odtwarzanie przerwane BUFFERING, SEEKING PAUSED, PAUSED_BUFFERING, SUPPRESSED, SUPPRESSED_BUFFERING, INTERRUPTED_BY_AD
Stany końcowe ENDED, STOPPED, FAILED, ABANDONED

Zamiar użytkownika, który chce zagrać, jest ważny, aby rozróżniać, kiedy użytkownik aktywne oczekiwanie na kontynuowanie odtwarzania po pasywnym czasie oczekiwania. Przykład: PlaybackStats.getTotalWaitTimeMs zwraca łączny czas spędzony w JOINING_FOREGROUND, BUFFERING i SEEKING, ale nie czas, gdy odtwarzanie zostało wstrzymane. Podobnie PlaybackStats.getTotalPlayAndWaitTimeMs będzie zwraca łączny czas gry z zamiarem użytkownika, czyli łączny czas czas oczekiwania i łączny czas w stanie PLAYING.

Przetworzone i zinterpretowane zdarzenia

Przetworzone i interpretowane zdarzenia możesz rejestrować za pomocą funkcji PlaybackStatsListener dzięki keepHistory=true. Wynikowa wartość PlaybackStats będzie zawierać te listy zdarzeń:

  • playbackStateHistory: uporządkowana lista rozszerzonych stanów odtwarzania zawierające ciąg EventTime, w którym zaczęły obowiązywać. Możesz też użyć PlaybackStats.getPlaybackStateAtTime, aby sprawdzić stan danej ściany na zegarze.
  • mediaTimeHistory: historia par zegarów ściennych i czasu multimediów, która umożliwia pozwala zrekonstruować fragmenty multimediów, które były odtwarzane w danym momencie. Dostępne opcje użyj też PlaybackStats.getMediaTimeMsAtRealtimeMs do wyszukania odtworzenia w określonym czasie.
  • videoFormatHistory i audioFormatHistory: uporządkowane listy filmów i formaty audio używane podczas odtwarzania na kontrolerze (EventTime), od którego został on rozpoczęty do wykorzystania.
  • fatalErrorHistory i nonFatalErrorHistory: uporządkowane listy błędów krytycznych i EventTime, na których wystąpiły błędy niekrytyczne. Błędy krytyczne: tych, które zakończyły odtwarzanie, podczas gdy niekrytyczne błędy da się naprawić.

Dane analityczne pojedynczego odtworzenia

Te dane są zbierane automatycznie, jeśli używasz PlaybackStatsListener, nawet dzięki keepHistory=false. Wartości końcowe to pola publiczne, w których możesz w PlaybackStats Javadoc oraz czasie trwania stanu odtwarzania. zwrócone przez getPlaybackStateDurationMs. Dla wygody znajdziesz też takie jak getTotalPlayTimeMs i getTotalWaitTimeMs, które zwracają czas trwania określonych kombinacji stanu odtwarzania.

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

Zbiorcze dane analityczne dotyczące wielu odtworzeń

Możesz połączyć kilka PlaybackStats, dzwoniąc PlaybackStats.merge Wynik PlaybackStats będzie zawierać zagregowane wartości danych wszystkich połączonych odtworzeń. Pamiętaj, że nie zawiera on historii poszczególnych zdarzeń związanych z odtwarzaniem, bo nie można ich sumować.

PlaybackStatsListener.getCombinedPlaybackStats może zostać użyte, aby uzyskać: zagregowany widok wszystkich danych analitycznych zebranych od początku istnienia usługi PlaybackStatsListener

Obliczone dane podsumowania

Oprócz podstawowych danych analitycznych PlaybackStats udostępnia wiele metod do obliczania danych podsumowujących.

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

Tematy zaawansowane

Powiązanie danych analitycznych z metadanymi odtwarzania

Podczas zbierania danych analitycznych o poszczególnych odtworzeniach możesz: kojarzyć dane statystyk odtwarzania z metadanymi dotyczącymi multimediów odtworzonej przez grę.

Zalecamy skonfigurowanie metadanych związanych z multimediami za pomocą parametru MediaItem.Builder.setTag. Tag mediów jest częścią elementu EventTime, który jest raportowany w przypadku nieprzetworzonych zdarzeń oraz gdy PlaybackStats są już zakończone, więc można je łatwo pobrać podczas obsługi odpowiadające im dane analityczne:

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

Raportowanie zdarzeń niestandardowych Analytics

Jeśli do danych analitycznych chcesz dodać zdarzenia niestandardowe, musisz zapisać plik zdarzenia w Twojej strukturze danych i połącz je z raportowanymi PlaybackStats później. Jeśli to pomoże, możesz przedłużyć termin DefaultAnalyticsCollector aby móc generować instancje EventTime dla zdarzeń niestandardowych do zarejestrowanych już detektorów, jak pokazano w przykładzie poniżej.

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