Analytics

এক্সোপ্লেয়ার প্লেব্যাক বিশ্লেষণের বিস্তৃত চাহিদা পূরণ করে। পরিশেষে, বিশ্লেষণ হল প্লেব্যাক থেকে ডেটা সংগ্রহ, ব্যাখ্যা, একত্রিতকরণ এবং সারসংক্ষেপ করা। এই ডেটা ডিভাইসে ব্যবহার করা যেতে পারে—উদাহরণস্বরূপ, লগিং, ডিবাগিং, অথবা ভবিষ্যতের প্লেব্যাক সিদ্ধান্ত জানাতে—অথবা সমস্ত ডিভাইস জুড়ে প্লেব্যাক পর্যবেক্ষণ করার জন্য সার্ভারে রিপোর্ট করা যেতে পারে।

একটি বিশ্লেষণ ব্যবস্থাকে সাধারণত প্রথমে ইভেন্ট সংগ্রহ করতে হয়, এবং তারপর সেগুলিকে অর্থবহ করে তোলার জন্য আরও প্রক্রিয়া করতে হয়:

  • ইভেন্ট সংগ্রহ : এটি একটি ExoPlayer ইনস্ট্যান্সে AnalyticsListener নিবন্ধন করে করা যেতে পারে। নিবন্ধিত অ্যানালিটিক্স শ্রোতারা প্লেয়ার ব্যবহারের সময় ঘটে যাওয়া ইভেন্টগুলি গ্রহণ করে। প্রতিটি ইভেন্ট প্লেলিস্টে সংশ্লিষ্ট মিডিয়া আইটেমের সাথে সম্পর্কিত, পাশাপাশি প্লেব্যাক অবস্থান এবং টাইমস্ট্যাম্প মেটাডেটার সাথে সম্পর্কিত।
  • ইভেন্ট প্রসেসিং : কিছু অ্যানালিটিক্স সিস্টেম সার্ভারে কাঁচা ইভেন্ট আপলোড করে, সমস্ত ইভেন্ট প্রসেসিং সার্ভার-সাইডে করা হয়। ডিভাইসে ইভেন্ট প্রসেস করাও সম্ভব, এবং এটি করা সহজ হতে পারে বা আপলোড করার জন্য প্রয়োজনীয় তথ্যের পরিমাণ কমাতে পারে। ExoPlayer PlaybackStatsListener প্রদান করে, যা আপনাকে নিম্নলিখিত প্রক্রিয়াকরণ পদক্ষেপগুলি সম্পাদন করতে দেয়:
    1. ইভেন্ট ব্যাখ্যা : বিশ্লেষণের উদ্দেশ্যে কার্যকর হওয়ার জন্য, ইভেন্টগুলিকে একটি একক প্লেব্যাকের প্রেক্ষাপটে ব্যাখ্যা করা প্রয়োজন। উদাহরণস্বরূপ, প্লেয়ারের অবস্থা STATE_BUFFERING এ পরিবর্তনের কাঁচা ঘটনাটি প্রাথমিক বাফারিং, একটি রিবাফার, অথবা একটি অনুসন্ধানের পরে ঘটে যাওয়া বাফারিংয়ের সাথে সম্পর্কিত হতে পারে।
    2. স্টেট ট্র্যাকিং : এই ধাপটি ইভেন্টগুলিকে কাউন্টারে রূপান্তর করে। উদাহরণস্বরূপ, স্টেট পরিবর্তন ইভেন্টগুলিকে প্রতিটি প্লেব্যাক অবস্থায় কত সময় ব্যয় করা হয়েছে তা ট্র্যাক করার জন্য কাউন্টারে রূপান্তর করা যেতে পারে। ফলাফল হল একটি একক প্লেব্যাকের জন্য বিশ্লেষণ ডেটা মানের একটি মৌলিক সেট।
    3. সমষ্টি : এই ধাপটি একাধিক প্লেব্যাক জুড়ে বিশ্লেষণ ডেটা একত্রিত করে, সাধারণত কাউন্টার যোগ করে।
    4. সারাংশ মেট্রিক্সের গণনা : সবচেয়ে কার্যকর মেট্রিক্সগুলির মধ্যে অনেকগুলি হল সেগুলি যা গড় গণনা করে বা অন্যান্য উপায়ে মৌলিক বিশ্লেষণ ডেটা মানগুলিকে একত্রিত করে। সারাংশ মেট্রিক্স একক বা একাধিক প্লেব্যাকের জন্য গণনা করা যেতে পারে।

AnalyticsListener এর সাথে ইভেন্ট সংগ্রহ

প্লেয়ার থেকে র প্লেব্যাক ইভেন্টগুলি AnalyticsListener বাস্তবায়নে রিপোর্ট করা হয়। আপনি সহজেই আপনার নিজস্ব শ্রোতা যোগ করতে পারেন এবং শুধুমাত্র আপনার আগ্রহের পদ্ধতিগুলিকে ওভাররাইড করতে পারেন:

কোটলিন

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

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

জাভা

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 ব্যবহার করতে পারেন। একাধিক প্লেব্যাকের জন্য বিশ্লেষণ ডেটা একত্রিত করা সম্ভব। PlaybackStatsListener.getPlaybackStats() ব্যবহার করে যেকোনো সময় বর্তমান প্লেব্যাক সেশনের জন্য PlaybackStats অনুসন্ধান করাও সম্ভব।

কোটলিন

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

জাভা

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 এর সাথে মারাত্মক এবং অ-মারাত্মক ত্রুটির তালিকা সাজানো হয়েছে। মারাত্মক ত্রুটি হল প্লেব্যাক শেষ করে এমন ত্রুটি, যেখানে অ-মারাত্মক ত্রুটিগুলি পুনরুদ্ধারযোগ্য হতে পারে।

একক-প্লেব্যাক বিশ্লেষণ ডেটা

PlaybackStatsListener ব্যবহার করলে এই ডেটা স্বয়ংক্রিয়ভাবে সংগ্রহ করা হয়, এমনকি keepHistory=false ব্যবহার করলেও। চূড়ান্ত মান হল পাবলিক ফিল্ড যা আপনি PlaybackStats Javadoc এ খুঁজে পেতে পারেন এবং getPlaybackStateDurationMs দ্বারা ফেরত প্লেব্যাক স্টেট সময়কাল। সুবিধার জন্য, আপনি getTotalPlayTimeMs এবং getTotalWaitTimeMs এর মতো পদ্ধতিগুলিও খুঁজে পাবেন যা নির্দিষ্ট প্লেব্যাক স্টেট সংমিশ্রণের সময়কাল ফেরত দেয়।

কোটলিন

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

জাভা

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

একাধিক প্লেব্যাকের সমষ্টিগত বিশ্লেষণ ডেটা

PlaybackStats.merge কল করে আপনি একাধিক PlaybackStats একসাথে একত্রিত করতে পারেন। ফলস্বরূপ PlaybackStats সমস্ত মার্জ করা প্লেব্যাকের সমষ্টিগত ডেটা থাকবে। মনে রাখবেন যে এতে পৃথক প্লেব্যাক ইভেন্টের ইতিহাস থাকবে না, কারণ এগুলি একত্রিত করা যাবে না।

PlaybackStatsListener.getCombinedPlaybackStats ব্যবহার করে একজন PlaybackStatsListener এর জীবদ্দশায় সংগৃহীত সমস্ত বিশ্লেষণ ডেটার একটি সমষ্টিগত ভিউ পাওয়া যেতে পারে।

গণনা করা সারাংশ মেট্রিক্স

মৌলিক বিশ্লেষণ তথ্য ছাড়াও, PlaybackStats সারাংশ মেট্রিক্স গণনা করার জন্য অনেক পদ্ধতি প্রদান করে।

কোটলিন

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

জাভা

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

উন্নত বিষয়

প্লেব্যাক মেটাডেটার সাথে বিশ্লেষণ ডেটা সংযুক্ত করা

পৃথক প্লেব্যাকের জন্য বিশ্লেষণ ডেটা সংগ্রহ করার সময়, আপনি প্লেব্যাক বিশ্লেষণ ডেটাটি মিডিয়া চালানোর মেটাডেটার সাথে সংযুক্ত করতে চাইতে পারেন।

MediaItem.Builder.setTag ব্যবহার করে মিডিয়া-নির্দিষ্ট মেটাডেটা সেট করা বাঞ্ছনীয়। মিডিয়া ট্যাগটি কাঁচা ইভেন্টের জন্য এবং PlaybackStats শেষ হওয়ার পরে রিপোর্ট করা EventTime এর অংশ, তাই সংশ্লিষ্ট বিশ্লেষণ ডেটা পরিচালনা করার সময় এটি সহজেই পুনরুদ্ধার করা যেতে পারে:

কোটলিন

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

জাভা

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 সাথে একত্রিত করতে হবে। যদি এটি সাহায্য করে, তাহলে আপনি আপনার কাস্টম ইভেন্টগুলির জন্য EventTime ইনস্ট্যান্স তৈরি করতে এবং নিম্নলিখিত উদাহরণে দেখানো হিসাবে ইতিমধ্যেই নিবন্ধিত শ্রোতাদের কাছে পাঠাতে সক্ষম হওয়ার জন্য DefaultAnalyticsCollector প্রসারিত করতে পারেন।

কোটলিন

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

জাভা

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