Интерфейс игрока

Проигрыватель — это компонент вашего приложения, который облегчает воспроизведение мультимедийных элементов. Интерфейс Media3 Player устанавливает структуру функций, обычно выполняемых проигрывателем. Это включает в себя:

  • Влияние на элементы управления воспроизведением, такие как воспроизведение, пауза и поиск.
  • Запрос свойств воспроизводимого в данный момент мультимедиа, например позиции воспроизведения
  • Управление списком воспроизведения/очередью мультимедийных элементов
  • Настройка свойств воспроизведения, таких как перемешивание, повторение, скорость и громкость.
  • Рендеринг видео на экран

Media3 также предоставляет реализацию интерфейса Player , называемого ExoPlayer .

Общий интерфейс между компонентами

Некоторые компоненты Media3 реализуют интерфейс Player, например:

Компонент Описание и примечания к поведению
ExoPlayer API медиаплеера и реализация интерфейса Player по умолчанию.
MediaController Взаимодействует с MediaSession для отправки команд воспроизведения. Если ваш Player и MediaSession находятся в Service , отдельной от Activity или Fragment , в котором находится пользовательский интерфейс вашего проигрывателя, вы можете назначить свой MediaController в качестве проигрывателя для пользовательского интерфейса PlayerView . Вызовы методов воспроизведения и списка воспроизведения отправляются на ваш Player через MediaSession .
MediaBrowser В дополнение к функциональности, предлагаемой MediaController , взаимодействует с MediaLibrarySession для просмотра доступного медиаконтента.
ForwardingPlayer Реализация Player , которая пересылает вызовы методов другому Player . Используйте этот класс для подавления или изменения определенных операций путем переопределения соответствующих методов.
SimpleBasePlayer Реализация Player , которая сокращает количество реализуемых методов до минимума. Полезно при использовании специального проигрывателя, который вы хотите подключить к MediaSession .
CastPlayer Реализация Player , которая взаимодействует с приложением-приемником Cast. Поведение зависит от базового сеанса Cast.

Хотя MediaSession не реализует интерфейс Player , при его создании требуется Player . Его цель — предоставить доступ к Player из других процессов или потоков.

Архитектура воспроизведения Media3

Если у вас есть доступ к Player , вам следует напрямую вызывать его методы для выдачи команд воспроизведения. Вы можете рекламировать свое воспроизведение и предоставлять управление воспроизведением внешним источникам, реализуя MediaSession . Эти внешние источники реализуют MediaController , который облегчает подключение к сеансу мультимедиа и выдачу запросов команд воспроизведения.

При воспроизведении мультимедиа в фоновом режиме вам необходимо разместить медиасеанс и проигрыватель в MediaSessionService или MediaLibraryService , который работает как служба переднего плана. Если вы это сделаете, вы сможете отделить свой проигрыватель от действия в вашем приложении, которое содержит пользовательский интерфейс для управления воспроизведением. Это может потребовать использования медиа-контроллера.

Схема, показывающая, как компоненты воспроизведения Media3 вписываются в архитектуру мультимедийного приложения.
Рис. 1. Интерфейс Player играет ключевую роль в архитектуре Media3.

Состояние игрока

Состояние медиаплеера, реализующего интерфейс Player состоит в основном из 4 категорий информации:

  1. Состояние воспроизведения
  2. Плейлист с медиа-материалами
    • Последовательность экземпляров MediaItem для воспроизведения.
    • Получить с помощью getCurrentTimeline()
    • Экземпляры Player могут предоставлять методы работы со списком воспроизведения, такие как добавление или удаление MediaItem , а также удобные методы, такие как getCurrentMediaItem() .
  3. Свойства воспроизведения/паузы, такие как:
    • playWhenReady : указывает, хочет ли пользователь, чтобы медиа воспроизводилось, когда это возможно, или оставалось на паузе.
    • Причина подавления воспроизведения : указание того, почему воспроизведение подавляется, если применимо, даже если playWhenReady имеет true
    • isPlaying : указание того, играет ли проигрыватель в данный момент, что будет true только в том случае, если состояние воспроизведения равно STATE_READY , playWhenReady имеет true и воспроизведение не подавляется.
  4. Позиция воспроизведения, включая:

Кроме того, интерфейс Player обеспечивает доступ к доступным трекам , метаданным мультимедиа , скорости воспроизведения , громкости и другим вспомогательным свойствам воспроизведения.

Слушайте изменения

Используйте Player.Listener для прослушивания изменений в Player . Подробную информацию о том, как создать и использовать прослушиватель, см. в документации ExoPlayer по событиям Player.

Обратите внимание, что интерфейс прослушивателя не включает никаких обратных вызовов для отслеживания нормального хода воспроизведения. Чтобы постоянно отслеживать ход воспроизведения, например, для настройки пользовательского интерфейса индикатора выполнения, вам следует запрашивать текущую позицию через определенные промежутки времени.

Котлин

val handler = Handler(Looper.getMainLooper())
fun checkPlaybackPosition(delayMs: Long): Boolean =
  handler.postDelayed(
    {
      val currentPosition = player.currentPosition
      // Update UI based on currentPosition
      checkPlaybackPosition(delayMs)
    },
    delayMs)

Ява

Handler handler = new Handler(Looper.getMainLooper());
boolean checkPlaybackPosition(long delayMs) {
    return handler.postDelayed(() -> {
        long currentPosition = player.getCurrentPosition();
        // Update UI based on currentPosition
        checkPlaybackPosition(delayMs);
    }, delayMs);
}

Управление воспроизведением

Интерфейс Player предлагает множество способов манипулирования состоянием и управления воспроизведением:

Пользовательские реализации Player

Чтобы создать собственный проигрыватель, вы можете расширить SimpleBasePlayer включенный в Media3. Этот класс предоставляет базовую реализацию интерфейса Player , позволяющую свести к минимуму количество методов, которые необходимо реализовать.

Начните с переопределения метода getState() . Этот метод должен заполнять текущее состояние игрока при вызове, включая:

  • Набор доступных команд
  • Свойства воспроизведения, например, должен ли проигрыватель начинать воспроизведение, когда состояние воспроизведения равно STATE_READY , индекс воспроизводимого в данный момент элемента мультимедиа и позиция воспроизведения внутри текущего элемента.

Котлин

class CustomPlayer : SimpleBasePlayer(looper) {
  override fun getState(): State {
    return State.Builder()
      .setAvailableCommands(...) // Set which playback commands the player can handle
      // Configure additional playback properties
      .setPlayWhenReady(true, PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST)
      .setCurrentMediaItemIndex(0)
      .setContentPositionMs(0)
      .build()
  }
}

Ява

public class CustomPlayer extends SimpleBasePlayer {
  public CustomPlayer(Looper looper) {
    super(looper);
  }

  @Override
  protected State getState() {
    return new State.Builder()
      .setAvailableCommands(...) // Set which playback commands the player can handle
      // Configure additional playback properties
      .setPlayWhenReady(true, PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST)
      .setCurrentMediaItemIndex(0)
      .setContentPositionMs(0)
      .build();
  }
}

SimpleBasePlayer будет обеспечивать создание State с допустимой комбинацией значений состояния. Он также будет обрабатывать прослушиватели и информировать их об изменениях состояния. Если вам нужно вручную запустить обновление состояния, вызовите invalidateState() .

Помимо метода getState() , вам нужно реализовать только те методы, которые используются для команд, которые ваш проигрыватель объявляет доступными. Найдите переопределяемый метод-обработчик, соответствующий функциональности, которую вы хотите реализовать. Например, переопределите метод handleSeek() для поддержки таких операций, как COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM и COMMAND_SEEK_TO_NEXT_MEDIA_ITEM .