يتوافق ExoPlayer مع مجموعة كبيرة من احتياجات إحصاءات التشغيل. في نهاية المطاف، تدور تحليلات الأداء حول جمع البيانات وتفسيرها وتجميعها وتلخيصها من عمليات التشغيل. يمكن استخدام هذه البيانات إما على الجهاز، مثلاً لتسجيل ملف السجلّ أو تصحيح الأخطاء أو لاتخاذ قرارات بشأن التشغيل في المستقبل، أو إرسالها إلى أحد الخوادم لمراقبة عمليات التشغيل على جميع الأجهزة.
يحتاج نظام الإحصاءات عادةً إلى جمع الأحداث أولاً، ثم معالجتها بشكل أكبر لجعلها ذات مغزى:
- جمع الأحداث:
يمكن إجراء ذلك من خلال تسجيل
AnalyticsListener
على مثيلExoPlayer
. تتلقّى أدوات معالجة الإحصاءات المسجّلة الأحداث عند وقوعها أثناء استخدام المشغّل. يرتبط كل حدث بعنصر الوسائط المقابل في قائمة التشغيل، بالإضافة إلى موضع التشغيل والبيانات الوصفية للطابع الزمني. - معالجة الأحداث:
تُحمِّل بعض أنظمة الإحصاءات الأحداث الأوّلية إلى خادم، ويتم تنفيذ جميع عمليات
معالجتها من جهة الخادم. من الممكن أيضًا معالجة الأحداث على
الجهاز، وقد يكون ذلك أبسط أو يقلل من كمية المعلومات التي
يجب تحميلها. يوفّر ExoPlayer
PlaybackStatsListener
، الذي يتيح لك تنفيذ خطوات المعالجة التالية:- تفسير الأحداث: لكي تكون الأحداث مفيدة لأغراض الإحصاءات، يجبinterpreted
تفسيرها في سياق تشغيل واحد. على سبيل المثال، قد يتوافق الحدث الأولي لتغيير حالة اللاعب إلى
STATE_BUFFERING
مع عملية التخزين المؤقت الأولية أو التخزين المؤقت أو التخزين المؤقت الذي يحدث بعد البحث. - تتبُّع الحالة: تحوّل هذه الخطوة الأحداث إلى عدادات. على سبيل المثال، يمكن تحويل أحداث تغيير الحالة إلى عدّادات تتتبّع مقدار الوقت المستغرق في كل حالة تشغيل. والنتيجة هي مجموعة أساسية من قيم data التحليلات لتشغيل واحد.
- التجميع: تجمع هذه الخطوة بيانات الإحصاءات على مستوى عدة عمليات تشغيل، عادةً من خلال جمع العدّادات.
- احتساب المقاييس التلخيصية: إنّ العديد من المقاييس الأكثر فائدة هي تلك التي تحسب المتوسطات أو تدمج قيم بيانات الإحصاءات الأساسية بطرق أخرى. يمكن احتساب المقاييس التلخيصية لمشاهدات واحدة أو متعدّدة.
- تفسير الأحداث: لكي تكون الأحداث مفيدة لأغراض الإحصاءات، يجبinterpreted
تفسيرها في سياق تشغيل واحد. على سبيل المثال، قد يتوافق الحدث الأولي لتغيير حالة اللاعب إلى
جمع الأحداث باستخدام 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
: لتحديد قائمة التشغيل والitem ضمن قائمة التشغيل التي ينتمي إليها الحدث تحتوي السمة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
. لتسهيل الأمر، ستجد أيضًا methods مثل 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();