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 no Media3. Recomendamos o uso do ExoPlayer, porque ele oferece um
conjunto abrangente de recursos que cobrem a maioria dos casos de uso de reprodução e é
personalizável 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
- Suporte a 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 para criar 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:
Kotlin
implementation("androidx.media3:media3-exoplayer:1.11.1")
implementation("androidx.media3:media3-ui:1.11.1")
implementation("androidx.media3:media3-common:1.11.1")
Groovy
implementation "androidx.media3:media3-exoplayer:1.11.1"
implementation "androidx.media3:media3-ui:1.11.1"
implementation "androidx.media3:media3-common:1.11.1"
Dependendo do 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.11.1 pela versão de sua preferência da
biblioteca. Consulte as notas da versão para conferir a versão mais recente.
Como criar um player de mídia
Com o Media3, você pode 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();
É possível criar o player de mídia no método de ciclo de vida onCreate() do
Activity, Fragment ou Service em que ele está.
O Builder inclui uma variedade de opções de personalização que podem ser do seu interesse, como:
setAudioAttributes()para configurar o processamento do foco de áudiosetHandleAudioBecomingNoisy()para configurar o comportamento de reprodução quando um dispositivo de saída de áudio é desconectado.setTrackSelector()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 mídia,
SubtitleView para exibir legendas e Surface para renderizar
vídeos.
Preparando 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 a 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 uma Activity ou Fragment, isso significa prepará-lo no
método de ciclo de vida onStart() no nível 24 da API e versões mais recentes ou no método de ciclo de vida onResume()
no nível 23 da API e versões anteriores. Para um player que está em um Service,
é possível prepará-lo em onCreate(). Consulte o codelab do ExoPlayer para ver um
exemplo de como implementar métodos de ciclo de vida.
Controlar o player
Depois que o player estiver preparado, você poderá controlar a reprodução chamando métodos nele, como:
play()epause()para iniciar e pausar a reproduçãoseekTo()para buscar 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 acordo quando vinculados a um player.
Liberar 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 uma Activity ou Fragment, libere-o no método de ciclo de vida onStop() no nível 24 da API e versões mais recentes ou no método onPause() no nível 23 da API e versões anteriores. Para um player que está em um Service, é possível liberá-lo
em onDestroy(). Consulte o codelab do ExoPlayer para ver um exemplo de como
implementar métodos de ciclo de vida.
Como 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 todos os limites do processo. Conectar uma sessão de mídia ao player permite anunciar a reprodução de mídia externamente e receber comandos de reprodução de fontes externas, por exemplo, para integração com os 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 do Media3:
Kotlin
implementation("androidx.media3:media3-session:1.11.1")
Groovy
implementation "androidx.media3:media3-session:1.11.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();
O 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 controlador 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 o
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 quer aceitar ou rejeitar a solicitação. Confira um exemplo disso no app de demonstração de sessão do Media3.
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 para cada solicitação.
Reproduzindo mídia em segundo plano
Para continuar reproduzindo 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, o Player e o 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 o
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, declare a 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 que você criou, substitua o método onGetSession() para
controlar o acesso do cliente à sessão de mídia. Retorne um MediaSession para aceitar
a solicitação de conexão ou null para rejeitá-la.
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 a sessão de mídia está em um Service separado da Activity ou
Fragment em que a interface do player está, use um MediaController para vincular
as duas. No método onStart() da Activity ou Fragment com
sua IU, crie um SessionToken para sua MediaSession e use o
SessionToken para criar um MediaController. A criação de um MediaController
ocorre 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, para que você possa usar os mesmos
métodos, como play() e pause(), para controlar a reprodução. Assim como em outros
componentes, lembre-se de liberar o MediaController quando ele não for mais
necessário no método de ciclo de vida onStop() de uma 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 notificação do MediaStyle
para você na forma de um MediaNotification. Para fornecer uma notificação personalizada, crie um MediaNotification.Provider com DefaultMediaNotificationProvider.Builder ou crie uma implementação personalizada da interface do provedor. Adicione o provedor ao
MediaSession com setMediaNotificationProvider.
Anunciar sua biblioteca de conteúdo
Um MediaLibraryService se baseia em um MediaSessionService, permitindo que os apps
cliente naveguem pelo conteúdo de mídia fornecido pelo seu app. Os apps cliente implementam um
MediaBrowser para interagir com seu MediaLibraryService.
A implementação de um MediaLibraryService é semelhante à de um
MediaSessionService, mas 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 de navegador navegue pelo conteúdo oferecido pelo
serviço de biblioteca.
Assim como no 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 o MediaLibraryService
e, para compatibilidade com versões anteriores, o MediaBrowserService legado. 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 filhos MediaItem. É possível exibir 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 o nó raiz
MediaItem e um único nível de nós filhos MediaItem, enquanto a árvore
que você retorna 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 a raizMediaItemde uma árvore de conteúdoonGetChildren()para quando um cliente solicita os filhos de umMediaItemna árvore de conteúdoonGetSearchResult()para quando um cliente solicita resultados da pesquisa na á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 está
interessado.