ExoPlayer IMA 拡張機能を使ってみる

ExoPlayer は、Android 用のアプリレベルのメディア プレーヤーです。このガイドでは、IMA Android DAI SDK をラップする ExoPlayer IMA 拡張機能を使用して、広告とコンテンツの両方を含むメディア ストリームをリクエストして再生する方法について説明します。

この拡張機能には次のようなメリットがあります。

  • IMA と機能を統合するために必要なコードが簡素化されます。
  • 新しいバージョンの IMA へのアップデートに必要な開発時間を短縮できます。

ExoPlayer IMA 拡張機能は、HLS と DASH ストリーミング プロトコルをサポートしています。概要は次のとおりです。

ExoPlayer-IMA 拡張機能のストリームのサポート
ライブ配信 VOD ストリーム
HLS チェックマーク チェックマーク
DASH チェックマーク チェックマーク

DASH ライブ ストリームは ExoPlayer-IMA バージョン 1.1.0 以降でサポートされています。

このガイドは ExoPlayer ガイドに基づいており、完全なアプリを作成して拡張機能を統合する方法について説明します。完全なサンプルアプリの例については、GitHub の ExoPlayerExample をご覧ください。

前提条件

新しい Android Studio プロジェクトの作成

Android Studio プロジェクトを作成する手順は次のとおりです。

  • Android Studio を起動します。
  • [Start a new Android Studio project] を選択します。
  • [プロジェクトの選択] ページで、[No Activity] テンプレートを選択します。
  • [次へ] をクリックします。
  • [Configure your project] ページでプロジェクトに名前を付け、言語として Java を選択します。

  • [完了] をクリックします。

ExoPlayer IMA 拡張機能をプロジェクトに追加する

拡張機能のインポートをアプリレベルの build.gradle ファイルの dependencies セクションに追加します。

Multidex を使用するようにアプリを構成し、有効にします。これは、拡張機能のサイズのために必要であり、minSdkVersionAndroid 4.4W(API レベル 20)以下に設定されているアプリでは必須です。

次の例をご覧ください。

app/build.gradle

android {

  ...

  defaultConfig {
      applicationId "com.google.ads.interactivemedia.v3.samples.videoplayerapp"
      minSdkVersion 19
      targetSdkVersion 34
      multiDexEnabled true
      versionCode 1
      versionName "1.0"
  }

    ...
}
dependencies {
    implementation 'androidx.multidex:multidex:2.0.1'
    implementation 'androidx.media3:media3-ui:1.1.1'
    implementation 'androidx.media3:media3-exoplayer:1.1.1'
    implementation 'androidx.media3:media3-exoplayer-hls:1.1.1'
    implementation 'androidx.media3:media3-exoplayer-dash:1.1.1'

    // Adding the ExoPlayer IMA extension for ads will also include the IMA
    // SDK as a dependency.
    implementation 'androidx.media3:media3-exoplayer-ima:1.1.1'
}

IMA SDK で広告のリクエストに必要なユーザー権限を追加します。

app/src/main/AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.project name">

    <!-- Required permissions for the IMA SDK -->
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

    ...

</manifest>

インテント宣言を追加する

Android 11(API レベル 30)以降をターゲットとするアプリの場合、IMA SDK の現行バージョンおよび最新バージョンでは、ウェブリンクを開くためにインテントを明示的に宣言する必要があります。広告のクリックスルー([詳細] ボタンをクリックするユーザー)を有効にするには、次のスニペットをアプリのマニフェスト ファイルに追加します。

  <?xml version="1.0" encoding="utf-8"?>
  <manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.example.project name">

      ...

    </application>

    <queries>
      <intent>
          <action android:name="android.intent.action.VIEW" />
          <data android:scheme="https" />
      </intent>
      <intent>
          <action android:name="android.intent.action.VIEW" />
          <data android:scheme="http" />
      </intent>
    </queries>
  </manifest>

ExoPlayer の UI を設定する

ExoPlayer が使用する PlayerView オブジェクトを作成します。

androidx.constraintlayout.widget.ConstraintLayoutLinearLayout に変更します。これは ExoPlayer IMA 拡張機能に推奨されています。

次の例をご覧ください。

app/src/main/res/layout/activity_my.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:background="@android:color/black"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MyActivity"
    tools:ignore="MergeRootFrame">

    <androidx.media3.ui.PlayerView
        android:id="@+id/player_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

ストリーム パラメータを追加する

プロジェクトをテストするためのストリーム アセットのサンプルについては、IMA ストリームのサンプルページをご覧ください。独自のストリームの設定については、DAI に関するアド マネージャーのセクションをご覧ください。

このステップではライブ ストリームの設定について説明しますが、ExoPlayer IMA 拡張機能は DAI VOD ストリームもサポートしています。アプリが VOD ストリームを処理するために必要な変更については、ビデオ オンデマンド(VOD)ストリームの手順をご覧ください。

ExoPlayer IMA 拡張機能をインポートする

ExoPlayer 拡張機能のインポート ステートメントを追加します。

次のプライベート変数を MyActivity.java に追加します。

Big Buck Bunny (Live) HLS ストリームのアセットキーを追加して、このストリームでテストします。他にも、IMA のサンプル ストリーム ページでテストできるストリームをご覧いただけます。

AdsLoader の状態の保存と取得を行う KEY_ADS_LOADER_STATE 定数を作成します。

次の例をご覧ください。

app/src/main/java/com/example/project name/MyActivity.java


import static androidx.media3.common.C.CONTENT_TYPE_HLS;

import android.app.Activity;
import android.net.Uri;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.annotation.OptIn;
import androidx.media3.common.MediaItem;
import androidx.media3.common.util.Util;
import androidx.media3.datasource.DataSource;
import androidx.media3.datasource.DefaultDataSource;
import androidx.media3.exoplayer.ExoPlayer;
import androidx.media3.exoplayer.ima.ImaServerSideAdInsertionMediaSource;
import androidx.media3.exoplayer.ima.ImaServerSideAdInsertionUriBuilder;
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory;
import androidx.media3.exoplayer.util.EventLogger;
import androidx.media3.ui.PlayerView;
import androidx.multidex.MultiDex;

...

public class MyActivity extends Activity {

  private static final String KEY_ADS_LOADER_STATE = "ads_loader_state";
  private static final String SAMPLE_ASSET_KEY = "c-rArva4ShKVIAkNfy6HUQ";

  private PlayerView playerView;
  private ExoPlayer player;
  private ImaServerSideAdInsertionMediaSource.AdsLoader adsLoader;
  private ImaServerSideAdInsertionMediaSource.AdsLoader.State adsLoaderState;

}

adsLoader インスタンスを作成する

onCreate メソッドを上書きして PlayerView を検出し、保存されている AdsLoader.State を確認します。これは、adsLoader オブジェクトの開始時に使用できます。

また、アプリのメソッド数と minSdkVersion で必要な場合は、Multidex を有効にします(ステップ 2 を参照)。

次の例をご覧ください。

app/src/main/java/com/example/project name/MyActivity.java

...

public class MyActivity extends Activity {

  private static final String KEY_ADS_LOADER_STATE = "ads_loader_state";
  private static final String SAMPLE_ASSET_KEY = "c-rArva4ShKVIAkNfy6HUQ";

  private PlayerView playerView;
  private ExoPlayer player;
  private ImaServerSideAdInsertionMediaSource.AdsLoader adsLoader;
  private ImaServerSideAdInsertionMediaSource.AdsLoader.State adsLoaderState;

  @Override
  protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_my);
    MultiDex.install(this);

    playerView = findViewById(R.id.player_view);

    // Checks if there is a saved AdsLoader state to be used later when
    // initiating the AdsLoader.
    if (savedInstanceState != null) {
      Bundle adsLoaderStateBundle = savedInstanceState.getBundle(KEY_ADS_LOADER_STATE);
      if (adsLoaderStateBundle != null) {
        adsLoaderState =
            ImaServerSideAdInsertionMediaSource.AdsLoader.State.CREATOR.fromBundle(
                adsLoaderStateBundle);
      }
    }
  }

}

プレーヤーを初期化するメソッドを追加する

プレーヤーを初期化するメソッドを追加して、次の操作を行います。

  • AdsLoader インスタンスを作成します。
  • ExoPlayer を作成します。
  • ライブ ストリームのアセットキーで MediaItem を作成します。
  • MediaItem をプレーヤーに設定します。

次の例をご覧ください。

app/src/main/java/com/example/project name/MyActivity.java

public class MyActivity extends Activity {

  ...

  
  // Create a server side ad insertion (SSAI) AdsLoader.
  private ImaServerSideAdInsertionMediaSource.AdsLoader createAdsLoader() {
    ImaServerSideAdInsertionMediaSource.AdsLoader.Builder adsLoaderBuilder =
        new ImaServerSideAdInsertionMediaSource.AdsLoader.Builder(this, playerView);

    // Attempt to set the AdsLoader state if available from a previous session.
    if (adsLoaderState != null) {
      adsLoaderBuilder.setAdsLoaderState(adsLoaderState);
    }

    return adsLoaderBuilder.build();
  }

  private void initializePlayer() {
    adsLoader = createAdsLoader();

    // Set up the factory for media sources, passing the ads loader.
    DataSource.Factory dataSourceFactory = new DefaultDataSource.Factory(this);
    DefaultMediaSourceFactory mediaSourceFactory = new DefaultMediaSourceFactory(dataSourceFactory);

    // MediaSource.Factory to create the ad sources for the current player.
    ImaServerSideAdInsertionMediaSource.Factory adsMediaSourceFactory =
        new ImaServerSideAdInsertionMediaSource.Factory(adsLoader, mediaSourceFactory);

    // 'mediaSourceFactory' is an ExoPlayer component for the DefaultMediaSourceFactory.
    // 'adsMediaSourceFactory' is an ExoPlayer component for a MediaSource factory for IMA server
    // side inserted ad streams.
    mediaSourceFactory.setServerSideAdInsertionMediaSourceFactory(adsMediaSourceFactory);

    // Create an ExoPlayer and set it as the player for content and ads.
    player = new ExoPlayer.Builder(this).setMediaSourceFactory(mediaSourceFactory).build();
    playerView.setPlayer(player);
    adsLoader.setPlayer(player);

    // Build an IMA SSAI media item to prepare the player with.
    Uri ssaiLiveUri =
        new ImaServerSideAdInsertionUriBuilder()
            .setAssetKey(SAMPLE_ASSET_KEY)
            .setFormat(CONTENT_TYPE_HLS) // Use CONTENT_TYPE_DASH for dash streams.
            .build();

    // Create the MediaItem to play, specifying the stream URI.
    MediaItem ssaiMediaItem = MediaItem.fromUri(ssaiLiveUri);

    // Prepare the content and ad to be played with the ExoPlayer.
    player.setMediaItem(ssaiMediaItem);
    player.prepare();

    // Set PlayWhenReady. If true, content and ads will autoplay.
    player.setPlayWhenReady(false);
  }
}

プレーヤーを解放するメソッドを追加する

プレーヤーを解放するメソッドを、次のシーケンスで追加します。

  • プレーヤー参照を null に設定し、プレーヤーのリソースを解放します。
  • adsLoader の状態を解放します。

app/src/main/java/com/example/project name/MyActivity.java

public class MyActivity extends Activity {

  ...

  private void releasePlayer() {
    // Set the player references to null and release the player's resources.
    playerView.setPlayer(null);
    player.release();
    player = null;

    // Release the adsLoader state so that it can be initiated again.
    adsLoaderState = adsLoader.release();
  }

プレーヤー イベントを処理する

最後に、アクティビティのライフサイクル イベントのコールバックを作成して、ストリームの再生を処理します。

Android SDK バージョン 24 以降をサポートするには:

バージョン 24 より前の Android SDK をサポートするには: - onResume() - onPause()

onStart()onResume()playerView.onResume() にマッピングされ、onStop()onPause()playerView.onPause() にマッピングされます。

このステップでは、onSaveInstanceState() イベントを使用して adsLoaderState の保存も試行します。

app/src/main/java/com/example/project name/MyActivity.java

public class MyActivity extends Activity {

  ...

  @Override
  public void onStart() {
    super.onStart();
    if (Util.SDK_INT > 23) {
      initializePlayer();
      if (playerView != null) {
        playerView.onResume();
      }
    }
  }

  @Override
  public void onResume() {
    super.onResume();
    if (Util.SDK_INT <= 23 || player == null) {
      initializePlayer();
      if (playerView != null) {
        playerView.onResume();
      }
    }
  }

  @Override
  public void onPause() {
    super.onPause();
    if (Util.SDK_INT <= 23) {
      if (playerView != null) {
        playerView.onPause();
      }
      releasePlayer();
    }
  }

  @Override
  public void onStop() {
    super.onStop();
    if (Util.SDK_INT > 23) {
      if (playerView != null) {
        playerView.onPause();
      }
      releasePlayer();
    }
  }

  @Override
  public void onSaveInstanceState(Bundle outState) {
    // Attempts to save the AdsLoader state to handle app backgrounding.
    if (adsLoaderState != null) {
      outState.putBundle(KEY_ADS_LOADER_STATE, adsLoaderState.toBundle());
    }
  }

  ...

}

VOD ストリームの設定(省略可)

アプリで広告付きの VOD コンテンツを再生する必要がある場合は、次のことを行う必要があります。

  1. VOD テスト ストリーム用に CMS IDVideo ID を追加します。
  2. ImaServerSideAdInsertionUriBuilder() を使用して SSAI VOD URI を作成します。
  3. この新しい URI をプレーヤーのメディア アイテムとして使用します。

app/src/main/java/com/example/project name/MyActivity.java

public class MyActivity extends Activity {

  private static final String KEY_ADS_LOADER_STATE = "ads_loader_state";
  private static final String SAMPLE_ASSET_KEY = "c-rArva4ShKVIAkNfy6HUQ";
  private static final String SAMPLE_CMS_ID = "2528370";
  private static final String SAMPLE_VIDEO_ID = "tears-of-steel";

  ...

  private void initializePlayer() {

     ...

    Uri ssaiVodUri =
        new ImaServerSideAdInsertionUriBuilder()
            .setContentSourceId(SAMPLE_CMS_ID)
            .setVideoId(SAMPLE_VIDEO_ID)
            .setFormat(CONTENT_TYPE_HLS)
            .build();

    // Create the MediaItem to play, specifying the stream URI.
    MediaItem ssaiMediaItem = MediaItem.fromUri(ssaiVodUri);

    // Prepare the content and ad to be played with the ExoPlayer.
    player.setMediaItem(ssaiMediaItem);
    player.prepare();

    // Set PlayWhenReady. If true, content and ads will autoplay.
    player.setPlayWhenReady(false);
  }

これで、これで、ExoPlayer IMA 拡張機能を使用してメディア ストリームをリクエストして再生できるようになりました。完全なコードについては、GitHub の Android DAI サンプルをご覧ください。