Прямой эфир

ExoPlayer поддерживает большинство адаптивных трансляций без дополнительной настройки. Подробнее о поддерживаемых форматах…

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

Обнаружение и отслеживание воспроизведения в реальном времени

При каждом обновлении окна трансляции зарегистрированные экземпляры Player.Listener будут получать событие onTimelineChanged. Чтобы получить информацию о текущем воспроизведении трансляции, можно использовать различные методы Player и Timeline.Window, перечисленные ниже и показанные на рисунке.

Окно трансляции

  • Player.isCurrentWindowLive указывает, является ли текущий медиаконтент трансляцией. Это значение остается истинным, даже если трансляция завершилась.
  • Player.isCurrentWindowDynamic указывает, обновляется ли сейчас воспроизводимый медиаконтент. Обычно это относится к трансляциям, которые ещё не завершены. Обратите внимание, что этот флаг также может быть установлен для обычных видео.
  • Player.getCurrentLiveOffset возвращает смещение между текущим реальным временем и позицией воспроизведения (если доступно).
  • Player.getDuration возвращает длину текущего окна трансляции.
  • Player.getCurrentPosition возвращает позицию воспроизведения относительно начала окна трансляции.
  • Player.getCurrentMediaItem возвращает текущий медиаконтент, где MediaItem.liveConfiguration содержит переопределения, предоставленные приложением для целевого смещения прямого эфира и параметров корректировки смещения прямого эфира.
  • Player.getCurrentTimeline возвращает текущую структуру медиаконтента в формате Timeline. Текущий объект Timeline.Window можно получить из объекта Timeline с помощью методов Player.getCurrentMediaItemIndex и Timeline.getWindow. В течение Window:
    • Window.liveConfiguration содержит целевое смещение трансляции и параметры корректировки смещения трансляции. Эти значения основаны на информации из медиаконтента и любых переопределений, заданных в приложении в MediaItem.liveConfiguration.
    • Window.windowStartTimeMs – время начала окна трансляции в формате Unix Epoch.
    • Window.getCurrentUnixTimeMs – время с начала эпохи Unix до текущего момента в реальном времени. Это значение может быть скорректировано с учетом известной разницы во времени между сервером и клиентом.
    • Window.getDefaultPositionMs – позиция в окне трансляции, с которой проигрыватель начнет воспроизведение по умолчанию.

Перемотка в прямых трансляциях

Вы можете перейти к любому моменту в окне трансляции, используя Player.seekTo. Позиция, указанная в запросе seek, отсчитывается от начала окна трансляции. Например, команда "назад seekTo(0)" переведет вас в начало окна трансляции. После перехода к определенной позиции проигрыватель попытается сохранить смещение относительно начала трансляции.

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

Интерфейс воспроизведения трансляции

Стандартные компоненты интерфейса ExoPlayer показывают продолжительность окна трансляции и текущую позицию воспроизведения в нем. Это означает, что при каждом обновлении окна трансляции позиция будет как бы отматываться назад. Если вам нужно другое поведение, например отображение Unix-времени или текущего смещения трансляции, вы можете создать ответвление PlayerControlView и изменить его в соответствии со своими потребностями.

Как настроить параметры воспроизведения трансляции

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

ExoPlayer получает значения этих параметров из трех источников в порядке убывания приоритета (используется первое найденное значение):

  • Значения MediaItem, переданные в MediaItem.Builder.setLiveConfiguration.
  • Глобальные значения по умолчанию, заданные в DefaultMediaSourceFactory.
  • Значения, считанные непосредственно из медиаконтента.

Kotlin

// Global settings.
val player =
  ExoPlayer.Builder(context)
    .setMediaSourceFactory(DefaultMediaSourceFactory(context).setLiveTargetOffsetMs(5000))
    .build()

// Per MediaItem settings.
val mediaItem =
  MediaItem.Builder()
    .setUri(mediaUri)
    .setLiveConfiguration(
      MediaItem.LiveConfiguration.Builder().setMaxPlaybackSpeed(1.02f).build()
    )
    .build()
player.setMediaItem(mediaItem)

Java

// Global settings.
ExoPlayer player =
    new ExoPlayer.Builder(context)
        .setMediaSourceFactory(
            new DefaultMediaSourceFactory(context).setLiveTargetOffsetMs(5000))
        .build();

// Per MediaItem settings.
MediaItem mediaItem =
    new MediaItem.Builder()
        .setUri(mediaUri)
        .setLiveConfiguration(
            new MediaItem.LiveConfiguration.Builder().setMaxPlaybackSpeed(1.02f).build())
        .build();
player.setMediaItem(mediaItem);

Доступные значения конфигурации:

  • targetOffsetMs – целевое смещение трансляции. Проигрыватель попытается приблизиться к этому смещению во время воспроизведения, если это возможно.
  • minOffsetMs – минимальное допустимое смещение трансляции. Даже если смещение будет скорректировано с учетом текущих условий сети, проигрыватель не будет пытаться уменьшить его во время воспроизведения.
  • maxOffsetMs – максимальное допустимое смещение трансляции. Даже если смещение будет скорректировано с учетом текущих условий сети, проигрыватель не будет пытаться превысить это смещение во время воспроизведения.
  • minPlaybackSpeed – минимальная скорость воспроизведения, которую может использовать проигрыватель, чтобы достичь целевого смещения трансляции.
  • maxPlaybackSpeed – максимальная скорость воспроизведения, которую может использовать проигрыватель, чтобы догнать трансляцию и достичь целевого смещения.

Настройка скорости воспроизведения

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

Если вы не хотите, чтобы скорость воспроизведения регулировалась автоматически, отключите эту функцию, задав для свойств minPlaybackSpeed и maxPlaybackSpeed значение 1.0f. Аналогичным образом можно включить эту функцию для трансляций с обычной задержкой, задав для этих параметров значения, отличные от 1.0f. Подробнее о том, как задавать эти свойства, рассказывается в разделе о настройке.

Как настроить алгоритм изменения скорости воспроизведения

Если регулировка скорости включена, LivePlaybackSpeedControl определяет, какие корректировки будут внесены. Вы можете реализовать собственный LivePlaybackSpeedControl или настроить реализацию по умолчанию, которая представлена в виде DefaultLivePlaybackSpeedControl. В обоих случаях экземпляр можно задать при создании проигрывателя:

Kotlin

val player =
  ExoPlayer.Builder(context)
    .setLivePlaybackSpeedControl(
      DefaultLivePlaybackSpeedControl.Builder().setFallbackMaxPlaybackSpeed(1.04f).build()
    )
    .build()

Java

ExoPlayer player =
    new ExoPlayer.Builder(context)
        .setLivePlaybackSpeedControl(
            new DefaultLivePlaybackSpeedControl.Builder()
                .setFallbackMaxPlaybackSpeed(1.04f)
                .build())
        .build();

К параметрам настройки DefaultLivePlaybackSpeedControl относятся:

  • fallbackMinPlaybackSpeed и fallbackMaxPlaybackSpeed – минимальная и максимальная скорости воспроизведения, которые можно использовать для регулировки, если ни медиаконтент, ни предоставленный приложением параметр MediaItem не определяют ограничения.
  • proportionalControlFactor – определяет, насколько плавно будет меняться скорость. Высокое значение делает изменения более резкими и заметными, но также более вероятными для восприятия на слух. Чем меньше значение, тем плавнее переход между скоростями, но тем медленнее будет выполняться задача.
  • targetLiveOffsetIncrementOnRebufferMs – это значение добавляется к целевому смещению трансляции при каждой повторной буферизации, чтобы обеспечить более осторожную работу. Чтобы отключить эту функцию, задайте значение 0.
  • minPossibleLiveOffsetSmoothingFactor: коэффициент экспоненциального сглаживания, который используется для отслеживания минимально возможного смещения трансляции на основе текущего буферизованного медиаконтента. Значение, близкое к 1, означает, что оценка более осторожная и может дольше адаптироваться к улучшению условий сети. Более низкое значение означает, что оценка будет быстрее адаптироваться, но при этом повышается риск повторной буферизации.

BehindLiveWindowException и ERROR_CODE_BEHIND_LIVE_WINDOW

Позиция воспроизведения может отставать от окна трансляции, например если проигрыватель был на паузе или буферизировался достаточно долго. В этом случае воспроизведение будет прервано, а исключение с кодом ошибки ERROR_CODE_BEHIND_LIVE_WINDOW будет передано через Player.Listener.onPlayerError. Код приложения может обрабатывать такие ошибки, возобновляя воспроизведение с позиции по умолчанию. В демонстрационном приложении этот подход реализован в PlayerActivity.

Kotlin

override fun onPlayerError(error: PlaybackException) {
  if (error.errorCode == PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW) {
    // Re-initialize player at the live edge.
    player.seekToDefaultPosition()
    player.prepare()
  } else {
    // Handle other errors
  }
}

Java

@Override
public void onPlayerError(PlaybackException error) {
  if (error.errorCode == PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW) {
    // Re-initialize player at the live edge.
    player.seekToDefaultPosition();
    player.prepare();
  } else {
    // Handle other errors
  }
}