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 usar o ExoPlayer, porque ele oferece um conjunto abrangente de recursos que cobrem a maioria dos casos de uso de reprodução e pode ser personalizado para lidar com outros casos de uso que você possa ter. O ExoPlayer também
abstrai a fragmentação de dispositivos e SOs para que seu código funcione de maneira consistente
em todo o ecossistema Android. O ExoPlayer inclui:
- Suporte para playlists
- Compatibilidade com vários formatos de streaming progressivo e adaptável
- Suporte para inserção de anúncios do lado do cliente e do lado do servidor
- Suporte para reprodução protegida por DRM
Esta página mostra algumas das principais etapas na criação de um app de reprodução. Para mais detalhes, consulte nossos guias completos sobre o ExoPlayer do Media3.
Primeiros passos
Para começar, adicione uma dependência aos módulos ExoPlayer, UI e Common do Jetpack Media3:
implementation "androidx.media3:media3-exoplayer:1.7.1" implementation "androidx.media3:media3-ui:1.7.1" implementation "androidx.media3:media3-common:1.7.1"
Dependendo do seu caso de uso, talvez você também precise de outros módulos do Media3,
como exoplayer-dash
para reproduzir streams no formato DASH.
Substitua 1.7.1
pela versão preferida da biblioteca. Consulte as notas da versão para conferir a versão mais recente.
Como criar um player de mídia
Com a Media3, é possível usar a implementação incluída da 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 está.
O Builder
inclui
uma variedade de opções de personalização que podem ser interessantes para você, como:
setAudioAttributes()
para configurar o gerenciamento do foco de áudiosetHandleAudioBecomingNoisy()
para configurar o comportamento de reprodução quando um dispositivo de saída de áudio é desconectadosetTrackSelector()
para configurar a seleção de faixa
O Media3 oferece um componente de interface PlayerView
que pode ser incluído no arquivo de layout do app. Esse componente encapsula um PlayerControlView
para controles de reprodução, um SubtitleView
para mostrar legendas e um Surface
para renderizar vídeo.
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 que o app esteja em primeiro plano. Se o
player estiver em um Activity
ou Fragment
, isso significa preparar o player no
método de ciclo de vida onStart()
no nível 24 da API e em versões mais recentes ou no método de ciclo de vida onResume()
no nível 23 da API e em versões anteriores. Para um jogador que está em um Service
,
é possível prepará-lo em onCreate()
.
Controlar o player
Depois que o player for preparado, você poderá controlar a reprodução chamando métodos no player, como:
play()
epause()
para iniciar e pausar a reproduçãoseekTo()
para procurar uma posição no item de mídia atualseekToNextMediaItem()
eseekToPreviousMediaItem()
para navegar pela playlist
Os componentes da interface, como PlayerView
ou PlayerControlView
, serão atualizados
de acordo com a vinculação a um player.
Soltar o player
A reprodução pode exigir recursos limitados, 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 um Activity
ou Fragment
, libere-o no
método de ciclo de vida onStop()
na API de nível 24 e mais recente ou no método onPause()
na API de nível 23 e anterior. Para um jogador que está em uma Service
, você pode
lançar 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 em limites de processos. Ao conectar uma sessão de mídia ao player, você pode anunciar a reprodução de mídia externamente e receber comandos de reprodução de fontes externas, por exemplo, para integrar com 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 de sessão da Media3:
implementation "androidx.media3:media3-session:1.7.1"
Criar uma sessão de mídia
Você pode criar um MediaSession
depois de 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 do 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
Os apps clientes podem implementar um controle de mídia
para controlar a reprodução da sua sessão de mídia. Para receber essas solicitações, defina um objeto de
callback ao
criar seu MediaSession
.
Quando um controlador está prestes a se conectar à sua sessão de mídia, o método
onConnect()
é chamado. Use o ControllerInfo
fornecido para decidir se você vai aceitar ou rejeitar o pedido. Confira um exemplo disso no app de demonstração da sessão do Media3 (link em inglês).
Depois de conectado, um controlador pode enviar comandos de reprodução para a sessão. A
sessão delega esses comandos ao player. 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 modificar a playlist. Esses callbacks também incluem um objeto ControllerInfo
para que você possa determinar o controle de acesso em cada solicitação.
Reproduzir mídia em segundo plano
Para continuar reproduzindo mídia quando o app não está em primeiro plano, por exemplo, para tocar músicas, audiolivros ou podcasts mesmo quando o usuário não tem o app
aberto, o Player
e o MediaSession
precisam ser encapsulados em um
serviço de primeiro plano. O Media3 fornece
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, sua classe Service
com um filtro de
intent MediaSessionService
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.MediaSessionService"/>
</intent-filter>
</service>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
Por fim, na classe criada, substitua o método onGetSession()
para controlar
o acesso do cliente à sua sessão de mídia. Retorne um MediaSession
para aceitar o
pedido de conexão ou null
para recusar.
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; }
Conectar à interface
Agora que sua sessão de mídia está em um Service
separado do Activity
ou
Fragment
em que a interface do player está, você pode usar um MediaController
para vincular
os dois. No método onStart()
da Activity
ou Fragment
com sua
interface, crie um SessionToken
para seu 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
. Assim, você pode usar os mesmos métodos, como play()
e pause()
, para controlar a reprodução. Assim como outros componentes, libere o MediaController
quando ele não for mais necessário, como o método de ciclo de vida onStop()
de um Activity
, chamando MediaController.releaseFuture()
.
Publicar uma notificação
Os serviços em primeiro plano precisam publicar uma notificação enquanto estão ativos. Um
MediaSessionService
cria automaticamente uma
MediaStyle
notificação para
você na forma de um MediaNotification
.
Para fornecer uma notificação personalizada, crie um
MediaNotification.Provider
com DefaultMediaNotificationProvider.Builder
ou criando uma implementação personalizada da interface do provedor. Adicione seu provedor ao MediaSession
com setMediaNotificationProvider
.
Anunciar sua biblioteca de conteúdo
Um MediaLibraryService
se baseia em um MediaSessionService
ao permitir que apps
clientes naveguem pelo conteúdo de mídia fornecido pelo seu app. Os apps clientes implementam um
MediaBrowser
para interagir
com seu MediaLibraryService
.
Implementar um MediaLibraryService
é semelhante a implementar um
MediaSessionService
, exceto que, em onGetSession()
, você precisa retornar um
MediaLibrarySession
em vez de um 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.
Semelhante ao MediaSessionService
, declare o MediaLibraryService
no
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, o MediaBrowserService
legado. O
filtro de intent adicional permite que 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 filhos MediaItem
. É possível veicular uma raiz ou uma á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 raiz MediaItem
e um único nível de nós filhos MediaItem
,
enquanto a árvore retornada a um app cliente diferente 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 solicita aMediaItem
raiz de uma árvore de conteúdoonGetChildren()
para quando um cliente solicita os filhos de umMediaItem
na árvore de conteúdoonGetSearchResult()
quando um cliente solicita resultados de pesquisa da árvore de conteúdo para uma determinada consulta
Os métodos de callback relevantes incluem um objeto LibraryParams
com outros indicadores sobre o tipo de árvore de conteúdo em que um app cliente
tem interesse.