/* * 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: * *

*/ public interface Player { /** * Listener of changes in player state. * *

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: * *

* * @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) {} } /** A set of {@link Event events}. */ final class Events { private final FlagSet flags; /** * Creates an instance. * * @param flags The {@link FlagSet} containing the {@link Event events}. */ public Events(FlagSet flags) { this.flags = flags; } /** * Returns whether the given {@link Event} occurred. * * @param event The {@link Event}. * @return Whether the {@link Event} occurred. */ public boolean contains(@Event int event) { return flags.contains(event); } /** * Returns whether any of the given {@link Event events} occurred. * * @param events The {@link Event events}. * @return Whether any of the {@link Event events} occurred. */ public boolean containsAny(@Event int... events) { return flags.containsAny(events); } /** Returns the number of events in the set. */ public int size() { return flags.size(); } /** * Returns the {@link Event} at the given index. * *

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 CREATOR = PositionInfo::fromBundle; private static PositionInfo fromBundle(Bundle bundle) { int mediaItemIndex = bundle.getInt(keyForField(FIELD_MEDIA_ITEM_INDEX), /* defaultValue= */ C.INDEX_UNSET); @Nullable MediaItem mediaItem = BundleableUtil.fromNullableBundle( MediaItem.CREATOR, bundle.getBundle(keyForField(FIELD_MEDIA_ITEM))); int periodIndex = bundle.getInt(keyForField(FIELD_PERIOD_INDEX), /* defaultValue= */ C.INDEX_UNSET); long positionMs = bundle.getLong(keyForField(FIELD_POSITION_MS), /* defaultValue= */ C.TIME_UNSET); long contentPositionMs = bundle.getLong(keyForField(FIELD_CONTENT_POSITION_MS), /* defaultValue= */ C.TIME_UNSET); int adGroupIndex = bundle.getInt(keyForField(FIELD_AD_GROUP_INDEX), /* defaultValue= */ C.INDEX_UNSET); int adIndexInAdGroup = bundle.getInt(keyForField(FIELD_AD_INDEX_IN_AD_GROUP), /* defaultValue= */ C.INDEX_UNSET); return new PositionInfo( /* windowUid= */ null, mediaItemIndex, mediaItem, /* periodUid= */ null, periodIndex, positionMs, contentPositionMs, adGroupIndex, adIndexInAdGroup); } private static String keyForField(@FieldNumber int field) { return Integer.toString(field, Character.MAX_RADIX); } } /** * A set of {@link Command commands}. * *

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 commandsBundle = new ArrayList<>(); for (int i = 0; i < flags.size(); i++) { commandsBundle.add(flags.get(i)); } bundle.putIntegerArrayList(keyForField(FIELD_COMMANDS), commandsBundle); return bundle; } /** Object that can restore {@link Commands} from a {@link Bundle}. */ public static final Creator CREATOR = Commands::fromBundle; private static Commands fromBundle(Bundle bundle) { @Nullable ArrayList commands = bundle.getIntegerArrayList(keyForField(FIELD_COMMANDS)); if (commands == null) { return Commands.EMPTY; } Builder builder = new Builder(); for (int i = 0; i < commands.size(); i++) { builder.add(commands.get(i)); } return builder.build(); } private static String keyForField(@FieldNumber int field) { return Integer.toString(field, Character.MAX_RADIX); } } /** * Listener of all changes in the Player. * *

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 cues) {} /** * Called when there is metadata associated with the current playback time. * * @param metadata The metadata. */ default void onMetadata(Metadata metadata) {} @Override default void onMediaMetadataChanged(MediaMetadata mediaMetadata) {} @Override default void onPlaylistMetadataChanged(MediaMetadata mediaMetadata) {} } /** * Playback state. One of {@link #STATE_IDLE}, {@link #STATE_BUFFERING}, {@link #STATE_READY} or * {@link #STATE_ENDED}. */ @Documented @Retention(RetentionPolicy.SOURCE) @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE}) @IntDef({STATE_IDLE, STATE_BUFFERING, STATE_READY, STATE_ENDED}) @interface State {} /** * The player is idle, meaning it holds only limited resources. The player must be {@link * #prepare() prepared} before it will play the media. */ int STATE_IDLE = 1; /** * The player is not able to immediately play the media, but is doing work toward being able to do * so. This state typically occurs when the player needs to buffer more data before playback can * start. */ int STATE_BUFFERING = 2; /** * The player is able to immediately play from its current position. The player will be playing if * {@link #getPlayWhenReady()} is true, and paused otherwise. */ int STATE_READY = 3; /** The player has finished playing the media. */ int STATE_ENDED = 4; /** * Reasons for {@link #getPlayWhenReady() playWhenReady} changes. One of {@link * #PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST}, {@link * #PLAY_WHEN_READY_CHANGE_REASON_AUDIO_FOCUS_LOSS}, {@link * #PLAY_WHEN_READY_CHANGE_REASON_AUDIO_BECOMING_NOISY}, {@link * #PLAY_WHEN_READY_CHANGE_REASON_REMOTE} or {@link * #PLAY_WHEN_READY_CHANGE_REASON_END_OF_MEDIA_ITEM}. */ @Documented @Retention(RetentionPolicy.SOURCE) @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE}) @IntDef({ PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST, PLAY_WHEN_READY_CHANGE_REASON_AUDIO_FOCUS_LOSS, PLAY_WHEN_READY_CHANGE_REASON_AUDIO_BECOMING_NOISY, PLAY_WHEN_READY_CHANGE_REASON_REMOTE, PLAY_WHEN_READY_CHANGE_REASON_END_OF_MEDIA_ITEM }) @interface PlayWhenReadyChangeReason {} /** Playback has been started or paused by a call to {@link #setPlayWhenReady(boolean)}. */ int PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST = 1; /** Playback has been paused because of a loss of audio focus. */ int PLAY_WHEN_READY_CHANGE_REASON_AUDIO_FOCUS_LOSS = 2; /** Playback has been paused to avoid becoming noisy. */ int PLAY_WHEN_READY_CHANGE_REASON_AUDIO_BECOMING_NOISY = 3; /** Playback has been started or paused because of a remote change. */ int PLAY_WHEN_READY_CHANGE_REASON_REMOTE = 4; /** Playback has been paused at the end of a media item. */ int PLAY_WHEN_READY_CHANGE_REASON_END_OF_MEDIA_ITEM = 5; /** * Reason why playback is suppressed even though {@link #getPlayWhenReady()} is {@code true}. One * of {@link #PLAYBACK_SUPPRESSION_REASON_NONE} or {@link * #PLAYBACK_SUPPRESSION_REASON_TRANSIENT_AUDIO_FOCUS_LOSS}. */ @Documented @Retention(RetentionPolicy.SOURCE) @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE}) @IntDef({ PLAYBACK_SUPPRESSION_REASON_NONE, PLAYBACK_SUPPRESSION_REASON_TRANSIENT_AUDIO_FOCUS_LOSS }) @interface PlaybackSuppressionReason {} /** Playback is not suppressed. */ int PLAYBACK_SUPPRESSION_REASON_NONE = 0; /** Playback is suppressed due to transient audio focus loss. */ int PLAYBACK_SUPPRESSION_REASON_TRANSIENT_AUDIO_FOCUS_LOSS = 1; /** * Repeat modes for playback. One of {@link #REPEAT_MODE_OFF}, {@link #REPEAT_MODE_ONE} or {@link * #REPEAT_MODE_ALL}. */ @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}. */ @Documented @Retention(RetentionPolicy.SOURCE) @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE}) @IntDef({ DISCONTINUITY_REASON_AUTO_TRANSITION, DISCONTINUITY_REASON_SEEK, DISCONTINUITY_REASON_SEEK_ADJUSTMENT, DISCONTINUITY_REASON_SKIP, DISCONTINUITY_REASON_REMOVE, DISCONTINUITY_REASON_INTERNAL }) @interface DiscontinuityReason {} /** * Automatic playback transition from one period in the timeline to the next. The period index may * be the same as it was before the discontinuity in case the current period is repeated. * *

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 mediaItems); /** * Clears the playlist and adds the specified {@link MediaItem MediaItems}. * * @param mediaItems The new {@link MediaItem MediaItems}. * @param resetPosition Whether the playback position should be reset to the default position in * the first {@link Timeline.Window}. If false, playback will start from the position defined * by {@link #getCurrentMediaItemIndex()} and {@link #getCurrentPosition()}. */ void setMediaItems(List mediaItems, boolean resetPosition); /** * Clears the playlist and adds the specified {@link MediaItem MediaItems}. * * @param mediaItems The new {@link MediaItem MediaItems}. * @param startIndex The {@link MediaItem} index to start playback from. If {@link C#INDEX_UNSET} * is passed, the current position is not reset. * @param startPositionMs The position in milliseconds to start playback from. If {@link * C#TIME_UNSET} is passed, the default position of the given {@link MediaItem} is used. In * any case, if {@code startIndex} is set to {@link C#INDEX_UNSET}, this parameter is ignored * and the position is not reset at all. * @throws IllegalSeekPositionException If the provided {@code startIndex} is not within the * bounds of the list of media items. */ void setMediaItems(List mediaItems, int startIndex, long startPositionMs); /** * Clears the playlist, adds the specified {@link MediaItem} and resets the position to the * default position. * * @param mediaItem The new {@link MediaItem}. */ void setMediaItem(MediaItem mediaItem); /** * Clears the playlist and adds the specified {@link MediaItem}. * * @param mediaItem The new {@link MediaItem}. * @param startPositionMs The position in milliseconds to start playback from. */ void setMediaItem(MediaItem mediaItem, long startPositionMs); /** * Clears the playlist and adds the specified {@link MediaItem}. * * @param mediaItem The new {@link MediaItem}. * @param resetPosition Whether the playback position should be reset to the default position. If * false, playback will start from the position defined by {@link #getCurrentMediaItemIndex()} * and {@link #getCurrentPosition()}. */ void setMediaItem(MediaItem mediaItem, boolean resetPosition); /** * Adds a media item to the end of the playlist. * * @param mediaItem The {@link MediaItem} to add. */ void addMediaItem(MediaItem mediaItem); /** * Adds a media item at the given index of the playlist. * * @param index The index at which to add the media item. If the index is larger than the size of * the playlist, the media item is added to the end of the playlist. * @param mediaItem The {@link MediaItem} to add. */ void addMediaItem(int index, MediaItem mediaItem); /** * Adds a list of media items to the end of the playlist. * * @param mediaItems The {@link MediaItem MediaItems} to add. */ void addMediaItems(List mediaItems); /** * Adds a list of media items at the given index of the playlist. * * @param index The index at which to add the media items. If the index is larger than the size of * the playlist, the media items are added to the end of the playlist. * @param mediaItems The {@link MediaItem MediaItems} to add. */ void addMediaItems(int index, List mediaItems); /** * Moves the media item at the current index to the new index. * * @param currentIndex The current index of the media item to move. * @param newIndex The new index of the media item. If the new index is larger than the size of * the playlist the item is moved to the end of the playlist. */ void moveMediaItem(int currentIndex, int newIndex); /** * Moves the media item range to the new index. * * @param fromIndex The start of the range to move. * @param toIndex The first item not to be included in the range (exclusive). * @param newIndex The new index of the first media item of the range. If the new index is larger * than the size of the remaining playlist after removing the range, the range is moved to the * end of the playlist. */ void moveMediaItems(int fromIndex, int toIndex, int newIndex); /** * Removes the media item at the given index of the playlist. * * @param index The index at which to remove the media item. */ void removeMediaItem(int index); /** * Removes a range of media items from the playlist. * * @param fromIndex The index at which to start removing media items. * @param toIndex The index of the first item to be kept (exclusive). If the index is larger than * the size of the playlist, media items to the end of the playlist are removed. */ void removeMediaItems(int fromIndex, int toIndex); /** Clears the playlist. */ void clearMediaItems(); /** * Returns whether the provided {@link Command} is available. * *

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: * *

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

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: * *

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

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: * *

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

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: * *

{@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. * *

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 getCurrentCues(); /** Gets the device information. */ DeviceInfo getDeviceInfo(); /** * Gets the current volume of the device. * *

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); }