public abstract class

BasePlayer

extends java.lang.Object

implements Player

 java.lang.Object

↳androidx.media3.common.BasePlayer

Subclasses:

SimpleExoPlayer, StubPlayer, StubExoPlayer, SimpleBasePlayer, ForwardingSimpleBasePlayer, CastPlayer, CompositionPlayer

Gradle dependencies

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

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

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

Overview

Abstract base Player which implements common implementation independent methods.

Summary

Fields
protected final Timeline.Windowwindow

Constructors
protectedBasePlayer()

Methods
public final voidaddMediaItem(int index, MediaItem mediaItem)

public final voidaddMediaItem(MediaItem mediaItem)

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

public final booleancanAdvertiseSession()

public final voidclearMediaItems()

public final intgetBufferedPercentage()

public final longgetContentDuration()

public final longgetCurrentLiveOffset()

public final java.lang.ObjectgetCurrentManifest()

public final MediaItemgetCurrentMediaItem()

public final intgetCurrentWindowIndex()

public final MediaItemgetMediaItemAt(int index)

public final intgetMediaItemCount()

public final intgetNextMediaItemIndex()

public final intgetNextWindowIndex()

public final intgetPreviousMediaItemIndex()

public final intgetPreviousWindowIndex()

public final booleanhasNext()

public final booleanhasNextMediaItem()

public final booleanhasNextWindow()

public final booleanhasPreviousMediaItem()

public final booleanisCommandAvailable(int command)

public final booleanisCurrentMediaItemDynamic()

public final booleanisCurrentMediaItemLive()

public final booleanisCurrentMediaItemSeekable()

public final booleanisCurrentWindowDynamic()

public final booleanisCurrentWindowLive()

public final booleanisCurrentWindowSeekable()

public final booleanisPlaying()

public final voidmoveMediaItem(int currentIndex, int newIndex)

public final voidnext()

public final voidpause()

public final voidplay()

public final voidremoveMediaItem(int index)

public final voidreplaceMediaItem(int index, MediaItem mediaItem)

public final voidseekBack()

public final voidseekForward()

public final voidseekTo(int mediaItemIndex, long positionMs)

public abstract voidseekTo(int mediaItemIndex, long positionMs, int seekCommand, boolean isRepeatingCurrentItem)

Seeks to a position in the specified MediaItem.

public final voidseekTo(long positionMs)

public final voidseekToDefaultPosition()

public final voidseekToDefaultPosition(int mediaItemIndex)

public final voidseekToNext()

public final voidseekToNextMediaItem()

public final voidseekToNextWindow()

public final voidseekToPrevious()

public final voidseekToPreviousMediaItem()

public final voidseekToPreviousWindow()

public final voidsetMediaItem(MediaItem mediaItem)

public final voidsetMediaItem(MediaItem mediaItem, boolean resetPosition)

public final voidsetMediaItem(MediaItem mediaItem, long startPositionMs)

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

public final voidsetPlaybackSpeed(float speed)

from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Fields

protected final Timeline.Window window

Constructors

protected BasePlayer()

Methods

public final void setMediaItem(MediaItem mediaItem)

public final void setMediaItem(MediaItem mediaItem, long startPositionMs)

public final void setMediaItem(MediaItem mediaItem, boolean resetPosition)

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

public final void addMediaItem(int index, MediaItem mediaItem)

public final void addMediaItem(MediaItem mediaItem)

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

public final void moveMediaItem(int currentIndex, int newIndex)

public final void replaceMediaItem(int index, MediaItem mediaItem)

public final void removeMediaItem(int index)

public final void clearMediaItems()

public final boolean isCommandAvailable(int command)

public final boolean canAdvertiseSession()

BasePlayer and its descendants will return true.

public final void play()

public final void pause()

public final boolean isPlaying()

public final void seekToDefaultPosition()

public final void seekToDefaultPosition(int mediaItemIndex)

public final void seekBack()

public final void seekForward()

public final boolean hasPreviousMediaItem()

public final void seekToPreviousWindow()

Deprecated: Use BasePlayer.seekToPreviousMediaItem() instead.

public final void seekToPreviousMediaItem()

public final void seekToPrevious()

public final boolean hasNext()

Deprecated: Use BasePlayer.hasNextMediaItem() instead.

public final boolean hasNextWindow()

Deprecated: Use BasePlayer.hasNextMediaItem() instead.

public final boolean hasNextMediaItem()

public final void next()

Deprecated: Use BasePlayer.seekToNextMediaItem() instead.

public final void seekToNextWindow()

Deprecated: Use BasePlayer.seekToNextMediaItem() instead.

public final void seekToNextMediaItem()

public final void seekToNext()

public final void seekTo(long positionMs)

public final void seekTo(int mediaItemIndex, long positionMs)

public abstract void seekTo(int mediaItemIndex, long positionMs, int seekCommand, boolean isRepeatingCurrentItem)

Seeks to a position in the specified MediaItem.

Parameters:

mediaItemIndex: The index of the MediaItem. If the original seek operation did not directly specify an index, this is the most likely implied index based on the available player state. If the implied action is to do nothing, this will be C.INDEX_UNSET.
positionMs: The seek position in the specified MediaItem in milliseconds, or C.TIME_UNSET to seek to the media item's default position. If the original seek operation did not directly specify a position, this is the most likely implied position based on the available player state.
seekCommand: The Player.Command used to trigger the seek.
isRepeatingCurrentItem: Whether this seeks repeats the current item.

public final void setPlaybackSpeed(float speed)

public final int getCurrentWindowIndex()

Deprecated: Use Player.getCurrentMediaItemIndex() instead.

public final int getNextWindowIndex()

Deprecated: Use BasePlayer.getNextMediaItemIndex() instead.

public final int getNextMediaItemIndex()

public final int getPreviousWindowIndex()

Deprecated: Use BasePlayer.getPreviousMediaItemIndex() instead.

public final int getPreviousMediaItemIndex()

public final MediaItem getCurrentMediaItem()

public final int getMediaItemCount()

public final MediaItem getMediaItemAt(int index)

public final java.lang.Object getCurrentManifest()

public final int getBufferedPercentage()

public final boolean isCurrentWindowDynamic()

Deprecated: Use BasePlayer.isCurrentMediaItemDynamic() instead.

public final boolean isCurrentMediaItemDynamic()

public final boolean isCurrentWindowLive()

Deprecated: Use BasePlayer.isCurrentMediaItemLive() instead.

public final boolean isCurrentMediaItemLive()

public final long getCurrentLiveOffset()

public final boolean isCurrentWindowSeekable()

Deprecated: Use BasePlayer.isCurrentMediaItemSeekable() instead.

public final boolean isCurrentMediaItemSeekable()

public final long getContentDuration()

Source

/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package androidx.media3.common;

import static androidx.annotation.VisibleForTesting.PROTECTED;
import static java.lang.Math.max;
import static java.lang.Math.min;

import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import com.google.common.collect.ImmutableList;
import java.util.List;

/** Abstract base {@link Player} which implements common implementation independent methods. */
@UnstableApi
public abstract class BasePlayer implements Player {

  protected final Timeline.Window window;

  protected BasePlayer() {
    window = new Timeline.Window();
  }

  @Override
  public final void setMediaItem(MediaItem mediaItem) {
    setMediaItems(ImmutableList.of(mediaItem));
  }

  @Override
  public final void setMediaItem(MediaItem mediaItem, long startPositionMs) {
    setMediaItems(ImmutableList.of(mediaItem), /* startIndex= */ 0, startPositionMs);
  }

  @Override
  public final void setMediaItem(MediaItem mediaItem, boolean resetPosition) {
    setMediaItems(ImmutableList.of(mediaItem), resetPosition);
  }

  @Override
  public final void setMediaItems(List<MediaItem> mediaItems) {
    setMediaItems(mediaItems, /* resetPosition= */ true);
  }

  @Override
  public final void addMediaItem(int index, MediaItem mediaItem) {
    addMediaItems(index, ImmutableList.of(mediaItem));
  }

  @Override
  public final void addMediaItem(MediaItem mediaItem) {
    addMediaItems(ImmutableList.of(mediaItem));
  }

  @Override
  public final void addMediaItems(List<MediaItem> mediaItems) {
    addMediaItems(/* index= */ Integer.MAX_VALUE, mediaItems);
  }

  @Override
  public final void moveMediaItem(int currentIndex, int newIndex) {
    if (currentIndex != newIndex) {
      moveMediaItems(/* fromIndex= */ currentIndex, /* toIndex= */ currentIndex + 1, newIndex);
    }
  }

  @Override
  public final void replaceMediaItem(int index, MediaItem mediaItem) {
    replaceMediaItems(
        /* fromIndex= */ index, /* toIndex= */ index + 1, ImmutableList.of(mediaItem));
  }

  @Override
  public final void removeMediaItem(int index) {
    removeMediaItems(/* fromIndex= */ index, /* toIndex= */ index + 1);
  }

  @Override
  public final void clearMediaItems() {
    removeMediaItems(/* fromIndex= */ 0, /* toIndex= */ Integer.MAX_VALUE);
  }

  @Override
  public final boolean isCommandAvailable(@Command int command) {
    return getAvailableCommands().contains(command);
  }

  /**
   * {@inheritDoc}
   *
   * <p>BasePlayer and its descendants will return {@code true}.
   */
  @Override
  public final boolean canAdvertiseSession() {
    return true;
  }

  @Override
  public final void play() {
    setPlayWhenReady(true);
  }

  @Override
  public final void pause() {
    setPlayWhenReady(false);
  }

  @Override
  public final boolean isPlaying() {
    return getPlaybackState() == Player.STATE_READY
        && getPlayWhenReady()
        && getPlaybackSuppressionReason() == PLAYBACK_SUPPRESSION_REASON_NONE;
  }

  @Override
  public final void seekToDefaultPosition() {
    seekToDefaultPositionInternal(
        getCurrentMediaItemIndex(), Player.COMMAND_SEEK_TO_DEFAULT_POSITION);
  }

  @Override
  public final void seekToDefaultPosition(int mediaItemIndex) {
    seekToDefaultPositionInternal(mediaItemIndex, Player.COMMAND_SEEK_TO_MEDIA_ITEM);
  }

  @Override
  public final void seekBack() {
    seekToOffset(-getSeekBackIncrement(), Player.COMMAND_SEEK_BACK);
  }

  @Override
  public final void seekForward() {
    seekToOffset(getSeekForwardIncrement(), Player.COMMAND_SEEK_FORWARD);
  }

  @Override
  public final boolean hasPreviousMediaItem() {
    return getPreviousMediaItemIndex() != C.INDEX_UNSET;
  }

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

  @Override
  public final void seekToPreviousMediaItem() {
    seekToPreviousMediaItemInternal(Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM);
  }

  @Override
  public final void seekToPrevious() {
    Timeline timeline = getCurrentTimeline();
    if (timeline.isEmpty() || isPlayingAd()) {
      ignoreSeek(Player.COMMAND_SEEK_TO_PREVIOUS);
      return;
    }
    boolean hasPreviousMediaItem = hasPreviousMediaItem();
    if (isCurrentMediaItemLive() && !isCurrentMediaItemSeekable()) {
      if (hasPreviousMediaItem) {
        seekToPreviousMediaItemInternal(Player.COMMAND_SEEK_TO_PREVIOUS);
      } else {
        ignoreSeek(Player.COMMAND_SEEK_TO_PREVIOUS);
      }
    } else if (hasPreviousMediaItem && getCurrentPosition() <= getMaxSeekToPreviousPosition()) {
      seekToPreviousMediaItemInternal(Player.COMMAND_SEEK_TO_PREVIOUS);
    } else {
      seekToCurrentItem(/* positionMs= */ 0, Player.COMMAND_SEEK_TO_PREVIOUS);
    }
  }

  /**
   * @deprecated Use {@link #hasNextMediaItem()} instead.
   */
  @Deprecated
  @Override
  public final boolean hasNext() {
    return hasNextMediaItem();
  }

  /**
   * @deprecated Use {@link #hasNextMediaItem()} instead.
   */
  @Deprecated
  @Override
  public final boolean hasNextWindow() {
    return hasNextMediaItem();
  }

  @Override
  public final boolean hasNextMediaItem() {
    return getNextMediaItemIndex() != C.INDEX_UNSET;
  }

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

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

  @Override
  public final void seekToNextMediaItem() {
    seekToNextMediaItemInternal(Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM);
  }

  @Override
  public final void seekToNext() {
    Timeline timeline = getCurrentTimeline();
    if (timeline.isEmpty() || isPlayingAd()) {
      ignoreSeek(Player.COMMAND_SEEK_TO_NEXT);
      return;
    }
    if (hasNextMediaItem()) {
      seekToNextMediaItemInternal(Player.COMMAND_SEEK_TO_NEXT);
    } else if (isCurrentMediaItemLive() && isCurrentMediaItemDynamic()) {
      seekToDefaultPositionInternal(getCurrentMediaItemIndex(), Player.COMMAND_SEEK_TO_NEXT);
    } else {
      ignoreSeek(Player.COMMAND_SEEK_TO_NEXT);
    }
  }

  @Override
  public final void seekTo(long positionMs) {
    seekToCurrentItem(positionMs, Player.COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM);
  }

  @Override
  public final void seekTo(int mediaItemIndex, long positionMs) {
    seekTo(
        mediaItemIndex,
        positionMs,
        Player.COMMAND_SEEK_TO_MEDIA_ITEM,
        /* isRepeatingCurrentItem= */ false);
  }

  /**
   * Seeks to a position in the specified {@link MediaItem}.
   *
   * @param mediaItemIndex The index of the {@link MediaItem}. If the original seek operation did
   *     not directly specify an index, this is the most likely implied index based on the available
   *     player state. If the implied action is to do nothing, this will be {@link C#INDEX_UNSET}.
   * @param positionMs The seek position in the specified {@link MediaItem} in milliseconds, or
   *     {@link C#TIME_UNSET} to seek to the media item's default position. If the original seek
   *     operation did not directly specify a position, this is the most likely implied position
   *     based on the available player state.
   * @param seekCommand The {@link Player.Command} used to trigger the seek.
   * @param isRepeatingCurrentItem Whether this seeks repeats the current item.
   */
  @VisibleForTesting(otherwise = PROTECTED)
  public abstract void seekTo(
      int mediaItemIndex,
      long positionMs,
      @Player.Command int seekCommand,
      boolean isRepeatingCurrentItem);

  @Override
  public final void setPlaybackSpeed(float speed) {
    setPlaybackParameters(getPlaybackParameters().withSpeed(speed));
  }

  /**
   * @deprecated Use {@link #getCurrentMediaItemIndex()} instead.
   */
  @Deprecated
  @Override
  public final int getCurrentWindowIndex() {
    return getCurrentMediaItemIndex();
  }

  /**
   * @deprecated Use {@link #getNextMediaItemIndex()} instead.
   */
  @Deprecated
  @Override
  public final int getNextWindowIndex() {
    return getNextMediaItemIndex();
  }

  @Override
  public final int getNextMediaItemIndex() {
    Timeline timeline = getCurrentTimeline();
    return timeline.isEmpty()
        ? C.INDEX_UNSET
        : timeline.getNextWindowIndex(
            getCurrentMediaItemIndex(), getRepeatModeForNavigation(), getShuffleModeEnabled());
  }

  /**
   * @deprecated Use {@link #getPreviousMediaItemIndex()} instead.
   */
  @Deprecated
  @Override
  public final int getPreviousWindowIndex() {
    return getPreviousMediaItemIndex();
  }

  @Override
  public final int getPreviousMediaItemIndex() {
    Timeline timeline = getCurrentTimeline();
    return timeline.isEmpty()
        ? C.INDEX_UNSET
        : timeline.getPreviousWindowIndex(
            getCurrentMediaItemIndex(), getRepeatModeForNavigation(), getShuffleModeEnabled());
  }

  @Override
  @Nullable
  public final MediaItem getCurrentMediaItem() {
    Timeline timeline = getCurrentTimeline();
    return timeline.isEmpty()
        ? null
        : timeline.getWindow(getCurrentMediaItemIndex(), window).mediaItem;
  }

  @Override
  public final int getMediaItemCount() {
    return getCurrentTimeline().getWindowCount();
  }

  @Override
  public final MediaItem getMediaItemAt(int index) {
    return getCurrentTimeline().getWindow(index, window).mediaItem;
  }

  @Override
  @Nullable
  public final Object getCurrentManifest() {
    Timeline timeline = getCurrentTimeline();
    return timeline.isEmpty()
        ? null
        : timeline.getWindow(getCurrentMediaItemIndex(), window).manifest;
  }

  @Override
  public final int getBufferedPercentage() {
    long position = getBufferedPosition();
    long duration = getDuration();
    return position == C.TIME_UNSET || duration == C.TIME_UNSET
        ? 0
        : duration == 0 ? 100 : Util.constrainValue((int) ((position * 100) / duration), 0, 100);
  }

  /**
   * @deprecated Use {@link #isCurrentMediaItemDynamic()} instead.
   */
  @Deprecated
  @Override
  public final boolean isCurrentWindowDynamic() {
    return isCurrentMediaItemDynamic();
  }

  @Override
  public final boolean isCurrentMediaItemDynamic() {
    Timeline timeline = getCurrentTimeline();
    return !timeline.isEmpty() && timeline.getWindow(getCurrentMediaItemIndex(), window).isDynamic;
  }

  /**
   * @deprecated Use {@link #isCurrentMediaItemLive()} instead.
   */
  @Deprecated
  @Override
  public final boolean isCurrentWindowLive() {
    return isCurrentMediaItemLive();
  }

  @Override
  public final boolean isCurrentMediaItemLive() {
    Timeline timeline = getCurrentTimeline();
    return !timeline.isEmpty() && timeline.getWindow(getCurrentMediaItemIndex(), window).isLive();
  }

  @Override
  public final long getCurrentLiveOffset() {
    Timeline timeline = getCurrentTimeline();
    if (timeline.isEmpty()) {
      return C.TIME_UNSET;
    }
    long windowStartTimeMs =
        timeline.getWindow(getCurrentMediaItemIndex(), window).windowStartTimeMs;
    if (windowStartTimeMs == C.TIME_UNSET) {
      return C.TIME_UNSET;
    }
    return window.getCurrentUnixTimeMs() - window.windowStartTimeMs - getContentPosition();
  }

  /**
   * @deprecated Use {@link #isCurrentMediaItemSeekable()} instead.
   */
  @Deprecated
  @Override
  public final boolean isCurrentWindowSeekable() {
    return isCurrentMediaItemSeekable();
  }

  @Override
  public final boolean isCurrentMediaItemSeekable() {
    Timeline timeline = getCurrentTimeline();
    return !timeline.isEmpty() && timeline.getWindow(getCurrentMediaItemIndex(), window).isSeekable;
  }

  @Override
  public final long getContentDuration() {
    Timeline timeline = getCurrentTimeline();
    return timeline.isEmpty()
        ? C.TIME_UNSET
        : timeline.getWindow(getCurrentMediaItemIndex(), window).getDurationMs();
  }

  private @RepeatMode int getRepeatModeForNavigation() {
    @RepeatMode int repeatMode = getRepeatMode();
    return repeatMode == REPEAT_MODE_ONE ? REPEAT_MODE_OFF : repeatMode;
  }

  private void ignoreSeek(@Player.Command int seekCommand) {
    seekTo(
        /* mediaItemIndex= */ C.INDEX_UNSET,
        /* positionMs= */ C.TIME_UNSET,
        seekCommand,
        /* isRepeatingCurrentItem= */ false);
  }

  private void seekToCurrentItem(long positionMs, @Player.Command int seekCommand) {
    seekTo(
        getCurrentMediaItemIndex(), positionMs, seekCommand, /* isRepeatingCurrentItem= */ false);
  }

  private void seekToOffset(long offsetMs, @Player.Command int seekCommand) {
    long positionMs = getCurrentPosition() + offsetMs;
    long durationMs = getDuration();
    if (durationMs != C.TIME_UNSET) {
      positionMs = min(positionMs, durationMs);
    }
    positionMs = max(positionMs, 0);
    seekToCurrentItem(positionMs, seekCommand);
  }

  private void seekToDefaultPositionInternal(int mediaItemIndex, @Player.Command int seekCommand) {
    seekTo(
        mediaItemIndex,
        /* positionMs= */ C.TIME_UNSET,
        seekCommand,
        /* isRepeatingCurrentItem= */ false);
  }

  private void seekToNextMediaItemInternal(@Player.Command int seekCommand) {
    int nextMediaItemIndex = getNextMediaItemIndex();
    if (nextMediaItemIndex == C.INDEX_UNSET) {
      ignoreSeek(seekCommand);
      return;
    }
    if (nextMediaItemIndex == getCurrentMediaItemIndex()) {
      repeatCurrentMediaItem(seekCommand);
    } else {
      seekToDefaultPositionInternal(nextMediaItemIndex, seekCommand);
    }
  }

  private void seekToPreviousMediaItemInternal(@Player.Command int seekCommand) {
    int previousMediaItemIndex = getPreviousMediaItemIndex();
    if (previousMediaItemIndex == C.INDEX_UNSET) {
      ignoreSeek(seekCommand);
      return;
    }
    if (previousMediaItemIndex == getCurrentMediaItemIndex()) {
      repeatCurrentMediaItem(seekCommand);
    } else {
      seekToDefaultPositionInternal(previousMediaItemIndex, seekCommand);
    }
  }

  private void repeatCurrentMediaItem(@Player.Command int seekCommand) {
    seekTo(
        getCurrentMediaItemIndex(),
        /* positionMs= */ C.TIME_UNSET,
        seekCommand,
        /* isRepeatingCurrentItem= */ true);
  }
}