From 6aab2bdc5545b8013e0989b4034efa572c139d1a Mon Sep 17 00:00:00 2001 From: tonihei Date: Tue, 17 Jul 2018 02:38:15 -0700 Subject: [PATCH] Set bandwidth meter at player level. This bandwidth meter is then forwarded to the track selection and as a transfer listener to media and data sources. When no bandwidth meter is specified in the ExoPlayerFactory methods, a static singleton instance will be used. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=204881497 --- RELEASENOTES.md | 10 +- .../android/exoplayer2/ExoPlayerFactory.java | 106 +++++++++++++++++- .../android/exoplayer2/ExoPlayerImpl.java | 4 + .../exoplayer2/ExoPlayerImplInternal.java | 8 +- .../android/exoplayer2/SimpleExoPlayer.java | 29 +++-- .../testutil/ExoPlayerTestRunner.java | 2 + 6 files changed, 133 insertions(+), 26 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 1c822aef5b..05e5cf6751 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -28,14 +28,18 @@ * Add support for lazy preparation of playlist media sources in `ConcatenatingMediaSource` ([#3972](https://github.com/google/ExoPlayer/issues/3972)). -* `BandwidthMeter` management (work in progress): +* `BandwidthMeter` management: + * Pass `BandwidthMeter` directly to `ExoPlayerFactory` instead of + `TrackSelection.Factory` and `DataSource.Factory`. May also be omitted to + use the default bandwidth meter automatically. This change only works + correctly if the following changes are adopted for custom `BandwidthMeter`s, + `TrackSelection`s, `MediaSource`s and `DataSource`s. * Pass `BandwidthMeter` to `TrackSelection.Factory` which can be used to - obtain bandwidth estimates in the future. Always null at the moment. + obtain bandwidth estimates. * Add method to `BandwidthMeter` to return the `TransferListener` used to gather bandwidth information. Also add methods to add and remove event listeners. * Pass `TransferListener` to `MediaSource`s to listen to media data transfers. - Always null at the moment. * Add method to `DataSource` to add `TransferListener`s. Custom `DataSource`s directly reading data should implement `BaseDataSource` to handle the registration correctly. Custom `DataSource`'s forwarding to other sources 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 e8bd8b34f6..bbbfa8fd09 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 @@ -22,6 +22,8 @@ import com.google.android.exoplayer2.analytics.AnalyticsCollector; import com.google.android.exoplayer2.drm.DrmSessionManager; import com.google.android.exoplayer2.drm.FrameworkMediaCrypto; 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.Clock; import com.google.android.exoplayer2.util.Util; @@ -30,6 +32,8 @@ import com.google.android.exoplayer2.util.Util; */ public final class ExoPlayerFactory { + private static @Nullable BandwidthMeter singletonBandwidthMeter; + private ExoPlayerFactory() {} /** @@ -157,7 +161,7 @@ public final class ExoPlayerFactory { */ public static SimpleExoPlayer newSimpleInstance(RenderersFactory renderersFactory, TrackSelector trackSelector, LoadControl loadControl) { - return new SimpleExoPlayer( + return newSimpleInstance( renderersFactory, trackSelector, loadControl, @@ -179,10 +183,36 @@ public final class ExoPlayerFactory { TrackSelector trackSelector, LoadControl loadControl, @Nullable DrmSessionManager drmSessionManager) { - return new SimpleExoPlayer( + return newSimpleInstance( renderersFactory, trackSelector, loadControl, drmSessionManager, Util.getLooper()); } + /** + * Creates a {@link SimpleExoPlayer} instance. + * + * @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. + */ + public static SimpleExoPlayer newSimpleInstance( + RenderersFactory renderersFactory, + TrackSelector trackSelector, + LoadControl loadControl, + @Nullable DrmSessionManager drmSessionManager, + BandwidthMeter bandwidthMeter) { + return newSimpleInstance( + renderersFactory, + trackSelector, + loadControl, + drmSessionManager, + bandwidthMeter, + new AnalyticsCollector.Factory(), + Util.getLooper()); + } + /** * Creates a {@link SimpleExoPlayer} instance. * @@ -200,7 +230,7 @@ public final class ExoPlayerFactory { LoadControl loadControl, @Nullable DrmSessionManager drmSessionManager, AnalyticsCollector.Factory analyticsCollectorFactory) { - return new SimpleExoPlayer( + return newSimpleInstance( renderersFactory, trackSelector, loadControl, @@ -226,8 +256,13 @@ public final class ExoPlayerFactory { LoadControl loadControl, @Nullable DrmSessionManager drmSessionManager, Looper looper) { - return new SimpleExoPlayer( - renderersFactory, trackSelector, loadControl, drmSessionManager, looper); + return newSimpleInstance( + renderersFactory, + trackSelector, + loadControl, + drmSessionManager, + new AnalyticsCollector.Factory(), + looper); } /** @@ -250,11 +285,43 @@ public final class ExoPlayerFactory { @Nullable DrmSessionManager drmSessionManager, AnalyticsCollector.Factory analyticsCollectorFactory, Looper looper) { + return newSimpleInstance( + renderersFactory, + trackSelector, + loadControl, + drmSessionManager, + getDefaultBandwidthMeter(), + analyticsCollectorFactory, + looper); + } + + /** + * Creates a {@link SimpleExoPlayer} instance. + * + * @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 analyticsCollectorFactory A factory for creating 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. + */ + public static SimpleExoPlayer newSimpleInstance( + RenderersFactory renderersFactory, + TrackSelector trackSelector, + LoadControl loadControl, + @Nullable DrmSessionManager drmSessionManager, + BandwidthMeter bandwidthMeter, + AnalyticsCollector.Factory analyticsCollectorFactory, + Looper looper) { return new SimpleExoPlayer( renderersFactory, trackSelector, loadControl, drmSessionManager, + bandwidthMeter, analyticsCollectorFactory, looper); } @@ -292,6 +359,33 @@ public final class ExoPlayerFactory { */ public static ExoPlayer newInstance( Renderer[] renderers, TrackSelector trackSelector, LoadControl loadControl, Looper looper) { - return new ExoPlayerImpl(renderers, trackSelector, loadControl, Clock.DEFAULT, looper); + return newInstance(renderers, trackSelector, loadControl, getDefaultBandwidthMeter(), looper); + } + + /** + * Creates an {@link ExoPlayer} instance. + * + * @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. + */ + public static ExoPlayer newInstance( + Renderer[] renderers, + TrackSelector trackSelector, + LoadControl loadControl, + BandwidthMeter bandwidthMeter, + Looper looper) { + return new ExoPlayerImpl( + renderers, trackSelector, loadControl, bandwidthMeter, Clock.DEFAULT, looper); + } + + private static synchronized BandwidthMeter getDefaultBandwidthMeter() { + if (singletonBandwidthMeter == null) { + singletonBandwidthMeter = new DefaultBandwidthMeter.Builder().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 51858a5cae..2c3a4fab1b 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 @@ -30,6 +30,7 @@ import com.google.android.exoplayer2.trackselection.TrackSelection; import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.trackselection.TrackSelector; import com.google.android.exoplayer2.trackselection.TrackSelectorResult; +import com.google.android.exoplayer2.upstream.BandwidthMeter; import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Clock; import com.google.android.exoplayer2.util.Util; @@ -81,6 +82,7 @@ import java.util.concurrent.CopyOnWriteArraySet; * @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 clock The {@link Clock} 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. @@ -90,6 +92,7 @@ import java.util.concurrent.CopyOnWriteArraySet; Renderer[] renderers, TrackSelector trackSelector, LoadControl loadControl, + BandwidthMeter bandwidthMeter, Clock clock, Looper looper) { Log.i(TAG, "Init " + Integer.toHexString(System.identityHashCode(this)) + " [" @@ -130,6 +133,7 @@ import java.util.concurrent.CopyOnWriteArraySet; trackSelector, emptyTrackSelectorResult, loadControl, + bandwidthMeter, playWhenReady, repeatMode, shuffleModeEnabled, diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index a566653963..0915dc9721 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -35,6 +35,7 @@ import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.trackselection.TrackSelection; import com.google.android.exoplayer2.trackselection.TrackSelector; import com.google.android.exoplayer2.trackselection.TrackSelectorResult; +import com.google.android.exoplayer2.upstream.BandwidthMeter; import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Clock; import com.google.android.exoplayer2.util.HandlerWrapper; @@ -87,6 +88,7 @@ import java.util.Collections; private final TrackSelector trackSelector; private final TrackSelectorResult emptyTrackSelectorResult; private final LoadControl loadControl; + private final BandwidthMeter bandwidthMeter; private final HandlerWrapper handler; private final HandlerThread internalPlaybackThread; private final Handler eventHandler; @@ -123,6 +125,7 @@ import java.util.Collections; TrackSelector trackSelector, TrackSelectorResult emptyTrackSelectorResult, LoadControl loadControl, + BandwidthMeter bandwidthMeter, boolean playWhenReady, @Player.RepeatMode int repeatMode, boolean shuffleModeEnabled, @@ -133,6 +136,7 @@ import java.util.Collections; this.trackSelector = trackSelector; this.emptyTrackSelectorResult = emptyTrackSelectorResult; this.loadControl = loadControl; + this.bandwidthMeter = bandwidthMeter; this.playWhenReady = playWhenReady; this.repeatMode = repeatMode; this.shuffleModeEnabled = shuffleModeEnabled; @@ -162,7 +166,7 @@ import java.util.Collections; enabledRenderers = new Renderer[0]; window = new Timeline.Window(); period = new Timeline.Period(); - trackSelector.init(/* listener= */ this, /* bandwidthMeter= */ null); + trackSelector.init(/* listener= */ this, bandwidthMeter); // Note: The documentation for Process.THREAD_PRIORITY_AUDIO that states "Applications can // not normally change to this priority" is incorrect. @@ -397,7 +401,7 @@ import java.util.Collections; player, /* isTopLevelSource= */ true, /* listener= */ this, - /* mediaTransferListener= */ null); + bandwidthMeter.getTransferListener()); handler.sendEmptyMessage(MSG_DO_SOME_WORK); } 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 2d7b5b2f31..cc1285c290 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 @@ -45,6 +45,7 @@ import com.google.android.exoplayer2.text.Cue; import com.google.android.exoplayer2.text.TextOutput; 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.util.Clock; import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.video.VideoRendererEventListener; @@ -99,23 +100,11 @@ public class SimpleExoPlayer private MediaSource mediaSource; private List currentCues; - /** - * @deprecated Use {@link #SimpleExoPlayer(RenderersFactory, TrackSelector, LoadControl, - * DrmSessionManager, Looper)}. - */ - @Deprecated - protected SimpleExoPlayer( - RenderersFactory renderersFactory, - TrackSelector trackSelector, - LoadControl loadControl, - @Nullable DrmSessionManager drmSessionManager) { - this(renderersFactory, trackSelector, loadControl, drmSessionManager, Util.getLooper()); - } - /** * @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 bandwidthMeter The {@link BandwidthMeter} 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 @@ -125,6 +114,7 @@ public class SimpleExoPlayer RenderersFactory renderersFactory, TrackSelector trackSelector, LoadControl loadControl, + BandwidthMeter bandwidthMeter, @Nullable DrmSessionManager drmSessionManager, Looper looper) { this( @@ -132,6 +122,7 @@ public class SimpleExoPlayer trackSelector, loadControl, drmSessionManager, + bandwidthMeter, new AnalyticsCollector.Factory(), looper); } @@ -142,6 +133,7 @@ public class SimpleExoPlayer * @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. * @param analyticsCollectorFactory A factory for creating 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 @@ -152,6 +144,7 @@ public class SimpleExoPlayer TrackSelector trackSelector, LoadControl loadControl, @Nullable DrmSessionManager drmSessionManager, + BandwidthMeter bandwidthMeter, AnalyticsCollector.Factory analyticsCollectorFactory, Looper looper) { this( @@ -159,6 +152,7 @@ public class SimpleExoPlayer trackSelector, loadControl, drmSessionManager, + bandwidthMeter, analyticsCollectorFactory, Clock.DEFAULT, looper); @@ -170,6 +164,7 @@ public class SimpleExoPlayer * @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. * @param analyticsCollectorFactory A factory for creating the {@link AnalyticsCollector} that * will collect and forward all player events. * @param clock The {@link Clock} that will be used by the instance. Should always be {@link @@ -182,6 +177,7 @@ public class SimpleExoPlayer TrackSelector trackSelector, LoadControl loadControl, @Nullable DrmSessionManager drmSessionManager, + BandwidthMeter bandwidthMeter, AnalyticsCollector.Factory analyticsCollectorFactory, Clock clock, Looper looper) { @@ -210,7 +206,8 @@ public class SimpleExoPlayer currentCues = Collections.emptyList(); // Build the player and associated objects. - player = createExoPlayerImpl(renderers, trackSelector, loadControl, clock, looper); + player = + createExoPlayerImpl(renderers, trackSelector, loadControl, bandwidthMeter, clock, looper); analyticsCollector = analyticsCollectorFactory.createAnalyticsCollector(player, clock); addListener(analyticsCollector); videoDebugListeners.add(analyticsCollector); @@ -993,6 +990,7 @@ public class SimpleExoPlayer * @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 clock The {@link Clock} that will be used by this instance. * @param looper The {@link Looper} which must be used for all calls to the player and which is * used to call listeners on. @@ -1002,9 +1000,10 @@ public class SimpleExoPlayer Renderer[] renderers, TrackSelector trackSelector, LoadControl loadControl, + BandwidthMeter bandwidthMeter, Clock clock, Looper looper) { - return new ExoPlayerImpl(renderers, trackSelector, loadControl, clock, looper); + return new ExoPlayerImpl(renderers, trackSelector, loadControl, bandwidthMeter, clock, looper); } private void removeSurfaceCallbacks() { diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExoPlayerTestRunner.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExoPlayerTestRunner.java index 1d6b38067d..bd98c1f1ca 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExoPlayerTestRunner.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExoPlayerTestRunner.java @@ -41,6 +41,7 @@ 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.DefaultBandwidthMeter; import com.google.android.exoplayer2.util.Clock; import com.google.android.exoplayer2.util.HandlerWrapper; import com.google.android.exoplayer2.util.MimeTypes; @@ -660,6 +661,7 @@ public final class ExoPlayerTestRunner implements Player.EventListener, ActionSc trackSelector, loadControl, /* drmSessionManager= */ null, + new DefaultBandwidthMeter.Builder().build(), new AnalyticsCollector.Factory(), clock, Looper.myLooper());