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


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:

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:

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:

Key states include:

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.

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

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

Midroll Ad Handling

VPAID Ads

Error Handling


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


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.