Finite State Machine Playback
Overview
The **Finite State Machine (FSM) Playback** module is the core component responsible for managing the lifecycle and transitions of media playback states within the media player system. It orchestrates playback of both content and advertisements, ensuring a smooth user experience through clearly defined states and transitions. This module solves the complex problem of integrating video content playback with dynamic ad insertion (preroll, midroll, postroll), including support for VPAID ads and cue point-based ad triggering, while handling errors and lifecycle changes gracefully.
Core Concepts and Purpose
State-driven playback management: Playback is controlled by a finite set of states, each encapsulating specific player behavior (e.g., fetching cue points, playing ads, playing content).
Seamless transitions: The FSM handles transitions triggered by input events (e.g., ad received, ad finished, error), enabling smooth switching between content and ads.
Ad and cue point integration: The FSM fetches cue points to know when ads should play and retrieves ads accordingly, integrating these asynchronously without disrupting content playback.
VPAID support: Special handling for VPAID ads played through a WebView interface is included as part of the FSM.
Error handling and recovery: The FSM detects errors in ad retrieval or playback and transitions to appropriate fallback states.
Lifecycle awareness: Transitions respect the host activity lifecycle, avoiding state changes when the UI is not visible or active.
How the Module Works
FSM Player (FsmPlayer)
`FsmPlayer` is the abstract core class implementing the FSM interface that manages playback state transitions and callback handling for ad retrieval. It has the following key responsibilities:
Maintaining current state (
State currentState) representing the player’s status.Holding references to controllers for UI (
PlayerUIController) and ad logic (PlayerAdLogicController).Managing media models for content (
MediaModel movieMedia) and ads (AdMediaModel adMedia).Interacting with ad server interfaces (
AdInterface) and retrievers (AdRetriever,CuePointsRetriever) to fetch ads and cue points.Controlling state transitions via the
transit(Input input)method, which delegates to the current state to determine the next state.
Key method excerpts:
public void transit(Input input) {
if (currentState != null) {
transitToState = currentState.transformToState(input, factory);
} else {
transitToState = factory.createState(initializeState());
}
if (transitToState != null) {
currentState = transitToState;
} else {
currentState = factory.createState(MoviePlayingState.class);
}
currentState.performWorkAndUpdatePlayerUI(this);
}
This mechanism ensures that each input event causes a well-defined state change or defaults to the content playing state if no valid transition exists.
Concrete FSM Player (FsmPlayerImperial)
`FsmPlayerImperial` extends `FsmPlayer` and implements the `CuePointCallBack` interface, adding logic to handle cue points received from the ad server:
It processes cue points, detects if preroll ads exist (a cue point at 0), and updates the cue point monitor accordingly.
Triggers transitions based on presence or absence of preroll ads.
Excerpt:
public void onCuePointReceived(long[] cuePoints) {
if (hasPrerollAd(cuePoints)) {
updateCuePointsWithRemoveFirstCue(cuePoints, true);
transit(Input.HAS_PREROLL_AD);
} else {
updateCuePointsWithRemoveFirstCue(cuePoints, false);
transit(Input.NO_PREROLL_AD);
}
}
State Management
Each playback state is represented by a class implementing the `State` interface (usually extending `BaseState`). States encapsulate:
Transition logic (
transformToState(Input input, StateFactory factory)): Defines how the FSM moves to other states in response to inputs.State behavior (
performWorkAndUpdatePlayerUI(FsmPlayer fsmPlayer)): Executes the state’s work and updates UI or playback accordingly.
Key states include:
FetchCuePointState
Initiates fetching cue points from the ad server to determine ad insertion times. Transitions to preroll ad fetching if preroll exists or directly to content playback otherwise.MakingPrerollAdCallState
Fetches preroll ads from the ad server based on cue point 0. Upon receiving ads, transitions to ad playing state.MakingAdCallState
Fetches midroll or other ads triggered by cue points during playback. On ad reception, transitions to receive ad state.ReceiveAdState
Prepares the player for ad playback; monitors player state for errors.AdPlayingState
Plays back ads using the ad player instance, pausing content playback. Manages ad playback UI updates and hides subtitles.VpaidState
Manages playing VPAID ads through a WebView interface, pausing both content and ad players, and showing the ad WebView.MoviePlayingState
Plays the main content, resuming playback after ads finish, hiding ad UI components, and restoring subtitles as needed.FinishState
Represents the terminal state after content playback ends.VastAdInteractionSandBoxState
Handles ad interaction UI sandbox for users clicking on ads.
Each state defines valid transitions triggered by `Input` enums such as `MAKE_AD_CALL`, `AD_RECEIVED`, `AD_FINISH`, `VPAID_FINISH`, `ERROR`, etc., ensuring predictable and manageable playback flow.
Example from `AdPlayingState` transitions:
switch (input) {
case NEXT_AD:
return factory.createState(AdPlayingState.class);
case AD_CLICK:
return factory.createState(VastAdInteractionSandBoxState.class);
case AD_FINISH:
return factory.createState(MoviePlayingState.class);
case VPAID_MANIFEST:
return factory.createState(VpaidState.class);
}
State Factory (StateFactory)
The `StateFactory` is responsible for creating and caching singleton instances of state classes to optimize resource usage and maintain consistent state objects.
Supports overriding default state classes with custom implementations.
Uses reflection to instantiate states lazily and caches instances for reuse.
Excerpt:
public State createState(@NonNull Class classType) {
Class finalClassType = convertToCustomClass(classType);
if (finalClassType == null) {
finalClassType = classType;
}
State buildState = getCacheInstance(finalClassType);
if (buildState == null) {
Constructor<?> ctor = finalClassType.getConstructor();
buildState = (State) ctor.newInstance();
setCacheInstance(finalClassType, buildState);
}
return buildState;
}
This design allows flexible extension of state behavior and ensures efficient state management.
Module Interactions
FSM Player and States:
FsmPlayerholds the current state and triggers transitions based on playback events and inputs. States execute playback logic and UI updates.Ad and Cue Point Interfaces: The FSM uses
AdInterfaceandCuePointsRetrieverto asynchronously fetch ad and cue point data, receiving callbacks to trigger state changes.Player Controllers:
PlayerUIControllerandPlayerAdLogicControllermanage ExoPlayer instances for content and ads, and update UI elements. FSM states interact with these controllers to prepare, play, pause, or stop media.VPAID Integration: The
VpaidStatemanages VPAID ads via aVpaidClientand a WebView, coordinating with the FSM and controllers to pause normal playback and show the interactive ad.Lifecycle Awareness: FSM transitions respect the Android lifecycle (
Lifecycle), preventing transitions when the UI is not active.
Illustration from `FsmPlayer`:
if (getLifecycle() != null && !getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) {
return; // avoid transitions if activity is stopped
}
Key Functional Workflows
Initialization and Playback Start
FSM initializes with
FetchCuePointStateto retrieve cue points.Based on cue points (e.g., preroll at 0), FSM transitions to
MakingPrerollAdCallStateor directly toMoviePlayingState.Preroll ads are fetched asynchronously; upon receipt, FSM enters
AdPlayingStateto play ads.After ads finish, FSM transitions back to
MoviePlayingStatefor content playback.
Midroll Ad Handling
The
CuePointMonitorlistens during content playback.Upon reaching cue points, FSM transitions to
MakingAdCallStateto fetch midroll ads.Received ads trigger
ReceiveAdStateand thenAdPlayingState.After ads finish, FSM returns to content playback.
VPAID Ads
When an ad is VPAID, FSM transitions to
VpaidState.Both content and ad players pause.
VPAID ads are loaded into a WebView controlled by
VpaidClient.FSM receives callbacks on ad completion or errors to resume playback or handle failures.
Error Handling
Errors in ad fetching or playback trigger transitions to error handling states or fallback to content playback.
FSM ensures the player recovers gracefully or finishes playback cleanly.
Visual Diagram: FSM Playback Workflow
flowchart TD
Start[Initialize Player]
Start --> FetchCuePoints[Fetch Cue Points]
FetchCuePoints -->|Has Preroll Ad| MakePrerollAdCall[Make Preroll Ad Call]
FetchCuePoints -->|No Preroll Ad| MoviePlaying[Play Movie]
MakePrerollAdCall --> ReceivePrerollAd[Receive Preroll Ad]
ReceivePrerollAd --> PlayPrerollAd[Play Preroll Ad]
PlayPrerollAd --> MoviePlaying
MoviePlaying --> CheckCuePoints[Check Cue Points During Playback]
CheckCuePoints -->|Cue Point Reached| MakeAdCall[Make Midroll Ad Call]
MakeAdCall --> ReceiveAd[Receive Ad]
ReceiveAd --> PlayAd[Play Ad]
PlayAd --> MoviePlaying
MoviePlaying --> End[Movie Finished]
PlayAd -->|Ad Finished| MoviePlaying
PlayPrerollAd -->|Ad Finished| MoviePlaying
MakeAdCall -->|No Ad| MoviePlaying
FetchCuePoints -->|Error| ErrorState[Error Handling]
MakePrerollAdCall -->|Error| ErrorState
MakeAdCall -->|Error| ErrorState
ErrorState --> End
Summary of Important Concepts
Input-driven transitions: The FSM uses an
Inputenum to trigger state changes.State encapsulation: Each state encapsulates specific behavior and transitions, promoting modularity and clarity.
Singleton state instances:
StateFactorycaches state instances to avoid repeated instantiations.Separation of concerns: FSM handles logic and state, controllers handle UI and player instances, and ad/cue point retrievers handle network requests.
Support for various ad types: Including standard video ads and VPAID interactive ads.
Lifecycle integration: Ensures transitions only occur when the UI is active to prevent illegal state changes.
Resume position management: FSM tracks and updates playback resume positions for both content and ads to support seamless user experience.
This detailed explanation captures the essence, workflow, and interactions of the Finite State Machine Playback module within the media player system, supported by referenced code and a visualization diagram.