Jetpack Media3 определяет интерфейс Player , описывающий основные функции воспроизведения видео- и аудиофайлов. ExoPlayer — это реализация этого интерфейса по умолчанию в Media3. Мы рекомендуем использовать ExoPlayer, поскольку он предоставляет полный набор функций, охватывающих большинство сценариев воспроизведения, и может быть настроен для обработки любых дополнительных сценариев использования. ExoPlayer также абстрагирует фрагментацию устройства и ОС, поэтому ваш код будет работать согласованно во всей экосистеме Android. ExoPlayer включает в себя:
- Поддержка плейлистов
- Поддержка различных прогрессивных и адаптивных форматов потоковой передачи.
- Поддержка вставки рекламы как на стороне клиента, так и на стороне сервера.
- Поддержка воспроизведения с защитой DRM.
На этой странице описаны некоторые ключевые этапы создания приложения для воспроизведения, а для получения более подробной информации вы можете перейти к нашим полным руководствам по Media3 ExoPlayer .
Начиная
Для начала добавьте зависимость от модулей ExoPlayer, UI и Common из пакета Jetpack Media3:
implementation "androidx.media3:media3-exoplayer:1.9.0" implementation "androidx.media3:media3-ui:1.9.0" implementation "androidx.media3:media3-common:1.9.0"
В зависимости от ваших задач, вам также могут потребоваться дополнительные модули от Media3, такие как exoplayer-dash для воспроизведения потоков в формате DASH.
Обязательно замените 1.9.0 на предпочитаемую вами версию библиотеки. Актуальную версию можно найти в примечаниях к выпуску .
Создание медиаплеера
В Media3 вы можете либо использовать встроенную реализацию интерфейса Player , ExoPlayer , либо создать собственную пользовательскую реализацию.
Создание ExoPlayer
Простейший способ создать экземпляр ExoPlayer выглядит следующим образом:
Котлин
val player = ExoPlayer.Builder(context).build()
Java
ExoPlayer player = new ExoPlayer.Builder(context).build();
Вы можете создать свой медиаплеер в методе жизненного цикла onCreate() Activity , Fragment или Service , в котором он находится.
Builder включает в себя ряд параметров настройки, которые могут вас заинтересовать, например:
- Используйте
setAudioAttributes()для настройки обработки фокуса на аудиопотоке. -
setHandleAudioBecomingNoisy()позволяет настроить поведение воспроизведения при отключении устройства вывода звука. -
setTrackSelector()для настройки выбора трека.
Media3 предоставляет компонент пользовательского интерфейса PlayerView , который можно включить в файл разметки вашего приложения. Этот компонент инкапсулирует PlayerControlView для управления воспроизведением, SubtitleView для отображения субтитров и Surface для рендеринга видео.
Подготовка игрока
Добавьте медиафайлы в плейлист для воспроизведения с помощью таких методов, как setMediaItem() и addMediaItem() . Затем вызовите метод prepare() , чтобы начать загрузку медиафайлов и получить необходимые ресурсы.
Эти шаги не следует выполнять до того, как приложение перейдет в активный режим. Если ваш плеер находится в Activity или Fragment , это означает подготовку плеера в методе жизненного цикла onStart() на уровне API 24 и выше или в методе жизненного цикла onResume() на уровне API 23 и ниже. Для плеера, находящегося в Service , подготовку можно выполнить в onCreate() . Пример реализации методов жизненного цикла можно найти в документации Exoplayer .
Управляйте игроком
После подготовки проигрывателя вы можете управлять воспроизведением, вызывая методы проигрывателя, например:
-
play()иpause()используются для запуска и приостановки воспроизведения. -
seekTo()используется для перехода к определенной позиции внутри текущего медиафайла. - Используйте
seekToNextMediaItem()иseekToPreviousMediaItem()для навигации по плейлисту.
Компоненты пользовательского интерфейса, такие как PlayerView или PlayerControlView будут обновляться соответствующим образом при привязке к игроку.
Отпустите игрока
Для воспроизведения могут потребоваться ресурсы, имеющиеся в ограниченном количестве, например, видеодекодеры, поэтому важно вызывать release() для вашего плеера, чтобы освободить ресурсы, когда плеер больше не нужен.
Если ваш плеер находится в Activity или Fragment , освободите его в методе жизненного цикла onStop() на API уровня 24 и выше или в методе onPause() на API уровня 23 и ниже. Для плеера, находящегося в Service , вы можете освободить его в onDestroy() . Пример реализации методов жизненного цикла можно найти в документации Exoplayer .
Управление воспроизведением в рамках медиасессии
На Android медиасессии предоставляют стандартизированный способ взаимодействия с медиаплеером вне рамок отдельных процессов. Подключение медиасессии к вашему плееру позволяет передавать информацию о воспроизведении медиафайлов во внешние сети и получать команды воспроизведения из внешних источников, например, для интеграции с системными элементами управления воспроизведением на мобильных устройствах и устройствах с большими экранами.
Для использования медиасессий добавьте зависимость от модуля Media3 Session:
implementation "androidx.media3:media3-session:1.9.0"
Создать медиасессию
Создать MediaSession можно после инициализации проигрывателя следующим образом:
Котлин
val player = ExoPlayer.Builder(context).build() val mediaSession = MediaSession.Builder(context, player).build()
Java
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() } }
Java
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
Java
@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() ) }
Java
@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 с дополнительными сигналами о типе дерева контента, который интересует клиентское приложение.