Log warning with stack trace if player is accessed from the wrong thread.

This doesn't break apps which violate this policy. But it creates a clear
warning which is also likely to be reported in analytics tools.

Issue:#4463

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=213442510
This commit is contained in:
tonihei 2018-09-18 06:57:40 -07:00 committed by Oliver Woodman
parent db33b3bbd1
commit a92344ac9e

View file

@ -109,6 +109,7 @@ public class SimpleExoPlayer
private List<Cue> currentCues; private List<Cue> currentCues;
private VideoFrameMetadataListener videoFrameMetadataListener; private VideoFrameMetadataListener videoFrameMetadataListener;
private CameraMotionListener cameraMotionListener; private CameraMotionListener cameraMotionListener;
private boolean hasNotifiedFullWrongThreadWarning;
/** /**
* @param context A {@link Context}. * @param context A {@link Context}.
@ -266,6 +267,7 @@ public class SimpleExoPlayer
*/ */
@Override @Override
public void setVideoScalingMode(@C.VideoScalingMode int videoScalingMode) { public void setVideoScalingMode(@C.VideoScalingMode int videoScalingMode) {
verifyApplicationThread();
this.videoScalingMode = videoScalingMode; this.videoScalingMode = videoScalingMode;
for (Renderer renderer : renderers) { for (Renderer renderer : renderers) {
if (renderer.getTrackType() == C.TRACK_TYPE_VIDEO) { if (renderer.getTrackType() == C.TRACK_TYPE_VIDEO) {
@ -285,11 +287,13 @@ public class SimpleExoPlayer
@Override @Override
public void clearVideoSurface() { public void clearVideoSurface() {
verifyApplicationThread();
setVideoSurface(null); setVideoSurface(null);
} }
@Override @Override
public void clearVideoSurface(Surface surface) { public void clearVideoSurface(Surface surface) {
verifyApplicationThread();
if (surface != null && surface == this.surface) { if (surface != null && surface == this.surface) {
setVideoSurface(null); setVideoSurface(null);
} }
@ -297,6 +301,7 @@ public class SimpleExoPlayer
@Override @Override
public void setVideoSurface(@Nullable Surface surface) { public void setVideoSurface(@Nullable Surface surface) {
verifyApplicationThread();
removeSurfaceCallbacks(); removeSurfaceCallbacks();
setVideoSurfaceInternal(surface, false); setVideoSurfaceInternal(surface, false);
int newSurfaceSize = surface == null ? 0 : C.LENGTH_UNSET; int newSurfaceSize = surface == null ? 0 : C.LENGTH_UNSET;
@ -305,6 +310,7 @@ public class SimpleExoPlayer
@Override @Override
public void setVideoSurfaceHolder(SurfaceHolder surfaceHolder) { public void setVideoSurfaceHolder(SurfaceHolder surfaceHolder) {
verifyApplicationThread();
removeSurfaceCallbacks(); removeSurfaceCallbacks();
this.surfaceHolder = surfaceHolder; this.surfaceHolder = surfaceHolder;
if (surfaceHolder == null) { if (surfaceHolder == null) {
@ -326,6 +332,7 @@ public class SimpleExoPlayer
@Override @Override
public void clearVideoSurfaceHolder(SurfaceHolder surfaceHolder) { public void clearVideoSurfaceHolder(SurfaceHolder surfaceHolder) {
verifyApplicationThread();
if (surfaceHolder != null && surfaceHolder == this.surfaceHolder) { if (surfaceHolder != null && surfaceHolder == this.surfaceHolder) {
setVideoSurfaceHolder(null); setVideoSurfaceHolder(null);
} }
@ -343,6 +350,7 @@ public class SimpleExoPlayer
@Override @Override
public void setVideoTextureView(TextureView textureView) { public void setVideoTextureView(TextureView textureView) {
verifyApplicationThread();
removeSurfaceCallbacks(); removeSurfaceCallbacks();
this.textureView = textureView; this.textureView = textureView;
if (textureView == null) { if (textureView == null) {
@ -367,6 +375,7 @@ public class SimpleExoPlayer
@Override @Override
public void clearVideoTextureView(TextureView textureView) { public void clearVideoTextureView(TextureView textureView) {
verifyApplicationThread();
if (textureView != null && textureView == this.textureView) { if (textureView != null && textureView == this.textureView) {
setVideoTextureView(null); setVideoTextureView(null);
} }
@ -389,6 +398,7 @@ public class SimpleExoPlayer
@Override @Override
public void setAudioAttributes(AudioAttributes audioAttributes, boolean handleAudioFocus) { public void setAudioAttributes(AudioAttributes audioAttributes, boolean handleAudioFocus) {
verifyApplicationThread();
if (!Util.areEqual(this.audioAttributes, audioAttributes)) { if (!Util.areEqual(this.audioAttributes, audioAttributes)) {
this.audioAttributes = audioAttributes; this.audioAttributes = audioAttributes;
for (Renderer renderer : renderers) { for (Renderer renderer : renderers) {
@ -424,6 +434,7 @@ public class SimpleExoPlayer
@Override @Override
public void setAuxEffectInfo(AuxEffectInfo auxEffectInfo) { public void setAuxEffectInfo(AuxEffectInfo auxEffectInfo) {
verifyApplicationThread();
for (Renderer renderer : renderers) { for (Renderer renderer : renderers) {
if (renderer.getTrackType() == C.TRACK_TYPE_AUDIO) { if (renderer.getTrackType() == C.TRACK_TYPE_AUDIO) {
player player
@ -442,6 +453,7 @@ public class SimpleExoPlayer
@Override @Override
public void setVolume(float audioVolume) { public void setVolume(float audioVolume) {
verifyApplicationThread();
audioVolume = Util.constrainValue(audioVolume, /* min= */ 0, /* max= */ 1); audioVolume = Util.constrainValue(audioVolume, /* min= */ 0, /* max= */ 1);
if (this.audioVolume == audioVolume) { if (this.audioVolume == audioVolume) {
return; return;
@ -500,6 +512,7 @@ public class SimpleExoPlayer
* @param listener The listener to be added. * @param listener The listener to be added.
*/ */
public void addAnalyticsListener(AnalyticsListener listener) { public void addAnalyticsListener(AnalyticsListener listener) {
verifyApplicationThread();
analyticsCollector.addListener(listener); analyticsCollector.addListener(listener);
} }
@ -509,6 +522,7 @@ public class SimpleExoPlayer
* @param listener The listener to be removed. * @param listener The listener to be removed.
*/ */
public void removeAnalyticsListener(AnalyticsListener listener) { public void removeAnalyticsListener(AnalyticsListener listener) {
verifyApplicationThread();
analyticsCollector.removeListener(listener); analyticsCollector.removeListener(listener);
} }
@ -571,6 +585,7 @@ public class SimpleExoPlayer
@Override @Override
public void setVideoFrameMetadataListener(VideoFrameMetadataListener listener) { public void setVideoFrameMetadataListener(VideoFrameMetadataListener listener) {
verifyApplicationThread();
videoFrameMetadataListener = listener; videoFrameMetadataListener = listener;
for (Renderer renderer : renderers) { for (Renderer renderer : renderers) {
if (renderer.getTrackType() == C.TRACK_TYPE_VIDEO) { if (renderer.getTrackType() == C.TRACK_TYPE_VIDEO) {
@ -585,6 +600,7 @@ public class SimpleExoPlayer
@Override @Override
public void clearVideoFrameMetadataListener(VideoFrameMetadataListener listener) { public void clearVideoFrameMetadataListener(VideoFrameMetadataListener listener) {
verifyApplicationThread();
if (videoFrameMetadataListener != listener) { if (videoFrameMetadataListener != listener) {
return; return;
} }
@ -601,6 +617,7 @@ public class SimpleExoPlayer
@Override @Override
public void setCameraMotionListener(CameraMotionListener listener) { public void setCameraMotionListener(CameraMotionListener listener) {
verifyApplicationThread();
cameraMotionListener = listener; cameraMotionListener = listener;
for (Renderer renderer : renderers) { for (Renderer renderer : renderers) {
if (renderer.getTrackType() == C.TRACK_TYPE_CAMERA_MOTION) { if (renderer.getTrackType() == C.TRACK_TYPE_CAMERA_MOTION) {
@ -615,6 +632,7 @@ public class SimpleExoPlayer
@Override @Override
public void clearCameraMotionListener(CameraMotionListener listener) { public void clearCameraMotionListener(CameraMotionListener listener) {
verifyApplicationThread();
if (cameraMotionListener != listener) { if (cameraMotionListener != listener) {
return; return;
} }
@ -814,26 +832,31 @@ public class SimpleExoPlayer
@Override @Override
public void addListener(Player.EventListener listener) { public void addListener(Player.EventListener listener) {
verifyApplicationThread();
player.addListener(listener); player.addListener(listener);
} }
@Override @Override
public void removeListener(Player.EventListener listener) { public void removeListener(Player.EventListener listener) {
verifyApplicationThread();
player.removeListener(listener); player.removeListener(listener);
} }
@Override @Override
public int getPlaybackState() { public int getPlaybackState() {
verifyApplicationThread();
return player.getPlaybackState(); return player.getPlaybackState();
} }
@Override @Override
public @Nullable ExoPlaybackException getPlaybackError() { public @Nullable ExoPlaybackException getPlaybackError() {
verifyApplicationThread();
return player.getPlaybackError(); return player.getPlaybackError();
} }
@Override @Override
public void retry() { public void retry() {
verifyApplicationThread();
if (mediaSource != null if (mediaSource != null
&& (getPlaybackError() != null || getPlaybackState() == Player.STATE_IDLE)) { && (getPlaybackError() != null || getPlaybackState() == Player.STATE_IDLE)) {
prepare(mediaSource, /* resetPosition= */ false, /* resetState= */ false); prepare(mediaSource, /* resetPosition= */ false, /* resetState= */ false);
@ -847,6 +870,7 @@ public class SimpleExoPlayer
@Override @Override
public void prepare(MediaSource mediaSource, boolean resetPosition, boolean resetState) { public void prepare(MediaSource mediaSource, boolean resetPosition, boolean resetState) {
verifyApplicationThread();
if (this.mediaSource != null) { if (this.mediaSource != null) {
this.mediaSource.removeEventListener(analyticsCollector); this.mediaSource.removeEventListener(analyticsCollector);
analyticsCollector.resetForNewMediaSource(); analyticsCollector.resetForNewMediaSource();
@ -861,6 +885,7 @@ public class SimpleExoPlayer
@Override @Override
public void setPlayWhenReady(boolean playWhenReady) { public void setPlayWhenReady(boolean playWhenReady) {
verifyApplicationThread();
@AudioFocusManager.PlayerCommand @AudioFocusManager.PlayerCommand
int playerCommand = audioFocusManager.handleSetPlayWhenReady(playWhenReady, getPlaybackState()); int playerCommand = audioFocusManager.handleSetPlayWhenReady(playWhenReady, getPlaybackState());
updatePlayWhenReady(playWhenReady, playerCommand); updatePlayWhenReady(playWhenReady, playerCommand);
@ -868,80 +893,95 @@ public class SimpleExoPlayer
@Override @Override
public boolean getPlayWhenReady() { public boolean getPlayWhenReady() {
verifyApplicationThread();
return player.getPlayWhenReady(); return player.getPlayWhenReady();
} }
@Override @Override
public @RepeatMode int getRepeatMode() { public @RepeatMode int getRepeatMode() {
verifyApplicationThread();
return player.getRepeatMode(); return player.getRepeatMode();
} }
@Override @Override
public void setRepeatMode(@RepeatMode int repeatMode) { public void setRepeatMode(@RepeatMode int repeatMode) {
verifyApplicationThread();
player.setRepeatMode(repeatMode); player.setRepeatMode(repeatMode);
} }
@Override @Override
public void setShuffleModeEnabled(boolean shuffleModeEnabled) { public void setShuffleModeEnabled(boolean shuffleModeEnabled) {
verifyApplicationThread();
player.setShuffleModeEnabled(shuffleModeEnabled); player.setShuffleModeEnabled(shuffleModeEnabled);
} }
@Override @Override
public boolean getShuffleModeEnabled() { public boolean getShuffleModeEnabled() {
verifyApplicationThread();
return player.getShuffleModeEnabled(); return player.getShuffleModeEnabled();
} }
@Override @Override
public boolean isLoading() { public boolean isLoading() {
verifyApplicationThread();
return player.isLoading(); return player.isLoading();
} }
@Override @Override
public void seekToDefaultPosition() { public void seekToDefaultPosition() {
verifyApplicationThread();
analyticsCollector.notifySeekStarted(); analyticsCollector.notifySeekStarted();
player.seekToDefaultPosition(); player.seekToDefaultPosition();
} }
@Override @Override
public void seekToDefaultPosition(int windowIndex) { public void seekToDefaultPosition(int windowIndex) {
verifyApplicationThread();
analyticsCollector.notifySeekStarted(); analyticsCollector.notifySeekStarted();
player.seekToDefaultPosition(windowIndex); player.seekToDefaultPosition(windowIndex);
} }
@Override @Override
public void seekTo(long positionMs) { public void seekTo(long positionMs) {
verifyApplicationThread();
analyticsCollector.notifySeekStarted(); analyticsCollector.notifySeekStarted();
player.seekTo(positionMs); player.seekTo(positionMs);
} }
@Override @Override
public void seekTo(int windowIndex, long positionMs) { public void seekTo(int windowIndex, long positionMs) {
verifyApplicationThread();
analyticsCollector.notifySeekStarted(); analyticsCollector.notifySeekStarted();
player.seekTo(windowIndex, positionMs); player.seekTo(windowIndex, positionMs);
} }
@Override @Override
public void setPlaybackParameters(@Nullable PlaybackParameters playbackParameters) { public void setPlaybackParameters(@Nullable PlaybackParameters playbackParameters) {
verifyApplicationThread();
player.setPlaybackParameters(playbackParameters); player.setPlaybackParameters(playbackParameters);
} }
@Override @Override
public PlaybackParameters getPlaybackParameters() { public PlaybackParameters getPlaybackParameters() {
verifyApplicationThread();
return player.getPlaybackParameters(); return player.getPlaybackParameters();
} }
@Override @Override
public void setSeekParameters(@Nullable SeekParameters seekParameters) { public void setSeekParameters(@Nullable SeekParameters seekParameters) {
verifyApplicationThread();
player.setSeekParameters(seekParameters); player.setSeekParameters(seekParameters);
} }
@Override @Override
public SeekParameters getSeekParameters() { public SeekParameters getSeekParameters() {
verifyApplicationThread();
return player.getSeekParameters(); return player.getSeekParameters();
} }
@Override @Override
public @Nullable Object getCurrentTag() { public @Nullable Object getCurrentTag() {
verifyApplicationThread();
return player.getCurrentTag(); return player.getCurrentTag();
} }
@ -952,6 +992,7 @@ public class SimpleExoPlayer
@Override @Override
public void stop(boolean reset) { public void stop(boolean reset) {
verifyApplicationThread();
player.stop(reset); player.stop(reset);
if (mediaSource != null) { if (mediaSource != null) {
mediaSource.removeEventListener(analyticsCollector); mediaSource.removeEventListener(analyticsCollector);
@ -992,6 +1033,7 @@ public class SimpleExoPlayer
@Override @Override
public PlayerMessage createMessage(PlayerMessage.Target target) { public PlayerMessage createMessage(PlayerMessage.Target target) {
verifyApplicationThread();
return player.createMessage(target); return player.createMessage(target);
} }
@ -1004,116 +1046,139 @@ public class SimpleExoPlayer
@Override @Override
public int getRendererCount() { public int getRendererCount() {
verifyApplicationThread();
return player.getRendererCount(); return player.getRendererCount();
} }
@Override @Override
public int getRendererType(int index) { public int getRendererType(int index) {
verifyApplicationThread();
return player.getRendererType(index); return player.getRendererType(index);
} }
@Override @Override
public TrackGroupArray getCurrentTrackGroups() { public TrackGroupArray getCurrentTrackGroups() {
verifyApplicationThread();
return player.getCurrentTrackGroups(); return player.getCurrentTrackGroups();
} }
@Override @Override
public TrackSelectionArray getCurrentTrackSelections() { public TrackSelectionArray getCurrentTrackSelections() {
verifyApplicationThread();
return player.getCurrentTrackSelections(); return player.getCurrentTrackSelections();
} }
@Override @Override
public Timeline getCurrentTimeline() { public Timeline getCurrentTimeline() {
verifyApplicationThread();
return player.getCurrentTimeline(); return player.getCurrentTimeline();
} }
@Override @Override
public @Nullable Object getCurrentManifest() { public @Nullable Object getCurrentManifest() {
verifyApplicationThread();
return player.getCurrentManifest(); return player.getCurrentManifest();
} }
@Override @Override
public int getCurrentPeriodIndex() { public int getCurrentPeriodIndex() {
verifyApplicationThread();
return player.getCurrentPeriodIndex(); return player.getCurrentPeriodIndex();
} }
@Override @Override
public int getCurrentWindowIndex() { public int getCurrentWindowIndex() {
verifyApplicationThread();
return player.getCurrentWindowIndex(); return player.getCurrentWindowIndex();
} }
@Override @Override
public int getNextWindowIndex() { public int getNextWindowIndex() {
verifyApplicationThread();
return player.getNextWindowIndex(); return player.getNextWindowIndex();
} }
@Override @Override
public int getPreviousWindowIndex() { public int getPreviousWindowIndex() {
verifyApplicationThread();
return player.getPreviousWindowIndex(); return player.getPreviousWindowIndex();
} }
@Override @Override
public long getDuration() { public long getDuration() {
verifyApplicationThread();
return player.getDuration(); return player.getDuration();
} }
@Override @Override
public long getCurrentPosition() { public long getCurrentPosition() {
verifyApplicationThread();
return player.getCurrentPosition(); return player.getCurrentPosition();
} }
@Override @Override
public long getBufferedPosition() { public long getBufferedPosition() {
verifyApplicationThread();
return player.getBufferedPosition(); return player.getBufferedPosition();
} }
@Override @Override
public int getBufferedPercentage() { public int getBufferedPercentage() {
verifyApplicationThread();
return player.getBufferedPercentage(); return player.getBufferedPercentage();
} }
@Override @Override
public long getTotalBufferedDuration() { public long getTotalBufferedDuration() {
verifyApplicationThread();
return player.getTotalBufferedDuration(); return player.getTotalBufferedDuration();
} }
@Override @Override
public boolean isCurrentWindowDynamic() { public boolean isCurrentWindowDynamic() {
verifyApplicationThread();
return player.isCurrentWindowDynamic(); return player.isCurrentWindowDynamic();
} }
@Override @Override
public boolean isCurrentWindowSeekable() { public boolean isCurrentWindowSeekable() {
verifyApplicationThread();
return player.isCurrentWindowSeekable(); return player.isCurrentWindowSeekable();
} }
@Override @Override
public boolean isPlayingAd() { public boolean isPlayingAd() {
verifyApplicationThread();
return player.isPlayingAd(); return player.isPlayingAd();
} }
@Override @Override
public int getCurrentAdGroupIndex() { public int getCurrentAdGroupIndex() {
verifyApplicationThread();
return player.getCurrentAdGroupIndex(); return player.getCurrentAdGroupIndex();
} }
@Override @Override
public int getCurrentAdIndexInAdGroup() { public int getCurrentAdIndexInAdGroup() {
verifyApplicationThread();
return player.getCurrentAdIndexInAdGroup(); return player.getCurrentAdIndexInAdGroup();
} }
@Override @Override
public long getContentDuration() { public long getContentDuration() {
verifyApplicationThread();
return player.getContentDuration(); return player.getContentDuration();
} }
@Override @Override
public long getContentPosition() { public long getContentPosition() {
verifyApplicationThread();
return player.getContentPosition(); return player.getContentPosition();
} }
@Override @Override
public long getContentBufferedPosition() { public long getContentBufferedPosition() {
verifyApplicationThread();
return player.getContentBufferedPosition(); return player.getContentBufferedPosition();
} }
@ -1183,12 +1248,23 @@ public class SimpleExoPlayer
private void updatePlayWhenReady( private void updatePlayWhenReady(
boolean playWhenReady, @AudioFocusManager.PlayerCommand int playerCommand) { boolean playWhenReady, @AudioFocusManager.PlayerCommand int playerCommand) {
player.setPlayWhenReady( player.setPlayWhenReady(
playWhenReady && playerCommand != AudioFocusManager.PLAYER_COMMAND_DO_NOT_PLAY, playWhenReady && playerCommand != AudioFocusManager.PLAYER_COMMAND_DO_NOT_PLAY,
playerCommand != AudioFocusManager.PLAYER_COMMAND_PLAY_WHEN_READY); playerCommand != AudioFocusManager.PLAYER_COMMAND_PLAY_WHEN_READY);
} }
private void verifyApplicationThread() {
if (Looper.myLooper() != getApplicationLooper()) {
Log.w(
TAG,
"Player is accessed on the wrong thread. See "
+ "https://google.github.io/ExoPlayer/faqs.html#"
+ "what-do-player-is-accessed-on-the-wrong-thread-warnings-mean",
hasNotifiedFullWrongThreadWarning ? null : new IllegalStateException());
hasNotifiedFullWrongThreadWarning = true;
}
}
private final class ComponentListener private final class ComponentListener
implements VideoRendererEventListener, implements VideoRendererEventListener,
AudioRendererEventListener, AudioRendererEventListener,