Page Summary
-
ExoPlayer is an Android media player, and the ExoPlayer IMA extension helps integrate IMA DAI SDK for playing streams with ads and content.
-
The ExoPlayer IMA extension simplifies code and reduces development time for IMA integration.
-
The extension supports HLS and DASH streaming protocols for both livestream and VOD streams.
-
To use the ExoPlayer IMA extension, you need Android Studio and AndroidX Media3 ExoPlayer version 1.0.0 or higher.
ExoPlayer is an Android media player. This guide shows you how to use the ExoPlayer IMA extension. This extension uses the IMA DAI SDK to request and play media streams with both ads and content.
The following lists benefits of the extension:
- Simplifies the code needed to integrate IMA features.
- Reduces the time required to update to new IMA versions.
The ExoPlayer IMA extension supports HLS and DASH streaming protocols. Here's a summary:
| ExoPlayer-IMA extension stream support | ||
|---|---|---|
| Livestream | VOD streams | |
| HLS | ![]() |
![]() |
| DASH | ![]() |
![]() |
ExoPlayer-IMA version 1.1.0 and later supports DASH live streams.
This guide uses the
ExoPlayer guide
to help you create a full app and integrate the extension. For a complete sample
app, see the
ExoPlayerExample on GitHub.
Prerequisites
- Android Studio
- AndroidX Media3 ExoPlayer version 1.0.0 or later for DAI support.
Create a new Android Studio project
To create your Android Studio project, follow these steps:
- Start Android Studio.
- Select Start a new Android Studio project.
- On the Choose your project page, select the No Activity template.
- Click Next.
- On the Configure your project page, name your project and select Java as the language. Note: The IMA DAI SDK works with Kotlin, but this guide uses Java examples.
- Click Finish.
Add the ExoPlayer IMA extension to your project
To add the ExoPlayer IMA extension, do the following:
Include the following imports in the
dependenciessection of your app'sbuild.gradlefile: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" }Add the user permissions that the IMA DAI SDK needs to request ads:
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
Set up the ExoPlayer UI
To set up the ExoPlayer UI, do the following:
Create the
PlayerViewobject for ExoPlayer.Change the
androidx.constraintlayout.widget.ConstraintLayoutview to aLinearLayoutview, as recommended by the ExoPlayer IMA extension:<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>
Add your stream parameters
See the IMA sample stream page for sample stream assets to test your project. To set up your own streams, see the Ad Manager section on DAI.
This step sets up a livestream. The ExoPlayer IMA extension also supports DAI VOD streams. To learn what changes your app needs for VOD streams, see the step for video on demand (VOD) streams.
Import the ExoPlayer IMA extension
Add the following import statements for the ExoPlayer extension:
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;In
MyActivity.java, add these private variables:PlayerViewExoPlayerImaServerSideAdInsertionMediaSource.AdsLoaderImaServerSideAdInsertionMediaSource.AdsLoader.State
To test with the Big Buck Bunny (Live) HLS stream, add its asset key. You can find more streams to test on IMA's sample stream page.
Create a
KEY_ADS_LOADER_STATEconstant to save and retrieve theAdsLoaderstate:/** 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;
Create an adsLoader instance
Override the onCreate method. In it, find the PlayerView and check for a
saved
AdsLoader.State.
You can use this state when you initialize the adsLoader object.
@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;
}
Add methods to initialize the player
Add a method to initialize the player. This method must do the following:
- Create an
AdsLoaderinstance. - Create the
ExoPlayer. - Create a
MediaItemusing the live stream's asset key. - Set the
MediaItemfor your player.
// 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();
}
Add a method to release the player
Add a method to release the player. This method must perform the following actions in sequence:
- Set the player references to null and release the player's resources.
- Release the
adsLoaderstate.
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();
}
Handle player events
To handle player events, create callbacks for the activity's lifecycle events to manage stream playback.
For Android API level 24 and later, use the following methods:
For Android API levels earlier than 24, use the following methods:
The onStart() and onResume() methods map to playerView.onResume(), while
onStop() and onPause() map to playerView.onPause().
This step also uses the
onSaveInstanceState()
event to save the 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 stream setup (optional)
If your app needs to play VOD content with ads, follow these steps:
- Add a
CMS IDandVideo IDfor a VOD stream. For testing, use these stream parameters:- CMS ID:
"2548831" - Video ID:
"tears-of-steel"
- CMS ID:
Create an SSAI VOD URI using the
ImaServerSideAdInsertionUriBuilder()method:/** * 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(); }Set the new VOD stream URI as your player's media item using the
MediaItem.fromUri()method.
If successful, you can request and play a media stream with the ExoPlayer IMA extension. For the complete example, see Android DAI samples on GitHub.
