AdPlayingMonitor.java
Overview
`AdPlayingMonitor.java` defines the `AdPlayingMonitor` class, a specialized event listener that monitors the playback state of video advertisements (ads) within the media player environment. Its primary purpose is to observe the lifecycle of ad playback—detecting when an ad finishes or encounters errors—and to notify the finite state machine (FSM) controlling player states so it can transition appropriately. Additionally, it implements a workaround for corrupted ad streams that get stuck buffering by seeking forward to keep playback progressing.
This class extends `EventLogger`, inheriting the ability to log playback events, and integrates tightly with the FSM layer (`FsmAdController`/`FsmPlayer`) to maintain synchronization between ad playback status and player state transitions.
Class: AdPlayingMonitor
public class AdPlayingMonitor extends EventLogger
Description
`AdPlayingMonitor` listens to key playback events from the ad player, handling ad completion, playback errors, and dropped frames to ensure smooth ad playback and robust error recovery. It acts as an intermediary between ExoPlayer's ad playback events and the FSM controlling the ad state machine.
Properties
Property | Type | Description |
|---|---|---|
`fsmPlayer` | `FsmAdController` | Reference to the FSM ad controller/player instance. Used to invoke FSM state transitions based on playback events. |
Constructor
public AdPlayingMonitor(@NonNull FsmPlayer fsmPlayer)
Parameters:
fsmPlayer: An instance ofFsmPlayer(or subclass) responsible for managing ad playback states.
Description:
Initializes the monitor with a reference to the FSM player. Passesnullto the superclass constructor (EventLogger), indicating that no additional event listener is chained.Usage Example:
FsmPlayer myFsmPlayer = ...; // existing FSM player instance
AdPlayingMonitor adMonitor = new AdPlayingMonitor(myFsmPlayer);
Methods
1. onPlayerStateChanged
@Override
public void onPlayerStateChanged(EventTime eventTime, boolean playWhenReady, int playbackState)
Parameters:
eventTime: The event timestamp and context.playWhenReady: Indicates whether playback should proceed when ready.playbackState: Current playback state of the player (e.g.,Player.STATE_ENDED).
Description:
Invoked when the ad player's state changes. This method logs the event (via superclass), then checks if the ad playback has ended while the player was supposed to be playing (playWhenReady == true). If so, it notifies the FSM to remove the played ad and transition to the next state, effectively signaling that ad playback is complete.Behavior:
if (playbackState == Player.STATE_ENDED && playWhenReady == true) { fsmPlayer.removePlayedAdAndTransitToNextState(); }Usage:
This is a callback invoked by the ExoPlayer framework and should not be called directly.
2. onPlayerError
@Override
public void onPlayerError(EventTime eventTime, ExoPlaybackException error)
Parameters:
eventTime: The event timestamp and context.error: The playback exception encountered.
Description:
Called when the ad player encounters an error. After logging, it immediately commands the FSM to remove the problematic ad and transition to the next state, ensuring that playback is not stalled indefinitely due to ad errors.Usage:
Automatically invoked by ExoPlayer upon ad playback errors.
3. onDroppedVideoFrames
@Override
public void onDroppedVideoFrames(final EventTime eventTime, final int droppedFrames, final long elapsedM)
Parameters:
eventTime: The event timestamp and context.droppedFrames: Number of video frames dropped.elapsedM: Time elapsed in milliseconds.
Description:
Called when video frames are dropped during ad playback. This method logs the event and then callsseekOrSkip()to attempt recovery from potential playback stalls caused by corrupted video.Usage:
Invoked by ExoPlayer on frame drop detection.
4. seekOrSkip
private void seekOrSkip()
Description:
A workaround method to recover from corrupted ad videos that cause the player to get stuck in the buffering state indefinitely. It checks if the ad player is currently buffering; if so, it seeks forward by 1000 milliseconds or to the end of the ad duration, then resumes playback.Implementation Details:
Checks if
fsmPlayeris non-null.Retrieves the ad player from the FSM player's controller.
If the ad player is buffering (
ExoPlayer.STATE_BUFFERING), advances playback position by 1 second or until the ad's end.Sets
playWhenReadytotrueto resume playback.
Algorithm:
Get current playback position.
Add 1000ms to position, but don't exceed ad duration.
Seek to the new position.
Resume playback.
Usage:
Internal method called when video frames are dropped to attempt playback recovery.
Important Implementation Details
Tight FSM Integration:
The class relies on the FSM (fsmPlayer) to manage state transitions rather than directly controlling playback UI or user interactions.Error and Completion Handling:
Both ad playback completion and errors lead to FSM notification to remove played ads and move forward, maintaining smooth playback continuity.Buffering Recovery Hack:
TheseekOrSkip()method addresses a known issue where corrupted ads cause the player to buffer endlessly. By seeking forward, it attempts to bypass the problematic segment.Inheritance:
ExtendsEventLogger, so all playback events are logged for diagnostics or analytics purposes.
Interaction with Other System Components
FSM Player (
FsmPlayer/FsmAdController):AdPlayingMonitorholds a reference to the FSM player and invokes its methods to trigger state transitions upon ad playback events.ExoPlayer Ad Playback:
The monitor listens for playback state changes, errors, and frame drops from the ExoPlayer instance used to play ads.Playback Controller:
Accesses the ad player viafsmPlayer.getController().getAdPlayer()to control playback position during the buffering recovery.
Usage Example
// Assume existing FSM player instance managing ad playback
FsmPlayer fsmPlayer = ...;
// Create the AdPlayingMonitor with FSM reference
AdPlayingMonitor adPlayingMonitor = new AdPlayingMonitor(fsmPlayer);
// Register the monitor as a listener to the ExoPlayer ad player instance
SimpleExoPlayer adPlayer = fsmPlayer.getController().getAdPlayer();
adPlayer.addListener(adPlayingMonitor);
Once registered, `AdPlayingMonitor` automatically handles the lifecycle events of the ad playback, triggering FSM transitions upon ad completion or errors.
Mermaid Class Diagram
classDiagram
class AdPlayingMonitor {
+FsmAdController fsmPlayer
+AdPlayingMonitor(FsmPlayer fsmPlayer)
+void onPlayerStateChanged(EventTime eventTime, boolean playWhenReady, int playbackState)
+void onPlayerError(EventTime eventTime, ExoPlaybackException error)
+void onDroppedVideoFrames(EventTime eventTime, int droppedFrames, long elapsedM)
-void seekOrSkip()
}
AdPlayingMonitor --|> EventLogger
Explanation:
The diagram showsAdPlayingMonitorextendingEventLogger, holding a reference toFsmAdController(fsmPlayer). It exposes the main overridden event listener methods and a private helper methodseekOrSkip().
Summary
The `AdPlayingMonitor` class plays a critical role in the ad playback lifecycle within the media player architecture. By observing ad player events and integrating with the FSM, it ensures:
Timely transition of player states after ad completion.
Robust handling of ad playback errors.
Recovery from buffering stalls caused by corrupted ads.
Its design leverages ExoPlayer callbacks and FSM state management, contributing to a smooth and resilient advertisement viewing experience in the application.