Analytics

ExoPlayer, वीडियो चलाने से जुड़े आंकड़ों को इकट्ठा करने की कई तरह की ज़रूरतों को पूरा करता है. आखिरकार, Analytics का काम प्लेबैक से डेटा इकट्ठा करना, उसकी व्याख्या करना, उसे एग्रीगेट करना, और उसकी खास जानकारी देना है. इस डेटा का इस्तेमाल डिवाइस पर किया जा सकता है. उदाहरण के लिए, लॉगिंग, डीबग करने या वीडियो चलाने से जुड़े फ़ैसले लेने के लिए. इसके अलावा, इस डेटा को किसी सर्वर को भेजा जा सकता है, ताकि सभी डिवाइसों पर वीडियो चलाने की प्रोसेस को मॉनिटर किया जा सके.

आम तौर पर, किसी Analytics सिस्टम को सबसे पहले इवेंट इकट्ठा करने होते हैं. इसके बाद, उन्हें ज़्यादा काम का बनाने के लिए प्रोसेस करना होता है:

  • इवेंट कलेक्शन: इसके लिए, ExoPlayer इंस्टेंस पर AnalyticsListener रजिस्टर करना होगा. रजिस्टर किए गए Analytics लिसनर को, प्लेयर के इस्तेमाल के दौरान होने वाले इवेंट मिलते हैं. हर इवेंट, प्लेलिस्ट में मौजूद मीडिया आइटम के साथ-साथ, चलाने की स्थिति और टाइमस्टैंप मेटाडेटा से जुड़ा होता है.
  • इवेंट प्रोसेसिंग: कुछ आंकड़ों के सिस्टम, रॉ इवेंट को सर्वर पर अपलोड करते हैं. साथ ही, सभी इवेंट प्रोसेसिंग सर्वर-साइड पर की जाती है. डिवाइस पर भी इवेंट प्रोसेस किए जा सकते हैं. ऐसा करना आसान हो सकता है या इससे अपलोड की जाने वाली जानकारी की मात्रा कम हो सकती है. ExoPlayer, PlaybackStatsListener उपलब्ध कराता है. इसकी मदद से, प्रोसेसिंग के ये चरण पूरे किए जा सकते हैं:
    1. इवेंट की व्याख्या: आंकड़ों के लिए इवेंट का इस्तेमाल करने के लिए, यह ज़रूरी है कि इवेंट की व्याख्या एक ही बार किए गए प्लेबैक के संदर्भ में की जाए. उदाहरण के लिए, प्लेयर की स्थिति में बदलाव करने वाले रॉ इवेंट STATE_BUFFERING का मतलब, शुरुआती बफ़रिंग, फिर से बफ़रिंग या सीक करने के बाद होने वाली बफ़रिंग हो सकता है.
    2. स्टेट ट्रैकिंग: इस चरण में, इवेंट को काउंटर में बदल दिया जाता है. उदाहरण के लिए, स्टेट में बदलाव वाले इवेंट को ऐसे काउंटर में बदला जा सकता है जो यह ट्रैक करते हैं कि हर प्लेबैक स्टेट में कितना समय बिताया गया. नतीजे के तौर पर, एक बार चलाए गए वीडियो के लिए, Analytics डेटा की वैल्यू का बुनियादी सेट मिलता है.
    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: इवेंट के समय की जानकारी देने वाली दीवार घड़ी.
  • timeline, windowIndex, और mediaPeriodId: इससे उस प्लेलिस्ट और प्लेलिस्ट में मौजूद उस आइटम के बारे में पता चलता है जिससे इवेंट जुड़ा है. mediaPeriodId में अतिरिक्त जानकारी शामिल होती है. हालांकि, यह जानकारी देना ज़रूरी नहीं है. उदाहरण के लिए, यह जानकारी दी जा सकती है कि इवेंट, आइटम के विज्ञापन से जुड़ा है या नहीं.
  • eventPlaybackPositionMs: इवेंट होने के समय, आइटम में वीडियो चलाने की पोज़िशन.
  • currentTimeline, currentWindowIndex, currentMediaPeriodId, और currentPlaybackPositionMs: ऊपर दी गई जानकारी के मुताबिक, लेकिन फ़िलहाल चल रहे आइटम के लिए. ऐसा हो सकता है कि अभी चल रहा आइटम, उस आइटम से अलग हो जिससे इवेंट जुड़ा है. उदाहरण के लिए, अगर इवेंट, चलने वाले अगले आइटम की प्री-बफ़रिंग से जुड़ा है.

PlaybackStatsListener की मदद से इवेंट प्रोसेस करना

PlaybackStatsListener एक AnalyticsListener है, जो डिवाइस पर इवेंट प्रोसेसिंग लागू करता है. यह PlaybackStats का हिसाब लगाता है. इसमें काउंटर और डिराइव की गई मेट्रिक शामिल होती हैं. जैसे:

  • खास जानकारी वाली मेट्रिक. उदाहरण के लिए, वीडियो चलाने का कुल समय.
  • वीडियो की क्वालिटी को अडजस्ट करने से जुड़ी मेट्रिक, जैसे कि वीडियो का औसत रिज़ॉल्यूशन.
  • रेंडरिंग क्वालिटी की मेट्रिक. उदाहरण के लिए, ड्रॉप किए गए फ़्रेम की दर.
  • संसाधन के इस्तेमाल से जुड़ी मेट्रिक. उदाहरण के लिए, नेटवर्क पर पढ़े गए बाइट की संख्या.

उपलब्ध संख्या और डिराइव की गई मेट्रिक की पूरी सूची, आपको PlaybackStats Javadoc में मिलेगी.

PlaybackStatsListener, प्लेलिस्ट में मौजूद हर मीडिया आइटम के लिए अलग-अलग PlaybackStats कैलकुलेट करता है. साथ ही, इन आइटम में शामिल किए गए क्लाइंट-साइड के हर विज्ञापन के लिए भी अलग-अलग PlaybackStats कैलकुलेट करता है. PlaybackStatsListener को कॉलबैक दिया जा सकता है, ताकि आपको पूरे प्लेबैक के बारे में सूचना मिल सके. साथ ही, कॉलबैक को पास किए गए EventTime का इस्तेमाल करके यह पता लगाया जा सकता है कि कौनसे प्लेबैक पूरे हो गए हैं. एक से ज़्यादा बार वीडियो चलाने के लिए, ऐनलिटिक्स डेटा को एग्रीगेट किया जा सकता है. PlaybackStats का इस्तेमाल करके, मौजूदा प्लेबैक सेशन के लिए 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 का कंस्ट्रक्टर, प्रोसेस किए गए इवेंट का पूरा इतिहास सेव करने का विकल्प देता है. ध्यान दें कि इससे मेमोरी पर असर पड़ सकता है. यह असर, वीडियो चलाने की अवधि और इवेंट की संख्या के हिसाब से अलग-अलग हो सकता है. इसलिए, आपको इसे सिर्फ़ तब चालू करना चाहिए, जब आपको प्रोसेस किए गए इवेंट के पूरे इतिहास का ऐक्सेस चाहिए हो. ऐसा तब करें, जब आपको सिर्फ़ फ़ाइनल आंकड़ों का डेटा न चाहिए हो.

ध्यान दें कि PlaybackStats, मीडिया की स्थिति के साथ-साथ उपयोगकर्ता के मीडिया चलाने के इरादे और अन्य जानकारी के बारे में बताने के लिए, राज्यों के एक्सटेंडेड सेट का इस्तेमाल करता है. जैसे, मीडिया चलाने में रुकावट क्यों आई या उसे क्यों बंद किया गया:

वीडियो चलने की स्थिति उपयोगकर्ता का गेम खेलने का इरादा वीडियो चलाने का कोई इरादा नहीं है
वीडियो चलाने से पहले JOINING_FOREGROUND NOT_STARTED, JOINING_BACKGROUND
चालू प्लेबैक PLAYING
वीडियो चलाने में रुकावट आना BUFFERING, SEEKING PAUSED, PAUSED_BUFFERING, SUPPRESSED, SUPPRESSED_BUFFERING, INTERRUPTED_BY_AD
खत्म होने की स्थितियां ENDED, STOPPED, FAILED, ABANDONED

उपयोगकर्ता के गेम खेलने के इरादे से यह पता चलता है कि वह कब गेम खेलने के लिए इंतज़ार कर रहा था और कब वह इंतज़ार नहीं कर रहा था. उदाहरण के लिए, PlaybackStats.getTotalWaitTimeMs, JOINING_FOREGROUND, BUFFERING, और SEEKING स्थितियों में बिताए गए कुल समय की जानकारी देता है. हालांकि, यह उस समय की जानकारी नहीं देता है, जब वीडियो को रोका गया था. इसी तरह, PlaybackStats.getTotalPlayAndWaitTimeMs से, गेम खेलने के लिए उपयोगकर्ता के इंतज़ार का कुल समय दिखेगा. यानी, सक्रिय इंतज़ार का कुल समय और PLAYING स्थिति में बिताया गया कुल समय.

प्रोसेस किए गए और इंटरप्रेट किए गए इवेंट

keepHistory=true के साथ PlaybackStatsListener का इस्तेमाल करके, प्रोसेस किए गए और इंटरप्रेट किए गए इवेंट रिकॉर्ड किए जा सकते हैं. इसके बाद, PlaybackStats में इवेंट की ये सूचियां शामिल होंगी:

  • playbackStateHistory: यह एक्सटेंड किए गए प्लेबैक की स्थितियों की क्रम से लगाई गई सूची है. इसमें EventTime भी शामिल है, जिससे पता चलता है कि ये स्थितियां कब लागू हुईं. किसी वॉल क्लॉक के समय के हिसाब से राज्य की जानकारी देखने के लिए, PlaybackStats.getPlaybackStateAtTime का इस्तेमाल भी किया जा सकता है.
  • mediaTimeHistory: इसमें वॉल क्लॉक टाइम और मीडिया टाइम के जोड़े का इतिहास होता है. इससे यह पता लगाया जा सकता है कि मीडिया के कौनसे हिस्से को किस समय चलाया गया था. PlaybackStats.getMediaTimeMsAtRealtimeMs का इस्तेमाल करके, किसी समय पर वीडियो के चलने की स्थिति भी देखी जा सकती है.
  • videoFormatHistory और audioFormatHistory: वीडियो और ऑडियो फ़ॉर्मैट की क्रम से लगाई गई सूचियां. इनमें यह भी बताया जाता है कि वीडियो चलाने के दौरान, किस EventTime पर इन फ़ॉर्मैट का इस्तेमाल शुरू हुआ.
  • fatalErrorHistory और nonFatalErrorHistory: ये जानलेवा और गैर-जानलेवा गड़बड़ियों की क्रम से लगाई गई सूचियां हैं. इनमें EventTime भी शामिल है, जिस पर ये गड़बड़ियां हुई थीं. गंभीर गड़बड़ियों की वजह से वीडियो चलना बंद हो जाता है. हालांकि, सामान्य गड़बड़ियों को ठीक किया जा सकता है.

सिंगल-प्लेबैक के आंकड़ों का डेटा

keepHistory=false का इस्तेमाल करने पर भी, PlaybackStatsListener का इस्तेमाल करने पर यह डेटा अपने-आप इकट्ठा हो जाता है. फ़ाइनल वैल्यू, सार्वजनिक फ़ील्ड होती हैं. इन्हें PlaybackStats Javadoc में देखा जा सकता है. साथ ही, ये getPlaybackStateDurationMs से मिले, वीडियो चलाने की स्थिति की अवधि के हिसाब से तय होती हैं. आसानी के लिए, आपको getTotalPlayTimeMs और getTotalWaitTimeMs जैसे तरीके भी मिलेंगे. ये वीडियो चलाने की स्थिति के खास कॉम्बिनेशन की अवधि दिखाते हैं.

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

कई बार चलाए गए वीडियो के आंकड़ों का एग्रीगेट किया गया डेटा

PlaybackStats पर कॉल करके, एक साथ कई PlaybackStats को जोड़ा जा सकता है.PlaybackStats.merge इससे मिलने वाले PlaybackStats में, मर्ज किए गए सभी प्लेबैक का एग्रीगेट किया गया डेटा शामिल होगा. ध्यान दें कि इसमें अलग-अलग वीडियो चलाने के इवेंट का इतिहास शामिल नहीं होगा, क्योंकि इन्हें एग्रीगेट नहीं किया जा सकता.

PlaybackStatsListener.getCombinedPlaybackStats का इस्तेमाल, 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());

ऐडवांस विषय

Analytics के डेटा को वीडियो चलाने से जुड़े मेटाडेटा के साथ जोड़ना

अलग-अलग प्लेबैक के लिए आंकड़ों का डेटा इकट्ठा करते समय, आपको प्लेबैक के आंकड़ों के डेटा को, चलाए जा रहे मीडिया के मेटाडेटा से जोड़ना पड़ सकता है.

हमारा सुझाव है कि मीडिया के हिसाब से मेटाडेटा को 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.
    });

कस्टम Analytics इवेंट की रिपोर्टिंग

अगर आपको Analytics डेटा में कस्टम इवेंट जोड़ने हैं, तो आपको इन इवेंट को अपने डेटा स्ट्रक्चर में सेव करना होगा. इसके बाद, इन्हें रिपोर्ट किए गए PlaybackStats के साथ जोड़ना होगा. अगर इससे मदद मिलती है, तो DefaultAnalyticsCollector को बढ़ाया जा सकता है, ताकि आपके कस्टम इवेंट के लिए EventTime इंस्टेंस जनरेट किए जा सकें और उन्हें पहले से रजिस्टर किए गए लिसनर को भेजा जा सके. इसके लिए, यहां दिया गया उदाहरण देखें.

Kotlin

@OptIn(UnstableApi::class)
private interface ExtendedListener : AnalyticsListener {
  fun onCustomEvent(eventTime: EventTime)
}

@OptIn(UnstableApi::class)
private class ExtendedCollector : DefaultAnalyticsCollector(Clock.DEFAULT) {

  fun customEvent() {
    val eventTime = super.generateCurrentPlayerMediaPeriodEventTime()
    super.sendEvent(eventTime, CUSTOM_EVENT_ID) { listener: AnalyticsListener ->
      if (listener is ExtendedListener) {
        listener.onCustomEvent(eventTime)
      }
    }
  }
}

@OptIn(UnstableApi::class)
fun useExtendedAnalyticsCollector(context: Context) {
  // 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

@OptIn(markerClass = UnstableApi.class)
private interface ExtendedListener extends AnalyticsListener {
  void onCustomEvent(EventTime eventTime);
}

@OptIn(markerClass = UnstableApi.class)
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);
          }
        });
  }
}

@OptIn(markerClass = UnstableApi.class)
public static void useExtendedAnalyticsCollector(Context context) {
  // 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();
}