/*
* Copyright 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.media3.session;
import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkState;
import static androidx.media3.common.util.Util.postOrRun;
import static androidx.media3.session.MediaConstants.EXTRAS_KEY_MEDIA_ID_COMPAT;
import static androidx.media3.session.MediaConstants.EXTRAS_KEY_PLAYBACK_SPEED_COMPAT;
import android.media.AudioManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
import android.support.v4.media.session.PlaybackStateCompat;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.TextureView;
import androidx.annotation.Nullable;
import androidx.media.VolumeProviderCompat;
import androidx.media3.common.AudioAttributes;
import androidx.media3.common.DeviceInfo;
import androidx.media3.common.ForwardingPlayer;
import androidx.media3.common.MediaItem;
import androidx.media3.common.MediaMetadata;
import androidx.media3.common.PlaybackException;
import androidx.media3.common.PlaybackParameters;
import androidx.media3.common.Player;
import androidx.media3.common.Timeline;
import androidx.media3.common.TrackSelectionParameters;
import androidx.media3.common.VideoSize;
import androidx.media3.common.text.CueGroup;
import androidx.media3.common.util.Log;
import androidx.media3.common.util.Util;
import com.google.common.collect.ImmutableList;
import java.util.List;
/**
* A wrapper of {@link Player} given by constructor of {@link MediaSession} or {@link
* MediaSession#setPlayer(Player)}. Use this wrapper for extra checks before calling methods and/or
* overriding the behavior.
*/
/* package */ class PlayerWrapper extends ForwardingPlayer {
private static final int STATUS_CODE_SUCCESS_COMPAT = -1;
private int legacyStatusCode;
@Nullable private String legacyErrorMessage;
@Nullable private Bundle legacyErrorExtras;
private ImmutableList<CommandButton> customLayout;
public PlayerWrapper(Player player) {
super(player);
legacyStatusCode = STATUS_CODE_SUCCESS_COMPAT;
customLayout = ImmutableList.of();
}
/**
* Sets the legacy error code.
*
* <p>This sets the legacy {@link PlaybackStateCompat} to {@link PlaybackStateCompat#STATE_ERROR}
* and calls {@link PlaybackStateCompat.Builder#setErrorMessage(int, CharSequence)} and {@link
* PlaybackStateCompat.Builder#setExtras(Bundle)} with the given arguments.
*
* <p>Use {@link #clearLegacyErrorStatus()} to clear the error state and to resume to the actual
* playback state reflecting the player.
*
* @param errorCode The legacy error code.
* @param errorMessage The legacy error message.
* @param extras The extras.
*/
public void setLegacyErrorStatus(int errorCode, String errorMessage, Bundle extras) {
checkState(errorCode != STATUS_CODE_SUCCESS_COMPAT);
legacyStatusCode = errorCode;
legacyErrorMessage = errorMessage;
legacyErrorExtras = extras;
}
/** Returns the legacy status code. */
public int getLegacyStatusCode() {
return legacyStatusCode;
}
/** Sets the custom layout. */
public void setCustomLayout(ImmutableList<CommandButton> customLayout) {
this.customLayout = customLayout;
}
/** Clears the legacy error status. */
public void clearLegacyErrorStatus() {
legacyStatusCode = STATUS_CODE_SUCCESS_COMPAT;
legacyErrorMessage = null;
legacyErrorExtras = null;
}
@Override
public void addListener(Listener listener) {
verifyApplicationThread();
super.addListener(listener);
}
@Override
public void removeListener(Listener listener) {
verifyApplicationThread();
super.removeListener(listener);
}
@Override
@Nullable
public PlaybackException getPlayerError() {
verifyApplicationThread();
return super.getPlayerError();
}
@Override
public void play() {
verifyApplicationThread();
super.play();
}
@Override
public void pause() {
verifyApplicationThread();
super.pause();
}
@Override
public void prepare() {
verifyApplicationThread();
super.prepare();
}
@Override
public void stop() {
verifyApplicationThread();
super.stop();
}
@Override
public void release() {
verifyApplicationThread();
super.release();
}
@Override
public void seekToDefaultPosition(int mediaItemIndex) {
verifyApplicationThread();
super.seekToDefaultPosition(mediaItemIndex);
}
@Override
public void seekTo(long positionMs) {
verifyApplicationThread();
super.seekTo(positionMs);
}
@Override
public void seekTo(int mediaItemIndex, long positionMs) {
verifyApplicationThread();
super.seekTo(mediaItemIndex, positionMs);
}
@Override
public long getSeekBackIncrement() {
verifyApplicationThread();
return super.getSeekBackIncrement();
}
@Override
public void seekBack() {
verifyApplicationThread();
super.seekBack();
}
@Override
public long getSeekForwardIncrement() {
verifyApplicationThread();
return super.getSeekForwardIncrement();
}
@Override
public void seekForward() {
verifyApplicationThread();
super.seekForward();
}
@Override
public void setPlaybackParameters(PlaybackParameters playbackParameters) {
verifyApplicationThread();
super.setPlaybackParameters(playbackParameters);
}
@Override
public void setPlaybackSpeed(float playbackSpeed) {
verifyApplicationThread();
super.setPlaybackSpeed(playbackSpeed);
}
@Override
public long getCurrentPosition() {
verifyApplicationThread();
return super.getCurrentPosition();
}
@Override
public long getDuration() {
verifyApplicationThread();
return super.getDuration();
}
@Override
public long getBufferedPosition() {
verifyApplicationThread();
return super.getBufferedPosition();
}
@Override
public int getBufferedPercentage() {
verifyApplicationThread();
return super.getBufferedPercentage();
}
@Override
public long getTotalBufferedDuration() {
verifyApplicationThread();
return super.getTotalBufferedDuration();
}
@Override
public long getCurrentLiveOffset() {
verifyApplicationThread();
return super.getCurrentLiveOffset();
}
@Override
public long getContentDuration() {
verifyApplicationThread();
return super.getContentDuration();
}
@Override
public long getContentPosition() {
verifyApplicationThread();
return super.getContentPosition();
}
@Override
public long getContentBufferedPosition() {
verifyApplicationThread();
return super.getContentBufferedPosition();
}
@Override
public boolean isPlayingAd() {
verifyApplicationThread();
return super.isPlayingAd();
}
@Override
public int getCurrentAdGroupIndex() {
verifyApplicationThread();
return super.getCurrentAdGroupIndex();
}
@Override
public int getCurrentAdIndexInAdGroup() {
verifyApplicationThread();
return super.getCurrentAdIndexInAdGroup();
}
@Override
public PlaybackParameters getPlaybackParameters() {
verifyApplicationThread();
return super.getPlaybackParameters();
}
@Override
public VideoSize getVideoSize() {
verifyApplicationThread();
return super.getVideoSize();
}
@Override
public void clearVideoSurface() {
verifyApplicationThread();
super.clearVideoSurface();
}
@Override
public void clearVideoSurface(@Nullable Surface surface) {
verifyApplicationThread();
super.clearVideoSurface(surface);
}
@Override
public void setVideoSurface(@Nullable Surface surface) {
verifyApplicationThread();
super.setVideoSurface(surface);
}
@Override
public void setVideoSurfaceHolder(@Nullable SurfaceHolder surfaceHolder) {
verifyApplicationThread();
super.setVideoSurfaceHolder(surfaceHolder);
}
@Override
public void clearVideoSurfaceHolder(@Nullable SurfaceHolder surfaceHolder) {
verifyApplicationThread();
super.clearVideoSurfaceHolder(surfaceHolder);
}
@Override
public void setVideoSurfaceView(@Nullable SurfaceView surfaceView) {
verifyApplicationThread();
super.setVideoSurfaceView(surfaceView);
}
@Override
public void clearVideoSurfaceView(@Nullable SurfaceView surfaceView) {
verifyApplicationThread();
super.clearVideoSurfaceView(surfaceView);
}
@Override
public void setVideoTextureView(@Nullable TextureView textureView) {
verifyApplicationThread();
super.setVideoTextureView(textureView);
}
@Override
public void clearVideoTextureView(@Nullable TextureView textureView) {
verifyApplicationThread();
super.clearVideoTextureView(textureView);
}
@Override
public AudioAttributes getAudioAttributes() {
verifyApplicationThread();
return super.getAudioAttributes();
}
@Override
public void setMediaItem(MediaItem mediaItem) {
verifyApplicationThread();
super.setMediaItem(mediaItem);
}
@Override
public void setMediaItem(MediaItem mediaItem, long startPositionMs) {
verifyApplicationThread();
super.setMediaItem(mediaItem, startPositionMs);
}
@Override
public void setMediaItem(MediaItem mediaItem, boolean resetPosition) {
verifyApplicationThread();
super.setMediaItem(mediaItem, resetPosition);
}
@Override
public void setMediaItems(List<MediaItem> mediaItems) {
verifyApplicationThread();
super.setMediaItems(mediaItems);
}
@Override
public void setMediaItems(List<MediaItem> mediaItems, boolean resetPosition) {
verifyApplicationThread();
super.setMediaItems(mediaItems, resetPosition);
}
@Override
public void setMediaItems(List<MediaItem> mediaItems, int startIndex, long startPositionMs) {
verifyApplicationThread();
super.setMediaItems(mediaItems, startIndex, startPositionMs);
}
@Override
public void addMediaItem(MediaItem mediaItem) {
verifyApplicationThread();
super.addMediaItem(mediaItem);
}
@Override
public void addMediaItem(int index, MediaItem mediaItem) {
verifyApplicationThread();
super.addMediaItem(index, mediaItem);
}
@Override
public void addMediaItems(List<MediaItem> mediaItems) {
verifyApplicationThread();
super.addMediaItems(mediaItems);
}
@Override
public void addMediaItems(int index, List<MediaItem> mediaItems) {
verifyApplicationThread();
super.addMediaItems(index, mediaItems);
}
@Override
public void clearMediaItems() {
verifyApplicationThread();
super.clearMediaItems();
}
@Override
public void removeMediaItem(int index) {
verifyApplicationThread();
super.removeMediaItem(index);
}
@Override
public void removeMediaItems(int fromIndex, int toIndex) {
verifyApplicationThread();
super.removeMediaItems(fromIndex, toIndex);
}
@Override
public void moveMediaItem(int currentIndex, int newIndex) {
verifyApplicationThread();
super.moveMediaItem(currentIndex, newIndex);
}
@Override
public void moveMediaItems(int fromIndex, int toIndex, int newIndex) {
verifyApplicationThread();
super.moveMediaItems(fromIndex, toIndex, newIndex);
}
@Deprecated
@Override
public boolean hasPrevious() {
verifyApplicationThread();
return super.hasPrevious();
}
@Deprecated
@Override
public boolean hasNext() {
verifyApplicationThread();
return super.hasNext();
}
@Deprecated
@Override
public boolean hasPreviousWindow() {
verifyApplicationThread();
return super.hasPreviousWindow();
}
@Deprecated
@Override
public boolean hasNextWindow() {
verifyApplicationThread();
return super.hasNextWindow();
}
@Override
public boolean hasPreviousMediaItem() {
verifyApplicationThread();
return super.hasPreviousMediaItem();
}
@Override
public boolean hasNextMediaItem() {
verifyApplicationThread();
return super.hasNextMediaItem();
}
@Deprecated
@Override
public void previous() {
verifyApplicationThread();
super.previous();
}
@Deprecated
@Override
public void next() {
verifyApplicationThread();
super.next();
}
@Deprecated
@Override
public void seekToPreviousWindow() {
verifyApplicationThread();
super.seekToPreviousWindow();
}
@Deprecated
@Override
public void seekToNextWindow() {
verifyApplicationThread();
super.seekToNextWindow();
}
@Override
public void seekToPreviousMediaItem() {
verifyApplicationThread();
super.seekToPreviousMediaItem();
}
@Override
public void seekToNextMediaItem() {
verifyApplicationThread();
super.seekToNextMediaItem();
}
@Override
public void setPlaylistMetadata(MediaMetadata playlistMetadata) {
verifyApplicationThread();
super.setPlaylistMetadata(playlistMetadata);
}
@Override
public void setRepeatMode(int repeatMode) {
verifyApplicationThread();
super.setRepeatMode(repeatMode);
}
@Override
public void setShuffleModeEnabled(boolean shuffleModeEnabled) {
verifyApplicationThread();
super.setShuffleModeEnabled(shuffleModeEnabled);
}
@Override
public Timeline getCurrentTimeline() {
verifyApplicationThread();
return super.getCurrentTimeline();
}
@Override
public MediaMetadata getPlaylistMetadata() {
verifyApplicationThread();
return super.getPlaylistMetadata();
}
@Override
public int getRepeatMode() {
verifyApplicationThread();
return super.getRepeatMode();
}
@Override
public boolean getShuffleModeEnabled() {
verifyApplicationThread();
return super.getShuffleModeEnabled();
}
@Override
@Nullable
public MediaItem getCurrentMediaItem() {
verifyApplicationThread();
return super.getCurrentMediaItem();
}
@Override
public int getMediaItemCount() {
verifyApplicationThread();
return super.getMediaItemCount();
}
@Override
public MediaItem getMediaItemAt(int index) {
verifyApplicationThread();
return super.getMediaItemAt(index);
}
@Deprecated
@Override
public int getCurrentWindowIndex() {
verifyApplicationThread();
return super.getCurrentWindowIndex();
}
@Override
public int getCurrentMediaItemIndex() {
verifyApplicationThread();
return super.getCurrentMediaItemIndex();
}
@Deprecated
@Override
public int getPreviousWindowIndex() {
verifyApplicationThread();
return super.getPreviousWindowIndex();
}
@Override
public int getPreviousMediaItemIndex() {
verifyApplicationThread();
return super.getPreviousMediaItemIndex();
}
@Deprecated
@Override
public int getNextWindowIndex() {
verifyApplicationThread();
return super.getNextWindowIndex();
}
@Override
public int getNextMediaItemIndex() {
verifyApplicationThread();
return super.getNextMediaItemIndex();
}
@Override
public float getVolume() {
verifyApplicationThread();
return super.getVolume();
}
@Override
public void setVolume(float volume) {
verifyApplicationThread();
super.setVolume(volume);
}
@Override
public CueGroup getCurrentCues() {
verifyApplicationThread();
return super.getCurrentCues();
}
@Override
public DeviceInfo getDeviceInfo() {
verifyApplicationThread();
return super.getDeviceInfo();
}
@Override
public int getDeviceVolume() {
verifyApplicationThread();
return super.getDeviceVolume();
}
@Override
public boolean isDeviceMuted() {
verifyApplicationThread();
return super.isDeviceMuted();
}
@Override
public void setDeviceVolume(int volume) {
verifyApplicationThread();
super.setDeviceVolume(volume);
}
@Override
public void increaseDeviceVolume() {
verifyApplicationThread();
super.increaseDeviceVolume();
}
@Override
public void decreaseDeviceVolume() {
verifyApplicationThread();
super.decreaseDeviceVolume();
}
@Override
public void setDeviceMuted(boolean muted) {
verifyApplicationThread();
super.setDeviceMuted(muted);
}
@Override
public void setPlayWhenReady(boolean playWhenReady) {
verifyApplicationThread();
super.setPlayWhenReady(playWhenReady);
}
@Override
public boolean getPlayWhenReady() {
verifyApplicationThread();
return super.getPlayWhenReady();
}
@Override
@PlaybackSuppressionReason
public int getPlaybackSuppressionReason() {
verifyApplicationThread();
return super.getPlaybackSuppressionReason();
}
@Override
@State
public int getPlaybackState() {
verifyApplicationThread();
return super.getPlaybackState();
}
@Override
public boolean isPlaying() {
verifyApplicationThread();
return super.isPlaying();
}
@Override
public boolean isLoading() {
verifyApplicationThread();
return super.isLoading();
}
@Override
public MediaMetadata getMediaMetadata() {
verifyApplicationThread();
return super.getMediaMetadata();
}
@Override
public boolean isCommandAvailable(@Command int command) {
verifyApplicationThread();
return super.isCommandAvailable(command);
}
@Override
public Commands getAvailableCommands() {
verifyApplicationThread();
return super.getAvailableCommands();
}
@Override
public TrackSelectionParameters getTrackSelectionParameters() {
verifyApplicationThread();
return super.getTrackSelectionParameters();
}
@Override
public void setTrackSelectionParameters(TrackSelectionParameters parameters) {
verifyApplicationThread();
super.setTrackSelectionParameters(parameters);
}
public PlaybackStateCompat createPlaybackStateCompat() {
if (legacyStatusCode != STATUS_CODE_SUCCESS_COMPAT) {
return new PlaybackStateCompat.Builder()
.setState(
PlaybackStateCompat.STATE_ERROR,
/* position= */ PlaybackStateCompat.PLAYBACK_POSITION_UNKNOWN,
/* playbackSpeed= */ 0,
/* updateTime= */ SystemClock.elapsedRealtime())
.setActions(0)
.setBufferedPosition(0)
.setErrorMessage(legacyStatusCode, checkNotNull(legacyErrorMessage))
.setExtras(checkNotNull(legacyErrorExtras))
.build();
}
@Nullable PlaybackException playerError = getPlayerError();
int state =
MediaUtils.convertToPlaybackStateCompatState(
playerError, getPlaybackState(), getPlayWhenReady());
long allActions =
PlaybackStateCompat.ACTION_STOP
| PlaybackStateCompat.ACTION_PAUSE
| PlaybackStateCompat.ACTION_PLAY
| PlaybackStateCompat.ACTION_REWIND
| PlaybackStateCompat.ACTION_FAST_FORWARD
| PlaybackStateCompat.ACTION_SET_RATING
| PlaybackStateCompat.ACTION_SEEK_TO
| PlaybackStateCompat.ACTION_PLAY_PAUSE
| PlaybackStateCompat.ACTION_PLAY_FROM_MEDIA_ID
| PlaybackStateCompat.ACTION_PLAY_FROM_SEARCH
| PlaybackStateCompat.ACTION_SKIP_TO_QUEUE_ITEM
| PlaybackStateCompat.ACTION_PLAY_FROM_URI
| PlaybackStateCompat.ACTION_PREPARE
| PlaybackStateCompat.ACTION_PREPARE_FROM_MEDIA_ID
| PlaybackStateCompat.ACTION_PREPARE_FROM_SEARCH
| PlaybackStateCompat.ACTION_PREPARE_FROM_URI
| PlaybackStateCompat.ACTION_SET_REPEAT_MODE
| PlaybackStateCompat.ACTION_SET_SHUFFLE_MODE
| PlaybackStateCompat.ACTION_SET_CAPTIONING_ENABLED;
if (getAvailableCommands().contains(COMMAND_SEEK_TO_PREVIOUS)
|| getAvailableCommands().contains(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM)) {
allActions |= PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS;
}
if (getAvailableCommands().contains(COMMAND_SEEK_TO_NEXT)
|| getAvailableCommands().contains(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM)) {
allActions |= PlaybackStateCompat.ACTION_SKIP_TO_NEXT;
}
long queueItemId = MediaUtils.convertToQueueItemId(getCurrentMediaItemIndex());
float playbackSpeed = getPlaybackParameters().speed;
float sessionPlaybackSpeed = isPlaying() ? playbackSpeed : 0f;
Bundle extras = new Bundle();
extras.putFloat(EXTRAS_KEY_PLAYBACK_SPEED_COMPAT, playbackSpeed);
@Nullable MediaItem currentMediaItem = getCurrentMediaItem();
if (currentMediaItem != null && !MediaItem.DEFAULT_MEDIA_ID.equals(currentMediaItem.mediaId)) {
extras.putString(EXTRAS_KEY_MEDIA_ID_COMPAT, currentMediaItem.mediaId);
}
PlaybackStateCompat.Builder builder =
new PlaybackStateCompat.Builder()
.setState(
state, getCurrentPosition(), sessionPlaybackSpeed, SystemClock.elapsedRealtime())
.setActions(allActions)
.setActiveQueueItemId(queueItemId)
.setBufferedPosition(getBufferedPosition())
.setExtras(extras);
for (int i = 0; i < customLayout.size(); i++) {
CommandButton commandButton = customLayout.get(i);
if (commandButton.sessionCommand != null) {
SessionCommand sessionCommand = commandButton.sessionCommand;
if (sessionCommand.commandCode == SessionCommand.COMMAND_CODE_CUSTOM) {
builder.addCustomAction(
new PlaybackStateCompat.CustomAction.Builder(
sessionCommand.customAction,
commandButton.displayName,
commandButton.iconResId)
.setExtras(sessionCommand.customExtras)
.build());
}
}
}
if (playerError != null) {
builder.setErrorMessage(
PlaybackStateCompat.ERROR_CODE_UNKNOWN_ERROR, Util.castNonNull(playerError.getMessage()));
}
return builder.build();
}
@Nullable
public VolumeProviderCompat createVolumeProviderCompat() {
if (getDeviceInfo().playbackType == DeviceInfo.PLAYBACK_TYPE_LOCAL) {
return null;
}
Commands availableCommands = getAvailableCommands();
int volumeControlType = VolumeProviderCompat.VOLUME_CONTROL_FIXED;
if (availableCommands.contains(COMMAND_ADJUST_DEVICE_VOLUME)) {
volumeControlType = VolumeProviderCompat.VOLUME_CONTROL_RELATIVE;
if (availableCommands.contains(COMMAND_SET_DEVICE_VOLUME)) {
volumeControlType = VolumeProviderCompat.VOLUME_CONTROL_ABSOLUTE;
}
}
Handler handler = new Handler(getApplicationLooper());
return new VolumeProviderCompat(
volumeControlType, getDeviceInfo().maxVolume, getDeviceVolume()) {
@Override
public void onSetVolumeTo(int volume) {
postOrRun(handler, () -> setDeviceVolume(volume));
}
@Override
public void onAdjustVolume(int direction) {
postOrRun(
handler,
() -> {
switch (direction) {
case AudioManager.ADJUST_RAISE:
increaseDeviceVolume();
break;
case AudioManager.ADJUST_LOWER:
decreaseDeviceVolume();
break;
case AudioManager.ADJUST_MUTE:
setDeviceMuted(true);
break;
case AudioManager.ADJUST_UNMUTE:
setDeviceMuted(false);
break;
case AudioManager.ADJUST_TOGGLE_MUTE:
setDeviceMuted(!isDeviceMuted());
break;
default:
Log.w(
"VolumeProviderCompat",
"onAdjustVolume: Ignoring unknown direction: " + direction);
break;
}
});
}
};
}
/**
* Creates a {@link PositionInfo} of this player for Bundling.
*
* <p>This excludes window uid and period uid that wouldn't be preserved when bundling.
*/
public PositionInfo createPositionInfoForBundling() {
return new PositionInfo(
/* windowUid= */ null,
getCurrentMediaItemIndex(),
getCurrentMediaItem(),
/* periodUid= */ null,
getCurrentPeriodIndex(),
getCurrentPosition(),
getContentPosition(),
getCurrentAdGroupIndex(),
getCurrentAdIndexInAdGroup());
}
/**
* Creates a {@link SessionPositionInfo} of this player for Bundling.
*
* <p>This excludes window uid and period uid that wouldn't be preserved when bundling.
*/
public SessionPositionInfo createSessionPositionInfoForBundling() {
return new SessionPositionInfo(
createPositionInfoForBundling(),
isPlayingAd(),
/* eventTimeMs= */ SystemClock.elapsedRealtime(),
getDuration(),
getBufferedPosition(),
getBufferedPercentage(),
getTotalBufferedDuration(),
getCurrentLiveOffset(),
getContentDuration(),
getContentBufferedPosition());
}
public PlayerInfo createPlayerInfoForBundling() {
return new PlayerInfo(
getPlayerError(),
PlayerInfo.MEDIA_ITEM_TRANSITION_REASON_DEFAULT,
createSessionPositionInfoForBundling(),
createPositionInfoForBundling(),
createPositionInfoForBundling(),
PlayerInfo.DISCONTINUITY_REASON_DEFAULT,
getPlaybackParameters(),
getRepeatMode(),
getShuffleModeEnabled(),
getVideoSize(),
getCurrentTimeline(),
getPlaylistMetadata(),
getVolume(),
getAudioAttributes(),
getCurrentCues(),
getDeviceInfo(),
getDeviceVolume(),
isDeviceMuted(),
getPlayWhenReady(),
PlayerInfo.PLAY_WHEN_READY_CHANGE_REASON_DEFAULT,
getPlaybackSuppressionReason(),
getPlaybackState(),
isPlaying(),
isLoading(),
getMediaMetadata(),
getSeekBackIncrement(),
getSeekForwardIncrement(),
getMaxSeekToPreviousPosition(),
getCurrentTracks(),
getTrackSelectionParameters());
}
private void verifyApplicationThread() {
checkState(Looper.myLooper() == getApplicationLooper());
}
}