public interface

Player

 androidx.media3.common.Player

Subclasses:

SimpleExoPlayer, ExoPlayer, StubPlayer, StubExoPlayer, BasePlayer, SimpleBasePlayer, ForwardingSimpleBasePlayer, ForwardingPlayer, CastPlayer, MediaController, MediaBrowser, CompositionPlayer

Gradle dependencies

compile group: 'androidx.media3', name: 'media3-common', version: '1.5.0-alpha01'

  • groupId: androidx.media3
  • artifactId: media3-common
  • version: 1.5.0-alpha01

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

Overview

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

Player features and usage

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

  • All methods must be called from a single application thread unless indicated otherwise. Callbacks in registered listeners are called on the same thread.
  • The available functionality can be limited. Player instances provide a set of available commands to signal feature support and users of the interface must only call methods if the corresponding Player.Command is available.
  • Users can register Player.Listener callbacks that get informed about state changes.
  • Player instances need to update the visible state immediately after each method call, even if the actual changes are handled on background threads or even other devices. This simplifies the usage for callers of methods as no asynchronous handling needs to be considered.
  • Player instances can provide playlist operations, like 'set', 'add', 'remove', 'move' or 'replace' of MediaItem instances. The player can also support repeat modes and shuffling within this playlist. The player provides a Timeline representing the structure of the playlist and all its items, which can be obtained by calling Player.getCurrentTimeline()
  • Player instances can provide seeking within the currently playing item and to other items, using the various seek... methods.
  • Player instances can provide Tracks defining the currently available and selected tracks, which can be obtained by calling Player.getCurrentTracks(). Users can also modify track selection behavior by setting TrackSelectionParameters with Player.setTrackSelectionParameters(TrackSelectionParameters).
  • Player instances can provide MediaMetadata about the currently playing item, which can be obtained by calling Player.getMediaMetadata().
  • Player instances can provide information about ads in its media structure, for example via Player.isPlayingAd().
  • Player instances can accept different types of video outputs, like SurfaceView or TextureView for video rendering.
  • Player instances can handle playback speed, audio attributes, and audio volume.
  • Player instances can provide information about the playback device, which may be remote, and allow to change the device's volume.

API stability guarantees

The majority of the Player interface and its related classes are part of the stable API that guarantees backwards-compatibility for users of the API. Only more advances use cases may need to rely on UnstableApi classes and methods that are subject to incompatible changes or even removal in a future release. Implementors of the Player interface are not covered by these API stability guarantees.

Player state

Users can listen to state changes by adding a Player.Listener with Player.addListener(Player.Listener).

The main elements of the overall player state are:

Note that there are no callbacks for normal playback progression, only for transitions between media items and other position discontinuities. Code that needs to monitor playback progress (for example, an UI progress bar) should query the current position in appropriate intervals.

Implementing the Player interface

Implementing the Player interface is complex, as the interface includes many convenience methods that need to provide a consistent state and behavior, requires correct handling of listeners and available commands, and expects immediate state changes even if methods are internally handled asynchronously. For this reason, implementations are advised to inherit SimpleBasePlayer that handles all of these complexities and provides a simpler integration point for implementors of the interface.

Summary

Fields
public static final intCOMMAND_ADJUST_DEVICE_VOLUME

public static final intCOMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS

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

public static final intCOMMAND_CHANGE_MEDIA_ITEMS

Command to change the media items 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 information about 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

public static final intCOMMAND_GET_METADATA

Command to get metadata related to the playlist and current MediaItem.

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_TRACKS

Command to get details of the current track selection.

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_RELEASE

Command to release the player.

public static final intCOMMAND_SEEK_BACK

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

public static final intCOMMAND_SEEK_FORWARD

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

public static final intCOMMAND_SEEK_IN_CURRENT_MEDIA_ITEM

Command to seek anywhere inside 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 MediaItem or the default position of the 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 MediaItem or the default position of the 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_AUDIO_ATTRIBUTES

Command to set the player's audio attributes.

public static final intCOMMAND_SET_DEVICE_VOLUME

public static final intCOMMAND_SET_DEVICE_VOLUME_WITH_FLAGS

Command to set the device volume with volume flags.

public static final intCOMMAND_SET_MEDIA_ITEM

Command to set a MediaItem.

public static final intCOMMAND_SET_MEDIA_ITEMS_METADATA

public static final intCOMMAND_SET_PLAYLIST_METADATA

Command to set the playlist 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.

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_SILENCE_SKIP

Discontinuity introduced by a skipped silence.

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.getCurrentTracks() 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_SUPPRESSED_TOO_LONG

Playback has been paused because playback has been suppressed too long.

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 intPLAYBACK_SUPPRESSION_REASON_UNSUITABLE_AUDIO_OUTPUT

Playback is suppressed due to attempt to play on an unsuitable audio output (e.g.

public static final intPLAYBACK_SUPPRESSION_REASON_UNSUITABLE_AUDIO_ROUTE

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()

public voiddecreaseDeviceVolume(int flags)

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 CueGroupgetCurrentCues()

Returns the current CueGroup.

public longgetCurrentLiveOffset()

Returns the offset of the current playback position from the live edge in milliseconds, or C.TIME_UNSET if the current MediaItem 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 TracksgetCurrentTracks()

Returns the current tracks.

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 SizegetSurfaceSize()

Gets the size of the surface on which the video is rendered.

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 booleanhasPreviousMediaItem()

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

public voidincreaseDeviceVolume()

public voidincreaseDeviceVolume(int flags)

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 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 voidreplaceMediaItem(int index, MediaItem mediaItem)

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

public voidreplaceMediaItems(int fromIndex, int toIndex, java.util.List<MediaItem> mediaItems)

Replaces the media items at the given range of 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 voidsetAudioAttributes(AudioAttributes audioAttributes, boolean handleAudioFocus)

Sets the attributes for audio playback, used by the underlying audio track.

public voidsetDeviceMuted(boolean muted)

public voidsetDeviceMuted(boolean muted, int flags)

Sets the mute state of the device.

public voidsetDeviceVolume(int volume)

public voidsetDeviceVolume(int volume, int flags)

Sets the volume of the device with volume flags.

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 media items and resets the position to the default position.

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

Clears the playlist and adds the specified media items.

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

Clears the playlist and adds the specified media items.

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.

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 PLAY_WHEN_READY_CHANGE_REASON_SUPPRESSED_TOO_LONG

Playback has been paused because playback has been suppressed too long.

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 PLAYBACK_SUPPRESSION_REASON_UNSUITABLE_AUDIO_ROUTE

Deprecated: Use Player.PLAYBACK_SUPPRESSION_REASON_UNSUITABLE_AUDIO_OUTPUT instead.

public static final int PLAYBACK_SUPPRESSION_REASON_UNSUITABLE_AUDIO_OUTPUT

Playback is suppressed due to attempt to play on an unsuitable audio output (e.g. attempt to play on built-in speaker on a Wear OS device).

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 DISCONTINUITY_REASON_SILENCE_SKIP

Discontinuity introduced by a skipped silence.

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.getCurrentTracks() 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.

The following methods must only be called if this command is available:

public static final int COMMAND_PREPARE

Command to prepare the player.

The Player.prepare() method must only be called if this command is available.

public static final int COMMAND_STOP

Command to stop playback.

The Player.stop() method must only be called if this command is available.

public static final int COMMAND_SEEK_TO_DEFAULT_POSITION

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

The Player.seekToDefaultPosition() method must only be called if this command is available.

public static final int COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM

Command to seek anywhere inside the current MediaItem.

The Player.seekTo(long) method must only be called if this command is available.

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.

The Player.seekToPreviousMediaItem() method must only be called if this command is available.

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 MediaItem or the default position of the previous MediaItem.

The Player.seekToPrevious() method must only be called if this command is available.

public static final int COMMAND_SEEK_TO_NEXT_MEDIA_ITEM

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

The Player.seekToNextMediaItem() method must only be called if this command is available.

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 MediaItem or the default position of the next MediaItem.

The Player.seekToNext() method must only be called if this command is available.

public static final int COMMAND_SEEK_TO_MEDIA_ITEM

Command to seek anywhere in any MediaItem.

The following methods must only be called if this command is available:

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 inside the current MediaItem.

The Player.seekBack() method must only be called if this command is available.

public static final int COMMAND_SEEK_FORWARD

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

The Player.seekForward() method must only be called if this command is available.

public static final int COMMAND_SET_SPEED_AND_PITCH

Command to set the playback speed and pitch.

The following methods must only be called if this command is available:

public static final int COMMAND_SET_SHUFFLE_MODE

Command to enable shuffling.

The Player.setShuffleModeEnabled(boolean) method must only be called if this command is available.

public static final int COMMAND_SET_REPEAT_MODE

Command to set the repeat mode.

The Player.setRepeatMode(int) method must only be called if this command is available.

public static final int COMMAND_GET_CURRENT_MEDIA_ITEM

Command to get information about the currently playing MediaItem.

The following methods must only be called if this command is available:

public static final int COMMAND_GET_TIMELINE

Command to get the information about the current timeline.

The following methods must only be called if this command is available:

public static final int COMMAND_GET_MEDIA_ITEMS_METADATA

Deprecated: Use Player.COMMAND_GET_METADATA instead.

public static final int COMMAND_GET_METADATA

Command to get metadata related to the playlist and current MediaItem.

The following methods must only be called if this command is available:

public static final int COMMAND_SET_MEDIA_ITEMS_METADATA

Deprecated: Use Player.COMMAND_SET_PLAYLIST_METADATA instead.

public static final int COMMAND_SET_PLAYLIST_METADATA

Command to set the playlist metadata.

The Player.setPlaylistMetadata(MediaMetadata) method must only be called if this command is available.

public static final int COMMAND_SET_MEDIA_ITEM

Command to set a MediaItem.

The following methods must only be called if this command is available:

public static final int COMMAND_CHANGE_MEDIA_ITEMS

Command to change the media items in the playlist.

The following methods must only be called if this command is available:

public static final int COMMAND_GET_AUDIO_ATTRIBUTES

Command to get the player current AudioAttributes.

The Player.getAudioAttributes() method must only be called if this command is available.

public static final int COMMAND_GET_VOLUME

Command to get the player volume.

The Player.getVolume() method must only be called if this command is available.

public static final int COMMAND_GET_DEVICE_VOLUME

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

The following methods must only be called if this command is available:

public static final int COMMAND_SET_VOLUME

Command to set the player volume.

The Player.setVolume(float) method must only be called if this command is available.

public static final int COMMAND_SET_DEVICE_VOLUME

Deprecated: Use Player.COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS instead.

public static final int COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS

Command to set the device volume with volume flags.

The Player.setDeviceVolume(int, int) method must only be called if this command is available.

public static final int COMMAND_ADJUST_DEVICE_VOLUME

Deprecated: Use Player.COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS instead.

public static final int COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS

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

The following methods must only be called if this command is available:

public static final int COMMAND_SET_AUDIO_ATTRIBUTES

Command to set the player's audio attributes.

The Player.setAudioAttributes(AudioAttributes, boolean) method must only be called if this command is available.

public static final int COMMAND_SET_VIDEO_SURFACE

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

The following methods must only be called if this command is available:

public static final int COMMAND_GET_TEXT

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

The Player.getCurrentCues() method must only be called if this command is available.

public static final int COMMAND_SET_TRACK_SELECTION_PARAMETERS

Command to set the player's track selection parameters.

The Player.setTrackSelectionParameters(TrackSelectionParameters) method must only be called if this command is available.

public static final int COMMAND_GET_TRACKS

Command to get details of the current track selection.

The Player.getCurrentTracks() method must only be called if this command is available.

public static final int COMMAND_RELEASE

Command to release the player.

The Player.release() method must only be called if this command is available.

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.

This method can be called from any thread.

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().

This method can be called from any thread.

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 media items and resets the position to the default position.

To replace a span of media items (possibly seamlessly) without clearing the playlist, use Player.replaceMediaItems(int, int, List).

This method must only be called if Player.COMMAND_CHANGE_MEDIA_ITEMS is available.

Parameters:

mediaItems: The new media items.

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

Clears the playlist and adds the specified media items.

To replace a span of media items (possibly seamlessly) without clearing the playlist, use Player.replaceMediaItems(int, int, List).

This method must only be called if Player.COMMAND_CHANGE_MEDIA_ITEMS is available.

Parameters:

mediaItems: The new media items.
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 media items.

To replace a span of media items (possibly seamlessly) without clearing the playlist, use Player.replaceMediaItems(int, int, List).

This method must only be called if Player.COMMAND_CHANGE_MEDIA_ITEMS is available.

Parameters:

mediaItems: The new media items.
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.

To replace a media item (possibly seamlessly) without clearing the playlist, use Player.replaceMediaItem(int, MediaItem).

This method must only be called if Player.COMMAND_SET_MEDIA_ITEM is available.

Parameters:

mediaItem: The new MediaItem.

public void setMediaItem(MediaItem mediaItem, long startPositionMs)

Clears the playlist and adds the specified MediaItem.

To replace a media item (possibly seamlessly) without clearing the playlist, use Player.replaceMediaItem(int, MediaItem).

This method must only be called if Player.COMMAND_SET_MEDIA_ITEM is available.

Parameters:

mediaItem: The new MediaItem.
startPositionMs: The position in milliseconds to start playback from. If C.TIME_UNSET is passed, the default position of the given MediaItem is used.

public void setMediaItem(MediaItem mediaItem, boolean resetPosition)

Clears the playlist and adds the specified MediaItem.

To replace a media item (possibly seamlessly) without clearing the playlist, use Player.replaceMediaItem(int, MediaItem).

This method must only be called if Player.COMMAND_SET_MEDIA_ITEM is available.

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.

This method must only be called if Player.COMMAND_CHANGE_MEDIA_ITEMS is available.

Parameters:

mediaItem: The MediaItem to add.

public void addMediaItem(int index, MediaItem mediaItem)

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

This method must only be called if Player.COMMAND_CHANGE_MEDIA_ITEMS is available.

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.

This method must only be called if Player.COMMAND_CHANGE_MEDIA_ITEMS is available.

Parameters:

mediaItems: The media items 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.

This method must only be called if Player.COMMAND_CHANGE_MEDIA_ITEMS is available.

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 media items to add.

public void moveMediaItem(int currentIndex, int newIndex)

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

This method must only be called if Player.COMMAND_CHANGE_MEDIA_ITEMS is available.

Parameters:

currentIndex: The current index of the media item to move. If the index is larger than the size of the playlist, the request is ignored.
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.

This method must only be called if Player.COMMAND_CHANGE_MEDIA_ITEMS is available.

Parameters:

fromIndex: The start of the range to move. If the index is larger than the size of the playlist, the request is ignored.
toIndex: The first item not to be included in the range (exclusive). If the index is larger than the size of the playlist, items up to the end of the playlist are moved.
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 replaceMediaItem(int index, MediaItem mediaItem)

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

Implementations of this method may attempt to seamlessly continue playback if the currently playing media item is replaced with a compatible one (e.g. same URL, only metadata has changed).

This method must only be called if Player.COMMAND_CHANGE_MEDIA_ITEMS is available.

Parameters:

index: The index at which to replace the media item. If the index is larger than the size of the playlist, the request is ignored.
mediaItem: The new MediaItem.

public void replaceMediaItems(int fromIndex, int toIndex, java.util.List<MediaItem> mediaItems)

Replaces the media items at the given range of the playlist.

Implementations of this method may attempt to seamlessly continue playback if the currently playing media item is replaced with a compatible one (e.g. same URL, only metadata has changed).

This method must only be called if Player.COMMAND_CHANGE_MEDIA_ITEMS is available.

Note that it is possible to replace a range with an arbitrary number of new items, so that the number of removed items defined by fromIndex and toIndex does not have to match the number of added items defined by mediaItems. As result, it may also change the index of subsequent items not touched by this operation.

Parameters:

fromIndex: The start of the range. If the index is larger than the size of the playlist, the request is ignored.
toIndex: The first item not to be included in the range (exclusive). If the index is larger than the size of the playlist, items up to the end of the playlist are replaced.
mediaItems: The media items to replace the range with.

public void removeMediaItem(int index)

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

This method must only be called if Player.COMMAND_CHANGE_MEDIA_ITEMS is available.

Parameters:

index: The index at which to remove the media item. If the index is larger than the size of the playlist, the request is ignored.

public void removeMediaItems(int fromIndex, int toIndex)

Removes a range of media items from the playlist.

This method must only be called if Player.COMMAND_CHANGE_MEDIA_ITEMS is available.

Parameters:

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

public void clearMediaItems()

Clears the playlist.

This method must only be called if Player.COMMAND_CHANGE_MEDIA_ITEMS is available.

public boolean isCommandAvailable(int command)

Returns whether the provided Player.Command is available.

This method does not execute the command.

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.

Returns:

The currently available Player.Commands.

See also: Player.Listener

public void prepare()

Prepares the player.

This method must only be called if Player.COMMAND_PREPARE is available.

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 Player.PlaybackSuppressionReason.

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).

This method must only be called if Player.COMMAND_PLAY_PAUSE is available.

public void pause()

Pauses playback. Equivalent to setPlayWhenReady(false).

This method must only be called if Player.COMMAND_PLAY_PAUSE is available.

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.

This method must only be called if Player.COMMAND_PLAY_PAUSE is available.

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.

This method must only be called if Player.COMMAND_SET_REPEAT_MODE is available.

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.

This method must only be called if Player.COMMAND_SET_SHUFFLE_MODE is available.

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.

This method must only be called if Player.COMMAND_SEEK_TO_DEFAULT_POSITION is available.

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.

This method must only be called if Player.COMMAND_SEEK_TO_MEDIA_ITEM is available.

Parameters:

mediaItemIndex: The index of the MediaItem whose associated default position should be seeked to. If the index is larger than the size of the playlist, the request is ignored.

public void seekTo(long positionMs)

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

This method must only be called if Player.COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM is available.

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.

This method must only be called if Player.COMMAND_SEEK_TO_MEDIA_ITEM is available.

Parameters:

mediaItemIndex: The index of the MediaItem. If the index is larger than the size of the playlist, the request is ignored.
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.

This method must only be called if Player.COMMAND_SEEK_BACK is available.

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.

This method must only be called if Player.COMMAND_SEEK_FORWARD is available.

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.

This method must only be called if Player.COMMAND_GET_TIMELINE is available.

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.

This method must only be called if Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM is available.

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:

This method must only be called if Player.COMMAND_SEEK_TO_PREVIOUS is available.

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.

This method must only be called if Player.COMMAND_GET_TIMELINE is available.

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.

This method must only be called if Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM is available.

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.

This method must only be called if Player.COMMAND_SEEK_TO_NEXT is available.

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.

This method must only be called if Player.COMMAND_SET_SPEED_AND_PITCH is available.

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)).

This method must only be called if Player.COMMAND_SET_SPEED_AND_PITCH is available.

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.

This method must only be called if Player.COMMAND_STOP is available.

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.

This method must only be called if Player.COMMAND_RELEASE is available.

public Tracks getCurrentTracks()

Returns the current tracks.

This method must only be called if Player.COMMAND_GET_TRACKS is available.

See also: Player.Listener.onTracksChanged(Tracks)

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())
 

This method must only be called if Player.COMMAND_SET_TRACK_SELECTION_PARAMETERS is available.

public MediaMetadata getMediaMetadata()

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

This MediaMetadata is a combination of the MediaItem metadata, the static metadata in the media's Format, and any timed metadata that has been parsed from the media and output via 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 timed metadata.

This method must only be called if Player.COMMAND_GET_METADATA is available.

See also: Player.Listener.onMediaMetadataChanged(MediaMetadata)

public MediaMetadata getPlaylistMetadata()

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

This method must only be called if Player.COMMAND_GET_METADATA is available.

See also: Player.Listener.onPlaylistMetadataChanged(MediaMetadata)

public void setPlaylistMetadata(MediaMetadata mediaMetadata)

Sets the playlist MediaMetadata.

This method must only be called if Player.COMMAND_SET_PLAYLIST_METADATA is available.

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.

This method must only be called if Player.COMMAND_GET_TIMELINE is available.

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

public int getCurrentPeriodIndex()

Returns the index of the period currently being played.

This method must only be called if Player.COMMAND_GET_TIMELINE is available.

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.

This method must only be called if Player.COMMAND_GET_TIMELINE is available.

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.

This method must only be called if Player.COMMAND_GET_TIMELINE is available.

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.

This method must only be called if Player.COMMAND_GET_TIMELINE is available.

public MediaItem getCurrentMediaItem()

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

This method must only be called if Player.COMMAND_GET_CURRENT_MEDIA_ITEM is available.

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

public int getMediaItemCount()

Returns the number of media items in the playlist.

This method must only be called if Player.COMMAND_GET_TIMELINE is available.

public MediaItem getMediaItemAt(int index)

Returns the MediaItem at the given index.

This method must only be called if Player.COMMAND_GET_TIMELINE is available.

public long getDuration()

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

This method must only be called if Player.COMMAND_GET_CURRENT_MEDIA_ITEM is available.

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.

This method must only be called if Player.COMMAND_GET_CURRENT_MEDIA_ITEM is available.

public long getBufferedPosition()

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

This method must only be called if Player.COMMAND_GET_CURRENT_MEDIA_ITEM is available.

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.

This method must only be called if Player.COMMAND_GET_CURRENT_MEDIA_ITEM is available.

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.

This method must only be called if Player.COMMAND_GET_CURRENT_MEDIA_ITEM is available.

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.

This method must only be called if Player.COMMAND_GET_CURRENT_MEDIA_ITEM is available.

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 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.

This method must only be called if Player.COMMAND_GET_CURRENT_MEDIA_ITEM is available.

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.

This method must only be called if Player.COMMAND_GET_CURRENT_MEDIA_ITEM is available.

See also: Timeline.Window.isSeekable

public boolean isPlayingAd()

Returns whether the player is currently playing an ad.

This method must only be called if Player.COMMAND_GET_CURRENT_MEDIA_ITEM is available.

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.

This method must only be called if Player.COMMAND_GET_CURRENT_MEDIA_ITEM is available.

public int getCurrentAdIndexInAdGroup()

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

This method must only be called if Player.COMMAND_GET_CURRENT_MEDIA_ITEM is available.

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().

This method must only be called if Player.COMMAND_GET_CURRENT_MEDIA_ITEM is available.

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().

This method must only be called if Player.COMMAND_GET_CURRENT_MEDIA_ITEM is available.

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().

This method must only be called if Player.COMMAND_GET_CURRENT_MEDIA_ITEM is available.

public AudioAttributes getAudioAttributes()

Returns the attributes for audio playback.

This method must only be called if Player.COMMAND_GET_AUDIO_ATTRIBUTES is available.

See also: Player.Listener.onAudioAttributesChanged(AudioAttributes)

public void setVolume(float volume)

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

This method must only be called if Player.COMMAND_SET_VOLUME is available.

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).

This method must only be called if Player.COMMAND_GET_VOLUME is available.

Returns:

The linear gain applied to all audio channels.

See also: Player.Listener.onVolumeChanged(float)

public void clearVideoSurface()

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

This method must only be called if Player.COMMAND_SET_VIDEO_SURFACE is available.

public void clearVideoSurface(Surface surface)

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

This method must only be called if Player.COMMAND_SET_VIDEO_SURFACE is available.

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.

This method must only be called if Player.COMMAND_SET_VIDEO_SURFACE is available.

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().

This method must only be called if Player.COMMAND_SET_VIDEO_SURFACE is available.

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.

This method must only be called if Player.COMMAND_SET_VIDEO_SURFACE is available.

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().

This method must only be called if Player.COMMAND_SET_VIDEO_SURFACE is available.

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.

This method must only be called if Player.COMMAND_SET_VIDEO_SURFACE is available.

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.

Consider using via Player.setVideoSurfaceView(SurfaceView) instead of TextureView. generally causes lower battery consumption, and has better handling for HDR and secure content. See Choosing a surface type for more information.

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

This method must only be called if Player.COMMAND_SET_VIDEO_SURFACE is available.

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.

This method must only be called if Player.COMMAND_SET_VIDEO_SURFACE is available.

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 supported video track or its size has not been determined yet.

See also: Player.Listener.onVideoSizeChanged(VideoSize)

public Size getSurfaceSize()

Gets the size of the surface on which the video is rendered.

See also: Player.Listener.onSurfaceSizeChanged(int, int)

public CueGroup getCurrentCues()

Returns the current CueGroup.

This method must only be called if Player.COMMAND_GET_TEXT is available.

See also: Player.Listener.onCues(CueGroup)

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.

Note that this method returns the volume of the device. To check the current stream volume, use Player.getVolume().

This method must only be called if Player.COMMAND_GET_DEVICE_VOLUME is available.

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

public boolean isDeviceMuted()

Gets whether the device is muted or not.

Note that this method returns the mute state of the device. To check if the current stream is muted, use getVolume() == 0.

This method must only be called if Player.COMMAND_GET_DEVICE_VOLUME is available.

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

public void setDeviceVolume(int volume)

Deprecated: Use Player.setDeviceVolume(int, int) instead.

public void setDeviceVolume(int volume, int flags)

Sets the volume of the device with volume flags.

Note that this method affects the device volume. To change the volume of the current stream only, use Player.setVolume(float).

This method must only be called if Player.COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS is available.

Parameters:

volume: The volume to set.
flags: Either 0 or a bitwise combination of one or more C.VolumeFlags.

public void increaseDeviceVolume()

Deprecated: Use Player.increaseDeviceVolume(int) instead.

public void increaseDeviceVolume(int flags)

Increases the volume of the device.

The Player.getDeviceVolume() device volume cannot be increased above DeviceInfo.maxVolume, if defined.

Note that this method affects the device volume. To change the volume of the current stream only, use Player.setVolume(float).

This method must only be called if Player.COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS is available.

Parameters:

flags: Either 0 or a bitwise combination of one or more C.VolumeFlags.

public void decreaseDeviceVolume()

Deprecated: Use Player.decreaseDeviceVolume(int) instead.

public void decreaseDeviceVolume(int flags)

Decreases the volume of the device.

The Player.getDeviceVolume() device volume cannot be decreased below DeviceInfo.minVolume.

Note that this method affects the device volume. To change the volume of the current stream only, use Player.setVolume(float).

This method must only be called if Player.COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS is available.

Parameters:

flags: Either 0 or a bitwise combination of one or more C.VolumeFlags.

public void setDeviceMuted(boolean muted)

Deprecated: Use Player.setDeviceMuted(boolean, int) instead.

public void setDeviceMuted(boolean muted, int flags)

Sets the mute state of the device.

Note that this method affects the device volume. To mute just the current stream, use setVolume(0) instead.

This method must only be called if Player.COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS is available.

Parameters:

muted: Whether to set the device to be muted or not
flags: Either 0 or a bitwise combination of one or more C.VolumeFlags.

public void setAudioAttributes(AudioAttributes audioAttributes, boolean handleAudioFocus)

Sets the attributes for audio playback, used by the underlying audio track. If not set, the default audio attributes will be used. They are suitable for general media playback.

Setting the audio attributes during playback may introduce a short gap in audio output as the audio track is recreated. A new audio session id will also be generated.

If tunneling is enabled by the track selector, the specified audio attributes will be ignored, but they will take effect if audio is later played without tunneling.

If the device is running a build before platform API version 21, audio attributes cannot be set directly on the underlying audio track. In this case, the usage will be mapped onto an equivalent stream type using Util.getStreamTypeForAudioUsage(int).

If audio focus should be handled, the AudioAttributes.usage must be C.USAGE_MEDIA or C.USAGE_GAME. Other usages will throw an java.lang.IllegalArgumentException.

This method must only be called if Player.COMMAND_SET_AUDIO_ATTRIBUTES is available.

Parameters:

audioAttributes: The attributes to use for audio playback.
handleAudioFocus: True if the player should handle audio focus, false otherwise.

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.annotation.VisibleForTesting;
import androidx.media3.common.text.Cue;
import androidx.media3.common.text.CueGroup;
import androidx.media3.common.util.Size;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import com.google.common.base.Objects;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
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 high-level functionality, such as the ability to play, pause,
 * seek and query properties of the currently playing media.
 *
 * <h2>Player features and usage</h2>
 *
 * <p>Some important properties of media players that implement this interface are:
 *
 * <ul>
 *   <li>All methods must be called from a single {@linkplain #getApplicationLooper() application
 *       thread} unless indicated otherwise. Callbacks in registered listeners are called on the
 *       same thread.
 *   <li>The available functionality can be limited. Player instances provide a set of {@link
 *       #getAvailableCommands() available commands} to signal feature support and users of the
 *       interface must only call methods if the corresponding {@link Command} is available.
 *   <li>Users can register {@link Player.Listener} callbacks that get informed about state changes.
 *   <li>Player instances need to update the visible state immediately after each method call, even
 *       if the actual changes are handled on background threads or even other devices. This
 *       simplifies the usage for callers of methods as no asynchronous handling needs to be
 *       considered.
 *   <li>Player instances can provide playlist operations, like 'set', 'add', 'remove', 'move' or
 *       'replace' of {@link MediaItem} instances. The player can also support {@linkplain
 *       RepeatMode repeat modes} and shuffling within this playlist. The player provides a {@link
 *       Timeline} representing the structure of the playlist and all its items, which can be
 *       obtained by calling {@link #getCurrentTimeline()}
 *   <li>Player instances can provide seeking within the currently playing item and to other items,
 *       using the various {@code seek...} methods.
 *   <li>Player instances can provide {@link Tracks} defining the currently available and selected
 *       tracks, which can be obtained by calling {@link #getCurrentTracks()}. Users can also modify
 *       track selection behavior by setting {@link TrackSelectionParameters} with {@link
 *       #setTrackSelectionParameters}.
 *   <li>Player instances can provide {@link MediaMetadata} about the currently playing item, which
 *       can be obtained by calling {@link #getMediaMetadata()}.
 *   <li>Player instances can provide information about ads in its media structure, for example via
 *       {@link #isPlayingAd()}.
 *   <li>Player instances can accept different types of video outputs, like {@link
 *       #setVideoSurfaceView SurfaceView} or {@link #setVideoTextureView TextureView} for video
 *       rendering.
 *   <li>Player instances can handle {@linkplain #setPlaybackSpeed playback speed}, {@linkplain
 *       #getAudioAttributes audio attributes}, and {@linkplain #setVolume audio volume}.
 *   <li>Player instances can provide information about the {@linkplain #getDeviceInfo playback
 *       device}, which may be remote, and allow to change the device's volume.
 * </ul>
 *
 * <h2>API stability guarantees</h2>
 *
 * <p>The majority of the Player interface and its related classes are part of the stable API that
 * guarantees backwards-compatibility for users of the API. Only more advances use cases may need to
 * rely on {@link UnstableApi} classes and methods that are subject to incompatible changes or even
 * removal in a future release. Implementors of the Player interface are not covered by these API
 * stability guarantees.
 *
 * <h2>Player state</h2>
 *
 * <p>Users can listen to state changes by adding a {@link Player.Listener} with {@link
 * #addListener}.
 *
 * <p>The main elements of the overall player state are:
 *
 * <ul>
 *   <li>Playlist
 *       <ul>
 *         <li>{@link MediaItem} instances can be added with methods like {@link #setMediaItem} to
 *             define what the player will be playing.
 *         <li>The current playlist can be obtained via {@link #getCurrentTimeline} and convenience
 *             methods like {@link #getMediaItemCount} or {@link #getCurrentMediaItem}.
 *         <li>With an empty playlist, the player can only be in {@link #STATE_IDLE} or {@link
 *             #STATE_ENDED}.
 *       </ul>
 *   <li>Playback state
 *       <ul>
 *         <li>{@link #STATE_IDLE}: This is the initial state, the state when the player is
 *             {@linkplain #stop stopped}, and when playback {@linkplain #getPlayerError failed}.
 *             The player will hold only limited resources in this state. {@link #prepare} must be
 *             called to transition away from this state.
 *         <li>{@link #STATE_BUFFERING}: The player is not able to immediately play from its current
 *             position. This mostly happens because more data needs to be loaded.
 *         <li>{@link #STATE_READY}: The player is able to immediately play from its current
 *             position.
 *         <li>{@link #STATE_ENDED}: The player finished playing all media, or there is no media to
 *             play.
 *       </ul>
 *   <li>Play/Pause, playback suppression and isPlaying
 *       <ul>
 *         <li>{@linkplain #getPlayWhenReady() playWhenReady}: Indicates the user intention to play.
 *             It can be set with {@link #play} or {@link #pause}.
 *         <li>{@linkplain #getPlaybackSuppressionReason() playback suppression}: Defines a reason
 *             for which playback will be suppressed even if {@linkplain #getPlayWhenReady()
 *             playWhenReady} is {@code true}.
 *         <li>{@link #isPlaying()}: Whether the player is playing (that is, its position is
 *             advancing and media is being presented). This will only be {@code true} if playback
 *             state is {@link #STATE_READY}, {@linkplain #getPlayWhenReady() playWhenReady} is
 *             {@code true}, and playback is not suppressed.
 *       </ul>
 *   <li>Playback position
 *       <ul>
 *         <li>{@linkplain #getCurrentMediaItemIndex() media item index}: The index in the playlist.
 *         <li>{@linkplain #isPlayingAd() ad insertion}: Whether an inserted ad is playing and which
 *             {@linkplain #getCurrentAdGroupIndex() ad group index} and {@linkplain
 *             #getCurrentAdIndexInAdGroup() ad index in the group} it belongs to
 *         <li>{@linkplain #getCurrentPosition() current position}: The current position of the
 *             playback. This is the same as the {@linkplain #getContentPosition() content position}
 *             unless an ad is playing, where this indicates the position in the inserted ad.
 *       </ul>
 * </ul>
 *
 * <p>Note that there are no callbacks for normal playback progression, only for {@linkplain
 * Listener#onMediaItemTransition transitions between media items} and other {@linkplain
 * Listener#onPositionDiscontinuity position discontinuities}. Code that needs to monitor playback
 * progress (for example, an UI progress bar) should query the current position in appropriate
 * intervals.
 *
 * <h2>Implementing the Player interface</h2>
 *
 * <p>Implementing the Player interface is complex, as the interface includes many convenience
 * methods that need to provide a consistent state and behavior, requires correct handling of
 * listeners and available commands, and expects immediate state changes even if methods are
 * internally handled asynchronously. For this reason, implementations are advised to inherit {@link
 * SimpleBasePlayer} that handles all of these complexities and provides a simpler integration point
 * for implementors of the interface.
 */
public interface Player {

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

    private final FlagSet flags;

    /**
     * Creates an instance.
     *
     * @param flags The {@link FlagSet} containing the {@linkplain 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 {@linkplain Event events} occurred.
     *
     * @param events The {@linkplain Event events}.
     * @return Whether any of the {@linkplain 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 {

    /**
     * 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
    @SuppressWarnings("deprecation") // Setting deprecated windowIndex field
    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 equalsForBundling(that)
          && Objects.equal(windowUid, that.windowUid)
          && Objects.equal(periodUid, that.periodUid);
    }

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

    /**
     * Returns whether this position info and the other position info would result in the same
     * {@link #toBundle() Bundle}.
     */
    @UnstableApi
    public boolean equalsForBundling(PositionInfo other) {
      return mediaItemIndex == other.mediaItemIndex
          && periodIndex == other.periodIndex
          && positionMs == other.positionMs
          && contentPositionMs == other.contentPositionMs
          && adGroupIndex == other.adGroupIndex
          && adIndexInAdGroup == other.adIndexInAdGroup
          && Objects.equal(mediaItem, other.mediaItem);
    }

    @VisibleForTesting static final String FIELD_MEDIA_ITEM_INDEX = Util.intToStringMaxRadix(0);
    private static final String FIELD_MEDIA_ITEM = Util.intToStringMaxRadix(1);
    @VisibleForTesting static final String FIELD_PERIOD_INDEX = Util.intToStringMaxRadix(2);
    @VisibleForTesting static final String FIELD_POSITION_MS = Util.intToStringMaxRadix(3);
    @VisibleForTesting static final String FIELD_CONTENT_POSITION_MS = Util.intToStringMaxRadix(4);
    private static final String FIELD_AD_GROUP_INDEX = Util.intToStringMaxRadix(5);
    private static final String FIELD_AD_INDEX_IN_AD_GROUP = Util.intToStringMaxRadix(6);

    /**
     * Returns a copy of this position info, filtered by the specified available commands.
     *
     * <p>The filtered fields are reset to their default values.
     *
     * <p>The return value may be the same object if nothing is filtered.
     *
     * @param canAccessCurrentMediaItem Whether {@link Player#COMMAND_GET_CURRENT_MEDIA_ITEM} is
     *     available.
     * @param canAccessTimeline Whether {@link Player#COMMAND_GET_TIMELINE} is available.
     * @return The filtered position info.
     */
    @UnstableApi
    public PositionInfo filterByAvailableCommands(
        boolean canAccessCurrentMediaItem, boolean canAccessTimeline) {
      if (canAccessCurrentMediaItem && canAccessTimeline) {
        return this;
      }
      return new PositionInfo(
          windowUid,
          canAccessTimeline ? mediaItemIndex : 0,
          canAccessCurrentMediaItem ? mediaItem : null,
          periodUid,
          canAccessTimeline ? periodIndex : 0,
          canAccessCurrentMediaItem ? positionMs : 0,
          canAccessCurrentMediaItem ? contentPositionMs : 0,
          canAccessCurrentMediaItem ? adGroupIndex : C.INDEX_UNSET,
          canAccessCurrentMediaItem ? adIndexInAdGroup : C.INDEX_UNSET);
    }

    /**
     * Returns a {@link Bundle} representing the information stored in this object.
     *
     * <p>It omits the {@link #windowUid} and {@link #periodUid} fields. The {@link #windowUid} and
     * {@link #periodUid} of an instance restored by {@link #fromBundle(Bundle)} will always be
     * {@code null}.
     *
     * @param controllerInterfaceVersion The interface version of the media controller this Bundle
     *     will be sent to.
     */
    @UnstableApi
    public Bundle toBundle(int controllerInterfaceVersion) {
      Bundle bundle = new Bundle();
      if (controllerInterfaceVersion < 3 || mediaItemIndex != 0) {
        bundle.putInt(FIELD_MEDIA_ITEM_INDEX, mediaItemIndex);
      }
      if (mediaItem != null) {
        bundle.putBundle(FIELD_MEDIA_ITEM, mediaItem.toBundle());
      }
      if (controllerInterfaceVersion < 3 || periodIndex != 0) {
        bundle.putInt(FIELD_PERIOD_INDEX, periodIndex);
      }
      if (controllerInterfaceVersion < 3 || positionMs != 0) {
        bundle.putLong(FIELD_POSITION_MS, positionMs);
      }
      if (controllerInterfaceVersion < 3 || contentPositionMs != 0) {
        bundle.putLong(FIELD_CONTENT_POSITION_MS, contentPositionMs);
      }
      if (adGroupIndex != C.INDEX_UNSET) {
        bundle.putInt(FIELD_AD_GROUP_INDEX, adGroupIndex);
      }
      if (adIndexInAdGroup != C.INDEX_UNSET) {
        bundle.putInt(FIELD_AD_INDEX_IN_AD_GROUP, adIndexInAdGroup);
      }
      return bundle;
    }

    /**
     * @deprecated Use {@link #toBundle(int)} instead.
     */
    @UnstableApi
    @Deprecated
    public Bundle toBundle() {
      return toBundle(Integer.MAX_VALUE);
    }

    /** Restores a {@code PositionInfo} from a {@link Bundle}. */
    @UnstableApi
    public static PositionInfo fromBundle(Bundle bundle) {
      int mediaItemIndex = bundle.getInt(FIELD_MEDIA_ITEM_INDEX, /* defaultValue= */ 0);
      @Nullable Bundle mediaItemBundle = bundle.getBundle(FIELD_MEDIA_ITEM);
      @Nullable
      MediaItem mediaItem = mediaItemBundle == null ? null : MediaItem.fromBundle(mediaItemBundle);
      int periodIndex = bundle.getInt(FIELD_PERIOD_INDEX, /* defaultValue= */ 0);
      long positionMs = bundle.getLong(FIELD_POSITION_MS, /* defaultValue= */ 0);
      long contentPositionMs = bundle.getLong(FIELD_CONTENT_POSITION_MS, /* defaultValue= */ 0);
      int adGroupIndex = bundle.getInt(FIELD_AD_GROUP_INDEX, /* defaultValue= */ C.INDEX_UNSET);
      int adIndexInAdGroup =
          bundle.getInt(FIELD_AD_INDEX_IN_AD_GROUP, /* defaultValue= */ C.INDEX_UNSET);
      return new PositionInfo(
          /* windowUid= */ null,
          mediaItemIndex,
          mediaItem,
          /* periodUid= */ null,
          periodIndex,
          positionMs,
          contentPositionMs,
          adGroupIndex,
          adIndexInAdGroup);
    }
  }

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

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

      @SuppressWarnings("deprecation") // Includes deprecated commands
      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_METADATA,
        COMMAND_SET_PLAYLIST_METADATA,
        COMMAND_SET_MEDIA_ITEM,
        COMMAND_CHANGE_MEDIA_ITEMS,
        COMMAND_GET_AUDIO_ATTRIBUTES,
        COMMAND_GET_VOLUME,
        COMMAND_GET_DEVICE_VOLUME,
        COMMAND_SET_VOLUME,
        COMMAND_SET_DEVICE_VOLUME,
        COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS,
        COMMAND_ADJUST_DEVICE_VOLUME,
        COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS,
        COMMAND_SET_AUDIO_ATTRIBUTES,
        COMMAND_SET_VIDEO_SURFACE,
        COMMAND_GET_TEXT,
        COMMAND_SET_TRACK_SELECTION_PARAMETERS,
        COMMAND_GET_TRACKS,
        COMMAND_RELEASE
      };

      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.
       */
      @CanIgnoreReturnValue
      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.
       */
      @CanIgnoreReturnValue
      public Builder addIf(@Command int command, boolean condition) {
        flagsBuilder.addIf(command, condition);
        return this;
      }

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

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

      /**
       * Adds all existing {@linkplain Command commands}.
       *
       * @return This builder.
       * @throws IllegalStateException If {@link #build()} has already been called.
       */
      @CanIgnoreReturnValue
      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.
       */
      @CanIgnoreReturnValue
      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.
       */
      @CanIgnoreReturnValue
      public Builder removeIf(@Command int command, boolean condition) {
        flagsBuilder.removeIf(command, condition);
        return this;
      }

      /**
       * Removes {@linkplain Command commands}.
       *
       * @param commands The {@linkplain Command commands} to remove.
       * @return This builder.
       * @throws IllegalStateException If {@link #build()} has already been called.
       */
      @CanIgnoreReturnValue
      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 whether the set of commands contains at least one of the given {@code commands}. */
    public boolean containsAny(@Command int... commands) {
      return flags.containsAny(commands);
    }

    /** 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();
    }

    private static final String FIELD_COMMANDS = Util.intToStringMaxRadix(0);

    @UnstableApi
    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(FIELD_COMMANDS, commandsBundle);
      return bundle;
    }

    /** Restores a {@code Commands} from a {@link Bundle}. */
    @UnstableApi
    public static Commands fromBundle(Bundle bundle) {
      @Nullable ArrayList<Integer> commands = bundle.getIntegerArrayList(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();
    }
  }

  /**
   * Listener for changes in a {@link Player}.
   *
   * <p>All methods have no-op default implementations to allow selective overrides.
   *
   * <p>If the return value of a {@link Player} getter changes due to a change in {@linkplain
   * #onAvailableCommandsChanged(Commands) command availability}, the corresponding listener
   * method(s) will be invoked. If the return value of a {@link Player} getter does not change
   * because the corresponding command is {@linkplain #onAvailableCommandsChanged(Commands) not
   * available}, the corresponding listener method will not be invoked.
   */
  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>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 value of {@link Player#getCurrentTimeline()} changes.
     *
     * <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 value of {@link #getCurrentTimeline()}
     * becomes non-empty or empty.
     *
     * <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 value of {@link Player#getCurrentTracks()} 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 tracks The available tracks information. Never null, but may be of length zero.
     */
    default void onTracksChanged(Tracks tracks) {}

    /**
     * Called when the value of {@link Player#getMediaMetadata()} changes.
     *
     * <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 value of {@link Player#getPlaylistMetadata()} 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}.
     */
    default void onPlaybackStateChanged(@State int playbackState) {}

    /**
     * Called when the value returned from {@link #getPlayWhenReady()} changes.
     *
     * <p>The current {@code playWhenReady} value may be re-reported if the {@code reason} for this
     * value 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} 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 {@linkplain 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 value of {@link #getPlaybackParameters()} changes. 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) {}

    /**
     * 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 value of {@link #getAudioAttributes()} 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 audioAttributes The audio attributes.
     */
    default void onAudioAttributesChanged(AudioAttributes audioAttributes) {}

    /**
     * Called when the value of {@link #getVolume()} 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 value of {@link #getDeviceVolume()} or {@link #isDeviceMuted()} 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 when {@link Player#getVideoSize()} 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 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 the value of {@link #getCurrentCues()} changes.
     *
     * <p>Both this method and {@link #onCues(CueGroup)} are called when there is a change in the
     * cues. You should only implement one or the other.
     *
     * <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.
     *
     * @deprecated Use {@link #onCues(CueGroup)} instead.
     */
    @Deprecated
    @UnstableApi
    default void onCues(List<Cue> cues) {}

    /**
     * Called when the value of {@link #getCurrentCues()} changes.
     *
     * <p>Both this method and {@link #onCues(List)} are called when there is a change in the cues.
     * You should only implement one or the other.
     *
     * <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 onCues(CueGroup cueGroup) {}

    /**
     * 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}, {@link
   * #PLAY_WHEN_READY_CHANGE_REASON_END_OF_MEDIA_ITEM} or {@link
   * #PLAY_WHEN_READY_CHANGE_REASON_SUPPRESSED_TOO_LONG}.
   */
  // @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,
    PLAY_WHEN_READY_CHANGE_REASON_SUPPRESSED_TOO_LONG
  })
  @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;

  /**
   * Playback has been paused because playback has been {@linkplain #getPlaybackSuppressionReason()
   * suppressed} too long.
   */
  int PLAY_WHEN_READY_CHANGE_REASON_SUPPRESSED_TOO_LONG = 6;

  /**
   * Reason why playback is suppressed even though {@link #getPlayWhenReady()} is {@code true}. One
   * of {@link #PLAYBACK_SUPPRESSION_REASON_NONE}, {@link
   * #PLAYBACK_SUPPRESSION_REASON_TRANSIENT_AUDIO_FOCUS_LOSS}, {@link
   * #PLAYBACK_SUPPRESSION_REASON_UNSUITABLE_AUDIO_ROUTE} or {@link
   * #PLAYBACK_SUPPRESSION_REASON_UNSUITABLE_AUDIO_OUTPUT}.
   */
  // @Target list includes both 'default' targets and TYPE_USE, to ensure backwards compatibility
  // with Kotlin usages from before TYPE_USE was added.
  @SuppressWarnings("deprecation") // Includes deprecated command
  @Documented
  @Retention(RetentionPolicy.SOURCE)
  @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
  @IntDef({
    PLAYBACK_SUPPRESSION_REASON_NONE,
    PLAYBACK_SUPPRESSION_REASON_TRANSIENT_AUDIO_FOCUS_LOSS,
    PLAYBACK_SUPPRESSION_REASON_UNSUITABLE_AUDIO_ROUTE,
    PLAYBACK_SUPPRESSION_REASON_UNSUITABLE_AUDIO_OUTPUT
  })
  @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;

  /**
   * @deprecated Use {@link #PLAYBACK_SUPPRESSION_REASON_UNSUITABLE_AUDIO_OUTPUT} instead.
   */
  @Deprecated int PLAYBACK_SUPPRESSION_REASON_UNSUITABLE_AUDIO_ROUTE = 2;

  /**
   * Playback is suppressed due to attempt to play on an unsuitable audio output (e.g. attempt to
   * play on built-in speaker on a Wear OS device).
   */
  int PLAYBACK_SUPPRESSION_REASON_UNSUITABLE_AUDIO_OUTPUT = 3;

  /**
   * 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,
    DISCONTINUITY_REASON_SILENCE_SKIP
  })
  @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;

  /** Discontinuity introduced by a skipped silence. */
  int DISCONTINUITY_REASON_SILENCE_SKIP = 6;

  /**
   * 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 #getCurrentTracks()} 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 indicate which method calls are currently permitted on a particular {@code
   * Player} instance.
   *
   * <p>The currently available commands can be inspected with {@link #getAvailableCommands()} and
   * {@link #isCommandAvailable(int)}.
   *
   * <p>See the documentation of each command constant for the details of which methods it permits
   * calling.
   *
   * <p>One of the following values:
   *
   * <ul>
   *   <li>{@link #COMMAND_PLAY_PAUSE}
   *   <li>{@link #COMMAND_PREPARE}
   *   <li>{@link #COMMAND_STOP}
   *   <li>{@link #COMMAND_SEEK_TO_DEFAULT_POSITION}
   *   <li>{@link #COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM}
   *   <li>{@link #COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM}
   *   <li>{@link #COMMAND_SEEK_TO_PREVIOUS}
   *   <li>{@link #COMMAND_SEEK_TO_NEXT_MEDIA_ITEM}
   *   <li>{@link #COMMAND_SEEK_TO_NEXT}
   *   <li>{@link #COMMAND_SEEK_TO_MEDIA_ITEM}
   *   <li>{@link #COMMAND_SEEK_BACK}
   *   <li>{@link #COMMAND_SEEK_FORWARD}
   *   <li>{@link #COMMAND_SET_SPEED_AND_PITCH}
   *   <li>{@link #COMMAND_SET_SHUFFLE_MODE}
   *   <li>{@link #COMMAND_SET_REPEAT_MODE}
   *   <li>{@link #COMMAND_GET_CURRENT_MEDIA_ITEM}
   *   <li>{@link #COMMAND_GET_TIMELINE}
   *   <li>{@link #COMMAND_GET_METADATA}
   *   <li>{@link #COMMAND_SET_PLAYLIST_METADATA}
   *   <li>{@link #COMMAND_SET_MEDIA_ITEM}
   *   <li>{@link #COMMAND_CHANGE_MEDIA_ITEMS}
   *   <li>{@link #COMMAND_GET_AUDIO_ATTRIBUTES}
   *   <li>{@link #COMMAND_GET_VOLUME}
   *   <li>{@link #COMMAND_GET_DEVICE_VOLUME}
   *   <li>{@link #COMMAND_SET_VOLUME}
   *   <li>{@link #COMMAND_SET_DEVICE_VOLUME}
   *   <li>{@link #COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS}
   *   <li>{@link #COMMAND_ADJUST_DEVICE_VOLUME}
   *   <li>{@link #COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS}
   *   <li>{@link #COMMAND_SET_AUDIO_ATTRIBUTES}
   *   <li>{@link #COMMAND_SET_VIDEO_SURFACE}
   *   <li>{@link #COMMAND_GET_TEXT}
   *   <li>{@link #COMMAND_SET_TRACK_SELECTION_PARAMETERS}
   *   <li>{@link #COMMAND_GET_TRACKS}
   *   <li>{@link #COMMAND_RELEASE}
   * </ul>
   */
  // @Target list includes both 'default' targets and TYPE_USE, to ensure backwards compatibility
  // with Kotlin usages from before TYPE_USE was added.
  @SuppressWarnings("deprecation") // Listing deprecated constants.
  @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_GET_METADATA,
    COMMAND_SET_MEDIA_ITEMS_METADATA,
    COMMAND_SET_PLAYLIST_METADATA,
    COMMAND_SET_MEDIA_ITEM,
    COMMAND_CHANGE_MEDIA_ITEMS,
    COMMAND_GET_AUDIO_ATTRIBUTES,
    COMMAND_GET_VOLUME,
    COMMAND_GET_DEVICE_VOLUME,
    COMMAND_SET_VOLUME,
    COMMAND_SET_DEVICE_VOLUME,
    COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS,
    COMMAND_ADJUST_DEVICE_VOLUME,
    COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS,
    COMMAND_SET_AUDIO_ATTRIBUTES,
    COMMAND_SET_VIDEO_SURFACE,
    COMMAND_GET_TEXT,
    COMMAND_SET_TRACK_SELECTION_PARAMETERS,
    COMMAND_GET_TRACKS,
    COMMAND_RELEASE,
  })
  @interface Command {}

  /**
   * Command to start, pause or resume playback.
   *
   * <p>The following methods must only be called if this command is {@linkplain
   * #isCommandAvailable(int) available}:
   *
   * <ul>
   *   <li>{@link #play()}
   *   <li>{@link #pause()}
   *   <li>{@link #setPlayWhenReady(boolean)}
   * </ul>
   */
  int COMMAND_PLAY_PAUSE = 1;

  /**
   * Command to prepare the player.
   *
   * <p>The {@link #prepare()} method must only be called if this command is {@linkplain
   * #isCommandAvailable(int) available}.
   */
  int COMMAND_PREPARE = 2;

  /**
   * Command to stop playback.
   *
   * <p>The {@link #stop()} method must only be called if this command is {@linkplain
   * #isCommandAvailable(int) available}.
   */
  int COMMAND_STOP = 3;

  /**
   * Command to seek to the default position of the current {@link MediaItem}.
   *
   * <p>The {@link #seekToDefaultPosition()} method must only be called if this command is
   * {@linkplain #isCommandAvailable(int) available}.
   */
  int COMMAND_SEEK_TO_DEFAULT_POSITION = 4;

  /**
   * Command to seek anywhere inside the current {@link MediaItem}.
   *
   * <p>The {@link #seekTo(long)} method must only be called if this command is {@linkplain
   * #isCommandAvailable(int) available}.
   */
  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}.
   *
   * <p>The {@link #seekToPreviousMediaItem()} method must only be called if this command is
   * {@linkplain #isCommandAvailable(int) available}.
   */
  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 {@link MediaItem} or the default position
   * of the previous {@link MediaItem}.
   *
   * <p>The {@link #seekToPrevious()} method must only be called if this command is {@linkplain
   * #isCommandAvailable(int) available}.
   */
  int COMMAND_SEEK_TO_PREVIOUS = 7;

  /**
   * Command to seek to the default position of the next {@link MediaItem}.
   *
   * <p>The {@link #seekToNextMediaItem()} method must only be called if this command is {@linkplain
   * #isCommandAvailable(int) available}.
   */
  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 {@link MediaItem} or the default position of
   * the next {@link MediaItem}.
   *
   * <p>The {@link #seekToNext()} method must only be called if this command is {@linkplain
   * #isCommandAvailable(int) available}.
   */
  int COMMAND_SEEK_TO_NEXT = 9;

  /**
   * Command to seek anywhere in any {@link MediaItem}.
   *
   * <p>The following methods must only be called if this command is {@linkplain
   * #isCommandAvailable(int) available}:
   *
   * <ul>
   *   <li>{@link #seekTo(int, long)}
   *   <li>{@link #seekToDefaultPosition(int)}
   * </ul>
   */
  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 inside the current {@link MediaItem}.
   *
   * <p>The {@link #seekBack()} method must only be called if this command is {@linkplain
   * #isCommandAvailable(int) available}.
   */
  int COMMAND_SEEK_BACK = 11;

  /**
   * Command to seek forward by a fixed increment inside the current {@link MediaItem}.
   *
   * <p>The {@link #seekForward()} method must only be called if this command is {@linkplain
   * #isCommandAvailable(int) available}.
   */
  int COMMAND_SEEK_FORWARD = 12;

  /**
   * Command to set the playback speed and pitch.
   *
   * <p>The following methods must only be called if this command is {@linkplain
   * #isCommandAvailable(int) available}:
   *
   * <ul>
   *   <li>{@link #setPlaybackParameters(PlaybackParameters)}
   *   <li>{@link #setPlaybackSpeed(float)}
   * </ul>
   */
  int COMMAND_SET_SPEED_AND_PITCH = 13;

  /**
   * Command to enable shuffling.
   *
   * <p>The {@link #setShuffleModeEnabled(boolean)} method must only be called if this command is
   * {@linkplain #isCommandAvailable(int) available}.
   */
  int COMMAND_SET_SHUFFLE_MODE = 14;

  /**
   * Command to set the repeat mode.
   *
   * <p>The {@link #setRepeatMode(int)} method must only be called if this command is {@linkplain
   * #isCommandAvailable(int) available}.
   */
  int COMMAND_SET_REPEAT_MODE = 15;

  /**
   * Command to get information about the currently playing {@link MediaItem}.
   *
   * <p>The following methods must only be called if this command is {@linkplain
   * #isCommandAvailable(int) available}:
   *
   * <ul>
   *   <li>{@link #getCurrentMediaItem()}
   *   <li>{@link #isCurrentMediaItemDynamic()}
   *   <li>{@link #isCurrentMediaItemLive()}
   *   <li>{@link #isCurrentMediaItemSeekable()}
   *   <li>{@link #getCurrentLiveOffset()}
   *   <li>{@link #getDuration()}
   *   <li>{@link #getCurrentPosition()}
   *   <li>{@link #getBufferedPosition()}
   *   <li>{@link #getContentDuration()}
   *   <li>{@link #getContentPosition()}
   *   <li>{@link #getContentBufferedPosition()}
   *   <li>{@link #getTotalBufferedDuration()}
   *   <li>{@link #isPlayingAd()}
   *   <li>{@link #getCurrentAdGroupIndex()}
   *   <li>{@link #getCurrentAdIndexInAdGroup()}
   * </ul>
   */
  int COMMAND_GET_CURRENT_MEDIA_ITEM = 16;

  /**
   * Command to get the information about the current timeline.
   *
   * <p>The following methods must only be called if this command is {@linkplain
   * #isCommandAvailable(int) available}:
   *
   * <ul>
   *   <li>{@link #getCurrentTimeline()}
   *   <li>{@link #getCurrentMediaItemIndex()}
   *   <li>{@link #getCurrentPeriodIndex()}
   *   <li>{@link #getMediaItemCount()}
   *   <li>{@link #getMediaItemAt(int)}
   *   <li>{@link #getNextMediaItemIndex()}
   *   <li>{@link #getPreviousMediaItemIndex()}
   *   <li>{@link #hasPreviousMediaItem()}
   *   <li>{@link #hasNextMediaItem()}
   * </ul>
   */
  int COMMAND_GET_TIMELINE = 17;

  /**
   * @deprecated Use {@link #COMMAND_GET_METADATA} instead.
   */
  @Deprecated int COMMAND_GET_MEDIA_ITEMS_METADATA = 18;

  /**
   * Command to get metadata related to the playlist and current {@link MediaItem}.
   *
   * <p>The following methods must only be called if this command is {@linkplain
   * #isCommandAvailable(int) available}:
   *
   * <ul>
   *   <li>{@link #getMediaMetadata()}
   *   <li>{@link #getPlaylistMetadata()}
   * </ul>
   */
  int COMMAND_GET_METADATA = 18;

  /**
   * @deprecated Use {@link #COMMAND_SET_PLAYLIST_METADATA} instead.
   */
  @Deprecated int COMMAND_SET_MEDIA_ITEMS_METADATA = 19;

  /**
   * Command to set the playlist metadata.
   *
   * <p>The {@link #setPlaylistMetadata(MediaMetadata)} method must only be called if this command
   * is {@linkplain #isCommandAvailable(int) available}.
   */
  int COMMAND_SET_PLAYLIST_METADATA = 19;

  /**
   * Command to set a {@link MediaItem}.
   *
   * <p>The following methods must only be called if this command is {@linkplain
   * #isCommandAvailable(int) available}:
   *
   * <ul>
   *   <li>{@link #setMediaItem(MediaItem)}
   *   <li>{@link #setMediaItem(MediaItem, boolean)}
   *   <li>{@link #setMediaItem(MediaItem, long)}
   * </ul>
   */
  int COMMAND_SET_MEDIA_ITEM = 31;

  /**
   * Command to change the {@linkplain MediaItem media items} in the playlist.
   *
   * <p>The following methods must only be called if this command is {@linkplain
   * #isCommandAvailable(int) available}:
   *
   * <ul>
   *   <li>{@link #addMediaItem(MediaItem)}
   *   <li>{@link #addMediaItem(int, MediaItem)}
   *   <li>{@link #addMediaItems(List)}
   *   <li>{@link #addMediaItems(int, List)}
   *   <li>{@link #clearMediaItems()}
   *   <li>{@link #moveMediaItem(int, int)}
   *   <li>{@link #moveMediaItems(int, int, int)}
   *   <li>{@link #removeMediaItem(int)}
   *   <li>{@link #removeMediaItems(int, int)}
   *   <li>{@link #setMediaItems(List)}
   *   <li>{@link #setMediaItems(List, boolean)}
   *   <li>{@link #setMediaItems(List, int, long)}
   *   <li>{@link #replaceMediaItem(int, MediaItem)}
   *   <li>{@link #replaceMediaItems(int, int, List)}
   * </ul>
   */
  int COMMAND_CHANGE_MEDIA_ITEMS = 20;

  /**
   * Command to get the player current {@link AudioAttributes}.
   *
   * <p>The {@link #getAudioAttributes()} method must only be called if this command is {@linkplain
   * #isCommandAvailable(int) available}.
   */
  int COMMAND_GET_AUDIO_ATTRIBUTES = 21;

  /**
   * Command to get the player volume.
   *
   * <p>The {@link #getVolume()} method must only be called if this command is {@linkplain
   * #isCommandAvailable(int) available}.
   */
  int COMMAND_GET_VOLUME = 22;

  /**
   * Command to get the device volume and whether it is muted.
   *
   * <p>The following methods must only be called if this command is {@linkplain
   * #isCommandAvailable(int) available}:
   *
   * <ul>
   *   <li>{@link #getDeviceVolume()}
   *   <li>{@link #isDeviceMuted()}
   * </ul>
   */
  int COMMAND_GET_DEVICE_VOLUME = 23;

  /**
   * Command to set the player volume.
   *
   * <p>The {@link #setVolume(float)} method must only be called if this command is {@linkplain
   * #isCommandAvailable(int) available}.
   */
  int COMMAND_SET_VOLUME = 24;

  /**
   * @deprecated Use {@link #COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS} instead.
   */
  @Deprecated int COMMAND_SET_DEVICE_VOLUME = 25;

  /**
   * Command to set the device volume with volume flags.
   *
   * <p>The {@link #setDeviceVolume(int, int)} method must only be called if this command is
   * {@linkplain #isCommandAvailable(int) available}.
   */
  int COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS = 33;

  /**
   * @deprecated Use {@link #COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS} instead.
   */
  @Deprecated int COMMAND_ADJUST_DEVICE_VOLUME = 26;

  /**
   * Command to increase and decrease the device volume and mute it with volume flags.
   *
   * <p>The following methods must only be called if this command is {@linkplain
   * #isCommandAvailable(int) available}:
   *
   * <ul>
   *   <li>{@link #increaseDeviceVolume(int)}
   *   <li>{@link #decreaseDeviceVolume(int)}
   *   <li>{@link #setDeviceMuted(boolean, int)}
   * </ul>
   */
  int COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS = 34;

  /**
   * Command to set the player's audio attributes.
   *
   * <p>The {@link #setAudioAttributes(AudioAttributes, boolean)} method must only be called if this
   * command is {@linkplain #isCommandAvailable(int) available}.
   */
  int COMMAND_SET_AUDIO_ATTRIBUTES = 35;

  /**
   * Command to set and clear the surface on which to render the video.
   *
   * <p>The following methods must only be called if this command is {@linkplain
   * #isCommandAvailable(int) available}:
   *
   * <ul>
   *   <li>{@link #setVideoSurface(Surface)}
   *   <li>{@link #clearVideoSurface()}
   *   <li>{@link #clearVideoSurface(Surface)}
   *   <li>{@link #setVideoSurfaceHolder(SurfaceHolder)}
   *   <li>{@link #clearVideoSurfaceHolder(SurfaceHolder)}
   *   <li>{@link #setVideoSurfaceView(SurfaceView)}
   *   <li>{@link #clearVideoSurfaceView(SurfaceView)}
   * </ul>
   */
  int COMMAND_SET_VIDEO_SURFACE = 27;

  /**
   * Command to get the text that should currently be displayed by the player.
   *
   * <p>The {@link #getCurrentCues()} method must only be called if this command is {@linkplain
   * #isCommandAvailable(int) available}.
   */
  int COMMAND_GET_TEXT = 28;

  /**
   * Command to set the player's track selection parameters.
   *
   * <p>The {@link #setTrackSelectionParameters(TrackSelectionParameters)} method must only be
   * called if this command is {@linkplain #isCommandAvailable(int) available}.
   */
  int COMMAND_SET_TRACK_SELECTION_PARAMETERS = 29;

  /**
   * Command to get details of the current track selection.
   *
   * <p>The {@link #getCurrentTracks()} method must only be called if this command is {@linkplain
   * #isCommandAvailable(int) available}.
   */
  int COMMAND_GET_TRACKS = 30;

  /**
   * Command to release the player.
   *
   * <p>The {@link #release()} method must only be called if this command is {@linkplain
   * #isCommandAvailable(int) available}.
   */
  int COMMAND_RELEASE = 32;

  /** 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.
   *
   * <p>This method can be called from any thread.
   */
  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()}.
   *
   * <p>This method can be called from any thread.
   *
   * @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 {@linkplain MediaItem media items} and resets the
   * position to the default position.
   *
   * <p>To replace a span of media items (possibly seamlessly) without clearing the playlist, use
   * {@link #replaceMediaItems}.
   *
   * <p>This method must only be called if {@link #COMMAND_CHANGE_MEDIA_ITEMS} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @param mediaItems The new {@linkplain MediaItem media items}.
   */
  void setMediaItems(List<MediaItem> mediaItems);

  /**
   * Clears the playlist and adds the specified {@linkplain MediaItem media items}.
   *
   * <p>To replace a span of media items (possibly seamlessly) without clearing the playlist, use
   * {@link #replaceMediaItems}.
   *
   * <p>This method must only be called if {@link #COMMAND_CHANGE_MEDIA_ITEMS} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @param mediaItems The new {@linkplain MediaItem media items}.
   * @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 {@linkplain MediaItem media items}.
   *
   * <p>To replace a span of media items (possibly seamlessly) without clearing the playlist, use
   * {@link #replaceMediaItems}.
   *
   * <p>This method must only be called if {@link #COMMAND_CHANGE_MEDIA_ITEMS} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @param mediaItems The new {@linkplain MediaItem media items}.
   * @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.
   *
   * <p>To replace a media item (possibly seamlessly) without clearing the playlist, use {@link
   * #replaceMediaItem}.
   *
   * <p>This method must only be called if {@link #COMMAND_SET_MEDIA_ITEM} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @param mediaItem The new {@link MediaItem}.
   */
  void setMediaItem(MediaItem mediaItem);

  /**
   * Clears the playlist and adds the specified {@link MediaItem}.
   *
   * <p>To replace a media item (possibly seamlessly) without clearing the playlist, use {@link
   * #replaceMediaItem}.
   *
   * <p>This method must only be called if {@link #COMMAND_SET_MEDIA_ITEM} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @param mediaItem The new {@link MediaItem}.
   * @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.
   */
  void setMediaItem(MediaItem mediaItem, long startPositionMs);

  /**
   * Clears the playlist and adds the specified {@link MediaItem}.
   *
   * <p>To replace a media item (possibly seamlessly) without clearing the playlist, use {@link
   * #replaceMediaItem}.
   *
   * <p>This method must only be called if {@link #COMMAND_SET_MEDIA_ITEM} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @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.
   *
   * <p>This method must only be called if {@link #COMMAND_CHANGE_MEDIA_ITEMS} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @param mediaItem The {@link MediaItem} to add.
   */
  void addMediaItem(MediaItem mediaItem);

  /**
   * Adds a media item at the given index of the playlist.
   *
   * <p>This method must only be called if {@link #COMMAND_CHANGE_MEDIA_ITEMS} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @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.
   *
   * <p>This method must only be called if {@link #COMMAND_CHANGE_MEDIA_ITEMS} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @param mediaItems The {@linkplain MediaItem media items} to add.
   */
  void addMediaItems(List<MediaItem> mediaItems);

  /**
   * Adds a list of media items at the given index of the playlist.
   *
   * <p>This method must only be called if {@link #COMMAND_CHANGE_MEDIA_ITEMS} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @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 {@linkplain MediaItem media items} to add.
   */
  void addMediaItems(int index, List<MediaItem> mediaItems);

  /**
   * Moves the media item at the current index to the new index.
   *
   * <p>This method must only be called if {@link #COMMAND_CHANGE_MEDIA_ITEMS} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @param currentIndex The current index of the media item to move. If the index is larger than
   *     the size of the playlist, the request is ignored.
   * @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.
   *
   * <p>This method must only be called if {@link #COMMAND_CHANGE_MEDIA_ITEMS} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @param fromIndex The start of the range to move. If the index is larger than the size of the
   *     playlist, the request is ignored.
   * @param toIndex The first item not to be included in the range (exclusive). If the index is
   *     larger than the size of the playlist, items up to the end of the playlist are moved.
   * @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);

  /**
   * Replaces the media item at the given index of the playlist.
   *
   * <p>Implementations of this method may attempt to seamlessly continue playback if the currently
   * playing media item is replaced with a compatible one (e.g. same URL, only metadata has
   * changed).
   *
   * <p>This method must only be called if {@link #COMMAND_CHANGE_MEDIA_ITEMS} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @param index The index at which to replace the media item. If the index is larger than the size
   *     of the playlist, the request is ignored.
   * @param mediaItem The new {@link MediaItem}.
   */
  void replaceMediaItem(int index, MediaItem mediaItem);

  /**
   * Replaces the media items at the given range of the playlist.
   *
   * <p>Implementations of this method may attempt to seamlessly continue playback if the currently
   * playing media item is replaced with a compatible one (e.g. same URL, only metadata has
   * changed).
   *
   * <p>This method must only be called if {@link #COMMAND_CHANGE_MEDIA_ITEMS} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * <p>Note that it is possible to replace a range with an arbitrary number of new items, so that
   * the number of removed items defined by {@code fromIndex} and {@code toIndex} does not have to
   * match the number of added items defined by {@code mediaItems}. As result, it may also change
   * the index of subsequent items not touched by this operation.
   *
   * @param fromIndex The start of the range. If the index is larger than the size of the playlist,
   *     the request is ignored.
   * @param toIndex The first item not to be included in the range (exclusive). If the index is
   *     larger than the size of the playlist, items up to the end of the playlist are replaced.
   * @param mediaItems The {@linkplain MediaItem media items} to replace the range with.
   */
  void replaceMediaItems(int fromIndex, int toIndex, List<MediaItem> mediaItems);

  /**
   * Removes the media item at the given index of the playlist.
   *
   * <p>This method must only be called if {@link #COMMAND_CHANGE_MEDIA_ITEMS} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @param index The index at which to remove the media item. If the index is larger than the size
   *     of the playlist, the request is ignored.
   */
  void removeMediaItem(int index);

  /**
   * Removes a range of media items from the playlist.
   *
   * <p>This method must only be called if {@link #COMMAND_CHANGE_MEDIA_ITEMS} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @param fromIndex The index at which to start removing media items. If the index is larger than
   *     the size of the playlist, the request is ignored.
   * @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 up to the end of the playlist are removed.
   */
  void removeMediaItems(int fromIndex, int toIndex);

  /**
   * Clears the playlist.
   *
   * <p>This method must only be called if {@link #COMMAND_CHANGE_MEDIA_ITEMS} is {@linkplain
   * #getAvailableCommands() available}.
   */
  void clearMediaItems();

  /**
   * Returns whether the provided {@link Command} is available.
   *
   * <p>This method does not execute the command.
   *
   * @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.
   *
   * @return The currently available {@link Commands}.
   * @see Listener#onAvailableCommandsChanged(Commands)
   */
  Commands getAvailableCommands();

  /**
   * Prepares the player.
   *
   * <p>This method must only be called if {@link #COMMAND_PREPARE} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * <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 {@linkplain State playback state} of the player.
   *
   * @return The current {@linkplain 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}.
   * @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
   * {@link #setPlayWhenReady(boolean) setPlayWhenReady(true)}.
   *
   * <p>This method must only be called if {@link #COMMAND_PLAY_PAUSE} is {@linkplain
   * #getAvailableCommands() available}.
   */
  void play();

  /**
   * Pauses playback. Equivalent to {@link #setPlayWhenReady(boolean) setPlayWhenReady(false)}.
   *
   * <p>This method must only be called if {@link #COMMAND_PLAY_PAUSE} is {@linkplain
   * #getAvailableCommands() available}.
   */
  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.
   *
   * <p>This method must only be called if {@link #COMMAND_PLAY_PAUSE} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @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.
   *
   * <p>This method must only be called if {@link #COMMAND_SET_REPEAT_MODE} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @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.
   *
   * <p>This method must only be called if {@link #COMMAND_SET_SHUFFLE_MODE} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @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.
   *
   * <p>This method must only be called if {@link #COMMAND_SEEK_TO_DEFAULT_POSITION} is {@linkplain
   * #getAvailableCommands() available}.
   */
  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.
   *
   * <p>This method must only be called if {@link #COMMAND_SEEK_TO_MEDIA_ITEM} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @param mediaItemIndex The index of the {@link MediaItem} whose associated default position
   *     should be seeked to. If the index is larger than the size of the playlist, the request is
   *     ignored.
   */
  void seekToDefaultPosition(int mediaItemIndex);

  /**
   * Seeks to a position specified in milliseconds in the current {@link MediaItem}.
   *
   * <p>This method must only be called if {@link #COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM} is
   * {@linkplain #getAvailableCommands() available}.
   *
   * @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}.
   *
   * <p>This method must only be called if {@link #COMMAND_SEEK_TO_MEDIA_ITEM} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @param mediaItemIndex The index of the {@link MediaItem}. If the index is larger than the size
   *     of the playlist, the request is ignored.
   * @param positionMs The seek position in the specified {@link MediaItem}, or {@link C#TIME_UNSET}
   *     to seek to the media item's default position.
   */
  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.
   *
   * <p>This method must only be called if {@link #COMMAND_SEEK_BACK} is {@linkplain
   * #getAvailableCommands() available}.
   */
  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.
   *
   * <p>This method must only be called if {@link #COMMAND_SEEK_FORWARD} is {@linkplain
   * #getAvailableCommands() available}.
   */
  void seekForward();

  /**
   * 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.
   *
   * <p>This method must only be called if {@link #COMMAND_GET_TIMELINE} is {@linkplain
   * #getAvailableCommands() available}.
   */
  boolean hasPreviousMediaItem();

  /**
   * @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.
   *
   * <p>This method must only be called if {@link #COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM} is
   * {@linkplain #getAvailableCommands() available}.
   */
  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 {@linkplain #isCurrentMediaItemLive()
   *       live} and {@linkplain #isCurrentMediaItemSeekable() unseekable}, then:
   *       <ul>
   *         <li>If {@linkplain #hasPreviousMediaItem() a previous media item exists}, seeks to the
   *             default position of the previous media item.
   *         <li>Otherwise, does nothing.
   *       </ul>
   *   <li>Otherwise, if {@linkplain #hasPreviousMediaItem() a previous media item exists} and the
   *       {@linkplain #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>
   *
   * <p>This method must only be called if {@link #COMMAND_SEEK_TO_PREVIOUS} is {@linkplain
   * #getAvailableCommands() available}.
   */
  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.
   *
   * <p>This method must only be called if {@link #COMMAND_GET_TIMELINE} is {@linkplain
   * #getAvailableCommands() available}.
   */
  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.
   *
   * <p>This method must only be called if {@link #COMMAND_SEEK_TO_NEXT_MEDIA_ITEM} is {@linkplain
   * #getAvailableCommands() available}.
   */
  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 {@linkplain #hasNextMediaItem() a next media item exists}, seeks to the
   *       default position of the next {@link MediaItem}.
   *   <li>Otherwise, if the current {@link MediaItem} is {@linkplain #isCurrentMediaItemLive()
   *       live} and has not ended, seeks to the live edge of the current {@link MediaItem}.
   *   <li>Otherwise, does nothing.
   * </ul>
   *
   * <p>This method must only be called if {@link #COMMAND_SEEK_TO_NEXT} is {@linkplain
   * #getAvailableCommands() available}.
   */
  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.
   *
   * <p>This method must only be called if {@link #COMMAND_SET_SPEED_AND_PITCH} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @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))}.
   *
   * <p>This method must only be called if {@link #COMMAND_SET_SPEED_AND_PITCH} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @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.
   *
   * <p>This method must only be called if {@link #COMMAND_STOP} is {@linkplain
   * #getAvailableCommands() available}.
   */
  void stop();

  /**
   * 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.
   *
   * <p>This method must only be called if {@link #COMMAND_RELEASE} is {@linkplain
   * #getAvailableCommands() available}.
   */
  void release();

  /**
   * Returns the current tracks.
   *
   * <p>This method must only be called if {@link #COMMAND_GET_TRACKS} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @see Listener#onTracksChanged(Tracks)
   */
  Tracks getCurrentTracks();

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

  // LINT.IfChange(set_track_selection_parameters)
  /**
   * 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>
   *
   * <p>This method must only be called if {@link #COMMAND_SET_TRACK_SELECTION_PARAMETERS} is
   * {@linkplain #getAvailableCommands() available}.
   */
  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 MediaItem
   * metadata}, the static metadata in the media's {@link Format#metadata Format}, and any timed
   * metadata that has been parsed from the media and output via {@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 timed metadata.
   *
   * <p>This method must only be called if {@link #COMMAND_GET_METADATA} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @see Listener#onMediaMetadataChanged(MediaMetadata)
   */
  MediaMetadata getMediaMetadata();

  /**
   * Returns the playlist {@link MediaMetadata}, as set by {@link
   * #setPlaylistMetadata(MediaMetadata)}, or {@link MediaMetadata#EMPTY} if not supported.
   *
   * <p>This method must only be called if {@link #COMMAND_GET_METADATA} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @see Listener#onPlaylistMetadataChanged(MediaMetadata)
   */
  MediaMetadata getPlaylistMetadata();

  /**
   * Sets the playlist {@link MediaMetadata}.
   *
   * <p>This method must only be called if {@link #COMMAND_SET_PLAYLIST_METADATA} is {@linkplain
   * #getAvailableCommands() available}.
   */
  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.
   *
   * <p>This method must only be called if {@link #COMMAND_GET_TIMELINE} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @see Listener#onTimelineChanged(Timeline, int)
   */
  Timeline getCurrentTimeline();

  /**
   * Returns the index of the period currently being played.
   *
   * <p>This method must only be called if {@link #COMMAND_GET_TIMELINE} is {@linkplain
   * #getAvailableCommands() available}.
   */
  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.
   *
   * <p>This method must only be called if {@link #COMMAND_GET_TIMELINE} is {@linkplain
   * #getAvailableCommands() available}.
   */
  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.
   *
   * <p>This method must only be called if {@link #COMMAND_GET_TIMELINE} is {@linkplain
   * #getAvailableCommands() available}.
   */
  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.
   *
   * <p>This method must only be called if {@link #COMMAND_GET_TIMELINE} is {@linkplain
   * #getAvailableCommands() available}.
   */
  int getPreviousMediaItemIndex();

  /**
   * Returns the currently playing {@link MediaItem}. May be null if the timeline is empty.
   *
   * <p>This method must only be called if {@link #COMMAND_GET_CURRENT_MEDIA_ITEM} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @see Listener#onMediaItemTransition(MediaItem, int)
   */
  @Nullable
  MediaItem getCurrentMediaItem();

  /**
   * Returns the number of {@linkplain MediaItem media items} in the playlist.
   *
   * <p>This method must only be called if {@link #COMMAND_GET_TIMELINE} is {@linkplain
   * #getAvailableCommands() available}.
   */
  int getMediaItemCount();

  /**
   * Returns the {@link MediaItem} at the given index.
   *
   * <p>This method must only be called if {@link #COMMAND_GET_TIMELINE} is {@linkplain
   * #getAvailableCommands() available}.
   */
  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.
   *
   * <p>This method must only be called if {@link #COMMAND_GET_CURRENT_MEDIA_ITEM} is {@linkplain
   * #getAvailableCommands() available}.
   */
  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.
   *
   * <p>This method must only be called if {@link #COMMAND_GET_CURRENT_MEDIA_ITEM} is {@linkplain
   * #getAvailableCommands() available}.
   */
  long getCurrentPosition();

  /**
   * Returns an estimate of the position in the current content or ad up to which data is buffered,
   * in milliseconds.
   *
   * <p>This method must only be called if {@link #COMMAND_GET_CURRENT_MEDIA_ITEM} is {@linkplain
   * #getAvailableCommands() available}.
   */
  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 {@linkplain MediaItem media items}.
   *
   * <p>This method must only be called if {@link #COMMAND_GET_CURRENT_MEDIA_ITEM} is {@linkplain
   * #getAvailableCommands() available}.
   */
  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.
   *
   * <p>This method must only be called if {@link #COMMAND_GET_CURRENT_MEDIA_ITEM} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @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.
   *
   * <p>This method must only be called if {@link #COMMAND_GET_CURRENT_MEDIA_ITEM} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @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} {@linkplain #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.
   *
   * <p>This method must only be called if {@link #COMMAND_GET_CURRENT_MEDIA_ITEM} is {@linkplain
   * #getAvailableCommands() available}.
   */
  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.
   *
   * <p>This method must only be called if {@link #COMMAND_GET_CURRENT_MEDIA_ITEM} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @see Timeline.Window#isSeekable
   */
  boolean isCurrentMediaItemSeekable();

  /**
   * Returns whether the player is currently playing an ad.
   *
   * <p>This method must only be called if {@link #COMMAND_GET_CURRENT_MEDIA_ITEM} is {@linkplain
   * #getAvailableCommands() available}.
   */
  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.
   *
   * <p>This method must only be called if {@link #COMMAND_GET_CURRENT_MEDIA_ITEM} is {@linkplain
   * #getAvailableCommands() available}.
   */
  int getCurrentAdGroupIndex();

  /**
   * If {@link #isPlayingAd()} returns true, returns the index of the ad in its ad group. Returns
   * {@link C#INDEX_UNSET} otherwise.
   *
   * <p>This method must only be called if {@link #COMMAND_GET_CURRENT_MEDIA_ITEM} is {@linkplain
   * #getAvailableCommands() available}.
   */
  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()}.
   *
   * <p>This method must only be called if {@link #COMMAND_GET_CURRENT_MEDIA_ITEM} is {@linkplain
   * #getAvailableCommands() available}.
   */
  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()}.
   *
   * <p>This method must only be called if {@link #COMMAND_GET_CURRENT_MEDIA_ITEM} is {@linkplain
   * #getAvailableCommands() available}.
   */
  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()}.
   *
   * <p>This method must only be called if {@link #COMMAND_GET_CURRENT_MEDIA_ITEM} is {@linkplain
   * #getAvailableCommands() available}.
   */
  long getContentBufferedPosition();

  /**
   * Returns the attributes for audio playback.
   *
   * <p>This method must only be called if {@link #COMMAND_GET_AUDIO_ATTRIBUTES} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @see Listener#onAudioAttributesChanged(AudioAttributes)
   */
  AudioAttributes getAudioAttributes();

  /**
   * Sets the audio volume, valid values are between 0 (silence) and 1 (unity gain, signal
   * unchanged), inclusive.
   *
   * <p>This method must only be called if {@link #COMMAND_SET_VOLUME} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @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).
   *
   * <p>This method must only be called if {@link #COMMAND_GET_VOLUME} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @return The linear gain applied to all audio channels.
   * @see Listener#onVolumeChanged(float)
   */
  @FloatRange(from = 0, to = 1.0)
  float getVolume();

  /**
   * Clears any {@link Surface}, {@link SurfaceHolder}, {@link SurfaceView} or {@link TextureView}
   * currently set on the player.
   *
   * <p>This method must only be called if {@link #COMMAND_SET_VIDEO_SURFACE} is {@linkplain
   * #getAvailableCommands() available}.
   */
  void clearVideoSurface();

  /**
   * Clears the {@link Surface} onto which video is being rendered if it matches the one passed.
   * Else does nothing.
   *
   * <p>This method must only be called if {@link #COMMAND_SET_VIDEO_SURFACE} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @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.
   *
   * <p>This method must only be called if {@link #COMMAND_SET_VIDEO_SURFACE} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @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()}.
   *
   * <p>This method must only be called if {@link #COMMAND_SET_VIDEO_SURFACE} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @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.
   *
   * <p>This method must only be called if {@link #COMMAND_SET_VIDEO_SURFACE} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @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()}.
   *
   * <p>This method must only be called if {@link #COMMAND_SET_VIDEO_SURFACE} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @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.
   *
   * <p>This method must only be called if {@link #COMMAND_SET_VIDEO_SURFACE} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @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>Consider using {@link SurfaceView} via {@link #setVideoSurfaceView} instead of {@link
   * TextureView}. {@link SurfaceView} generally causes lower battery consumption, and has better
   * handling for HDR and secure content. See <a
   * href="https://developer.android.com/guide/topics/media/ui/playerview#surfacetype">Choosing a
   * surface type</a> for more information.
   *
   * <p>The thread that calls the {@link TextureView.SurfaceTextureListener} methods must be the
   * thread associated with {@link #getApplicationLooper()}.
   *
   * <p>This method must only be called if {@link #COMMAND_SET_VIDEO_SURFACE} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @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.
   *
   * <p>This method must only be called if {@link #COMMAND_SET_VIDEO_SURFACE} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @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 {@linkplain
   * Tracks#isTypeSupported(int) no supported video track} or its size has not been determined yet.
   *
   * @see Listener#onVideoSizeChanged(VideoSize)
   */
  VideoSize getVideoSize();

  /**
   * Gets the size of the surface on which the video is rendered.
   *
   * @see Listener#onSurfaceSizeChanged(int, int)
   */
  @UnstableApi
  Size getSurfaceSize();

  /**
   * Returns the current {@link CueGroup}.
   *
   * <p>This method must only be called if {@link #COMMAND_GET_TEXT} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @see Listener#onCues(CueGroup)
   */
  CueGroup 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.
   *
   * <p>Note that this method returns the volume of the device. To check the current stream volume,
   * use {@link #getVolume()}.
   *
   * <p>This method must only be called if {@link #COMMAND_GET_DEVICE_VOLUME} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @see Listener#onDeviceVolumeChanged(int, boolean)
   */
  @IntRange(from = 0)
  int getDeviceVolume();

  /**
   * Gets whether the device is muted or not.
   *
   * <p>Note that this method returns the mute state of the device. To check if the current stream
   * is muted, use {@code getVolume() == 0}.
   *
   * <p>This method must only be called if {@link #COMMAND_GET_DEVICE_VOLUME} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @see Listener#onDeviceVolumeChanged(int, boolean)
   */
  boolean isDeviceMuted();

  /**
   * @deprecated Use {@link #setDeviceVolume(int, int)} instead.
   */
  @Deprecated
  void setDeviceVolume(@IntRange(from = 0) int volume);

  /**
   * Sets the volume of the device with volume flags.
   *
   * <p>Note that this method affects the device volume. To change the volume of the current stream
   * only, use {@link #setVolume}.
   *
   * <p>This method must only be called if {@link #COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS} is
   * {@linkplain #getAvailableCommands() available}.
   *
   * @param volume The volume to set.
   * @param flags Either 0 or a bitwise combination of one or more {@link C.VolumeFlags}.
   */
  void setDeviceVolume(@IntRange(from = 0) int volume, @C.VolumeFlags int flags);

  /**
   * @deprecated Use {@link #increaseDeviceVolume(int)} instead.
   */
  @Deprecated
  void increaseDeviceVolume();

  /**
   * Increases the volume of the device.
   *
   * <p>The {@link #getDeviceVolume()} device volume cannot be increased above {@link
   * DeviceInfo#maxVolume}, if defined.
   *
   * <p>Note that this method affects the device volume. To change the volume of the current stream
   * only, use {@link #setVolume}.
   *
   * <p>This method must only be called if {@link #COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS} is
   * {@linkplain #getAvailableCommands() available}.
   *
   * @param flags Either 0 or a bitwise combination of one or more {@link C.VolumeFlags}.
   */
  void increaseDeviceVolume(@C.VolumeFlags int flags);

  /**
   * @deprecated Use {@link #decreaseDeviceVolume(int)} instead.
   */
  @Deprecated
  void decreaseDeviceVolume();

  /**
   * Decreases the volume of the device.
   *
   * <p>The {@link #getDeviceVolume()} device volume cannot be decreased below {@link
   * DeviceInfo#minVolume}.
   *
   * <p>Note that this method affects the device volume. To change the volume of the current stream
   * only, use {@link #setVolume}.
   *
   * <p>This method must only be called if {@link #COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS} is
   * {@linkplain #getAvailableCommands() available}.
   *
   * @param flags Either 0 or a bitwise combination of one or more {@link C.VolumeFlags}.
   */
  void decreaseDeviceVolume(@C.VolumeFlags int flags);

  /**
   * @deprecated Use {@link #setDeviceMuted(boolean, int)} instead.
   */
  @Deprecated
  void setDeviceMuted(boolean muted);

  /**
   * Sets the mute state of the device.
   *
   * <p>Note that this method affects the device volume. To mute just the current stream, use {@code
   * setVolume(0)} instead.
   *
   * <p>This method must only be called if {@link #COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS} is
   * {@linkplain #getAvailableCommands() available}.
   *
   * @param muted Whether to set the device to be muted or not
   * @param flags Either 0 or a bitwise combination of one or more {@link C.VolumeFlags}.
   */
  void setDeviceMuted(boolean muted, @C.VolumeFlags int flags);

  /**
   * Sets the attributes for audio playback, used by the underlying audio track. If not set, the
   * default audio attributes will be used. They are suitable for general media playback.
   *
   * <p>Setting the audio attributes during playback may introduce a short gap in audio output as
   * the audio track is recreated. A new audio session id will also be generated.
   *
   * <p>If tunneling is enabled by the track selector, the specified audio attributes will be
   * ignored, but they will take effect if audio is later played without tunneling.
   *
   * <p>If the device is running a build before platform API version 21, audio attributes cannot be
   * set directly on the underlying audio track. In this case, the usage will be mapped onto an
   * equivalent stream type using {@link Util#getStreamTypeForAudioUsage(int)}.
   *
   * <p>If audio focus should be handled, the {@link AudioAttributes#usage} must be {@link
   * C#USAGE_MEDIA} or {@link C#USAGE_GAME}. Other usages will throw an {@link
   * IllegalArgumentException}.
   *
   * <p>This method must only be called if {@link #COMMAND_SET_AUDIO_ATTRIBUTES} is {@linkplain
   * #getAvailableCommands() available}.
   *
   * @param audioAttributes The attributes to use for audio playback.
   * @param handleAudioFocus True if the player should handle audio focus, false otherwise.
   */
  void setAudioAttributes(AudioAttributes audioAttributes, boolean handleAudioFocus);
}