Medya oturumları, bir ses veya video oynatıcıyla etkileşim kurmak için evrensel bir yol sağlar. Media3'te varsayılan oynatıcı, Player
arayüzünü uygulayan ExoPlayer
sınıfıdır. Medya oturumunu oynatıcıya bağlamak, uygulamanın harici olarak medya oynatma reklamı yapmasına ve harici kaynaklardan oynatma komutları almasına olanak tanır.
Komutlar, mikrofonlu kulaklıktaki oynat düğmesi veya TV uzaktan kumandası gibi fiziksel düğmelerden gelebilir. Google Asistan'a "duraklatma" talimatı vermek gibi bir medya denetleyicisi olan istemci uygulamalarından da gelebilirler. Medya oturumu, bu komutları medya uygulamasının oynatıcısına aktarır.
Medya oturumu ne zaman seçilmelidir?
MediaSession
öğesini uyguladığınızda, kullanıcıların oynatmayı kontrol etmesine izin vermiş olursunuz:
- Kulaklıklarını kullanarak. Genellikle kullanıcılar medya içeriğini oynatmak veya duraklatmak ya da sonraki veya önceki parçaya gitmek için kulaklıklarında düğmeler veya dokunma etkileşimleri gerçekleştirir.
- Google Asistan'la konuşarak. Cihazda oynatılan medyaları duraklatmak için "Ok Google, paused" (Ok Google, duraklat) gibi yaygın bir kalıp kullanılır.
- Wear OS kol saati üzerinden. Bu şekilde çocuğunuzun telefonunda oynarken en yaygın oynatma kontrollerine daha kolay erişebilirsiniz.
- Medya kontrolleri aracılığıyla. Bu bant, çalışan her medya oturumuna ait kontrolleri gösterir.
- TV'de. Fiziksel oynatma düğmeleri, platform oynatma kontrolü ve güç yönetimiyle işlemlere izin verir (örneğin TV, ses çubuğu veya A/V alıcısı kapanırsa veya giriş değiştirilirse, uygulamada oynatma durmalıdır).
- Oynatmayı etkilemesi gereken diğer harici işlemler.
Bu, birçok kullanım alanı için idealdir. Özellikle şu durumlarda MediaSession
kullanmayı düşünmeniz gerekir:
- Filmler veya canlı TV gibi uzun video içeriklerini canlı oynatıyorsanız.
- Podcast veya müzik oynatma listeleri gibi uzun ses içeriklerini canlı oynatıyorsanız.
- TV uygulaması oluşturuyorsunuz.
Ancak tüm kullanım alanları MediaSession
ile uyumlu değildir. Aşağıdaki durumlarda yalnızca Player
özelliğini kullanmak isteyebilirsiniz:
- Kullanıcı etkileşimi ve etkileşiminin büyük önem taşıdığı kısa içerikler gösteriyorsunuz.
- Tek bir etkin video yoktur. Örneğin, kullanıcı bir listeyi kaydırıyor ve ekranda aynı anda birden fazla video gösteriliyor.
- Kullanıcınızın aktif olarak izlemesini beklediğiniz bir tek seferlik tanıtım veya açıklama videosunu oynatıyorsunuz.
- İçeriğiniz gizlilik açısından hassas ve harici işlemlerin medya meta verilerine erişmesini istemiyorsunuz (ör. bir tarayıcıda gizli mod)
Kullanım alanınız yukarıda listelenenlerin hiçbirine uymuyorsa kullanıcı içerikle aktif olarak etkileşimde bulunmadığında uygulamanızın
oynatmaya devam etmesini isteyip istemediğinizi düşünün. Yanıtınız evetse muhtemelen MediaSession
ürününü seçmek istersiniz. Yanıtınız hayırsa bunun yerine Player
öğesini kullanmak isteyebilirsiniz.
Medya oturumu oluşturma
Yönettiği oynatıcının yanında bir medya oturumu gerçekleşir. Bir Context
ve Player
nesnesiyle medya oturumu oluşturabilirsiniz. Gerektiğinde bir medya oturumu oluşturmanız ve başlatmanız gerekir. Örneğin, Activity
veya Fragment
'ın onStart()
ya da onResume()
yaşam döngüsü yöntemi veya medya oturumuna ve ilişkili oynatıcısına sahip olan Service
'nin onCreate()
yöntemi.
Medya oturumu oluşturmak için bir Player
başlatın ve MediaSession.Builder
öğesine şu şekilde sağlayın:
Kotlin
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();
Otomatik durum işleme
Media3 kitaplığı, oynatıcının durumunu kullanarak medya oturumunu otomatik olarak günceller. Bu nedenle, oynatıcıdan oturuma eşleme işlemini manuel olarak yapmanız gerekmez.
Bu, oynatıcının kendisinden bağımsız bir şekilde bir PlaybackStateCompat
oluşturup sürdürmeniz (örneğin, hataları belirtmek için) gereken eski yaklaşımdan bir ara oluşturur.
Benzersiz oturum kimliği
Varsayılan olarak MediaSession.Builder
, oturum kimliği olarak boş bir dizeyle oturum oluşturur. Bir uygulama yalnızca tek bir oturum örneği oluşturmayı planlıyorsa bu yeterlidir. Bu, en sık karşılaşılan durumdur.
Bir uygulama aynı anda birden fazla oturum örneğini yönetmek istiyorsa uygulama her oturumun oturum kimliğinin benzersiz olduğundan emin olmalıdır. MediaSession.Builder.setId(String id)
ile oturum oluştururken oturum kimliği ayarlanabilir.
IllegalStateException: Session ID must be unique. ID=
hata mesajıyla uygulamanızı kilitleyen bir IllegalStateException
görürseniz aynı kimliğe sahip daha önce oluşturulmuş bir örnek yayınlanmadan önce beklenmedik bir şekilde bir oturum oluşturulmuş olabilir. Oturumların bir programlama hatası tarafından sızdırılmasını önlemek için bu tür durumlar tespit edilir ve bir istisna uygulanarak bilgilendirilir.
Diğer istemcilere denetim izni ver
Medya oturumu, oynatmayı kontrol etmenin en önemli unsurudur. Harici kaynaklardan gelen komutları, medyanızı oynatma işlemini yapan oynatıcıya yönlendirmenizi sağlar. Bu kaynaklar; mikrofonlu kulaklıktaki veya TV uzaktan kumandasındaki oynat düğmesi gibi fiziksel düğmeler ya da Google Asistan'a "duraklat" talimatı gibi dolaylı komutlar olabilir. Benzer şekilde, bildirim ve kilit ekranı kontrollerini kolaylaştırmak için Android sistemine veya oynatmayı kadrandan kontrol edebilmek için Wear OS kol saatine erişim izni verebilirsiniz. Harici istemciler, medya uygulamanıza oynatma komutları yayınlamak için bir medya denetleyici kullanabilir. Bunlar medya oturumunuz tarafından alınır, ardından komutlar medya oynatıcıya yetki verir.
Bir denetleyici, medya oturumunuza bağlanmak üzereyken onConnect()
yöntemi çağrılır. İsteği kabul etmeye veya reddetmeye karar vermek için sağlanan ControllerInfo
öğesini kullanabilirsiniz. Bağlantı isteğini kabul etmeyle ilgili bir örneği Kullanılabilir komutları bildirme bölümünde görebilirsiniz.
Bağlantı kurulduktan sonra kumanda, oturuma oynatma komutları gönderebilir. Ardından oturum, bu komutları oyuncuya delege eder. Player
arayüzünde tanımlanan oynatma ve oynatma listesi komutları, oturum tarafından otomatik olarak işlenir.
Diğer geri çağırma yöntemleri, örneğin özel oynatma komutları ve oynatma listesini değiştirme gibi istekleri yönetmenize olanak tanır.
Bu geri çağırma işlevleri benzer şekilde ControllerInfo
nesnesi içerir. Böylece her isteğe nasıl yanıt vereceğinizi denetleyici bazında değiştirebilirsiniz.
Oynatma listesini değiştirme
Bir medya oturumu, oynatma listeleri için ExoPlayer kılavuzunda açıklandığı gibi, oynatıcısının oynatma listesini doğrudan değiştirebilir.
Ayrıca kumandada COMMAND_SET_MEDIA_ITEM
veya COMMAND_CHANGE_MEDIA_ITEMS
kullanılabiliyorsa oynatma listesi üzerinde değişiklik yapılabilir.
Oynatma listesine yeni öğeler eklerken oynatıcı genellikle bunların oynatılabilmesi için tanımlanmış URI ile MediaItem
örneklerine ihtiyaç duyar. Varsayılan olarak, yeni eklenen öğeler tanımlı bir URI'ya sahipse player.addMediaItem
gibi oynatıcı yöntemlerine otomatik olarak yönlendirilir.
Oynatıcıya eklenen MediaItem
örneklerini özelleştirmek isterseniz onAddMediaItems()
örneğini geçersiz kılabilirsiniz.
Bu adım, tanımlanmış bir URI olmadan medya isteğinde bulunan denetleyicileri desteklemek istediğinizde gereklidir. Bunun yerine, MediaItem
genellikle istenen medyayı açıklamak için aşağıdaki alanlardan birini veya daha fazlasını içerir:
MediaItem.id
: Medyayı tanımlayan genel bir kimliktir.MediaItem.RequestMetadata.mediaUri
: Özel bir şema kullanabilecek ve oynatıcı tarafından doğrudan oynatılabilmesi gerekmeyen bir istek URI'si.MediaItem.RequestMetadata.searchQuery
: Metin biçiminde bir arama sorgusu (örneğin, Google Asistan'dan).MediaItem.MediaMetadata
: "Başlık" veya "sanatçı" gibi yapılandırılmış meta veriler.
Tamamen yeni oynatma listeleriyle ilgili daha fazla özelleştirme seçeneği için başlangıç öğesini ve oynatma listesindeki konumu tanımlamanıza olanak tanıyan onSetMediaItems()
değerini de geçersiz kılabilirsiniz. Örneğin, istenen tek bir öğeyi oynatma listesinin tamamını genişletebilir ve oynatıcıya, başlangıçta istenen öğenin dizininden başlamasını söyleyebilirsiniz. Bu özellik ile onSetMediaItems()
örnek uygulamasını oturum demo uygulamasında bulabilirsiniz.
Özel düzeni ve özel komutları yönetin
Aşağıdaki bölümlerde, özel komut düğmeleri düzeninin istemci uygulamalarına nasıl tanıtılacağı ve özel komutları göndermek için denetleyicilere nasıl yetki verileceği açıklanmaktadır.
Oturumun özel düzenini tanımlayın
İstemci uygulamalarına hangi oynatma kontrollerinin kullanıcıya gösterilmesini istediğinizi belirtmek için hizmetinizin onCreate()
yönteminde MediaSession
oluştururken oturumun özel düzenini ayarlayın.
Kotlin
override fun onCreate() { super.onCreate() val likeButton = CommandButton.Builder() .setDisplayName("Like") .setIconResId(R.drawable.like_icon) .setSessionCommand(SessionCommand(SessionCommand.COMMAND_CODE_SESSION_SET_RATING)) .build() val favoriteButton = CommandButton.Builder() .setDisplayName("Save to favorites") .setIconResId(R.drawable.favorite_icon) .setSessionCommand(SessionCommand(SAVE_TO_FAVORITES, Bundle())) .build() session = MediaSession.Builder(this, player) .setCallback(CustomMediaSessionCallback()) .setCustomLayout(ImmutableList.of(likeButton, favoriteButton)) .build() }
Java
@Override public void onCreate() { super.onCreate(); CommandButton likeButton = new CommandButton.Builder() .setDisplayName("Like") .setIconResId(R.drawable.like_icon) .setSessionCommand(new SessionCommand(SessionCommand.COMMAND_CODE_SESSION_SET_RATING)) .build(); CommandButton favoriteButton = new CommandButton.Builder() .setDisplayName("Save to favorites") .setIconResId(R.drawable.favorite_icon) .setSessionCommand(new SessionCommand(SAVE_TO_FAVORITES, new Bundle())) .build(); Player player = new ExoPlayer.Builder(this).build(); mediaSession = new MediaSession.Builder(this, player) .setCallback(new CustomMediaSessionCallback()) .setCustomLayout(ImmutableList.of(likeButton, favoriteButton)) .build(); }
Kullanılabilir oynatıcıyı ve özel komutları bildir
Medya uygulamaları, örneğin özel bir düzende kullanılabilecek özel komutlar tanımlayabilir. Örneğin, kullanıcının bir medya öğesini favori öğeler listesine kaydetmesine
izin veren düğmeler uygulamak isteyebilirsiniz. MediaController
, özel komutlar gönderir, MediaSession.Callback
ise bunları alır.
Medya oturumunuza bağlandığında MediaController
tarafından hangi özel oturum komutlarının kullanılabileceğini tanımlayabilirsiniz. Bunu, MediaSession.Callback.onConnect()
değerini geçersiz kılarak elde edersiniz. onConnect
geri çağırma yönteminde, MediaController
özelliğinden gelen bir bağlantı isteğini kabul ederken kullanılabilir komut grubunu yapılandırın ve döndürün:
Kotlin
private inner class CustomMediaSessionCallback: MediaSession.Callback { // Configure commands available to the controller in onConnect() override fun onConnect( session: MediaSession, controller: MediaSession.ControllerInfo ): MediaSession.ConnectionResult { val sessionCommands = ConnectionResult.DEFAULT_SESSION_COMMANDS.buildUpon() .add(SessionCommand(SAVE_TO_FAVORITES, Bundle.EMPTY)) .build() return AcceptedResultBuilder(session) .setAvailableSessionCommands(sessionCommands) .build() } }
Java
class CustomMediaSessionCallback implements MediaSession.Callback { // Configure commands available to the controller in onConnect() @Override public ConnectionResult onConnect( MediaSession session, ControllerInfo controller) { SessionCommands sessionCommands = ConnectionResult.DEFAULT_SESSION_COMMANDS.buildUpon() .add(new SessionCommand(SAVE_TO_FAVORITES, new Bundle())) .build(); return new AcceptedResultBuilder(session) .setAvailableSessionCommands(sessionCommands) .build(); } }
MediaController
öğesinden özel komut istekleri almak için Callback
içindeki onCustomCommand()
yöntemini geçersiz kılın.
Kotlin
private inner class CustomMediaSessionCallback: MediaSession.Callback { ... override fun onCustomCommand( session: MediaSession, controller: MediaSession.ControllerInfo, customCommand: SessionCommand, args: Bundle ): ListenableFuture<SessionResult> { if (customCommand.customAction == SAVE_TO_FAVORITES) { // Do custom logic here saveToFavorites(session.player.currentMediaItem) return Futures.immediateFuture( SessionResult(SessionResult.RESULT_SUCCESS) ) } ... } }
Java
class CustomMediaSessionCallback implements MediaSession.Callback { ... @Override public ListenableFuture<SessionResult> onCustomCommand( MediaSession session, ControllerInfo controller, SessionCommand customCommand, Bundle args ) { if(customCommand.customAction.equals(SAVE_TO_FAVORITES)) { // Do custom logic here saveToFavorites(session.getPlayer().getCurrentMediaItem()); return Futures.immediateFuture( new SessionResult(SessionResult.RESULT_SUCCESS) ); } ... } }
Callback
yöntemlerine iletilen MediaSession.ControllerInfo
nesnesinin packageName
özelliğini kullanarak hangi medya denetleyicisinin istekte bulunduğunu izleyebilirsiniz. Bu sayede uygulamanızın sistemden, kendi uygulamanızdan veya başka istemci uygulamalarından geliyorsa davranışını belirli bir komuta göre özelleştirebilirsiniz.
Kullanıcı etkileşiminden sonra özel düzeni güncelleme
Özel bir komut verdikten veya oynatıcınızla başka herhangi bir etkileşimde bulunduktan sonra, kumanda arayüzünde gösterilen düzeni güncellemek isteyebilirsiniz. Tipik bir örnek, bu düğmeyle ilişkili işlemi tetikledikten sonra simgesini değiştiren bir açma/kapatma düğmesidir. Düzeni güncellemek için MediaSession.setCustomLayout
:
Kotlin
val removeFromFavoritesButton = CommandButton.Builder() .setDisplayName("Remove from favorites") .setIconResId(R.drawable.favorite_remove_icon) .setSessionCommand(SessionCommand(REMOVE_FROM_FAVORITES, Bundle())) .build() mediaSession.setCustomLayout(ImmutableList.of(likeButton, removeFromFavoritesButton))
Java
CommandButton removeFromFavoritesButton = new CommandButton.Builder() .setDisplayName("Remove from favorites") .setIconResId(R.drawable.favorite_remove_icon) .setSessionCommand(new SessionCommand(REMOVE_FROM_FAVORITES, new Bundle())) .build(); mediaSession.setCustomLayout(ImmutableList.of(likeButton, removeFromFavoritesButton));
Oynatma komutu davranışını özelleştirme
Player
arayüzünde play()
veya seekToNext()
gibi tanımlı bir komutun davranışını özelleştirmek için Player
öğenizi ForwardingPlayer
içine yerleştirin.
Kotlin
val player = ExoPlayer.Builder(context).build() val forwardingPlayer = object : ForwardingPlayer(player) { override fun play() { // Add custom logic super.play() } override fun setPlayWhenReady(playWhenReady: Boolean) { // Add custom logic super.setPlayWhenReady(playWhenReady) } } val mediaSession = MediaSession.Builder(context, forwardingPlayer).build()
Java
ExoPlayer player = new ExoPlayer.Builder(context).build(); ForwardingPlayer forwardingPlayer = new ForwardingPlayer(player) { @Override public void play() { // Add custom logic super.play(); } @Override public void setPlayWhenReady(boolean playWhenReady) { // Add custom logic super.setPlayWhenReady(playWhenReady); } }; MediaSession mediaSession = new MediaSession.Builder(context, forwardingPlayer).build();
ForwardingPlayer
hakkında daha fazla bilgi için Özelleştirme ile ilgili ExoPlayer kılavuzuna bakın.
Oynatıcı komutunun istekte bulunan denetleyicisini tanımlayın
Player
yöntemi için yapılan çağrı bir MediaController
tarafından gerçekleştirildiğinde, kaynak kaynağını MediaSession.controllerForCurrentRequest
ile belirleyebilir ve mevcut istek için ControllerInfo
değerini edinebilirsiniz:
Kotlin
class CallerAwareForwardingPlayer(player: Player) : ForwardingPlayer(player) { override fun seekToNext() { Log.d( "caller", "seekToNext called from package ${session.controllerForCurrentRequest?.packageName}" ) super.seekToNext() } }
Java
public class CallerAwareForwardingPlayer extends ForwardingPlayer { public CallerAwareForwardingPlayer(Player player) { super(player); } @Override public void seekToNext() { Log.d( "caller", "seekToNext called from package: " + session.getControllerForCurrentRequest().getPackageName()); super.seekToNext(); } }
Medya düğmelerine yanıt verme
Medya düğmeleri, Android cihazlarda ve diğer çevre birimi cihazlarında bulunan (Bluetooth mikrofonlu kulaklıktaki oynat/duraklat düğmesi gibi) donanım düğmeleridir. Media3, oturuma geldiğinde sizin için medya düğmesi etkinliklerini işler ve oturum oynatıcısında uygun Player
yöntemini çağırır.
Bir uygulama, MediaSession.Callback.onMediaButtonEvent(Intent)
değerini geçersiz kılarak varsayılan davranışı geçersiz kılabilir. Böyle bir durumda, uygulamanın tüm API özelliklerini kendi başına işlemesi gerekir/gerekir.