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