/* * 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 com.google.android.exoplayer2; 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 com.google.android.exoplayer2.audio.AudioAttributes; import com.google.android.exoplayer2.metadata.Metadata; import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.text.Cue; import com.google.android.exoplayer2.trackselection.TrackSelection; import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.trackselection.TrackSelectionParameters; import com.google.android.exoplayer2.util.BundleableUtil; import com.google.android.exoplayer2.util.FlagSet; import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.video.VideoSize; import com.google.common.base.Objects; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.util.ArrayList; import java.util.List; /** * A media player interface defining traditional high-level functionality, such as the ability to * play, pause, seek and query properties of the currently playing media. * *
This interface includes some convenience methods that can be implemented by calling other * methods in the interface. {@link BasePlayer} implements these convenience methods so inheriting * {@link BasePlayer} is recommended when implementing the interface so that only the minimal set of * required methods can be implemented. * *
Some important properties of media players that implement this interface are: * *
All methods have no-op default implementations to allow selective overrides. * *
Listeners can choose to implement individual events (e.g. {@link * #onIsPlayingChanged(boolean)}) or {@link #onEvents(Player, Events)}, which is called after one * or more events occurred together. * * @deprecated Use {@link Player.Listener}. */ @Deprecated interface EventListener { /** * Called when the timeline has been refreshed. * *
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. * *
{@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}. * *
Note that this callback is also called when the playlist becomes non-empty or empty as a * consequence of a playlist change. * *
{@link #onEvents(Player, Events)} will also be called to report this event along with * other events that happen in the same {@link Looper} message queue iteration. * * @param mediaItem The {@link MediaItem}. May be null if the playlist becomes empty. * @param reason The reason for the transition. */ default void onMediaItemTransition( @Nullable MediaItem mediaItem, @MediaItemTransitionReason int reason) {} /** * Called when the available or selected tracks change. * *
{@link #onEvents(Player, Events)} will also be called to report this event along with * other events that happen in the same {@link Looper} message queue iteration. * * @param trackGroups The available tracks. Never null, but may be of length zero. * @param trackSelections The selected tracks. Never null, but may contain null elements. A * concrete implementation may include null elements if it has a fixed number of renderer * components, wishes to report a TrackSelection for each of them, and has one or more * renderer components that is not assigned any selected tracks. * @deprecated Use {@link #onTracksInfoChanged(TracksInfo)} instead. */ @Deprecated default void onTracksChanged( TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {} /** * Called when the available or selected tracks change. * *
{@link #onEvents(Player, Events)} will also be called to report this event along with * other events that happen in the same {@link Looper} message queue iteration. * * @param tracksInfo The available tracks information. Never null, but may be of length zero. */ default void onTracksInfoChanged(TracksInfo tracksInfo) {} /** * Called when the combined {@link MediaMetadata} changes. * *
The provided {@link MediaMetadata} is a combination of the {@link MediaItem#mediaMetadata} * and the static and dynamic metadata from the {@link TrackSelection#getFormat(int) track * selections' formats} and {@link Listener#onMetadata(Metadata)}. If a field is populated in * the {@link MediaItem#mediaMetadata}, it will be prioritised above the same field coming from * static or dynamic metadata. * *
This method may be called multiple times in quick succession. * *
{@link #onEvents(Player, Events)} will also be called to report this event along with * other events that happen in the same {@link Looper} message queue iteration. * * @param mediaMetadata The combined {@link MediaMetadata}. */ default void onMediaMetadataChanged(MediaMetadata mediaMetadata) {} /** Called when the playlist {@link MediaMetadata} changes. */ default void onPlaylistMetadataChanged(MediaMetadata mediaMetadata) {} /** * Called when the player starts or stops loading the source. * *
{@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 default void onLoadingChanged(boolean isLoading) {} /** * Called when the value returned from {@link #isCommandAvailable(int)} changes for at least one * {@link Command}. * *
{@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. * *
{@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 default void onPlayerStateChanged(boolean playWhenReady, @State int playbackState) {} /** * Called when the value returned from {@link #getPlaybackState()} changes. * *
{@link #onEvents(Player, Events)} will also be called to report this event along with * other events that happen in the same {@link Looper} message queue iteration. * * @param playbackState The new playback {@link State state}. */ default void onPlaybackStateChanged(@State int playbackState) {} /** * Called when the value returned from {@link #getPlayWhenReady()} changes. * *
{@link #onEvents(Player, Events)} will also be called to report this event along with * other events that happen in the same {@link Looper} message queue iteration. * * @param playWhenReady Whether playback will proceed when ready. * @param reason The {@link PlayWhenReadyChangeReason reason} for the change. */ default void onPlayWhenReadyChanged( boolean playWhenReady, @PlayWhenReadyChangeReason int reason) {} /** * Called when the value returned from {@link #getPlaybackSuppressionReason()} changes. * *
{@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. * *
{@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. * *
{@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. * *
{@link #onEvents(Player, Events)} will also be called to report this event along with * other events that happen in the same {@link Looper} message queue iteration. * * @param shuffleModeEnabled Whether shuffling of {@link MediaItem media items} is enabled. */ default void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {} /** * Called when an error occurs. The playback state will transition to {@link #STATE_IDLE} * immediately after this method is called. The player instance can still be used, and {@link * #release()} must still be called on the player should it no longer be required. * *
{@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. * *
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. * *
{@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. * *
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 default void onPositionDiscontinuity(@DiscontinuityReason int reason) {} /** * Called when a position discontinuity occurs. * *
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. * *
{@link #onEvents(Player, Events)} will also be called to report this event along with * other events that happen in the same {@link Looper} message queue iteration. * * @param oldPosition The position before the discontinuity. * @param newPosition The position after the discontinuity. * @param reason The {@link DiscontinuityReason} responsible for the discontinuity. */ default void onPositionDiscontinuity( PositionInfo oldPosition, PositionInfo newPosition, @DiscontinuityReason int reason) {} /** * Called when the current playback parameters change. The playback parameters may change due to * a call to {@link #setPlaybackParameters(PlaybackParameters)}, or the player itself may change * them (for example, if audio playback switches to passthrough or offload mode, where speed * adjustment is no longer possible). * *
{@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. * *
{@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. * *
{@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. * *
{@link #onEvents(Player, Events)} will also be called to report this event along with * other events that happen in the same {@link Looper} message queue iteration. * * @param maxSeekToPreviousPositionMs The maximum position for which {@link #seekToPrevious()} * seeks to the previous position, in milliseconds. */ default void onMaxSeekToPreviousPositionChanged(long maxSeekToPreviousPositionMs) {} /** * @deprecated Seeks are processed without delay. Listen to {@link * #onPositionDiscontinuity(PositionInfo, PositionInfo, int)} with reason {@link * #DISCONTINUITY_REASON_SEEK} instead. */ @Deprecated default void onSeekProcessed() {} /** * Called when one or more player states changed. * *
State changes and events that happen within one {@link Looper} message queue iteration are * reported together and only after all individual callbacks were triggered. * *
Only state changes represented by {@link Event events} are reported through this method. * *
Listeners should prefer this method over individual callbacks in the following cases: * *
Although index-based access is possible, it doesn't imply a particular order of these * events. * * @param index The index. Must be between 0 (inclusive) and {@link #size()} (exclusive). * @return The {@link Event} at the given index. * @throws IndexOutOfBoundsException If index is outside the allowed range. */ public @Event int get(int index) { return flags.get(index); } @Override public int hashCode() { return flags.hashCode(); } @Override public boolean equals(@Nullable Object obj) { if (this == obj) { return true; } if (!(obj instanceof Events)) { return false; } Events other = (Events) obj; return flags.equals(other.flags); } } /** Position info describing a playback position involved in a discontinuity. */ final class PositionInfo implements Bundleable { /** * The UID of the window, or {@code null} if the timeline is {@link Timeline#isEmpty() empty}. */ @Nullable public final Object windowUid; /** @deprecated Use {@link #mediaItemIndex} instead. */ @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}. */ @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. * *
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 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. */ public PositionInfo( @Nullable Object windowUid, int mediaItemIndex, @Nullable MediaItem mediaItem, @Nullable Object periodUid, int periodIndex, long positionMs, long contentPositionMs, int adGroupIndex, int adIndexInAdGroup) { this.windowUid = windowUid; this.windowIndex = mediaItemIndex; this.mediaItemIndex = mediaItemIndex; this.mediaItem = mediaItem; this.periodUid = periodUid; this.periodIndex = periodIndex; this.positionMs = positionMs; this.contentPositionMs = contentPositionMs; this.adGroupIndex = adGroupIndex; this.adIndexInAdGroup = adIndexInAdGroup; } @Override public boolean equals(@Nullable Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } PositionInfo that = (PositionInfo) o; return mediaItemIndex == that.mediaItemIndex && periodIndex == that.periodIndex && positionMs == that.positionMs && contentPositionMs == that.contentPositionMs && adGroupIndex == that.adGroupIndex && adIndexInAdGroup == that.adIndexInAdGroup && Objects.equal(windowUid, that.windowUid) && Objects.equal(periodUid, that.periodUid) && Objects.equal(mediaItem, that.mediaItem); } @Override public int hashCode() { return Objects.hashCode( windowUid, mediaItemIndex, mediaItem, periodUid, periodIndex, positionMs, contentPositionMs, adGroupIndex, adIndexInAdGroup); } // Bundleable implementation. @Documented @Retention(RetentionPolicy.SOURCE) @IntDef({ FIELD_MEDIA_ITEM_INDEX, FIELD_MEDIA_ITEM, FIELD_PERIOD_INDEX, FIELD_POSITION_MS, FIELD_CONTENT_POSITION_MS, FIELD_AD_GROUP_INDEX, FIELD_AD_INDEX_IN_AD_GROUP }) private @interface FieldNumber {} private static final int FIELD_MEDIA_ITEM_INDEX = 0; private static final int FIELD_MEDIA_ITEM = 1; private static final int FIELD_PERIOD_INDEX = 2; private static final int FIELD_POSITION_MS = 3; private static final int FIELD_CONTENT_POSITION_MS = 4; private static final int FIELD_AD_GROUP_INDEX = 5; private static final int FIELD_AD_INDEX_IN_AD_GROUP = 6; /** * {@inheritDoc} * *
It omits the {@link #windowUid} and {@link #periodUid} fields. The {@link #windowUid} and
* {@link #periodUid} of an instance restored by {@link #CREATOR} will always be {@code null}.
*/
@Override
public Bundle toBundle() {
Bundle bundle = new Bundle();
bundle.putInt(keyForField(FIELD_MEDIA_ITEM_INDEX), mediaItemIndex);
bundle.putBundle(keyForField(FIELD_MEDIA_ITEM), BundleableUtil.toNullableBundle(mediaItem));
bundle.putInt(keyForField(FIELD_PERIOD_INDEX), periodIndex);
bundle.putLong(keyForField(FIELD_POSITION_MS), positionMs);
bundle.putLong(keyForField(FIELD_CONTENT_POSITION_MS), contentPositionMs);
bundle.putInt(keyForField(FIELD_AD_GROUP_INDEX), adGroupIndex);
bundle.putInt(keyForField(FIELD_AD_INDEX_IN_AD_GROUP), adIndexInAdGroup);
return bundle;
}
/** Object that can restore {@link PositionInfo} from a {@link Bundle}. */
public static final Creator Instances are immutable.
*/
final class Commands implements Bundleable {
/** A builder for {@link Commands} instances. */
public static final class Builder {
@Command
private static final int[] SUPPORTED_COMMANDS = {
COMMAND_PLAY_PAUSE,
COMMAND_PREPARE,
COMMAND_STOP,
COMMAND_SEEK_TO_DEFAULT_POSITION,
COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM,
COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM,
COMMAND_SEEK_TO_PREVIOUS,
COMMAND_SEEK_TO_NEXT_MEDIA_ITEM,
COMMAND_SEEK_TO_NEXT,
COMMAND_SEEK_TO_MEDIA_ITEM,
COMMAND_SEEK_BACK,
COMMAND_SEEK_FORWARD,
COMMAND_SET_SPEED_AND_PITCH,
COMMAND_SET_SHUFFLE_MODE,
COMMAND_SET_REPEAT_MODE,
COMMAND_GET_CURRENT_MEDIA_ITEM,
COMMAND_GET_TIMELINE,
COMMAND_GET_MEDIA_ITEMS_METADATA,
COMMAND_SET_MEDIA_ITEMS_METADATA,
COMMAND_CHANGE_MEDIA_ITEMS,
COMMAND_GET_AUDIO_ATTRIBUTES,
COMMAND_GET_VOLUME,
COMMAND_GET_DEVICE_VOLUME,
COMMAND_SET_VOLUME,
COMMAND_SET_DEVICE_VOLUME,
COMMAND_ADJUST_DEVICE_VOLUME,
COMMAND_SET_VIDEO_SURFACE,
COMMAND_GET_TEXT,
COMMAND_SET_TRACK_SELECTION_PARAMETERS,
COMMAND_GET_TRACK_INFOS,
};
private final FlagSet.Builder flagsBuilder;
/** Creates a builder. */
public Builder() {
flagsBuilder = new FlagSet.Builder();
}
private Builder(Commands commands) {
flagsBuilder = new FlagSet.Builder();
flagsBuilder.addAll(commands.flags);
}
/**
* Adds a {@link Command}.
*
* @param command A {@link Command}.
* @return This builder.
* @throws IllegalStateException If {@link #build()} has already been called.
*/
public Builder add(@Command int command) {
flagsBuilder.add(command);
return this;
}
/**
* Adds a {@link Command} if the provided condition is true. Does nothing otherwise.
*
* @param command A {@link Command}.
* @param condition A condition.
* @return This builder.
* @throws IllegalStateException If {@link #build()} has already been called.
*/
public Builder addIf(@Command int command, boolean condition) {
flagsBuilder.addIf(command, condition);
return this;
}
/**
* Adds {@link Command commands}.
*
* @param commands The {@link Command commands} to add.
* @return This builder.
* @throws IllegalStateException If {@link #build()} has already been called.
*/
public Builder addAll(@Command int... commands) {
flagsBuilder.addAll(commands);
return this;
}
/**
* Adds {@link Commands}.
*
* @param commands The set of {@link Command commands} to add.
* @return This builder.
* @throws IllegalStateException If {@link #build()} has already been called.
*/
public Builder addAll(Commands commands) {
flagsBuilder.addAll(commands.flags);
return this;
}
/**
* Adds all existing {@link Command commands}.
*
* @return This builder.
* @throws IllegalStateException If {@link #build()} has already been called.
*/
public Builder addAllCommands() {
flagsBuilder.addAll(SUPPORTED_COMMANDS);
return this;
}
/**
* Removes a {@link Command}.
*
* @param command A {@link Command}.
* @return This builder.
* @throws IllegalStateException If {@link #build()} has already been called.
*/
public Builder remove(@Command int command) {
flagsBuilder.remove(command);
return this;
}
/**
* Removes a {@link Command} if the provided condition is true. Does nothing otherwise.
*
* @param command A {@link Command}.
* @param condition A condition.
* @return This builder.
* @throws IllegalStateException If {@link #build()} has already been called.
*/
public Builder removeIf(@Command int command, boolean condition) {
flagsBuilder.removeIf(command, condition);
return this;
}
/**
* Removes {@link Command commands}.
*
* @param commands The {@link Command commands} to remove.
* @return This builder.
* @throws IllegalStateException If {@link #build()} has already been called.
*/
public Builder removeAll(@Command int... commands) {
flagsBuilder.removeAll(commands);
return this;
}
/**
* Builds a {@link Commands} instance.
*
* @throws IllegalStateException If this method has already been called.
*/
public Commands build() {
return new Commands(flagsBuilder.build());
}
}
/** An empty set of commands. */
public static final Commands EMPTY = new Builder().build();
private final FlagSet flags;
private Commands(FlagSet flags) {
this.flags = flags;
}
/** Returns a {@link Builder} initialized with the values of this instance. */
public Builder buildUpon() {
return new Builder(this);
}
/** Returns whether the set of commands contains the specified {@link Command}. */
public boolean contains(@Command int command) {
return flags.contains(command);
}
/** Returns the number of commands in this set. */
public int size() {
return flags.size();
}
/**
* Returns the {@link Command} at the given index.
*
* @param index The index. Must be between 0 (inclusive) and {@link #size()} (exclusive).
* @return The {@link Command} at the given index.
* @throws IndexOutOfBoundsException If index is outside the allowed range.
*/
public @Command int get(int index) {
return flags.get(index);
}
@Override
public boolean equals(@Nullable Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Commands)) {
return false;
}
Commands commands = (Commands) obj;
return flags.equals(commands.flags);
}
@Override
public int hashCode() {
return flags.hashCode();
}
// Bundleable implementation.
@Documented
@Retention(RetentionPolicy.SOURCE)
@IntDef({FIELD_COMMANDS})
private @interface FieldNumber {}
private static final int FIELD_COMMANDS = 0;
@Override
public Bundle toBundle() {
Bundle bundle = new Bundle();
ArrayList All methods have no-op default implementations to allow selective overrides.
*/
interface Listener extends EventListener {
@Override
default void onTimelineChanged(Timeline timeline, @TimelineChangeReason int reason) {}
@Override
default void onMediaItemTransition(
@Nullable MediaItem mediaItem, @MediaItemTransitionReason int reason) {}
@Override
default void onTracksInfoChanged(TracksInfo tracksInfo) {}
@Override
default void onIsLoadingChanged(boolean isLoading) {}
@Override
default void onAvailableCommandsChanged(Commands availableCommands) {}
@Override
default void onPlaybackStateChanged(@State int playbackState) {}
@Override
default void onPlayWhenReadyChanged(
boolean playWhenReady, @PlayWhenReadyChangeReason int reason) {}
@Override
default void onPlaybackSuppressionReasonChanged(
@PlaybackSuppressionReason int playbackSuppressionReason) {}
@Override
default void onIsPlayingChanged(boolean isPlaying) {}
@Override
default void onRepeatModeChanged(@RepeatMode int repeatMode) {}
@Override
default void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {}
@Override
default void onPlayerError(PlaybackException error) {}
@Override
default void onPlayerErrorChanged(@Nullable PlaybackException error) {}
@Override
default void onPositionDiscontinuity(
PositionInfo oldPosition, PositionInfo newPosition, @DiscontinuityReason int reason) {}
@Override
default void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {}
@Override
default void onSeekForwardIncrementChanged(long seekForwardIncrementMs) {}
@Override
default void onSeekBackIncrementChanged(long seekBackIncrementMs) {}
/**
* Called when the audio session ID changes.
*
* @param audioSessionId The audio session ID.
*/
default void onAudioSessionIdChanged(int audioSessionId) {}
/**
* Called when the audio attributes change.
*
* @param audioAttributes The audio attributes.
*/
default void onAudioAttributesChanged(AudioAttributes audioAttributes) {}
/**
* Called when the volume changes.
*
* @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.
*
* @param skipSilenceEnabled Whether skipping silences in the audio stream is enabled.
*/
default void onSkipSilenceEnabledChanged(boolean skipSilenceEnabled) {}
/** Called when the device information changes. */
default void onDeviceInfoChanged(DeviceInfo deviceInfo) {}
/** Called when the device volume or mute state changes. */
default void onDeviceVolumeChanged(int volume, boolean muted) {}
@Override
default void onEvents(Player player, Events events) {}
/**
* Called each time there's a change in the size of the video being rendered.
*
* @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.
*
* @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.
*/
default void onRenderedFirstFrame() {}
/**
* Called when there is a change in the {@link Cue Cues}.
*
* {@code cues} is in ascending order of priority. If any of the cue boxes overlap when
* displayed, the {@link Cue} nearer the end of the list should be shown on top.
*
* @param cues The {@link Cue Cues}. May be empty.
*/
default void onCues(List This reason also indicates an automatic transition from the content period to an inserted ad
* period or vice versa. Or a transition caused by another player (e.g. multiple controllers can
* control the same playback on a remote device).
*/
int DISCONTINUITY_REASON_AUTO_TRANSITION = 0;
/** Seek within the current period or to another period. */
int DISCONTINUITY_REASON_SEEK = 1;
/**
* Seek adjustment due to being unable to seek to the requested position or because the seek was
* permitted to be inexact.
*/
int DISCONTINUITY_REASON_SEEK_ADJUSTMENT = 2;
/** Discontinuity introduced by a skipped period (for instance a skipped ad). */
int DISCONTINUITY_REASON_SKIP = 3;
/** Discontinuity caused by the removal of the current period from the {@link Timeline}. */
int DISCONTINUITY_REASON_REMOVE = 4;
/** Discontinuity introduced internally (e.g. by the source). */
int DISCONTINUITY_REASON_INTERNAL = 5;
/**
* Reasons for timeline changes. One of {@link #TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED} or {@link
* #TIMELINE_CHANGE_REASON_SOURCE_UPDATE}.
*/
@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).
*
* 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}.
*/
@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.
*
* 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)}.
*
* One of the {@link Player}{@code .EVENT_*} values.
*/
@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,
})
@interface Event {}
/** {@link #getCurrentTimeline()} changed. */
int EVENT_TIMELINE_CHANGED = 0;
/** {@link #getCurrentMediaItem()} changed or the player started repeating the current item. */
int EVENT_MEDIA_ITEM_TRANSITION = 1;
/** {@link #getCurrentTracksInfo()} changed. */
int EVENT_TRACKS_CHANGED = 2;
/** {@link #isLoading()} ()} changed. */
int EVENT_IS_LOADING_CHANGED = 3;
/** {@link #getPlaybackState()} changed. */
int EVENT_PLAYBACK_STATE_CHANGED = 4;
/** {@link #getPlayWhenReady()} changed. */
int EVENT_PLAY_WHEN_READY_CHANGED = 5;
/** {@link #getPlaybackSuppressionReason()} changed. */
int EVENT_PLAYBACK_SUPPRESSION_REASON_CHANGED = 6;
/** {@link #isPlaying()} changed. */
int EVENT_IS_PLAYING_CHANGED = 7;
/** {@link #getRepeatMode()} changed. */
int EVENT_REPEAT_MODE_CHANGED = 8;
/** {@link #getShuffleModeEnabled()} changed. */
int EVENT_SHUFFLE_MODE_ENABLED_CHANGED = 9;
/** {@link #getPlayerError()} changed. */
int EVENT_PLAYER_ERROR = 10;
/**
* A position discontinuity occurred. See {@link Listener#onPositionDiscontinuity(PositionInfo,
* PositionInfo, int)}.
*/
int EVENT_POSITION_DISCONTINUITY = 11;
/** {@link #getPlaybackParameters()} changed. */
int EVENT_PLAYBACK_PARAMETERS_CHANGED = 12;
/** {@link #isCommandAvailable(int)} changed for at least one {@link Command}. */
int EVENT_AVAILABLE_COMMANDS_CHANGED = 13;
/** {@link #getMediaMetadata()} changed. */
int EVENT_MEDIA_METADATA_CHANGED = 14;
/** {@link #getPlaylistMetadata()} changed. */
int EVENT_PLAYLIST_METADATA_CHANGED = 15;
/** {@link #getSeekBackIncrement()} changed. */
int EVENT_SEEK_BACK_INCREMENT_CHANGED = 16;
/** {@link #getSeekForwardIncrement()} changed. */
int EVENT_SEEK_FORWARD_INCREMENT_CHANGED = 17;
/** {@link #getMaxSeekToPreviousPosition()} changed. */
int EVENT_MAX_SEEK_TO_PREVIOUS_POSITION_CHANGED = 18;
/** {@link #getTrackSelectionParameters()} changed. */
int EVENT_TRACK_SELECTION_PARAMETERS_CHANGED = 19;
/**
* Commands that can be executed on a {@code Player}. One of {@link #COMMAND_PLAY_PAUSE}, {@link
* #COMMAND_PREPARE}, {@link #COMMAND_STOP}, {@link #COMMAND_SEEK_TO_DEFAULT_POSITION}, {@link
* #COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM}, {@link #COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM}, {@link
* #COMMAND_SEEK_TO_PREVIOUS}, {@link #COMMAND_SEEK_TO_NEXT_MEDIA_ITEM}, {@link
* #COMMAND_SEEK_TO_NEXT}, {@link #COMMAND_SEEK_TO_MEDIA_ITEM}, {@link #COMMAND_SEEK_BACK}, {@link
* #COMMAND_SEEK_FORWARD}, {@link #COMMAND_SET_SPEED_AND_PITCH}, {@link
* #COMMAND_SET_SHUFFLE_MODE}, {@link #COMMAND_SET_REPEAT_MODE}, {@link
* #COMMAND_GET_CURRENT_MEDIA_ITEM}, {@link #COMMAND_GET_TIMELINE}, {@link
* #COMMAND_GET_MEDIA_ITEMS_METADATA}, {@link #COMMAND_SET_MEDIA_ITEMS_METADATA}, {@link
* #COMMAND_CHANGE_MEDIA_ITEMS}, {@link #COMMAND_GET_AUDIO_ATTRIBUTES}, {@link
* #COMMAND_GET_VOLUME}, {@link #COMMAND_GET_DEVICE_VOLUME}, {@link #COMMAND_SET_VOLUME}, {@link
* #COMMAND_SET_DEVICE_VOLUME}, {@link #COMMAND_ADJUST_DEVICE_VOLUME}, {@link
* #COMMAND_SET_VIDEO_SURFACE}, {@link #COMMAND_GET_TEXT}, {@link
* #COMMAND_SET_TRACK_SELECTION_PARAMETERS} or {@link #COMMAND_GET_TRACK_INFOS}.
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
@IntDef({
COMMAND_INVALID,
COMMAND_PLAY_PAUSE,
COMMAND_PREPARE,
COMMAND_STOP,
COMMAND_SEEK_TO_DEFAULT_POSITION,
COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM,
COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM,
COMMAND_SEEK_TO_PREVIOUS,
COMMAND_SEEK_TO_NEXT_MEDIA_ITEM,
COMMAND_SEEK_TO_NEXT,
COMMAND_SEEK_TO_MEDIA_ITEM,
COMMAND_SEEK_BACK,
COMMAND_SEEK_FORWARD,
COMMAND_SET_SPEED_AND_PITCH,
COMMAND_SET_SHUFFLE_MODE,
COMMAND_SET_REPEAT_MODE,
COMMAND_GET_CURRENT_MEDIA_ITEM,
COMMAND_GET_TIMELINE,
COMMAND_GET_MEDIA_ITEMS_METADATA,
COMMAND_SET_MEDIA_ITEMS_METADATA,
COMMAND_CHANGE_MEDIA_ITEMS,
COMMAND_GET_AUDIO_ATTRIBUTES,
COMMAND_GET_VOLUME,
COMMAND_GET_DEVICE_VOLUME,
COMMAND_SET_VOLUME,
COMMAND_SET_DEVICE_VOLUME,
COMMAND_ADJUST_DEVICE_VOLUME,
COMMAND_SET_VIDEO_SURFACE,
COMMAND_GET_TEXT,
COMMAND_SET_TRACK_SELECTION_PARAMETERS,
COMMAND_GET_TRACK_INFOS,
})
@interface Command {}
/** Command to start, pause or resume playback. */
int COMMAND_PLAY_PAUSE = 1;
/** Command to prepare the player. */
int COMMAND_PREPARE = 2;
/** Command to stop playback or release the player. */
int COMMAND_STOP = 3;
/** Command to seek to the default position of the current {@link MediaItem}. */
int COMMAND_SEEK_TO_DEFAULT_POSITION = 4;
/** Command to seek anywhere into the current {@link MediaItem}. */
int COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM = 5;
/** @deprecated Use {@link #COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM} instead. */
@Deprecated int COMMAND_SEEK_IN_CURRENT_WINDOW = COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM;
/** Command to seek to the default position of the previous {@link MediaItem}. */
int COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM = 6;
/** @deprecated Use {@link #COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM} instead. */
@Deprecated int COMMAND_SEEK_TO_PREVIOUS_WINDOW = COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM;
/** Command to seek to an earlier position in the current or previous {@link MediaItem}. */
int COMMAND_SEEK_TO_PREVIOUS = 7;
/** Command to seek to the default position of the next {@link MediaItem}. */
int COMMAND_SEEK_TO_NEXT_MEDIA_ITEM = 8;
/** @deprecated Use {@link #COMMAND_SEEK_TO_NEXT_MEDIA_ITEM} instead. */
@Deprecated int COMMAND_SEEK_TO_NEXT_WINDOW = COMMAND_SEEK_TO_NEXT_MEDIA_ITEM;
/** Command to seek to a later position in the current or next {@link MediaItem}. */
int COMMAND_SEEK_TO_NEXT = 9;
/** Command to seek anywhere in any {@link MediaItem}. */
int COMMAND_SEEK_TO_MEDIA_ITEM = 10;
/** @deprecated Use {@link #COMMAND_SEEK_TO_MEDIA_ITEM} instead. */
@Deprecated int COMMAND_SEEK_TO_WINDOW = COMMAND_SEEK_TO_MEDIA_ITEM;
/** Command to seek back by a fixed increment into the current {@link MediaItem}. */
int COMMAND_SEEK_BACK = 11;
/** Command to seek forward by a fixed increment into the current {@link MediaItem}. */
int COMMAND_SEEK_FORWARD = 12;
/** Command to set the playback speed and pitch. */
int COMMAND_SET_SPEED_AND_PITCH = 13;
/** Command to enable shuffling. */
int COMMAND_SET_SHUFFLE_MODE = 14;
/** Command to set the repeat mode. */
int COMMAND_SET_REPEAT_MODE = 15;
/** Command to get the currently playing {@link MediaItem}. */
int COMMAND_GET_CURRENT_MEDIA_ITEM = 16;
/** Command to get the information about the current timeline. */
int COMMAND_GET_TIMELINE = 17;
/** Command to get the {@link MediaItem MediaItems} metadata. */
int COMMAND_GET_MEDIA_ITEMS_METADATA = 18;
/** Command to set the {@link MediaItem MediaItems} metadata. */
int COMMAND_SET_MEDIA_ITEMS_METADATA = 19;
/** Command to change the {@link MediaItem MediaItems} in the playlist. */
int COMMAND_CHANGE_MEDIA_ITEMS = 20;
/** Command to get the player current {@link AudioAttributes}. */
int COMMAND_GET_AUDIO_ATTRIBUTES = 21;
/** Command to get the player volume. */
int COMMAND_GET_VOLUME = 22;
/** Command to get the device volume and whether it is muted. */
int COMMAND_GET_DEVICE_VOLUME = 23;
/** Command to set the player volume. */
int COMMAND_SET_VOLUME = 24;
/** Command to set the device volume and mute it. */
int COMMAND_SET_DEVICE_VOLUME = 25;
/** Command to increase and decrease the device volume and mute it. */
int COMMAND_ADJUST_DEVICE_VOLUME = 26;
/** Command to set and clear the surface on which to render the video. */
int COMMAND_SET_VIDEO_SURFACE = 27;
/** Command to get the text that should currently be displayed by the player. */
int COMMAND_GET_TEXT = 28;
/** Command to set the player's track selection parameters. */
int COMMAND_SET_TRACK_SELECTION_PARAMETERS = 29;
/** Command to get track infos. */
int COMMAND_GET_TRACK_INFOS = 30;
/** Represents an invalid {@link Command}. */
int COMMAND_INVALID = -1;
/**
* Returns the {@link Looper} associated with the application thread that's used to access the
* player and on which player events are received.
*/
Looper getApplicationLooper();
/**
* Registers a listener to receive all events from the player.
*
* The listener's methods will be called on the thread associated with {@link
* #getApplicationLooper()}.
*
* @param listener The listener to register.
*/
void addListener(Listener listener);
/**
* Unregister a listener registered through {@link #addListener(Listener)}. The listener will no
* longer receive events.
*
* @param listener The listener to unregister.
*/
void removeListener(Listener listener);
/**
* Clears the playlist, adds the specified {@link MediaItem MediaItems} and resets the position to
* the default position.
*
* @param mediaItems The new {@link MediaItem MediaItems}.
*/
void setMediaItems(List This method does not execute the command.
*
* Executing a command that is not available (for example, calling {@link
* #seekToNextMediaItem()} if {@link #COMMAND_SEEK_TO_NEXT_MEDIA_ITEM} is unavailable) will
* neither throw an exception nor generate a {@link #getPlayerError()} player error}.
*
* {@link #COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM} and {@link #COMMAND_SEEK_TO_NEXT_MEDIA_ITEM}
* are unavailable if there is no such {@link MediaItem}.
*
* @param command A {@link Command}.
* @return Whether the {@link Command} is available.
* @see Listener#onAvailableCommandsChanged(Commands)
*/
boolean isCommandAvailable(@Command int command);
/** Returns whether the player can be used to advertise a media session. */
boolean canAdvertiseSession();
/**
* Returns the player's currently available {@link Commands}.
*
* 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.
*
* Executing a command that is not available (for example, calling {@link
* #seekToNextMediaItem()} if {@link #COMMAND_SEEK_TO_NEXT_MEDIA_ITEM} is unavailable) will
* neither throw an exception nor generate a {@link #getPlayerError()} player error}.
*
* {@link #COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM} and {@link #COMMAND_SEEK_TO_NEXT_MEDIA_ITEM}
* are unavailable if there is no such {@link MediaItem}.
*
* @return The currently available {@link Commands}.
* @see Listener#onAvailableCommandsChanged
*/
Commands getAvailableCommands();
/**
* Prepares the player.
*
* This will move the player out of {@link #STATE_IDLE idle state} and the player will start
* loading media and acquire resources needed for playback.
*/
void prepare();
/**
* Returns the current {@link State playback state} of the player.
*
* @return The current {@link State playback state}.
* @see Listener#onPlaybackStateChanged(int)
*/
@State
int getPlaybackState();
/**
* Returns the reason why playback is suppressed even though {@link #getPlayWhenReady()} is {@code
* true}, or {@link #PLAYBACK_SUPPRESSION_REASON_NONE} if playback is not suppressed.
*
* @return The current {@link PlaybackSuppressionReason playback suppression reason}.
* @see Listener#onPlaybackSuppressionReasonChanged(int)
*/
@PlaybackSuppressionReason
int getPlaybackSuppressionReason();
/**
* Returns whether the player is playing, i.e. {@link #getCurrentPosition()} is advancing.
*
* If {@code false}, then at least one of the following is true:
*
* Note that this method will always return {@code null} if {@link #getPlaybackState()} is not
* {@link #STATE_IDLE}.
*
* @return The error, or {@code null}.
* @see Listener#onPlayerError(PlaybackException)
*/
@Nullable
PlaybackException getPlayerError();
/**
* Resumes playback as soon as {@link #getPlaybackState()} == {@link #STATE_READY}. Equivalent to
* {@code setPlayWhenReady(true)}.
*/
void play();
/** Pauses playback. Equivalent to {@code setPlayWhenReady(false)}. */
void pause();
/**
* Sets whether playback should proceed when {@link #getPlaybackState()} == {@link #STATE_READY}.
*
* If the player is already in the ready state then this method pauses and resumes playback.
*
* @param playWhenReady Whether playback should proceed when ready.
*/
void setPlayWhenReady(boolean playWhenReady);
/**
* Whether playback will proceed when {@link #getPlaybackState()} == {@link #STATE_READY}.
*
* @return Whether playback will proceed when ready.
* @see Listener#onPlayWhenReadyChanged(boolean, int)
*/
boolean getPlayWhenReady();
/**
* Sets the {@link RepeatMode} to be used for playback.
*
* @param repeatMode The repeat mode.
*/
void setRepeatMode(@RepeatMode int repeatMode);
/**
* Returns the current {@link RepeatMode} used for playback.
*
* @return The current repeat mode.
* @see Listener#onRepeatModeChanged(int)
*/
@RepeatMode
int getRepeatMode();
/**
* Sets whether shuffling of media items is enabled.
*
* @param shuffleModeEnabled Whether shuffling is enabled.
*/
void setShuffleModeEnabled(boolean shuffleModeEnabled);
/**
* Returns whether shuffling of media items is enabled.
*
* @see Listener#onShuffleModeEnabledChanged(boolean)
*/
boolean getShuffleModeEnabled();
/**
* Whether the player is currently loading the source.
*
* @return Whether the player is currently loading the source.
* @see Listener#onIsLoadingChanged(boolean)
*/
boolean isLoading();
/**
* Seeks to the default position associated with the current {@link MediaItem}. The position can
* depend on the type of media being played. For live streams it will typically be the live edge.
* For other streams it will typically be the start.
*/
void seekToDefaultPosition();
/**
* Seeks to the default position associated with the specified {@link MediaItem}. The position can
* depend on the type of media being played. For live streams it will typically be the live edge.
* For other streams it will typically be the start.
*
* @param mediaItemIndex The index of the {@link MediaItem} whose associated default position
* should be seeked to.
* @throws IllegalSeekPositionException If the player has a non-empty timeline and the provided
* {@code mediaItemIndex} is not within the bounds of the current timeline.
*/
void seekToDefaultPosition(int mediaItemIndex);
/**
* Seeks to a position specified in milliseconds in the current {@link MediaItem}.
*
* @param positionMs The seek position in the current {@link MediaItem}, or {@link C#TIME_UNSET}
* to seek to the media item's default position.
*/
void seekTo(long positionMs);
/**
* Seeks to a position specified in milliseconds in the specified {@link MediaItem}.
*
* @param mediaItemIndex The index of the {@link MediaItem}.
* @param positionMs The seek position in the specified {@link MediaItem}, or {@link C#TIME_UNSET}
* to seek to the media item's default position.
* @throws IllegalSeekPositionException If the player has a non-empty timeline and the provided
* {@code mediaItemIndex} is not within the bounds of the current timeline.
*/
void seekTo(int mediaItemIndex, long positionMs);
/**
* Returns the {@link #seekBack()} increment.
*
* @return The seek back increment, in milliseconds.
* @see Listener#onSeekBackIncrementChanged(long)
*/
long getSeekBackIncrement();
/**
* Seeks back in the current {@link MediaItem} by {@link #getSeekBackIncrement()} milliseconds.
*/
void seekBack();
/**
* Returns the {@link #seekForward()} increment.
*
* @return The seek forward increment, in milliseconds.
* @see Listener#onSeekForwardIncrementChanged(long)
*/
long getSeekForwardIncrement();
/**
* Seeks forward in the current {@link MediaItem} by {@link #getSeekForwardIncrement()}
* milliseconds.
*/
void seekForward();
/** @deprecated Use {@link #hasPreviousMediaItem()} instead. */
@Deprecated
boolean hasPrevious();
/** @deprecated Use {@link #hasPreviousMediaItem()} instead. */
@Deprecated
boolean hasPreviousWindow();
/**
* 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 {@link #REPEAT_MODE_ONE}, this method behaves the same as when
* the current repeat mode is {@link #REPEAT_MODE_OFF}. See {@link #REPEAT_MODE_ONE} for more
* details.
*/
boolean hasPreviousMediaItem();
/** @deprecated Use {@link #seekToPreviousMediaItem()} instead. */
@Deprecated
void previous();
/** @deprecated Use {@link #seekToPreviousMediaItem()} instead. */
@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}.
*
* Note: When the repeat mode is {@link #REPEAT_MODE_ONE}, this method behaves the same as when
* the current repeat mode is {@link #REPEAT_MODE_OFF}. See {@link #REPEAT_MODE_ONE} for more
* details.
*/
void seekToPreviousMediaItem();
/**
* Returns the maximum position for which {@link #seekToPrevious()} seeks to the previous {@link
* MediaItem}, in milliseconds.
*
* @return The maximum seek to previous position, in milliseconds.
* @see Listener#onMaxSeekToPreviousPositionChanged(long)
*/
long getMaxSeekToPreviousPosition();
/**
* Seeks to an earlier position in the current or previous {@link MediaItem} (if available). More
* precisely:
*
* Note: When the repeat mode is {@link #REPEAT_MODE_ONE}, this method behaves the same as when
* the current repeat mode is {@link #REPEAT_MODE_OFF}. See {@link #REPEAT_MODE_ONE} for more
* details.
*/
boolean hasNextMediaItem();
/** @deprecated Use {@link #seekToNextMediaItem()} instead. */
@Deprecated
void next();
/** @deprecated Use {@link #seekToNextMediaItem()} instead. */
@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}.
*
* Note: When the repeat mode is {@link #REPEAT_MODE_ONE}, this method behaves the same as when
* the current repeat mode is {@link #REPEAT_MODE_OFF}. See {@link #REPEAT_MODE_ONE} for more
* details.
*/
void seekToNextMediaItem();
/**
* Seeks to a later position in the current or next {@link MediaItem} (if available). More
* precisely:
*
* Playback parameters changes may cause the player to buffer. {@link
* Listener#onPlaybackParametersChanged(PlaybackParameters)} will be called whenever the currently
* active playback parameters change.
*
* @param playbackParameters The playback parameters.
*/
void setPlaybackParameters(PlaybackParameters playbackParameters);
/**
* Changes the rate at which playback occurs. The pitch is not changed.
*
* This is equivalent to {@code
* setPlaybackParameters(getPlaybackParameters().withSpeed(speed))}.
*
* @param speed The linear factor by which playback will be sped up. Must be higher than 0. 1 is
* normal speed, 2 is twice as fast, 0.5 is half normal speed...
*/
void setPlaybackSpeed(@FloatRange(from = 0, fromInclusive = false) float speed);
/**
* Returns the currently active playback parameters.
*
* @see Listener#onPlaybackParametersChanged(PlaybackParameters)
*/
PlaybackParameters getPlaybackParameters();
/**
* Stops playback without resetting the playlist. Use {@link #pause()} rather than this method if
* the intention is to pause playback.
*
* 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.
*
* Calling this method does not clear the playlist, reset the playback position or the playback
* error.
*/
void stop();
/**
* @deprecated Use {@link #stop()} and {@link #clearMediaItems()} (if {@code reset} is true) or
* just {@link #stop()} (if {@code reset} is false). Any player error will be cleared when
* {@link #prepare() re-preparing} the player.
*/
@Deprecated
void stop(boolean reset);
/**
* Releases the player. This method must be called when the player is no longer required. The
* player must not be used after calling this method.
*/
void release();
/**
* Returns the available track groups.
*
* @see Listener#onTracksChanged(TrackGroupArray, TrackSelectionArray)
* @deprecated Use {@link #getCurrentTracksInfo()}.
*/
@Deprecated
TrackGroupArray getCurrentTrackGroups();
/**
* Returns the current track selections.
*
* A concrete implementation may include null elements if it has a fixed number of renderer
* components, wishes to report a TrackSelection for each of them, and has one or more renderer
* components that is not assigned any selected tracks.
*
* @see Listener#onTracksChanged(TrackGroupArray, TrackSelectionArray)
* @deprecated Use {@link #getCurrentTracksInfo()}.
*/
@Deprecated
TrackSelectionArray getCurrentTrackSelections();
/**
* Returns the available tracks, as well as the tracks' support, type, and selection status.
*
* @see Listener#onTracksChanged(TrackGroupArray, TrackSelectionArray)
*/
TracksInfo getCurrentTracksInfo();
/**
* Returns the parameters constraining the track selection.
*
* @see Listener#onTrackSelectionParametersChanged}
*/
TrackSelectionParameters getTrackSelectionParameters();
/**
* Sets the parameters constraining the track selection.
*
* Unsupported parameters will be silently ignored.
*
* Use {@link #getTrackSelectionParameters()} to retrieve the current parameters. For example,
* the following snippet restricts video to SD whilst keep other track selection parameters
* unchanged:
*
* This {@link MediaMetadata} is a combination of the {@link MediaItem#mediaMetadata} and the
* static and dynamic metadata from the {@link TrackSelection#getFormat(int) track selections'
* formats} and {@link Listener#onMetadata(Metadata)}. If a field is populated in the {@link
* MediaItem#mediaMetadata}, it will be prioritised above the same field coming from static or
* dynamic metadata.
*/
MediaMetadata getMediaMetadata();
/**
* Returns the playlist {@link MediaMetadata}, as set by {@link
* #setPlaylistMetadata(MediaMetadata)}, or {@link MediaMetadata#EMPTY} if not supported.
*/
MediaMetadata getPlaylistMetadata();
/** Sets the playlist {@link MediaMetadata}. */
void setPlaylistMetadata(MediaMetadata mediaMetadata);
/**
* Returns the current manifest. The type depends on the type of media being played. May be null.
*/
@Nullable
Object getCurrentManifest();
/**
* Returns the current {@link Timeline}. Never null, but may be empty.
*
* @see Listener#onTimelineChanged(Timeline, int)
*/
Timeline getCurrentTimeline();
/** Returns the index of the period currently being played. */
int getCurrentPeriodIndex();
/** @deprecated Use {@link #getCurrentMediaItemIndex()} instead. */
@Deprecated
int getCurrentWindowIndex();
/**
* Returns the index of the current {@link MediaItem} in the {@link #getCurrentTimeline()
* timeline}, or the prospective index if the {@link #getCurrentTimeline() current timeline} is
* empty.
*/
int getCurrentMediaItemIndex();
/** @deprecated Use {@link #getNextMediaItemIndex()} instead. */
@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}.
*
* Note: When the repeat mode is {@link #REPEAT_MODE_ONE}, this method behaves the same as when
* the current repeat mode is {@link #REPEAT_MODE_OFF}. See {@link #REPEAT_MODE_ONE} for more
* details.
*/
int getNextMediaItemIndex();
/** @deprecated Use {@link #getPreviousMediaItemIndex()} instead. */
@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}.
*
* Note: When the repeat mode is {@link #REPEAT_MODE_ONE}, this method behaves the same as when
* the current repeat mode is {@link #REPEAT_MODE_OFF}. See {@link #REPEAT_MODE_ONE} for more
* details.
*/
int getPreviousMediaItemIndex();
/**
* Returns the currently playing {@link MediaItem}. May be null if the timeline is empty.
*
* @see Listener#onMediaItemTransition(MediaItem, int)
*/
@Nullable
MediaItem getCurrentMediaItem();
/** Returns the number of {@link MediaItem media items} in the playlist. */
int getMediaItemCount();
/** Returns the {@link MediaItem} at the given index. */
MediaItem getMediaItemAt(int index);
/**
* Returns the duration of the current content or ad in milliseconds, or {@link C#TIME_UNSET} if
* the duration is not known.
*/
long getDuration();
/**
* Returns the playback position in the current content or ad, in milliseconds, or the prospective
* position in milliseconds if the {@link #getCurrentTimeline() current timeline} is empty.
*/
long getCurrentPosition();
/**
* Returns an estimate of the position in the current content or ad up to which data is buffered,
* in milliseconds.
*/
long getBufferedPosition();
/**
* Returns an estimate of the percentage in the current content or ad up to which data is
* buffered, or 0 if no estimate is available.
*/
@IntRange(from = 0, to = 100)
int getBufferedPercentage();
/**
* Returns an estimate of the total buffered duration from the current position, in milliseconds.
* This includes pre-buffered data for subsequent ads and {@link MediaItem media items}.
*/
long getTotalBufferedDuration();
/** @deprecated Use {@link #isCurrentMediaItemDynamic()} instead. */
@Deprecated
boolean isCurrentWindowDynamic();
/**
* Returns whether the current {@link MediaItem} is dynamic (may change when the {@link Timeline}
* is updated), or {@code false} if the {@link Timeline} is empty.
*
* @see Timeline.Window#isDynamic
*/
boolean isCurrentMediaItemDynamic();
/** @deprecated Use {@link #isCurrentMediaItemLive()} instead. */
@Deprecated
boolean isCurrentWindowLive();
/**
* Returns whether the current {@link MediaItem} is live, or {@code false} if the {@link Timeline}
* is empty.
*
* @see Timeline.Window#isLive()
*/
boolean isCurrentMediaItemLive();
/**
* Returns the offset of the current playback position from the live edge in milliseconds, or
* {@link C#TIME_UNSET} if the current {@link MediaItem} {@link #isCurrentMediaItemLive()} isn't
* live} or the offset is unknown.
*
* The offset is calculated as {@code 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.
*/
long getCurrentLiveOffset();
/** @deprecated Use {@link #isCurrentMediaItemSeekable()} instead. */
@Deprecated
boolean isCurrentWindowSeekable();
/**
* Returns whether the current {@link MediaItem} is seekable, or {@code false} if the {@link
* Timeline} is empty.
*
* @see Timeline.Window#isSeekable
*/
boolean isCurrentMediaItemSeekable();
/** Returns whether the player is currently playing an ad. */
boolean isPlayingAd();
/**
* If {@link #isPlayingAd()} returns true, returns the index of the ad group in the period
* currently being played. Returns {@link C#INDEX_UNSET} otherwise.
*/
int getCurrentAdGroupIndex();
/**
* If {@link #isPlayingAd()} returns true, returns the index of the ad in its ad group. Returns
* {@link C#INDEX_UNSET} otherwise.
*/
int getCurrentAdIndexInAdGroup();
/**
* If {@link #isPlayingAd()} returns {@code true}, returns the duration of the current content in
* milliseconds, or {@link C#TIME_UNSET} if the duration is not known. If there is no ad playing,
* the returned duration is the same as that returned by {@link #getDuration()}.
*/
long getContentDuration();
/**
* If {@link #isPlayingAd()} returns {@code true}, returns the content position that will be
* played once all ads in the ad group have finished playing, in milliseconds. If there is no ad
* playing, the returned position is the same as that returned by {@link #getCurrentPosition()}.
*/
long getContentPosition();
/**
* If {@link #isPlayingAd()} returns {@code true}, returns an estimate of the content position in
* the current content up to which data is buffered, in milliseconds. If there is no ad playing,
* the returned position is the same as that returned by {@link #getBufferedPosition()}.
*/
long getContentBufferedPosition();
/** Returns the attributes for audio playback. */
AudioAttributes getAudioAttributes();
/**
* Sets the audio volume, valid values are between 0 (silence) and 1 (unity gain, signal
* unchanged), inclusive.
*
* @param volume Linear output gain to apply to all audio channels.
*/
void setVolume(@FloatRange(from = 0, to = 1.0) float volume);
/**
* Returns the audio volume, with 0 being silence and 1 being unity gain (signal unchanged).
*
* @return The linear gain applied to all audio channels.
*/
@FloatRange(from = 0, to = 1.0)
float getVolume();
/**
* Clears any {@link Surface}, {@link SurfaceHolder}, {@link SurfaceView} or {@link TextureView}
* currently set on the player.
*/
void clearVideoSurface();
/**
* Clears the {@link Surface} onto which video is being rendered if it matches the one passed.
* Else does nothing.
*
* @param surface The surface to clear.
*/
void clearVideoSurface(@Nullable Surface surface);
/**
* Sets the {@link Surface} onto which video will be rendered. The caller is responsible for
* tracking the lifecycle of the surface, and must clear the surface by calling {@code
* setVideoSurface(null)} if the surface is destroyed.
*
* If the surface is held by a {@link SurfaceView}, {@link TextureView} or {@link
* SurfaceHolder} then it's recommended to use {@link #setVideoSurfaceView(SurfaceView)}, {@link
* #setVideoTextureView(TextureView)} or {@link #setVideoSurfaceHolder(SurfaceHolder)} rather than
* this method, since passing the holder allows the player to track the lifecycle of the surface
* automatically.
*
* @param surface The {@link Surface}.
*/
void setVideoSurface(@Nullable Surface surface);
/**
* Sets the {@link SurfaceHolder} that holds the {@link Surface} onto which video will be
* rendered. The player will track the lifecycle of the surface automatically.
*
* The thread that calls the {@link SurfaceHolder.Callback} methods must be the thread
* associated with {@link #getApplicationLooper()}.
*
* @param surfaceHolder The surface holder.
*/
void setVideoSurfaceHolder(@Nullable SurfaceHolder surfaceHolder);
/**
* Clears the {@link SurfaceHolder} that holds the {@link Surface} onto which video is being
* rendered if it matches the one passed. Else does nothing.
*
* @param surfaceHolder The surface holder to clear.
*/
void clearVideoSurfaceHolder(@Nullable SurfaceHolder surfaceHolder);
/**
* Sets the {@link SurfaceView} onto which video will be rendered. The player will track the
* lifecycle of the surface automatically.
*
* The thread that calls the {@link SurfaceHolder.Callback} methods must be the thread
* associated with {@link #getApplicationLooper()}.
*
* @param surfaceView The surface view.
*/
void setVideoSurfaceView(@Nullable SurfaceView surfaceView);
/**
* Clears the {@link SurfaceView} onto which video is being rendered if it matches the one passed.
* Else does nothing.
*
* @param surfaceView The texture view to clear.
*/
void clearVideoSurfaceView(@Nullable SurfaceView surfaceView);
/**
* Sets the {@link TextureView} onto which video will be rendered. The player will track the
* lifecycle of the surface automatically.
*
* The thread that calls the {@link TextureView.SurfaceTextureListener} methods must be the
* thread associated with {@link #getApplicationLooper()}.
*
* @param textureView The texture view.
*/
void setVideoTextureView(@Nullable TextureView textureView);
/**
* Clears the {@link TextureView} onto which video is being rendered if it matches the one passed.
* Else does nothing.
*
* @param textureView The texture view to clear.
*/
void clearVideoTextureView(@Nullable TextureView textureView);
/**
* Gets the size of the video.
*
* The video's width and height are {@code 0} if there is no video or its size has not been
* determined yet.
*
* @see Listener#onVideoSizeChanged(VideoSize)
*/
VideoSize getVideoSize();
/** Returns the current {@link Cue Cues}. This list may be empty. */
List 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)}.
*
* For devices with {@link DeviceInfo#PLAYBACK_TYPE_REMOTE remote playback}, the volume of the
* remote device is returned.
*/
@IntRange(from = 0)
int getDeviceVolume();
/** Gets whether the device is muted or not. */
boolean isDeviceMuted();
/**
* Sets the volume of the device.
*
* @param volume The volume to set.
*/
void setDeviceVolume(@IntRange(from = 0) int volume);
/** Increases the volume of the device. */
void increaseDeviceVolume();
/** Decreases the volume of the device. */
void decreaseDeviceVolume();
/** Sets the mute state of the device. */
void setDeviceMuted(boolean muted);
}
*
*
* @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.
*
*
*
*/
void seekToPrevious();
/** @deprecated Use {@link #hasNextMediaItem()} instead. */
@Deprecated
boolean hasNext();
/** @deprecated Use {@link #hasNextMediaItem()} instead. */
@Deprecated
boolean hasNextWindow();
/**
* Returns whether a next {@link MediaItem} exists, which may depend on the current repeat mode
* and whether shuffle mode is enabled.
*
*
*
*
*
*/
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.
*
* {@code
* player.setTrackSelectionParameters(
* player.getTrackSelectionParameters()
* .buildUpon()
* .setMaxVideoSizeSd()
* .build())
* }
*/
void setTrackSelectionParameters(TrackSelectionParameters parameters);
/**
* Returns the current combined {@link MediaMetadata}, or {@link MediaMetadata#EMPTY} if not
* supported.
*
*