MediaLibraryService ile içerik sunma

Medya uygulamaları genellikle hiyerarşik olarak düzenlenmiş medya öğesi koleksiyonları içerir. Örneğin, bir albümdeki şarkılar veya oynatma listesindeki TV bölümleri. Medya öğelerinin bu hiyerarşisine medya kitaplığı denir.

Hiyerarşik olarak düzenlenmiş medya içeriği örnekleri
Şekil 1: Medya kitaplığı oluşturan medya öğesi hiyerarşisi örnekleri.

MediaLibraryService, medya kitaplığınıza erişmek ve kitaplığınızı sunmak için standartlaştırılmış bir API sağlar. Bu, örneğin, medya kitaplığınız için kendi sürücü güvenli kullanıcı arayüzünü sağlayan medya uygulamanıza Android Auto desteği eklerken yararlı olabilir.

MediaLibraryService oluşturun

MediaLibraryService uygulamak, MediaSessionService uygulamanıza benzer. Tek fark, onGetSession() yönteminde MediaSession yerine MediaLibrarySession döndürmeniz gerekmesidir.

Kotlin

class PlaybackService : MediaLibraryService() {
  private var mediaLibrarySession: MediaLibrarySession? = null
  private val callback: MediaLibrarySession.Callback =
    object : MediaLibrarySession.Callback {
      /* ... */
    }

  override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaLibrarySession? {
    // 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 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()
  }
}

Java

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 ve gerekli izinleri manifest dosyasında da beyan etmeyi unutmayın:

<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" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />

Hizmetinizi hem platform hem de Media3 hizmet arayüzü olarak kaydetmeniz önerilir:

  • Platform medya oturumu API'lerini kullanan istemcilerle uyumluluk için intent-filter öğesine <action android:name="android.media.browse.MediaBrowserService"/> eklemeniz önerilir. Media3, bu hizmet arayüzüne otomatik olarak geriye dönük uyumluluk sağlar.

  • Geleceğe hazır bir kurulum için ve Media3 kullanan uygulamaların Media3 API'yi kullanarak hizmetinizle iletişim kurabilmesi için platform seçeneğiyle birlikte <action android:name="androidx.media3.session.MediaLibraryService"/> sağlanmalıdır.

Bu sayede uygulamalar, PackageManager üzerinden hizmetinizi bulabilir ve bu arayüzlerden biri aracılığıyla MediaBrowser ile bağlantı kurabilir.

MediaLibrarySession kullanın

MediaLibraryService API'si, medya kitaplığınızın tek bir kök düğüm ve oynatılabilir veya daha fazla göz atılabilir alt düğüm içeren bir ağaç biçiminde yapılandırılmasını bekler.

MediaLibrarySession, içerik tarama API'leri eklemek için MediaSession API'sini genişletir. MediaSession geri çağırma işleviyle karşılaştırıldığında MediaLibrarySession geri çağırma işlevi, aşağıdaki gibi yöntemler ekler:

  • İstemci, bir içerik ağacının kök MediaItem değerini istediğinde onGetLibraryRoot()
  • İçerik ağacında bir MediaItem öğesinin alt öğeleri istendiğinde onGetChildren()
  • onGetSearchResult(): İstemci, belirli bir sorgu için içerik ağacından arama sonuçları istediğinde kullanılır.

İlgili geri çağırma yöntemleri, istemci uygulamasının ilgilendiği içerik ağacı türü hakkında ek sinyaller içeren bir LibraryParams nesnesi içerir.

Medya öğeleri için komut düğmeleri

Oturum uygulaması, MediaMetadata içinde MediaItem tarafından desteklenen komut düğmelerini bildirebilir. Bu sayede, bir denetleyicinin görüntüleyebileceği ve öğenin özel komutunu oturuma kolayca göndermek için kullanabileceği bir medya öğesine bir veya daha fazla CommandButton girişi atanabilir.

Oturum tarafında komut düğmelerini ayarlama

Oturum uygulaması, oturumu oluştururken oturumun özel komut olarak işleyebileceği komut düğmelerini bildirir:

Kotlin

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(),
  )
// Add all command buttons for media items supported by the session.
val session =
  MediaSession.Builder(context, player)
    .setCommandButtonsForMediaItems(allCommandButtons)
    .build()

Java

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();

Medya öğesi oluştururken oturum uygulaması, oturum oluşturulurken ayarlanmış komut düğmelerinin oturum komutlarına referans veren bir dizi desteklenen komut kimliği ekleyebilir:

Kotlin

val mediaItem =
  MediaItem.Builder()
    .setMediaMetadata(
      MediaMetadata.Builder()
        .setSupportedCommands(listOf(COMMAND_PLAYLIST_ADD, COMMAND_RADIO))
        .build()
    )
    .build()

Java

MediaItem mediaItem =
    new MediaItem.Builder()
        .setMediaMetadata(
            new MediaMetadata.Builder()
                .setSupportedCommands(ImmutableList.of(COMMAND_PLAYLIST_ADD, COMMAND_RADIO))
                .build())
        .build();

Bir kumanda veya tarayıcı bağlandığında ya da oturumun başka bir yöntemini çağırdığında Callback, oturum uygulaması, bir kumandanın veya tarayıcının görüntüleyebileceği maksimum komut düğmesi sayısını almak için geri çağırmaya iletilen ControllerInfo değerini inceleyebilir. Geri çağırma yöntemine iletilen ControllerInfo, bu değere kolayca erişmek için bir alıcı sağlar. Varsayılan olarak değer 0'dır. Bu değer, tarayıcının veya denetleyicinin bu özelliği desteklemediğini gösterir:

Kotlin

override fun onGetItem(
  session: MediaLibrarySession,
  browser: MediaSession.ControllerInfo,
  mediaId: String,
): ListenableFuture<LibraryResult<MediaItem>> {
  val settableFuture = SettableFuture.create<LibraryResult<MediaItem>>()

  val maxCommandsForMediaItems = browser.maxCommandsForMediaItems
  loadMediaItemAsync(settableFuture, mediaId, maxCommandsForMediaItems)

  return settableFuture
}

Java

@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;
}

Bir medya öğesi için gönderilen özel işlemi işlerken oturum uygulaması, onCustomCommand yöntemine iletilen Bundle bağımsız değişkenlerinden medya öğesi kimliğini alabilir:

Kotlin

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)
}

Java

@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);
}

Komut düğmelerini tarayıcı veya kumanda olarak kullanma

MediaController tarafında, bir uygulama MediaController veya MediaBrowser oluştururken bir medya öğesi için desteklediği maksimum komut düğmesi sayısını bildirebilir:

Kotlin

val browserFuture =
  MediaBrowser.Builder(context, sessionToken).setMaxCommandsForMediaItems(3).buildAsync()

Java

ListenableFuture<MediaBrowser> browserFuture =
    new MediaBrowser.Builder(context, sessionToken).setMaxCommandsForMediaItems(3).buildAsync();

Oturuma bağlandığında kumanda uygulaması, medya öğesi tarafından desteklenen ve kumandanın oturum uygulaması tarafından verilen kullanılabilir komuta sahip olduğu komut düğmelerini alabilir:

Kotlin

val commandButtonsForMediaItem = controller.getCommandButtonsForMediaItem(mediaItem)

Java

ImmutableList<CommandButton> commandButtonsForMediaItem =
    controller.getCommandButtonsForMediaItem(mediaItem);

Kotlin

val future =
  controller.sendCustomCommand(
    requireNotNull(addToPlaylistButton.sessionCommand),
    mediaItem,
    Bundle.EMPTY,
  )

Java

ListenableFuture<SessionResult> future =
    controller.sendCustomCommand(
        checkNotNull(addToPlaylistButton.sessionCommand), mediaItem, Bundle.EMPTY);