Medya oturumları, ses veya video oynatıcıyla etkileşime geçmenin evrensel bir yolunu sunar. 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 medya oynatmanın reklamını harici olarak yapmasına ve harici kaynaklardan oynatma komutları almasına olanak tanır.
Komutlar, kulaklıktaki veya TV uzaktan kumandanızdaki oynatma düğmesi gibi fiziksel düğmelerden gelebilir. Bu komutlar, medya denetleyicisi olan istemci uygulamalarından da gelebilir (ör. Google Asistan'a "duraklat" komutu verme). Medya oturumu bu komutları medya uygulamasının oynatıcısına iletir.
Medya oturumu ne zaman seçilir?
MediaSession
özelliğini uyguladığınızda kullanıcıların oynatmayı kontrol etmesine izin vermiş olursunuz:
- Kulaklıklarından. Kullanıcıların, medyayı oynatmak veya duraklatmak ya da sonraki veya önceki parçaya gitmek için kulaklıklarında kullanabileceği düğmeler veya dokunma etkileşimleri genellikle vardır.
- Google Asistan ile konuşarak. Cihazda oynatılan medyayı duraklatmak için "Ok Google, duraklat" demeniz yeterlidir.
- Wear OS kol saati üzerinden. Bu sayede, telefonda oynarken en yaygın oynatma denetimlerine daha kolay erişebilirler.
- Medya kontrolleri'ni kullanarak. Bu bantta, çalışan her medya oturumunun kontrolleri gösterilir.
- TV'de. Fiziksel oynatma düğmeleriyle, platform oynatma kontrolüyle ve güç yönetimiyle ilgili işlemlere izin verir (ör. TV, ses çubuğu veya A/V alıcı kapanırsa ya da giriş değiştirilirse uygulamada oynatma durdurulur).
- Oynatmayı etkilemesi gereken diğer harici işlemler.
Bu, birçok kullanım alanı için mükemmeldir. Özellikle aşağıdaki durumlarda MediaSession
kullanmayı kesinlikle düşünmeniz önerilir:
- Film veya canlı TV gibi uzun video içerikleri yayınlıyorsanız
- Podcast'ler veya müzik oynatma listeleri gibi uzun ses içerikleri yayınlıyorsanız
- TV uygulaması oluşturuyorsanız
Ancak tüm kullanım alanları MediaSession
ile uyumlu değildir. Aşağıdaki durumlarda yalnızca Player
simgesini kullanabilirsiniz:
- Kullanıcı etkileşimi ve etkileşiminin büyük önem taşıdığı kısa içerikler gösteriyorsunuz.
- Tek bir etkin video yoktur (ör. kullanıcı bir listede gezinirken ekranda aynı anda birden fazla video gösterilir).
- Kullanıcınızın etkin bir şekilde izleyeceğini düşündüğünüz tek seferlik bir tanıtım veya açıklama videosu oynatıyorsunuz.
- İçeriğiniz gizliliğe duyarlı ve harici işlemlerin medya meta verilerine erişmesini istemiyorsunuz (ör. tarayıcıda gizli mod)
Kullanım alanınız yukarıda listelenenlerden hiçbirine uymuyorsa kullanıcı içerikle aktif olarak etkileşimde değilken uygulamanızın oynatmaya devam etmesine izin verip vermeyeceğinizi düşünün. Yanıt evetse muhtemelen MediaSession
seçeneğini tercih edersiniz. Cevabınız hayırsa bunun yerine Player
öğesini kullanmanız daha verimli olabilir.
Medya oturumu oluşturma
Yönettiği oynatıcının yanında bir medya oturumu gerçekleşir. Context
ve Player
nesnesi kullanarak bir medya oturumu oluşturabilirsiniz. Gerektiği zaman bir medya oturumu oluşturup başlatmanız gerekir. Örneğin, Activity
veya Fragment
öğesinin onStart()
ya da onResume()
yaşam döngüsü yöntemi ya da medya oturumunun ve ilişkili oynatıcının sahibi olan Service
öğesinin onCreate()
yöntemi.
Medya oturumu oluşturmak için bir Player
başlatın ve MediaSession.Builder
'a ş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 yönetimi
Media3 kitaplığı, oynatıcının durumunu kullanarak medya oturumunu otomatik olarak günceller. Bu nedenle, oynatıcıdan oturuma eşlemeyi manuel olarak yönetmeniz gerekmez.
Bu, örneğin hataları belirtmek için oynatıcıdan bağımsız olarak bir PlaybackStateCompat
oluşturmanız ve sürdürmeniz gereken eski yaklaşımdan farklıdır.
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ı amaçlıyorsa (en yaygın durum budur) bu yeterlidir.
Bir uygulama aynı anda birden fazla oturum örneğini yönetmek istiyorsa 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
hatası ile uygulamanızın kilitlendiğini ve IllegalStateException: Session ID must be unique. ID=
hata mesajını görüyorsanız muhtemelen aynı kimliğe sahip daha önce oluşturulmuş bir örnek yayınlanmadan önce beklenmedik bir şekilde bir oturum oluşturulmuştur. Oturumların bir programlama hatası nedeniyle sızdırılmasının önüne geçmek için bu tür durumlar algılanır ve bir istisna atılarak bildirilir.
Diğer istemcilere kontrol verme
Medya oturumu, oynatmayı kontrol etmenin en önemli unsurudur. Harici kaynaklardan gelen komutları, medyanızı oynatan oynatıcıya yönlendirmenizi sağlar. Bu kaynaklar, mikrofonlu kulaklık veya TV uzaktan kumandasındaki oynatma düğmesi gibi fiziksel düğmeler ya da Google Asistan'a "duraklat" talimatı verme gibi dolaylı komutlar olabilir. Benzer şekilde, bildirim ve kilit ekranı denetimlerini 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ı göndermek için medya denetleyici kullanabilir. Bu komutlar medya oturumunuz tarafından alınır ve nihayetinde medya oynatıcıya iletilir.
Bir kumanda medya oturumunuza bağlanmak üzereyken onConnect()
yöntemi çağrılır. İsteği kabul etmek veya reddetmek için sağlanan ControllerInfo
simgesini kullanabilirsiniz. Kullanılabilir komutları tanımlama bölümünde, bağlantı isteğini kabul etme örneğini görebilirsiniz.
Denetleyici, bağlandıktan sonra oturuma oynatma komutları gönderebilir. Oturum daha sonra bu komutları oynatıcıya iletir. 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 isteklerini işlemenize olanak tanır.
Bu geri çağırma işlevleri de benzer şekilde bir ControllerInfo
nesnesi içerir. Böylece, her isteğe verdiğiniz yanıtı kontrolör 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ının, oynatılabilmeleri için genellikle MediaItem
tanımlanmış URI
bulunan örneklere ihtiyacı vardır. 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 istiyorsanız onAddMediaItems()
öğesini geçersiz kılabilirsiniz.
Tanımlanmış bir URI olmadan medya isteyen denetleyicileri desteklemek istediğinizde bu adım gereklidir. Bunun yerine, MediaItem
genellikle istenen medyayı tanımlamak için aşağıdaki alanlardan en az birini içerir:
MediaItem.id
: Medyayı tanımlayan genel bir kimliktir.MediaItem.RequestMetadata.mediaUri
: Özel bir şema kullanabilen ve oynatıcı tarafından doğrudan oynatılması gerekmeyen bir istek URI'si.MediaItem.RequestMetadata.searchQuery
: Google Asistan'dan alınan metin arama sorgusu gibi.MediaItem.MediaMetadata
: "Başlık" veya "sanatçı" gibi yapılandırılmış meta veriler.
Tamamen yeni şarkı listeleri için daha fazla özelleştirme seçeneği sunmak istiyorsanız şarkı listesinde başlangıç öğesini ve konumunu tanımlamanıza olanak tanıyan onSetMediaItems()
parametresini de geçersiz kılabilirsiniz. Örneğin, istenen tek bir öğeyi oynatma listesinin tamamına genişletebilir ve oynatıcıya başlangıç olarak istenen öğenin dizini gösterilmesini sağlayabilirsiniz. Bu özelliğin kullanıldığı onSetMediaItems()
örnek uygulamasını oturum demo uygulamasında bulabilirsiniz.
Özel düzeni ve özel komutları yönetme
Aşağıdaki bölümlerde, istemci uygulamalarına özel komut düğmelerinin özel düzeninin nasıl tanıtılacağı ve denetleyicilerin özel komutları göndermesi için nasıl yetkilendirileceği açıklanmaktadır.
Oturum için özel düzen tanımlama
İstemci uygulamalarına kullanıcıya göstermek istediğiniz oynatma denetimlerini 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ı ve özel komutları belirtme
Medya uygulamaları, örneğin özel bir düzende kullanılabilecek özel komutlar tanımlayabilir. Örneğin, kullanıcının bir medya öğesini favoriler listesine kaydetmesine olanak tanıyan düğmeler uygulamak isteyebilirsiniz. MediaController
, özel komutlar gönderir ve MediaSession.Callback
bunları alır.
MediaController
, medya oturumunuza bağlandığında hangi özel oturum komutlarını kullanabileceğini tanımlayabilirsiniz. Bunu MediaSession.Callback.onConnect()
değerini geçersiz kılarak yapabilirsiniz. onConnect
geri çağırma yönteminde bir MediaController
kullanıcısından gelen bağlantı isteğini kabul ederken kullanılabilen komutları 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(); } }
Bir MediaController
'ten özel komut istekleri almak için Callback
'deki 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
mülkünü kullanarak hangi medya denetleyicinin istek gönderdiğini izleyebilirsiniz. Bu sayede, sistemden, kendi uygulamanızdan veya diğer istemci uygulamalarından gelen belirli bir komuta yanıt olarak uygulamanızın davranışını özelleştirebilirsiniz.
Kullanıcı etkileşiminden sonra özel düzeni güncelleme
Özel bir komutu veya oynatıcınızla başka bir etkileşimi işledikten sonra, kumanda kullanıcı 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
şunları kullanabilirsiniz:
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 tanımlanan bir komutun (ör. play()
veya seekToNext()
) davranışını özelleştirmek için Player
'nizi ForwardingPlayer
içine alın.
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 istek gönderen denetleyicisini tanımlama
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 birimleri cihazlarında bulunan donanım düğmeleridir (ör. Bluetooth kulaklıktaki oynatma/duraklatma düğmesi). Media3, oturuma ulaşan medya düğmesi etkinliklerini sizin için yönetir 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 uygulama, tüm API özelliklerini kendi başına işleyebilir/işlemelidir.
Hata işleme ve raporlama
Bir oturumun yayınladığı ve denetleyicilere bildirdiği iki tür hata vardır. Önemli hatalar, oturum oynatıcısında oynatmayı kesintiye uğratan teknik bir oynatma hatası olduğunu bildirir. Önemli hatalar oluştuğunda denetleyiciye otomatik olarak bildirilir. Önemli olmayan hatalar, oynatmayı kesintiye uğratmayan ve uygulama tarafından manuel olarak kontrol cihazlarına gönderilen teknik olmayan veya politika hatalarıdır.
Önemli oynatma hataları
Önemli bir oynatma hatası, oynatıcı tarafından oturuma bildirilir ve ardından Player.Listener.onPlayerError(PlaybackException)
ve Player.Listener.onPlayerErrorChanged(@Nullable PlaybackException)
üzerinden çağrı yapılması için denetleyicilere bildirilir.
Böyle bir durumda, oynatma durumu STATE_IDLE
olarak değiştirilir ve MediaController.getPlaybackError()
, geçişe neden olan PlaybackException
değerini döndürür. Denetleyici, hatanın nedeni hakkında bilgi edinmek için PlayerException.errorCode
öğesini inceleyebilir.
Birlikte çalışabilirlik için önemli bir hata, platform oturumunun durumu STATE_ERROR
olarak ayarlanıp hata kodu ve mesajı PlaybackException
doğrultusunda ayarlanarak platform oturumunun PlaybackStateCompat
öğesine çoğaltılır.
Önemli hataları özelleştirme
Kullanıcıya yerelleştirilmiş ve anlamlı bilgiler sağlamak için, oturum oluşturulurken ForwardingPlayer
kullanılarak önemli oynatma hatalarının hata kodu, hata mesajı ve hata ek bilgileri özelleştirilebilir:
Kotlin
val forwardingPlayer = ErrorForwardingPlayer(player) val session = MediaSession.Builder(context, forwardingPlayer).build()
Java
Player forwardingPlayer = new ErrorForwardingPlayer(player); MediaSession session = new MediaSession.Builder(context, forwardingPlayer).build();
Yönlendirme oynatıcı, gerçek oynatıcıya bir Player.Listener
kaydeder ve hata bildiren geri çağırmalara müdahale eder. Ardından, yönlendiren oynatıcıya kayıtlı dinleyicilere özelleştirilmiş bir PlaybackException
atanır. Bunun çalışması için yönlendiren oynatıcı, özelleştirilmiş hata kodu, mesaj veya ekstralar göndermek üzere dinleyicilere erişebilmek için Player.addListener
ve Player.removeListener
'yi geçersiz kılar:
Kotlin
class ErrorForwardingPlayer(private val context: Context, player: Player) : ForwardingPlayer(player) { private val listeners: MutableList<Player.Listener> = mutableListOf() private var customizedPlaybackException: PlaybackException? = null init { player.addListener(ErrorCustomizationListener()) } override fun addListener(listener: Player.Listener) { listeners.add(listener) } override fun removeListener(listener: Player.Listener) { listeners.remove(listener) } override fun getPlayerError(): PlaybackException? { return customizedPlaybackException } private inner class ErrorCustomizationListener : Player.Listener { override fun onPlayerErrorChanged(error: PlaybackException?) { customizedPlaybackException = error?.let { customizePlaybackException(it) } listeners.forEach { it.onPlayerErrorChanged(customizedPlaybackException) } } override fun onPlayerError(error: PlaybackException) { listeners.forEach { it.onPlayerError(customizedPlaybackException!!) } } private fun customizePlaybackException( error: PlaybackException, ): PlaybackException { val buttonLabel: String val errorMessage: String when (error.errorCode) { PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW -> { buttonLabel = context.getString(R.string.err_button_label_restart_stream) errorMessage = context.getString(R.string.err_msg_behind_live_window) } // Apps can customize further error messages by adding more branches. else -> { buttonLabel = context.getString(R.string.err_button_label_ok) errorMessage = context.getString(R.string.err_message_default) } } val extras = Bundle() extras.putString("button_label", buttonLabel) return PlaybackException(errorMessage, error.cause, error.errorCode, extras) } override fun onEvents(player: Player, events: Player.Events) { listeners.forEach { it.onEvents(player, events) } } // Delegate all other callbacks to all listeners without changing arguments like onEvents. } }
Java
private static class ErrorForwardingPlayer extends ForwardingPlayer { private final Context context; private List<Player.Listener> listeners; @Nullable private PlaybackException customizedPlaybackException; public ErrorForwardingPlayer(Context context, Player player) { super(player); this.context = context; listeners = new ArrayList<>(); player.addListener(new ErrorCustomizationListener()); } @Override public void addListener(Player.Listener listener) { listeners.add(listener); } @Override public void removeListener(Player.Listener listener) { listeners.remove(listener); } @Nullable @Override public PlaybackException getPlayerError() { return customizedPlaybackException; } private class ErrorCustomizationListener implements Listener { @Override public void onPlayerErrorChanged(@Nullable PlaybackException error) { customizedPlaybackException = error != null ? customizePlaybackException(error, context) : null; for (int i = 0; i < listeners.size(); i++) { listeners.get(i).onPlayerErrorChanged(customizedPlaybackException); } } @Override public void onPlayerError(PlaybackException error) { for (int i = 0; i < listeners.size(); i++) { listeners.get(i).onPlayerError(checkNotNull(customizedPlaybackException)); } } private PlaybackException customizePlaybackException( PlaybackException error, Context context) { String buttonLabel; String errorMessage; switch (error.errorCode) { case PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW: buttonLabel = context.getString(R.string.err_button_label_restart_stream); errorMessage = context.getString(R.string.err_msg_behind_live_window); break; // Apps can customize further error messages by adding more case statements. default: buttonLabel = context.getString(R.string.err_button_label_ok); errorMessage = context.getString(R.string.err_message_default); break; } Bundle extras = new Bundle(); extras.putString("button_label", buttonLabel); return new PlaybackException(errorMessage, error.getCause(), error.errorCode, extras); } @Override public void onEvents(Player player, Events events) { for (int i = 0; i < listeners.size(); i++) { listeners.get(i).onEvents(player, events); } } // Delegate all other callbacks to all listeners without changing arguments like onEvents. } }
Önemli olmayan hatalar
Teknik bir istisnadan kaynaklanmayan kritik olmayan hatalar, bir uygulama tarafından tüm kontrol cihazlarına veya belirli bir kontrol cihazına gönderilebilir:
Kotlin
val sessionError = SessionError( SessionError.ERROR_SESSION_AUTHENTICATION_EXPIRED, context.getString(R.string.error_message_authentication_expired), ) // Sending a nonfatal error to all controllers. mediaSession.sendError(sessionError) // Interoperability: Sending a nonfatal error to the media notification controller to set the // error code and error message in the playback state of the platform media session. mediaSession.mediaNotificationControllerInfo?.let { mediaSession.sendError(it, sessionError) }
Java
SessionError sessionError = new SessionError( SessionError.ERROR_SESSION_AUTHENTICATION_EXPIRED, context.getString(R.string.error_message_authentication_expired)); // Sending a nonfatal error to all controllers. mediaSession.sendError(sessionError); // Interoperability: Sending a nonfatal error to the media notification controller to set the // error code and error message in the playback state of the platform media session. ControllerInfo mediaNotificationControllerInfo = mediaSession.getMediaNotificationControllerInfo(); if (mediaNotificationControllerInfo != null) { mediaSession.sendError(mediaNotificationControllerInfo, sessionError); }
Medya bildirim denetleyicisine gönderilen önemli olmayan bir hata, platform oturumunun PlaybackStateCompat
bölümüne çoğaltılır. Bu nedenle, yalnızca hata kodu ve hata mesajı uygun şekilde PlaybackStateCompat
olarak ayarlanır. PlaybackStateCompat.state
ise STATE_ERROR
olarak değiştirilmez.
Önemli olmayan hataları al
MediaController
, MediaController.Listener.onError
'ü uygulayarak önemli olmayan bir hata alır:
Kotlin
val future = MediaController.Builder(context, sessionToken) .setListener(object : MediaController.Listener { override fun onError(controller: MediaController, sessionError: SessionError) { // Handle nonfatal error. } }) .buildAsync()
Java
MediaController.Builder future = new MediaController.Builder(context, sessionToken) .setListener( new MediaController.Listener() { @Override public void onError(MediaController controller, SessionError sessionError) { // Handle nonfatal error. } });