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

Primary Responsibilities

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:**

**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.

**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:


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]

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:

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:

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


Interaction with Other Components


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.


End of EventLogger.java documentation.