ExoPlayer supporta un'ampia gamma di esigenze di analisi della riproduzione. In definitiva, l'analisi si occupa di raccogliere, interpretare, aggregare e riepilogare i dati delle riproduzioni. Questi dati possono essere utilizzati sul dispositivo, ad esempio per il logging, il debug o per informare le decisioni di riproduzione future, oppure possono essere inviati a un server per monitorare le riproduzioni su tutti i dispositivi.
In genere, un sistema di analisi deve prima raccogliere gli eventi e poi elaborarli ulteriormente per renderli significativi:
- Raccolta di eventi:
per farlo, registra un
AnalyticsListener
in un'istanzaExoPlayer
. Gli ascoltatori di analisi registrati ricevono gli eventi man mano che si verificano durante l'utilizzo del player. Ogni evento è associato all'elemento media corrispondente nella playlist, nonché alla posizione di riproduzione e ai metadati del timestamp. - Elaborazione degli eventi: alcuni sistemi di analisi caricano gli eventi non elaborati su un server, con tutta l'elaborazione degli eventi eseguita lato server. È anche possibile elaborare gli eventi sul
dispositivo, il che potrebbe essere più semplice o ridurre la quantità di informazioni
che devono essere caricate. ExoPlayer fornisce
PlaybackStatsListener
, che consente di eseguire i seguenti passaggi di elaborazione:- Interpretazione degli eventi: per essere utili a fini di analisi, gli eventi devono essere interpretati nel contesto di una singola riproduzione. Ad esempio, l'evento grezzo di una variazione dello stato del player in
STATE_BUFFERING
può corrispondere al buffering iniziale, a un nuovo buffering 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 impiegato in ogni stato di riproduzione. Il risultato è un insieme di base di valori di dati di analisi per una singola riproduzione.
- Aggregazione: questo passaggio combina i dati di analisi di più letture, 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 di dati di analisi di base in altri modi. Le metriche di riepilogo possono essere calcolate per una o più riproduzioni.
- Interpretazione degli eventi: per essere utili a fini di analisi, gli eventi devono essere interpretati nel contesto di una singola riproduzione. Ad esempio, l'evento grezzo di una variazione dello stato del player in
Raccolta di eventi con AnalyticsListener
Gli eventi di riproduzione non elaborati del player vengono registrati nelle implementazioni AnalyticsListener
. Puoi aggiungere facilmente il tuo ascoltatore 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) {} });
L'oggetto EventTime
passato a ogni callback associa l'evento a un elemento media della playlist, nonché alla posizione di riproduzione e ai metadati del timestamp:
realtimeMs
: l'ora dell'evento in ora standard.timeline
,windowIndex
emediaPeriodId
: definisce la playlist e l'elemento all'interno della playlist a cui appartiene l'evento.mediaPeriodId
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 al momento in cui 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 da quello 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 la durata totale della riproduzione.
- Metriche sulla qualità di riproduzione adattiva, ad esempio la risoluzione video media.
- Metriche relative alla qualità del rendering, ad esempio la frequenza dei frame interrotti.
- Metriche sull'utilizzo delle risorse, ad esempio il numero di byte letti sulla rete.
Puoi trovare un elenco completo dei conteggi e delle metriche derivate disponibili nel
PlaybackStats
Javadoc.
PlaybackStatsListener
calcola un valore di PlaybackStats
separato 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 completate e utilizzare EventTime
passato al callback per identificare la riproduzione completata. È possibile aggregare i dati di analisi per più riproduzioni. Puoi anche eseguire 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 potrebbe verificarsi un overhead di memoria sconosciuto a seconda della durata della riproduzione e del numero di eventi. Pertanto, devi 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 di giocare | 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 finali | ENDED , STOPPED , FAILED , ABANDONED |
L'intenzione di riprodurre contenuti da parte dell'utente è importante per distinguere i momenti in cui l'utente stava
attivo in attesa che la riproduzione continuasse dai tempi di attesa passivi. Ad esempio,
PlaybackStats.getTotalWaitTimeMs
restituisce il tempo totale trascorso negli stati
JOINING_FOREGROUND
, BUFFERING
e SEEKING
, ma non il momento in cui
la riproduzione è stata messa in pausa. Analogamente, PlaybackStats.getTotalPlayAndWaitTimeMs
restituirà il tempo totale con l'intenzione di giocare da parte dell'utente, ovvero il tempo di attesa attivo totale e il tempo totale trascorso nello stato PLAYING
.
Eventi elaborati e interpretati
Puoi registrare gli eventi elaborati e interpretati utilizzando PlaybackStatsListener
con keepHistory=true
. Il PlaybackStats
risultante conterrà i seguenti elenchi di eventi:
playbackStateHistory
: un elenco ordinato degli stati di riproduzione estesa con ilEventTime
a partire dal quale sono stati applicati. Puoi anche utilizzarePlaybackStats.getPlaybackStateAtTime
per cercare lo stato in un determinato orario di orologio reale.mediaTimeHistory
: una cronologia di coppie di ora del tempo reale e ora dei contenuti multimediali che ti consente di ricostruire quali parti dei contenuti multimediali sono state riprodotte a quale ora. Puoi anche usarePlaybackStats.getMediaTimeMsAtRealtimeMs
per cercare il punto di riproduzione in un determinato orario.videoFormatHistory
eaudioFormatHistory
: elenchi ordinati dei formati video e audio utilizzati durante la riproduzione con la dataEventTime
in cui sono stati resi disponibili.fatalErrorHistory
enonFatalErrorHistory
: elenchi ordinati di errori irreversibili e non irreversibili con ilEventTime
in cui si sono verificati. Gli errori irreversibili sono quelli che hanno interrotto la riproduzione, mentre gli errori non irreversibili potrebbero essere stati recuperabili.
Dati analitici relativi alla riproduzione singola
Questi dati vengono raccolti automaticamente se utilizzi PlaybackStatsListener
, anche con keepHistory=false
. I valori finali sono i campi pubblici che puoi trovare nella documentazione Javadoc di PlaybackStats
e le durate degli stati 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);
Dati e analisi aggregati di più riproduzioni
Puoi combinare più PlaybackStats
chiamando
PlaybackStats.merge
. Il PlaybackStats
risultante conterrà i dati aggregati di tutte le riproduzioni unite. Tieni presente che non conterrà la cronologia dei
singoli eventi di riproduzione, poiché questi eventi non possono essere aggregati.
È possibile utilizzare PlaybackStatsListener.getCombinedPlaybackStats
per ottenere una visualizzazione aggregata di tutti i dati di analisi raccolti durante il ciclo di vita di un PlaybackStatsListener
.
Metriche di riepilogo calcolate
Oltre ai dati di analisi di base, PlaybackStats
fornisce 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 i dati e analisi per le singole riproduzioni, ti consigliamo di associarli ai metadati dei contenuti multimediali riprodotti.
Ti consigliamo di impostare i metadati specifici dei contenuti multimediali con MediaItem.Builder.setTag
.
Il tag media fa parte di EventTime
registrato per gli eventi non elaborati e al termine di PlaybackStats
, pertanto 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. });
Generazione di report sugli eventi di analisi personalizzati
Se devi aggiungere eventi personalizzati ai dati di analisi, devi salvarli nella tua struttura di dati e combinarli con i dati registrati in un secondo momento.PlaybackStats
Se ti è utile, puoi estendere DefaultAnalyticsCollector
per poter generare istanze EventTime
per i tuoi eventi personalizzati e inviarli
gli ascoltatori 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();