ExoPlayer supporta un'ampia gamma di esigenze di analisi della riproduzione. In definitiva, l'analisi riguarda la raccolta, l'interpretazione, l'aggregazione e il riepilogo dei dati delle riproduzioni. Questi dati possono essere utilizzati sul dispositivo, ad esempio per il logging, il debug o per prendere decisioni future in merito alla riproduzione, oppure possono essere trasmessi a un server per monitorare le riproduzioni su tutti i dispositivi.
Solitamente, un sistema di analisi deve raccogliere prima gli eventi per poi elaborarli ulteriormente per renderli significativi:
- Raccolta eventi:
puoi farlo registrando un
AnalyticsListener
in un'istanzaExoPlayer
. I listener di analisi registrati ricevono gli eventi quando si verificano durante l'utilizzo del player. Ogni evento è associato all'elemento multimediale corrispondente nella playlist, nonché ai metadati relativi alla posizione di riproduzione e al timestamp. - Elaborazione degli eventi: alcuni sistemi di analisi caricano gli eventi non elaborati su un server, mentre l'elaborazione di tutti gli eventi viene eseguita sul lato server. È anche possibile elaborare eventi sul dispositivo e farlo potrebbe essere più semplice o ridurre la quantità di informazioni da caricare. ExoPlayer fornisce
PlaybackStatsListener
, che ti consente di eseguire i seguenti passaggi di elaborazione:- Interpretazione degli eventi: per essere utili ai fini dell'analisi, gli eventi devono
essere interpretati nel contesto di una singola riproduzione. Ad esempio, l'evento non elaborato di una modifica dello stato del player in
STATE_BUFFERING
potrebbe corrispondere al buffering iniziale, al rebuffer o al buffering che si verifica dopo una ricerca. - Monitoraggio dello stato: questo passaggio converte gli eventi in contatori. Ad esempio, gli eventi di modifica dello stato possono essere convertiti in contatori che monitorano il tempo trascorso in ogni stato di riproduzione. Il risultato è un insieme di base di valori dei dati di analisi per una singola riproduzione.
- Aggregazione: questo passaggio combina i dati di analisi su più riproduzioni, in genere sommando i contatori.
- Calcolo delle metriche di riepilogo: molte delle metriche più utili sono quelle che calcolano le medie o combinano i valori dei dati di analisi di base in altri modi. Le metriche di riepilogo possono essere calcolate per riproduzioni singole o multiple.
- Interpretazione degli eventi: per essere utili ai fini dell'analisi, gli eventi devono
essere interpretati nel contesto di una singola riproduzione. Ad esempio, l'evento non elaborato di una modifica dello stato del player in
Raccolta di eventi con AnalyticsListener
Gli eventi di riproduzione non elaborati dal player vengono segnalati alle implementazioni AnalyticsListener
. Puoi aggiungere facilmente un listener personalizzato e sostituire solo i metodi che ti interessano:
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) {} });
Il valore EventTime
passato a ogni callback associa l'evento a un elemento multimediale nella playlist, nonché ai metadati della posizione di riproduzione e del timestamp:
realtimeMs
: l'orario reale dell'evento.timeline
,windowIndex
emediaPeriodId
: definiscono la playlist e l'elemento all'interno della playlist a cui appartiene l'evento. L'elementomediaPeriodId
contiene informazioni aggiuntive facoltative, ad esempio indica se l'evento appartiene a un annuncio all'interno dell'elemento.eventPlaybackPositionMs
: la posizione di riproduzione nell'elemento quando si è verificato l'evento.currentTimeline
,currentWindowIndex
,currentMediaPeriodId
ecurrentPlaybackPositionMs
: come sopra ma per l'elemento attualmente in riproduzione. L'elemento attualmente in riproduzione potrebbe essere diverso dall'elemento a cui appartiene l'evento, ad esempio se l'evento corrisponde al pre-buffering dell'elemento successivo da riprodurre.
Elaborazione degli eventi con PlaybackStatsListener
PlaybackStatsListener
è un AnalyticsListener
che implementa l'elaborazione degli eventi sul dispositivo. Calcola PlaybackStats
, con contatori e metriche derivate, tra cui:
- Metriche di riepilogo, ad esempio il tempo di riproduzione totale.
- Metriche relative alla qualità di riproduzione adattiva, ad esempio la risoluzione media dei video.
- Metriche sulla qualità del rendering, ad esempio la percentuale di frame ignorati.
- Metriche di utilizzo delle risorse, ad esempio il numero di byte letti sulla rete.
Troverai un elenco completo dei conteggi disponibili e delle metriche derivate in Javadoc di PlaybackStats
.
PlaybackStatsListener
calcola PlaybackStats
separati per ogni elemento multimediale nella playlist, nonché per ogni annuncio lato client inserito all'interno di questi elementi. Puoi
fornire un callback a PlaybackStatsListener
per ricevere informazioni sulle riproduzioni
concluse e utilizzare il comando EventTime
passato al callback per identificare la riproduzione terminata. È possibile aggregare i dati di analisi per
più riproduzioni. Inoltre, puoi eseguire una query su PlaybackStats
per la sessione di riproduzione corrente in qualsiasi momento utilizzando 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. }));
Il costruttore di PlaybackStatsListener
offre la possibilità di conservare la cronologia completa degli eventi elaborati. Tieni presente che questo potrebbe comportare un overhead di memoria sconosciuto, a seconda della durata della riproduzione e del numero di eventi. Pertanto, ti consigliamo di attivarla solo se hai bisogno di accedere alla cronologia completa degli eventi elaborati, anziché solo ai dati di analisi finali.
Tieni presente che PlaybackStats
utilizza un insieme esteso di stati per indicare non solo lo stato dei contenuti multimediali, ma anche l'intenzione dell'utente di riprodurre e informazioni più dettagliate, ad esempio il motivo per cui la riproduzione è stata interrotta o terminata:
Stato di riproduzione | Intenzione dell'utente a riprodurre | Nessuna intenzione di giocare |
---|---|---|
Prima della riproduzione | JOINING_FOREGROUND |
NOT_STARTED , JOINING_BACKGROUND |
Riproduzione attiva | PLAYING |
|
Riproduzione interrotta | BUFFERING , SEEKING |
PAUSED , PAUSED_BUFFERING , SUPPRESSED , SUPPRESSED_BUFFERING e INTERRUPTED_BY_AD |
Stati di fine | ENDED , STOPPED , FAILED , ABANDONED |
L'intenzione dell'utente di giocare è importante per distinguere i tempi di attesa passivi in cui l'utente stava
attivando attivamente la riproduzione per continuare. Ad esempio,
PlaybackStats.getTotalWaitTimeMs
restituisce il tempo totale trascorso negli stati
JOINING_FOREGROUND
, BUFFERING
e SEEKING
, ma non il tempo in cui
la riproduzione è stata messa in pausa. Analogamente, PlaybackStats.getTotalPlayAndWaitTimeMs
restituirà il tempo totale di riproduzione con un'intenzione dell'utente, ovvero il tempo di attesa totale di attività e il tempo totale trascorso nello stato PLAYING
.
Eventi elaborati e interpretati
Puoi registrare eventi elaborati e interpretati utilizzando PlaybackStatsListener
con keepHistory=true
. Il valore PlaybackStats
risultante conterrà i seguenti elenchi di eventi:
playbackStateHistory
: un elenco ordinato di stati di riproduzione estesa con il valoreEventTime
da cui è stata avviata l'applicazione. Puoi anche utilizzarePlaybackStats.getPlaybackStateAtTime
per controllare lo stato a una determinata ora.mediaTimeHistory
: una cronologia delle coppie di ore e ore multimediali che ti consente di ricostruire quali parti dei contenuti multimediali sono state riprodotte e in quale momento. Puoi anche usarePlaybackStats.getMediaTimeMsAtRealtimeMs
per cercare la posizione di riproduzione in una determinata ora.videoFormatHistory
eaudioFormatHistory
: elenchi ordinati di formati video e audio utilizzati durante la riproduzione conEventTime
, da cui hanno iniziato a essere utilizzati.fatalErrorHistory
enonFatalErrorHistory
: elenchi ordinati di errori irreversibili e non irreversibili con iEventTime
in cui si sono verificati. Gli errori irreversibili sono quelli che hanno terminato la riproduzione, mentre gli errori non irreversibili potrebbero essere stati recuperabili.
Dati di analisi per riproduzione singola
Questi dati vengono raccolti automaticamente se utilizzi PlaybackStatsListener
, anche
con keepHistory=false
. I valori finali sono i campi pubblici che puoi trovare in Javadoc di PlaybackStats
e le durate dello stato di riproduzione restituite da getPlaybackStateDurationMs
. Per praticità, troverai anche
metodi come getTotalPlayTimeMs
e getTotalWaitTimeMs
che restituiscono
la durata di combinazioni specifiche di stati di riproduzione.
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);
Aggrega dati analitici relativi a più riproduzioni
Puoi combinare più PlaybackStats
chiamando
PlaybackStats.merge
. Il file PlaybackStats
risultante conterrà i dati
aggregati di tutte le riproduzioni unite. Tieni presente che non conterrà la cronologia dei singoli eventi di riproduzione, dato che non possono essere aggregati.
PlaybackStatsListener.getCombinedPlaybackStats
può essere utilizzato per ottenere una vista aggregata di tutti i dati di analisi raccolti durante il ciclo di vita di un PlaybackStatsListener
.
Metriche di riepilogo calcolate
Oltre ai dati analitici di base, PlaybackStats
offre molti metodi per calcolare le metriche di riepilogo.
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());
Argomenti avanzati
Associare i dati di analisi ai metadati di riproduzione
Quando raccogli dati di analisi per le singole riproduzioni, puoi associare i dati di analisi delle riproduzioni ai metadati relativi ai contenuti multimediali riprodotti.
Si consiglia di impostare metadati specifici per i contenuti multimediali con MediaItem.Builder.setTag
.
Il tag multimediale fa parte dell'elemento EventTime
riportato per gli eventi non elaborati e una volta terminati PlaybackStats
, quindi può essere facilmente recuperato durante la gestione dei dati di analisi corrispondenti:
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. });
Report sugli eventi di analisi personalizzati
Nel caso in cui tu debba aggiungere eventi personalizzati ai dati di analisi, devi salvare questi eventi nella tua struttura dei dati e combinarli con i PlaybackStats
report in un secondo momento. Se può esserti di aiuto, puoi estendere DefaultAnalyticsCollector
per poter generare istanze EventTime
per i tuoi eventi personalizzati e inviarle
ai listener già registrati, come mostrato nell'esempio seguente.
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();