Медиа-приложения часто содержат коллекции медиа-элементов, организованные в иерархию. Например, песни в альбоме или эпизоды ТВ в плейлисте. Такая иерархия медиа-элементов известна как медиа-библиотека.
MediaLibraryService
предоставляет стандартизированный API для обслуживания и доступа к вашей медиатеке. Это может быть полезно, например, при добавлении поддержки Android Auto в ваше медиаприложение, которое предоставляет свой собственный безопасный для водителя пользовательский интерфейс для вашей медиатеке.
Создание службы MediaLibraryService
Реализация MediaLibraryService
аналогична реализации MediaSessionService
, за исключением того, что в методе onGetSession()
необходимо возвращать MediaLibrarySession
вместо MediaSession
.
Котлин
class PlaybackService : MediaLibraryService() { var mediaLibrarySession: MediaLibrarySession? = null var callback: MediaLibrarySession.Callback = object : MediaLibrarySession.Callback {...} // If desired, validate the controller before returning the media library session override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaLibrarySession? = mediaLibrarySession // Create your player and media library session in the onCreate lifecycle event override fun onCreate() { super.onCreate() val player = ExoPlayer.Builder(this).build() mediaLibrarySession = MediaLibrarySession.Builder(this, player, callback).build() } // Remember to release the player and media library session in onDestroy override fun onDestroy() { mediaLibrarySession?.run { player.release() release() mediaLibrarySession = null } super.onDestroy() } }
Ява
class PlaybackService extends MediaLibraryService { MediaLibrarySession mediaLibrarySession = null; MediaLibrarySession.Callback callback = new MediaLibrarySession.Callback() {...}; @Override public MediaLibrarySession onGetSession(MediaSession.ControllerInfo controllerInfo) { // If desired, validate the controller before returning the media library session return mediaLibrarySession; } // Create your player and media library session in the onCreate lifecycle event @Override public void onCreate() { super.onCreate(); ExoPlayer player = new ExoPlayer.Builder(this).build(); mediaLibrarySession = new MediaLibrarySession.Builder(this, player, callback).build(); } // Remember to release the player and media library session in onDestroy @Override public void onDestroy() { if (mediaLibrarySession != null) { mediaLibrarySession.getPlayer().release(); mediaLibrarySession.release(); mediaLibrarySession = null; } super.onDestroy(); } }
Не забудьте также указать свою Service
и требуемые разрешения в файле манифеста:
<service
android:name=".PlaybackService"
android:foregroundServiceType="mediaPlayback"
android:exported="true">
<intent-filter>
<action android:name="androidx.media3.session.MediaSessionService"/>
<action android:name="android.media.browse.MediaBrowserService"/>
</intent-filter>
</service>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
Использовать MediaLibrarySession
API MediaLibraryService
ожидает, что ваша медиабиблиотека будет структурирована в формате дерева с одним корневым узлом и дочерними узлами, которые могут быть воспроизведены или просмотрены в дальнейшем.
MediaLibrarySession
расширяет API MediaSession
для добавления API просмотра контента. По сравнению с обратным вызовом MediaSession
, обратный вызов MediaLibrarySession
добавляет такие методы, как:
-
onGetLibraryRoot()
, когда клиент запрашивает корневойMediaItem
дерева контента -
onGetChildren()
, когда клиент запрашивает дочерние элементыMediaItem
в дереве контента -
onGetSearchResult()
, когда клиент запрашивает результаты поиска из дерева контента для заданного запроса
Соответствующие методы обратного вызова будут включать объект LibraryParams
с дополнительными сигналами о типе дерева контента, который интересует клиентское приложение.
Кнопки управления для элементов мультимедиа
Приложение сеанса может объявлять кнопки команд, поддерживаемые MediaItem
в MediaMetadata
. Это позволяет назначить одну или несколько записей CommandButton
элементу мультимедиа, который контроллер может отображать и использовать для отправки пользовательской команды для элемента в сеанс удобным способом.
Кнопки команд настройки на стороне сеанса
При создании сеанса приложение сеанса объявляет набор кнопок команд, которые сеанс может обрабатывать как пользовательские команды:
Котлин
val allCommandButtons = listOf( CommandButton.Builder(CommandButton.ICON_PLAYLIST_ADD) .setDisplayName(context.getString(R.string.add_to_playlist)) .setSessionCommand(SessionCommand(COMMAND_PLAYLIST_ADD, Bundle.EMPTY)) .setExtras(playlistAddExtras) .build(), CommandButton.Builder(CommandButton.ICON_RADIO) .setDisplayName(context.getString(R.string.radio_station)) .setSessionCommand(SessionCommand(COMMAND_RADIO, Bundle.EMPTY)) .setExtras(radioExtras) .build(), // possibly more here ) // Add all command buttons for media items supported by the session. val session = MediaSession.Builder(context, player) .setCommandButtonsForMediaItems(allCommandButtons) .build()
Ява
ImmutableList<CommandButton> allCommandButtons = ImmutableList.of( new CommandButton.Builder(CommandButton.ICON_PLAYLIST_ADD) .setDisplayName(context.getString(R.string.add_to_playlist)) .setSessionCommand(new SessionCommand(COMMAND_PLAYLIST_ADD, Bundle.EMPTY)) .setExtras(playlistAddExtras) .build(), new CommandButton.Builder(CommandButton.ICON_RADIO) .setDisplayName(context.getString(R.string.radio_station)) .setSessionCommand(new SessionCommand(COMMAND_RADIO, Bundle.EMPTY)) .setExtras(radioExtras) .build()); // Add all command buttons for media items supported by the session. MediaSession session = new MediaSession.Builder(context, player) .setCommandButtonsForMediaItems(allCommandButtons) .build();
При создании элемента мультимедиа приложение сеанса может добавить набор поддерживаемых идентификаторов команд, которые ссылаются на команды сеанса кнопок команд, настроенных при создании сеанса:
Котлин
val mediaItem = MediaItem.Builder() .setMediaMetadata( MediaMetadata.Builder() .setSupportedCommands(listOf(COMMAND_PLAYLIST_ADD, COMMAND_RADIO)) .build()) .build()
Ява
MediaItem mediaItem = new MediaItem.Builder() .setMediaMetadata( new MediaMetadata.Builder() .setSupportedCommands(ImmutableList.of(COMMAND_PLAYLIST_ADD, COMMAND_RADIO)) .build()) .build();
Когда контроллер или браузер подключается или вызывает другой метод Callback
сеанса, приложение сеанса может проверить ControllerInfo
переданный в обратный вызов, чтобы получить максимальное количество кнопок команд, которые может отобразить контроллер или браузер. ControllerInfo
переданный в метод обратного вызова, предоставляет геттер для удобного доступа к этому значению. По умолчанию значение установлено на 0, что указывает на то, что браузер или контроллер не поддерживает эту функцию:
Котлин
override fun onGetItem( session: MediaLibrarySession, browser: MediaSession.ControllerInfo, mediaId: String, ): ListenableFuture<LibraryResult<MediaItem>> { val settableFuture = SettableFuture.create<LibraryResult<MediaItem>>() val maxCommandsForMediaItems = browser.maxCommandsForMediaItems scope.launch { loadMediaItem(settableFuture, mediaId, maxCommandsForMediaItems) } return settableFuture }
Ява
@Override public ListenableFuture<LibraryResult<MediaItem>> onGetItem( MediaLibraryService.MediaLibrarySession session, ControllerInfo browser, String mediaId) { SettableFuture<LibraryResult<MediaItem>> settableFuture = SettableFuture.create(); int maxCommandsForMediaItems = browser.getMaxCommandsForMediaItems(); loadMediaItemAsync(settableFuture, mediaId, maxCommandsForMediaItems); return settableFuture; }
При обработке пользовательского действия, отправленного для элемента мультимедиа, приложение сеанса может получить идентификатор элемента мультимедиа из аргументов Bundle
, переданных в onCustomCommand
:
Котлин
override fun onCustomCommand( session: MediaSession, controller: MediaSession.ControllerInfo, customCommand: SessionCommand, args: Bundle, ): ListenableFuture<SessionResult> { val mediaItemId = args.getString(MediaConstants.EXTRA_KEY_MEDIA_ID) return if (mediaItemId != null) handleCustomCommandForMediaItem(controller, customCommand, mediaItemId, args) else handleCustomCommand(controller, customCommand, args) }
Ява
@Override public ListenableFuture<SessionResult> onCustomCommand( MediaSession session, ControllerInfo controller, SessionCommand customCommand, Bundle args) { String mediaItemId = args.getString(MediaConstants.EXTRA_KEY_MEDIA_ID); return mediaItemId != null ? handleCustomCommandForMediaItem(controller, customCommand, mediaItemId, args) : handleCustomCommand(controller, customCommand, args); }
Используйте кнопки управления в качестве браузера или контроллера
На стороне MediaController
приложение может объявить максимальное количество кнопок управления, которые оно поддерживает для элемента мультимедиа, при создании MediaController
или MediaBrowser
:
Котлин
val browserFuture = MediaBrowser.Builder(context, sessionToken) .setMaxCommandsForMediaItems(3) .buildAsync()
Ява
ListenableFuture<MediaBrowser> browserFuture = new MediaBrowser.Builder(context, sessionToken) .setMaxCommandsForMediaItems(3) .buildAsync();
При подключении к сеансу приложение контроллера может получать кнопки команд, которые поддерживаются элементом мультимедиа и для которых контроллер имеет доступную команду, предоставленную приложением сеанса :
Котлин
val commandButtonsForMediaItem: List<CommandButton> = controller.getCommandButtonsForMediaItem(mediaItem)
Ява
ImmutableList<CommandButton> commandButtonsForMediaItem = controller.getCommandButtonsForMediaItem(mediaItem);
Для удобства MediaController
может отправлять специальные команды для определенных элементов мультимедиа с помощью MediaController.sendCustomCommand(SessionCommand, MediaItem, Bundle)
:
Котлин
controller.sendCustomCommand(addToPlaylistButton.sessionCommand!!, mediaItem, Bundle.EMPTY)
Ява
controller.sendCustomCommand( checkNotNull(addToPlaylistButton.sessionCommand), mediaItem, Bundle.EMPTY);
Медиа-приложения часто содержат коллекции медиа-элементов, организованные в иерархию. Например, песни в альбоме или эпизоды ТВ в плейлисте. Такая иерархия медиа-элементов известна как медиа-библиотека.
MediaLibraryService
предоставляет стандартизированный API для обслуживания и доступа к вашей медиатеке. Это может быть полезно, например, при добавлении поддержки Android Auto в ваше медиаприложение, которое предоставляет свой собственный безопасный для водителя пользовательский интерфейс для вашей медиатеке.
Создание службы MediaLibraryService
Реализация MediaLibraryService
аналогична реализации MediaSessionService
, за исключением того, что в методе onGetSession()
необходимо возвращать MediaLibrarySession
вместо MediaSession
.
Котлин
class PlaybackService : MediaLibraryService() { var mediaLibrarySession: MediaLibrarySession? = null var callback: MediaLibrarySession.Callback = object : MediaLibrarySession.Callback {...} // If desired, validate the controller before returning the media library session override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaLibrarySession? = mediaLibrarySession // Create your player and media library session in the onCreate lifecycle event override fun onCreate() { super.onCreate() val player = ExoPlayer.Builder(this).build() mediaLibrarySession = MediaLibrarySession.Builder(this, player, callback).build() } // Remember to release the player and media library session in onDestroy override fun onDestroy() { mediaLibrarySession?.run { player.release() release() mediaLibrarySession = null } super.onDestroy() } }
Ява
class PlaybackService extends MediaLibraryService { MediaLibrarySession mediaLibrarySession = null; MediaLibrarySession.Callback callback = new MediaLibrarySession.Callback() {...}; @Override public MediaLibrarySession onGetSession(MediaSession.ControllerInfo controllerInfo) { // If desired, validate the controller before returning the media library session return mediaLibrarySession; } // Create your player and media library session in the onCreate lifecycle event @Override public void onCreate() { super.onCreate(); ExoPlayer player = new ExoPlayer.Builder(this).build(); mediaLibrarySession = new MediaLibrarySession.Builder(this, player, callback).build(); } // Remember to release the player and media library session in onDestroy @Override public void onDestroy() { if (mediaLibrarySession != null) { mediaLibrarySession.getPlayer().release(); mediaLibrarySession.release(); mediaLibrarySession = null; } super.onDestroy(); } }
Не забудьте также указать свою Service
и требуемые разрешения в файле манифеста:
<service
android:name=".PlaybackService"
android:foregroundServiceType="mediaPlayback"
android:exported="true">
<intent-filter>
<action android:name="androidx.media3.session.MediaSessionService"/>
<action android:name="android.media.browse.MediaBrowserService"/>
</intent-filter>
</service>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
Использовать MediaLibrarySession
API MediaLibraryService
ожидает, что ваша медиабиблиотека будет структурирована в формате дерева с одним корневым узлом и дочерними узлами, которые могут быть воспроизведены или просмотрены в дальнейшем.
MediaLibrarySession
расширяет API MediaSession
для добавления API просмотра контента. По сравнению с обратным вызовом MediaSession
, обратный вызов MediaLibrarySession
добавляет такие методы, как:
-
onGetLibraryRoot()
, когда клиент запрашивает корневойMediaItem
дерева контента -
onGetChildren()
, когда клиент запрашивает дочерние элементыMediaItem
в дереве контента -
onGetSearchResult()
, когда клиент запрашивает результаты поиска из дерева контента для заданного запроса
Соответствующие методы обратного вызова будут включать объект LibraryParams
с дополнительными сигналами о типе дерева контента, который интересует клиентское приложение.
Кнопки управления для элементов мультимедиа
Приложение сеанса может объявлять кнопки команд, поддерживаемые MediaItem
в MediaMetadata
. Это позволяет назначить одну или несколько записей CommandButton
элементу мультимедиа, который контроллер может отображать и использовать для отправки пользовательской команды для элемента в сеанс удобным способом.
Кнопки команд настройки на стороне сеанса
При создании сеанса приложение сеанса объявляет набор кнопок команд, которые сеанс может обрабатывать как пользовательские команды:
Котлин
val allCommandButtons = listOf( CommandButton.Builder(CommandButton.ICON_PLAYLIST_ADD) .setDisplayName(context.getString(R.string.add_to_playlist)) .setSessionCommand(SessionCommand(COMMAND_PLAYLIST_ADD, Bundle.EMPTY)) .setExtras(playlistAddExtras) .build(), CommandButton.Builder(CommandButton.ICON_RADIO) .setDisplayName(context.getString(R.string.radio_station)) .setSessionCommand(SessionCommand(COMMAND_RADIO, Bundle.EMPTY)) .setExtras(radioExtras) .build(), // possibly more here ) // Add all command buttons for media items supported by the session. val session = MediaSession.Builder(context, player) .setCommandButtonsForMediaItems(allCommandButtons) .build()
Ява
ImmutableList<CommandButton> allCommandButtons = ImmutableList.of( new CommandButton.Builder(CommandButton.ICON_PLAYLIST_ADD) .setDisplayName(context.getString(R.string.add_to_playlist)) .setSessionCommand(new SessionCommand(COMMAND_PLAYLIST_ADD, Bundle.EMPTY)) .setExtras(playlistAddExtras) .build(), new CommandButton.Builder(CommandButton.ICON_RADIO) .setDisplayName(context.getString(R.string.radio_station)) .setSessionCommand(new SessionCommand(COMMAND_RADIO, Bundle.EMPTY)) .setExtras(radioExtras) .build()); // Add all command buttons for media items supported by the session. MediaSession session = new MediaSession.Builder(context, player) .setCommandButtonsForMediaItems(allCommandButtons) .build();
При создании элемента мультимедиа приложение сеанса может добавить набор поддерживаемых идентификаторов команд, которые ссылаются на команды сеанса кнопок команд, настроенных при создании сеанса:
Котлин
val mediaItem = MediaItem.Builder() .setMediaMetadata( MediaMetadata.Builder() .setSupportedCommands(listOf(COMMAND_PLAYLIST_ADD, COMMAND_RADIO)) .build()) .build()
Ява
MediaItem mediaItem = new MediaItem.Builder() .setMediaMetadata( new MediaMetadata.Builder() .setSupportedCommands(ImmutableList.of(COMMAND_PLAYLIST_ADD, COMMAND_RADIO)) .build()) .build();
Когда контроллер или браузер подключается или вызывает другой метод Callback
сеанса, приложение сеанса может проверить ControllerInfo
переданный в обратный вызов, чтобы получить максимальное количество кнопок команд, которые может отобразить контроллер или браузер. ControllerInfo
переданный в метод обратного вызова, предоставляет геттер для удобного доступа к этому значению. По умолчанию значение установлено на 0, что указывает на то, что браузер или контроллер не поддерживает эту функцию:
Котлин
override fun onGetItem( session: MediaLibrarySession, browser: MediaSession.ControllerInfo, mediaId: String, ): ListenableFuture<LibraryResult<MediaItem>> { val settableFuture = SettableFuture.create<LibraryResult<MediaItem>>() val maxCommandsForMediaItems = browser.maxCommandsForMediaItems scope.launch { loadMediaItem(settableFuture, mediaId, maxCommandsForMediaItems) } return settableFuture }
Ява
@Override public ListenableFuture<LibraryResult<MediaItem>> onGetItem( MediaLibraryService.MediaLibrarySession session, ControllerInfo browser, String mediaId) { SettableFuture<LibraryResult<MediaItem>> settableFuture = SettableFuture.create(); int maxCommandsForMediaItems = browser.getMaxCommandsForMediaItems(); loadMediaItemAsync(settableFuture, mediaId, maxCommandsForMediaItems); return settableFuture; }
При обработке пользовательского действия, отправленного для элемента мультимедиа, приложение сеанса может получить идентификатор элемента мультимедиа из аргументов Bundle
, переданных в onCustomCommand
:
Котлин
override fun onCustomCommand( session: MediaSession, controller: MediaSession.ControllerInfo, customCommand: SessionCommand, args: Bundle, ): ListenableFuture<SessionResult> { val mediaItemId = args.getString(MediaConstants.EXTRA_KEY_MEDIA_ID) return if (mediaItemId != null) handleCustomCommandForMediaItem(controller, customCommand, mediaItemId, args) else handleCustomCommand(controller, customCommand, args) }
Ява
@Override public ListenableFuture<SessionResult> onCustomCommand( MediaSession session, ControllerInfo controller, SessionCommand customCommand, Bundle args) { String mediaItemId = args.getString(MediaConstants.EXTRA_KEY_MEDIA_ID); return mediaItemId != null ? handleCustomCommandForMediaItem(controller, customCommand, mediaItemId, args) : handleCustomCommand(controller, customCommand, args); }
Используйте кнопки управления в качестве браузера или контроллера
На стороне MediaController
приложение может объявить максимальное количество кнопок управления, которые оно поддерживает для элемента мультимедиа, при создании MediaController
или MediaBrowser
:
Котлин
val browserFuture = MediaBrowser.Builder(context, sessionToken) .setMaxCommandsForMediaItems(3) .buildAsync()
Ява
ListenableFuture<MediaBrowser> browserFuture = new MediaBrowser.Builder(context, sessionToken) .setMaxCommandsForMediaItems(3) .buildAsync();
При подключении к сеансу приложение контроллера может получать кнопки команд, которые поддерживаются элементом мультимедиа и для которых контроллер имеет доступную команду, предоставленную приложением сеанса :
Котлин
val commandButtonsForMediaItem: List<CommandButton> = controller.getCommandButtonsForMediaItem(mediaItem)
Ява
ImmutableList<CommandButton> commandButtonsForMediaItem = controller.getCommandButtonsForMediaItem(mediaItem);
Для удобства MediaController
может отправлять специальные команды для определенных элементов мультимедиа с помощью MediaController.sendCustomCommand(SessionCommand, MediaItem, Bundle)
:
Котлин
controller.sendCustomCommand(addToPlaylistButton.sessionCommand!!, mediaItem, Bundle.EMPTY)
Ява
controller.sendCustomCommand( checkNotNull(addToPlaylistButton.sessionCommand), mediaItem, Bundle.EMPTY);