Создайте базовое приложение медиаплеера с помощью Media3 ExoPlayer.

Jetpack Media3 определяет интерфейс Player , в котором описываются основные функции воспроизведения видео и аудио файлов. ExoPlayer является реализацией этого интерфейса по умолчанию в Media3. Мы рекомендуем использовать ExoPlayer, поскольку он предоставляет полный набор функций, которые охватывают большинство вариантов использования воспроизведения, и его можно настроить для обработки любых дополнительных вариантов использования, которые могут у вас возникнуть. ExoPlayer также абстрагирует фрагментацию устройств и ОС, поэтому ваш код работает согласованно во всей экосистеме Android. ExoPlayer включает в себя:

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

Начиная

Для начала добавьте зависимость от модулей ExoPlayer, UI и Common Jetpack Media3:

implementation "androidx.media3:media3-exoplayer:1.4.1"
implementation "androidx.media3:media3-ui:1.4.1"
implementation "androidx.media3:media3-common:1.4.1"

В зависимости от вашего варианта использования вам также могут понадобиться дополнительные модули из Media3, такие как exoplayer-dash для воспроизведения потоков в формате DASH.

Обязательно замените 1.4.1 предпочитаемой версией библиотеки. Вы можете обратиться к примечаниям к выпуску, чтобы увидеть последнюю версию.

Создание медиаплеера

С Media3 вы можете использовать встроенную реализацию интерфейса Player ExoPlayer или создать свою собственную реализацию.

Создание ExoPlayer

Самый простой способ создать экземпляр ExoPlayer заключается в следующем:

Котлин

val player = ExoPlayer.Builder(context).build()

Ява

ExoPlayer player = new ExoPlayer.Builder(context).build();

Вы можете создать свой медиаплеер в методе жизненного цикла onCreate() Activity , Fragment или Service , где он находится.

Builder включает в себя ряд параметров настройки, которые могут вас заинтересовать, например:

Media3 предоставляет компонент пользовательского интерфейса PlayerView , который вы можете включить в файл макета вашего приложения. Этот компонент инкапсулирует PlayerControlView для элементов управления воспроизведением, SubtitleView для отображения субтитров и Surface для рендеринга видео.

Подготовка игрока

Добавляйте медиа-элементы в список воспроизведения для воспроизведения с помощью таких методов, как setMediaItem() и addMediaItem() . Затем вызовите prepare() , чтобы начать загрузку носителя и получить необходимые ресурсы.

Не следует выполнять эти действия, пока приложение не окажется на переднем плане. Если ваш проигрыватель находится в Activity или Fragment , это означает подготовку проигрывателя с помощью метода жизненного цикла onStart() на уровне API 24 и выше или метода жизненного цикла onResume() на уровне API 23 и ниже. Для игрока, находящегося в Service , вы можете подготовить его в onCreate() .

Управляйте игроком

После подготовки проигрывателя вы можете управлять воспроизведением, вызывая такие методы проигрывателя, как:

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

Отпустить плеер

Для воспроизведения могут потребоваться ресурсы, количество которых ограничено, например видеодекодеры, поэтому важно вызывать release() на вашем проигрывателе, чтобы освободить ресурсы, когда проигрыватель больше не нужен.

Если ваш проигрыватель находится в Activity или Fragment , освободите его с помощью метода жизненного цикла onStop() на уровне API 24 и выше или метода onPause() на уровне API 23 и ниже. Для игрока, находящегося в Service , вы можете освободить его с помощью onDestroy() .

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

В Android медиасеансы предоставляют стандартизированный способ взаимодействия с медиаплеером, невзирая на границы процесса. Подключение медиа-сеанса к вашему проигрывателю позволяет вам рекламировать воспроизведение мультимедиа извне и получать команды воспроизведения из внешних источников, например, для интеграции с системными элементами управления мультимедиа на мобильных устройствах и устройствах с большим экраном.

Чтобы использовать медиа-сессии, добавьте зависимость к модулю Media3 Session:

implementation "androidx.media3:media3-session:1.4.1"

Создать медиа-сессию

Вы можете создать MediaSession после инициализации проигрывателя следующим образом:

Котлин

val player = ExoPlayer.Builder(context).build()
val mediaSession = MediaSession.Builder(context, player).build()

Ява

ExoPlayer player = new ExoPlayer.Builder(context).build();
MediaSession mediaSession = new MediaSession.Builder(context, player).build();

Media3 автоматически синхронизирует состояние Player с состоянием MediaSession . Это работает с любой реализацией Player , включая ExoPlayer , CastPlayer или пользовательскую реализацию.

Предоставить контроль другим клиентам

Клиентские приложения могут реализовать медиа-контроллер для управления воспроизведением вашего медиа-сеанса. Чтобы получать эти запросы, установите объект обратного вызова при создании MediaSession .

Когда контроллер собирается подключиться к вашему медиа-сеансу, вызывается метод onConnect() . Вы можете использовать предоставленную ControllerInfo , чтобы решить, принять или отклонить запрос. См. пример этого в демонстрационном приложении Media3 Session .

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

Другие методы обратного вызова позволяют обрабатывать, например, запросы на пользовательские команды воспроизведения и изменение списка воспроизведения . Эти обратные вызовы также включают объект ControllerInfo , поэтому вы можете определять управление доступом для каждого запроса.

Воспроизведение мультимедиа в фоновом режиме

Чтобы продолжить воспроизведение мультимедиа, когда ваше приложение не находится на переднем плане, например для воспроизведения музыки, аудиокниг или подкастов, даже если у пользователя не открыто ваше приложение, ваш Player и MediaSession должны быть инкапсулированы в службу переднего плана . Для этой цели Media3 предоставляет интерфейс MediaSessionService .

Реализация MediaSessionService

Создайте класс, расширяющий MediaSessionService , и создайте экземпляр MediaSession в методе жизненного цикла onCreate() .

Котлин

class PlaybackService : MediaSessionService() {
    private var mediaSession: MediaSession? = null

    // Create your Player and MediaSession in the onCreate lifecycle event
    override fun onCreate() {
        super.onCreate()
        val player = ExoPlayer.Builder(this).build()
        mediaSession = MediaSession.Builder(this, player).build()
    }

    // Remember to release the player and media session in onDestroy
    override fun onDestroy() {
        mediaSession?.run {
            player.release()
            release()
            mediaSession = null
        }
        super.onDestroy()
    }
}

Ява

public class PlaybackService extends MediaSessionService {
    private MediaSession mediaSession = null;

    @Override
    public void onCreate() {
        super.onCreate();
        ExoPlayer player = new ExoPlayer.Builder(this).build();
        mediaSession = new MediaSession.Builder(this, player).build();
    }

    @Override
    public void onDestroy() {
        mediaSession.getPlayer().release();
        mediaSession.release();
        mediaSession = null;
        super.onDestroy();
    }
}

В вашем манифесте ваш класс Service с фильтром намерений MediaSessionService и запросит разрешение FOREGROUND_SERVICE для запуска службы переднего плана:

<service
    android:name=".PlaybackService"
    android:foregroundServiceType="mediaPlayback"
    android:exported="true">
    <intent-filter>
        <action android:name="androidx.media3.session.MediaSessionService"/>
    </intent-filter>
</service>

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

Наконец, в созданном вами классе переопределите метод onGetSession() чтобы контролировать доступ клиента к вашему медиа-сеансу. Верните MediaSession , чтобы принять запрос на соединение, или верните null , чтобы отклонить запрос.

Котлин

// This example always accepts the connection request
override fun onGetSession(
    controllerInfo: MediaSession.ControllerInfo
): MediaSession? = mediaSession

Ява

@Override
public MediaSession onGetSession(MediaSession.ControllerInfo controllerInfo) {
  // This example always accepts the connection request
  return mediaSession;
}

Подключение к вашему пользовательскому интерфейсу

Теперь, когда ваш медиа-сеанс находится в Service отдельном от Activity или Fragment , в котором находится пользовательский интерфейс вашего проигрывателя, вы можете использовать MediaController , чтобы связать их вместе. В методе onStart() Activity или Fragment вашего пользовательского интерфейса создайте SessionToken для вашего MediaSession , затем используйте SessionToken для создания MediaController . Создание MediaController происходит асинхронно.

Котлин

override fun onStart() {
  val sessionToken = SessionToken(this, ComponentName(this, PlaybackService::class.java))
  val controllerFuture = MediaController.Builder(this, sessionToken).buildAsync()
  controllerFuture.addListener(
    {
        // Call controllerFuture.get() to retrieve the MediaController.
        // MediaController implements the Player interface, so it can be
        // attached to the PlayerView UI component.
        playerView.setPlayer(controllerFuture.get())
      },
    MoreExecutors.directExecutor()
  )
}

Ява

@Override
public void onStart() {
  SessionToken sessionToken =
    new SessionToken(this, new ComponentName(this, PlaybackService.class));
  ListenableFuture<MediaController> controllerFuture =
    new MediaController.Builder(this, sessionToken).buildAsync();
  controllerFuture.addListener(() -> {
    // Call controllerFuture.get() to retrieve the MediaController.
    // MediaController implements the Player interface, so it can be
    // attached to the PlayerView UI component.
    playerView.setPlayer(controllerFuture.get());
  }, MoreExecutors.directExecutor())
}

MediaController реализует интерфейс Player , поэтому для управления воспроизведением можно использовать те же методы, что и play() и pause() . Как и в случае с другими компонентами, не забудьте освободить MediaController , когда он больше не нужен, например, метод жизненного цикла onStop() Activity , вызвав MediaController.releaseFuture() .

Публикация уведомления

Службы переднего плана должны публиковать уведомления, пока они активны. MediaSessionService автоматически создаст для вас уведомление MediaStyle в форме MediaNotification . Чтобы предоставить настраиваемое уведомление, создайте MediaNotification.Provider с помощью DefaultMediaNotificationProvider.Builder или создайте собственную реализацию интерфейса поставщика. Добавьте своего провайдера в свой MediaSession с помощью setMediaNotificationProvider .

Реклама вашей библиотеки контента

MediaLibraryService основан на MediaSessionService , позволяя клиентским приложениям просматривать мультимедийный контент, предоставляемый вашим приложением. Клиентские приложения реализуют MediaBrowser для взаимодействия с вашим MediaLibraryService .

Реализация MediaLibraryService аналогична реализации MediaSessionService , за исключением того, что в onGetSession() вы должны возвращать MediaLibrarySession вместо MediaSession . По сравнению с MediaSession.Callback MediaLibrarySession.Callback включает дополнительные методы, которые позволяют клиенту браузера перемещаться по содержимому, предлагаемому вашей библиотечной службой.

Подобно MediaSessionService , объявите MediaLibraryService в своем манифесте и запросите разрешение FOREGROUND_SERVICE для запуска службы переднего плана:

<service
    android:name=".PlaybackService"
    android:foregroundServiceType="mediaPlayback"
    android:exported="true">
    <intent-filter>
        <action android:name="androidx.media3.session.MediaLibraryService"/>
        <action android:name="android.media.browse.MediaBrowserService"/>
    </intent-filter>
</service>

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

Приведенный выше пример включает фильтр намерений как для MediaLibraryService , так и для обратной совместимости для устаревшего MediaBrowserService . Дополнительный фильтр намерений позволяет клиентским приложениям, использующим API MediaBrowserCompat распознавать вашу Service .

MediaLibrarySession позволяет обслуживать вашу библиотеку контента в древовидной структуре с одним корневым MediaItem . Каждый MediaItem в дереве может иметь любое количество дочерних узлов MediaItem . Вы можете использовать другой корень или другое дерево в зависимости от запроса клиентского приложения. Например, дерево, которое вы возвращаете клиенту в поисках списка рекомендуемых медиа-элементов, может содержать только корневой MediaItem и один уровень дочерних узлов MediaItem , тогда как дерево, которое вы возвращаете в другое клиентское приложение, может представлять собой более полную библиотеку содержание.

Создание сеанса MediaLibrarySession

MediaLibrarySession расширяет API MediaSession , добавляя API просмотра контента. По сравнению с обратным вызовом MediaSession , обратный вызов MediaLibrarySession добавляет такие методы, как:

  • onGetLibraryRoot() , когда клиент запрашивает корневой MediaItem дерева контента.
  • onGetChildren() , когда клиент запрашивает дочерние элементы MediaItem в дереве контента
  • onGetSearchResult() когда клиент запрашивает результаты поиска из дерева контента для данного запроса

Соответствующие методы обратного вызова будут включать объект LibraryParams с дополнительными сигналами о типе дерева контента, которое интересует клиентское приложение.