VPAID Ad Integration

This module provides support for playing VPAID-compliant video ads within the media player system by leveraging an Android WebView. VPAID (Video Player Ad-Serving Interface Definition) ads are interactive and scripted advertisements designed primarily for web environments. Integrating them into a native player requires embedding a WebView to host the ad content and manage communication between the JavaScript ad code and the native media playback finite state machine (FSM).


Core Concepts and Purpose


How the Module Works

1. WebView-Based VPAID Client (TubiVPAID)

2. VAST XML Data (Vastxml)

3. VPAID Playback Activity (WebviewActivity)


Interaction with Other Parts of the System


Important Concepts and Design Patterns


Code References Illustrating Key Points

JavaScript Interface Methods in TubiVPAID

These methods are called by the ad's JavaScript code within the WebView to notify the native layer of important events:

@JavascriptInterface
public void notifyVideoEnd() {
    mHandler.post(() -> {
        if (fsmPlayer != null) {
            fsmPlayer.removePlayedAdAndTransitToNextState();
        }
    });
}

@JavascriptInterface
public void notifyAdError(int code, String error) {
    mHandler.post(() -> {
        if (fsmPlayer != null) {
            fsmPlayer.removePlayedAdAndTransitToNextState();
        }
    });
}

@JavascriptInterface
public String getVastXml() {
    return vastXml;
}

VPAID State Managing WebView Playback (VpaidState)

This state pauses all native ExoPlayer instances, prepares the VPAID client, and switches UI visibility:

private void pausePlayerAndSHowVpaid(PlayerUIController controller, PlayerAdLogicController componentController,
        FsmPlayer fsmPlayer, AdMediaModel adMedia) {

    ExoPlayer moviePlayer = controller.getContentPlayer();
    if (moviePlayer != null && moviePlayer.getPlayWhenReady()) {
        moviePlayer.setPlayWhenReady(false);
    }

    ExoPlayer adPlayer = controller.getAdPlayer();
    if (adPlayer != null && adPlayer.getPlayWhenReady()) {
        adPlayer.setPlayWhenReady(false);
    }

    VpaidClient client = componentController.getVpaidClient();

    if (client != null) {
        MediaModel ad = adMedia.nextAD();
        if (ad == null) {
            return;
        }

        client.init(ad);

        controller.getExoPlayerView().setVisibility(View.INVISIBLE);

        WebView vpaidWebView = controller.getVpaidWebView();
        vpaidWebView.setVisibility(View.VISIBLE);
        vpaidWebView.bringToFront();
        vpaidWebView.invalidate();

        vpaidWebView.addJavascriptInterface(client, "TubiNativeJSInterface");
        vpaidWebView.loadUrl(fsmPlayer.getVPAID_END_POINT());

        ((TubiExoPlayerView) controller.getExoPlayerView()).getSubtitleView().setVisibility(View.INVISIBLE);
    }
}

Dependency Injection of VPAID Client (FSMModuleReal)

The module provides a scoped `VpaidClient` instance that links the WebView and FSM player:

@ActicityScope
@Provides
VpaidClient provideVpaidClient(FsmPlayer player) {
    return new TubiVPAID(webView, new Handler(Looper.getMainLooper()), player);
}

Visual Diagram: VPAID Ad Playback Sequence

sequenceDiagram
    participant FSM as FsmPlayer
    participant State as VpaidState
    participant UI as PlayerUIController
    participant VPAID as TubiVPAID (WebView)
    participant JS as VPAID JavaScript Player

    FSM->>State: Transition to VpaidState
    State->>UI: Pause ExoPlayer, hide video views
    State->>VPAID: init(adMedia)
    UI->>VPAID: Show WebView, add JS interface
    VPAID->>JS: Load VPAID endpoint URL with VAST XML
    JS->>VPAID: Call getVastXml()
    JS->>JS: Play VPAID ad
    JS->>VPAID: notifyVideoEnd() or notifyAdError()
    VPAID->>FSM: removePlayedAdAndTransitToNextState()
    FSM->>State: Transition to next state (e.g. MoviePlayingState)
    UI->>UI: Show ExoPlayer views

This sequence outlines how the FSM delegates VPAID ad playback to the WebView client and resumes normal playback after ad completion or error.


Summary

The VPAID Ad Integration module enables interactive VPAID video ads to play within the media player by embedding a WebView that hosts the VPAID JavaScript player. The `TubiVPAID` client manages the WebView configuration and communication with the FSM player, exposing JavaScript interface methods for event callbacks. The FSM transitions into a dedicated `VpaidState` to pause regular video playback and switch UI visibility to the WebView. Upon ad completion or error, the FSM is notified to continue playback flow seamlessly. The VAST XML ad data needed for VPAID playback is provided statically by the [Vastxml](/projects/288/68276) helper class. This design effectively bridges native playback and web-based ad interaction, ensuring extensible and robust ad integration within the system.