EventLogger.java
Overview
`EventLogger` is a utility class designed to provide detailed logging of media playback events within an Android application using ExoPlayer. It implements multiple ExoPlayer listener interfaces, including `AnalyticsListener`, `MediaSourceEventListener`, `MetadataOutput`, and `ExtractorMediaSource.EventListener`, to track and log the lifecycle of media playback comprehensively.
The main purpose of this class is to aid developers and testers by emitting human-readable debug logs that describe player state changes, track selections, metadata processing, timeline updates, loading events, and errors. These logs facilitate debugging, performance monitoring, and deeper understanding of the playback pipeline without altering playback behavior.
Class: EventLogger
Package
`com.tubitv.media.utilities`
Implements
AnalyticsListenerMediaSourceEventListenerMetadataOutputExtractorMediaSource.EventListener
Primary Responsibilities
Listen to key ExoPlayer events.
Format event details into concise log statements.
Output logs via Android's
Logutility.Parse and log media metadata (e.g., ID3 tags, event messages).
Format timeline and track group information for easy interpretation.
Fields
Field | Type | Description |
|---|---|---|
`TAG` | `String` | Tag used for Android logging (`"EventLogger"`). |
`MAX_TIMELINE_ITEM_LINES` | `int` | Limits the number of timeline entries logged (set to 3). |
`TIME_FORMAT` | `NumberFormat` | Formats time values in seconds with 2 decimal places. |
`trackSelector` | `MappingTrackSelector` | Used to retrieve current track selection and capabilities. |
`window` | `Timeline.Window` | Helper object to access timeline window info. |
`period` | `Timeline.Period` | Helper object to access timeline period info. |
`startTimeMs` | `long` | Timestamp when the logger instance was created, for session-relative logging. |
Constructor
EventLogger(@Nullable MappingTrackSelector trackSelector)
Creates a new `EventLogger` instance to log ExoPlayer events.
**Parameters:**
trackSelector(MappingTrackSelectorornull): The track selector associated with the player. Used to log track information. Can benullif track details are not needed.
**Usage example:**
MappingTrackSelector trackSelector = ...; // Initialize track selector
EventLogger eventLogger = new EventLogger(trackSelector);
Key Static Utility Methods
These methods convert raw data from ExoPlayer into readable strings for logging.
getTimeString(long timeMs) : String
Returns a formatted string representation of the time in seconds with two decimal places.
Returns
"?"if the time is unspecified (C.TIME_UNSET).
**Example:**
String timeStr = getTimeString(12345); // "12.35"
getStateString(int state) : String
Maps ExoPlayer player states to short string codes:
State | Code |
|---|---|
`Player.STATE_BUFFERING` | "B" |
`Player.STATE_ENDED` | "E" |
`Player.STATE_IDLE` | "I" |
`Player.STATE_READY` | "R" |
Unknown / default | "?" |
getFormatSupportString(int formatSupport) : String
Maps `RendererCapabilities` format support constants to strings:
Format Support Constant | String |
|---|---|
`FORMAT_HANDLED` | "YES" |
`FORMAT_EXCEEDS_CAPABILITIES` | "NO_EXCEEDS_CAPABILITIES" |
`FORMAT_UNSUPPORTED_SUBTYPE` | "NO_UNSUPPORTED_TYPE" |
`FORMAT_UNSUPPORTED_TYPE` | "NO" |
Default | "?" |
getAdaptiveSupportString(int trackCount, int adaptiveSupport) : String
Human-readable representation of adaptive streaming support based on track count and adaptive support:
If fewer than 2 tracks:
"N/A"Otherwise, based on adaptive support constants:
ADAPTIVE_SEAMLESS→"YES"ADAPTIVE_NOT_SEAMLESS→"YES_NOT_SEAMLESS"ADAPTIVE_NOT_SUPPORTED→"NO"Default →
"?"
getTrackStatusString(TrackSelection selection, TrackGroup group, int trackIndex) : String
Returns `"[X]"` if the given track is enabled (selected), otherwise `"[ ]"`.
getTrackStatusString(boolean enabled) : String
Returns `"[X]"` if `enabled` is true, else `"[ ]"`.
Event Callbacks
The `EventLogger` implements many methods from ExoPlayer listener interfaces. Below are some of the most relevant and implemented ones with logging.
onLoadingChanged(EventTime eventTime, boolean isLoading)
Logs when the player starts or stops loading media.
**Log example:**
loading [true]
onPlayerStateChanged(EventTime eventTime, boolean playWhenReady, int playbackState)
Logs player state changes with session-relative timestamp, play/pause status, and state code.
**Example log:**
state [12.35, true, R]
12.35is seconds elapsed sinceEventLoggercreation.trueindicates playing.RmeansSTATE_READY.
onTimelineChanged(EventTime eventTime, int reason)
Logs timeline period and window counts and durations (up to 3 entries each).
**Example output:**
sourceInfo [periodCount=2, windowCount=1
period [60.00]
period [120.00]
window [180.00, true, false]
]
onPlayerError(EventTime eventTime, ExoPlaybackException e)
Logs player errors with stack trace and session timestamp.
onTracksChanged(EventTime eventTime, TrackGroupArray ignored, TrackSelectionArray trackSelections)
Logs detailed track info per renderer:
Track groups and their adaptive support.
Track status (enabled or not).
Format details and support status.
Metadata associated with selected tracks (logs first metadata found).
Also logs unassociated track groups (not linked to any renderer).
This method provides the most comprehensive insight into media tracks currently active and available.
onMetadata(Metadata metadata)
Logs metadata entries such as ID3 tags and event messages.
Delegates the actual parsing and printing to the private method `printMetadata(Metadata, String)`.
onLoadError(EventTime eventTime, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData, IOException error, boolean wasCanceled)
Logs internal errors related to media loading.
onLoadError(IOException error)
Logs internal errors related to loading outside the context of a specific event.
Private Helper Methods
printMetadata(Metadata metadata, String prefix)
Iterates through metadata entries and logs relevant information based on metadata type, including:
TextInformationFrameUrlLinkFramePrivFrameGeobFrameApicFrameCommentFrameId3FrameEventMessage
The method formats the log line to include fields like ID, value, URL, owner, MIME type, language, etc., prefixed for readability.
printInternalError(String type, Exception e)
Logs an internal error with the error type and stack trace, including the session timestamp.
getSessionTimeString() : String
Calculates the elapsed time in milliseconds since the `EventLogger` instance was created and formats it as a string.
Usage Example
This logger is typically registered as a listener on an ExoPlayer instance to monitor playback:
MappingTrackSelector trackSelector = new DefaultTrackSelector(context);
EventLogger eventLogger = new EventLogger(trackSelector);
ExoPlayer player = ExoPlayerFactory.newSimpleInstance(context, trackSelector);
player.addAnalyticsListener(eventLogger);
player.addMetadataOutput(eventLogger);
player.addListener(eventLogger);
As the player runs, `EventLogger` will log state changes, errors, track selections, and metadata to Android's logcat under the tag `"EventLogger"`.
Implementation Details and Algorithms
Uses
SystemClock.elapsedRealtime()to establish a session start timestamp to provide relative timing for events.Limits logging of timeline periods/windows to avoid excessive output.
Utilizes ExoPlayer's
MappingTrackSelectorandMappedTrackInfoclasses to interrogate the track groups and capabilities.Parses various ID3 metadata frames and event messages, supporting rich metadata logging.
Uses concise, single-character or short string codes for states to keep logs compact.
Implements multiple ExoPlayer event listener interfaces to cover a broad range of playback events.
Interaction with Other Components
ExoPlayer:
EventLoggeris tightly coupled to ExoPlayer’s event model and expects to be registered as a listener to receive callbacks.MappingTrackSelector: Used to extract detailed track selection and capability info during track changes.
Android Log: Outputs all logs to Android's
Logsystem, enabling viewing via logcat.MediaSource and ExtractorMediaSource: Receives load events and media period lifecycle events, although many are no-ops or placeholders.
Playback State Management and FSM: While
EventLoggerdoes not directly interact with FSM states, it provides a runtime trace of player states and errors that reflect FSM transitions and playback flow.Metadata Handlers: Parses metadata frames that may originate from media streams, augmenting playback insights.
Mermaid Class Diagram
classDiagram
class EventLogger {
-static TAG: String = "EventLogger"
-static MAX_TIMELINE_ITEM_LINES: int = 3
-static TIME_FORMAT: NumberFormat
-trackSelector: MappingTrackSelector
-window: Timeline.Window
-period: Timeline.Period
-startTimeMs: long
+EventLogger(MappingTrackSelector)
+onLoadingChanged(EventTime, boolean)
+onPlayerStateChanged(EventTime, boolean, int)
+onRepeatModeChanged(EventTime, int)
+onShuffleModeChanged(EventTime, boolean)
+onPositionDiscontinuity(EventTime, int)
+onSeekStarted(EventTime)
+onPlaybackParametersChanged(EventTime, PlaybackParameters)
+onSeekProcessed(EventTime)
+onTimelineChanged(EventTime, int)
+onPlayerError(EventTime, ExoPlaybackException)
+onTracksChanged(EventTime, TrackGroupArray, TrackSelectionArray)
+onLoadStarted(EventTime, LoadEventInfo, MediaLoadData)
+onLoadCompleted(EventTime, LoadEventInfo, MediaLoadData)
+onLoadCanceled(EventTime, LoadEventInfo, MediaLoadData)
+onMetadata(Metadata)
+onLoadError(EventTime, LoadEventInfo, MediaLoadData, IOException, boolean)
+onDownstreamFormatChanged(EventTime, MediaLoadData)
+onUpstreamDiscarded(EventTime, MediaLoadData)
+onMediaPeriodCreated(EventTime)
+onMediaPeriodReleased(EventTime)
+onReadingStarted(EventTime)
+onBandwidthEstimate(EventTime, int, long, long)
+onViewportSizeChange(EventTime, int, int)
+onNetworkTypeChanged(EventTime, NetworkInfo)
+onMetadata(EventTime, Metadata)
+onDecoderEnabled(EventTime, int, DecoderCounters)
+onDecoderInitialized(EventTime, int, String, long)
+onDecoderInputFormatChanged(EventTime, int, Format)
+onDecoderDisabled(EventTime, int, DecoderCounters)
+onAudioSessionId(EventTime, int)
+onAudioUnderrun(EventTime, int, long, long)
+onDroppedVideoFrames(EventTime, int, long)
+onVideoSizeChanged(EventTime, int, int, int, float)
+onRenderedFirstFrame(EventTime, Surface)
+onDrmKeysLoaded(EventTime)
+onDrmSessionManagerError(EventTime, Exception)
+onDrmKeysRestored(EventTime)
+onDrmKeysRemoved(EventTime)
+onLoadError(IOException)
-printMetadata(Metadata, String)
-printInternalError(String, Exception)
-getSessionTimeString(): String
-static getTimeString(long): String
-static getStateString(int): String
-static getFormatSupportString(int): String
-static getAdaptiveSupportString(int, int): String
-static getTrackStatusString(TrackSelection, TrackGroup, int): String
-static getTrackStatusString(boolean): String
}
Summary
`EventLogger.java` is a comprehensive logging utility class for ExoPlayer-based Android media playback applications. It provides rich, structured, and human-readable logs for player lifecycle events, track information, metadata, and errors. By implementing several ExoPlayer event listener interfaces, it acts as an observer of playback internals and outputs detailed diagnostics to Android's logging system. This facilitates easier debugging, monitoring, and maintenance of the media playback system.
Its design emphasizes non-intrusive logging that complements playback control layers, such as FSMs and UI controllers, by offering visibility into the underlying ExoPlayer operations without altering behavior. The class is extensible and can be attached to any ExoPlayer instance with or without a track selector to provide valuable insights during development or troubleshooting.