Analytics

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

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

  • مجموعه رویداد: این کار را می‌توان با ثبت AnalyticsListener در نمونه ExoPlayer انجام داد. شنوندگان ثبت‌شده تجزیه‌وتحلیل رویدادها را درحین استفاده از پخش‌کننده دریافت می‌کنند. هر رویداد با عنصر رسانه‌ای مربوطه در فهرست پخش و همچنین فراداده‌های مُهر زمان و موقعیت بازپخش مرتبط است.
  • پردازش رویداد: برخی‌از سیستم‌های تجزیه‌وتحلیل رویدادهای خام را در سرور بارگذاری می‌کنند و همه پردازش رویداد در سمت سرور انجام می‌شود. همچنین امکان پردازش رویدادها در دستگاه وجود دارد و انجام این کار ممکن است ساده‌تر باشد یا مقدار اطلاعاتی را که باید بارگذاری شود کاهش دهد. ‫ExoPlayer PlaybackStatsListener را ارائه می‌دهد که به شما امکان می‌دهد مراحل پردازش زیر را انجام دهید:
    1. تفسیر رویداد: برای اینکه رویدادها برای اهداف تحلیلی مفید باشند، باید در زمینه یک بازپخش واحد تفسیر شوند. برای مثال، رویداد خام تغییر وضعیت پخش‌کننده به STATE_BUFFERING ممکن است مربوط به بافرینگ اولیه، بافرینگ مجدد، یا بافرینگی باشد که پس‌از جستجو رخ می‌دهد.
    2. پیگیری وضعیت: این مرحله رویدادها را به شمارنده‌ها تبدیل می‌کند. برای مثال، رویدادهای تغییر وضعیت می‌توانند به شمارنده‌هایی تبدیل شوند که مدت زمان صرف‌شده در هر وضعیت بازپخش را ردیابی می‌کنند. نتیجه مجموعه‌ای پایه از مقادیر داده‌های تجزیه‌وتحلیل برای یک بازپخش است.
    3. تراکم: این مرحله داده‌های تجزیه‌وتحلیل را در چندین بازپخش ترکیب می‌کند، معمولاً با افزودن شمارنده‌ها.
    4. محاسبه سنجه‌های خلاصه: بسیاری از مفیدترین سنجه‌ها آن‌هایی هستند که میانگین‌ها را محاسبه می‌کنند یا مقادیر داده‌های پایه Analytics را به روش‌های دیگر ترکیب می‌کنند. سنجه‌های خلاصه را می‌توان برای یک یا چند بازپخش محاسبه کرد.

گردآوری رویداد با 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 ارسال‌شده به پاسخ تماس برای شناسایی پخش تمام‌شده استفاده کنید. امکان تجمیع داده‌های Analytics برای پخش‌های متعدد وجود دارد. همچنین می‌توانید در هر زمانی بااستفاده از 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.

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

می‌توانید رویدادهای پردازش‌شده و تفسیرشده را بااستفاده از 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 می‌توان برای دریافت نمای تجمیعی از همه داده‌های Analytics جمع‌آوری‌شده در طول عمر PlaybackStatsListener استفاده کرد.

سنجه‌های خلاصه محاسبه‌شده

علاوه‌بر داده‌های پایه Analytics،‏ 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());

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

مرتبط کردن داده‌های Analytics با فراداده‌های بازپخش

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

توصیه می‌شود فراداده‌های مختص رسانه را با 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

درصورتی‌که نیاز داشته باشید رویدادهای سفارشی به داده‌های 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();
}