public interface

Player

 androidx.media3.common.Player

Subclasses:

ExoPlayer, SimpleExoPlayer, CastPlayer, ForwardingPlayer, BasePlayer, MediaController, MediaBrowser, StubPlayer, StubExoPlayer

Gradle dependencies

compile group: 'androidx.media3', name: 'media3-common', version: '1.0.0-alpha03'

  • groupId: androidx.media3
  • artifactId: media3-common
  • version: 1.0.0-alpha03

Artifact androidx.media3:media3-common:1.0.0-alpha03 it located at Google repository (https://maven.google.com/)

Overview

A media player interface defining traditional high-level functionality, such as the ability to play, pause, seek and query properties of the currently playing media.

This interface includes some convenience methods that can be implemented by calling other methods in the interface. BasePlayer implements these convenience methods so inheriting BasePlayer is recommended when implementing the interface so that only the minimal set of required methods can be implemented.

Some important properties of media players that implement this interface are:

Summary

Fields
public static final intCOMMAND_ADJUST_DEVICE_VOLUME

Command to increase and decrease the device volume and mute it.

public static final intCOMMAND_CHANGE_MEDIA_ITEMS

Command to change the MediaItems in the playlist.

public static final intCOMMAND_GET_AUDIO_ATTRIBUTES

Command to get the player current AudioAttributes.

public static final intCOMMAND_GET_CURRENT_MEDIA_ITEM

Command to get the currently playing MediaItem.

public static final intCOMMAND_GET_DEVICE_VOLUME

Command to get the device volume and whether it is muted.

public static final intCOMMAND_GET_MEDIA_ITEMS_METADATA

Command to get the MediaItems metadata.

public static final intCOMMAND_GET_TEXT

Command to get the text that should currently be displayed by the player.

public static final intCOMMAND_GET_TIMELINE

Command to get the information about the current timeline.

public static final intCOMMAND_GET_TRACK_INFOS

Command to get track infos.

public static final intCOMMAND_GET_VOLUME

Command to get the player volume.

public static final intCOMMAND_INVALID

Represents an invalid Player.Command.

public static final intCOMMAND_PLAY_PAUSE

Command to start, pause or resume playback.

public static final intCOMMAND_PREPARE

Command to prepare the player.

public static final intCOMMAND_SEEK_BACK

Command to seek back by a fixed increment into the current MediaItem.

public static final intCOMMAND_SEEK_FORWARD

Command to seek forward by a fixed increment into the current MediaItem.

public static final intCOMMAND_SEEK_IN_CURRENT_MEDIA_ITEM

Command to seek anywhere into the current MediaItem.

public static final intCOMMAND_SEEK_IN_CURRENT_WINDOW

public static final intCOMMAND_SEEK_TO_DEFAULT_POSITION

Command to seek to the default position of the current MediaItem.

public static final intCOMMAND_SEEK_TO_MEDIA_ITEM

Command to seek anywhere in any MediaItem.

public static final intCOMMAND_SEEK_TO_NEXT

Command to seek to a later position in the current or next MediaItem.

public static final intCOMMAND_SEEK_TO_NEXT_MEDIA_ITEM

Command to seek to the default position of the next MediaItem.

public static final intCOMMAND_SEEK_TO_NEXT_WINDOW

public static final intCOMMAND_SEEK_TO_PREVIOUS

Command to seek to an earlier position in the current or previous MediaItem.

public static final intCOMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM

Command to seek to the default position of the previous MediaItem.

public static final intCOMMAND_SEEK_TO_PREVIOUS_WINDOW

public static final intCOMMAND_SEEK_TO_WINDOW

public static final intCOMMAND_SET_DEVICE_VOLUME

Command to set the device volume and mute it.

public static final intCOMMAND_SET_MEDIA_ITEMS_METADATA

Command to set the MediaItems metadata.

public static final intCOMMAND_SET_REPEAT_MODE

Command to set the repeat mode.

public static final intCOMMAND_SET_SHUFFLE_MODE

Command to enable shuffling.

public static final intCOMMAND_SET_SPEED_AND_PITCH

Command to set the playback speed and pitch.

public static final intCOMMAND_SET_TRACK_SELECTION_PARAMETERS

Command to set the player's track selection parameters.

public static final intCOMMAND_SET_VIDEO_SURFACE

Command to set and clear the surface on which to render the video.

public static final intCOMMAND_SET_VOLUME

Command to set the player volume.

public static final intCOMMAND_STOP

Command to stop playback or release the player.

public static final intDISCONTINUITY_REASON_AUTO_TRANSITION

Automatic playback transition from one period in the timeline to the next.

public static final intDISCONTINUITY_REASON_INTERNAL

Discontinuity introduced internally (e.g.

public static final intDISCONTINUITY_REASON_REMOVE

Discontinuity caused by the removal of the current period from the Timeline.

public static final intDISCONTINUITY_REASON_SEEK

Seek within the current period or to another period.

public static final intDISCONTINUITY_REASON_SEEK_ADJUSTMENT

Seek adjustment due to being unable to seek to the requested position or because the seek was permitted to be inexact.

public static final intDISCONTINUITY_REASON_SKIP

Discontinuity introduced by a skipped period (for instance a skipped ad).

public static final intEVENT_AUDIO_ATTRIBUTES_CHANGED

Player.getAudioAttributes() changed.

public static final intEVENT_AUDIO_SESSION_ID

The audio session id was set.

public static final intEVENT_AVAILABLE_COMMANDS_CHANGED

Player.isCommandAvailable(int) changed for at least one Player.Command.

public static final intEVENT_CUES

Player.getCurrentCues() changed.

public static final intEVENT_DEVICE_INFO_CHANGED

Player.getDeviceInfo() changed.

public static final intEVENT_DEVICE_VOLUME_CHANGED

Player.getDeviceVolume() changed.

public static final intEVENT_IS_LOADING_CHANGED

Player.isLoading() ()} changed.

public static final intEVENT_IS_PLAYING_CHANGED

Player.isPlaying() changed.

public static final intEVENT_MAX_SEEK_TO_PREVIOUS_POSITION_CHANGED

Player.getMaxSeekToPreviousPosition() changed.

public static final intEVENT_MEDIA_ITEM_TRANSITION

Player.getCurrentMediaItem() changed or the player started repeating the current item.

public static final intEVENT_MEDIA_METADATA_CHANGED

Player.getMediaMetadata() changed.

public static final intEVENT_METADATA

Metadata associated with the current playback time changed.

public static final intEVENT_PLAY_WHEN_READY_CHANGED

Player.getPlayWhenReady() changed.

public static final intEVENT_PLAYBACK_PARAMETERS_CHANGED

Player.getPlaybackParameters() changed.

public static final intEVENT_PLAYBACK_STATE_CHANGED

Player.getPlaybackState() changed.

public static final intEVENT_PLAYBACK_SUPPRESSION_REASON_CHANGED

Player.getPlaybackSuppressionReason() changed.

public static final intEVENT_PLAYER_ERROR

Player.getPlayerError() changed.

public static final intEVENT_PLAYLIST_METADATA_CHANGED

Player.getPlaylistMetadata() changed.

public static final intEVENT_POSITION_DISCONTINUITY

A position discontinuity occurred.

public static final intEVENT_RENDERED_FIRST_FRAME

A frame is rendered for the first time since setting the surface, or since the renderer was reset, or since the stream being rendered was changed.

public static final intEVENT_REPEAT_MODE_CHANGED

Player.getRepeatMode() changed.

public static final intEVENT_SEEK_BACK_INCREMENT_CHANGED

Player.getSeekBackIncrement() changed.

public static final intEVENT_SEEK_FORWARD_INCREMENT_CHANGED

Player.getSeekForwardIncrement() changed.

public static final intEVENT_SHUFFLE_MODE_ENABLED_CHANGED

Player.getShuffleModeEnabled() changed.

public static final intEVENT_SKIP_SILENCE_ENABLED_CHANGED

Skipping silences in the audio stream is enabled or disabled.

public static final intEVENT_SURFACE_SIZE_CHANGED

The size of the surface onto which the video is being rendered changed.

public static final intEVENT_TIMELINE_CHANGED

Player.getCurrentTimeline() changed.

public static final intEVENT_TRACK_SELECTION_PARAMETERS_CHANGED

Player.getTrackSelectionParameters() changed.

public static final intEVENT_TRACKS_CHANGED

Player.getCurrentTracksInfo() changed.

public static final intEVENT_VIDEO_SIZE_CHANGED

Player.getVideoSize() changed.

public static final intEVENT_VOLUME_CHANGED

Player.getVolume() changed.

public static final intMEDIA_ITEM_TRANSITION_REASON_AUTO

Playback has automatically transitioned to the next media item.

public static final intMEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED

The current media item has changed because of a change in the playlist.

public static final intMEDIA_ITEM_TRANSITION_REASON_REPEAT

The media item has been repeated.

public static final intMEDIA_ITEM_TRANSITION_REASON_SEEK

A seek to another media item has occurred.

public static final intPLAY_WHEN_READY_CHANGE_REASON_AUDIO_BECOMING_NOISY

Playback has been paused to avoid becoming noisy.

public static final intPLAY_WHEN_READY_CHANGE_REASON_AUDIO_FOCUS_LOSS

Playback has been paused because of a loss of audio focus.

public static final intPLAY_WHEN_READY_CHANGE_REASON_END_OF_MEDIA_ITEM

Playback has been paused at the end of a media item.

public static final intPLAY_WHEN_READY_CHANGE_REASON_REMOTE

Playback has been started or paused because of a remote change.

public static final intPLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST

Playback has been started or paused by a call to Player.setPlayWhenReady(boolean).

public static final intPLAYBACK_SUPPRESSION_REASON_NONE

Playback is not suppressed.

public static final intPLAYBACK_SUPPRESSION_REASON_TRANSIENT_AUDIO_FOCUS_LOSS

Playback is suppressed due to transient audio focus loss.

public static final intREPEAT_MODE_ALL

Repeats the entire timeline infinitely.

public static final intREPEAT_MODE_OFF

Normal playback without repetition.

public static final intREPEAT_MODE_ONE

Repeats the currently playing MediaItem infinitely during ongoing playback.

public static final intSTATE_BUFFERING

The player is not able to immediately play the media, but is doing work toward being able to do so.

public static final intSTATE_ENDED

The player has finished playing the media.

public static final intSTATE_IDLE

The player is idle, meaning it holds only limited resources.

public static final intSTATE_READY

The player is able to immediately play from its current position.

public static final intTIMELINE_CHANGE_REASON_PLAYLIST_CHANGED

Timeline changed as a result of a change of the playlist items or the order of the items.

public static final intTIMELINE_CHANGE_REASON_SOURCE_UPDATE

Timeline changed as a result of a source update (e.g.

Methods
public voidaddListener(Player.Listener listener)

Registers a listener to receive all events from the player.

public voidaddMediaItem(int index, MediaItem mediaItem)

Adds a media item at the given index of the playlist.

public voidaddMediaItem(MediaItem mediaItem)

Adds a media item to the end of the playlist.

public voidaddMediaItems(int index, java.util.List<MediaItem> mediaItems)

Adds a list of media items at the given index of the playlist.

public voidaddMediaItems(java.util.List<MediaItem> mediaItems)

Adds a list of media items to the end of the playlist.

public booleancanAdvertiseSession()

Returns whether the player can be used to advertise a media session.

public voidclearMediaItems()

Clears the playlist.

public voidclearVideoSurface()

Clears any , SurfaceHolder, or TextureView currently set on the player.

public voidclearVideoSurface(Surface surface)

Clears the onto which video is being rendered if it matches the one passed.

public voidclearVideoSurfaceHolder(SurfaceHolder surfaceHolder)

Clears the SurfaceHolder that holds the onto which video is being rendered if it matches the one passed.

public voidclearVideoSurfaceView(SurfaceView surfaceView)

Clears the onto which video is being rendered if it matches the one passed.

public voidclearVideoTextureView(TextureView textureView)

Clears the TextureView onto which video is being rendered if it matches the one passed.

public voiddecreaseDeviceVolume()

Decreases the volume of the device.

public LoopergetApplicationLooper()

Returns the associated with the application thread that's used to access the player and on which player events are received.

public AudioAttributesgetAudioAttributes()

Returns the attributes for audio playback.

public Player.CommandsgetAvailableCommands()

Returns the player's currently available Player.Commands.

public intgetBufferedPercentage()

Returns an estimate of the percentage in the current content or ad up to which data is buffered, or 0 if no estimate is available.

public longgetBufferedPosition()

Returns an estimate of the position in the current content or ad up to which data is buffered, in milliseconds.

public longgetContentBufferedPosition()

If Player.isPlayingAd() returns true, returns an estimate of the content position in the current content up to which data is buffered, in milliseconds.

public longgetContentDuration()

If Player.isPlayingAd() returns true, returns the duration of the current content in milliseconds, or C.TIME_UNSET if the duration is not known.

public longgetContentPosition()

If Player.isPlayingAd() returns true, returns the content position that will be played once all ads in the ad group have finished playing, in milliseconds.

public intgetCurrentAdGroupIndex()

If Player.isPlayingAd() returns true, returns the index of the ad group in the period currently being played.

public intgetCurrentAdIndexInAdGroup()

If Player.isPlayingAd() returns true, returns the index of the ad in its ad group.

public java.util.List<Cue>getCurrentCues()

Returns the current Cues.

public longgetCurrentLiveOffset()

Returns the offset of the current playback position from the live edge in milliseconds, or C.TIME_UNSET if the current MediaItem Player.isCurrentMediaItemLive() isn't live} or the offset is unknown.

public java.lang.ObjectgetCurrentManifest()

Returns the current manifest.

public MediaItemgetCurrentMediaItem()

Returns the currently playing MediaItem.

public intgetCurrentMediaItemIndex()

Returns the index of the current MediaItem in the timeline, or the prospective index if the current timeline is empty.

public intgetCurrentPeriodIndex()

Returns the index of the period currently being played.

public longgetCurrentPosition()

Returns the playback position in the current content or ad, in milliseconds, or the prospective position in milliseconds if the current timeline is empty.

public TimelinegetCurrentTimeline()

Returns the current Timeline.

public TrackGroupArraygetCurrentTrackGroups()

Returns the available track groups.

public TrackSelectionArraygetCurrentTrackSelections()

Returns the current track selections.

public TracksInfogetCurrentTracksInfo()

Returns the available tracks, as well as the tracks' support, type, and selection status.

public intgetCurrentWindowIndex()

public DeviceInfogetDeviceInfo()

Gets the device information.

public intgetDeviceVolume()

Gets the current volume of the device.

public longgetDuration()

Returns the duration of the current content or ad in milliseconds, or C.TIME_UNSET if the duration is not known.

public longgetMaxSeekToPreviousPosition()

Returns the maximum position for which Player.seekToPrevious() seeks to the previous MediaItem, in milliseconds.

public MediaItemgetMediaItemAt(int index)

Returns the MediaItem at the given index.

public intgetMediaItemCount()

Returns the number of media items in the playlist.

public MediaMetadatagetMediaMetadata()

Returns the current combined MediaMetadata, or MediaMetadata.EMPTY if not supported.

public intgetNextMediaItemIndex()

Returns the index of the MediaItem that will be played if Player.seekToNextMediaItem() is called, which may depend on the current repeat mode and whether shuffle mode is enabled.

public intgetNextWindowIndex()

public PlaybackParametersgetPlaybackParameters()

Returns the currently active playback parameters.

public intgetPlaybackState()

Returns the current playback state of the player.

public intgetPlaybackSuppressionReason()

Returns the reason why playback is suppressed even though Player.getPlayWhenReady() is true, or Player.PLAYBACK_SUPPRESSION_REASON_NONE if playback is not suppressed.

public PlaybackExceptiongetPlayerError()

Returns the error that caused playback to fail.

public MediaMetadatagetPlaylistMetadata()

Returns the playlist MediaMetadata, as set by Player.setPlaylistMetadata(MediaMetadata), or MediaMetadata.EMPTY if not supported.

public booleangetPlayWhenReady()

Whether playback will proceed when Player.getPlaybackState() == Player.STATE_READY.

public intgetPreviousMediaItemIndex()

Returns the index of the MediaItem that will be played if Player.seekToPreviousMediaItem() is called, which may depend on the current repeat mode and whether shuffle mode is enabled.

public intgetPreviousWindowIndex()

public intgetRepeatMode()

Returns the current Player.RepeatMode used for playback.

public longgetSeekBackIncrement()

Returns the Player.seekBack() increment.

public longgetSeekForwardIncrement()

Returns the Player.seekForward() increment.

public booleangetShuffleModeEnabled()

Returns whether shuffling of media items is enabled.

public longgetTotalBufferedDuration()

Returns an estimate of the total buffered duration from the current position, in milliseconds.

public TrackSelectionParametersgetTrackSelectionParameters()

Returns the parameters constraining the track selection.

public VideoSizegetVideoSize()

Gets the size of the video.

public floatgetVolume()

Returns the audio volume, with 0 being silence and 1 being unity gain (signal unchanged).

public booleanhasNext()

public booleanhasNextMediaItem()

Returns whether a next MediaItem exists, which may depend on the current repeat mode and whether shuffle mode is enabled.

public booleanhasNextWindow()

public booleanhasPrevious()

public booleanhasPreviousMediaItem()

Returns whether a previous media item exists, which may depend on the current repeat mode and whether shuffle mode is enabled.

public booleanhasPreviousWindow()

public voidincreaseDeviceVolume()

Increases the volume of the device.

public booleanisCommandAvailable(int command)

Returns whether the provided Player.Command is available.

public booleanisCurrentMediaItemDynamic()

Returns whether the current MediaItem is dynamic (may change when the Timeline is updated), or false if the Timeline is empty.

public booleanisCurrentMediaItemLive()

Returns whether the current MediaItem is live, or false if the Timeline is empty.

public booleanisCurrentMediaItemSeekable()

Returns whether the current MediaItem is seekable, or false if the Timeline is empty.

public booleanisCurrentWindowDynamic()

public booleanisCurrentWindowLive()

public booleanisCurrentWindowSeekable()

public booleanisDeviceMuted()

Gets whether the device is muted or not.

public booleanisLoading()

Whether the player is currently loading the source.

public booleanisPlaying()

Returns whether the player is playing, i.e.

public booleanisPlayingAd()

Returns whether the player is currently playing an ad.

public voidmoveMediaItem(int currentIndex, int newIndex)

Moves the media item at the current index to the new index.

public voidmoveMediaItems(int fromIndex, int toIndex, int newIndex)

Moves the media item range to the new index.

public voidnext()

public voidpause()

Pauses playback.

public voidplay()

Resumes playback as soon as Player.getPlaybackState() == Player.STATE_READY.

public voidprepare()

Prepares the player.

public voidprevious()

public voidrelease()

Releases the player.

public voidremoveListener(Player.Listener listener)

Unregister a listener registered through Player.addListener(Player.Listener).

public voidremoveMediaItem(int index)

Removes the media item at the given index of the playlist.

public voidremoveMediaItems(int fromIndex, int toIndex)

Removes a range of media items from the playlist.

public voidseekBack()

Seeks back in the current MediaItem by Player.getSeekBackIncrement() milliseconds.

public voidseekForward()

Seeks forward in the current MediaItem by Player.getSeekForwardIncrement() milliseconds.

public voidseekTo(int mediaItemIndex, long positionMs)

Seeks to a position specified in milliseconds in the specified MediaItem.

public voidseekTo(long positionMs)

Seeks to a position specified in milliseconds in the current MediaItem.

public voidseekToDefaultPosition()

Seeks to the default position associated with the current MediaItem.

public voidseekToDefaultPosition(int mediaItemIndex)

Seeks to the default position associated with the specified MediaItem.

public voidseekToNext()

Seeks to a later position in the current or next MediaItem (if available).

public voidseekToNextMediaItem()

Seeks to the default position of the next MediaItem, which may depend on the current repeat mode and whether shuffle mode is enabled.

public voidseekToNextWindow()

public voidseekToPrevious()

Seeks to an earlier position in the current or previous MediaItem (if available).

public voidseekToPreviousMediaItem()

Seeks to the default position of the previous MediaItem, which may depend on the current repeat mode and whether shuffle mode is enabled.

public voidseekToPreviousWindow()

public voidsetDeviceMuted(boolean muted)

Sets the mute state of the device.

public voidsetDeviceVolume(int volume)

Sets the volume of the device.

public voidsetMediaItem(MediaItem mediaItem)

Clears the playlist, adds the specified MediaItem and resets the position to the default position.

public voidsetMediaItem(MediaItem mediaItem, boolean resetPosition)

Clears the playlist and adds the specified MediaItem.

public voidsetMediaItem(MediaItem mediaItem, long startPositionMs)

Clears the playlist and adds the specified MediaItem.

public voidsetMediaItems(java.util.List<MediaItem> mediaItems)

Clears the playlist, adds the specified MediaItems and resets the position to the default position.

public voidsetMediaItems(java.util.List<MediaItem> mediaItems, boolean resetPosition)

Clears the playlist and adds the specified MediaItems.

public voidsetMediaItems(java.util.List<MediaItem> mediaItems, int startIndex, long startPositionMs)

Clears the playlist and adds the specified MediaItems.

public voidsetPlaybackParameters(PlaybackParameters playbackParameters)

Attempts to set the playback parameters.

public voidsetPlaybackSpeed(float speed)

Changes the rate at which playback occurs.

public voidsetPlaylistMetadata(MediaMetadata mediaMetadata)

Sets the playlist MediaMetadata.

public voidsetPlayWhenReady(boolean playWhenReady)

Sets whether playback should proceed when Player.getPlaybackState() == Player.STATE_READY.

public voidsetRepeatMode(int repeatMode)

Sets the Player.RepeatMode to be used for playback.

public voidsetShuffleModeEnabled(boolean shuffleModeEnabled)

Sets whether shuffling of media items is enabled.

public voidsetTrackSelectionParameters(TrackSelectionParameters parameters)

Sets the parameters constraining the track selection.

public voidsetVideoSurface(Surface surface)

Sets the onto which video will be rendered.

public voidsetVideoSurfaceHolder(SurfaceHolder surfaceHolder)

Sets the SurfaceHolder that holds the onto which video will be rendered.

public voidsetVideoSurfaceView(SurfaceView surfaceView)

Sets the onto which video will be rendered.

public voidsetVideoTextureView(TextureView textureView)

Sets the TextureView onto which video will be rendered.

public voidsetVolume(float volume)

Sets the audio volume, valid values are between 0 (silence) and 1 (unity gain, signal unchanged), inclusive.

public voidstop()

Stops playback without resetting the playlist.

public voidstop(boolean reset)

Fields

public static final int STATE_IDLE

The player is idle, meaning it holds only limited resources. The player must be prepared before it will play the media.

public static final int STATE_BUFFERING

The player is not able to immediately play the media, but is doing work toward being able to do so. This state typically occurs when the player needs to buffer more data before playback can start.

public static final int STATE_READY

The player is able to immediately play from its current position. The player will be playing if Player.getPlayWhenReady() is true, and paused otherwise.

public static final int STATE_ENDED

The player has finished playing the media.

public static final int PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST

Playback has been started or paused by a call to Player.setPlayWhenReady(boolean).

public static final int PLAY_WHEN_READY_CHANGE_REASON_AUDIO_FOCUS_LOSS

Playback has been paused because of a loss of audio focus.

public static final int PLAY_WHEN_READY_CHANGE_REASON_AUDIO_BECOMING_NOISY

Playback has been paused to avoid becoming noisy.

public static final int PLAY_WHEN_READY_CHANGE_REASON_REMOTE

Playback has been started or paused because of a remote change.

public static final int PLAY_WHEN_READY_CHANGE_REASON_END_OF_MEDIA_ITEM

Playback has been paused at the end of a media item.

public static final int PLAYBACK_SUPPRESSION_REASON_NONE

Playback is not suppressed.

public static final int PLAYBACK_SUPPRESSION_REASON_TRANSIENT_AUDIO_FOCUS_LOSS

Playback is suppressed due to transient audio focus loss.

public static final int REPEAT_MODE_OFF

Normal playback without repetition. "Previous" and "Next" actions move to the previous and next MediaItem respectively, and do nothing when there is no previous or next MediaItem to move to.

public static final int REPEAT_MODE_ONE

Repeats the currently playing MediaItem infinitely during ongoing playback. "Previous" and "Next" actions behave as they do in Player.REPEAT_MODE_OFF, moving to the previous and next MediaItem respectively, and doing nothing when there is no previous or next MediaItem to move to.

public static final int REPEAT_MODE_ALL

Repeats the entire timeline infinitely. "Previous" and "Next" actions behave as they do in Player.REPEAT_MODE_OFF, but with looping at the ends so that "Previous" when playing the first MediaItem will move to the last MediaItem, and "Next" when playing the last MediaItem will move to the first MediaItem.

public static final int DISCONTINUITY_REASON_AUTO_TRANSITION

Automatic playback transition from one period in the timeline to the next. The period index may be the same as it was before the discontinuity in case the current period is repeated.

This reason also indicates an automatic transition from the content period to an inserted ad period or vice versa. Or a transition caused by another player (e.g. multiple controllers can control the same playback on a remote device).

public static final int DISCONTINUITY_REASON_SEEK

Seek within the current period or to another period.

public static final int DISCONTINUITY_REASON_SEEK_ADJUSTMENT

Seek adjustment due to being unable to seek to the requested position or because the seek was permitted to be inexact.

public static final int DISCONTINUITY_REASON_SKIP

Discontinuity introduced by a skipped period (for instance a skipped ad).

public static final int DISCONTINUITY_REASON_REMOVE

Discontinuity caused by the removal of the current period from the Timeline.

public static final int DISCONTINUITY_REASON_INTERNAL

Discontinuity introduced internally (e.g. by the source).

public static final int TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED

Timeline changed as a result of a change of the playlist items or the order of the items.

public static final int TIMELINE_CHANGE_REASON_SOURCE_UPDATE

Timeline changed as a result of a source update (e.g. result of a dynamic update by the played media).

This reason also indicates a change caused by another player (e.g. multiple controllers can control the same playback on the remote device).

public static final int MEDIA_ITEM_TRANSITION_REASON_REPEAT

The media item has been repeated.

public static final int MEDIA_ITEM_TRANSITION_REASON_AUTO

Playback has automatically transitioned to the next media item.

This reason also indicates a transition caused by another player (e.g. multiple controllers can control the same playback on a remote device).

public static final int MEDIA_ITEM_TRANSITION_REASON_SEEK

A seek to another media item has occurred.

public static final int MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED

The current media item has changed because of a change in the playlist. This can either be if the media item previously being played has been removed, or when the playlist becomes non-empty after being empty.

public static final int EVENT_TIMELINE_CHANGED

Player.getCurrentTimeline() changed.

public static final int EVENT_MEDIA_ITEM_TRANSITION

Player.getCurrentMediaItem() changed or the player started repeating the current item.

public static final int EVENT_TRACKS_CHANGED

Player.getCurrentTracksInfo() changed.

public static final int EVENT_IS_LOADING_CHANGED

Player.isLoading() ()} changed.

public static final int EVENT_PLAYBACK_STATE_CHANGED

Player.getPlaybackState() changed.

public static final int EVENT_PLAY_WHEN_READY_CHANGED

Player.getPlayWhenReady() changed.

public static final int EVENT_PLAYBACK_SUPPRESSION_REASON_CHANGED

Player.getPlaybackSuppressionReason() changed.

public static final int EVENT_IS_PLAYING_CHANGED

Player.isPlaying() changed.

public static final int EVENT_REPEAT_MODE_CHANGED

Player.getRepeatMode() changed.

public static final int EVENT_SHUFFLE_MODE_ENABLED_CHANGED

Player.getShuffleModeEnabled() changed.

public static final int EVENT_PLAYER_ERROR

Player.getPlayerError() changed.

public static final int EVENT_POSITION_DISCONTINUITY

A position discontinuity occurred. See Player.Listener.

public static final int EVENT_PLAYBACK_PARAMETERS_CHANGED

Player.getPlaybackParameters() changed.

public static final int EVENT_AVAILABLE_COMMANDS_CHANGED

Player.isCommandAvailable(int) changed for at least one Player.Command.

public static final int EVENT_MEDIA_METADATA_CHANGED

Player.getMediaMetadata() changed.

public static final int EVENT_PLAYLIST_METADATA_CHANGED

Player.getPlaylistMetadata() changed.

public static final int EVENT_SEEK_BACK_INCREMENT_CHANGED

Player.getSeekBackIncrement() changed.

public static final int EVENT_SEEK_FORWARD_INCREMENT_CHANGED

Player.getSeekForwardIncrement() changed.

public static final int EVENT_MAX_SEEK_TO_PREVIOUS_POSITION_CHANGED

Player.getMaxSeekToPreviousPosition() changed.

public static final int EVENT_TRACK_SELECTION_PARAMETERS_CHANGED

Player.getTrackSelectionParameters() changed.

public static final int EVENT_AUDIO_ATTRIBUTES_CHANGED

Player.getAudioAttributes() changed.

public static final int EVENT_AUDIO_SESSION_ID

The audio session id was set.

public static final int EVENT_VOLUME_CHANGED

Player.getVolume() changed.

public static final int EVENT_SKIP_SILENCE_ENABLED_CHANGED

Skipping silences in the audio stream is enabled or disabled.

public static final int EVENT_SURFACE_SIZE_CHANGED

The size of the surface onto which the video is being rendered changed.

public static final int EVENT_VIDEO_SIZE_CHANGED

Player.getVideoSize() changed.

public static final int EVENT_RENDERED_FIRST_FRAME

A frame is rendered for the first time since setting the surface, or since the renderer was reset, or since the stream being rendered was changed.

public static final int EVENT_CUES

Player.getCurrentCues() changed.

public static final int EVENT_METADATA

Metadata associated with the current playback time changed.

public static final int EVENT_DEVICE_INFO_CHANGED

Player.getDeviceInfo() changed.

public static final int EVENT_DEVICE_VOLUME_CHANGED

Player.getDeviceVolume() changed.

public static final int COMMAND_PLAY_PAUSE

Command to start, pause or resume playback.

public static final int COMMAND_PREPARE

Command to prepare the player.

public static final int COMMAND_STOP

Command to stop playback or release the player.

public static final int COMMAND_SEEK_TO_DEFAULT_POSITION

Command to seek to the default position of the current MediaItem.

public static final int COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM

Command to seek anywhere into the current MediaItem.

public static final int COMMAND_SEEK_IN_CURRENT_WINDOW

Deprecated: Use Player.COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM instead.

public static final int COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM

Command to seek to the default position of the previous MediaItem.

public static final int COMMAND_SEEK_TO_PREVIOUS_WINDOW

Deprecated: Use Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM instead.

public static final int COMMAND_SEEK_TO_PREVIOUS

Command to seek to an earlier position in the current or previous MediaItem.

public static final int COMMAND_SEEK_TO_NEXT_MEDIA_ITEM

Command to seek to the default position of the next MediaItem.

public static final int COMMAND_SEEK_TO_NEXT_WINDOW

Deprecated: Use Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM instead.

public static final int COMMAND_SEEK_TO_NEXT

Command to seek to a later position in the current or next MediaItem.

public static final int COMMAND_SEEK_TO_MEDIA_ITEM

Command to seek anywhere in any MediaItem.

public static final int COMMAND_SEEK_TO_WINDOW

Deprecated: Use Player.COMMAND_SEEK_TO_MEDIA_ITEM instead.

public static final int COMMAND_SEEK_BACK

Command to seek back by a fixed increment into the current MediaItem.

public static final int COMMAND_SEEK_FORWARD

Command to seek forward by a fixed increment into the current MediaItem.

public static final int COMMAND_SET_SPEED_AND_PITCH

Command to set the playback speed and pitch.

public static final int COMMAND_SET_SHUFFLE_MODE

Command to enable shuffling.

public static final int COMMAND_SET_REPEAT_MODE

Command to set the repeat mode.

public static final int COMMAND_GET_CURRENT_MEDIA_ITEM

Command to get the currently playing MediaItem.

public static final int COMMAND_GET_TIMELINE

Command to get the information about the current timeline.

public static final int COMMAND_GET_MEDIA_ITEMS_METADATA

Command to get the MediaItems metadata.

public static final int COMMAND_SET_MEDIA_ITEMS_METADATA

Command to set the MediaItems metadata.

public static final int COMMAND_CHANGE_MEDIA_ITEMS

Command to change the MediaItems in the playlist.

public static final int COMMAND_GET_AUDIO_ATTRIBUTES

Command to get the player current AudioAttributes.

public static final int COMMAND_GET_VOLUME

Command to get the player volume.

public static final int COMMAND_GET_DEVICE_VOLUME

Command to get the device volume and whether it is muted.

public static final int COMMAND_SET_VOLUME

Command to set the player volume.

public static final int COMMAND_SET_DEVICE_VOLUME

Command to set the device volume and mute it.

public static final int COMMAND_ADJUST_DEVICE_VOLUME

Command to increase and decrease the device volume and mute it.

public static final int COMMAND_SET_VIDEO_SURFACE

Command to set and clear the surface on which to render the video.

public static final int COMMAND_GET_TEXT

Command to get the text that should currently be displayed by the player.

public static final int COMMAND_SET_TRACK_SELECTION_PARAMETERS

Command to set the player's track selection parameters.

public static final int COMMAND_GET_TRACK_INFOS

Command to get track infos.

public static final int COMMAND_INVALID

Represents an invalid Player.Command.

Methods

public Looper getApplicationLooper()

Returns the associated with the application thread that's used to access the player and on which player events are received.

public void addListener(Player.Listener listener)

Registers a listener to receive all events from the player.

The listener's methods will be called on the thread associated with Player.getApplicationLooper().

Parameters:

listener: The listener to register.

public void removeListener(Player.Listener listener)

Unregister a listener registered through Player.addListener(Player.Listener). The listener will no longer receive events.

Parameters:

listener: The listener to unregister.

public void setMediaItems(java.util.List<MediaItem> mediaItems)

Clears the playlist, adds the specified MediaItems and resets the position to the default position.

Parameters:

mediaItems: The new MediaItems.

public void setMediaItems(java.util.List<MediaItem> mediaItems, boolean resetPosition)

Clears the playlist and adds the specified MediaItems.

Parameters:

mediaItems: The new MediaItems.
resetPosition: Whether the playback position should be reset to the default position in the first Timeline.Window. If false, playback will start from the position defined by Player.getCurrentMediaItemIndex() and Player.getCurrentPosition().

public void setMediaItems(java.util.List<MediaItem> mediaItems, int startIndex, long startPositionMs)

Clears the playlist and adds the specified MediaItems.

Parameters:

mediaItems: The new MediaItems.
startIndex: The MediaItem index to start playback from. If C.INDEX_UNSET is passed, the current position is not reset.
startPositionMs: The position in milliseconds to start playback from. If C.TIME_UNSET is passed, the default position of the given MediaItem is used. In any case, if startIndex is set to C.INDEX_UNSET, this parameter is ignored and the position is not reset at all.

public void setMediaItem(MediaItem mediaItem)

Clears the playlist, adds the specified MediaItem and resets the position to the default position.

Parameters:

mediaItem: The new MediaItem.

public void setMediaItem(MediaItem mediaItem, long startPositionMs)

Clears the playlist and adds the specified MediaItem.

Parameters:

mediaItem: The new MediaItem.
startPositionMs: The position in milliseconds to start playback from.

public void setMediaItem(MediaItem mediaItem, boolean resetPosition)

Clears the playlist and adds the specified MediaItem.

Parameters:

mediaItem: The new MediaItem.
resetPosition: Whether the playback position should be reset to the default position. If false, playback will start from the position defined by Player.getCurrentMediaItemIndex() and Player.getCurrentPosition().

public void addMediaItem(MediaItem mediaItem)

Adds a media item to the end of the playlist.

Parameters:

mediaItem: The MediaItem to add.

public void addMediaItem(int index, MediaItem mediaItem)

Adds a media item at the given index of the playlist.

Parameters:

index: The index at which to add the media item. If the index is larger than the size of the playlist, the media item is added to the end of the playlist.
mediaItem: The MediaItem to add.

public void addMediaItems(java.util.List<MediaItem> mediaItems)

Adds a list of media items to the end of the playlist.

Parameters:

mediaItems: The MediaItems to add.

public void addMediaItems(int index, java.util.List<MediaItem> mediaItems)

Adds a list of media items at the given index of the playlist.

Parameters:

index: The index at which to add the media items. If the index is larger than the size of the playlist, the media items are added to the end of the playlist.
mediaItems: The MediaItems to add.

public void moveMediaItem(int currentIndex, int newIndex)

Moves the media item at the current index to the new index.

Parameters:

currentIndex: The current index of the media item to move.
newIndex: The new index of the media item. If the new index is larger than the size of the playlist the item is moved to the end of the playlist.

public void moveMediaItems(int fromIndex, int toIndex, int newIndex)

Moves the media item range to the new index.

Parameters:

fromIndex: The start of the range to move.
toIndex: The first item not to be included in the range (exclusive).
newIndex: The new index of the first media item of the range. If the new index is larger than the size of the remaining playlist after removing the range, the range is moved to the end of the playlist.

public void removeMediaItem(int index)

Removes the media item at the given index of the playlist.

Parameters:

index: The index at which to remove the media item.

public void removeMediaItems(int fromIndex, int toIndex)

Removes a range of media items from the playlist.

Parameters:

fromIndex: The index at which to start removing media items.
toIndex: The index of the first item to be kept (exclusive). If the index is larger than the size of the playlist, media items to the end of the playlist are removed.

public void clearMediaItems()

Clears the playlist.

public boolean isCommandAvailable(int command)

Returns whether the provided Player.Command is available.

This method does not execute the command.

Executing a command that is not available (for example, calling Player.seekToNextMediaItem() if Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM is unavailable) will neither throw an exception nor generate a Player.getPlayerError() player error}.

Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM and Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM are unavailable if there is no such MediaItem.

Parameters:

command: A Player.Command.

Returns:

Whether the Player.Command is available.

See also: Player.Listener

public boolean canAdvertiseSession()

Returns whether the player can be used to advertise a media session.

public Player.Commands getAvailableCommands()

Returns the player's currently available Player.Commands.

The returned Player.Commands are not updated when available commands change. Use Player.Listener to get an update when the available commands change.

Executing a command that is not available (for example, calling Player.seekToNextMediaItem() if Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM is unavailable) will neither throw an exception nor generate a Player.getPlayerError() player error}.

Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM and Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM are unavailable if there is no such MediaItem.

Returns:

The currently available Player.Commands.

See also: Player.Listener.onAvailableCommandsChanged(Player.Commands)

public void prepare()

Prepares the player.

This will move the player out of idle state and the player will start loading media and acquire resources needed for playback.

public int getPlaybackState()

Returns the current playback state of the player.

Returns:

The current playback state.

See also: Player.Listener.onPlaybackStateChanged(int)

public int getPlaybackSuppressionReason()

Returns the reason why playback is suppressed even though Player.getPlayWhenReady() is true, or Player.PLAYBACK_SUPPRESSION_REASON_NONE if playback is not suppressed.

Returns:

The current playback suppression reason.

See also: Player.Listener.onPlaybackSuppressionReasonChanged(int)

public boolean isPlaying()

Returns whether the player is playing, i.e. Player.getCurrentPosition() is advancing.

If false, then at least one of the following is true:

Returns:

Whether the player is playing.

See also: Player.Listener.onIsPlayingChanged(boolean)

public PlaybackException getPlayerError()

Returns the error that caused playback to fail. This is the same error that will have been reported via Player.Listener.onPlayerError(PlaybackException) at the time of failure. It can be queried using this method until the player is re-prepared.

Note that this method will always return null if Player.getPlaybackState() is not Player.STATE_IDLE.

Returns:

The error, or null.

See also: Player.Listener.onPlayerError(PlaybackException)

public void play()

Resumes playback as soon as Player.getPlaybackState() == Player.STATE_READY. Equivalent to setPlayWhenReady(true).

public void pause()

Pauses playback. Equivalent to setPlayWhenReady(false).

public void setPlayWhenReady(boolean playWhenReady)

Sets whether playback should proceed when Player.getPlaybackState() == Player.STATE_READY.

If the player is already in the ready state then this method pauses and resumes playback.

Parameters:

playWhenReady: Whether playback should proceed when ready.

public boolean getPlayWhenReady()

Whether playback will proceed when Player.getPlaybackState() == Player.STATE_READY.

Returns:

Whether playback will proceed when ready.

See also: Player.Listener.onPlayWhenReadyChanged(boolean, int)

public void setRepeatMode(int repeatMode)

Sets the Player.RepeatMode to be used for playback.

Parameters:

repeatMode: The repeat mode.

public int getRepeatMode()

Returns the current Player.RepeatMode used for playback.

Returns:

The current repeat mode.

See also: Player.Listener.onRepeatModeChanged(int)

public void setShuffleModeEnabled(boolean shuffleModeEnabled)

Sets whether shuffling of media items is enabled.

Parameters:

shuffleModeEnabled: Whether shuffling is enabled.

public boolean getShuffleModeEnabled()

Returns whether shuffling of media items is enabled.

See also: Player.Listener.onShuffleModeEnabledChanged(boolean)

public boolean isLoading()

Whether the player is currently loading the source.

Returns:

Whether the player is currently loading the source.

See also: Player.Listener.onIsLoadingChanged(boolean)

public void seekToDefaultPosition()

Seeks to the default position associated with the current MediaItem. The position can depend on the type of media being played. For live streams it will typically be the live edge. For other streams it will typically be the start.

public void seekToDefaultPosition(int mediaItemIndex)

Seeks to the default position associated with the specified MediaItem. The position can depend on the type of media being played. For live streams it will typically be the live edge. For other streams it will typically be the start.

Parameters:

mediaItemIndex: The index of the MediaItem whose associated default position should be seeked to.

public void seekTo(long positionMs)

Seeks to a position specified in milliseconds in the current MediaItem.

Parameters:

positionMs: The seek position in the current MediaItem, or C.TIME_UNSET to seek to the media item's default position.

public void seekTo(int mediaItemIndex, long positionMs)

Seeks to a position specified in milliseconds in the specified MediaItem.

Parameters:

mediaItemIndex: The index of the MediaItem.
positionMs: The seek position in the specified MediaItem, or C.TIME_UNSET to seek to the media item's default position.

public long getSeekBackIncrement()

Returns the Player.seekBack() increment.

Returns:

The seek back increment, in milliseconds.

See also: Player.Listener.onSeekBackIncrementChanged(long)

public void seekBack()

Seeks back in the current MediaItem by Player.getSeekBackIncrement() milliseconds.

public long getSeekForwardIncrement()

Returns the Player.seekForward() increment.

Returns:

The seek forward increment, in milliseconds.

See also: Player.Listener.onSeekForwardIncrementChanged(long)

public void seekForward()

Seeks forward in the current MediaItem by Player.getSeekForwardIncrement() milliseconds.

public boolean hasPrevious()

Deprecated: Use Player.hasPreviousMediaItem() instead.

public boolean hasPreviousWindow()

Deprecated: Use Player.hasPreviousMediaItem() instead.

public boolean hasPreviousMediaItem()

Returns whether a previous media item exists, which may depend on the current repeat mode and whether shuffle mode is enabled.

Note: When the repeat mode is Player.REPEAT_MODE_ONE, this method behaves the same as when the current repeat mode is Player.REPEAT_MODE_OFF. See Player.REPEAT_MODE_ONE for more details.

public void previous()

Deprecated: Use Player.seekToPreviousMediaItem() instead.

public void seekToPreviousWindow()

Deprecated: Use Player.seekToPreviousMediaItem() instead.

public void seekToPreviousMediaItem()

Seeks to the default position of the previous MediaItem, which may depend on the current repeat mode and whether shuffle mode is enabled. Does nothing if Player.hasPreviousMediaItem() is false.

Note: When the repeat mode is Player.REPEAT_MODE_ONE, this method behaves the same as when the current repeat mode is Player.REPEAT_MODE_OFF. See Player.REPEAT_MODE_ONE for more details.

public long getMaxSeekToPreviousPosition()

Returns the maximum position for which Player.seekToPrevious() seeks to the previous MediaItem, in milliseconds.

Returns:

The maximum seek to previous position, in milliseconds.

See also: Player.Listener.onMaxSeekToPreviousPositionChanged(long)

public void seekToPrevious()

Seeks to an earlier position in the current or previous MediaItem (if available). More precisely:

public boolean hasNext()

Deprecated: Use Player.hasNextMediaItem() instead.

public boolean hasNextWindow()

Deprecated: Use Player.hasNextMediaItem() instead.

public boolean hasNextMediaItem()

Returns whether a next MediaItem exists, which may depend on the current repeat mode and whether shuffle mode is enabled.

Note: When the repeat mode is Player.REPEAT_MODE_ONE, this method behaves the same as when the current repeat mode is Player.REPEAT_MODE_OFF. See Player.REPEAT_MODE_ONE for more details.

public void next()

Deprecated: Use Player.seekToNextMediaItem() instead.

public void seekToNextWindow()

Deprecated: Use Player.seekToNextMediaItem() instead.

public void seekToNextMediaItem()

Seeks to the default position of the next MediaItem, which may depend on the current repeat mode and whether shuffle mode is enabled. Does nothing if Player.hasNextMediaItem() is false.

Note: When the repeat mode is Player.REPEAT_MODE_ONE, this method behaves the same as when the current repeat mode is Player.REPEAT_MODE_OFF. See Player.REPEAT_MODE_ONE for more details.

public void seekToNext()

Seeks to a later position in the current or next MediaItem (if available). More precisely:

  • If the timeline is empty or seeking is not possible, does nothing.
  • Otherwise, if a next media item exists, seeks to the default position of the next MediaItem.
  • Otherwise, if the current MediaItem is live and has not ended, seeks to the live edge of the current MediaItem.
  • Otherwise, does nothing.

public void setPlaybackParameters(PlaybackParameters playbackParameters)

Attempts to set the playback parameters. Passing PlaybackParameters.DEFAULT resets the player to the default, which means there is no speed or pitch adjustment.

Playback parameters changes may cause the player to buffer. Player.Listener.onPlaybackParametersChanged(PlaybackParameters) will be called whenever the currently active playback parameters change.

Parameters:

playbackParameters: The playback parameters.

public void setPlaybackSpeed(float speed)

Changes the rate at which playback occurs. The pitch is not changed.

This is equivalent to setPlaybackParameters(getPlaybackParameters().withSpeed(speed)).

Parameters:

speed: The linear factor by which playback will be sped up. Must be higher than 0. 1 is normal speed, 2 is twice as fast, 0.5 is half normal speed...

public PlaybackParameters getPlaybackParameters()

Returns the currently active playback parameters.

See also: Player.Listener.onPlaybackParametersChanged(PlaybackParameters)

public void stop()

Stops playback without resetting the playlist. Use Player.pause() rather than this method if the intention is to pause playback.

Calling this method will cause the playback state to transition to Player.STATE_IDLE and the player will release the loaded media and resources required for playback. The player instance can still be used by calling Player.prepare() again, and Player.release() must still be called on the player if it's no longer required.

Calling this method does not clear the playlist, reset the playback position or the playback error.

public void stop(boolean reset)

Deprecated: Use Player.stop() and Player.clearMediaItems() (if reset is true) or just Player.stop() (if reset is false). Any player error will be cleared when re-preparing the player.

public void release()

Releases the player. This method must be called when the player is no longer required. The player must not be used after calling this method.

public TrackGroupArray getCurrentTrackGroups()

Deprecated: Use Player.getCurrentTracksInfo().

Returns the available track groups.

See also: Player.Listener.onTracksChanged(TrackGroupArray, TrackSelectionArray)

public TrackSelectionArray getCurrentTrackSelections()

Deprecated: Use Player.getCurrentTracksInfo().

Returns the current track selections.

A concrete implementation may include null elements if it has a fixed number of renderer components, wishes to report a TrackSelection for each of them, and has one or more renderer components that is not assigned any selected tracks.

See also: Player.Listener.onTracksChanged(TrackGroupArray, TrackSelectionArray)

public TracksInfo getCurrentTracksInfo()

Returns the available tracks, as well as the tracks' support, type, and selection status.

See also: Player.Listener.onTracksChanged(TrackGroupArray, TrackSelectionArray)

public TrackSelectionParameters getTrackSelectionParameters()

Returns the parameters constraining the track selection.

See also: Player.Listener

public void setTrackSelectionParameters(TrackSelectionParameters parameters)

Sets the parameters constraining the track selection.

Unsupported parameters will be silently ignored.

Use Player.getTrackSelectionParameters() to retrieve the current parameters. For example, the following snippet restricts video to SD whilst keep other track selection parameters unchanged:

 player.setTrackSelectionParameters(
   player.getTrackSelectionParameters()
         .buildUpon()
         .setMaxVideoSizeSd()
         .build())
 

public MediaMetadata getMediaMetadata()

Returns the current combined MediaMetadata, or MediaMetadata.EMPTY if not supported.

This MediaMetadata is a combination of the MediaItem.mediaMetadata and the static and dynamic metadata from the track selections' formats and Player.Listener.onMetadata(Metadata). If a field is populated in the MediaItem.mediaMetadata, it will be prioritised above the same field coming from static or dynamic metadata.

public MediaMetadata getPlaylistMetadata()

Returns the playlist MediaMetadata, as set by Player.setPlaylistMetadata(MediaMetadata), or MediaMetadata.EMPTY if not supported.

public void setPlaylistMetadata(MediaMetadata mediaMetadata)

Sets the playlist MediaMetadata.

public java.lang.Object getCurrentManifest()

Returns the current manifest. The type depends on the type of media being played. May be null.

public Timeline getCurrentTimeline()

Returns the current Timeline. Never null, but may be empty.

See also: Player.Listener.onTimelineChanged(Timeline, int)

public int getCurrentPeriodIndex()

Returns the index of the period currently being played.

public int getCurrentWindowIndex()

Deprecated: Use Player.getCurrentMediaItemIndex() instead.

public int getCurrentMediaItemIndex()

Returns the index of the current MediaItem in the timeline, or the prospective index if the current timeline is empty.

public int getNextWindowIndex()

Deprecated: Use Player.getNextMediaItemIndex() instead.

public int getNextMediaItemIndex()

Returns the index of the MediaItem that will be played if Player.seekToNextMediaItem() is called, which may depend on the current repeat mode and whether shuffle mode is enabled. Returns C.INDEX_UNSET if Player.hasNextMediaItem() is false.

Note: When the repeat mode is Player.REPEAT_MODE_ONE, this method behaves the same as when the current repeat mode is Player.REPEAT_MODE_OFF. See Player.REPEAT_MODE_ONE for more details.

public int getPreviousWindowIndex()

Deprecated: Use Player.getPreviousMediaItemIndex() instead.

public int getPreviousMediaItemIndex()

Returns the index of the MediaItem that will be played if Player.seekToPreviousMediaItem() is called, which may depend on the current repeat mode and whether shuffle mode is enabled. Returns C.INDEX_UNSET if Player.hasPreviousMediaItem() is false.

Note: When the repeat mode is Player.REPEAT_MODE_ONE, this method behaves the same as when the current repeat mode is Player.REPEAT_MODE_OFF. See Player.REPEAT_MODE_ONE for more details.

public MediaItem getCurrentMediaItem()

Returns the currently playing MediaItem. May be null if the timeline is empty.

See also: Player.Listener.onMediaItemTransition(MediaItem, int)

public int getMediaItemCount()

Returns the number of media items in the playlist.

public MediaItem getMediaItemAt(int index)

Returns the MediaItem at the given index.

public long getDuration()

Returns the duration of the current content or ad in milliseconds, or C.TIME_UNSET if the duration is not known.

public long getCurrentPosition()

Returns the playback position in the current content or ad, in milliseconds, or the prospective position in milliseconds if the current timeline is empty.

public long getBufferedPosition()

Returns an estimate of the position in the current content or ad up to which data is buffered, in milliseconds.

public int getBufferedPercentage()

Returns an estimate of the percentage in the current content or ad up to which data is buffered, or 0 if no estimate is available.

public long getTotalBufferedDuration()

Returns an estimate of the total buffered duration from the current position, in milliseconds. This includes pre-buffered data for subsequent ads and media items.

public boolean isCurrentWindowDynamic()

Deprecated: Use Player.isCurrentMediaItemDynamic() instead.

public boolean isCurrentMediaItemDynamic()

Returns whether the current MediaItem is dynamic (may change when the Timeline is updated), or false if the Timeline is empty.

See also: Timeline.Window.isDynamic

public boolean isCurrentWindowLive()

Deprecated: Use Player.isCurrentMediaItemLive() instead.

public boolean isCurrentMediaItemLive()

Returns whether the current MediaItem is live, or false if the Timeline is empty.

See also: Timeline.Window.isLive()

public long getCurrentLiveOffset()

Returns the offset of the current playback position from the live edge in milliseconds, or C.TIME_UNSET if the current MediaItem Player.isCurrentMediaItemLive() isn't live} or the offset is unknown.

The offset is calculated as currentTime - playbackPosition, so should usually be positive.

Note that this offset may rely on an accurate local time, so this method may return an incorrect value if the difference between system clock and server clock is unknown.

public boolean isCurrentWindowSeekable()

Deprecated: Use Player.isCurrentMediaItemSeekable() instead.

public boolean isCurrentMediaItemSeekable()

Returns whether the current MediaItem is seekable, or false if the Timeline is empty.

See also: Timeline.Window.isSeekable

public boolean isPlayingAd()

Returns whether the player is currently playing an ad.

public int getCurrentAdGroupIndex()

If Player.isPlayingAd() returns true, returns the index of the ad group in the period currently being played. Returns C.INDEX_UNSET otherwise.

public int getCurrentAdIndexInAdGroup()

If Player.isPlayingAd() returns true, returns the index of the ad in its ad group. Returns C.INDEX_UNSET otherwise.

public long getContentDuration()

If Player.isPlayingAd() returns true, returns the duration of the current content in milliseconds, or C.TIME_UNSET if the duration is not known. If there is no ad playing, the returned duration is the same as that returned by Player.getDuration().

public long getContentPosition()

If Player.isPlayingAd() returns true, returns the content position that will be played once all ads in the ad group have finished playing, in milliseconds. If there is no ad playing, the returned position is the same as that returned by Player.getCurrentPosition().

public long getContentBufferedPosition()

If Player.isPlayingAd() returns true, returns an estimate of the content position in the current content up to which data is buffered, in milliseconds. If there is no ad playing, the returned position is the same as that returned by Player.getBufferedPosition().

public AudioAttributes getAudioAttributes()

Returns the attributes for audio playback.

public void setVolume(float volume)

Sets the audio volume, valid values are between 0 (silence) and 1 (unity gain, signal unchanged), inclusive.

Parameters:

volume: Linear output gain to apply to all audio channels.

public float getVolume()

Returns the audio volume, with 0 being silence and 1 being unity gain (signal unchanged).

Returns:

The linear gain applied to all audio channels.

public void clearVideoSurface()

Clears any , SurfaceHolder, or TextureView currently set on the player.

public void clearVideoSurface(Surface surface)

Clears the onto which video is being rendered if it matches the one passed. Else does nothing.

Parameters:

surface: The surface to clear.

public void setVideoSurface(Surface surface)

Sets the onto which video will be rendered. The caller is responsible for tracking the lifecycle of the surface, and must clear the surface by calling setVideoSurface(null) if the surface is destroyed.

If the surface is held by a , TextureView or SurfaceHolder then it's recommended to use Player.setVideoSurfaceView(SurfaceView), Player.setVideoTextureView(TextureView) or Player.setVideoSurfaceHolder(SurfaceHolder) rather than this method, since passing the holder allows the player to track the lifecycle of the surface automatically.

Parameters:

surface: The .

public void setVideoSurfaceHolder(SurfaceHolder surfaceHolder)

Sets the SurfaceHolder that holds the onto which video will be rendered. The player will track the lifecycle of the surface automatically.

The thread that calls the methods must be the thread associated with Player.getApplicationLooper().

Parameters:

surfaceHolder: The surface holder.

public void clearVideoSurfaceHolder(SurfaceHolder surfaceHolder)

Clears the SurfaceHolder that holds the onto which video is being rendered if it matches the one passed. Else does nothing.

Parameters:

surfaceHolder: The surface holder to clear.

public void setVideoSurfaceView(SurfaceView surfaceView)

Sets the onto which video will be rendered. The player will track the lifecycle of the surface automatically.

The thread that calls the methods must be the thread associated with Player.getApplicationLooper().

Parameters:

surfaceView: The surface view.

public void clearVideoSurfaceView(SurfaceView surfaceView)

Clears the onto which video is being rendered if it matches the one passed. Else does nothing.

Parameters:

surfaceView: The texture view to clear.

public void setVideoTextureView(TextureView textureView)

Sets the TextureView onto which video will be rendered. The player will track the lifecycle of the surface automatically.

The thread that calls the methods must be the thread associated with Player.getApplicationLooper().

Parameters:

textureView: The texture view.

public void clearVideoTextureView(TextureView textureView)

Clears the TextureView onto which video is being rendered if it matches the one passed. Else does nothing.

Parameters:

textureView: The texture view to clear.

public VideoSize getVideoSize()

Gets the size of the video.

The video's width and height are 0 if there is no video or its size has not been determined yet.

See also: Player.Listener.onVideoSizeChanged(VideoSize)

public java.util.List<Cue> getCurrentCues()

Returns the current Cues. This list may be empty.

public DeviceInfo getDeviceInfo()

Gets the device information.

public int getDeviceVolume()

Gets the current volume of the device.

For devices with local playback, the volume returned by this method varies according to the current stream type. The stream type is determined by AudioAttributes.usage which can be converted to stream type with Util.getStreamTypeForAudioUsage(int).

For devices with remote playback, the volume of the remote device is returned.

public boolean isDeviceMuted()

Gets whether the device is muted or not.

public void setDeviceVolume(int volume)

Sets the volume of the device.

Parameters:

volume: The volume to set.

public void increaseDeviceVolume()

Increases the volume of the device.

public void decreaseDeviceVolume()

Decreases the volume of the device.

public void setDeviceMuted(boolean muted)

Sets the mute state of the device.

Source

/*
 * Copyright (C) 2017 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.common;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE_USE;

import android.os.Bundle;
import android.os.Looper;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.TextureView;
import androidx.annotation.FloatRange;
import androidx.annotation.IntDef;
import androidx.annotation.IntRange;
import androidx.annotation.Nullable;
import androidx.media3.common.text.Cue;
import androidx.media3.common.util.BundleableUtil;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import com.google.common.base.Objects;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.List;

/**
 * A media player interface defining traditional high-level functionality, such as the ability to
 * play, pause, seek and query properties of the currently playing media.
 *
 * <p>This interface includes some convenience methods that can be implemented by calling other
 * methods in the interface. {@link BasePlayer} implements these convenience methods so inheriting
 * {@link BasePlayer} is recommended when implementing the interface so that only the minimal set of
 * required methods can be implemented.
 *
 * <p>Some important properties of media players that implement this interface are:
 *
 * <ul>
 *   <li>They can provide a {@link Timeline} representing the structure of the media being played,
 *       which can be obtained by calling {@link #getCurrentTimeline()}.
 *   <li>They can provide a {@link TracksInfo} defining the currently available tracks and which are
 *       selected to be rendered, which can be obtained by calling {@link #getCurrentTracksInfo()}.
 * </ul>
 */
public interface Player {

  /** A set of {@link Event events}. */
  final class Events {

    private final FlagSet flags;

    /**
     * Creates an instance.
     *
     * @param flags The {@link FlagSet} containing the {@link Event events}.
     */
    @UnstableApi
    public Events(FlagSet flags) {
      this.flags = flags;
    }

    /**
     * Returns whether the given {@link Event} occurred.
     *
     * @param event The {@link Event}.
     * @return Whether the {@link Event} occurred.
     */
    public boolean contains(@Event int event) {
      return flags.contains(event);
    }

    /**
     * Returns whether any of the given {@link Event events} occurred.
     *
     * @param events The {@link Event events}.
     * @return Whether any of the {@link Event events} occurred.
     */
    public boolean containsAny(@Event int... events) {
      return flags.containsAny(events);
    }

    /** Returns the number of events in the set. */
    public int size() {
      return flags.size();
    }

    /**
     * Returns the {@link Event} at the given index.
     *
     * <p>Although index-based access is possible, it doesn't imply a particular order of these
     * events.
     *
     * @param index The index. Must be between 0 (inclusive) and {@link #size()} (exclusive).
     * @return The {@link Event} at the given index.
     * @throws IndexOutOfBoundsException If index is outside the allowed range.
     */
    public @Event int get(int index) {
      return flags.get(index);
    }

    @Override
    public int hashCode() {
      return flags.hashCode();
    }

    @Override
    public boolean equals(@Nullable Object obj) {
      if (this == obj) {
        return true;
      }
      if (!(obj instanceof Events)) {
        return false;
      }
      Events other = (Events) obj;
      return flags.equals(other.flags);
    }
  }

  /** Position info describing a playback position involved in a discontinuity. */
  final class PositionInfo implements Bundleable {

    /**
     * The UID of the window, or {@code null} if the timeline is {@link Timeline#isEmpty() empty}.
     */
    @Nullable public final Object windowUid;
    /** @deprecated Use {@link #mediaItemIndex} instead. */
    @UnstableApi @Deprecated public final int windowIndex;
    /** The media item index. */
    public final int mediaItemIndex;
    /** The media item, or {@code null} if the timeline is {@link Timeline#isEmpty() empty}. */
    @UnstableApi @Nullable public final MediaItem mediaItem;
    /**
     * The UID of the period, or {@code null} if the timeline is {@link Timeline#isEmpty() empty}.
     */
    @Nullable public final Object periodUid;
    /** The period index. */
    public final int periodIndex;
    /** The playback position, in milliseconds. */
    public final long positionMs;
    /**
     * The content position, in milliseconds.
     *
     * <p>If {@link #adGroupIndex} is {@link C#INDEX_UNSET}, this is the same as {@link
     * #positionMs}.
     */
    public final long contentPositionMs;
    /**
     * The ad group index if the playback position is within an ad, {@link C#INDEX_UNSET} otherwise.
     */
    public final int adGroupIndex;
    /**
     * The index of the ad within the ad group if the playback position is within an ad, {@link
     * C#INDEX_UNSET} otherwise.
     */
    public final int adIndexInAdGroup;

    /**
     * @deprecated Use {@link #PositionInfo(Object, int, MediaItem, Object, int, long, long, int,
     *     int)} instead.
     */
    @Deprecated
    @UnstableApi
    public PositionInfo(
        @Nullable Object windowUid,
        int mediaItemIndex,
        @Nullable Object periodUid,
        int periodIndex,
        long positionMs,
        long contentPositionMs,
        int adGroupIndex,
        int adIndexInAdGroup) {
      this(
          windowUid,
          mediaItemIndex,
          MediaItem.EMPTY,
          periodUid,
          periodIndex,
          positionMs,
          contentPositionMs,
          adGroupIndex,
          adIndexInAdGroup);
    }

    /** Creates an instance. */
    @UnstableApi
    public PositionInfo(
        @Nullable Object windowUid,
        int mediaItemIndex,
        @Nullable MediaItem mediaItem,
        @Nullable Object periodUid,
        int periodIndex,
        long positionMs,
        long contentPositionMs,
        int adGroupIndex,
        int adIndexInAdGroup) {
      this.windowUid = windowUid;
      this.windowIndex = mediaItemIndex;
      this.mediaItemIndex = mediaItemIndex;
      this.mediaItem = mediaItem;
      this.periodUid = periodUid;
      this.periodIndex = periodIndex;
      this.positionMs = positionMs;
      this.contentPositionMs = contentPositionMs;
      this.adGroupIndex = adGroupIndex;
      this.adIndexInAdGroup = adIndexInAdGroup;
    }

    @Override
    public boolean equals(@Nullable Object o) {
      if (this == o) {
        return true;
      }
      if (o == null || getClass() != o.getClass()) {
        return false;
      }
      PositionInfo that = (PositionInfo) o;
      return mediaItemIndex == that.mediaItemIndex
          && periodIndex == that.periodIndex
          && positionMs == that.positionMs
          && contentPositionMs == that.contentPositionMs
          && adGroupIndex == that.adGroupIndex
          && adIndexInAdGroup == that.adIndexInAdGroup
          && Objects.equal(windowUid, that.windowUid)
          && Objects.equal(periodUid, that.periodUid)
          && Objects.equal(mediaItem, that.mediaItem);
    }

    @Override
    public int hashCode() {
      return Objects.hashCode(
          windowUid,
          mediaItemIndex,
          mediaItem,
          periodUid,
          periodIndex,
          positionMs,
          contentPositionMs,
          adGroupIndex,
          adIndexInAdGroup);
    }

    // Bundleable implementation.
    @Documented
    @Retention(RetentionPolicy.SOURCE)
    @Target(TYPE_USE)
    @IntDef({
      FIELD_MEDIA_ITEM_INDEX,
      FIELD_MEDIA_ITEM,
      FIELD_PERIOD_INDEX,
      FIELD_POSITION_MS,
      FIELD_CONTENT_POSITION_MS,
      FIELD_AD_GROUP_INDEX,
      FIELD_AD_INDEX_IN_AD_GROUP
    })
    private @interface FieldNumber {}

    private static final int FIELD_MEDIA_ITEM_INDEX = 0;
    private static final int FIELD_MEDIA_ITEM = 1;
    private static final int FIELD_PERIOD_INDEX = 2;
    private static final int FIELD_POSITION_MS = 3;
    private static final int FIELD_CONTENT_POSITION_MS = 4;
    private static final int FIELD_AD_GROUP_INDEX = 5;
    private static final int FIELD_AD_INDEX_IN_AD_GROUP = 6;

    /**
     * {@inheritDoc}
     *
     * <p>It omits the {@link #windowUid} and {@link #periodUid} fields. The {@link #windowUid} and
     * {@link #periodUid} of an instance restored by {@link #CREATOR} will always be {@code null}.
     */
    @UnstableApi
    @Override
    public Bundle toBundle() {
      Bundle bundle = new Bundle();
      bundle.putInt(keyForField(FIELD_MEDIA_ITEM_INDEX), mediaItemIndex);
      bundle.putBundle(keyForField(FIELD_MEDIA_ITEM), BundleableUtil.toNullableBundle(mediaItem));
      bundle.putInt(keyForField(FIELD_PERIOD_INDEX), periodIndex);
      bundle.putLong(keyForField(FIELD_POSITION_MS), positionMs);
      bundle.putLong(keyForField(FIELD_CONTENT_POSITION_MS), contentPositionMs);
      bundle.putInt(keyForField(FIELD_AD_GROUP_INDEX), adGroupIndex);
      bundle.putInt(keyForField(FIELD_AD_INDEX_IN_AD_GROUP), adIndexInAdGroup);
      return bundle;
    }

    /** Object that can restore {@link PositionInfo} from a {@link Bundle}. */
    @UnstableApi public static final Creator<PositionInfo> CREATOR = PositionInfo::fromBundle;

    private static PositionInfo fromBundle(Bundle bundle) {
      int mediaItemIndex =
          bundle.getInt(keyForField(FIELD_MEDIA_ITEM_INDEX), /* defaultValue= */ C.INDEX_UNSET);
      @Nullable
      MediaItem mediaItem =
          BundleableUtil.fromNullableBundle(
              MediaItem.CREATOR, bundle.getBundle(keyForField(FIELD_MEDIA_ITEM)));
      int periodIndex =
          bundle.getInt(keyForField(FIELD_PERIOD_INDEX), /* defaultValue= */ C.INDEX_UNSET);
      long positionMs =
          bundle.getLong(keyForField(FIELD_POSITION_MS), /* defaultValue= */ C.TIME_UNSET);
      long contentPositionMs =
          bundle.getLong(keyForField(FIELD_CONTENT_POSITION_MS), /* defaultValue= */ C.TIME_UNSET);
      int adGroupIndex =
          bundle.getInt(keyForField(FIELD_AD_GROUP_INDEX), /* defaultValue= */ C.INDEX_UNSET);
      int adIndexInAdGroup =
          bundle.getInt(keyForField(FIELD_AD_INDEX_IN_AD_GROUP), /* defaultValue= */ C.INDEX_UNSET);
      return new PositionInfo(
          /* windowUid= */ null,
          mediaItemIndex,
          mediaItem,
          /* periodUid= */ null,
          periodIndex,
          positionMs,
          contentPositionMs,
          adGroupIndex,
          adIndexInAdGroup);
    }

    private static String keyForField(@FieldNumber int field) {
      return Integer.toString(field, Character.MAX_RADIX);
    }
  }

  /**
   * A set of {@link Command commands}.
   *
   * <p>Instances are immutable.
   */
  final class Commands implements Bundleable {

    /** A builder for {@link Commands} instances. */
    @UnstableApi
    public static final class Builder {

      private static final @Command int[] SUPPORTED_COMMANDS = {
        COMMAND_PLAY_PAUSE,
        COMMAND_PREPARE,
        COMMAND_STOP,
        COMMAND_SEEK_TO_DEFAULT_POSITION,
        COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM,
        COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM,
        COMMAND_SEEK_TO_PREVIOUS,
        COMMAND_SEEK_TO_NEXT_MEDIA_ITEM,
        COMMAND_SEEK_TO_NEXT,
        COMMAND_SEEK_TO_MEDIA_ITEM,
        COMMAND_SEEK_BACK,
        COMMAND_SEEK_FORWARD,
        COMMAND_SET_SPEED_AND_PITCH,
        COMMAND_SET_SHUFFLE_MODE,
        COMMAND_SET_REPEAT_MODE,
        COMMAND_GET_CURRENT_MEDIA_ITEM,
        COMMAND_GET_TIMELINE,
        COMMAND_GET_MEDIA_ITEMS_METADATA,
        COMMAND_SET_MEDIA_ITEMS_METADATA,
        COMMAND_CHANGE_MEDIA_ITEMS,
        COMMAND_GET_AUDIO_ATTRIBUTES,
        COMMAND_GET_VOLUME,
        COMMAND_GET_DEVICE_VOLUME,
        COMMAND_SET_VOLUME,
        COMMAND_SET_DEVICE_VOLUME,
        COMMAND_ADJUST_DEVICE_VOLUME,
        COMMAND_SET_VIDEO_SURFACE,
        COMMAND_GET_TEXT,
        COMMAND_SET_TRACK_SELECTION_PARAMETERS,
        COMMAND_GET_TRACK_INFOS,
      };

      private final FlagSet.Builder flagsBuilder;

      /** Creates a builder. */
      public Builder() {
        flagsBuilder = new FlagSet.Builder();
      }

      private Builder(Commands commands) {
        flagsBuilder = new FlagSet.Builder();
        flagsBuilder.addAll(commands.flags);
      }

      /**
       * Adds a {@link Command}.
       *
       * @param command A {@link Command}.
       * @return This builder.
       * @throws IllegalStateException If {@link #build()} has already been called.
       */
      public Builder add(@Command int command) {
        flagsBuilder.add(command);
        return this;
      }

      /**
       * Adds a {@link Command} if the provided condition is true. Does nothing otherwise.
       *
       * @param command A {@link Command}.
       * @param condition A condition.
       * @return This builder.
       * @throws IllegalStateException If {@link #build()} has already been called.
       */
      public Builder addIf(@Command int command, boolean condition) {
        flagsBuilder.addIf(command, condition);
        return this;
      }

      /**
       * Adds {@link Command commands}.
       *
       * @param commands The {@link Command commands} to add.
       * @return This builder.
       * @throws IllegalStateException If {@link #build()} has already been called.
       */
      public Builder addAll(@Command int... commands) {
        flagsBuilder.addAll(commands);
        return this;
      }

      /**
       * Adds {@link Commands}.
       *
       * @param commands The set of {@link Command commands} to add.
       * @return This builder.
       * @throws IllegalStateException If {@link #build()} has already been called.
       */
      public Builder addAll(Commands commands) {
        flagsBuilder.addAll(commands.flags);
        return this;
      }

      /**
       * Adds all existing {@link Command commands}.
       *
       * @return This builder.
       * @throws IllegalStateException If {@link #build()} has already been called.
       */
      public Builder addAllCommands() {
        flagsBuilder.addAll(SUPPORTED_COMMANDS);
        return this;
      }

      /**
       * Removes a {@link Command}.
       *
       * @param command A {@link Command}.
       * @return This builder.
       * @throws IllegalStateException If {@link #build()} has already been called.
       */
      public Builder remove(@Command int command) {
        flagsBuilder.remove(command);
        return this;
      }

      /**
       * Removes a {@link Command} if the provided condition is true. Does nothing otherwise.
       *
       * @param command A {@link Command}.
       * @param condition A condition.
       * @return This builder.
       * @throws IllegalStateException If {@link #build()} has already been called.
       */
      public Builder removeIf(@Command int command, boolean condition) {
        flagsBuilder.removeIf(command, condition);
        return this;
      }

      /**
       * Removes {@link Command commands}.
       *
       * @param commands The {@link Command commands} to remove.
       * @return This builder.
       * @throws IllegalStateException If {@link #build()} has already been called.
       */
      public Builder removeAll(@Command int... commands) {
        flagsBuilder.removeAll(commands);
        return this;
      }

      /**
       * Builds a {@link Commands} instance.
       *
       * @throws IllegalStateException If this method has already been called.
       */
      public Commands build() {
        return new Commands(flagsBuilder.build());
      }
    }

    /** An empty set of commands. */
    public static final Commands EMPTY = new Builder().build();

    private final FlagSet flags;

    private Commands(FlagSet flags) {
      this.flags = flags;
    }

    /** Returns a {@link Builder} initialized with the values of this instance. */
    @UnstableApi
    public Builder buildUpon() {
      return new Builder(this);
    }

    /** Returns whether the set of commands contains the specified {@link Command}. */
    public boolean contains(@Command int command) {
      return flags.contains(command);
    }

    /** Returns the number of commands in this set. */
    public int size() {
      return flags.size();
    }

    /**
     * Returns the {@link Command} at the given index.
     *
     * @param index The index. Must be between 0 (inclusive) and {@link #size()} (exclusive).
     * @return The {@link Command} at the given index.
     * @throws IndexOutOfBoundsException If index is outside the allowed range.
     */
    public @Command int get(int index) {
      return flags.get(index);
    }

    @Override
    public boolean equals(@Nullable Object obj) {
      if (this == obj) {
        return true;
      }
      if (!(obj instanceof Commands)) {
        return false;
      }
      Commands commands = (Commands) obj;
      return flags.equals(commands.flags);
    }

    @Override
    public int hashCode() {
      return flags.hashCode();
    }

    // Bundleable implementation.

    @Documented
    @Retention(RetentionPolicy.SOURCE)
    @Target(TYPE_USE)
    @IntDef({FIELD_COMMANDS})
    private @interface FieldNumber {}

    private static final int FIELD_COMMANDS = 0;

    @UnstableApi
    @Override
    public Bundle toBundle() {
      Bundle bundle = new Bundle();
      ArrayList<Integer> commandsBundle = new ArrayList<>();
      for (int i = 0; i < flags.size(); i++) {
        commandsBundle.add(flags.get(i));
      }
      bundle.putIntegerArrayList(keyForField(FIELD_COMMANDS), commandsBundle);
      return bundle;
    }

    /** Object that can restore {@link Commands} from a {@link Bundle}. */
    @UnstableApi public static final Creator<Commands> CREATOR = Commands::fromBundle;

    private static Commands fromBundle(Bundle bundle) {
      @Nullable
      ArrayList<Integer> commands = bundle.getIntegerArrayList(keyForField(FIELD_COMMANDS));
      if (commands == null) {
        return Commands.EMPTY;
      }
      Builder builder = new Builder();
      for (int i = 0; i < commands.size(); i++) {
        builder.add(commands.get(i));
      }
      return builder.build();
    }

    private static String keyForField(@FieldNumber int field) {
      return Integer.toString(field, Character.MAX_RADIX);
    }
  }

  /**
   * Listener of all changes in the Player.
   *
   * <p>All methods have no-op default implementations to allow selective overrides.
   */
  interface Listener {

    /**
     * Called when one or more player states changed.
     *
     * <p>State changes and events that happen within one {@link Looper} message queue iteration are
     * reported together and only after all individual callbacks were triggered.
     *
     * <p>Only state changes represented by {@link Event events} are reported through this method.
     *
     * <p>Listeners should prefer this method over individual callbacks in the following cases:
     *
     * <ul>
     *   <li>They intend to trigger the same logic for multiple events (e.g. when updating a UI for
     *       both {@link #onPlaybackStateChanged(int)} and {@link #onPlayWhenReadyChanged(boolean,
     *       int)}).
     *   <li>They need access to the {@link Player} object to trigger further events (e.g. to call
     *       {@link Player#seekTo(long)} after a {@link #onMediaItemTransition(MediaItem, int)}).
     *   <li>They intend to use multiple state values together or in combination with {@link Player}
     *       getter methods. For example using {@link #getCurrentMediaItemIndex()} with the {@code
     *       timeline} provided in {@link #onTimelineChanged(Timeline, int)} is only safe from
     *       within this method.
     *   <li>They are interested in events that logically happened together (e.g {@link
     *       #onPlaybackStateChanged(int)} to {@link #STATE_BUFFERING} because of {@link
     *       #onMediaItemTransition(MediaItem, int)}).
     * </ul>
     *
     * @param player The {@link Player} whose state changed. Use the getters to obtain the latest
     *     states.
     * @param events The {@link Events} that happened in this iteration, indicating which player
     *     states changed.
     */
    default void onEvents(Player player, Events events) {}

    /**
     * Called when the timeline has been refreshed.
     *
     * <p>Note that the current {@link MediaItem} or playback position may change as a result of a
     * timeline change. If playback can't continue smoothly because of this timeline change, a
     * separate {@link #onPositionDiscontinuity(PositionInfo, PositionInfo, int)} callback will be
     * triggered.
     *
     * <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
     * other events that happen in the same {@link Looper} message queue iteration.
     *
     * @param timeline The latest timeline. Never null, but may be empty.
     * @param reason The {@link TimelineChangeReason} responsible for this timeline change.
     */
    default void onTimelineChanged(Timeline timeline, @TimelineChangeReason int reason) {}

    /**
     * Called when playback transitions to a media item or starts repeating a media item according
     * to the current {@link #getRepeatMode() repeat mode}.
     *
     * <p>Note that this callback is also called when the playlist becomes non-empty or empty as a
     * consequence of a playlist change.
     *
     * <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
     * other events that happen in the same {@link Looper} message queue iteration.
     *
     * @param mediaItem The {@link MediaItem}. May be null if the playlist becomes empty.
     * @param reason The reason for the transition.
     */
    default void onMediaItemTransition(
        @Nullable MediaItem mediaItem, @MediaItemTransitionReason int reason) {}

    /**
     * Called when the available or selected tracks change.
     *
     * <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
     * other events that happen in the same {@link Looper} message queue iteration.
     *
     * @param trackGroups The available tracks. Never null, but may be of length zero.
     * @param trackSelections The selected tracks. Never null, but may contain null elements. A
     *     concrete implementation may include null elements if it has a fixed number of renderer
     *     components, wishes to report a TrackSelection for each of them, and has one or more
     *     renderer components that is not assigned any selected tracks.
     * @deprecated Use {@link #onTracksInfoChanged(TracksInfo)} instead.
     */
    @UnstableApi
    @Deprecated
    default void onTracksChanged(
        TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {}

    /**
     * Called when the available or selected tracks change.
     *
     * <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
     * other events that happen in the same {@link Looper} message queue iteration.
     *
     * @param tracksInfo The available tracks information. Never null, but may be of length zero.
     */
    default void onTracksInfoChanged(TracksInfo tracksInfo) {}

    /**
     * Called when the combined {@link MediaMetadata} changes.
     *
     * <p>The provided {@link MediaMetadata} is a combination of the {@link MediaItem#mediaMetadata}
     * and the static and dynamic metadata from the {@link TrackSelection#getFormat(int) track
     * selections' formats} and {@link Listener#onMetadata(Metadata)}. If a field is populated in
     * the {@link MediaItem#mediaMetadata}, it will be prioritised above the same field coming from
     * static or dynamic metadata.
     *
     * <p>This method may be called multiple times in quick succession.
     *
     * <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
     * other events that happen in the same {@link Looper} message queue iteration.
     *
     * @param mediaMetadata The combined {@link MediaMetadata}.
     */
    default void onMediaMetadataChanged(MediaMetadata mediaMetadata) {}

    /**
     * Called when the playlist {@link MediaMetadata} changes.
     *
     * <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
     * other events that happen in the same {@link Looper} message queue iteration.
     */
    default void onPlaylistMetadataChanged(MediaMetadata mediaMetadata) {}

    /**
     * Called when the player starts or stops loading the source.
     *
     * <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
     * other events that happen in the same {@link Looper} message queue iteration.
     *
     * @param isLoading Whether the source is currently being loaded.
     */
    default void onIsLoadingChanged(boolean isLoading) {}

    /** @deprecated Use {@link #onIsLoadingChanged(boolean)} instead. */
    @Deprecated
    @UnstableApi
    default void onLoadingChanged(boolean isLoading) {}

    /**
     * Called when the value returned from {@link #isCommandAvailable(int)} changes for at least one
     * {@link Command}.
     *
     * <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
     * other events that happen in the same {@link Looper} message queue iteration.
     *
     * @param availableCommands The available {@link Commands}.
     */
    default void onAvailableCommandsChanged(Commands availableCommands) {}

    /**
     * Called when the value returned from {@link #getTrackSelectionParameters()} changes.
     *
     * <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
     * other events that happen in the same {@link Looper} message queue iteration.
     *
     * @param parameters The new {@link TrackSelectionParameters}.
     */
    default void onTrackSelectionParametersChanged(TrackSelectionParameters parameters) {}

    /**
     * @deprecated Use {@link #onPlaybackStateChanged(int)} and {@link
     *     #onPlayWhenReadyChanged(boolean, int)} instead.
     */
    @Deprecated
    @UnstableApi
    default void onPlayerStateChanged(boolean playWhenReady, @State int playbackState) {}

    /**
     * Called when the value returned from {@link #getPlaybackState()} changes.
     *
     * <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
     * other events that happen in the same {@link Looper} message queue iteration.
     *
     * @param playbackState The new playback {@link State state}.
     */
    default void onPlaybackStateChanged(@State int playbackState) {}

    /**
     * Called when the value returned from {@link #getPlayWhenReady()} changes.
     *
     * <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
     * other events that happen in the same {@link Looper} message queue iteration.
     *
     * @param playWhenReady Whether playback will proceed when ready.
     * @param reason The {@link PlayWhenReadyChangeReason reason} for the change.
     */
    default void onPlayWhenReadyChanged(
        boolean playWhenReady, @PlayWhenReadyChangeReason int reason) {}

    /**
     * Called when the value returned from {@link #getPlaybackSuppressionReason()} changes.
     *
     * <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
     * other events that happen in the same {@link Looper} message queue iteration.
     *
     * @param playbackSuppressionReason The current {@link PlaybackSuppressionReason}.
     */
    default void onPlaybackSuppressionReasonChanged(
        @PlaybackSuppressionReason int playbackSuppressionReason) {}

    /**
     * Called when the value of {@link #isPlaying()} changes.
     *
     * <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
     * other events that happen in the same {@link Looper} message queue iteration.
     *
     * @param isPlaying Whether the player is playing.
     */
    default void onIsPlayingChanged(boolean isPlaying) {}

    /**
     * Called when the value of {@link #getRepeatMode()} changes.
     *
     * <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
     * other events that happen in the same {@link Looper} message queue iteration.
     *
     * @param repeatMode The {@link RepeatMode} used for playback.
     */
    default void onRepeatModeChanged(@RepeatMode int repeatMode) {}

    /**
     * Called when the value of {@link #getShuffleModeEnabled()} changes.
     *
     * <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
     * other events that happen in the same {@link Looper} message queue iteration.
     *
     * @param shuffleModeEnabled Whether shuffling of {@link MediaItem media items} is enabled.
     */
    default void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {}

    /**
     * Called when an error occurs. The playback state will transition to {@link #STATE_IDLE}
     * immediately after this method is called. The player instance can still be used, and {@link
     * #release()} must still be called on the player should it no longer be required.
     *
     * <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
     * other events that happen in the same {@link Looper} message queue iteration.
     *
     * <p>Implementations of Player may pass an instance of a subclass of {@link PlaybackException}
     * to this method in order to include more information about the error.
     *
     * @param error The error.
     */
    default void onPlayerError(PlaybackException error) {}

    /**
     * Called when the {@link PlaybackException} returned by {@link #getPlayerError()} changes.
     *
     * <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
     * other events that happen in the same {@link Looper} message queue iteration.
     *
     * <p>Implementations of Player may pass an instance of a subclass of {@link PlaybackException}
     * to this method in order to include more information about the error.
     *
     * @param error The new error, or null if the error is being cleared.
     */
    default void onPlayerErrorChanged(@Nullable PlaybackException error) {}

    /**
     * @deprecated Use {@link #onPositionDiscontinuity(PositionInfo, PositionInfo, int)} instead.
     */
    @Deprecated
    @UnstableApi
    default void onPositionDiscontinuity(@DiscontinuityReason int reason) {}

    /**
     * Called when a position discontinuity occurs.
     *
     * <p>A position discontinuity occurs when the playing period changes, the playback position
     * jumps within the period currently being played, or when the playing period has been skipped
     * or removed.
     *
     * <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
     * other events that happen in the same {@link Looper} message queue iteration.
     *
     * @param oldPosition The position before the discontinuity.
     * @param newPosition The position after the discontinuity.
     * @param reason The {@link DiscontinuityReason} responsible for the discontinuity.
     */
    default void onPositionDiscontinuity(
        PositionInfo oldPosition, PositionInfo newPosition, @DiscontinuityReason int reason) {}

    /**
     * Called when the current playback parameters change. The playback parameters may change due to
     * a call to {@link #setPlaybackParameters(PlaybackParameters)}, or the player itself may change
     * them (for example, if audio playback switches to passthrough or offload mode, where speed
     * adjustment is no longer possible).
     *
     * <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
     * other events that happen in the same {@link Looper} message queue iteration.
     *
     * @param playbackParameters The playback parameters.
     */
    default void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {}

    /**
     * Called when the value of {@link #getSeekBackIncrement()} changes.
     *
     * <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
     * other events that happen in the same {@link Looper} message queue iteration.
     *
     * @param seekBackIncrementMs The {@link #seekBack()} increment, in milliseconds.
     */
    default void onSeekBackIncrementChanged(long seekBackIncrementMs) {}

    /**
     * Called when the value of {@link #getSeekForwardIncrement()} changes.
     *
     * <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
     * other events that happen in the same {@link Looper} message queue iteration.
     *
     * @param seekForwardIncrementMs The {@link #seekForward()} increment, in milliseconds.
     */
    default void onSeekForwardIncrementChanged(long seekForwardIncrementMs) {}

    /**
     * Called when the value of {@link #getMaxSeekToPreviousPosition()} changes.
     *
     * <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
     * other events that happen in the same {@link Looper} message queue iteration.
     *
     * @param maxSeekToPreviousPositionMs The maximum position for which {@link #seekToPrevious()}
     *     seeks to the previous position, in milliseconds.
     */
    default void onMaxSeekToPreviousPositionChanged(long maxSeekToPreviousPositionMs) {}

    /**
     * @deprecated Seeks are processed without delay. Listen to {@link
     *     #onPositionDiscontinuity(PositionInfo, PositionInfo, int)} with reason {@link
     *     #DISCONTINUITY_REASON_SEEK} instead.
     */
    @Deprecated
    @UnstableApi
    default void onSeekProcessed() {}

    /**
     * Called when the audio session ID changes.
     *
     * <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
     * other events that happen in the same {@link Looper} message queue iteration.
     *
     * @param audioSessionId The audio session ID.
     */
    @UnstableApi
    default void onAudioSessionIdChanged(int audioSessionId) {}

    /**
     * Called when the audio attributes change.
     *
     * <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
     * other events that happen in the same {@link Looper} message queue iteration.
     *
     * @param audioAttributes The audio attributes.
     */
    default void onAudioAttributesChanged(AudioAttributes audioAttributes) {}

    /**
     * Called when the volume changes.
     *
     * <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
     * other events that happen in the same {@link Looper} message queue iteration.
     *
     * @param volume The new volume, with 0 being silence and 1 being unity gain.
     */
    default void onVolumeChanged(float volume) {}

    /**
     * Called when skipping silences is enabled or disabled in the audio stream.
     *
     * <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
     * other events that happen in the same {@link Looper} message queue iteration.
     *
     * @param skipSilenceEnabled Whether skipping silences in the audio stream is enabled.
     */
    default void onSkipSilenceEnabledChanged(boolean skipSilenceEnabled) {}

    /**
     * Called when the device information changes
     *
     * <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
     * other events that happen in the same {@link Looper} message queue iteration.
     *
     * @param deviceInfo The new {@link DeviceInfo}.
     */
    default void onDeviceInfoChanged(DeviceInfo deviceInfo) {}

    /**
     * Called when the device volume or mute state changes.
     *
     * <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
     * other events that happen in the same {@link Looper} message queue iteration.
     *
     * @param volume The new device volume, with 0 being silence and 1 being unity gain.
     * @param muted Whether the device is muted.
     */
    default void onDeviceVolumeChanged(int volume, boolean muted) {}

    /**
     * Called each time there's a change in the size of the video being rendered.
     *
     * <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
     * other events that happen in the same {@link Looper} message queue iteration.
     *
     * @param videoSize The new size of the video.
     */
    default void onVideoSizeChanged(VideoSize videoSize) {}

    /**
     * Called each time there's a change in the size of the surface onto which the video is being
     * rendered.
     *
     * <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
     * other events that happen in the same {@link Looper} message queue iteration.
     *
     * @param width The surface width in pixels. May be {@link C#LENGTH_UNSET} if unknown, or 0 if
     *     the video is not rendered onto a surface.
     * @param height The surface height in pixels. May be {@link C#LENGTH_UNSET} if unknown, or 0 if
     *     the video is not rendered onto a surface.
     */
    default void onSurfaceSizeChanged(int width, int height) {}

    /**
     * Called when a frame is rendered for the first time since setting the surface, or since the
     * renderer was reset, or since the stream being rendered was changed.
     *
     * <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
     * other events that happen in the same {@link Looper} message queue iteration.
     */
    default void onRenderedFirstFrame() {}

    /**
     * Called when there is a change in the {@link Cue Cues}.
     *
     * <p>{@code cues} is in ascending order of priority. If any of the cue boxes overlap when
     * displayed, the {@link Cue} nearer the end of the list should be shown on top.
     *
     * <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
     * other events that happen in the same {@link Looper} message queue iteration.
     *
     * @param cues The {@link Cue Cues}. May be empty.
     */
    default void onCues(List<Cue> cues) {}

    /**
     * Called when there is metadata associated with the current playback time.
     *
     * <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
     * other events that happen in the same {@link Looper} message queue iteration.
     *
     * @param metadata The metadata.
     */
    @UnstableApi
    default void onMetadata(Metadata metadata) {}
  }

  /**
   * Playback state. One of {@link #STATE_IDLE}, {@link #STATE_BUFFERING}, {@link #STATE_READY} or
   * {@link #STATE_ENDED}.
   */
  // @Target list includes both 'default' targets and TYPE_USE, to ensure backwards compatibility
  // with Kotlin usages from before TYPE_USE was added.
  @Documented
  @Retention(RetentionPolicy.SOURCE)
  @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
  @IntDef({STATE_IDLE, STATE_BUFFERING, STATE_READY, STATE_ENDED})
  @interface State {}
  /**
   * The player is idle, meaning it holds only limited resources. The player must be {@link
   * #prepare() prepared} before it will play the media.
   */
  int STATE_IDLE = 1;
  /**
   * The player is not able to immediately play the media, but is doing work toward being able to do
   * so. This state typically occurs when the player needs to buffer more data before playback can
   * start.
   */
  int STATE_BUFFERING = 2;
  /**
   * The player is able to immediately play from its current position. The player will be playing if
   * {@link #getPlayWhenReady()} is true, and paused otherwise.
   */
  int STATE_READY = 3;
  /** The player has finished playing the media. */
  int STATE_ENDED = 4;

  /**
   * Reasons for {@link #getPlayWhenReady() playWhenReady} changes. One of {@link
   * #PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST}, {@link
   * #PLAY_WHEN_READY_CHANGE_REASON_AUDIO_FOCUS_LOSS}, {@link
   * #PLAY_WHEN_READY_CHANGE_REASON_AUDIO_BECOMING_NOISY}, {@link
   * #PLAY_WHEN_READY_CHANGE_REASON_REMOTE} or {@link
   * #PLAY_WHEN_READY_CHANGE_REASON_END_OF_MEDIA_ITEM}.
   */
  // @Target list includes both 'default' targets and TYPE_USE, to ensure backwards compatibility
  // with Kotlin usages from before TYPE_USE was added.
  @Documented
  @Retention(RetentionPolicy.SOURCE)
  @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
  @IntDef({
    PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST,
    PLAY_WHEN_READY_CHANGE_REASON_AUDIO_FOCUS_LOSS,
    PLAY_WHEN_READY_CHANGE_REASON_AUDIO_BECOMING_NOISY,
    PLAY_WHEN_READY_CHANGE_REASON_REMOTE,
    PLAY_WHEN_READY_CHANGE_REASON_END_OF_MEDIA_ITEM
  })
  @interface PlayWhenReadyChangeReason {}
  /** Playback has been started or paused by a call to {@link #setPlayWhenReady(boolean)}. */
  int PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST = 1;
  /** Playback has been paused because of a loss of audio focus. */
  int PLAY_WHEN_READY_CHANGE_REASON_AUDIO_FOCUS_LOSS = 2;
  /** Playback has been paused to avoid becoming noisy. */
  int PLAY_WHEN_READY_CHANGE_REASON_AUDIO_BECOMING_NOISY = 3;
  /** Playback has been started or paused because of a remote change. */
  int PLAY_WHEN_READY_CHANGE_REASON_REMOTE = 4;
  /** Playback has been paused at the end of a media item. */
  int PLAY_WHEN_READY_CHANGE_REASON_END_OF_MEDIA_ITEM = 5;

  /**
   * Reason why playback is suppressed even though {@link #getPlayWhenReady()} is {@code true}. One
   * of {@link #PLAYBACK_SUPPRESSION_REASON_NONE} or {@link
   * #PLAYBACK_SUPPRESSION_REASON_TRANSIENT_AUDIO_FOCUS_LOSS}.
   */
  // @Target list includes both 'default' targets and TYPE_USE, to ensure backwards compatibility
  // with Kotlin usages from before TYPE_USE was added.
  @Documented
  @Retention(RetentionPolicy.SOURCE)
  @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
  @IntDef({
    PLAYBACK_SUPPRESSION_REASON_NONE,
    PLAYBACK_SUPPRESSION_REASON_TRANSIENT_AUDIO_FOCUS_LOSS
  })
  @interface PlaybackSuppressionReason {}
  /** Playback is not suppressed. */
  int PLAYBACK_SUPPRESSION_REASON_NONE = 0;
  /** Playback is suppressed due to transient audio focus loss. */
  int PLAYBACK_SUPPRESSION_REASON_TRANSIENT_AUDIO_FOCUS_LOSS = 1;

  /**
   * Repeat modes for playback. One of {@link #REPEAT_MODE_OFF}, {@link #REPEAT_MODE_ONE} or {@link
   * #REPEAT_MODE_ALL}.
   */
  // @Target list includes both 'default' targets and TYPE_USE, to ensure backwards compatibility
  // with Kotlin usages from before TYPE_USE was added.
  @Documented
  @Retention(RetentionPolicy.SOURCE)
  @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
  @IntDef({REPEAT_MODE_OFF, REPEAT_MODE_ONE, REPEAT_MODE_ALL})
  @interface RepeatMode {}
  /**
   * Normal playback without repetition. "Previous" and "Next" actions move to the previous and next
   * {@link MediaItem} respectively, and do nothing when there is no previous or next {@link
   * MediaItem} to move to.
   */
  int REPEAT_MODE_OFF = 0;
  /**
   * Repeats the currently playing {@link MediaItem} infinitely during ongoing playback. "Previous"
   * and "Next" actions behave as they do in {@link #REPEAT_MODE_OFF}, moving to the previous and
   * next {@link MediaItem} respectively, and doing nothing when there is no previous or next {@link
   * MediaItem} to move to.
   */
  int REPEAT_MODE_ONE = 1;
  /**
   * Repeats the entire timeline infinitely. "Previous" and "Next" actions behave as they do in
   * {@link #REPEAT_MODE_OFF}, but with looping at the ends so that "Previous" when playing the
   * first {@link MediaItem} will move to the last {@link MediaItem}, and "Next" when playing the
   * last {@link MediaItem} will move to the first {@link MediaItem}.
   */
  int REPEAT_MODE_ALL = 2;

  /**
   * Reasons for position discontinuities. One of {@link #DISCONTINUITY_REASON_AUTO_TRANSITION},
   * {@link #DISCONTINUITY_REASON_SEEK}, {@link #DISCONTINUITY_REASON_SEEK_ADJUSTMENT}, {@link
   * #DISCONTINUITY_REASON_SKIP}, {@link #DISCONTINUITY_REASON_REMOVE} or {@link
   * #DISCONTINUITY_REASON_INTERNAL}.
   */
  // @Target list includes both 'default' targets and TYPE_USE, to ensure backwards compatibility
  // with Kotlin usages from before TYPE_USE was added.
  @Documented
  @Retention(RetentionPolicy.SOURCE)
  @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
  @IntDef({
    DISCONTINUITY_REASON_AUTO_TRANSITION,
    DISCONTINUITY_REASON_SEEK,
    DISCONTINUITY_REASON_SEEK_ADJUSTMENT,
    DISCONTINUITY_REASON_SKIP,
    DISCONTINUITY_REASON_REMOVE,
    DISCONTINUITY_REASON_INTERNAL
  })
  @interface DiscontinuityReason {}
  /**
   * Automatic playback transition from one period in the timeline to the next. The period index may
   * be the same as it was before the discontinuity in case the current period is repeated.
   *
   * <p>This reason also indicates an automatic transition from the content period to an inserted ad
   * period or vice versa. Or a transition caused by another player (e.g. multiple controllers can
   * control the same playback on a remote device).
   */
  int DISCONTINUITY_REASON_AUTO_TRANSITION = 0;
  /** Seek within the current period or to another period. */
  int DISCONTINUITY_REASON_SEEK = 1;
  /**
   * Seek adjustment due to being unable to seek to the requested position or because the seek was
   * permitted to be inexact.
   */
  int DISCONTINUITY_REASON_SEEK_ADJUSTMENT = 2;
  /** Discontinuity introduced by a skipped period (for instance a skipped ad). */
  int DISCONTINUITY_REASON_SKIP = 3;
  /** Discontinuity caused by the removal of the current period from the {@link Timeline}. */
  int DISCONTINUITY_REASON_REMOVE = 4;
  /** Discontinuity introduced internally (e.g. by the source). */
  int DISCONTINUITY_REASON_INTERNAL = 5;

  /**
   * Reasons for timeline changes. One of {@link #TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED} or {@link
   * #TIMELINE_CHANGE_REASON_SOURCE_UPDATE}.
   */
  // @Target list includes both 'default' targets and TYPE_USE, to ensure backwards compatibility
  // with Kotlin usages from before TYPE_USE was added.
  @Documented
  @Retention(RetentionPolicy.SOURCE)
  @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
  @IntDef({TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED, TIMELINE_CHANGE_REASON_SOURCE_UPDATE})
  @interface TimelineChangeReason {}
  /** Timeline changed as a result of a change of the playlist items or the order of the items. */
  int TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED = 0;
  /**
   * Timeline changed as a result of a source update (e.g. result of a dynamic update by the played
   * media).
   *
   * <p>This reason also indicates a change caused by another player (e.g. multiple controllers can
   * control the same playback on the remote device).
   */
  int TIMELINE_CHANGE_REASON_SOURCE_UPDATE = 1;

  /**
   * Reasons for media item transitions. One of {@link #MEDIA_ITEM_TRANSITION_REASON_REPEAT}, {@link
   * #MEDIA_ITEM_TRANSITION_REASON_AUTO}, {@link #MEDIA_ITEM_TRANSITION_REASON_SEEK} or {@link
   * #MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED}.
   */
  // @Target list includes both 'default' targets and TYPE_USE, to ensure backwards compatibility
  // with Kotlin usages from before TYPE_USE was added.
  @Documented
  @Retention(RetentionPolicy.SOURCE)
  @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
  @IntDef({
    MEDIA_ITEM_TRANSITION_REASON_REPEAT,
    MEDIA_ITEM_TRANSITION_REASON_AUTO,
    MEDIA_ITEM_TRANSITION_REASON_SEEK,
    MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED
  })
  @interface MediaItemTransitionReason {}
  /** The media item has been repeated. */
  int MEDIA_ITEM_TRANSITION_REASON_REPEAT = 0;
  /**
   * Playback has automatically transitioned to the next media item.
   *
   * <p>This reason also indicates a transition caused by another player (e.g. multiple controllers
   * can control the same playback on a remote device).
   */
  int MEDIA_ITEM_TRANSITION_REASON_AUTO = 1;
  /** A seek to another media item has occurred. */
  int MEDIA_ITEM_TRANSITION_REASON_SEEK = 2;
  /**
   * The current media item has changed because of a change in the playlist. This can either be if
   * the media item previously being played has been removed, or when the playlist becomes non-empty
   * after being empty.
   */
  int MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED = 3;

  /**
   * Events that can be reported via {@link Listener#onEvents(Player, Events)}.
   *
   * <p>One of the {@link Player}{@code .EVENT_*} values.
   */
  // @Target list includes both 'default' targets and TYPE_USE, to ensure backwards compatibility
  // with Kotlin usages from before TYPE_USE was added.
  @Documented
  @Retention(RetentionPolicy.SOURCE)
  @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
  @IntDef({
    EVENT_TIMELINE_CHANGED,
    EVENT_MEDIA_ITEM_TRANSITION,
    EVENT_TRACKS_CHANGED,
    EVENT_IS_LOADING_CHANGED,
    EVENT_PLAYBACK_STATE_CHANGED,
    EVENT_PLAY_WHEN_READY_CHANGED,
    EVENT_PLAYBACK_SUPPRESSION_REASON_CHANGED,
    EVENT_IS_PLAYING_CHANGED,
    EVENT_REPEAT_MODE_CHANGED,
    EVENT_SHUFFLE_MODE_ENABLED_CHANGED,
    EVENT_PLAYER_ERROR,
    EVENT_POSITION_DISCONTINUITY,
    EVENT_PLAYBACK_PARAMETERS_CHANGED,
    EVENT_AVAILABLE_COMMANDS_CHANGED,
    EVENT_MEDIA_METADATA_CHANGED,
    EVENT_PLAYLIST_METADATA_CHANGED,
    EVENT_SEEK_BACK_INCREMENT_CHANGED,
    EVENT_SEEK_FORWARD_INCREMENT_CHANGED,
    EVENT_MAX_SEEK_TO_PREVIOUS_POSITION_CHANGED,
    EVENT_TRACK_SELECTION_PARAMETERS_CHANGED,
    EVENT_AUDIO_ATTRIBUTES_CHANGED,
    EVENT_AUDIO_SESSION_ID,
    EVENT_VOLUME_CHANGED,
    EVENT_SKIP_SILENCE_ENABLED_CHANGED,
    EVENT_SURFACE_SIZE_CHANGED,
    EVENT_VIDEO_SIZE_CHANGED,
    EVENT_RENDERED_FIRST_FRAME,
    EVENT_CUES,
    EVENT_METADATA,
    EVENT_DEVICE_INFO_CHANGED,
    EVENT_DEVICE_VOLUME_CHANGED
  })
  @interface Event {}
  /** {@link #getCurrentTimeline()} changed. */
  int EVENT_TIMELINE_CHANGED = 0;
  /** {@link #getCurrentMediaItem()} changed or the player started repeating the current item. */
  int EVENT_MEDIA_ITEM_TRANSITION = 1;
  /** {@link #getCurrentTracksInfo()} changed. */
  int EVENT_TRACKS_CHANGED = 2;
  /** {@link #isLoading()} ()} changed. */
  int EVENT_IS_LOADING_CHANGED = 3;
  /** {@link #getPlaybackState()} changed. */
  int EVENT_PLAYBACK_STATE_CHANGED = 4;
  /** {@link #getPlayWhenReady()} changed. */
  int EVENT_PLAY_WHEN_READY_CHANGED = 5;
  /** {@link #getPlaybackSuppressionReason()} changed. */
  int EVENT_PLAYBACK_SUPPRESSION_REASON_CHANGED = 6;
  /** {@link #isPlaying()} changed. */
  int EVENT_IS_PLAYING_CHANGED = 7;
  /** {@link #getRepeatMode()} changed. */
  int EVENT_REPEAT_MODE_CHANGED = 8;
  /** {@link #getShuffleModeEnabled()} changed. */
  int EVENT_SHUFFLE_MODE_ENABLED_CHANGED = 9;
  /** {@link #getPlayerError()} changed. */
  int EVENT_PLAYER_ERROR = 10;
  /**
   * A position discontinuity occurred. See {@link Listener#onPositionDiscontinuity(PositionInfo,
   * PositionInfo, int)}.
   */
  int EVENT_POSITION_DISCONTINUITY = 11;
  /** {@link #getPlaybackParameters()} changed. */
  int EVENT_PLAYBACK_PARAMETERS_CHANGED = 12;
  /** {@link #isCommandAvailable(int)} changed for at least one {@link Command}. */
  int EVENT_AVAILABLE_COMMANDS_CHANGED = 13;
  /** {@link #getMediaMetadata()} changed. */
  int EVENT_MEDIA_METADATA_CHANGED = 14;
  /** {@link #getPlaylistMetadata()} changed. */
  int EVENT_PLAYLIST_METADATA_CHANGED = 15;
  /** {@link #getSeekBackIncrement()} changed. */
  int EVENT_SEEK_BACK_INCREMENT_CHANGED = 16;
  /** {@link #getSeekForwardIncrement()} changed. */
  int EVENT_SEEK_FORWARD_INCREMENT_CHANGED = 17;
  /** {@link #getMaxSeekToPreviousPosition()} changed. */
  int EVENT_MAX_SEEK_TO_PREVIOUS_POSITION_CHANGED = 18;
  /** {@link #getTrackSelectionParameters()} changed. */
  int EVENT_TRACK_SELECTION_PARAMETERS_CHANGED = 19;
  /** {@link #getAudioAttributes()} changed. */
  int EVENT_AUDIO_ATTRIBUTES_CHANGED = 20;
  /** The audio session id was set. */
  int EVENT_AUDIO_SESSION_ID = 21;
  /** {@link #getVolume()} changed. */
  int EVENT_VOLUME_CHANGED = 22;
  /** Skipping silences in the audio stream is enabled or disabled. */
  int EVENT_SKIP_SILENCE_ENABLED_CHANGED = 23;
  /** The size of the surface onto which the video is being rendered changed. */
  int EVENT_SURFACE_SIZE_CHANGED = 24;
  /** {@link #getVideoSize()} changed. */
  int EVENT_VIDEO_SIZE_CHANGED = 25;
  /**
   * A frame is rendered for the first time since setting the surface, or since the renderer was
   * reset, or since the stream being rendered was changed.
   */
  int EVENT_RENDERED_FIRST_FRAME = 26;
  /** {@link #getCurrentCues()} changed. */
  int EVENT_CUES = 27;
  /** Metadata associated with the current playback time changed. */
  int EVENT_METADATA = 28;
  /** {@link #getDeviceInfo()} changed. */
  int EVENT_DEVICE_INFO_CHANGED = 29;
  /** {@link #getDeviceVolume()} changed. */
  int EVENT_DEVICE_VOLUME_CHANGED = 30;

  /**
   * Commands that can be executed on a {@code Player}. One of {@link #COMMAND_PLAY_PAUSE}, {@link
   * #COMMAND_PREPARE}, {@link #COMMAND_STOP}, {@link #COMMAND_SEEK_TO_DEFAULT_POSITION}, {@link
   * #COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM}, {@link #COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM}, {@link
   * #COMMAND_SEEK_TO_PREVIOUS}, {@link #COMMAND_SEEK_TO_NEXT_MEDIA_ITEM}, {@link
   * #COMMAND_SEEK_TO_NEXT}, {@link #COMMAND_SEEK_TO_MEDIA_ITEM}, {@link #COMMAND_SEEK_BACK}, {@link
   * #COMMAND_SEEK_FORWARD}, {@link #COMMAND_SET_SPEED_AND_PITCH}, {@link
   * #COMMAND_SET_SHUFFLE_MODE}, {@link #COMMAND_SET_REPEAT_MODE}, {@link
   * #COMMAND_GET_CURRENT_MEDIA_ITEM}, {@link #COMMAND_GET_TIMELINE}, {@link
   * #COMMAND_GET_MEDIA_ITEMS_METADATA}, {@link #COMMAND_SET_MEDIA_ITEMS_METADATA}, {@link
   * #COMMAND_CHANGE_MEDIA_ITEMS}, {@link #COMMAND_GET_AUDIO_ATTRIBUTES}, {@link
   * #COMMAND_GET_VOLUME}, {@link #COMMAND_GET_DEVICE_VOLUME}, {@link #COMMAND_SET_VOLUME}, {@link
   * #COMMAND_SET_DEVICE_VOLUME}, {@link #COMMAND_ADJUST_DEVICE_VOLUME}, {@link
   * #COMMAND_SET_VIDEO_SURFACE}, {@link #COMMAND_GET_TEXT}, {@link
   * #COMMAND_SET_TRACK_SELECTION_PARAMETERS} or {@link #COMMAND_GET_TRACK_INFOS}.
   */
  // @Target list includes both 'default' targets and TYPE_USE, to ensure backwards compatibility
  // with Kotlin usages from before TYPE_USE was added.
  @Documented
  @Retention(RetentionPolicy.SOURCE)
  @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
  @IntDef({
    COMMAND_INVALID,
    COMMAND_PLAY_PAUSE,
    COMMAND_PREPARE,
    COMMAND_STOP,
    COMMAND_SEEK_TO_DEFAULT_POSITION,
    COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM,
    COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM,
    COMMAND_SEEK_TO_PREVIOUS,
    COMMAND_SEEK_TO_NEXT_MEDIA_ITEM,
    COMMAND_SEEK_TO_NEXT,
    COMMAND_SEEK_TO_MEDIA_ITEM,
    COMMAND_SEEK_BACK,
    COMMAND_SEEK_FORWARD,
    COMMAND_SET_SPEED_AND_PITCH,
    COMMAND_SET_SHUFFLE_MODE,
    COMMAND_SET_REPEAT_MODE,
    COMMAND_GET_CURRENT_MEDIA_ITEM,
    COMMAND_GET_TIMELINE,
    COMMAND_GET_MEDIA_ITEMS_METADATA,
    COMMAND_SET_MEDIA_ITEMS_METADATA,
    COMMAND_CHANGE_MEDIA_ITEMS,
    COMMAND_GET_AUDIO_ATTRIBUTES,
    COMMAND_GET_VOLUME,
    COMMAND_GET_DEVICE_VOLUME,
    COMMAND_SET_VOLUME,
    COMMAND_SET_DEVICE_VOLUME,
    COMMAND_ADJUST_DEVICE_VOLUME,
    COMMAND_SET_VIDEO_SURFACE,
    COMMAND_GET_TEXT,
    COMMAND_SET_TRACK_SELECTION_PARAMETERS,
    COMMAND_GET_TRACK_INFOS,
  })
  @interface Command {}
  /** Command to start, pause or resume playback. */
  int COMMAND_PLAY_PAUSE = 1;
  /** Command to prepare the player. */
  int COMMAND_PREPARE = 2;
  /** Command to stop playback or release the player. */
  int COMMAND_STOP = 3;
  /** Command to seek to the default position of the current {@link MediaItem}. */
  int COMMAND_SEEK_TO_DEFAULT_POSITION = 4;
  /** Command to seek anywhere into the current {@link MediaItem}. */
  int COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM = 5;
  /** @deprecated Use {@link #COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM} instead. */
  @UnstableApi @Deprecated int COMMAND_SEEK_IN_CURRENT_WINDOW = COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM;
  /** Command to seek to the default position of the previous {@link MediaItem}. */
  int COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM = 6;
  /** @deprecated Use {@link #COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM} instead. */
  @UnstableApi @Deprecated
  int COMMAND_SEEK_TO_PREVIOUS_WINDOW = COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM;
  /** Command to seek to an earlier position in the current or previous {@link MediaItem}. */
  int COMMAND_SEEK_TO_PREVIOUS = 7;
  /** Command to seek to the default position of the next {@link MediaItem}. */
  int COMMAND_SEEK_TO_NEXT_MEDIA_ITEM = 8;
  /** @deprecated Use {@link #COMMAND_SEEK_TO_NEXT_MEDIA_ITEM} instead. */
  @UnstableApi @Deprecated int COMMAND_SEEK_TO_NEXT_WINDOW = COMMAND_SEEK_TO_NEXT_MEDIA_ITEM;
  /** Command to seek to a later position in the current or next {@link MediaItem}. */
  int COMMAND_SEEK_TO_NEXT = 9;
  /** Command to seek anywhere in any {@link MediaItem}. */
  int COMMAND_SEEK_TO_MEDIA_ITEM = 10;
  /** @deprecated Use {@link #COMMAND_SEEK_TO_MEDIA_ITEM} instead. */
  @UnstableApi @Deprecated int COMMAND_SEEK_TO_WINDOW = COMMAND_SEEK_TO_MEDIA_ITEM;
  /** Command to seek back by a fixed increment into the current {@link MediaItem}. */
  int COMMAND_SEEK_BACK = 11;
  /** Command to seek forward by a fixed increment into the current {@link MediaItem}. */
  int COMMAND_SEEK_FORWARD = 12;
  /** Command to set the playback speed and pitch. */
  int COMMAND_SET_SPEED_AND_PITCH = 13;
  /** Command to enable shuffling. */
  int COMMAND_SET_SHUFFLE_MODE = 14;
  /** Command to set the repeat mode. */
  int COMMAND_SET_REPEAT_MODE = 15;
  /** Command to get the currently playing {@link MediaItem}. */
  int COMMAND_GET_CURRENT_MEDIA_ITEM = 16;
  /** Command to get the information about the current timeline. */
  int COMMAND_GET_TIMELINE = 17;
  /** Command to get the {@link MediaItem MediaItems} metadata. */
  int COMMAND_GET_MEDIA_ITEMS_METADATA = 18;
  /** Command to set the {@link MediaItem MediaItems} metadata. */
  int COMMAND_SET_MEDIA_ITEMS_METADATA = 19;
  /** Command to change the {@link MediaItem MediaItems} in the playlist. */
  int COMMAND_CHANGE_MEDIA_ITEMS = 20;
  /** Command to get the player current {@link AudioAttributes}. */
  int COMMAND_GET_AUDIO_ATTRIBUTES = 21;
  /** Command to get the player volume. */
  int COMMAND_GET_VOLUME = 22;
  /** Command to get the device volume and whether it is muted. */
  int COMMAND_GET_DEVICE_VOLUME = 23;
  /** Command to set the player volume. */
  int COMMAND_SET_VOLUME = 24;
  /** Command to set the device volume and mute it. */
  int COMMAND_SET_DEVICE_VOLUME = 25;
  /** Command to increase and decrease the device volume and mute it. */
  int COMMAND_ADJUST_DEVICE_VOLUME = 26;
  /** Command to set and clear the surface on which to render the video. */
  int COMMAND_SET_VIDEO_SURFACE = 27;
  /** Command to get the text that should currently be displayed by the player. */
  int COMMAND_GET_TEXT = 28;
  /** Command to set the player's track selection parameters. */
  int COMMAND_SET_TRACK_SELECTION_PARAMETERS = 29;
  /** Command to get track infos. */
  int COMMAND_GET_TRACK_INFOS = 30;

  /** Represents an invalid {@link Command}. */
  int COMMAND_INVALID = -1;

  /**
   * Returns the {@link Looper} associated with the application thread that's used to access the
   * player and on which player events are received.
   */
  Looper getApplicationLooper();

  /**
   * Registers a listener to receive all events from the player.
   *
   * <p>The listener's methods will be called on the thread associated with {@link
   * #getApplicationLooper()}.
   *
   * @param listener The listener to register.
   */
  void addListener(Listener listener);

  /**
   * Unregister a listener registered through {@link #addListener(Listener)}. The listener will no
   * longer receive events.
   *
   * @param listener The listener to unregister.
   */
  void removeListener(Listener listener);

  /**
   * Clears the playlist, adds the specified {@link MediaItem MediaItems} and resets the position to
   * the default position.
   *
   * @param mediaItems The new {@link MediaItem MediaItems}.
   */
  void setMediaItems(List<MediaItem> mediaItems);

  /**
   * Clears the playlist and adds the specified {@link MediaItem MediaItems}.
   *
   * @param mediaItems The new {@link MediaItem MediaItems}.
   * @param resetPosition Whether the playback position should be reset to the default position in
   *     the first {@link Timeline.Window}. If false, playback will start from the position defined
   *     by {@link #getCurrentMediaItemIndex()} and {@link #getCurrentPosition()}.
   */
  void setMediaItems(List<MediaItem> mediaItems, boolean resetPosition);

  /**
   * Clears the playlist and adds the specified {@link MediaItem MediaItems}.
   *
   * @param mediaItems The new {@link MediaItem MediaItems}.
   * @param startIndex The {@link MediaItem} index to start playback from. If {@link C#INDEX_UNSET}
   *     is passed, the current position is not reset.
   * @param startPositionMs The position in milliseconds to start playback from. If {@link
   *     C#TIME_UNSET} is passed, the default position of the given {@link MediaItem} is used. In
   *     any case, if {@code startIndex} is set to {@link C#INDEX_UNSET}, this parameter is ignored
   *     and the position is not reset at all.
   * @throws IllegalSeekPositionException If the provided {@code startIndex} is not within the
   *     bounds of the list of media items.
   */
  void setMediaItems(List<MediaItem> mediaItems, int startIndex, long startPositionMs);

  /**
   * Clears the playlist, adds the specified {@link MediaItem} and resets the position to the
   * default position.
   *
   * @param mediaItem The new {@link MediaItem}.
   */
  void setMediaItem(MediaItem mediaItem);

  /**
   * Clears the playlist and adds the specified {@link MediaItem}.
   *
   * @param mediaItem The new {@link MediaItem}.
   * @param startPositionMs The position in milliseconds to start playback from.
   */
  void setMediaItem(MediaItem mediaItem, long startPositionMs);

  /**
   * Clears the playlist and adds the specified {@link MediaItem}.
   *
   * @param mediaItem The new {@link MediaItem}.
   * @param resetPosition Whether the playback position should be reset to the default position. If
   *     false, playback will start from the position defined by {@link #getCurrentMediaItemIndex()}
   *     and {@link #getCurrentPosition()}.
   */
  void setMediaItem(MediaItem mediaItem, boolean resetPosition);

  /**
   * Adds a media item to the end of the playlist.
   *
   * @param mediaItem The {@link MediaItem} to add.
   */
  void addMediaItem(MediaItem mediaItem);

  /**
   * Adds a media item at the given index of the playlist.
   *
   * @param index The index at which to add the media item. If the index is larger than the size of
   *     the playlist, the media item is added to the end of the playlist.
   * @param mediaItem The {@link MediaItem} to add.
   */
  void addMediaItem(int index, MediaItem mediaItem);

  /**
   * Adds a list of media items to the end of the playlist.
   *
   * @param mediaItems The {@link MediaItem MediaItems} to add.
   */
  void addMediaItems(List<MediaItem> mediaItems);

  /**
   * Adds a list of media items at the given index of the playlist.
   *
   * @param index The index at which to add the media items. If the index is larger than the size of
   *     the playlist, the media items are added to the end of the playlist.
   * @param mediaItems The {@link MediaItem MediaItems} to add.
   */
  void addMediaItems(int index, List<MediaItem> mediaItems);

  /**
   * Moves the media item at the current index to the new index.
   *
   * @param currentIndex The current index of the media item to move.
   * @param newIndex The new index of the media item. If the new index is larger than the size of
   *     the playlist the item is moved to the end of the playlist.
   */
  void moveMediaItem(int currentIndex, int newIndex);

  /**
   * Moves the media item range to the new index.
   *
   * @param fromIndex The start of the range to move.
   * @param toIndex The first item not to be included in the range (exclusive).
   * @param newIndex The new index of the first media item of the range. If the new index is larger
   *     than the size of the remaining playlist after removing the range, the range is moved to the
   *     end of the playlist.
   */
  void moveMediaItems(int fromIndex, int toIndex, int newIndex);

  /**
   * Removes the media item at the given index of the playlist.
   *
   * @param index The index at which to remove the media item.
   */
  void removeMediaItem(int index);

  /**
   * Removes a range of media items from the playlist.
   *
   * @param fromIndex The index at which to start removing media items.
   * @param toIndex The index of the first item to be kept (exclusive). If the index is larger than
   *     the size of the playlist, media items to the end of the playlist are removed.
   */
  void removeMediaItems(int fromIndex, int toIndex);

  /** Clears the playlist. */
  void clearMediaItems();

  /**
   * Returns whether the provided {@link Command} is available.
   *
   * <p>This method does not execute the command.
   *
   * <p>Executing a command that is not available (for example, calling {@link
   * #seekToNextMediaItem()} if {@link #COMMAND_SEEK_TO_NEXT_MEDIA_ITEM} is unavailable) will
   * neither throw an exception nor generate a {@link #getPlayerError()} player error}.
   *
   * <p>{@link #COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM} and {@link #COMMAND_SEEK_TO_NEXT_MEDIA_ITEM}
   * are unavailable if there is no such {@link MediaItem}.
   *
   * @param command A {@link Command}.
   * @return Whether the {@link Command} is available.
   * @see Listener#onAvailableCommandsChanged(Commands)
   */
  boolean isCommandAvailable(@Command int command);

  /** Returns whether the player can be used to advertise a media session. */
  boolean canAdvertiseSession();

  /**
   * Returns the player's currently available {@link Commands}.
   *
   * <p>The returned {@link Commands} are not updated when available commands change. Use {@link
   * Listener#onAvailableCommandsChanged(Commands)} to get an update when the available commands
   * change.
   *
   * <p>Executing a command that is not available (for example, calling {@link
   * #seekToNextMediaItem()} if {@link #COMMAND_SEEK_TO_NEXT_MEDIA_ITEM} is unavailable) will
   * neither throw an exception nor generate a {@link #getPlayerError()} player error}.
   *
   * <p>{@link #COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM} and {@link #COMMAND_SEEK_TO_NEXT_MEDIA_ITEM}
   * are unavailable if there is no such {@link MediaItem}.
   *
   * @return The currently available {@link Commands}.
   * @see Listener#onAvailableCommandsChanged
   */
  Commands getAvailableCommands();

  /**
   * Prepares the player.
   *
   * <p>This will move the player out of {@link #STATE_IDLE idle state} and the player will start
   * loading media and acquire resources needed for playback.
   */
  void prepare();

  /**
   * Returns the current {@link State playback state} of the player.
   *
   * @return The current {@link State playback state}.
   * @see Listener#onPlaybackStateChanged(int)
   */
  @State
  int getPlaybackState();

  /**
   * Returns the reason why playback is suppressed even though {@link #getPlayWhenReady()} is {@code
   * true}, or {@link #PLAYBACK_SUPPRESSION_REASON_NONE} if playback is not suppressed.
   *
   * @return The current {@link PlaybackSuppressionReason playback suppression reason}.
   * @see Listener#onPlaybackSuppressionReasonChanged(int)
   */
  @PlaybackSuppressionReason
  int getPlaybackSuppressionReason();

  /**
   * Returns whether the player is playing, i.e. {@link #getCurrentPosition()} is advancing.
   *
   * <p>If {@code false}, then at least one of the following is true:
   *
   * <ul>
   *   <li>The {@link #getPlaybackState() playback state} is not {@link #STATE_READY ready}.
   *   <li>There is no {@link #getPlayWhenReady() intention to play}.
   *   <li>Playback is {@link #getPlaybackSuppressionReason() suppressed for other reasons}.
   * </ul>
   *
   * @return Whether the player is playing.
   * @see Listener#onIsPlayingChanged(boolean)
   */
  boolean isPlaying();

  /**
   * Returns the error that caused playback to fail. This is the same error that will have been
   * reported via {@link Listener#onPlayerError(PlaybackException)} at the time of failure. It can
   * be queried using this method until the player is re-prepared.
   *
   * <p>Note that this method will always return {@code null} if {@link #getPlaybackState()} is not
   * {@link #STATE_IDLE}.
   *
   * @return The error, or {@code null}.
   * @see Listener#onPlayerError(PlaybackException)
   */
  @Nullable
  PlaybackException getPlayerError();

  /**
   * Resumes playback as soon as {@link #getPlaybackState()} == {@link #STATE_READY}. Equivalent to
   * {@code setPlayWhenReady(true)}.
   */
  void play();

  /** Pauses playback. Equivalent to {@code setPlayWhenReady(false)}. */
  void pause();

  /**
   * Sets whether playback should proceed when {@link #getPlaybackState()} == {@link #STATE_READY}.
   *
   * <p>If the player is already in the ready state then this method pauses and resumes playback.
   *
   * @param playWhenReady Whether playback should proceed when ready.
   */
  void setPlayWhenReady(boolean playWhenReady);

  /**
   * Whether playback will proceed when {@link #getPlaybackState()} == {@link #STATE_READY}.
   *
   * @return Whether playback will proceed when ready.
   * @see Listener#onPlayWhenReadyChanged(boolean, int)
   */
  boolean getPlayWhenReady();

  /**
   * Sets the {@link RepeatMode} to be used for playback.
   *
   * @param repeatMode The repeat mode.
   */
  void setRepeatMode(@RepeatMode int repeatMode);

  /**
   * Returns the current {@link RepeatMode} used for playback.
   *
   * @return The current repeat mode.
   * @see Listener#onRepeatModeChanged(int)
   */
  @RepeatMode
  int getRepeatMode();

  /**
   * Sets whether shuffling of media items is enabled.
   *
   * @param shuffleModeEnabled Whether shuffling is enabled.
   */
  void setShuffleModeEnabled(boolean shuffleModeEnabled);

  /**
   * Returns whether shuffling of media items is enabled.
   *
   * @see Listener#onShuffleModeEnabledChanged(boolean)
   */
  boolean getShuffleModeEnabled();

  /**
   * Whether the player is currently loading the source.
   *
   * @return Whether the player is currently loading the source.
   * @see Listener#onIsLoadingChanged(boolean)
   */
  boolean isLoading();

  /**
   * Seeks to the default position associated with the current {@link MediaItem}. The position can
   * depend on the type of media being played. For live streams it will typically be the live edge.
   * For other streams it will typically be the start.
   */
  void seekToDefaultPosition();

  /**
   * Seeks to the default position associated with the specified {@link MediaItem}. The position can
   * depend on the type of media being played. For live streams it will typically be the live edge.
   * For other streams it will typically be the start.
   *
   * @param mediaItemIndex The index of the {@link MediaItem} whose associated default position
   *     should be seeked to.
   * @throws IllegalSeekPositionException If the player has a non-empty timeline and the provided
   *     {@code mediaItemIndex} is not within the bounds of the current timeline.
   */
  void seekToDefaultPosition(int mediaItemIndex);

  /**
   * Seeks to a position specified in milliseconds in the current {@link MediaItem}.
   *
   * @param positionMs The seek position in the current {@link MediaItem}, or {@link C#TIME_UNSET}
   *     to seek to the media item's default position.
   */
  void seekTo(long positionMs);

  /**
   * Seeks to a position specified in milliseconds in the specified {@link MediaItem}.
   *
   * @param mediaItemIndex The index of the {@link MediaItem}.
   * @param positionMs The seek position in the specified {@link MediaItem}, or {@link C#TIME_UNSET}
   *     to seek to the media item's default position.
   * @throws IllegalSeekPositionException If the player has a non-empty timeline and the provided
   *     {@code mediaItemIndex} is not within the bounds of the current timeline.
   */
  void seekTo(int mediaItemIndex, long positionMs);

  /**
   * Returns the {@link #seekBack()} increment.
   *
   * @return The seek back increment, in milliseconds.
   * @see Listener#onSeekBackIncrementChanged(long)
   */
  long getSeekBackIncrement();

  /**
   * Seeks back in the current {@link MediaItem} by {@link #getSeekBackIncrement()} milliseconds.
   */
  void seekBack();

  /**
   * Returns the {@link #seekForward()} increment.
   *
   * @return The seek forward increment, in milliseconds.
   * @see Listener#onSeekForwardIncrementChanged(long)
   */
  long getSeekForwardIncrement();

  /**
   * Seeks forward in the current {@link MediaItem} by {@link #getSeekForwardIncrement()}
   * milliseconds.
   */
  void seekForward();

  /** @deprecated Use {@link #hasPreviousMediaItem()} instead. */
  @UnstableApi
  @Deprecated
  boolean hasPrevious();

  /** @deprecated Use {@link #hasPreviousMediaItem()} instead. */
  @UnstableApi
  @Deprecated
  boolean hasPreviousWindow();

  /**
   * Returns whether a previous media item exists, which may depend on the current repeat mode and
   * whether shuffle mode is enabled.
   *
   * <p>Note: When the repeat mode is {@link #REPEAT_MODE_ONE}, this method behaves the same as when
   * the current repeat mode is {@link #REPEAT_MODE_OFF}. See {@link #REPEAT_MODE_ONE} for more
   * details.
   */
  boolean hasPreviousMediaItem();

  /** @deprecated Use {@link #seekToPreviousMediaItem()} instead. */
  @UnstableApi
  @Deprecated
  void previous();

  /** @deprecated Use {@link #seekToPreviousMediaItem()} instead. */
  @UnstableApi
  @Deprecated
  void seekToPreviousWindow();

  /**
   * Seeks to the default position of the previous {@link MediaItem}, which may depend on the
   * current repeat mode and whether shuffle mode is enabled. Does nothing if {@link
   * #hasPreviousMediaItem()} is {@code false}.
   *
   * <p>Note: When the repeat mode is {@link #REPEAT_MODE_ONE}, this method behaves the same as when
   * the current repeat mode is {@link #REPEAT_MODE_OFF}. See {@link #REPEAT_MODE_ONE} for more
   * details.
   */
  void seekToPreviousMediaItem();

  /**
   * Returns the maximum position for which {@link #seekToPrevious()} seeks to the previous {@link
   * MediaItem}, in milliseconds.
   *
   * @return The maximum seek to previous position, in milliseconds.
   * @see Listener#onMaxSeekToPreviousPositionChanged(long)
   */
  long getMaxSeekToPreviousPosition();

  /**
   * Seeks to an earlier position in the current or previous {@link MediaItem} (if available). More
   * precisely:
   *
   * <ul>
   *   <li>If the timeline is empty or seeking is not possible, does nothing.
   *   <li>Otherwise, if the current {@link MediaItem} is {@link #isCurrentMediaItemLive()} live}
   *       and {@link #isCurrentMediaItemSeekable() unseekable}, then:
   *       <ul>
   *         <li>If {@link #hasPreviousMediaItem() a previous media item exists}, seeks to the
   *             default position of the previous media item.
   *         <li>Otherwise, does nothing.
   *       </ul>
   *   <li>Otherwise, if {@link #hasPreviousMediaItem() a previous media item exists} and the {@link
   *       #getCurrentPosition() current position} is less than {@link
   *       #getMaxSeekToPreviousPosition()}, seeks to the default position of the previous {@link
   *       MediaItem}.
   *   <li>Otherwise, seeks to 0 in the current {@link MediaItem}.
   * </ul>
   */
  void seekToPrevious();

  /** @deprecated Use {@link #hasNextMediaItem()} instead. */
  @UnstableApi
  @Deprecated
  boolean hasNext();

  /** @deprecated Use {@link #hasNextMediaItem()} instead. */
  @UnstableApi
  @Deprecated
  boolean hasNextWindow();

  /**
   * Returns whether a next {@link MediaItem} exists, which may depend on the current repeat mode
   * and whether shuffle mode is enabled.
   *
   * <p>Note: When the repeat mode is {@link #REPEAT_MODE_ONE}, this method behaves the same as when
   * the current repeat mode is {@link #REPEAT_MODE_OFF}. See {@link #REPEAT_MODE_ONE} for more
   * details.
   */
  boolean hasNextMediaItem();

  /** @deprecated Use {@link #seekToNextMediaItem()} instead. */
  @UnstableApi
  @Deprecated
  void next();

  /** @deprecated Use {@link #seekToNextMediaItem()} instead. */
  @UnstableApi
  @Deprecated
  void seekToNextWindow();

  /**
   * Seeks to the default position of the next {@link MediaItem}, which may depend on the current
   * repeat mode and whether shuffle mode is enabled. Does nothing if {@link #hasNextMediaItem()} is
   * {@code false}.
   *
   * <p>Note: When the repeat mode is {@link #REPEAT_MODE_ONE}, this method behaves the same as when
   * the current repeat mode is {@link #REPEAT_MODE_OFF}. See {@link #REPEAT_MODE_ONE} for more
   * details.
   */
  void seekToNextMediaItem();

  /**
   * Seeks to a later position in the current or next {@link MediaItem} (if available). More
   * precisely:
   *
   * <ul>
   *   <li>If the timeline is empty or seeking is not possible, does nothing.
   *   <li>Otherwise, if {@link #hasNextMediaItem() a next media item exists}, seeks to the default
   *       position of the next {@link MediaItem}.
   *   <li>Otherwise, if the current {@link MediaItem} is {@link #isCurrentMediaItemLive() live} and
   *       has not ended, seeks to the live edge of the current {@link MediaItem}.
   *   <li>Otherwise, does nothing.
   * </ul>
   */
  void seekToNext();

  /**
   * Attempts to set the playback parameters. Passing {@link PlaybackParameters#DEFAULT} resets the
   * player to the default, which means there is no speed or pitch adjustment.
   *
   * <p>Playback parameters changes may cause the player to buffer. {@link
   * Listener#onPlaybackParametersChanged(PlaybackParameters)} will be called whenever the currently
   * active playback parameters change.
   *
   * @param playbackParameters The playback parameters.
   */
  void setPlaybackParameters(PlaybackParameters playbackParameters);

  /**
   * Changes the rate at which playback occurs. The pitch is not changed.
   *
   * <p>This is equivalent to {@code
   * setPlaybackParameters(getPlaybackParameters().withSpeed(speed))}.
   *
   * @param speed The linear factor by which playback will be sped up. Must be higher than 0. 1 is
   *     normal speed, 2 is twice as fast, 0.5 is half normal speed...
   */
  void setPlaybackSpeed(@FloatRange(from = 0, fromInclusive = false) float speed);

  /**
   * Returns the currently active playback parameters.
   *
   * @see Listener#onPlaybackParametersChanged(PlaybackParameters)
   */
  PlaybackParameters getPlaybackParameters();

  /**
   * Stops playback without resetting the playlist. Use {@link #pause()} rather than this method if
   * the intention is to pause playback.
   *
   * <p>Calling this method will cause the playback state to transition to {@link #STATE_IDLE} and
   * the player will release the loaded media and resources required for playback. The player
   * instance can still be used by calling {@link #prepare()} again, and {@link #release()} must
   * still be called on the player if it's no longer required.
   *
   * <p>Calling this method does not clear the playlist, reset the playback position or the playback
   * error.
   */
  void stop();

  /**
   * @deprecated Use {@link #stop()} and {@link #clearMediaItems()} (if {@code reset} is true) or
   *     just {@link #stop()} (if {@code reset} is false). Any player error will be cleared when
   *     {@link #prepare() re-preparing} the player.
   */
  @UnstableApi
  @Deprecated
  void stop(boolean reset);

  /**
   * Releases the player. This method must be called when the player is no longer required. The
   * player must not be used after calling this method.
   */
  void release();

  /**
   * Returns the available track groups.
   *
   * @see Listener#onTracksChanged(TrackGroupArray, TrackSelectionArray)
   * @deprecated Use {@link #getCurrentTracksInfo()}.
   */
  @UnstableApi
  @Deprecated
  TrackGroupArray getCurrentTrackGroups();

  /**
   * Returns the current track selections.
   *
   * <p>A concrete implementation may include null elements if it has a fixed number of renderer
   * components, wishes to report a TrackSelection for each of them, and has one or more renderer
   * components that is not assigned any selected tracks.
   *
   * @see Listener#onTracksChanged(TrackGroupArray, TrackSelectionArray)
   * @deprecated Use {@link #getCurrentTracksInfo()}.
   */
  @UnstableApi
  @Deprecated
  TrackSelectionArray getCurrentTrackSelections();

  /**
   * Returns the available tracks, as well as the tracks' support, type, and selection status.
   *
   * @see Listener#onTracksChanged(TrackGroupArray, TrackSelectionArray)
   */
  TracksInfo getCurrentTracksInfo();

  /**
   * Returns the parameters constraining the track selection.
   *
   * @see Listener#onTrackSelectionParametersChanged}
   */
  TrackSelectionParameters getTrackSelectionParameters();

  /**
   * Sets the parameters constraining the track selection.
   *
   * <p>Unsupported parameters will be silently ignored.
   *
   * <p>Use {@link #getTrackSelectionParameters()} to retrieve the current parameters. For example,
   * the following snippet restricts video to SD whilst keep other track selection parameters
   * unchanged:
   *
   * <pre>{@code
   * player.setTrackSelectionParameters(
   *   player.getTrackSelectionParameters()
   *         .buildUpon()
   *         .setMaxVideoSizeSd()
   *         .build())
   * }</pre>
   */
  void setTrackSelectionParameters(TrackSelectionParameters parameters);

  /**
   * Returns the current combined {@link MediaMetadata}, or {@link MediaMetadata#EMPTY} if not
   * supported.
   *
   * <p>This {@link MediaMetadata} is a combination of the {@link MediaItem#mediaMetadata} and the
   * static and dynamic metadata from the {@link TrackSelection#getFormat(int) track selections'
   * formats} and {@link Listener#onMetadata(Metadata)}. If a field is populated in the {@link
   * MediaItem#mediaMetadata}, it will be prioritised above the same field coming from static or
   * dynamic metadata.
   */
  MediaMetadata getMediaMetadata();

  /**
   * Returns the playlist {@link MediaMetadata}, as set by {@link
   * #setPlaylistMetadata(MediaMetadata)}, or {@link MediaMetadata#EMPTY} if not supported.
   */
  MediaMetadata getPlaylistMetadata();

  /** Sets the playlist {@link MediaMetadata}. */
  void setPlaylistMetadata(MediaMetadata mediaMetadata);

  /**
   * Returns the current manifest. The type depends on the type of media being played. May be null.
   */
  @UnstableApi
  @Nullable
  Object getCurrentManifest();

  /**
   * Returns the current {@link Timeline}. Never null, but may be empty.
   *
   * @see Listener#onTimelineChanged(Timeline, int)
   */
  Timeline getCurrentTimeline();

  /** Returns the index of the period currently being played. */
  int getCurrentPeriodIndex();

  /** @deprecated Use {@link #getCurrentMediaItemIndex()} instead. */
  @UnstableApi
  @Deprecated
  int getCurrentWindowIndex();

  /**
   * Returns the index of the current {@link MediaItem} in the {@link #getCurrentTimeline()
   * timeline}, or the prospective index if the {@link #getCurrentTimeline() current timeline} is
   * empty.
   */
  int getCurrentMediaItemIndex();

  /** @deprecated Use {@link #getNextMediaItemIndex()} instead. */
  @UnstableApi
  @Deprecated
  int getNextWindowIndex();

  /**
   * Returns the index of the {@link MediaItem} that will be played if {@link
   * #seekToNextMediaItem()} is called, which may depend on the current repeat mode and whether
   * shuffle mode is enabled. Returns {@link C#INDEX_UNSET} if {@link #hasNextMediaItem()} is {@code
   * false}.
   *
   * <p>Note: When the repeat mode is {@link #REPEAT_MODE_ONE}, this method behaves the same as when
   * the current repeat mode is {@link #REPEAT_MODE_OFF}. See {@link #REPEAT_MODE_ONE} for more
   * details.
   */
  int getNextMediaItemIndex();

  /** @deprecated Use {@link #getPreviousMediaItemIndex()} instead. */
  @UnstableApi
  @Deprecated
  int getPreviousWindowIndex();

  /**
   * Returns the index of the {@link MediaItem} that will be played if {@link
   * #seekToPreviousMediaItem()} is called, which may depend on the current repeat mode and whether
   * shuffle mode is enabled. Returns {@link C#INDEX_UNSET} if {@link #hasPreviousMediaItem()} is
   * {@code false}.
   *
   * <p>Note: When the repeat mode is {@link #REPEAT_MODE_ONE}, this method behaves the same as when
   * the current repeat mode is {@link #REPEAT_MODE_OFF}. See {@link #REPEAT_MODE_ONE} for more
   * details.
   */
  int getPreviousMediaItemIndex();

  /**
   * Returns the currently playing {@link MediaItem}. May be null if the timeline is empty.
   *
   * @see Listener#onMediaItemTransition(MediaItem, int)
   */
  @Nullable
  MediaItem getCurrentMediaItem();

  /** Returns the number of {@link MediaItem media items} in the playlist. */
  int getMediaItemCount();

  /** Returns the {@link MediaItem} at the given index. */
  MediaItem getMediaItemAt(int index);

  /**
   * Returns the duration of the current content or ad in milliseconds, or {@link C#TIME_UNSET} if
   * the duration is not known.
   */
  long getDuration();

  /**
   * Returns the playback position in the current content or ad, in milliseconds, or the prospective
   * position in milliseconds if the {@link #getCurrentTimeline() current timeline} is empty.
   */
  long getCurrentPosition();

  /**
   * Returns an estimate of the position in the current content or ad up to which data is buffered,
   * in milliseconds.
   */
  long getBufferedPosition();

  /**
   * Returns an estimate of the percentage in the current content or ad up to which data is
   * buffered, or 0 if no estimate is available.
   */
  @IntRange(from = 0, to = 100)
  int getBufferedPercentage();

  /**
   * Returns an estimate of the total buffered duration from the current position, in milliseconds.
   * This includes pre-buffered data for subsequent ads and {@link MediaItem media items}.
   */
  long getTotalBufferedDuration();

  /** @deprecated Use {@link #isCurrentMediaItemDynamic()} instead. */
  @UnstableApi
  @Deprecated
  boolean isCurrentWindowDynamic();

  /**
   * Returns whether the current {@link MediaItem} is dynamic (may change when the {@link Timeline}
   * is updated), or {@code false} if the {@link Timeline} is empty.
   *
   * @see Timeline.Window#isDynamic
   */
  boolean isCurrentMediaItemDynamic();

  /** @deprecated Use {@link #isCurrentMediaItemLive()} instead. */
  @UnstableApi
  @Deprecated
  boolean isCurrentWindowLive();

  /**
   * Returns whether the current {@link MediaItem} is live, or {@code false} if the {@link Timeline}
   * is empty.
   *
   * @see Timeline.Window#isLive()
   */
  boolean isCurrentMediaItemLive();

  /**
   * Returns the offset of the current playback position from the live edge in milliseconds, or
   * {@link C#TIME_UNSET} if the current {@link MediaItem} {@link #isCurrentMediaItemLive()} isn't
   * live} or the offset is unknown.
   *
   * <p>The offset is calculated as {@code currentTime - playbackPosition}, so should usually be
   * positive.
   *
   * <p>Note that this offset may rely on an accurate local time, so this method may return an
   * incorrect value if the difference between system clock and server clock is unknown.
   */
  long getCurrentLiveOffset();

  /** @deprecated Use {@link #isCurrentMediaItemSeekable()} instead. */
  @UnstableApi
  @Deprecated
  boolean isCurrentWindowSeekable();

  /**
   * Returns whether the current {@link MediaItem} is seekable, or {@code false} if the {@link
   * Timeline} is empty.
   *
   * @see Timeline.Window#isSeekable
   */
  boolean isCurrentMediaItemSeekable();

  /** Returns whether the player is currently playing an ad. */
  boolean isPlayingAd();

  /**
   * If {@link #isPlayingAd()} returns true, returns the index of the ad group in the period
   * currently being played. Returns {@link C#INDEX_UNSET} otherwise.
   */
  int getCurrentAdGroupIndex();

  /**
   * If {@link #isPlayingAd()} returns true, returns the index of the ad in its ad group. Returns
   * {@link C#INDEX_UNSET} otherwise.
   */
  int getCurrentAdIndexInAdGroup();

  /**
   * If {@link #isPlayingAd()} returns {@code true}, returns the duration of the current content in
   * milliseconds, or {@link C#TIME_UNSET} if the duration is not known. If there is no ad playing,
   * the returned duration is the same as that returned by {@link #getDuration()}.
   */
  long getContentDuration();

  /**
   * If {@link #isPlayingAd()} returns {@code true}, returns the content position that will be
   * played once all ads in the ad group have finished playing, in milliseconds. If there is no ad
   * playing, the returned position is the same as that returned by {@link #getCurrentPosition()}.
   */
  long getContentPosition();

  /**
   * If {@link #isPlayingAd()} returns {@code true}, returns an estimate of the content position in
   * the current content up to which data is buffered, in milliseconds. If there is no ad playing,
   * the returned position is the same as that returned by {@link #getBufferedPosition()}.
   */
  long getContentBufferedPosition();

  /** Returns the attributes for audio playback. */
  AudioAttributes getAudioAttributes();

  /**
   * Sets the audio volume, valid values are between 0 (silence) and 1 (unity gain, signal
   * unchanged), inclusive.
   *
   * @param volume Linear output gain to apply to all audio channels.
   */
  void setVolume(@FloatRange(from = 0, to = 1.0) float volume);

  /**
   * Returns the audio volume, with 0 being silence and 1 being unity gain (signal unchanged).
   *
   * @return The linear gain applied to all audio channels.
   */
  @FloatRange(from = 0, to = 1.0)
  float getVolume();

  /**
   * Clears any {@link Surface}, {@link SurfaceHolder}, {@link SurfaceView} or {@link TextureView}
   * currently set on the player.
   */
  void clearVideoSurface();

  /**
   * Clears the {@link Surface} onto which video is being rendered if it matches the one passed.
   * Else does nothing.
   *
   * @param surface The surface to clear.
   */
  void clearVideoSurface(@Nullable Surface surface);

  /**
   * Sets the {@link Surface} onto which video will be rendered. The caller is responsible for
   * tracking the lifecycle of the surface, and must clear the surface by calling {@code
   * setVideoSurface(null)} if the surface is destroyed.
   *
   * <p>If the surface is held by a {@link SurfaceView}, {@link TextureView} or {@link
   * SurfaceHolder} then it's recommended to use {@link #setVideoSurfaceView(SurfaceView)}, {@link
   * #setVideoTextureView(TextureView)} or {@link #setVideoSurfaceHolder(SurfaceHolder)} rather than
   * this method, since passing the holder allows the player to track the lifecycle of the surface
   * automatically.
   *
   * @param surface The {@link Surface}.
   */
  void setVideoSurface(@Nullable Surface surface);

  /**
   * Sets the {@link SurfaceHolder} that holds the {@link Surface} onto which video will be
   * rendered. The player will track the lifecycle of the surface automatically.
   *
   * <p>The thread that calls the {@link SurfaceHolder.Callback} methods must be the thread
   * associated with {@link #getApplicationLooper()}.
   *
   * @param surfaceHolder The surface holder.
   */
  void setVideoSurfaceHolder(@Nullable SurfaceHolder surfaceHolder);

  /**
   * Clears the {@link SurfaceHolder} that holds the {@link Surface} onto which video is being
   * rendered if it matches the one passed. Else does nothing.
   *
   * @param surfaceHolder The surface holder to clear.
   */
  void clearVideoSurfaceHolder(@Nullable SurfaceHolder surfaceHolder);

  /**
   * Sets the {@link SurfaceView} onto which video will be rendered. The player will track the
   * lifecycle of the surface automatically.
   *
   * <p>The thread that calls the {@link SurfaceHolder.Callback} methods must be the thread
   * associated with {@link #getApplicationLooper()}.
   *
   * @param surfaceView The surface view.
   */
  void setVideoSurfaceView(@Nullable SurfaceView surfaceView);

  /**
   * Clears the {@link SurfaceView} onto which video is being rendered if it matches the one passed.
   * Else does nothing.
   *
   * @param surfaceView The texture view to clear.
   */
  void clearVideoSurfaceView(@Nullable SurfaceView surfaceView);

  /**
   * Sets the {@link TextureView} onto which video will be rendered. The player will track the
   * lifecycle of the surface automatically.
   *
   * <p>The thread that calls the {@link TextureView.SurfaceTextureListener} methods must be the
   * thread associated with {@link #getApplicationLooper()}.
   *
   * @param textureView The texture view.
   */
  void setVideoTextureView(@Nullable TextureView textureView);

  /**
   * Clears the {@link TextureView} onto which video is being rendered if it matches the one passed.
   * Else does nothing.
   *
   * @param textureView The texture view to clear.
   */
  void clearVideoTextureView(@Nullable TextureView textureView);

  /**
   * Gets the size of the video.
   *
   * <p>The video's width and height are {@code 0} if there is no video or its size has not been
   * determined yet.
   *
   * @see Listener#onVideoSizeChanged(VideoSize)
   */
  VideoSize getVideoSize();

  /** Returns the current {@link Cue Cues}. This list may be empty. */
  List<Cue> getCurrentCues();

  /** Gets the device information. */
  DeviceInfo getDeviceInfo();

  /**
   * Gets the current volume of the device.
   *
   * <p>For devices with {@link DeviceInfo#PLAYBACK_TYPE_LOCAL local playback}, the volume returned
   * by this method varies according to the current {@link C.StreamType stream type}. The stream
   * type is determined by {@link AudioAttributes#usage} which can be converted to stream type with
   * {@link Util#getStreamTypeForAudioUsage(int)}.
   *
   * <p>For devices with {@link DeviceInfo#PLAYBACK_TYPE_REMOTE remote playback}, the volume of the
   * remote device is returned.
   */
  @IntRange(from = 0)
  int getDeviceVolume();

  /** Gets whether the device is muted or not. */
  boolean isDeviceMuted();

  /**
   * Sets the volume of the device.
   *
   * @param volume The volume to set.
   */
  void setDeviceVolume(@IntRange(from = 0) int volume);

  /** Increases the volume of the device. */
  void increaseDeviceVolume();

  /** Decreases the volume of the device. */
  void decreaseDeviceVolume();

  /** Sets the mute state of the device. */
  void setDeviceMuted(boolean muted);
}