From 7b552d7786e773cd8c82533867bbe40d3e86bc04 Mon Sep 17 00:00:00 2001 From: tonihei Date: Thu, 14 May 2020 09:08:42 +0100 Subject: [PATCH] Move common init steps into SimpleExoPlayer builder. Some player setup steps that are likely to be only done once should be moved into the Builder so that player setup can use a consistent style (builder vs setters). This also prevents some threading warning issues when the player is built on a background thread (e.g. for dependency injection frameworks) and setters can't be used due to threading restrictions. PiperOrigin-RevId: 311487224 --- RELEASENOTES.md | 2 + .../google/android/exoplayer2/ExoPlayer.java | 66 ++++-- .../android/exoplayer2/ExoPlayerFactory.java | 2 + .../android/exoplayer2/ExoPlayerImpl.java | 9 +- .../exoplayer2/ExoPlayerImplInternal.java | 5 +- .../android/exoplayer2/SimpleExoPlayer.java | 205 ++++++++++++++++-- 6 files changed, 244 insertions(+), 45 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 1098e1155e..1defae4356 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -7,6 +7,8 @@ * Added `TextComponent.getCurrentCues` because the current cues are no longer forwarded to a new `TextOutput` in `SimpleExoPlayer` automatically. + * Add additional options to `SimpleExoPlayer.Builder` that were previously + only accessible via setters. * Add opt-in to verify correct thread usage with `SimpleExoPlayer.setThrowsWhenUsingWrongThread(true)` ([#4463](https://github.com/google/ExoPlayer/issues/4463)). 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 d779037817..b4cd9a399d 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 @@ -146,6 +146,8 @@ public interface ExoPlayer extends Player { private Looper looper; @Nullable private AnalyticsCollector analyticsCollector; private boolean useLazyPreparation; + private SeekParameters seekParameters; + private boolean pauseAtEndOfMediaItems; private boolean buildCalled; private long releaseTimeoutMs; @@ -166,6 +168,8 @@ public interface ExoPlayer extends Player { * Looper} *
  • {@link AnalyticsCollector}: {@link AnalyticsCollector} with {@link Clock#DEFAULT} *
  • {@code useLazyPreparation}: {@code true} + *
  • {@link SeekParameters}: {@link SeekParameters#DEFAULT} + *
  • {@code pauseAtEndOfMediaItems}: {@code false} *
  • {@link Clock}: {@link Clock#DEFAULT} * * @@ -178,50 +182,37 @@ public interface ExoPlayer extends Player { new DefaultTrackSelector(context), DefaultMediaSourceFactory.newInstance(context), new DefaultLoadControl(), - DefaultBandwidthMeter.getSingletonInstance(context), - Util.getLooper(), - /* analyticsCollector= */ null, - /* useLazyPreparation= */ true, - Clock.DEFAULT); + DefaultBandwidthMeter.getSingletonInstance(context)); } /** * 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. + *

    Note that this constructor is only useful to try and ensure that ExoPlayer's default + * components can be removed by ProGuard or R8. * * @param renderers The {@link Renderer Renderers} to be used by the player. * @param trackSelector A {@link TrackSelector}. * @param mediaSourceFactory A {@link MediaSourceFactory}. * @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 analyticsCollector An {@link AnalyticsCollector}. - * @param useLazyPreparation Whether media sources should be initialized lazily. - * @param clock A {@link Clock}. Should always be {@link Clock#DEFAULT}. */ public Builder( Renderer[] renderers, TrackSelector trackSelector, MediaSourceFactory mediaSourceFactory, LoadControl loadControl, - BandwidthMeter bandwidthMeter, - Looper looper, - @Nullable AnalyticsCollector analyticsCollector, - boolean useLazyPreparation, - Clock clock) { + BandwidthMeter bandwidthMeter) { Assertions.checkArgument(renderers.length > 0); this.renderers = renderers; this.trackSelector = trackSelector; this.mediaSourceFactory = mediaSourceFactory; this.loadControl = loadControl; this.bandwidthMeter = bandwidthMeter; - this.looper = looper; - this.analyticsCollector = analyticsCollector; - this.useLazyPreparation = useLazyPreparation; - this.clock = clock; + looper = Util.getLooper(); + useLazyPreparation = true; + seekParameters = SeekParameters.DEFAULT; + clock = Clock.DEFAULT; } /** @@ -347,6 +338,37 @@ public interface ExoPlayer extends Player { return this; } + /** + * Sets the parameters that control how seek operations are performed. + * + * @param seekParameters The {@link SeekParameters}. + * @return This builder. + * @throws IllegalStateException If {@link #build()} has already been called. + */ + public Builder setSeekParameters(SeekParameters seekParameters) { + Assertions.checkState(!buildCalled); + this.seekParameters = seekParameters; + return this; + } + + /** + * Sets whether to pause playback at the end of each media item. + * + *

    This means the player will pause at the end of each window in the current {@link + * #getCurrentTimeline() timeline}. Listeners will be informed by a call to {@link + * Player.EventListener#onPlayWhenReadyChanged(boolean, int)} with the reason {@link + * Player#PLAY_WHEN_READY_CHANGE_REASON_END_OF_MEDIA_ITEM} when this happens. + * + * @param pauseAtEndOfMediaItems Whether to pause playback at the end of each media item. + * @return This builder. + * @throws IllegalStateException If {@link #build()} has already been called. + */ + public Builder setPauseAtEndOfMediaItems(boolean pauseAtEndOfMediaItems) { + Assertions.checkState(!buildCalled); + this.pauseAtEndOfMediaItems = pauseAtEndOfMediaItems; + return this; + } + /** * Sets the {@link Clock} that will be used by the player. Should only be set for testing * purposes. @@ -379,6 +401,8 @@ public interface ExoPlayer extends Player { bandwidthMeter, analyticsCollector, useLazyPreparation, + seekParameters, + pauseAtEndOfMediaItems, clock, looper); 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 32d00d90c1..2c07593aaa 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 @@ -258,6 +258,8 @@ public final class ExoPlayerFactory { bandwidthMeter, /* analyticsCollector= */ null, /* useLazyPreparation= */ true, + SeekParameters.DEFAULT, + /* pauseAtEndOfMediaItems= */ false, Clock.DEFAULT, applicationLooper); } 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 543e72b2dd..26357a18dc 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 @@ -109,6 +109,8 @@ import java.util.concurrent.TimeoutException; * @param useLazyPreparation Whether playlist items are prepared lazily. If false, all manifest * loads and other initial preparation steps happen immediately. If true, these initial * preparations are triggered only when the player starts buffering the media. + * @param seekParameters The {@link SeekParameters}. + * @param pauseAtEndOfMediaItems Whether to pause playback at the end of each media item. * @param clock The {@link Clock}. * @param applicationLooper The {@link Looper} that must be used for all calls to the player and * which is used to call listeners on. @@ -122,6 +124,8 @@ import java.util.concurrent.TimeoutException; BandwidthMeter bandwidthMeter, @Nullable AnalyticsCollector analyticsCollector, boolean useLazyPreparation, + SeekParameters seekParameters, + boolean pauseAtEndOfMediaItems, Clock clock, Looper applicationLooper) { Log.i(TAG, "Init " + Integer.toHexString(System.identityHashCode(this)) + " [" @@ -131,6 +135,8 @@ import java.util.concurrent.TimeoutException; this.trackSelector = checkNotNull(trackSelector); this.mediaSourceFactory = mediaSourceFactory; this.useLazyPreparation = useLazyPreparation; + this.seekParameters = seekParameters; + this.pauseAtEndOfMediaItems = pauseAtEndOfMediaItems; repeatMode = Player.REPEAT_MODE_OFF; listeners = new CopyOnWriteArrayList<>(); mediaSourceHolders = new ArrayList<>(); @@ -142,7 +148,6 @@ import java.util.concurrent.TimeoutException; null); period = new Timeline.Period(); playbackSpeed = Player.DEFAULT_PLAYBACK_SPEED; - seekParameters = SeekParameters.DEFAULT; maskingWindowIndex = C.INDEX_UNSET; applicationHandler = new Handler(applicationLooper) { @@ -166,6 +171,8 @@ import java.util.concurrent.TimeoutException; repeatMode, shuffleModeEnabled, analyticsCollector, + seekParameters, + pauseAtEndOfMediaItems, applicationHandler, clock); internalPlayerHandler = new Handler(internalPlayer.getPlaybackLooper()); 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 96e8f3d8ac..53c8a5d080 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 @@ -146,6 +146,8 @@ import java.util.concurrent.atomic.AtomicBoolean; @Player.RepeatMode int repeatMode, boolean shuffleModeEnabled, @Nullable AnalyticsCollector analyticsCollector, + SeekParameters seekParameters, + boolean pauseAtEndOfWindow, Handler eventHandler, Clock clock) { this.renderers = renderers; @@ -155,6 +157,8 @@ import java.util.concurrent.atomic.AtomicBoolean; this.bandwidthMeter = bandwidthMeter; this.repeatMode = repeatMode; this.shuffleModeEnabled = shuffleModeEnabled; + this.seekParameters = seekParameters; + this.pauseAtEndOfWindow = pauseAtEndOfWindow; this.eventHandler = eventHandler; this.clock = clock; this.queue = new MediaPeriodQueue(); @@ -162,7 +166,6 @@ import java.util.concurrent.atomic.AtomicBoolean; backBufferDurationUs = loadControl.getBackBufferDurationUs(); retainBackBufferFromKeyframe = loadControl.retainBackBufferFromKeyframe(); - seekParameters = SeekParameters.DEFAULT; playbackInfo = PlaybackInfo.createDummy(emptyTrackSelectorResult); playbackInfoUpdate = new PlaybackInfoUpdate(playbackInfo); rendererCapabilities = new RendererCapabilities[renderers.length]; 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 338df091b8..d1f0cfc798 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 @@ -99,7 +99,16 @@ public class SimpleExoPlayer extends BasePlayer private BandwidthMeter bandwidthMeter; private AnalyticsCollector analyticsCollector; private Looper looper; + @Nullable private PriorityTaskManager priorityTaskManager; + private AudioAttributes audioAttributes; + private boolean handleAudioFocus; + @C.WakeMode private int wakeMode; + private boolean handleAudioBecomingNoisy; + private boolean skipSilenceEnabled; + @Renderer.VideoScalingMode private int videoScalingMode; private boolean useLazyPreparation; + private SeekParameters seekParameters; + private boolean pauseAtEndOfMediaItems; private boolean throwWhenStuckBuffering; private boolean buildCalled; @@ -122,7 +131,15 @@ public class SimpleExoPlayer extends BasePlayer * Looper} of the application's main thread if the current thread doesn't have a {@link * Looper} *

  • {@link AnalyticsCollector}: {@link AnalyticsCollector} with {@link Clock#DEFAULT} + *
  • {@link PriorityTaskManager}: {@code null} (not used) + *
  • {@link AudioAttributes}: {@link AudioAttributes#DEFAULT}, not handling audio focus + *
  • {@link C.WakeMode}: {@link C#WAKE_MODE_NONE} + *
  • {@code handleAudioBecomingNoisy}: {@code true} + *
  • {@code skipSilenceEnabled}: {@code false} + *
  • {@link Renderer.VideoScalingMode}: {@link Renderer#VIDEO_SCALING_MODE_DEFAULT} *
  • {@code useLazyPreparation}: {@code true} + *
  • {@link SeekParameters}: {@link SeekParameters#DEFAULT} + *
  • {@code pauseAtEndOfMediaItems}: {@code false} *
  • {@link Clock}: {@link Clock#DEFAULT} * * @@ -149,18 +166,14 @@ public class SimpleExoPlayer extends BasePlayer DefaultMediaSourceFactory.newInstance(context), new DefaultLoadControl(), DefaultBandwidthMeter.getSingletonInstance(context), - Util.getLooper(), - new AnalyticsCollector(Clock.DEFAULT), - /* useLazyPreparation= */ true, - Clock.DEFAULT); + new AnalyticsCollector(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. + *

    Note that this constructor is only useful to try and ensure that ExoPlayer's default + * components can be removed by ProGuard or R8. * * @param context A {@link Context}. * @param renderersFactory A factory for creating {@link Renderer Renderers} to be used by the @@ -169,12 +182,7 @@ public class SimpleExoPlayer extends BasePlayer * @param mediaSourceFactory A {@link MediaSourceFactory}. * @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 analyticsCollector An {@link AnalyticsCollector}. - * @param useLazyPreparation Whether playlist items should be prepared lazily. If false, all - * initial preparation steps (e.g., manifest loads) happen immediately. If true, these - * initial preparations are triggered only when the player starts buffering the media. - * @param clock A {@link Clock}. Should always be {@link Clock#DEFAULT}. */ public Builder( Context context, @@ -183,20 +191,21 @@ public class SimpleExoPlayer extends BasePlayer MediaSourceFactory mediaSourceFactory, LoadControl loadControl, BandwidthMeter bandwidthMeter, - Looper looper, - AnalyticsCollector analyticsCollector, - boolean useLazyPreparation, - Clock clock) { + AnalyticsCollector analyticsCollector) { this.context = context; this.renderersFactory = renderersFactory; this.trackSelector = trackSelector; this.mediaSourceFactory = mediaSourceFactory; this.loadControl = loadControl; this.bandwidthMeter = bandwidthMeter; - this.looper = looper; this.analyticsCollector = analyticsCollector; - this.useLazyPreparation = useLazyPreparation; - this.clock = clock; + looper = Util.getLooper(); + audioAttributes = AudioAttributes.DEFAULT; + wakeMode = C.WAKE_MODE_NONE; + videoScalingMode = Renderer.VIDEO_SCALING_MODE_DEFAULT; + useLazyPreparation = true; + seekParameters = SeekParameters.DEFAULT; + clock = Clock.DEFAULT; } /** @@ -278,6 +287,111 @@ public class SimpleExoPlayer extends BasePlayer return this; } + /** + * Sets an {@link PriorityTaskManager} that will be used by the player. + * + *

    The priority {@link C#PRIORITY_PLAYBACK} will be set while the player is loading. + * + * @param priorityTaskManager A {@link PriorityTaskManager}, or null to not use one. + * @return This builder. + * @throws IllegalStateException If {@link #build()} has already been called. + */ + public Builder setPriorityTaskManager(@Nullable PriorityTaskManager priorityTaskManager) { + Assertions.checkState(!buildCalled); + this.priorityTaskManager = priorityTaskManager; + return this; + } + + /** + * Sets {@link AudioAttributes} that will be used by the player and whether to handle audio + * focus. + * + *

    If audio focus should be handled, the {@link AudioAttributes#usage} must be {@link + * C#USAGE_MEDIA} or {@link C#USAGE_GAME}. Other usages will throw an {@link + * IllegalArgumentException}. + * + * @param audioAttributes {@link AudioAttributes}. + * @param handleAudioFocus Whether the player should hanlde audio focus. + * @return This builder. + * @throws IllegalStateException If {@link #build()} has already been called. + */ + public Builder setAudioAttributes(AudioAttributes audioAttributes, boolean handleAudioFocus) { + Assertions.checkState(!buildCalled); + this.audioAttributes = audioAttributes; + this.handleAudioFocus = handleAudioFocus; + return this; + } + + /** + * Sets the {@link C.WakeMode} that will be used by the player. + * + *

    Enabling this feature requires the {@link android.Manifest.permission#WAKE_LOCK} + * permission. It should be used together with a foreground {@link android.app.Service} for use + * cases where playback occurs and the screen is off (e.g. background audio playback). It is not + * useful when the screen will be kept on during playback (e.g. foreground video playback). + * + *

    When enabled, the locks ({@link android.os.PowerManager.WakeLock} / {@link + * android.net.wifi.WifiManager.WifiLock}) will be held whenever the player is in the {@link + * #STATE_READY} or {@link #STATE_BUFFERING} states with {@code playWhenReady = true}. The locks + * held depend on the specified {@link C.WakeMode}. + * + * @param wakeMode A {@link C.WakeMode}. + * @return This builder. + * @throws IllegalStateException If {@link #build()} has already been called. + */ + public Builder setWakeMode(@C.WakeMode int wakeMode) { + Assertions.checkState(!buildCalled); + this.wakeMode = wakeMode; + return this; + } + + /** + * Sets whether the player should pause automatically when audio is rerouted from a headset to + * device speakers. See the audio + * becoming noisy documentation for more information. + * + * @param handleAudioBecomingNoisy Whether the player should pause automatically when audio is + * rerouted from a headset to device speakers. + * @return This builder. + * @throws IllegalStateException If {@link #build()} has already been called. + */ + public Builder setHandleAudioBecomingNoisy(boolean handleAudioBecomingNoisy) { + Assertions.checkState(!buildCalled); + this.handleAudioBecomingNoisy = handleAudioBecomingNoisy; + return this; + } + + /** + * Sets whether silences silences in the audio stream is enabled. + * + * @param skipSilenceEnabled Whether skipping silences is enabled. + * @return This builder. + * @throws IllegalStateException If {@link #build()} has already been called. + */ + public Builder setSkipSilenceEnabled(boolean skipSilenceEnabled) { + Assertions.checkState(!buildCalled); + this.skipSilenceEnabled = skipSilenceEnabled; + return this; + } + + /** + * Sets the {@link Renderer.VideoScalingMode} that will be used by the player. + * + *

    Note that the scaling mode only applies if a {@link MediaCodec}-based video {@link + * Renderer} is enabled and if the output surface is owned by a {@link + * android.view.SurfaceView}. + * + * @param videoScalingMode A {@link Renderer.VideoScalingMode}. + * @return This builder. + * @throws IllegalStateException If {@link #build()} has already been called. + */ + public Builder setVideoScalingMode(@Renderer.VideoScalingMode int videoScalingMode) { + Assertions.checkState(!buildCalled); + this.videoScalingMode = videoScalingMode; + return this; + } + /** * Sets whether media sources should be initialized lazily. * @@ -295,6 +409,37 @@ public class SimpleExoPlayer extends BasePlayer return this; } + /** + * Sets the parameters that control how seek operations are performed. + * + * @param seekParameters The {@link SeekParameters}. + * @return This builder. + * @throws IllegalStateException If {@link #build()} has already been called. + */ + public Builder setSeekParameters(SeekParameters seekParameters) { + Assertions.checkState(!buildCalled); + this.seekParameters = seekParameters; + return this; + } + + /** + * Sets whether to pause playback at the end of each media item. + * + *

    This means the player will pause at the end of each window in the current {@link + * #getCurrentTimeline() timeline}. Listeners will be informed by a call to {@link + * Player.EventListener#onPlayWhenReadyChanged(boolean, int)} with the reason {@link + * Player#PLAY_WHEN_READY_CHANGE_REASON_END_OF_MEDIA_ITEM} when this happens. + * + * @param pauseAtEndOfMediaItems Whether to pause playback at the end of each media item. + * @return This builder. + * @throws IllegalStateException If {@link #build()} has already been called. + */ + public Builder setPauseAtEndOfMediaItems(boolean pauseAtEndOfMediaItems) { + Assertions.checkState(!buildCalled); + this.pauseAtEndOfMediaItems = pauseAtEndOfMediaItems; + return this; + } + /** * Sets whether the player should throw when it detects it's stuck buffering. * @@ -326,7 +471,7 @@ public class SimpleExoPlayer extends BasePlayer /** * Builds a {@link SimpleExoPlayer} instance. * - * @throws IllegalStateException If {@link #build()} has already been called. + * @throws IllegalStateException If this method has already been called. */ public SimpleExoPlayer build() { Assertions.checkState(!buildCalled); @@ -416,6 +561,10 @@ public class SimpleExoPlayer extends BasePlayer protected SimpleExoPlayer(Builder builder) { bandwidthMeter = builder.bandwidthMeter; analyticsCollector = builder.analyticsCollector; + priorityTaskManager = builder.priorityTaskManager; + audioAttributes = builder.audioAttributes; + videoScalingMode = builder.videoScalingMode; + skipSilenceEnabled = builder.skipSilenceEnabled; componentListener = new ComponentListener(); videoListeners = new CopyOnWriteArraySet<>(); audioListeners = new CopyOnWriteArraySet<>(); @@ -436,8 +585,6 @@ public class SimpleExoPlayer extends BasePlayer // Set initial values. audioVolume = 1; audioSessionId = C.AUDIO_SESSION_ID_UNSET; - audioAttributes = AudioAttributes.DEFAULT; - videoScalingMode = Renderer.VIDEO_SCALING_MODE_DEFAULT; currentCues = Collections.emptyList(); // Build the player and associated objects. @@ -450,6 +597,8 @@ public class SimpleExoPlayer extends BasePlayer bandwidthMeter, analyticsCollector, builder.useLazyPreparation, + builder.seekParameters, + builder.pauseAtEndOfMediaItems, builder.clock, builder.looper); analyticsCollector.setPlayer(player); @@ -461,16 +610,27 @@ public class SimpleExoPlayer extends BasePlayer audioListeners.add(analyticsCollector); addMetadataOutput(analyticsCollector); bandwidthMeter.addEventListener(eventHandler, analyticsCollector); + audioBecomingNoisyManager = new AudioBecomingNoisyManager(builder.context, eventHandler, componentListener); + audioBecomingNoisyManager.setEnabled(builder.handleAudioBecomingNoisy); audioFocusManager = new AudioFocusManager(builder.context, eventHandler, componentListener); + audioFocusManager.setAudioAttributes(builder.handleAudioFocus ? audioAttributes : null); streamVolumeManager = new StreamVolumeManager(builder.context, eventHandler, componentListener); + streamVolumeManager.setStreamType(Util.getStreamTypeForAudioUsage(audioAttributes.usage)); wakeLockManager = new WakeLockManager(builder.context); + wakeLockManager.setEnabled(builder.wakeMode != C.WAKE_MODE_NONE); wifiLockManager = new WifiLockManager(builder.context); + wifiLockManager.setEnabled(builder.wakeMode == C.WAKE_MODE_NETWORK); deviceInfo = createDeviceInfo(streamVolumeManager); if (builder.throwWhenStuckBuffering) { player.experimental_throwWhenStuckBuffering(); } + + sendRendererMessage(C.TRACK_TYPE_AUDIO, Renderer.MSG_SET_AUDIO_ATTRIBUTES, audioAttributes); + sendRendererMessage(C.TRACK_TYPE_VIDEO, Renderer.MSG_SET_SCALING_MODE, videoScalingMode); + sendRendererMessage( + C.TRACK_TYPE_AUDIO, Renderer.MSG_SET_SKIP_SILENCE_ENABLED, skipSilenceEnabled); } @Override @@ -1686,6 +1846,7 @@ public class SimpleExoPlayer extends BasePlayer * @param wakeMode The {@link C.WakeMode} option to keep the device awake during playback. */ public void setWakeMode(@C.WakeMode int wakeMode) { + verifyApplicationThread(); switch (wakeMode) { case C.WAKE_MODE_NONE: wakeLockManager.setEnabled(false);