Commit a92344ac by tonihei Committed by Oliver Woodman

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
parent db33b3bb
...@@ -109,6 +109,7 @@ public class SimpleExoPlayer ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment