Adverts with Google IMA

This application inserts advertisements using the IMAWrapper class via the Google Interactive Media Ads (IMA) SDK to access ad servers that support VAST and VMAP.

For more information, see:

Prerequisites

The code for this feature is located in the dynamic-ads-ima folder in the example code zip file, which is included in the SDK package (opy-sdk-android-<version>-example-code.zip).

You also need an ad server already configured and knowledge of the ad tag URLs that will be used to access it.

This procedure assumes that you have an existing player based on the OpenTV Player Android SDK for which you want to enable ad insertion.

Procedure

The main stages are as follows:

Project setup

  1. Unzip the supplied example code zip file and extract the dynamic-ads-ima folder. This folder contains an Android Studio project for building example code with adverts fetched from a demo ad-server.

    • The project is based on the basic-playback project, with ad support built on top of it.
    • Within the Java source code of the project, the adverts folder contains the IMAWrapper package (in source-code) provided by Nagra. This package simplifies configuration and access to an ad-server, as well as playback and display of the adverts.
    • You may build upon this code, or use it as a reference for your application. See the Android SDK4 Integration Guide for more details.

    The following instructions show you how to modify your existing application to make use of the IMAWrapper package with the Google IMA libraries.

  2. In the application project you are building, update your Gradle sript to fetch the Google IMA Play Services libraries from the Google Maven repository.

    Add the repository:

    repositories {
      jcenter()
      mavenCentral()
    
    ... << other repositories omitted >> ...
    
      maven {
        url "https://maven.google.com/"
      }
    }
    

    Add the following third-party dependencies:

    ... <<details omitted >> ...
    
    dependencies {
      ... << other dependencies omitted >> ...
    
     implementation 'com.google.ads.interactivemedia.v3:interactivemedia:3.11.3'
      implementation 'com.google.android.gms:play-services-ads:11.8.0'
    }
    

    There is the potential for a clash between the versions of play-services-ads and play-services-cast-framework dependencies. Ideally the version of play-services-ads should be the latest from the v11 series (11.8.0), but for this to align with the same version of play-services-cast-framework in an application, it means the Android build tools version needs to be 27.

Enable playback of linear adverts

Edit the layout XML to support linear ads

For each layout and screen density that needs to support ads, you may need to edit the layout files.

The following example shows a layout identified as ad_container being allocated for the rendering of linear adverts.

This must be separate from the container of NMPVideoView since Google IMA overrides touch event handling when it renders adverts and when those complete the control bar must not be impacted.

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:id="@+id/nmpVideoViewContainer"
        >

      <nagra.nmp.sdk.NMPVideoView
          android:id="@+id/surfaceview"
          android:layout_width="fill_parent"
          android:layout_height="fill_parent" />
    ...
    </RelativeLayout>

    <RelativeLayout
        android:id="@+id/ad_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@null"/>
    ...

Update the player's Java source code.

  1. Import the IMAWrapper classes (adjust the package path if you changed the source code).

    import com.nagra.example.dynamicima.adverts.IMAWrapper;
    import com.nagra.example.dynamicima.adverts.IMAWrapperDelegate;
    

    In the code for the class that extends Activity, two additional attributes are required, one for IMAWrapper and one for the IMAWrapperDelegate.

  2. Implement the wrapper delegate.

    The delegate needs to implement functions for the following to handle the interactions between the adverts manager and the application.

    private IMAWrapperDelegate mIMADelegate = new IMAWrapperDelegate() {
      @Override
      public void resumeContent(IMAWrapperResumeType xResumeType) {
        // Warning: Consider whether it is appropriate to (re-)start here
        // It is advisable to check if the content has completed
        mVideoView.start();
      }
    
      @Override
      public void pauseContent() {
        mVideoView.pause();
      }
    
      @Override
      public long getContentPosition() {
        return mVideoView.getCurrentPosition();
      }
    
      @Override
      public long getContentDuration() {
        if (null != mVideoView) {
          return mVideoView.getDuration();
        }
        return 0;
      }
    
      @Override
      public void advertStarted() {
        ...
      }
    
      @Override
      public void completedCallback() {
        ...
      }
    
      @Override
      public void logEvent(Map<String, String> xAdData) {
        ...
      }
      ...
    }
    

    To ensure that pre-roll adverts play before the content, you are advised to hold back the NMPVideoView.start() method until the pre-roll adverts have played, and not played as soon as it would have been if there were no adverts. So that the content does not re-start after post-roll adverts play, it is advised that a check is made to see if the content has already completed.
    Between adverts in a pod, or just before the start of an advert, a freeze frame of the content will be seen unless action is taken to avoid it. If you prefer to display a black frame, remove the video view when adverts start and reinstate it on completion.
    Any latency with the Google IMA system starting playback of an advert may elongate the freeze frame or black screen. To reduce the black frame time, the remove action can be taken as late as possible, such as on receipt of the Ad Started event. You can do this by removing the view when the IMAWrapperDelegate advertStarted() method is called.
    To log more information about the Google IMA system, you can implement appropriate code in the logEvent() method.
    Google IMA reports errors via the IMAWrapper and this method in the IMAWrapperDelegate.

  3. Instantiate the wrapper.

    During creation of this activity, such as within the onCreate() method, you must create and configure the IMAWrapper member and then call startAdsServices() on it, passing the user interface ViewGroup set aside for linear adverts.

    ViewGroup adUiContainerViewGroup = (ViewGroup) findViewById(R.id.nmpVideoViewContainer);
    
    mIMAWrapper = new IMAWrapper(mContext);
    mIMAWrapper.startAdsServices(adUiContainerViewGroup);
    

    The call to startAdsServices() is slightly different if companion ads are also used – see below.

  4. Associate the delegate to the wrapper.

    The wrapper needs to be made aware of the delegate via the setDelegate() method:

    mIMAWrapper.setDelegate(mIMADelegate);
    

    Alternatively, you can pass the delegate to the wrapper's contructor when you create it:
    mIMAWrapper = new IMAWrapper(mContext, mIMADelegate);

  5. Request the ads.

    Pass the advert tag URI into the IMAWrapper via the requestAds() method:

    mIMAWrapper.requestAds(xAdvertTag);
    

    You should call requestAds() as early as possible to minimise latency in retrieving the ads.

Replacing playback content (Zapping)

Destroying the IMAWrapper instance cancels any scheduled ads and terminates a playing ad if it exists.
If you keep the IMAWrapper instance, you must request a new ad session with requestAds() whenever the playback content changes. A stopIMAServices() method is provided in the IMAWrapper to clean up an old configuration and its associated instances.

For a better user experience, you are advised to explicitly pause the new content after the new URI is set to allow for pre-

Enable companion adverts

Companion adverts can be added if the screen layout and real estate of the application allow them. Multiple differently sized slots can be set aside for companion adverts to appear in. The dimensions selected depend on the style of companion adverts that you want to display. In the following examples, more than one configuration is shown and provided as a List of IMAWrapperCompanionAdContainer objects. An instance of one of these objects is created by providing a pair of integers for the dimensions and a reference to the ViewGroup.

There maybe subtle differences in how the application is organised, so there are alternatives for how companion adverts are configured and enabled, but in both cases you provide a List of IMAWrapperCompanionAdContainer objects, just at different points.

This procedure assumes you have already enabled linear ads, as described above.

  1. Generate companion ad list.

    ViewGroup companionAdPlaceholder = (ViewGroup) findViewById(R.id.companionAdSlot);
    ViewGroup anotherCompanionAdPlaceholder = (ViewGroup) findViewById(R.id.anotherCompanionAdSlot);
    
    List<IMAWrapper.IMAWrapperCompanionAdContainer> companionList = new ArrayList<IMAWrapper.IMAWrapperCompanionAdContainer>();
    
    companionList.add(new IMAWrapper.IMAWrapperCompanionAdContainer(
        new Pair<Integer, Integer>(300, 250), companionAdPlaceholder));
    
    companionList.add(new IMAWrapper.IMAWrapperCompanionAdContainer(
        new Pair<Integer, Integer>(728, 90), anotherCompanionAdPlaceholder));
    
  2. Edit the layout XML to support companion ads.

    The following example provides a pair of companion advert slots with different dimensions to accommodate different companion advert sizes. The number and dimensions of slots provided will depend on the style of adverts required to be shown and the available screen real estate.

    References to these slots and their dimensions must be provided to the IMAWrapper in order to enable companion adverts.

    <LinearLayout
        android:id="@+id/companionAdSlot"
        android:layout_width="300px"
        android:layout_height="250px"
        android:background="@android:color/transparent"
        android:gravity="center"
        android:orientation="horizontal"
        android:visibility="gone"/>
    
    <LinearLayout
        android:id="@+id/anotherCompanionAdSlot"
        android:layout_width="728px"
        android:layout_height="90px"
        android:background="@android:color/transparent"
        android:gravity="center"
        android:orientation="horizontal"
        android:visibility="gone"/>
    
  3. Set up the companion ads.

    • Simple case: overlay.
      In a simple application, the activity layout could be the video view and companion ad slots are configured together such that the video is overlaid with a companion advert when one is rendered.
      In this case, the IMAWrapper allows for the linear advert overlay and companion adverts to be configured in one go. The List can be provided to the IMAWrapper at the same time as the linear adverts ViewGroup in the call to startAdsServices():

      mIMAWrapper.startAdsServices(adUiContainerViewGroup, companionList);
      
    • More complex case: activity fragments.
      A more complex application may have activity fragments that are put together to form the overall user experience.
      Here, it may be more complicated to configure the companion advert placeholders and the main video advert overlay together, so the IMAWrapper allows for this to be enabled separately with a later call to setCompanionAdViews():

      mIMAWrapper.setCompanionAdViews(companionList);