Analytics

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

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

  • इवेंट कलेक्शन: इसके लिए, ExoPlayer इंस्टेंस पर AnalyticsListener को रजिस्टर करें. रजिस्टर किए गए Analytics लिसनर को इवेंट की जानकारी मिलती है. ऐसा तब होता है, जब प्लेयर का इस्तेमाल किया जा रहा हो. हर इवेंट, प्लेलिस्ट में मौजूद उससे जुड़े मीडिया आइटम के साथ-साथ, वीडियो चलाने की पोज़िशन और टाइमस्टैंप के मेटाडेटा से जुड़ा होता है.
  • इवेंट प्रोसेसिंग: कुछ Analytics सिस्टम, रॉ इवेंट को सर्वर पर अपलोड करते हैं. साथ ही, सभी इवेंट की प्रोसेसिंग सर्वर-साइड पर की जाती है. डिवाइस पर भी इवेंट प्रोसेस किए जा सकते हैं. ऐसा करना आसान हो सकता है या इससे अपलोड की जाने वाली जानकारी की मात्रा कम हो सकती है. ExoPlayer, PlaybackStatsListener उपलब्ध कराता है. इसकी मदद से, ये काम किए जा सकते हैं:
    1. इवेंट को समझना: आंकड़ों के मकसद से काम का होने के लिए, इवेंट को एक ही प्लेबैक के संदर्भ में समझा जाना चाहिए. उदाहरण के लिए, प्लेयर की स्थिति में STATE_BUFFERING पर बदलाव होने का रॉ इवेंट, शुरुआती बफ़रिंग, फिर से बफ़रिंग या वीडियो को आगे-पीछे करने के बाद होने वाली बफ़रिंग से जुड़ा हो सकता है.
    2. स्टेट ट्रैकिंग: इस चरण में, इवेंट को काउंटर में बदला जाता है. उदाहरण के लिए, स्थिति में बदलाव वाले इवेंट को काउंटर में बदला जा सकता है. इससे यह ट्रैक किया जा सकता है कि वीडियो चलाने की हर स्थिति में कितना समय बिताया गया. इससे, एक बार वीडियो चलाने पर मिलने वाले आंकड़ों के डेटा की बुनियादी वैल्यू का सेट मिलता है.
    3. एग्रीगेशन: इस चरण में, कई प्लेबैक के आंकड़ों को एक साथ जोड़ा जाता है. आम तौर पर, इसके लिए काउंटर जोड़े जाते हैं.
    4. समरी मेट्रिक का कैलकुलेशन: सबसे काम की मेट्रिक वे होती हैं जो औसत की गिनती करती हैं या अन्य तरीकों से बुनियादी Analytics डेटा वैल्यू को जोड़ती हैं. समरी मेट्रिक को एक या कई प्लेबैक के लिए कैलकुलेट किया जा सकता है.

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

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_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 भी शामिल होता है. गंभीर गड़बड़ियां वे होती हैं जिनकी वजह से वीडियो चलना बंद हो जाता है. वहीं, सामान्य गड़बड़ियों को ठीक किया जा सकता है.

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

PlaybackStatsListener का इस्तेमाल करने पर, यह डेटा अपने-आप इकट्ठा हो जाता है. भले ही, आपने keepHistory=false का इस्तेमाल किया हो. फ़ाइनल वैल्यू, सार्वजनिक फ़ील्ड होते हैं. इन्हें 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.merge को कॉल करके, कई PlaybackStats को एक साथ जोड़ा जा सकता है. मर्ज किए गए सभी प्लेबैक का कुल डेटा, नतीजे के तौर पर मिलने वाले 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 के खत्म होने पर, इसे संबंधित Analytics डेटा को मैनेज करते समय वापस पाया जा सकता है:

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

ट्रैकिंग से जुड़े फ़ीचर फ़्लैग और कैनरी मोड

A/B टेस्टिंग करते समय या Media3 के नए ऑप्टिमाइज़ेशन के असर का आकलन करते समय, वीडियो चलाने से जुड़े आंकड़ों के डेटा को चालू फ़ीचर फ़्लैग और Canary मोड के साथ कोरिलेट किया जा सकता है.

Flags.getLogString पर क्वेरी की जा सकती है या Flags.getEnabledOverrides और Flags.getDisabledOverrides का इस्तेमाल करके, खास फ़्लैग ओवरराइड की जांच की जा सकती है. इससे, कस्टम ऐनलिटिक्स पेलोड या सेशन मेटाडेटा में फ़्लैग की स्थितियों को शामिल किया जा सकता है.