From cd4571161ae2bbe97788a2bf8ba51ed0580d407d Mon Sep 17 00:00:00 2001 From: tonihei Date: Wed, 14 Aug 2019 14:41:40 +0100 Subject: [PATCH] Add builders for SimpleExoPlayer and ExoPlayer. The current ExoPlayerFactory is growing too big and usage becomes increasingly complicated because it's not possible to set individual components without specifying many other defaults. Adding new builder classes makes building easier and more future-proof. PiperOrigin-RevId: 263339078 --- RELEASENOTES.md | 2 + .../exoplayer2/castdemo/PlayerManager.java | 3 +- .../exoplayer2/gvrdemo/PlayerActivity.java | 5 +- .../exoplayer2/imademo/PlayerManager.java | 3 +- .../exoplayer2/demo/PlayerActivity.java | 5 +- extensions/ffmpeg/README.md | 20 +- extensions/flac/README.md | 20 +- .../exoplayer2/ext/flac/FlacPlaybackTest.java | 6 +- extensions/opus/README.md | 20 +- .../exoplayer2/ext/opus/OpusPlaybackTest.java | 6 +- extensions/vp9/README.md | 20 +- .../exoplayer2/ext/vp9/VpxPlaybackTest.java | 6 +- .../exoplayer2/DefaultRenderersFactory.java | 6 +- .../google/android/exoplayer2/ExoPlayer.java | 165 ++++++++++- .../android/exoplayer2/ExoPlayerFactory.java | 267 ++++-------------- .../android/exoplayer2/ExoPlayerImpl.java | 4 +- .../android/exoplayer2/SimpleExoPlayer.java | 228 ++++++++++++++- .../AdaptiveTrackSelection.java | 8 +- .../trackselection/DefaultTrackSelector.java | 3 +- .../upstream/DefaultBandwidthMeter.java | 15 + .../playbacktests/gts/DashTestRunner.java | 12 +- .../exoplayer2/testutil/ExoHostedTest.java | 17 +- 22 files changed, 543 insertions(+), 298 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 2fe1cf8a54..bf89c83724 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -34,6 +34,8 @@ * Reset `DefaultBandwidthMeter` to initial values on network change. * Increase maximum buffer size for video in `DefaultLoadControl` to ensure high quality video can be loaded up to the full default buffer duration. +* Replace `ExoPlayerFactory` by `SimpleExoPlayer.Builder` and + `ExoPlayer.Builder`. ### 2.10.4 ### diff --git a/demos/cast/src/main/java/com/google/android/exoplayer2/castdemo/PlayerManager.java b/demos/cast/src/main/java/com/google/android/exoplayer2/castdemo/PlayerManager.java index 8b75eb0c74..b1a12f6bc9 100644 --- a/demos/cast/src/main/java/com/google/android/exoplayer2/castdemo/PlayerManager.java +++ b/demos/cast/src/main/java/com/google/android/exoplayer2/castdemo/PlayerManager.java @@ -20,7 +20,6 @@ import android.net.Uri; import android.view.KeyEvent; import android.view.View; import com.google.android.exoplayer2.C; -import com.google.android.exoplayer2.ExoPlayerFactory; import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Player.DiscontinuityReason; import com.google.android.exoplayer2.Player.EventListener; @@ -119,7 +118,7 @@ import java.util.Map; mediaDrms = new IdentityHashMap<>(); trackSelector = new DefaultTrackSelector(context); - exoPlayer = ExoPlayerFactory.newSimpleInstance(context, trackSelector); + exoPlayer = new SimpleExoPlayer.Builder(context).setTrackSelector(trackSelector).build(); exoPlayer.addListener(this); localPlayerView.setPlayer(exoPlayer); diff --git a/demos/gvr/src/main/java/com/google/android/exoplayer2/gvrdemo/PlayerActivity.java b/demos/gvr/src/main/java/com/google/android/exoplayer2/gvrdemo/PlayerActivity.java index 059f26b374..15cc9b6469 100644 --- a/demos/gvr/src/main/java/com/google/android/exoplayer2/gvrdemo/PlayerActivity.java +++ b/demos/gvr/src/main/java/com/google/android/exoplayer2/gvrdemo/PlayerActivity.java @@ -24,7 +24,6 @@ import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C.ContentType; import com.google.android.exoplayer2.DefaultRenderersFactory; import com.google.android.exoplayer2.ExoPlaybackException; -import com.google.android.exoplayer2.ExoPlayerFactory; import com.google.android.exoplayer2.PlaybackPreparer; import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.SimpleExoPlayer; @@ -138,7 +137,9 @@ public class PlayerActivity extends GvrPlayerActivity implements PlaybackPrepare lastSeenTrackGroupArray = null; player = - ExoPlayerFactory.newSimpleInstance(/* context= */ this, renderersFactory, trackSelector); + new SimpleExoPlayer.Builder(/* context= */ this, renderersFactory) + .setTrackSelector(trackSelector) + .build(); player.addListener(new PlayerEventListener()); player.setPlayWhenReady(startAutoPlay); player.addAnalyticsListener(new EventLogger(trackSelector)); diff --git a/demos/ima/src/main/java/com/google/android/exoplayer2/imademo/PlayerManager.java b/demos/ima/src/main/java/com/google/android/exoplayer2/imademo/PlayerManager.java index 8f2c891e3a..3caf7f0c16 100644 --- a/demos/ima/src/main/java/com/google/android/exoplayer2/imademo/PlayerManager.java +++ b/demos/ima/src/main/java/com/google/android/exoplayer2/imademo/PlayerManager.java @@ -20,7 +20,6 @@ import android.net.Uri; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C.ContentType; import com.google.android.exoplayer2.ExoPlayer; -import com.google.android.exoplayer2.ExoPlayerFactory; import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.ext.ima.ImaAdsLoader; import com.google.android.exoplayer2.source.MediaSource; @@ -54,7 +53,7 @@ import com.google.android.exoplayer2.util.Util; public void init(Context context, PlayerView playerView) { // Create a player instance. - player = ExoPlayerFactory.newSimpleInstance(context); + player = new SimpleExoPlayer.Builder(context).build(); adsLoader.setPlayer(player); playerView.setPlayer(player); diff --git a/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java b/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java index 1e231dd45e..d3c32ac957 100644 --- a/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java +++ b/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java @@ -33,7 +33,6 @@ import android.widget.Toast; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C.ContentType; import com.google.android.exoplayer2.ExoPlaybackException; -import com.google.android.exoplayer2.ExoPlayerFactory; import com.google.android.exoplayer2.PlaybackPreparer; import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.RenderersFactory; @@ -371,7 +370,9 @@ public class PlayerActivity extends AppCompatActivity lastSeenTrackGroupArray = null; player = - ExoPlayerFactory.newSimpleInstance(/* context= */ this, renderersFactory, trackSelector); + new SimpleExoPlayer.Builder(/* context= */ this, renderersFactory) + .setTrackSelector(trackSelector) + .build(); player.addListener(new PlayerEventListener()); player.setPlayWhenReady(startAutoPlay); player.addAnalyticsListener(new EventLogger(trackSelector)); diff --git a/extensions/ffmpeg/README.md b/extensions/ffmpeg/README.md index 5b68f1e352..dd9ce38d35 100644 --- a/extensions/ffmpeg/README.md +++ b/extensions/ffmpeg/README.md @@ -122,22 +122,22 @@ Once you've followed the instructions above to check out, build and depend on the extension, the next step is to tell ExoPlayer to use `FfmpegAudioRenderer`. How you do this depends on which player API you're using: -* If you're passing a `DefaultRenderersFactory` to - `ExoPlayerFactory.newSimpleInstance`, you can enable using the extension by - setting the `extensionRendererMode` parameter of the `DefaultRenderersFactory` - constructor to `EXTENSION_RENDERER_MODE_ON`. This will use - `FfmpegAudioRenderer` for playback if `MediaCodecAudioRenderer` doesn't - support the input format. Pass `EXTENSION_RENDERER_MODE_PREFER` to give - `FfmpegAudioRenderer` priority over `MediaCodecAudioRenderer`. +* If you're passing a `DefaultRenderersFactory` to `SimpleExoPlayer.Builder`, + you can enable using the extension by setting the `extensionRendererMode` + parameter of the `DefaultRenderersFactory` constructor to + `EXTENSION_RENDERER_MODE_ON`. This will use `FfmpegAudioRenderer` for playback + if `MediaCodecAudioRenderer` doesn't support the input format. Pass + `EXTENSION_RENDERER_MODE_PREFER` to give `FfmpegAudioRenderer` priority over + `MediaCodecAudioRenderer`. * If you've subclassed `DefaultRenderersFactory`, add an `FfmpegAudioRenderer` to the output list in `buildAudioRenderers`. ExoPlayer will use the first `Renderer` in the list that supports the input media format. * If you've implemented your own `RenderersFactory`, return an `FfmpegAudioRenderer` instance from `createRenderers`. ExoPlayer will use the first `Renderer` in the returned array that supports the input media format. -* If you're using `ExoPlayerFactory.newInstance`, pass an `FfmpegAudioRenderer` - in the array of `Renderer`s. ExoPlayer will use the first `Renderer` in the - list that supports the input media format. +* If you're using `ExoPlayer.Builder`, pass an `FfmpegAudioRenderer` in the + array of `Renderer`s. ExoPlayer will use the first `Renderer` in the list that + supports the input media format. Note: These instructions assume you're using `DefaultTrackSelector`. If you have a custom track selector the choice of `Renderer` is up to your implementation, diff --git a/extensions/flac/README.md b/extensions/flac/README.md index 78035f4d87..b4b0dae002 100644 --- a/extensions/flac/README.md +++ b/extensions/flac/README.md @@ -68,22 +68,22 @@ renderer. ### Using `LibflacAudioRenderer` ### -* If you're passing a `DefaultRenderersFactory` to - `ExoPlayerFactory.newSimpleInstance`, you can enable using the extension by - setting the `extensionRendererMode` parameter of the `DefaultRenderersFactory` - constructor to `EXTENSION_RENDERER_MODE_ON`. This will use - `LibflacAudioRenderer` for playback if `MediaCodecAudioRenderer` doesn't - support the input format. Pass `EXTENSION_RENDERER_MODE_PREFER` to give - `LibflacAudioRenderer` priority over `MediaCodecAudioRenderer`. +* If you're passing a `DefaultRenderersFactory` to `SimpleExoPlayer.Builder`, + you can enable using the extension by setting the `extensionRendererMode` + parameter of the `DefaultRenderersFactory` constructor to + `EXTENSION_RENDERER_MODE_ON`. This will use `LibflacAudioRenderer` for + playback if `MediaCodecAudioRenderer` doesn't support the input format. Pass + `EXTENSION_RENDERER_MODE_PREFER` to give `LibflacAudioRenderer` priority over + `MediaCodecAudioRenderer`. * If you've subclassed `DefaultRenderersFactory`, add a `LibflacAudioRenderer` to the output list in `buildAudioRenderers`. ExoPlayer will use the first `Renderer` in the list that supports the input media format. * If you've implemented your own `RenderersFactory`, return a `LibflacAudioRenderer` instance from `createRenderers`. ExoPlayer will use the first `Renderer` in the returned array that supports the input media format. -* If you're using `ExoPlayerFactory.newInstance`, pass a `LibflacAudioRenderer` - in the array of `Renderer`s. ExoPlayer will use the first `Renderer` in the - list that supports the input media format. +* If you're using `ExoPlayer.Builder`, pass a `LibflacAudioRenderer` in the + array of `Renderer`s. ExoPlayer will use the first `Renderer` in the list that + supports the input media format. Note: These instructions assume you're using `DefaultTrackSelector`. If you have a custom track selector the choice of `Renderer` is up to your implementation, diff --git a/extensions/flac/src/androidTest/java/com/google/android/exoplayer2/ext/flac/FlacPlaybackTest.java b/extensions/flac/src/androidTest/java/com/google/android/exoplayer2/ext/flac/FlacPlaybackTest.java index c10d6fdb27..bf96442f61 100644 --- a/extensions/flac/src/androidTest/java/com/google/android/exoplayer2/ext/flac/FlacPlaybackTest.java +++ b/extensions/flac/src/androidTest/java/com/google/android/exoplayer2/ext/flac/FlacPlaybackTest.java @@ -24,13 +24,10 @@ import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlayer; -import com.google.android.exoplayer2.ExoPlayerFactory; import com.google.android.exoplayer2.Player; -import com.google.android.exoplayer2.Renderer; import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor; import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.ProgressiveMediaSource; -import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory; import org.junit.Before; import org.junit.Test; @@ -82,8 +79,7 @@ public class FlacPlaybackTest { public void run() { Looper.prepare(); LibflacAudioRenderer audioRenderer = new LibflacAudioRenderer(); - DefaultTrackSelector trackSelector = new DefaultTrackSelector(context); - player = ExoPlayerFactory.newInstance(context, new Renderer[] {audioRenderer}, trackSelector); + player = new ExoPlayer.Builder(context, audioRenderer).build(); player.addListener(this); MediaSource mediaSource = new ProgressiveMediaSource.Factory( diff --git a/extensions/opus/README.md b/extensions/opus/README.md index 95c6807275..af44e84b04 100644 --- a/extensions/opus/README.md +++ b/extensions/opus/README.md @@ -71,22 +71,22 @@ Once you've followed the instructions above to check out, build and depend on the extension, the next step is to tell ExoPlayer to use `LibopusAudioRenderer`. How you do this depends on which player API you're using: -* If you're passing a `DefaultRenderersFactory` to - `ExoPlayerFactory.newSimpleInstance`, you can enable using the extension by - setting the `extensionRendererMode` parameter of the `DefaultRenderersFactory` - constructor to `EXTENSION_RENDERER_MODE_ON`. This will use - `LibopusAudioRenderer` for playback if `MediaCodecAudioRenderer` doesn't - support the input format. Pass `EXTENSION_RENDERER_MODE_PREFER` to give - `LibopusAudioRenderer` priority over `MediaCodecAudioRenderer`. +* If you're passing a `DefaultRenderersFactory` to `SimpleExoPlayer.Builder`, + you can enable using the extension by setting the `extensionRendererMode` + parameter of the `DefaultRenderersFactory` constructor to + `EXTENSION_RENDERER_MODE_ON`. This will use `LibopusAudioRenderer` for + playback if `MediaCodecAudioRenderer` doesn't support the input format. Pass + `EXTENSION_RENDERER_MODE_PREFER` to give `LibopusAudioRenderer` priority over + `MediaCodecAudioRenderer`. * If you've subclassed `DefaultRenderersFactory`, add a `LibopusAudioRenderer` to the output list in `buildAudioRenderers`. ExoPlayer will use the first `Renderer` in the list that supports the input media format. * If you've implemented your own `RenderersFactory`, return a `LibopusAudioRenderer` instance from `createRenderers`. ExoPlayer will use the first `Renderer` in the returned array that supports the input media format. -* If you're using `ExoPlayerFactory.newInstance`, pass a `LibopusAudioRenderer` - in the array of `Renderer`s. ExoPlayer will use the first `Renderer` in the - list that supports the input media format. +* If you're using `ExoPlayer.Builder`, pass a `LibopusAudioRenderer` in the + array of `Renderer`s. ExoPlayer will use the first `Renderer` in the list that + supports the input media format. Note: These instructions assume you're using `DefaultTrackSelector`. If you have a custom track selector the choice of `Renderer` is up to your implementation, diff --git a/extensions/opus/src/androidTest/java/com/google/android/exoplayer2/ext/opus/OpusPlaybackTest.java b/extensions/opus/src/androidTest/java/com/google/android/exoplayer2/ext/opus/OpusPlaybackTest.java index 382ee38e06..b3d5b525d5 100644 --- a/extensions/opus/src/androidTest/java/com/google/android/exoplayer2/ext/opus/OpusPlaybackTest.java +++ b/extensions/opus/src/androidTest/java/com/google/android/exoplayer2/ext/opus/OpusPlaybackTest.java @@ -24,13 +24,10 @@ import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlayer; -import com.google.android.exoplayer2.ExoPlayerFactory; import com.google.android.exoplayer2.Player; -import com.google.android.exoplayer2.Renderer; import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor; import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.ProgressiveMediaSource; -import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory; import org.junit.Before; import org.junit.Test; @@ -82,8 +79,7 @@ public class OpusPlaybackTest { public void run() { Looper.prepare(); LibopusAudioRenderer audioRenderer = new LibopusAudioRenderer(); - DefaultTrackSelector trackSelector = new DefaultTrackSelector(context); - player = ExoPlayerFactory.newInstance(context, new Renderer[] {audioRenderer}, trackSelector); + player = new ExoPlayer.Builder(context, audioRenderer).build(); player.addListener(this); MediaSource mediaSource = new ProgressiveMediaSource.Factory( diff --git a/extensions/vp9/README.md b/extensions/vp9/README.md index be75eae359..34230db2ec 100644 --- a/extensions/vp9/README.md +++ b/extensions/vp9/README.md @@ -85,22 +85,22 @@ Once you've followed the instructions above to check out, build and depend on the extension, the next step is to tell ExoPlayer to use `LibvpxVideoRenderer`. How you do this depends on which player API you're using: -* If you're passing a `DefaultRenderersFactory` to - `ExoPlayerFactory.newSimpleInstance`, you can enable using the extension by - setting the `extensionRendererMode` parameter of the `DefaultRenderersFactory` - constructor to `EXTENSION_RENDERER_MODE_ON`. This will use - `LibvpxVideoRenderer` for playback if `MediaCodecVideoRenderer` doesn't - support decoding the input VP9 stream. Pass `EXTENSION_RENDERER_MODE_PREFER` - to give `LibvpxVideoRenderer` priority over `MediaCodecVideoRenderer`. +* If you're passing a `DefaultRenderersFactory` to `SimpleExoPlayer.Builder`, + you can enable using the extension by setting the `extensionRendererMode` + parameter of the `DefaultRenderersFactory` constructor to + `EXTENSION_RENDERER_MODE_ON`. This will use `LibvpxVideoRenderer` for playback + if `MediaCodecVideoRenderer` doesn't support decoding the input VP9 stream. + Pass `EXTENSION_RENDERER_MODE_PREFER` to give `LibvpxVideoRenderer` priority + over `MediaCodecVideoRenderer`. * If you've subclassed `DefaultRenderersFactory`, add a `LibvpxVideoRenderer` to the output list in `buildVideoRenderers`. ExoPlayer will use the first `Renderer` in the list that supports the input media format. * If you've implemented your own `RenderersFactory`, return a `LibvpxVideoRenderer` instance from `createRenderers`. ExoPlayer will use the first `Renderer` in the returned array that supports the input media format. -* If you're using `ExoPlayerFactory.newInstance`, pass a `LibvpxVideoRenderer` - in the array of `Renderer`s. ExoPlayer will use the first `Renderer` in the - list that supports the input media format. +* If you're using `ExoPlayer.Builder`, pass a `LibvpxVideoRenderer` in the array + of `Renderer`s. ExoPlayer will use the first `Renderer` in the list that + supports the input media format. Note: These instructions assume you're using `DefaultTrackSelector`. If you have a custom track selector the choice of `Renderer` is up to your implementation, diff --git a/extensions/vp9/src/androidTest/java/com/google/android/exoplayer2/ext/vp9/VpxPlaybackTest.java b/extensions/vp9/src/androidTest/java/com/google/android/exoplayer2/ext/vp9/VpxPlaybackTest.java index 9be1d9c0e5..d4e0795293 100644 --- a/extensions/vp9/src/androidTest/java/com/google/android/exoplayer2/ext/vp9/VpxPlaybackTest.java +++ b/extensions/vp9/src/androidTest/java/com/google/android/exoplayer2/ext/vp9/VpxPlaybackTest.java @@ -25,13 +25,10 @@ import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlayer; -import com.google.android.exoplayer2.ExoPlayerFactory; import com.google.android.exoplayer2.Player; -import com.google.android.exoplayer2.Renderer; import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor; import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.ProgressiveMediaSource; -import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory; import com.google.android.exoplayer2.util.Log; import org.junit.Before; @@ -115,8 +112,7 @@ public class VpxPlaybackTest { public void run() { Looper.prepare(); LibvpxVideoRenderer videoRenderer = new LibvpxVideoRenderer(0); - DefaultTrackSelector trackSelector = new DefaultTrackSelector(context); - player = ExoPlayerFactory.newInstance(context, new Renderer[] {videoRenderer}, trackSelector); + player = new ExoPlayer.Builder(context, videoRenderer).build(); player.addListener(this); MediaSource mediaSource = new ProgressiveMediaSource.Factory( diff --git a/library/core/src/main/java/com/google/android/exoplayer2/DefaultRenderersFactory.java b/library/core/src/main/java/com/google/android/exoplayer2/DefaultRenderersFactory.java index 490d961396..a97b1e0d5a 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/DefaultRenderersFactory.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/DefaultRenderersFactory.java @@ -104,7 +104,7 @@ public class DefaultRenderersFactory implements RenderersFactory { /** * @deprecated Use {@link #DefaultRenderersFactory(Context)} and pass {@link DrmSessionManager} - * directly to {@link SimpleExoPlayer} or {@link ExoPlayerFactory}. + * directly to {@link SimpleExoPlayer.Builder}. */ @Deprecated @SuppressWarnings("deprecation") @@ -127,7 +127,7 @@ public class DefaultRenderersFactory implements RenderersFactory { /** * @deprecated Use {@link #DefaultRenderersFactory(Context)} and {@link * #setExtensionRendererMode(int)}, and pass {@link DrmSessionManager} directly to {@link - * SimpleExoPlayer} or {@link ExoPlayerFactory}. + * SimpleExoPlayer.Builder}. */ @Deprecated @SuppressWarnings("deprecation") @@ -154,7 +154,7 @@ public class DefaultRenderersFactory implements RenderersFactory { /** * @deprecated Use {@link #DefaultRenderersFactory(Context)}, {@link * #setExtensionRendererMode(int)} and {@link #setAllowedVideoJoiningTimeMs(long)}, and pass - * {@link DrmSessionManager} directly to {@link SimpleExoPlayer} or {@link ExoPlayerFactory}. + * {@link DrmSessionManager} directly to {@link SimpleExoPlayer.Builder}. */ @Deprecated public DefaultRenderersFactory( diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java index ee29af9c99..27c3a630f8 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java @@ -15,8 +15,10 @@ */ package com.google.android.exoplayer2; +import android.content.Context; import android.os.Looper; import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; import com.google.android.exoplayer2.audio.MediaCodecAudioRenderer; import com.google.android.exoplayer2.metadata.MetadataRenderer; import com.google.android.exoplayer2.source.ClippingMediaSource; @@ -29,12 +31,17 @@ import com.google.android.exoplayer2.source.SingleSampleMediaSource; import com.google.android.exoplayer2.text.TextRenderer; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; import com.google.android.exoplayer2.trackselection.TrackSelector; +import com.google.android.exoplayer2.upstream.BandwidthMeter; import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Clock; +import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.video.MediaCodecVideoRenderer; /** * An extensible media player that plays {@link MediaSource}s. Instances can be obtained from {@link - * ExoPlayerFactory}. + * SimpleExoPlayer.Builder} or {@link ExoPlayer.Builder}. * *

Player components

* @@ -117,6 +124,162 @@ import com.google.android.exoplayer2.video.MediaCodecVideoRenderer; */ public interface ExoPlayer extends Player { + /** + * A builder for {@link ExoPlayer} instances. + * + *

See {@link #Builder(Context, Renderer...)} for the list of default values. + */ + final class Builder { + + private final Renderer[] renderers; + + private Clock clock; + private TrackSelector trackSelector; + private LoadControl loadControl; + private BandwidthMeter bandwidthMeter; + private Looper looper; + private boolean buildCalled; + + /** + * Creates a builder with a list of {@link Renderer Renderers}. + * + *

The builder uses the following default values: + * + *

+ * + * @param context A {@link Context}. + * @param renderers The {@link Renderer Renderers} to be used by the player. + */ + public Builder(Context context, Renderer... renderers) { + this( + renderers, + new DefaultTrackSelector(context), + new DefaultLoadControl(), + DefaultBandwidthMeter.getSingletonInstance(context), + Util.getLooper(), + Clock.DEFAULT); + } + + /** + * Creates a builder with the specified custom components. + * + *

Note that this constructor is only useful if you try to ensure that ExoPlayer's default + * components can be removed by ProGuard or R8. For most components except renderers, there is + * only a marginal benefit of doing that. + * + * @param renderers The {@link Renderer Renderers} to be used by the player. + * @param trackSelector A {@link TrackSelector}. + * @param loadControl A {@link LoadControl}. + * @param bandwidthMeter A {@link BandwidthMeter}. + * @param looper A {@link Looper} that must be used for all calls to the player. + * @param clock A {@link Clock}. Should always be {@link Clock#DEFAULT}. + */ + public Builder( + Renderer[] renderers, + TrackSelector trackSelector, + LoadControl loadControl, + BandwidthMeter bandwidthMeter, + Looper looper, + Clock clock) { + Assertions.checkArgument(renderers.length > 0); + this.renderers = renderers; + this.trackSelector = trackSelector; + this.loadControl = loadControl; + this.bandwidthMeter = bandwidthMeter; + this.looper = looper; + this.clock = clock; + } + + /** + * Sets the {@link TrackSelector} that will be used by the player. + * + * @param trackSelector A {@link TrackSelector}. + * @return This builder. + * @throws IllegalStateException If {@link #build()} has already been called. + */ + public Builder setTrackSelector(TrackSelector trackSelector) { + Assertions.checkState(!buildCalled); + this.trackSelector = trackSelector; + return this; + } + + /** + * Sets the {@link LoadControl} that will be used by the player. + * + * @param loadControl A {@link LoadControl}. + * @return This builder. + * @throws IllegalStateException If {@link #build()} has already been called. + */ + public Builder setLoadControl(LoadControl loadControl) { + Assertions.checkState(!buildCalled); + this.loadControl = loadControl; + return this; + } + + /** + * Sets the {@link BandwidthMeter} that will be used by the player. + * + * @param bandwidthMeter A {@link BandwidthMeter}. + * @return This builder. + * @throws IllegalStateException If {@link #build()} has already been called. + */ + public Builder setBandwidthMeter(BandwidthMeter bandwidthMeter) { + Assertions.checkState(!buildCalled); + this.bandwidthMeter = bandwidthMeter; + return this; + } + + /** + * Sets the {@link Looper} that must be used for all calls to the player and that is used to + * call listeners on. + * + * @param looper A {@link Looper}. + * @return This builder. + * @throws IllegalStateException If {@link #build()} has already been called. + */ + public Builder setLooper(Looper looper) { + Assertions.checkState(!buildCalled); + this.looper = looper; + return this; + } + + /** + * Sets the {@link Clock} that will be used by the player. Should only be set for testing + * purposes. + * + * @param clock A {@link Clock}. + * @return This builder. + * @throws IllegalStateException If {@link #build()} has already been called. + */ + @VisibleForTesting + public Builder setClock(Clock clock) { + Assertions.checkState(!buildCalled); + this.clock = clock; + return this; + } + + /** + * Builds an {@link ExoPlayer} instance. + * + * @throws IllegalStateException If {@link #build()} has already been called. + */ + public ExoPlayer build() { + Assertions.checkState(!buildCalled); + buildCalled = true; + return new ExoPlayerImpl( + renderers, trackSelector, loadControl, bandwidthMeter, clock, looper); + } + } + /** Returns the {@link Looper} associated with the playback thread. */ Looper getPlaybackLooper(); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerFactory.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerFactory.java index 9168f1bd76..82bc94dab8 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerFactory.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerFactory.java @@ -28,30 +28,15 @@ import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter; import com.google.android.exoplayer2.util.Clock; import com.google.android.exoplayer2.util.Util; -/** - * A factory for {@link ExoPlayer} instances. - */ +/** @deprecated Use {@link SimpleExoPlayer.Builder} or {@link ExoPlayer.Builder} instead. */ +@Deprecated public final class ExoPlayerFactory { - private static @Nullable BandwidthMeter singletonBandwidthMeter; - private ExoPlayerFactory() {} - /** - * Creates a {@link SimpleExoPlayer} instance. - * - * @param context A {@link Context}. - * @param trackSelector The {@link TrackSelector} that will be used by the instance. - * @param loadControl The {@link LoadControl} that will be used by the instance. - * @param drmSessionManager An optional {@link DrmSessionManager}. May be null if the instance - * will not be used for DRM protected playbacks. - * @param extensionRendererMode The extension renderer mode, which determines if and how available - * extension renderers are used. Note that extensions must be included in the application - * build for them to be considered available. - * @deprecated Use {@link #newSimpleInstance(Context, RenderersFactory, TrackSelector, - * LoadControl, DrmSessionManager)}. - */ + /** @deprecated Use {@link SimpleExoPlayer.Builder} instead. */ @Deprecated + @SuppressWarnings("deprecation") public static SimpleExoPlayer newSimpleInstance( Context context, TrackSelector trackSelector, @@ -64,23 +49,9 @@ public final class ExoPlayerFactory { context, renderersFactory, trackSelector, loadControl, drmSessionManager); } - /** - * Creates a {@link SimpleExoPlayer} instance. - * - * @param context A {@link Context}. - * @param trackSelector The {@link TrackSelector} that will be used by the instance. - * @param loadControl The {@link LoadControl} that will be used by the instance. - * @param drmSessionManager An optional {@link DrmSessionManager}. May be null if the instance - * will not be used for DRM protected playbacks. - * @param extensionRendererMode The extension renderer mode, which determines if and how available - * extension renderers are used. Note that extensions must be included in the application - * build for them to be considered available. - * @param allowedVideoJoiningTimeMs The maximum duration for which a video renderer can attempt to - * seamlessly join an ongoing playback. - * @deprecated Use {@link #newSimpleInstance(Context, RenderersFactory, TrackSelector, - * LoadControl, DrmSessionManager)}. - */ + /** @deprecated Use {@link SimpleExoPlayer.Builder} instead. */ @Deprecated + @SuppressWarnings("deprecation") public static SimpleExoPlayer newSimpleInstance( Context context, TrackSelector trackSelector, @@ -96,59 +67,40 @@ public final class ExoPlayerFactory { context, renderersFactory, trackSelector, loadControl, drmSessionManager); } - /** - * Creates a {@link SimpleExoPlayer} instance. - * - * @param context A {@link Context}. - */ + /** @deprecated Use {@link SimpleExoPlayer.Builder} instead. */ + @Deprecated + @SuppressWarnings("deprecation") public static SimpleExoPlayer newSimpleInstance(Context context) { return newSimpleInstance(context, new DefaultTrackSelector(context)); } - /** - * Creates a {@link SimpleExoPlayer} instance. - * - * @param context A {@link Context}. - * @param trackSelector The {@link TrackSelector} that will be used by the instance. - */ + /** @deprecated Use {@link SimpleExoPlayer.Builder} instead. */ + @Deprecated + @SuppressWarnings("deprecation") public static SimpleExoPlayer newSimpleInstance(Context context, TrackSelector trackSelector) { return newSimpleInstance(context, new DefaultRenderersFactory(context), trackSelector); } - /** - * Creates a {@link SimpleExoPlayer} instance. - * - * @param context A {@link Context}. - * @param renderersFactory A factory for creating {@link Renderer}s to be used by the instance. - * @param trackSelector The {@link TrackSelector} that will be used by the instance. - */ + /** @deprecated Use {@link SimpleExoPlayer.Builder} instead. */ + @Deprecated + @SuppressWarnings("deprecation") public static SimpleExoPlayer newSimpleInstance( Context context, RenderersFactory renderersFactory, TrackSelector trackSelector) { return newSimpleInstance(context, renderersFactory, trackSelector, new DefaultLoadControl()); } - /** - * Creates a {@link SimpleExoPlayer} instance. - * - * @param context A {@link Context}. - * @param trackSelector The {@link TrackSelector} that will be used by the instance. - * @param loadControl The {@link LoadControl} that will be used by the instance. - */ + /** @deprecated Use {@link SimpleExoPlayer.Builder} instead. */ + @Deprecated + @SuppressWarnings("deprecation") public static SimpleExoPlayer newSimpleInstance( Context context, TrackSelector trackSelector, LoadControl loadControl) { RenderersFactory renderersFactory = new DefaultRenderersFactory(context); return newSimpleInstance(context, renderersFactory, trackSelector, loadControl); } - /** - * Creates a {@link SimpleExoPlayer} instance. Available extension renderers are not used. - * - * @param context A {@link Context}. - * @param trackSelector The {@link TrackSelector} that will be used by the instance. - * @param loadControl The {@link LoadControl} that will be used by the instance. - * @param drmSessionManager An optional {@link DrmSessionManager}. May be null if the instance - * will not be used for DRM protected playbacks. - */ + /** @deprecated Use {@link SimpleExoPlayer.Builder} instead. */ + @Deprecated + @SuppressWarnings("deprecation") public static SimpleExoPlayer newSimpleInstance( Context context, TrackSelector trackSelector, @@ -159,15 +111,9 @@ public final class ExoPlayerFactory { context, renderersFactory, trackSelector, loadControl, drmSessionManager); } - /** - * Creates a {@link SimpleExoPlayer} instance. - * - * @param context A {@link Context}. - * @param renderersFactory A factory for creating {@link Renderer}s to be used by the instance. - * @param trackSelector The {@link TrackSelector} that will be used by the instance. - * @param drmSessionManager An optional {@link DrmSessionManager}. May be null if the instance - * will not be used for DRM protected playbacks. - */ + /** @deprecated Use {@link SimpleExoPlayer.Builder} instead. */ + @Deprecated + @SuppressWarnings("deprecation") public static SimpleExoPlayer newSimpleInstance( Context context, RenderersFactory renderersFactory, @@ -177,14 +123,9 @@ public final class ExoPlayerFactory { context, renderersFactory, trackSelector, new DefaultLoadControl(), drmSessionManager); } - /** - * Creates a {@link SimpleExoPlayer} instance. - * - * @param context A {@link Context}. - * @param renderersFactory A factory for creating {@link Renderer}s to be used by the instance. - * @param trackSelector The {@link TrackSelector} that will be used by the instance. - * @param loadControl The {@link LoadControl} that will be used by the instance. - */ + /** @deprecated Use {@link SimpleExoPlayer.Builder} instead. */ + @Deprecated + @SuppressWarnings("deprecation") public static SimpleExoPlayer newSimpleInstance( Context context, RenderersFactory renderersFactory, @@ -199,16 +140,9 @@ public final class ExoPlayerFactory { Util.getLooper()); } - /** - * Creates a {@link SimpleExoPlayer} instance. - * - * @param context A {@link Context}. - * @param renderersFactory A factory for creating {@link Renderer}s to be used by the instance. - * @param trackSelector The {@link TrackSelector} that will be used by the instance. - * @param loadControl The {@link LoadControl} that will be used by the instance. - * @param drmSessionManager An optional {@link DrmSessionManager}. May be null if the instance - * will not be used for DRM protected playbacks. - */ + /** @deprecated Use {@link SimpleExoPlayer.Builder} instead. */ + @Deprecated + @SuppressWarnings("deprecation") public static SimpleExoPlayer newSimpleInstance( Context context, RenderersFactory renderersFactory, @@ -219,17 +153,9 @@ public final class ExoPlayerFactory { context, renderersFactory, trackSelector, loadControl, drmSessionManager, Util.getLooper()); } - /** - * Creates a {@link SimpleExoPlayer} instance. - * - * @param context A {@link Context}. - * @param renderersFactory A factory for creating {@link Renderer}s to be used by the instance. - * @param trackSelector The {@link TrackSelector} that will be used by the instance. - * @param loadControl The {@link LoadControl} that will be used by the instance. - * @param drmSessionManager An optional {@link DrmSessionManager}. May be null if the instance - * will not be used for DRM protected playbacks. - * @param bandwidthMeter The {@link BandwidthMeter} that will be used by the instance. - */ + /** @deprecated Use {@link SimpleExoPlayer.Builder} instead. */ + @Deprecated + @SuppressWarnings("deprecation") public static SimpleExoPlayer newSimpleInstance( Context context, RenderersFactory renderersFactory, @@ -248,18 +174,9 @@ public final class ExoPlayerFactory { Util.getLooper()); } - /** - * Creates a {@link SimpleExoPlayer} instance. - * - * @param context A {@link Context}. - * @param renderersFactory A factory for creating {@link Renderer}s to be used by the instance. - * @param trackSelector The {@link TrackSelector} that will be used by the instance. - * @param loadControl The {@link LoadControl} that will be used by the instance. - * @param drmSessionManager An optional {@link DrmSessionManager}. May be null if the instance - * will not be used for DRM protected playbacks. - * @param analyticsCollector The {@link AnalyticsCollector} that will collect and forward all - * player events. - */ + /** @deprecated Use {@link SimpleExoPlayer.Builder} instead. */ + @Deprecated + @SuppressWarnings("deprecation") public static SimpleExoPlayer newSimpleInstance( Context context, RenderersFactory renderersFactory, @@ -277,18 +194,9 @@ public final class ExoPlayerFactory { Util.getLooper()); } - /** - * Creates a {@link SimpleExoPlayer} instance. - * - * @param context A {@link Context}. - * @param renderersFactory A factory for creating {@link Renderer}s to be used by the instance. - * @param trackSelector The {@link TrackSelector} that will be used by the instance. - * @param loadControl The {@link LoadControl} that will be used by the instance. - * @param drmSessionManager An optional {@link DrmSessionManager}. May be null if the instance - * will not be used for DRM protected playbacks. - * @param looper The {@link Looper} which must be used for all calls to the player and which is - * used to call listeners on. - */ + /** @deprecated Use {@link SimpleExoPlayer.Builder} instead. */ + @Deprecated + @SuppressWarnings("deprecation") public static SimpleExoPlayer newSimpleInstance( Context context, RenderersFactory renderersFactory, @@ -306,20 +214,9 @@ public final class ExoPlayerFactory { looper); } - /** - * Creates a {@link SimpleExoPlayer} instance. - * - * @param context A {@link Context}. - * @param renderersFactory A factory for creating {@link Renderer}s to be used by the instance. - * @param trackSelector The {@link TrackSelector} that will be used by the instance. - * @param loadControl The {@link LoadControl} that will be used by the instance. - * @param drmSessionManager An optional {@link DrmSessionManager}. May be null if the instance - * will not be used for DRM protected playbacks. - * @param analyticsCollector The {@link AnalyticsCollector} that will collect and forward all - * player events. - * @param looper The {@link Looper} which must be used for all calls to the player and which is - * used to call listeners on. - */ + /** @deprecated Use {@link SimpleExoPlayer.Builder} instead. */ + @Deprecated + @SuppressWarnings("deprecation") public static SimpleExoPlayer newSimpleInstance( Context context, RenderersFactory renderersFactory, @@ -334,25 +231,13 @@ public final class ExoPlayerFactory { trackSelector, loadControl, drmSessionManager, - getDefaultBandwidthMeter(context), + DefaultBandwidthMeter.getSingletonInstance(context), analyticsCollector, looper); } - /** - * Creates a {@link SimpleExoPlayer} instance. - * - * @param context A {@link Context}. - * @param renderersFactory A factory for creating {@link Renderer}s to be used by the instance. - * @param trackSelector The {@link TrackSelector} that will be used by the instance. - * @param loadControl The {@link LoadControl} that will be used by the instance. - * @param drmSessionManager An optional {@link DrmSessionManager}. May be null if the instance - * will not be used for DRM protected playbacks. - * @param analyticsCollector The {@link AnalyticsCollector} that will collect and forward all - * player events. - * @param looper The {@link Looper} which must be used for all calls to the player and which is - * used to call listeners on. - */ + /** @deprecated Use {@link SimpleExoPlayer.Builder} instead. */ + @Deprecated public static SimpleExoPlayer newSimpleInstance( Context context, RenderersFactory renderersFactory, @@ -373,41 +258,25 @@ public final class ExoPlayerFactory { looper); } - /** - * Creates an {@link ExoPlayer} instance. - * - * @param context A {@link Context}. - * @param renderers The {@link Renderer}s that will be used by the instance. - * @param trackSelector The {@link TrackSelector} that will be used by the instance. - */ + /** @deprecated Use {@link ExoPlayer.Builder} instead. */ + @Deprecated + @SuppressWarnings("deprecation") public static ExoPlayer newInstance( Context context, Renderer[] renderers, TrackSelector trackSelector) { return newInstance(context, renderers, trackSelector, new DefaultLoadControl()); } - /** - * Creates an {@link ExoPlayer} instance. - * - * @param context A {@link Context}. - * @param renderers The {@link Renderer}s that will be used by the instance. - * @param trackSelector The {@link TrackSelector} that will be used by the instance. - * @param loadControl The {@link LoadControl} that will be used by the instance. - */ + /** @deprecated Use {@link ExoPlayer.Builder} instead. */ + @Deprecated + @SuppressWarnings("deprecation") public static ExoPlayer newInstance( Context context, Renderer[] renderers, TrackSelector trackSelector, LoadControl loadControl) { return newInstance(context, renderers, trackSelector, loadControl, Util.getLooper()); } - /** - * Creates an {@link ExoPlayer} instance. - * - * @param context A {@link Context}. - * @param renderers The {@link Renderer}s that will be used by the instance. - * @param trackSelector The {@link TrackSelector} that will be used by the instance. - * @param loadControl The {@link LoadControl} that will be used by the instance. - * @param looper The {@link Looper} which must be used for all calls to the player and which is - * used to call listeners on. - */ + /** @deprecated Use {@link ExoPlayer.Builder} instead. */ + @Deprecated + @SuppressWarnings("deprecation") public static ExoPlayer newInstance( Context context, Renderer[] renderers, @@ -415,21 +284,16 @@ public final class ExoPlayerFactory { LoadControl loadControl, Looper looper) { return newInstance( - context, renderers, trackSelector, loadControl, getDefaultBandwidthMeter(context), looper); + context, + renderers, + trackSelector, + loadControl, + DefaultBandwidthMeter.getSingletonInstance(context), + looper); } - /** - * Creates an {@link ExoPlayer} instance. - * - * @param context A {@link Context}. - * @param renderers The {@link Renderer}s that will be used by the instance. - * @param trackSelector The {@link TrackSelector} that will be used by the instance. - * @param loadControl The {@link LoadControl} that will be used by the instance. - * @param bandwidthMeter The {@link BandwidthMeter} that will be used by the instance. - * @param looper The {@link Looper} which must be used for all calls to the player and which is - * used to call listeners on. - */ - @SuppressWarnings("unused") + /** @deprecated Use {@link ExoPlayer.Builder} instead. */ + @Deprecated public static ExoPlayer newInstance( Context context, Renderer[] renderers, @@ -440,11 +304,4 @@ public final class ExoPlayerFactory { return new ExoPlayerImpl( renderers, trackSelector, loadControl, bandwidthMeter, Clock.DEFAULT, looper); } - - private static synchronized BandwidthMeter getDefaultBandwidthMeter(Context context) { - if (singletonBandwidthMeter == null) { - singletonBandwidthMeter = new DefaultBandwidthMeter.Builder(context).build(); - } - return singletonBandwidthMeter; - } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java index e99429d3b2..cacdaec02e 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java @@ -37,7 +37,9 @@ import com.google.android.exoplayer2.util.Util; import java.util.ArrayDeque; import java.util.concurrent.CopyOnWriteArrayList; -/** An {@link ExoPlayer} implementation. Instances can be obtained from {@link ExoPlayerFactory}. */ +/** + * An {@link ExoPlayer} implementation. Instances can be obtained from {@link ExoPlayer.Builder}. + */ /* package */ final class ExoPlayerImpl extends BasePlayer implements ExoPlayer { private static final String TAG = "ExoPlayerImpl"; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java index 8913fbdaba..749cf79e78 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java @@ -24,6 +24,7 @@ import android.media.PlaybackParams; import android.os.Handler; import android.os.Looper; import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; import android.view.Surface; import android.view.SurfaceHolder; import android.view.SurfaceView; @@ -45,9 +46,11 @@ import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.text.Cue; import com.google.android.exoplayer2.text.TextOutput; +import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.trackselection.TrackSelector; import com.google.android.exoplayer2.upstream.BandwidthMeter; +import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter; import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Clock; import com.google.android.exoplayer2.util.Log; @@ -63,7 +66,7 @@ import java.util.concurrent.CopyOnWriteArraySet; /** * An {@link ExoPlayer} implementation that uses default {@link Renderer} components. Instances can - * be obtained from {@link ExoPlayerFactory}. + * be obtained from {@link SimpleExoPlayer.Builder}. */ public class SimpleExoPlayer extends BasePlayer implements ExoPlayer, @@ -76,6 +79,229 @@ public class SimpleExoPlayer extends BasePlayer @Deprecated public interface VideoListener extends com.google.android.exoplayer2.video.VideoListener {} + /** + * A builder for {@link SimpleExoPlayer} instances. + * + *

See {@link #Builder(Context)} for the list of default values. + */ + public static final class Builder { + + private final Context context; + private final RenderersFactory renderersFactory; + + private Clock clock; + private TrackSelector trackSelector; + private LoadControl loadControl; + private DrmSessionManager drmSessionManager; + private BandwidthMeter bandwidthMeter; + private AnalyticsCollector analyticsCollector; + private Looper looper; + private boolean buildCalled; + + /** + * Creates a builder. + * + *

Use {@link #Builder(Context, RenderersFactory)} instead, if you intend to provide a custom + * {@link RenderersFactory}. This is to ensure that ProGuard or R8 can remove ExoPlayer's {@link + * DefaultRenderersFactory} from the APK. + * + *

The builder uses the following default values: + * + *

+ * + * @param context A {@link Context}. + */ + public Builder(Context context) { + this(context, new DefaultRenderersFactory(context)); + } + + /** + * Creates a builder with a custom {@link RenderersFactory}. + * + *

See {@link #Builder(Context)} for a list of default values. + * + * @param context A {@link Context}. + * @param renderersFactory A factory for creating {@link Renderer Renderers} to be used by the + * player. + */ + public Builder(Context context, RenderersFactory renderersFactory) { + this( + context, + renderersFactory, + new DefaultTrackSelector(context), + new DefaultLoadControl(), + DrmSessionManager.getDummyDrmSessionManager(), + DefaultBandwidthMeter.getSingletonInstance(context), + Util.getLooper(), + new AnalyticsCollector(Clock.DEFAULT), + Clock.DEFAULT); + } + + /** + * Creates a builder with the specified custom components. + * + *

Note that this constructor is only useful if you try to ensure that ExoPlayer's default + * components can be removed by ProGuard or R8. For most components except renderers, there is + * only a marginal benefit of doing that. + * + * @param context A {@link Context}. + * @param renderersFactory A factory for creating {@link Renderer Renderers} to be used by the + * player. + * @param trackSelector A {@link TrackSelector}. + * @param loadControl A {@link LoadControl}. + * @param drmSessionManager A {@link DrmSessionManager}. + * @param bandwidthMeter A {@link BandwidthMeter}. + * @param looper A {@link Looper} that must be used for all calls to the player. + * @param analyticsCollector An {@link AnalyticsCollector}. + * @param clock A {@link Clock}. Should always be {@link Clock#DEFAULT}. + */ + public Builder( + Context context, + RenderersFactory renderersFactory, + TrackSelector trackSelector, + LoadControl loadControl, + DrmSessionManager drmSessionManager, + BandwidthMeter bandwidthMeter, + Looper looper, + AnalyticsCollector analyticsCollector, + Clock clock) { + this.context = context; + this.renderersFactory = renderersFactory; + this.trackSelector = trackSelector; + this.loadControl = loadControl; + this.drmSessionManager = drmSessionManager; + this.bandwidthMeter = bandwidthMeter; + this.looper = looper; + this.analyticsCollector = analyticsCollector; + this.clock = clock; + } + + /** + * Sets the {@link TrackSelector} that will be used by the player. + * + * @param trackSelector A {@link TrackSelector}. + * @return This builder. + * @throws IllegalStateException If {@link #build()} has already been called. + */ + public Builder setTrackSelector(TrackSelector trackSelector) { + Assertions.checkState(!buildCalled); + this.trackSelector = trackSelector; + return this; + } + + /** + * Sets the {@link LoadControl} that will be used by the player. + * + * @param loadControl A {@link LoadControl}. + * @return This builder. + * @throws IllegalStateException If {@link #build()} has already been called. + */ + public Builder setLoadControl(LoadControl loadControl) { + Assertions.checkState(!buildCalled); + this.loadControl = loadControl; + return this; + } + + /** + * Sets the {@link DrmSessionManager} that will be used for DRM protected playbacks. + * + * @param drmSessionManager A {@link DrmSessionManager}. + * @return This builder. + * @throws IllegalStateException If {@link #build()} has already been called. + */ + public Builder setDrmSessionManager(DrmSessionManager drmSessionManager) { + Assertions.checkState(!buildCalled); + this.drmSessionManager = drmSessionManager; + return this; + } + + /** + * Sets the {@link BandwidthMeter} that will be used by the player. + * + * @param bandwidthMeter A {@link BandwidthMeter}. + * @return This builder. + * @throws IllegalStateException If {@link #build()} has already been called. + */ + public Builder setBandwidthMeter(BandwidthMeter bandwidthMeter) { + Assertions.checkState(!buildCalled); + this.bandwidthMeter = bandwidthMeter; + return this; + } + + /** + * Sets the {@link Looper} that must be used for all calls to the player and that is used to + * call listeners on. + * + * @param looper A {@link Looper}. + * @return This builder. + * @throws IllegalStateException If {@link #build()} has already been called. + */ + public Builder setLooper(Looper looper) { + Assertions.checkState(!buildCalled); + this.looper = looper; + return this; + } + + /** + * Sets the {@link AnalyticsCollector} that will collect and forward all player events. + * + * @param analyticsCollector An {@link AnalyticsCollector}. + * @return This builder. + * @throws IllegalStateException If {@link #build()} has already been called. + */ + public Builder setAnalyticsCollector(AnalyticsCollector analyticsCollector) { + Assertions.checkState(!buildCalled); + this.analyticsCollector = analyticsCollector; + return this; + } + + /** + * Sets the {@link Clock} that will be used by the player. Should only be set for testing + * purposes. + * + * @param clock A {@link Clock}. + * @return This builder. + * @throws IllegalStateException If {@link #build()} has already been called. + */ + @VisibleForTesting + public Builder setClock(Clock clock) { + Assertions.checkState(!buildCalled); + this.clock = clock; + return this; + } + + /** + * Builds a {@link SimpleExoPlayer} instance. + * + * @throws IllegalStateException If {@link #build()} has already been called. + */ + public SimpleExoPlayer build() { + Assertions.checkState(!buildCalled); + buildCalled = true; + return new SimpleExoPlayer( + context, + renderersFactory, + trackSelector, + loadControl, + drmSessionManager, + bandwidthMeter, + analyticsCollector, + clock, + looper); + } + } + private static final String TAG = "SimpleExoPlayer"; protected final Renderer[] renderers; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/AdaptiveTrackSelection.java b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/AdaptiveTrackSelection.java index c5d22c15cb..f457701031 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/AdaptiveTrackSelection.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/AdaptiveTrackSelection.java @@ -17,7 +17,6 @@ package com.google.android.exoplayer2.trackselection; import androidx.annotation.Nullable; import com.google.android.exoplayer2.C; -import com.google.android.exoplayer2.ExoPlayerFactory; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.source.TrackGroup; import com.google.android.exoplayer2.source.chunk.MediaChunk; @@ -64,7 +63,7 @@ public class AdaptiveTrackSelection extends BaseTrackSelection { /** * @deprecated Use {@link #Factory()} instead. Custom bandwidth meter should be directly passed - * to the player in {@link ExoPlayerFactory}. + * to the player in {@link SimpleExoPlayer.Builder}. */ @Deprecated @SuppressWarnings("deprecation") @@ -112,7 +111,7 @@ public class AdaptiveTrackSelection extends BaseTrackSelection { /** * @deprecated Use {@link #Factory(int, int, int, float)} instead. Custom bandwidth meter should - * be directly passed to the player in {@link ExoPlayerFactory}. + * be directly passed to the player in {@link SimpleExoPlayer.Builder}. */ @Deprecated @SuppressWarnings("deprecation") @@ -181,7 +180,8 @@ public class AdaptiveTrackSelection extends BaseTrackSelection { /** * @deprecated Use {@link #Factory(int, int, int, float, float, long, Clock)} instead. Custom - * bandwidth meter should be directly passed to the player in {@link ExoPlayerFactory}. + * bandwidth meter should be directly passed to the player in {@link + * SimpleExoPlayer.Builder}. */ @Deprecated public Factory( diff --git a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java index 8e1284f7ef..b43701f1bc 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java @@ -26,7 +26,6 @@ import android.util.SparseArray; import android.util.SparseBooleanArray; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlaybackException; -import com.google.android.exoplayer2.ExoPlayerFactory; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Renderer; @@ -1408,7 +1407,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { /** * @deprecated Use {@link #DefaultTrackSelector(Context)} instead. The bandwidth meter should be - * passed directly to the player in {@link ExoPlayerFactory}. + * passed directly to the player in {@link SimpleExoPlayer.Builder}. */ @Deprecated @SuppressWarnings("deprecation") diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultBandwidthMeter.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultBandwidthMeter.java index 9f76ca544f..67dd9a7a55 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultBandwidthMeter.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultBandwidthMeter.java @@ -79,6 +79,8 @@ public final class DefaultBandwidthMeter implements BandwidthMeter, TransferList /** Default maximum weight for the sliding window. */ public static final int DEFAULT_SLIDING_WINDOW_MAX_WEIGHT = 2000; + @Nullable private static DefaultBandwidthMeter singletonInstance; + /** Builder for a bandwidth meter. */ public static final class Builder { @@ -214,6 +216,19 @@ public final class DefaultBandwidthMeter implements BandwidthMeter, TransferList } } + /** + * Returns a singleton instance of a {@link DefaultBandwidthMeter} with default configuration. + * + * @param context A {@link Context}. + * @return The singleton instance. + */ + public static synchronized DefaultBandwidthMeter getSingletonInstance(Context context) { + if (singletonInstance == null) { + singletonInstance = new DefaultBandwidthMeter.Builder(context).build(); + } + return singletonInstance; + } + private static final int ELAPSED_MILLIS_FOR_ESTIMATE = 2000; private static final int BYTES_TRANSFERRED_FOR_ESTIMATE = 512 * 1024; diff --git a/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashTestRunner.java b/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashTestRunner.java index e452e391d5..e2fc079887 100644 --- a/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashTestRunner.java +++ b/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashTestRunner.java @@ -23,8 +23,6 @@ import android.media.UnsupportedSchemeException; import android.net.Uri; import android.view.Surface; import com.google.android.exoplayer2.C; -import com.google.android.exoplayer2.DefaultLoadControl; -import com.google.android.exoplayer2.ExoPlayerFactory; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.RendererCapabilities; import com.google.android.exoplayer2.SimpleExoPlayer; @@ -290,12 +288,10 @@ public final class DashTestRunner { MappingTrackSelector trackSelector, DrmSessionManager drmSessionManager) { SimpleExoPlayer player = - ExoPlayerFactory.newSimpleInstance( - host, - new DebugRenderersFactory(host), - trackSelector, - new DefaultLoadControl(), - drmSessionManager); + new SimpleExoPlayer.Builder(host, new DebugRenderersFactory(host)) + .setTrackSelector(trackSelector) + .setDrmSessionManager(drmSessionManager) + .build(); player.setVideoSurface(surface); return player; } diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExoHostedTest.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExoHostedTest.java index 3ebd47b7a6..214c51c00c 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExoHostedTest.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExoHostedTest.java @@ -22,13 +22,10 @@ import android.os.Looper; import android.os.SystemClock; import android.view.Surface; import com.google.android.exoplayer2.C; -import com.google.android.exoplayer2.DefaultLoadControl; import com.google.android.exoplayer2.DefaultRenderersFactory; import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlayer; -import com.google.android.exoplayer2.ExoPlayerFactory; import com.google.android.exoplayer2.Player; -import com.google.android.exoplayer2.RenderersFactory; import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.analytics.AnalyticsListener; import com.google.android.exoplayer2.audio.DefaultAudioSink; @@ -245,14 +242,14 @@ public abstract class ExoHostedTest implements AnalyticsListener, HostedTest { Surface surface, MappingTrackSelector trackSelector, DrmSessionManager drmSessionManager) { - RenderersFactory renderersFactory = - new DefaultRenderersFactory( - host, - DefaultRenderersFactory.EXTENSION_RENDERER_MODE_OFF, - /* allowedVideoJoiningTimeMs= */ 0); + DefaultRenderersFactory renderersFactory = new DefaultRenderersFactory(host); + renderersFactory.setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_OFF); + renderersFactory.setAllowedVideoJoiningTimeMs(/* allowedVideoJoiningTimeMs= */ 0); SimpleExoPlayer player = - ExoPlayerFactory.newSimpleInstance( - host, renderersFactory, trackSelector, new DefaultLoadControl(), drmSessionManager); + new SimpleExoPlayer.Builder(host, renderersFactory) + .setTrackSelector(trackSelector) + .setDrmSessionManager(drmSessionManager) + .build(); player.setVideoSurface(surface); return player; }