Depend on the IMA extension in noExtensions variant

Also use the cronet extension in the demo app.

PiperOrigin-RevId: 322108530
This commit is contained in:
andrewlewis 2020-07-20 11:16:30 +01:00 committed by Oliver Woodman
parent a8b64f9530
commit 7fce04a67f
7 changed files with 41 additions and 75 deletions

View File

@ -250,7 +250,10 @@
* Migrate to new 'friendly obstruction' IMA SDK APIs, and allow apps to
register a purpose and detail reason for overlay views via
`AdsLoader.AdViewProvider`.
* Demo app: Retain previous position in list of samples.
* Demo app:
* Retain previous position in list of samples.
* Replace the `extensions` variant with `decoderExtensions` and make the
demo app use the Cronet and IMA extensions by default.
* Add Guava dependency.
### 2.11.7 (2020-06-29) ###

View File

@ -50,14 +50,14 @@ android {
disable 'GoogleAppIndexingWarning','MissingTranslation','IconDensities'
}
flavorDimensions "extensions"
flavorDimensions "decoderExtensions"
productFlavors {
noExtensions {
dimension "extensions"
noDecoderExtensions {
dimension "decoderExtensions"
}
withExtensions {
dimension "extensions"
withDecoderExtensions {
dimension "decoderExtensions"
}
}
}
@ -72,13 +72,14 @@ dependencies {
implementation project(modulePrefix + 'library-hls')
implementation project(modulePrefix + 'library-smoothstreaming')
implementation project(modulePrefix + 'library-ui')
withExtensionsImplementation project(path: modulePrefix + 'extension-av1')
withExtensionsImplementation project(path: modulePrefix + 'extension-ffmpeg')
withExtensionsImplementation project(path: modulePrefix + 'extension-flac')
withExtensionsImplementation project(path: modulePrefix + 'extension-ima')
withExtensionsImplementation project(path: modulePrefix + 'extension-opus')
withExtensionsImplementation project(path: modulePrefix + 'extension-vp9')
withExtensionsImplementation project(path: modulePrefix + 'extension-rtmp')
implementation project(modulePrefix + 'extension-cronet')
implementation project(modulePrefix + 'extension-ima')
withDecoderExtensionsImplementation project(modulePrefix + 'extension-av1')
withDecoderExtensionsImplementation project(modulePrefix + 'extension-ffmpeg')
withDecoderExtensionsImplementation project(modulePrefix + 'extension-flac')
withDecoderExtensionsImplementation project(modulePrefix + 'extension-opus')
withDecoderExtensionsImplementation project(modulePrefix + 'extension-vp9')
withDecoderExtensionsImplementation project(modulePrefix + 'extension-rtmp')
}
apply plugin: 'com.google.android.gms.strict-version-matcher-plugin'

View File

@ -1,7 +1,2 @@
# Proguard rules specific to the main demo app.
# Constructor accessed via reflection in PlayerActivity
-dontnote com.google.android.exoplayer2.ext.ima.ImaAdsLoader
-keepclassmembers class com.google.android.exoplayer2.ext.ima.ImaAdsLoader {
<init>(android.content.Context, android.net.Uri);
}

View File

@ -20,13 +20,14 @@ import com.google.android.exoplayer2.DefaultRenderersFactory;
import com.google.android.exoplayer2.RenderersFactory;
import com.google.android.exoplayer2.database.DatabaseProvider;
import com.google.android.exoplayer2.database.ExoDatabaseProvider;
import com.google.android.exoplayer2.ext.cronet.CronetDataSourceFactory;
import com.google.android.exoplayer2.ext.cronet.CronetEngineWrapper;
import com.google.android.exoplayer2.offline.ActionFileUpgradeUtil;
import com.google.android.exoplayer2.offline.DefaultDownloadIndex;
import com.google.android.exoplayer2.offline.DownloadManager;
import com.google.android.exoplayer2.ui.DownloadNotificationHelper;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory;
import com.google.android.exoplayer2.upstream.HttpDataSource;
import com.google.android.exoplayer2.upstream.cache.Cache;
import com.google.android.exoplayer2.upstream.cache.CacheDataSource;
@ -50,8 +51,7 @@ public class DemoApplication extends MultiDexApplication {
private static final String DOWNLOAD_TRACKER_ACTION_FILE = "tracked_actions";
private static final String DOWNLOAD_CONTENT_DIRECTORY = "downloads";
protected String userAgent;
private HttpDataSource.Factory httpDataSourceFactory;
private DatabaseProvider databaseProvider;
private File downloadDirectory;
private Cache downloadCache;
@ -62,24 +62,26 @@ public class DemoApplication extends MultiDexApplication {
@Override
public void onCreate() {
super.onCreate();
userAgent = Util.getUserAgent(this, "ExoPlayerDemo");
CronetEngineWrapper cronetEngineWrapper = new CronetEngineWrapper(/* context= */ this);
String userAgent = Util.getUserAgent(this, "ExoPlayerDemo");
httpDataSourceFactory =
new CronetDataSourceFactory(
cronetEngineWrapper,
Executors.newSingleThreadExecutor(),
/* transferListener= */ null,
userAgent);
}
/** Returns a {@link DataSource.Factory}. */
public DataSource.Factory buildDataSourceFactory() {
DefaultDataSourceFactory upstreamFactory =
new DefaultDataSourceFactory(this, buildHttpDataSourceFactory());
new DefaultDataSourceFactory(/* context= */ this, httpDataSourceFactory);
return buildReadOnlyCacheDataSource(upstreamFactory, getDownloadCache());
}
/** Returns a {@link HttpDataSource.Factory}. */
public HttpDataSource.Factory buildHttpDataSourceFactory() {
return new DefaultHttpDataSourceFactory(userAgent);
}
/** Returns whether extension renderers should be used. */
public boolean useExtensionRenderers() {
return "withExtensions".equals(BuildConfig.FLAVOR);
return "withDecoderExtensions".equals(BuildConfig.FLAVOR);
}
public RenderersFactory buildRenderersFactory(boolean preferExtensionRenderer) {
@ -112,7 +114,7 @@ public class DemoApplication extends MultiDexApplication {
return downloadTracker;
}
protected synchronized Cache getDownloadCache() {
private synchronized Cache getDownloadCache() {
if (downloadCache == null) {
File downloadContentDirectory = new File(getDownloadDirectory(), DOWNLOAD_CONTENT_DIRECTORY);
downloadCache =
@ -130,10 +132,10 @@ public class DemoApplication extends MultiDexApplication {
DOWNLOAD_TRACKER_ACTION_FILE, downloadIndex, /* addNewDownloadsAsCompleted= */ true);
downloadManager =
new DownloadManager(
this,
/* context= */ this,
getDatabaseProvider(),
getDownloadCache(),
buildHttpDataSourceFactory(),
httpDataSourceFactory,
Executors.newFixedThreadPool(/* nThreads= */ 6));
downloadTracker =
new DownloadTracker(/* context= */ this, buildDataSourceFactory(), downloadManager);
@ -171,7 +173,7 @@ public class DemoApplication extends MultiDexApplication {
return downloadDirectory;
}
protected static CacheDataSource.Factory buildReadOnlyCacheDataSource(
private static CacheDataSource.Factory buildReadOnlyCacheDataSource(
DataSource.Factory upstreamFactory, Cache cache) {
return new CacheDataSource.Factory()
.setCache(cache)

View File

@ -29,7 +29,6 @@ import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlaybackException;
@ -39,6 +38,7 @@ import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.RenderersFactory;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.audio.AudioAttributes;
import com.google.android.exoplayer2.ext.ima.ImaAdsLoader;
import com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.DecoderInitializationException;
import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException;
import com.google.android.exoplayer2.source.BehindLiveWindowException;
@ -60,7 +60,6 @@ import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.ErrorMessageProvider;
import com.google.android.exoplayer2.util.EventLogger;
import com.google.android.exoplayer2.util.Util;
import java.lang.reflect.Constructor;
import java.net.CookieHandler;
import java.net.CookieManager;
import java.net.CookiePolicy;
@ -447,31 +446,6 @@ public class PlayerActivity extends AppCompatActivity
return ((DemoApplication) getApplication()).buildDataSourceFactory();
}
/**
* Returns an ads loader for the Interactive Media Ads SDK if found in the classpath, or null
* otherwise.
*/
@Nullable
private AdsLoader maybeCreateAdsLoader(Uri adTagUri) {
// Load the extension source using reflection so the demo app doesn't have to depend on it.
try {
Class<?> loaderClass = Class.forName("com.google.android.exoplayer2.ext.ima.ImaAdsLoader");
// Full class names used so the lint rule triggers should any of the classes move.
// LINT.IfChange
Constructor<? extends AdsLoader> loaderConstructor =
loaderClass
.asSubclass(AdsLoader.class)
.getConstructor(android.content.Context.class, android.net.Uri.class);
// LINT.ThenChange(../../../../../../../../proguard-rules.txt)
return loaderConstructor.newInstance(this, adTagUri);
} catch (ClassNotFoundException e) {
// IMA extension not loaded.
return null;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// User controls
private void updateButtonVisibility() {
@ -585,7 +559,6 @@ public class PlayerActivity extends AppCompatActivity
private class AdSupportProvider implements DefaultMediaSourceFactory.AdSupportProvider {
@Nullable
@Override
public AdsLoader getAdsLoader(Uri adTagUri) {
if (mediaItems.size() > 1) {
@ -599,13 +572,9 @@ public class PlayerActivity extends AppCompatActivity
}
// The ads loader is reused for multiple playbacks, so that ad playback can resume.
if (adsLoader == null) {
adsLoader = maybeCreateAdsLoader(adTagUri);
}
if (adsLoader != null) {
adsLoader.setPlayer(player);
} else {
showToast(R.string.ima_not_loaded);
adsLoader = new ImaAdsLoader(/* context= */ PlayerActivity.this, adTagUri);
}
adsLoader.setPlayer(player);
return adsLoader;
}

View File

@ -51,8 +51,6 @@
<string name="sample_list_load_error">One or more sample lists failed to load</string>
<string name="ima_not_loaded">Playing sample without ads, as the IMA extension was not loaded</string>
<string name="unsupported_ads_in_concatenation">Playing sample without ads, as ads are not supported in concatenations</string>
<string name="download_start_error">Failed to start download</string>

View File

@ -46,12 +46,10 @@ On returning to the foreground, seek to that position before preparing the new
player instance. Finally, it is important to call `ImaAdsLoader.release()` when
playback of the content/ads has finished and will not be resumed.
You can try the IMA extension in the ExoPlayer demo app. To do this you must
select and build one of the `withExtensions` build variants of the demo app in
Android Studio. You can find IMA test content in the "IMA sample ad tags"
section of the app. The demo app's `PlayerActivity` also shows how to persist
the `ImaAdsLoader` instance and the player position when backgrounded during ad
playback.
You can try the IMA extension in the ExoPlayer demo app, which has test content
in the "IMA sample ad tags" section of the sample chooser. The demo app's
`PlayerActivity` also shows how to persist the `ImaAdsLoader` instance and the
player position when backgrounded during ad playback.
[top level README]: https://github.com/google/ExoPlayer/blob/release-v2/README.md
[sample ad tags]: https://developers.google.com/interactive-media-ads/docs/sdks/android/tags