Jetpack Media3 определяет интерфейс Player
, в котором описываются основные функции воспроизведения видео и аудио файлов. ExoPlayer
является реализацией этого интерфейса по умолчанию в Media3. Мы рекомендуем использовать ExoPlayer, поскольку он предоставляет полный набор функций, которые охватывают большинство вариантов использования воспроизведения, и его можно настроить для обработки любых дополнительных вариантов использования, которые могут у вас возникнуть. ExoPlayer также абстрагирует фрагментацию устройств и ОС, поэтому ваш код работает согласованно во всей экосистеме Android. ExoPlayer включает в себя:
- Поддержка плейлистов
- Поддержка различных прогрессивных и адаптивных форматов потоковой передачи.
- Поддержка вставки рекламы как на стороне клиента, так и на стороне сервера.
- Поддержка воспроизведения с защитой DRM
На этой странице описаны некоторые ключевые этапы создания приложения для воспроизведения, а для получения более подробной информации вы можете обратиться к нашим полным руководствам по 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
включает в себя ряд параметров настройки, которые могут вас заинтересовать, например:
-
setAudioAttributes()
для настройки обработки фокуса звука -
setHandleAudioBecomingNoisy()
для настройки поведения воспроизведения при отключении устройства вывода звука -
setTrackSelector()
для настройки выбора трека
Media3 предоставляет компонент пользовательского интерфейса PlayerView
, который вы можете включить в файл макета вашего приложения. Этот компонент инкапсулирует PlayerControlView
для элементов управления воспроизведением, SubtitleView
для отображения субтитров и Surface
для рендеринга видео.
Подготовка игрока
Добавьте медиа-элементы в список воспроизведения для воспроизведения с помощью таких методов, как setMediaItem()
и addMediaItem()
. Затем вызовите prepare()
, чтобы начать загрузку носителя и получить необходимые ресурсы.
Не следует выполнять эти действия, пока приложение не окажется на переднем плане. Если ваш проигрыватель находится в Activity
или Fragment
, это означает подготовку проигрывателя с помощью метода жизненного цикла onStart()
на уровне API 24 и выше или метода жизненного цикла onResume()
на уровне API 23 и ниже. Для игрока, находящегося в Service
, вы можете подготовить его в onCreate()
.
Управляйте игроком
После подготовки проигрывателя вы можете управлять воспроизведением, вызывая такие методы проигрывателя, как:
-
play()
иpause()
для запуска и приостановки воспроизведения -
seekTo()
для поиска позиции в текущем элементе мультимедиа -
seekToNextMediaItem()
иseekToPreviousMediaItem()
для навигации по списку воспроизведения.
Компоненты пользовательского интерфейса, такие как 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
с дополнительными сигналами о типе дерева контента, которое интересует клиентское приложение.