Analytics

يتوافق ExoPlayer مع مجموعة كبيرة من احتياجات إحصاءات التشغيل. في نهاية المطاف، فإن التحليلات تدور حول جمع البيانات وتفسيرها وتجميعها وتلخيصها من عمليات التشغيل. يمكن استخدام هذه البيانات إما على الجهاز — على سبيل المثال التسجيل أو تصحيح الأخطاء أو اتخاذ قرارات التشغيل المستقبلية، أو إبلاغ الخادم لمراقبة عمليات التشغيل عبر جميع الأجهزة.

عادةً ما يحتاج نظام التحليلات إلى جمع الأحداث أولاً، ثم معالجتها بشكل أكبر لجعلها ذات مغزى:

  • جمع الفعالية: ويمكنك إجراء ذلك من خلال تسجيل AnalyticsListener على ExoPlayer. مثال. يتلقّى مستمعو الإحصاءات المسجّلون الأحداث فور وقوعها استخدام المشغل. يرتبط كل حدث بالوسائط المناسبة. بالإضافة إلى موضع التشغيل والبيانات الوصفية للطابع الزمني.
  • معالجة الأحداث: تُحمّل بعض أنظمة التحليلات الأحداث الأولية إلى الخادم، مع تحميل جميع الأحداث إجراء المعالجة من جانب الخادم. ومن الممكن أيضًا معالجة الأحداث في جهازك، وقد يكون القيام بذلك أبسط أو يقلل من كمية المعلومات التي يجب تحميله. يوفّر ExoPlayer ميزة PlaybackStatsListener، التي إجراء خطوات المعالجة التالية:
    1. تفسير الحدث: لتكون الأحداث مفيدة لأغراض الإحصاءات، تحتاج إلى الأحداث. ليتم تفسيره في سياق تشغيل واحد. على سبيل المثال، السمة الأولية الحدث الذي تم فيه تغيير حالة اللاعب إلى STATE_BUFFERING قد يتوافق مع التخزين المؤقت الأوّلي أو التخزين المؤقت مجددًا أو التخزين المؤقت الذي يحدث بعد البحث.
    2. تتبُّع الحالة: تحوِّل هذه الخطوة الأحداث إلى عدّادات. على سبيل المثال: يمكن تحويل أحداث تغيير الحالة إلى عدادات تتعقب مقدار الوقت كل حالة تشغيل. والنتيجة هي مجموعة أساسية من بيانات التحليلات القيم لعملية تشغيل واحدة.
    3. التجميع: تجمع هذه الخطوة بيانات الإحصاءات على مستوى عدة عمليات التشغيل، عادةً عن طريق جمع عدادات.
    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 منفصلة لكل ملف وسائط في قائمة التشغيل وأيضًا كل إعلان من جهة العميل يتم إدراجه في هذه العناصر. إِنْتَ يمكنه توفير معاودة اتصال إلى PlaybackStatsListener لإعلامه مكتملاً عمليات التشغيل، واستخدام EventTime الذي تم تمريره إلى معاودة الاتصال لتحديد انتهى التشغيل. من الممكن تجميع بيانات التحليلات عمليات تشغيل متعددة. من الممكن أيضًا الاستعلام عن 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.

الأحداث التي تمت معالجتها وتفسيرها

يمكنك تسجيل الأحداث التي تمت معالجتها وتفسيرها باستخدام ميزة "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 التي تعرض مدة مجموعات حالات التشغيل المحددة.

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

مواضيع متقدمة

ربط بيانات الإحصاءات بالبيانات الوصفية للتشغيل

عند جمع بيانات إحصائية لعمليات تشغيل فردية، يمكنك ربط بيانات تحليلات التشغيل بالبيانات الوصفية حول الوسائط لعبها.

من المستحسن ضبط البيانات الوصفية الخاصة بالوسائط باستخدام 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.
    });

الإبلاغ عن أحداث الإحصاءات المخصّصة

إذا كنت بحاجة إلى إضافة أحداث مخصّصة إلى بيانات الإحصاءات، عليك حفظ هذه الأحداث في بنية بياناتك الخاصة ودمجها مع الأحداث بعد PlaybackStats. يمكنك تمديد مهلة DefaultAnalyticsCollector إذا كانت مفيدة. لتتمكّن من إنشاء EventTime مثيل للأحداث المخصّصة وإرسال للمستمعين الذين سبق تسجيلهم كما هو موضح في المثال التالي.

Kotlin

private interface ExtendedListener : AnalyticsListener {
  fun onCustomEvent(eventTime: EventTime)
}

private class ExtendedCollector : DefaultAnalyticsCollector(Clock.DEFAULT) {
  fun customEvent() {
    val eventTime = generateCurrentPlayerMediaPeriodEventTime()
    sendEvent(eventTime, CUSTOM_EVENT_ID) { listener: AnalyticsListener ->
      if (listener is ExtendedListener) {
        listener.onCustomEvent(eventTime)
      }
    }
  }
}

// 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

private interface ExtendedListener extends AnalyticsListener {
  void onCustomEvent(EventTime eventTime);
}

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

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