ExoPlayer mendukung berbagai kebutuhan analisis pemutaran. Pada akhirnya, analisis adalah pengumpulan, interpretasi, penggabungan, dan perangkuman data dari pemutaran. Data ini dapat digunakan di perangkat—misalnya untuk logging, proses debug, atau untuk menginformasikan keputusan pemutaran di masa mendatang—atau dilaporkan ke server untuk memantau pemutaran di semua perangkat.
Sistem analisis biasanya perlu mengumpulkan peristiwa terlebih dahulu, lalu memprosesnya lebih lanjut agar lebih bermakna:
- Pengumpulan peristiwa:
Hal ini dapat dilakukan dengan mendaftarkan
AnalyticsListener
pada instanceExoPlayer
. Pemroses analisis terdaftar menerima peristiwa saat terjadi selama penggunaan pemutar. Setiap peristiwa dikaitkan dengan item media yang sesuai dalam playlist, serta metadata posisi pemutaran dan stempel waktu. - Pemrosesan peristiwa: Beberapa sistem analisis mengupload peristiwa mentah ke server, dengan semua pemrosesan peristiwa yang dilakukan di sisi server. Anda juga dapat memproses peristiwa di
perangkat, dan melakukannya mungkin lebih sederhana atau mengurangi jumlah informasi yang
perlu diupload. ExoPlayer menyediakan
PlaybackStatsListener
, yang memungkinkan Anda melakukan langkah-langkah pemrosesan berikut:- Penafsiran peristiwa: Agar berguna untuk tujuan analisis, peristiwa harus ditafsirkan dalam konteks satu pemutaran. Misalnya, peristiwa mentah
perubahan status pemutar menjadi
STATE_BUFFERING
mungkin sesuai dengan buffering awal, buffering ulang, atau buffering yang terjadi setelah pencarian. - Pelacakan status: Langkah ini mengubah peristiwa menjadi penghitung. Misalnya, peristiwa perubahan status dapat dikonversi menjadi penghitung yang melacak banyaknya waktu yang dihabiskan di setiap status pemutaran. Hasilnya adalah kumpulan nilai data analisis dasar untuk satu pemutaran.
- Agregasi: Langkah ini menggabungkan data analisis di beberapa pemutaran, biasanya dengan menambahkan penghitung.
- Penghitungan metrik ringkasan: Banyak metrik yang paling berguna adalah metrik yang menghitung rata-rata atau menggabungkan nilai data analisis dasar dengan cara lain. Metrik ringkasan dapat dihitung untuk satu atau beberapa pemutaran.
- Penafsiran peristiwa: Agar berguna untuk tujuan analisis, peristiwa harus ditafsirkan dalam konteks satu pemutaran. Misalnya, peristiwa mentah
perubahan status pemutar menjadi
Pengumpulan peristiwa dengan AnalyticsListener
Peristiwa pemutaran mentah dari pemutar dilaporkan ke implementasi
AnalyticsListener
. Anda dapat dengan mudah menambahkan pemroses sendiri dan mengganti metode yang diinginkan saja:
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
yang diteruskan ke setiap callback akan mengaitkan peristiwa ke item
media dalam playlist, serta metadata posisi pemutaran dan stempel waktu:
realtimeMs
: Waktu jam dinding acara.timeline
,windowIndex
, danmediaPeriodId
: Menentukan playlist dan item dalam playlist yang memiliki peristiwa tersebut.mediaPeriodId
berisi informasi tambahan opsional, misalnya yang menunjukkan apakah peristiwa termasuk dalam iklan dalam item tersebut.eventPlaybackPositionMs
: Posisi pemutaran dalam item saat peristiwa terjadi.currentTimeline
,currentWindowIndex
,currentMediaPeriodId
, dancurrentPlaybackPositionMs
: Seperti di atas, tetapi untuk item yang sedang diputar. Item yang sedang diputar mungkin berbeda dengan item yang memuat peristiwa tersebut, misalnya jika peristiwa terkait dengan pra-buffering item berikutnya yang akan diputar.
Pemrosesan peristiwa dengan PlaybackStatsListener
PlaybackStatsListener
adalah AnalyticsListener
yang mengimplementasikan pemrosesan peristiwa
di perangkat. Metode ini menghitung PlaybackStats
, dengan penghitung dan metrik turunan yang mencakup:
- Ringkasan metrik, misalnya total waktu pemutaran.
- Metrik kualitas pemutaran adaptif, misalnya resolusi video rata-rata.
- Merender metrik kualitas, misalnya, tingkat penurunan frame.
- Metrik penggunaan resource, misalnya jumlah byte yang dibaca melalui jaringan.
Anda akan menemukan daftar lengkap jumlah yang tersedia dan metrik turunan di PlaybackStats
Javadoc.
PlaybackStatsListener
menghitung PlaybackStats
terpisah untuk setiap item media
dalam playlist, dan juga setiap iklan sisi klien yang disisipkan dalam item ini. Anda
dapat memberikan callback ke PlaybackStatsListener
untuk diberi tahu tentang pemutaran
yang telah selesai, dan menggunakan EventTime
yang diteruskan ke callback untuk mengidentifikasi
pemutaran mana yang selesai. Anda dapat menggabungkan data analisis untuk
beberapa pemutaran. Anda juga dapat membuat kueri PlaybackStats
untuk
sesi pemutaran saat ini kapan saja menggunakan
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. }));
Konstruktor PlaybackStatsListener
memberikan opsi untuk menyimpan histori lengkap peristiwa yang diproses. Perhatikan bahwa hal ini dapat menyebabkan overhead memori yang tidak diketahui,
bergantung pada durasi pemutaran dan jumlah peristiwa. Oleh karena itu, sebaiknya hanya aktifkan jika Anda memerlukan akses ke histori lengkap peristiwa yang diproses, bukan hanya ke data analisis akhir.
Perhatikan bahwa PlaybackStats
menggunakan serangkaian status yang diperluas untuk menunjukkan tidak hanya
status media, tetapi juga maksud pengguna untuk memutar dan informasi yang lebih
mendetail seperti alasan pemutaran terganggu atau berakhir:
Status pemutaran | Niat pengguna untuk bermain | Tidak ada niat untuk memutar |
---|---|---|
Sebelum pemutaran | JOINING_FOREGROUND |
NOT_STARTED , JOINING_BACKGROUND |
Pemutaran aktif | PLAYING |
|
Pemutaran terganggu | BUFFERING , SEEKING |
PAUSED , PAUSED_BUFFERING , SUPPRESSED , SUPPRESSED_BUFFERING , INTERRUPTED_BY_AD |
Status akhir | ENDED , STOPPED , FAILED , ABANDONED |
Niat pengguna untuk melakukan pemutaran penting untuk membedakan waktu saat pengguna
aktif menunggu pemutaran berlanjut dari waktu tunggu pasif. Misalnya,
PlaybackStats.getTotalWaitTimeMs
menampilkan total waktu yang dihabiskan dalam status
JOINING_FOREGROUND
, BUFFERING
, dan SEEKING
, tetapi tidak menampilkan waktu saat
pemutaran dijeda. Demikian pula, PlaybackStats.getTotalPlayAndWaitTimeMs
akan
menampilkan total waktu dengan niat pengguna untuk bermain, yaitu total waktu tunggu
aktif dan total waktu yang dihabiskan dalam status PLAYING
.
Peristiwa yang diproses dan ditafsirkan
Anda dapat mencatat peristiwa yang diproses dan ditafsirkan menggunakan PlaybackStatsListener
dengan keepHistory=true
. PlaybackStats
yang dihasilkan akan berisi daftar peristiwa berikut:
playbackStateHistory
: Daftar urut status pemutaran yang diperpanjang denganEventTime
tempat status tersebut mulai diterapkan. Anda juga dapat menggunakanPlaybackStats.getPlaybackStateAtTime
untuk mencari status pada waktu jam wall tertentu.mediaTimeHistory
: Histori waktu jam dinding dan pasangan waktu media memungkinkan Anda merekonstruksi bagian media mana yang diputar pada saat itu. Anda juga dapat menggunakanPlaybackStats.getMediaTimeMsAtRealtimeMs
untuk mencari posisi pemutaran pada waktu jam dinding tertentu.videoFormatHistory
danaudioFormatHistory
: Urutan daftar format video dan audio yang digunakan selama pemutaran denganEventTime
tempat format tersebut mulai digunakan.fatalErrorHistory
dannonFatalErrorHistory
: Mengurutkan daftar error fatal dan non-fatal denganEventTime
tempat terjadinya error tersebut. Error fatal adalah error yang mengakhiri pemutaran, sedangkan error non-fatal dapat dipulihkan.
Data analisis pemutaran tunggal
Data ini otomatis dikumpulkan jika Anda menggunakan PlaybackStatsListener
, bahkan
dengan keepHistory=false
. Nilai akhirnya adalah kolom publik yang dapat Anda
temukan di PlaybackStats
Javadoc dan durasi status pemutaran
yang ditampilkan oleh getPlaybackStateDurationMs
. Untuk memudahkan, Anda juga akan menemukan
metode seperti getTotalPlayTimeMs
dan getTotalWaitTimeMs
yang menampilkan
durasi kombinasi status pemutaran tertentu.
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);
Data analisis gabungan dari beberapa pemutaran
Anda dapat menggabungkan beberapa PlaybackStats
bersama-sama dengan memanggil
PlaybackStats.merge
. PlaybackStats
yang dihasilkan akan berisi data
gabungan dari semua pemutaran gabungan. Perhatikan bahwa histori ini tidak akan berisi histori
peristiwa pemutaran individual, karena peristiwa tersebut tidak dapat digabungkan.
PlaybackStatsListener.getCombinedPlaybackStats
dapat digunakan untuk mendapatkan tampilan gabungan dari semua data analisis yang dikumpulkan selama masa aktif PlaybackStatsListener
.
Metrik ringkasan yang dihitung
Selain data analisis dasar, PlaybackStats
menyediakan banyak metode untuk menghitung metrik ringkasan.
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());
Topik lanjutan
Mengaitkan data analisis dengan metadata pemutaran
Saat mengumpulkan data analisis untuk setiap pemutaran, Anda mungkin ingin mengaitkan data analisis pemutaran dengan metadata tentang media yang diputar.
Sebaiknya setel metadata khusus media dengan MediaItem.Builder.setTag
.
Tag media adalah bagian dari EventTime
yang dilaporkan untuk peristiwa mentah dan saat
PlaybackStats
selesai, sehingga dapat diambil dengan mudah saat menangani
data analisis yang sesuai:
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. });
Melaporkan peristiwa analisis kustom
Jika perlu menambahkan peristiwa kustom ke data analisis, Anda harus menyimpan peristiwa ini dalam struktur data Anda sendiri dan menggabungkannya dengan PlaybackStats
yang dilaporkan nanti. Jika membantu, Anda dapat memperluas DefaultAnalyticsCollector
agar dapat menghasilkan instance EventTime
untuk peristiwa kustom dan mengirimkannya
ke pemroses yang sudah terdaftar seperti yang ditunjukkan dalam contoh berikut.
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();