O Jetpack Media3 define uma interface Player
que descreve a funcionalidade básica
para reprodução de arquivos de vídeo e áudio. ExoPlayer
é a implementação padrão
dessa interface na Media3. Recomendamos o uso do ExoPlayer, porque ele oferece um
conjunto abrangente de recursos que aborda a maioria dos casos de uso de reprodução e é
personalizável para processar outros casos de uso. O ExoPlayer também
abstrai a fragmentação de dispositivos e do SO para que seu código funcione de maneira consistente
em todo o ecossistema do Android. O ExoPlayer inclui:
- Compatibilidade com playlists
- Compatibilidade com vários formatos de streaming progressivo e adaptativo
- Suporte para inserção de anúncios do lado do cliente e do servidor
- Compatibilidade com reprodução protegida por DRM
Esta página apresenta algumas das principais etapas para criar um app de reprodução e, para mais detalhes, consulte nossos guias completos no Media3 ExoPlayer (links em inglês).
Como começar
Para começar, adicione uma dependência aos módulos do ExoPlayer, da interface e do Common do Jetpack Media3:
implementation "androidx.media3:media3-exoplayer:1.3.1" implementation "androidx.media3:media3-ui:1.3.1" implementation "androidx.media3:media3-common:1.3.1"
Dependendo do seu caso de uso, talvez você também precise de outros módulos da Media3,
como exoplayer-dash
para reproduzir streams no formato DASH.
Substitua 1.3.1
pela versão de sua preferência da
biblioteca. Consulte as notas da versão para conferir a versão mais recente.
Criar um player de mídia
Com a Media3, é possível usar a implementação incluída na interface Player
, ExoPlayer
, ou criar sua própria implementação personalizada.
Como criar um ExoPlayer
A maneira mais simples de criar uma instância ExoPlayer
é a seguinte:
Kotlin
val player = ExoPlayer.Builder(context).build()
Java
ExoPlayer player = new ExoPlayer.Builder(context).build();
Você pode criar seu player de mídia no método de ciclo de vida onCreate()
da
Activity
, Fragment
ou Service
em que ele se encontra.
O Builder
inclui
várias opções de personalização que podem ser do seu interesse, como:
setAudioAttributes()
para configurar o processamento de seleção de áudio.setHandleAudioBecomingNoisy()
para configurar o comportamento de reprodução quando um dispositivo de saída de áudio é desconectadosetTrackSelector()
para configurar a seleção de faixas.
A Media3 fornece um componente de interface PlayerView
que pode ser incluído no arquivo de layout
do seu app. Esse componente encapsula um PlayerControlView
para controles
de reprodução, um SubtitleView
para mostrar legendas e um Surface
para renderizar
vídeos.
Como preparar o player
Adicione itens de mídia a uma playlist para
reprodução com métodos como
setMediaItem()
e addMediaItem()
.
Em seguida, chame prepare()
para
começar a carregar mídia e adquirir os recursos necessários.
Não execute essas etapas antes de o app ser colocado em primeiro plano. Se o
jogador estiver em uma Activity
ou Fragment
, isso significa prepará-lo no
método de ciclo de vida onStart()
na API de nível 24 e mais recentes ou no método de ciclo de vida onResume()
no nível da API 23 e anteriores. Para um player que está em um Service
,
você pode prepará-lo em onCreate()
.
Controlar o player
Depois que o player estiver preparado, será possível controlar a reprodução chamando métodos no player, como:
play()
epause()
para iniciar e pausar a reprodução.seekTo()
para procurar uma posição no item de mídia atual.seekToNextMediaItem()
eseekToPreviousMediaItem()
para navegar pela playlist.
Os componentes da interface, como PlayerView
ou PlayerControlView
, serão atualizados
de forma adequada quando vinculados a um player.
Solte o player
A reprodução pode exigir recursos com fornecimento limitado, como decodificadores
de vídeo. Por isso, é importante chamar release()
no player para liberar recursos quando ele não for mais necessário.
Se o player estiver em uma Activity
ou Fragment
, solte-o no
método de ciclo de vida onStop()
na API de nível 24 e mais recentes ou no método onPause()
no nível de API 23 e anteriores. Para um player que está em um Service
, ele pode ser
liberado em onDestroy()
.
Gerenciar a reprodução com uma sessão de mídia
No Android, as sessões de mídia oferecem uma maneira padronizada de interagir com um player de mídia nos limites do processo. Conectar uma sessão de mídia ao player permite que você anuncie sua reprodução de mídia externamente e receba comandos de fontes externas, por exemplo, para integrar controles de mídia do sistema em dispositivos móveis e de tela grande.
Para usar sessões de mídia, adicione uma dependência ao módulo Media3 Session:
implementation "androidx.media3:media3-session:1.3.1"
Criar uma sessão de mídia
Você pode criar um MediaSession
após inicializar um player da seguinte maneira:
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();
A Media3 sincroniza automaticamente o estado da Player
com o estado do
MediaSession
. Isso funciona com qualquer implementação de Player
, incluindo
ExoPlayer
, CastPlayer
ou uma
implementação personalizada.
Conceder controle a outros clientes
Apps clientes podem implementar um controlador de mídia
para controlar a reprodução da sessão de mídia. Para receber essas solicitações, defina um
objeto de callback ao
criar seu MediaSession
.
Quando um controle está prestes a se conectar à sua sessão de mídia, o
método onConnect()
é chamado. É possível usar a ControllerInfo
fornecida para decidir se vai aceitar
ou rejeitar
a solicitação. Confira um exemplo no app de demonstração Media3 Session (link em inglês).
Depois de conectado, um controlador pode enviar comandos de reprodução à sessão. Em seguida,
a sessão delega esses comandos ao jogador. Os comandos de reprodução e
playlist definidos na interface Player
são processados automaticamente pela
sessão.
Outros métodos de callback permitem processar, por exemplo, solicitações de
comandos de reprodução personalizados
e modificações na playlist. Esses callbacks incluem de maneira semelhante um objeto ControllerInfo
para que você
possa determinar o controle de acesso a cada solicitação.
Reproduzindo mídia em segundo plano
Para continuar tocando mídia quando o app não estiver em primeiro plano, por exemplo,
para tocar músicas, audiolivros ou podcasts, mesmo quando o usuário não estiver com o app
aberto, Player
e MediaSession
precisam ser encapsulados em um
serviço em primeiro plano. A Media3 oferece a
interface MediaSessionService
para essa finalidade.
Implementar um MediaSessionService
Crie uma classe que estenda MediaSessionService
e instancie seu
MediaSession
no método de ciclo de vida onCreate()
.
Kotlin
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() } }
Java
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(); } }
No manifesto, a classe Service
com um filtro de intent MediaSessionService
e solicita a permissão FOREGROUND_SERVICE
para executar um serviço em primeiro
plano:
<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" />
Por fim, na classe que você criou, modifique o método onGetSession()
para controlar
o acesso do cliente à sua sessão de mídia. Retorne um MediaSession
para aceitar a
solicitação de conexão ou null
para rejeitar a solicitação.
Kotlin
// This example always accepts the connection request override fun onGetSession( controllerInfo: MediaSession.ControllerInfo ): MediaSession? = mediaSession
Java
@Override public MediaSession onGetSession(MediaSession.ControllerInfo controllerInfo) { // This example always accepts the connection request return mediaSession; }
Como se conectar à interface
Agora que sua sessão de mídia está em um Service
separado do Activity
ou da
Fragment
em que a interface do seu player reside, você pode usar um MediaController
para vinculá-los. No método onStart()
do Activity
ou Fragment
com a
interface, crie um SessionToken
para o MediaSession
e use o SessionToken
para criar um MediaController
. A criação de um MediaController
acontece
de forma assíncrona.
Kotlin
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() ) }
Java
@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()) }
O MediaController
implementa a interface Player
, então você pode usar os mesmos
métodos, como play()
e pause()
, para controlar a reprodução. Assim como em outros
componentes, lembre-se de liberar a MediaController
quando ela não for mais
necessária, como o método de ciclo de vida onStop()
de um Activity
, chamando
MediaController.releaseFuture()
.
Como publicar uma notificação
Os serviços em primeiro plano são necessários para publicar uma notificação enquanto estão ativos. Uma
MediaSessionService
vai criar automaticamente uma
notificação MediaStyle
para
você na forma de uma MediaNotification
.
Para fornecer uma notificação personalizada, crie uma
MediaNotification.Provider
com DefaultMediaNotificationProvider.Builder
ou criando uma implementação personalizada da interface do provedor. Adicione o
provedor ao MediaSession
com
setMediaNotificationProvider
.
Como anunciar sua biblioteca de conteúdo
Um MediaLibraryService
se baseia em um MediaSessionService
, permitindo que apps
clientes naveguem pelo conteúdo de mídia fornecido pelo app. Apps clientes implementam um
MediaBrowser
para interagir
com o MediaLibraryService
.
A implementação de um MediaLibraryService
é semelhante à implementação de um
MediaSessionService
. A diferença é que, no onGetSession()
, você precisa retornar um
MediaLibrarySession
em vez de uma MediaSession
. Em comparação com um
MediaSession.Callback
, o MediaLibrarySession.Callback
inclui outros
métodos que permitem que um cliente do navegador navegue pelo conteúdo oferecido pelo
serviço de biblioteca.
De forma semelhante ao MediaSessionService
, declare o MediaLibraryService
no seu
manifesto e solicite a permissão FOREGROUND_SERVICE
para executar um serviço em
primeiro plano:
<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" />
O exemplo acima inclui um filtro de intent para MediaLibraryService
e, para compatibilidade com versões anteriores, a MediaBrowserService
legada. O
filtro de intent adicional permite que os apps clientes que usam a API MediaBrowserCompat
reconheçam seu Service
.
Um MediaLibrarySession
permite disponibilizar sua biblioteca de conteúdo em uma estrutura de
árvore, com um único MediaItem
raiz. Cada MediaItem
na árvore pode ter
qualquer número de nós MediaItem
filhos. É possível disponibilizar uma raiz ou árvore diferente, com base na solicitação do app cliente. Por exemplo, a árvore que você
retorna a um cliente que procura uma lista de itens de mídia recomendados pode conter
apenas a MediaItem
raiz e um único nível de nós MediaItem
filhos,
enquanto a árvore que você retorna para outro app cliente pode representar uma
biblioteca de conteúdo mais completa.
Como criar um MediaLibrarySession
Um MediaLibrarySession
estende a API MediaSession
para adicionar APIs de navegação de conteúdo. Em comparação com o
callback MediaSession
,
o callback MediaLibrarySession
adiciona métodos como:
onGetLibraryRoot()
para quando um cliente solicitar a raizMediaItem
de uma árvore de conteúdo.onGetChildren()
para quando um cliente solicitar os filhos de umMediaItem
na árvore de conteúdo.onGetSearchResult()
para quando um cliente solicita resultados de pesquisa da árvore de conteúdo para uma determinada consulta.
Os métodos de callback relevantes vão incluir um objeto LibraryParams
com outros indicadores sobre o tipo de árvore de conteúdo em que um app cliente
tem interesse.