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
с дополнительными сигналами о типе дерева контента, который интересует клиентское приложение.