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

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

この拡張機能のメリットは次のとおりです。

  • IMA 機能を統合するために必要なコードを簡素化します。
  • 新しい IMA バージョンへの更新に必要な時間を短縮します。

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

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

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

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

前提条件

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

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

  1. Android Studio を起動します。
  2. [Start a new Android Studio project] を選択します。
  3. [Choose your project] ページで、[No Activity] テンプレートを選択します。
  4. [次へ] をクリックします。
  5. [Configure your project] ページで、プロジェクトに名前を付け、言語として [Java] を選択します。注: IMA DAI SDK は Kotlin で動作しますが、このガイドでは Java の例を使用します。
  • [完了] をクリックします。

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

ExoPlayer IMA 拡張機能を追加する手順は次のとおりです。

  1. アプリの build.gradle ファイルの dependencies セクションに次のインポートを含めます。

    dependencies {
        def media3_version = "1.8.0"
        implementation(platform("org.jetbrains.kotlin:kotlin-bom:1.8.0"))
        implementation 'androidx.appcompat:appcompat:1.7.1'
        implementation "androidx.media3:media3-ui:$media3_version"
        implementation "androidx.media3:media3-exoplayer:$media3_version"
        implementation "androidx.media3:media3-exoplayer-hls:$media3_version"
        implementation "androidx.media3:media3-exoplayer-dash:$media3_version"
    
        // The library adds the IMA ExoPlayer integration for ads.
        implementation "androidx.media3:media3-exoplayer-ima:$media3_version"
    }
    
  2. IMA DAI SDK が広告をリクエストするために必要なユーザー権限を追加します。

    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    

ExoPlayer UI を設定する

ExoPlayer UI を設定する手順は次のとおりです。

  1. ExoPlayer の PlayerView オブジェクトを作成します。

  2. ExoPlayer IMA 拡張機能の推奨に従って、androidx.constraintlayout.widget.ConstraintLayout ビューを LinearLayout ビューに変更します。

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        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:fitsSystemWindows="true"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    
        <!-- UI element for viewing SDK event log -->
        <TextView
            android:id="@+id/logText"
            android:gravity="bottom"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:maxLines="100"
            android:scrollbars="vertical"
            android:textSize="@dimen/font_size">
        </TextView>
    
    </LinearLayout>
    
    

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

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

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

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

  1. ExoPlayer 拡張機能の次の import ステートメントを追加します。

    import static androidx.media3.common.C.CONTENT_TYPE_HLS;
    
    import android.annotation.SuppressLint;
    import android.app.Activity;
    import android.net.Uri;
    import android.os.Bundle;
    import android.text.method.ScrollingMovementMethod;
    import android.util.Log;
    import android.widget.TextView;
    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.ui.PlayerView;
    import com.google.ads.interactivemedia.v3.api.AdEvent;
    import com.google.ads.interactivemedia.v3.api.ImaSdkFactory;
    import com.google.ads.interactivemedia.v3.api.ImaSdkSettings;
    import java.util.HashMap;
    import java.util.Map;
    
    
  2. MyActivity.java に、次の非公開変数を追加します。

    Big Buck Bunny(ライブ)HLS ストリームでテストするには、そのアセットキーを追加します。テスト用のストリームは、IMA のサンプル ストリーム ページで確認できます。

  3. AdsLoader の状態を保存して取得するための KEY_ADS_LOADER_STATE 定数を作成します。

    /** Main Activity. */
    @SuppressLint("UnsafeOptInUsageError")
    /* @SuppressLint is needed for new media3 APIs. */
    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 LOG_TAG = "ImaExoPlayerExample";
    
      private PlayerView playerView;
      private TextView logText;
      private ExoPlayer player;
      private ImaServerSideAdInsertionMediaSource.AdsLoader adsLoader;
      private ImaServerSideAdInsertionMediaSource.AdsLoader.State adsLoaderState;
      private ImaSdkSettings imaSdkSettings;
    
    

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

onCreate メソッドをオーバーライドします。その中で PlayerView を見つけ、保存された AdsLoader.State があるかどうかを確認します。この状態は、adsLoader オブジェクトを初期化するときに使用できます。

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

  // Initialize the IMA SDK as early as possible when the app starts. If your app already
  // overrides Application.onCreate(), call this method inside the onCreate() method.
  // https://developer.android.com/topic/performance/vitals/launch-time#app-creation
  ImaSdkFactory.getInstance().initialize(this, getImaSdkSettings());

  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.fromBundle(adsLoaderStateBundle);
    }
  }
}

private ImaSdkSettings getImaSdkSettings() {
  if (imaSdkSettings == null) {
    imaSdkSettings = ImaSdkFactory.getInstance().createImaSdkSettings();
    // Set any IMA SDK settings here.
  }
  return imaSdkSettings;
}

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

プレーヤーを初期化するメソッドを追加します。このメソッドは、次の処理を行う必要があります。

  • AdsLoader インスタンスを作成します。
  • ExoPlayer を作成します。
  • ライブ ストリームのアセットキーを使用して MediaItem を作成します。
  • プレーヤーの MediaItem を設定します。
// Create a server side ad insertion (SSAI) AdsLoader.
private ImaServerSideAdInsertionMediaSource.AdsLoader createAdsLoader() {
  ImaServerSideAdInsertionMediaSource.AdsLoader.Builder adsLoaderBuilder =
      new ImaServerSideAdInsertionMediaSource.AdsLoader.Builder(this, playerView);

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

  return adsLoaderBuilder
      .setAdEventListener(buildAdEventListener())
      .setImaSdkSettings(getImaSdkSettings())
      .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 a SimpleExoPlayer and set it as the player for content and ads.
  player = new ExoPlayer.Builder(this).setMediaSourceFactory(mediaSourceFactory).build();
  playerView.setPlayer(player);
  adsLoader.setPlayer(player);

  // Create the MediaItem to play, specifying the stream URI.
  Uri ssaiUri = buildLiveStreamUri(SAMPLE_ASSET_KEY, CONTENT_TYPE_HLS);
  MediaItem ssaiMediaItem = MediaItem.fromUri(ssaiUri);

  // 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);
}

/**
 * Builds an IMA SSAI live stream URI for the given asset key and format.
 *
 * @param assetKey The asset key of the live stream.
 * @param format The format of the live stream request, either {@code CONTENT_TYPE_HLS} or {@code
 *     CONTENT_TYPE_DASH}.
 * @return The URI of the live stream.
 */
public Uri buildLiveStreamUri(String assetKey, int format) {
  Map<String, String> adTagParams = new HashMap<String, String>();
  // Update the adTagParams map with any parameters.
  // For more information, see https://support.google.com/admanager/answer/7320899

  return new ImaServerSideAdInsertionUriBuilder()
      .setAssetKey(assetKey)
      .setFormat(format)
      .setAdTagParameters(adTagParams)
      .build();
}

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

プレーヤーをリリースするメソッドを追加します。このメソッドは、次のアクションを順番に実行する必要があります。

  • プレーヤー参照を null に設定し、プレーヤーのリソースを解放します。
  • adsLoader 状態を解放します。
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 API レベル 24 以降では、次のメソッドを使用します。

Android API レベル 24 より前の場合は、次のメソッドを使用します。

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

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

@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. ビデオ オンデマンド ストリームの CMS IDVideo ID を追加します。テストには、次のストリーム パラメータを使用します。
    • CMS ID: "2548831"
    • 動画 ID: "tears-of-steel"
  2. ImaServerSideAdInsertionUriBuilder() メソッドを使用して SSAI VOD URI を作成します。

    /**
     * Builds an IMA SSAI VOD stream URI for the given CMS ID, video ID, and format.
     *
     * @param cmsId The CMS ID of the VOD stream.
     * @param videoId The video ID of the VOD stream.
     * @param format The format of the VOD stream request, either {@code CONTENT_TYPE_HLS} or {@code
     *     CONTENT_TYPE_DASH}.
     * @return The URI of the VOD stream.
     */
    public Uri buildVodStreamUri(String cmsId, String videoId, int format) {
      Map<String, String> adTagParams = new HashMap<String, String>();
      // Update the adTagParams map with any parameters.
      // For more information, see https://support.google.com/admanager/answer/7320899
    
      return new ImaServerSideAdInsertionUriBuilder()
          .setContentSourceId(cmsId)
          .setVideoId(videoId)
          .setFormat(format)
          .setAdTagParameters(adTagParams)
          .build();
    }
    
    
  3. MediaItem.fromUri() メソッドを使用して、新しい VOD ストリーム URI をプレーヤーのメディア アイテムとして設定します。

成功すると、ExoPlayer IMA 拡張機能を使用してメディア ストリームをリクエストして再生できます。完全な例については、GitHub の Android DAI サンプルをご覧ください。