Analytics

ExoPlayer از طیف گسترده‌ای از نیازهای تجزیه‌وتحلیل بازپخش پشتیبانی می‌کند. درنهایت، تجزیه‌وتحلیل به جمع‌آوری، تفسیر، تجمیع، و خلاصه کردن داده‌ها از بازپخش‌ها مربوط می‌شود. این داده‌ها را می‌توان در دستگاه استفاده کرد—برای مثال برای ثبت، اشکال‌زدایی، یا اطلاع‌رسانی تصمیمات بازپخش آتی—یا به سرور گزارش کرد تا بازپخش‌ها در همه دستگاه‌ها نظارت شود.

یک سیستم تجزیه‌وتحلیل معمولاً ابتدا باید رویدادها را جمع‌آوری کند و سپس آن‌ها را پردازش کند تا آن‌ها را معنادار کند:

  • مجموعه رویداد: این کار را می‌توان با ثبت AnalyticsListener در نمونه ExoPlayer انجام داد. شنوندگان تجزیه‌وتحلیل ثبت‌شده رویدادها را هنگام وقوع درطول استفاده از پخش‌کننده دریافت می‌کنند. هر رویداد با فایل رسانه‌ای مربوطه در فهرست پخش، و همچنین موقعیت بازپخش و فراداده مُهر زمان مرتبط است.
  • پردازش رویداد: برخی‌از سیستم‌های تجزیه‌وتحلیل رویدادهای خام را در سرور بارگذاری می‌کنند و همه پردازش‌های رویداد در سمت سرور انجام می‌شود. همچنین می‌توان رویدادها را در دستگاه پردازش کرد و انجام این کار ممکن است ساده‌تر باشد یا مقدار اطلاعاتی را که باید بارگذاری شود کاهش دهد. 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 که به هر callback ارسال می‌شود، رویداد را به یک فایل رسانه‌ای در فهرست پخش، و همچنین به فراداده‌های موقعیت بازپخش و مُهر زمان مرتبط می‌کند:

  • ‫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 این گزینه را ارائه می‌دهد که سابقه کامل رویدادهای پردازش‌شده حفظ شود. توجه داشته باشید که این کار ممکن است سربار حافظه نامشخصی ایجاد کند که به طول بازپخش و تعداد رویدادها بستگی دارد. بنابراین، فقط درصورتی باید آن را روشن کنید که به دسترسی به سابقه کامل رویدادهای پردازش‌شده نیاز داشته باشید، نه فقط به داده‌های نهایی 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.

رویدادهای پردازش‌شده و تفسیرشده

می‌توانید رویدادهای پردازش‌شده و تفسیرشده را بااستفاده از PlaybackStatsListener با keepHistory=true ضبط کنید. 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());

موضوعات پیشرفته

مرتبط کردن داده‌های تجزیه‌وتحلیل با فراداده بازپخش

When collecting analytics data for individual playbacks, you may want to associate the playback analytics data with metadata about the media being played.

توصیه می‌شود فراداده‌های خاص رسانه را با MediaItem.Builder.setTag تنظیم کنید. برچسب رسانه بخشی از EventTime گزارش‌شده برای رویدادهای خام است و وقتی PlaybackStats تمام شد، می‌توان آن را هنگام رسیدگی به داده‌های تجزیه‌وتحلیل مربوطه بازیابی کرد:

کاتلین

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

گزارش کردن رویدادهای تجزیه‌وتحلیل سفارشی

اگر لازم است رویدادهای سفارشی را به داده‌های Analytics اضافه کنید، باید این رویدادها را در ساختار داده‌های خودتان ذخیره کنید و بعداً آن‌ها را با PlaybackStats گزارش‌شده ترکیب کنید. اگر مفید است، می‌توانید DefaultAnalyticsCollector را گسترش دهید تا بتوانید نمونه‌های EventTime را برای رویدادهای سفارشی‌تان تولید کنید و آن‌ها را به شنوندگان ثبت‌شده ارسال کنید، همان‌طور که در مثال زیر نشان داده شده است.

کاتلین

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

ردیابی پرچم‌های ویژگی و حالت Canary

هنگام انجام آزمایش A/B یا ارزیابی تأثیر بهینه‌سازی‌های جدید Media3، می‌توانید داده‌های تجزیه‌وتحلیل بازپخش را با پرچم‌های ویژگی فعال و حالت Canary مرتبط کنید.

می‌توانید بااستفاده از Flags.getEnabledOverrides و Flags.getDisabledOverrides، Flags.getLogString را پُرسمان کنید یا لغوهای پرچم خاص را بازرسی کنید تا وضعیت‌های پرچم را در فراداده جلسه یا بار داده‌های تجزیه‌وتحلیل سفارشی‌تان بگنجانید.