Última atualização: 09/09/2020
Quais são os benefícios de adicionar um MediaSession à reprodução do vídeo?
As sessões de mídia vinculam a plataforma Android e os apps de mídia de forma integral. De um lado, este vínculo informa ao Android que a mídia está sendo reproduzida, assim as ações de mídia podem ser encaminhadas para a sessão correta. Do outro, ele também informa a plataforma sobre o que está sendo reproduzido e como isso pode ser controlado.
A exposição de um MediaSession pelo aplicativo traz vários benefícios aos usuários. Veja alguns ótimos exemplos.
Google Assistente
Os usuários podem interagir facilmente com a mídia no seu app por comandos de voz, como "Pausar", "Retomar" e "Próximo". Os metadados da sua mídia também podem ser usados para conseguir respostas sobre o que está sendo reproduzido no momento.
Android TV
Em experiências de tela grande, o app Android TV pode usar controles remotos convencionais para usuários com TVs compatíveis com HDMI-CEC. Comandos emitidos pelos botões de reprodução/pausar, parar, próximo e anterior são retransmitidos para seu aplicativo.
Controles de mídia na tela
A partir do Android 4.0 (API de nível 14), o sistema pode acessar o estado de reprodução de uma sessão de mídia e os metadados. Essa funcionalidade permite que a tela de bloqueio mostre controles de mídia e obras de arte. Esse comportamento varia de acordo com a versão do Android.
Mídia em segundo plano
A mídia pode ser controlada em qualquer um desses cenários mesmo se o aplicativo que está reproduzindo a mídia estiver sendo executado em segundo plano.
Computação no ambiente
A exposição da sua mídia com dados sobre o que está sendo reproduzido e como ela pode ser controlada pode funcionar entre dispositivos para que os usuários possam interagir com ela de várias maneiras.
O que você criará
Neste codelab, você ampliará a amostra existente do Exoplayer para adicionar suporte à sessão de mídia. Seu app irá:
- refletir corretamente o estado ativo da sessão de mídia;
- redirecionar os controles de mídia para o ExoPlayer;
- transmitir os metadados dos itens na fila para a sessão de mídia.
O que você aprenderá
- Por qual razão as sessões de mídia oferecem aos usuários uma experiência melhor
- Como criar uma sessão de mídia e gerenciar o estado dela
- Como conectar uma sessão de mídia ao ExoPlayer
- Como incluir metadados de itens da fila de reprodução na sessão de mídia
- Como adicionar mais ações (personalizadas)
Este codelab se concentra no SDK do MediaSession. Conceitos não-relevantes e blocos de código (incluindo detalhes sobre a implementação do ExoPlayer) são fornecidos para você copiar e colar, mas não serão abordados.
Pré-requisitos
- Uma versão recente do Android Studio (3.5 ou mais recente)
- Conhecimento básico sobre o desenvolvimento de apps Android
Qual é nosso ponto de partida?
Nosso ponto de partida é a principal demonstração do ExoPlayer. Esta demonstração contém vídeos com controles de reprodução na tela, mas não usa sessões de mídia prontas para uso. É um ótimo lugar para entrar e adicioná-las!
Receba a amostra do ExoPlayer
Para começar, vamos usar a amostra do ExoPlayer. Clone o repositório do GitHub neste link:
Abrir a demonstração
No Android Studio, abra o projeto de demonstração principal, localizado em demos/main
.
O Android Studio solicitará que você defina o caminho do SDK. Se você encontrar problemas, siga as recomendações para atualizar as ferramentas do SDK e o ambiente de desenvolvimento integrado.
Se for solicitado que você use a versão mais recente do Gradle, atualize-a.
Reserve um tempo para entender melhor como o app foi projetado. Observe que há duas atividades: SampleChooserActivity e PlayerActivity. Passaremos o restante do codelab em PlayerActivity, onde a mídia realmente é reproduzida, então abra esta classe e vá para a próxima seção.
Criar a sessão de mídia
Abra o PlayerActivity.java
Essa classe cria o ExoPlayer e gerencia as funções dele, como renderizar vídeos na tela. Nesta atividade, conectaremos o ExoPlayer a uma sessão de mídia.
Declare os dois campos a seguir na parte superior da classe. Usaremos esses campos ao longo desta seção.
private MediaSessionCompat mediaSession;
private MediaSessionConnector mediaSessionConnector;
Será necessário adicionar a dependência do projeto "extension-mediasession" ao build.gradle
do módulo para "Module: demo":
implementation project(path: ':extension-mediasession')
O Android Studio pode ajudar a adicionar essa dependência automaticamente se você passar o mouse sobre o erro de resolução do MediaSessionConnector:
Por fim, resolva as importações de classe adicionando o seguinte:
import android.support.v4.media.session.MediaSessionCompat;
import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector;
Ao criar a atividade, criaremos uma sessão de mídia e um conector de sessão de mídia que atua como intermediário entre a sessão e o ExoPlayer.
O lugar ideal para inserir isso é onde o ExoPlayer também é criado. Em nosso app de demonstração, é possível anexar nosso código ao final de initializePlayer()
. Adicione essa lógica depois que o player for instanciado.
private void initializePlayer() {
if (player == null) {
...
player = ...
...
mediaSession = new MediaSessionCompat(this, "sample");
mediaSessionConnector = new MediaSessionConnector(mediaSession);
mediaSessionConnector.setPlayer(player);
}
...
}
Liberar a sessão de mídia
Libere a sessão de mídia quando ela não for mais necessária. Quando lançamos o ExoPlayer em releasePlayer()
, também podemos incluir o seguinte código para fazer isso:
private void releasePlayer() {
if (mediaSession != null) {
mediaSession.release();
}
...
}
Gerenciar o estado da sessão de mídia
Agora que instanciamos a sessão de mídia, precisamos garantir que o estado dela seja refletido corretamente à medida que o usuário interage com a atividade.
Quando o usuário inicia a atividade, a sessão de mídia precisa se tornar ativa:
@Override
public void onStart() {
...
if (mediaSession != null) {
mediaSession.setActive(true);
}
}
Como nosso aplicativo não reproduz mídia em segundo plano, é essencial garantir que a sessão de mídia fique inativa conforme o usuário sai da atividade:
@Override
public void onStop() {
super.onStop();
if (mediaSession != null) {
mediaSession.setActive(false);
}
...
}
Vamos executar a demonstração
- Anexe um dispositivo Android ou inicie um emulador.
- Confira se a opção "demo" está selecionada para execução na barra de ferramentas do Android Studio.
- Clique em na barra de ferramentas do Android Studio.
- Quando o app for iniciado no dispositivo, selecione um stream de vídeo para assistir.
- Quando a reprodução começar, use os seguintes comandos
adb
para controlar a sessão de mídia:adb shell media dispatch pauseadb shell media dispatch playadb shell media dispatch play-pauseadb shell media dispatch fast-forwardadb shell media dispatch rewind
.
- Descubra também como o Android vê sua sessão de mídia executando:
adb shell dumpsys media_session
. - Se você estiver usando um dispositivo físico com um microfone, tente invocar o Google Assistente e emitir comandos de voz, como: "Pausar", "Retomar", "Avançar 1 minuto".
Exemplo do ExoPlayer em execução no Android TV.
Agora, podemos ampliar os recursos compatíveis da nossa sessão de mídia, onde criamos o MediaSessionConnector no initializePlayer()
.
Como adicionar um TimelineQueueNavigator
O ExoPlayer representa a estrutura de mídia como uma linha do tempo. Para ver detalhes sobre esse processo, leia sobre o objeto Timeline (link em inglês) do ExoPlayer. Ao tocar na estrutura, podemos ser avisados quando o conteúdo mudar e expor os metadados do que está sendo reproduzido quando solicitado.
Para isso, vamos definir um TimelineQueueNavigator. Localize a instanciação do MediaSessionConnector em initializePlayer()
e adicione uma implementação de TimelineQueueNavigator depois da mediaSession
ser inicializada.
mediaSessionConnector.setQueueNavigator(new TimelineQueueNavigator(mediaSession) {
@Override
public MediaDescriptionCompat getMediaDescription(Player player, int windowIndex) {
return new MediaDescriptionCompat.Builder()
.setTitle("MediaDescription title")
.setDescription("MediaDescription description for " + windowIndex)
.setSubtitle("MediaDescription subtitle")
.build();
}
});
Para resolver as importações de classe, adicione:
import android.support.v4.media.MediaDescriptionCompat;
import com.google.android.exoplayer2.ext.mediasession.TimelineQueueNavigator;
Observe que o parâmetro windowIndex
corresponde ao item desse índice na fila de reprodução.
Agora que você adicionou alguns metadados, teste se o Assistente entende o que está tocando. Ao reproduzir um vídeo no Android TV, invoque o Assistente e pergunte "O que está tocando?".
É possível que seu player não seja compatível com algumas ações, ou que você queira incluir compatibilidade com outras opções. Agora vamos aprofundar a sessão de mídia em que criamos o MediaSessionConnector no initializePlayer()
.
Como declarar ações compatíveis
Tente usar o mediaSessionConnector.setEnabledPlaybackActions()
para personalizar as ações que você quer que a sessão de mídia aceite.
Observe que o conjunto completo é:
mediaSessionConnector.setEnabledPlaybackActions(
PlaybackStateCompat.ACTION_PLAY_PAUSE
| PlaybackStateCompat.ACTION_PLAY
| PlaybackStateCompat.ACTION_PAUSE
| PlaybackStateCompat.ACTION_SEEK_TO
| PlaybackStateCompat.ACTION_FAST_FORWARD
| PlaybackStateCompat.ACTION_REWIND
| PlaybackStateCompat.ACTION_STOP
| PlaybackStateCompat.ACTION_SET_REPEAT_MODE
| PlaybackStateCompat.ACTION_SET_SHUFFLE_MODE
);
Vejamos novamente como esses dados são expostos à plataforma:
- Como antes, inicie um vídeo.
- Para descobrir como o Android vê os metadados da sessão de mídia, execute:
adb shell dumpsys media_session
- Localize a linha que contém metadados e observe que o título e a descrição estão incluídos e associados a
com.google.android.exoplayer2.demo/sample
.
Adicionar outras ações
É possível ampliar nossa sessão de mídia com algumas ações adicionais. Nesta seção, adicionaremos compatibilidade apenas para legendas.
Compatibilidade com legendas
Adicionar compatibilidade a legendas em sessões de mídia permite que os usuários as ativem ou desativem por voz. Onde você inicializou o conector de sessão de mídia, adicione o seguinte:
mediaSessionConnector.setCaptionCallback(new MediaSessionConnector.CaptionCallback() {
@Override
public void onSetCaptioningEnabled(Player player, boolean enabled) {
Log.d("MediaSession", "onSetCaptioningEnabled: enabled=" + enabled);
}
@Override
public boolean hasCaptions(Player player) {
return true;
}
@Override
public boolean onCommand(Player player, ControlDispatcher controlDispatcher, String command, Bundle extras, ResultReceiver cb) {
return false;
}
}
);
Por fim, resolva todas as importações ausentes.
É possível testar isso invocando o Google Assistente no Android TV e dizendo "Ativar legendas". Verifique o Logcat para ver mensagens e saber como isso é chamado no seu código.
Parabéns! Você adicionou sessões de mídia à amostra com sucesso.
Você acrescentou uma enorme quantidade de funcionalidades ao:
- adicionar uma sessão de mídia;
- conectar sessões de mídia a uma instância do ExoPlayer;
- adicionar metadados e outras ações.
Agora você sabe as principais etapas necessárias para melhorar um aplicativo de mídia e oferecer aos usuários uma experiência mais versátil!
Uma última observação
Este codelab foi construído com base em um exemplo do código-fonte do ExoPlayer. Não é necessário usar o ExoPlayer do código-fonte. Recomendamos que você extraia as dependências do ExoPlayer e do MediaSessionConnector para facilitar a atualização com as versões mais recentes.
Para isso, basta substituir as dependências do projeto, como:
implementation project(modulePrefix + 'library-core')
implementation project(path: ':extension-mediasession')
para extrair de repositórios Maven, como:
implementation 'com.google.android.exoplayer:exoplayer-core:2.+'
implementation 'com.google.android.exoplayer:extension-mediasession:2.+'
Documentos de referência
- Como usar uma sessão de mídia
- Visão geral da arquitetura de apps de mídia
- Estrutura da linha do tempo do ExoPlayer (link em inglês)
- Guia do desenvolvedor do ExoPlayer (link em inglês)
- Referência da API MediaSessionConnector do ExoPlayer (link em inglês)