Como usar uma sessão de mídia

As sessões de mídia oferecem uma maneira universal de interagir com um áudio ou vídeo de futebol. Ao informar ao Android que a mídia está em reprodução em um app, a reprodução podem ser delegados ao app. A integração com a sessão de mídia permite um app para anunciar a reprodução de mídia externamente e receber comandos de reprodução de fontes externas. Essas fontes podem ser botões físicos (como o botão em um fone de ouvido ou controle remoto da TV) ou comandos indiretos (como com a instrução "pausar" ao Google Assistente). A sessão de mídia delega essas ao aplicativo que os aplica ao player de mídia para o qual transparente onde os comandos foram originados.

Uma sessão de mídia convive com o player que a gerencia. Você deve criar e inicializar uma sessão de mídia no método onCreate() da atividade ou que é proprietário da sessão de mídia e do player associado a ele.

Inicializar a sessão de mídia

Uma sessão de mídia recém-criada não tem recursos. Inicialize a sessão executando estas etapas:

  • Defina sinalizações para que a sessão de mídia receba callbacks de controladores de mídia e botões de mídia.
  • Crie e inicialize uma instância de PlaybackStateCompat e a atribua à sessão. O estado de reprodução muda durante a sessão, por isso recomendamos o cache de PlaybackStateCompat.Builder para reutilização.
  • Crie uma instância de MediaSessionCompat.Callback e a atribua à sessão. Veja abaixo mais informações sobre callbacks.

Crie e inicialize uma sessão de mídia no método onCreate() da atividade ou serviço proprietário da sessão.

Para que os botões de mídia funcionem, quando o app é recém-inicializado (ou interrompido), o PlaybackState precisa conter uma ação de reprodução correspondente à intent que o botão de mídia envia. Isso é por que ACTION_PLAY é atribuído ao estado da sessão durante inicialização do sistema. Para mais informações, consulte Como responder a mídias Botões.

Manter o estado de reprodução e os metadados

Há duas classes que representam o estado de uma sessão de mídia.

A PlaybackStateCompat descreve o estado operacional atual do player. Isso inclui:

  • O estado de transporte, isto é, se o player está em reprodução/pausado/em buffer etc. Veja getState().
  • Um código de erro e uma mensagem de erro opcional, quando aplicável. Veja getErrorCode() e leia Estados e erros, abaixo.
  • A posição do player
  • As ações válidas do controlador que podem ser processadas no estado atual

O MediaMetadataCompat descreve o material que está sendo reproduzido:

  • O nome do artista, álbum e faixa
  • A duração da faixa
  • Arte do álbum para exibição na tela de bloqueio. A imagem é um bitmap com tamanho máximo de 320 x 320 dp. Se for maior, ela será reduzida.
  • Uma instância de ContentUris que aponta para uma versão maior da obra de arte

O estado do player e os metadados podem mudar durante a vida útil de uma sessão de mídia. Sempre que o estado ou os metadados mudarem, você precisará usar o builder correspondente para cada classe, PlaybackStateCompat.Builder() ou MediaMetadataCompat.Builder() e, em seguida, transmitir a nova instância para a sessão de mídia chamando setPlaybackState() ou setMetaData(). Para reduzir o consumo geral de memória em função dessas operações frequentes, uma boa sugestão é criar os builders uma vez e reutilizá-los ao longo da vida da sessão.

Estados e erros

Observe que PlaybackState é um objeto que contém valores separados para o estado de reprodução da sessão (getState()) e, quando necessário, um código de erro (getErrorCode()) associado. Os erros podem ser fatais ou não fatais:

Sempre que a reprodução for interrompida, você deverá gerar um erro fatal: defina o o estado de transporte para STATE_ERROR e especificar um erro associado a setErrorMessage(int, CharSequence). Enquanto a reprodução estiver bloqueada pelo erro, a PlaybackState vai continuar para informar STATE_ERROR e o erro.

Um erro não fatal ocorre quando o app não consegue processar uma solicitação, mas pode continuar a jogar: O transporte permanece em um estado "normal" estado (como STATE_PLAYING), mas o PlaybackState contém um código de erro. Por exemplo, se a última música estiver tocando e o usuário pedir para pular para a próxima, a reprodução pode continuar, mas é necessário criar uma nova PlaybackState com o código de erro ERROR_CODE_END_OF_QUEUE e depois, chame setPlaybackState(). Os controladores de mídia anexados à sessão vão receber o callback onPlaybackStateChanged() e explique ao usuário o que aconteceu. Um erro não fatal precisar ser informado apenas uma vez, no momento em que ocorre. Na próxima vez que a sessão atualizar o PlaybackState, não defina o mesmo erro não fatal novamente, a menos que ele tenha ocorrido em resposta a uma nova solicitação.

Telas de bloqueio de sessão de mídia

A partir do Android 4.0 (API de nível 14), o sistema pode acessar o sistema estado de reprodução e metadados. É assim que a tela de bloqueio exibe os controles de mídia e arte. O comportamento varia de acordo com o Versão do Android.

Arte do álbum

Do Android 4.0 (nível 14 da API) ao Android 10 (nível 29 da API), o plano de fundo da tela de bloqueio exibe a capa do álbum, mas somente se a sessão de mídia incluem um bitmap de plano de fundo.

Controles de transporte

Do Android 4.0 (API de nível 14) até o Android 4.4 (API de nível 19), quando uma sessão de mídia está ativa e os metadados da sessão incluem um bitmap em segundo plano, a tela de bloqueio exibe automaticamente os controles de transporte.

No Android 5.0 (API de nível 21) ou versões mais recentes, o sistema não oferece controles na tela de bloqueio. Em vez disso, você deve usar um MediaStyle notificação para exibir controles de transporte.

Adicionar ações personalizadas

Aplicativos de mídia podem definir ações personalizadas; por exemplo: gostei, gostei ou voltar 30 segundos. Uma ação personalizada precisa implementar um comportamento completamente novo. O que fazer não usar uma ação personalizada para substituir uma das ações padrão de controle de transporte; definido em PlaybackStateCompat.

Adicione ações personalizadas com addCustomAction(). O exemplo a seguir mostra como adicionar um controle para uma ação "Gostei":

Kotlin

stateBuilder.addCustomAction(
        PlaybackStateCompat.CustomAction.Builder(
                CUSTOM_ACTION_THUMBS_UP,
                resources.getString(R.string.thumbs_up),
                thumbsUpIcon
        ).run {
            setExtras(customActionExtras)
            build()
        }
)

Java

stateBuilder.addCustomAction(new PlaybackStateCompat.CustomAction.Builder(
    CUSTOM_ACTION_THUMBS_UP, resources.getString(R.string.thumbs_up), thumbsUpIcon)
    .setExtras(customActionExtras)
    .build());

Consulte Universal Music Player para ver um exemplo completo.

Você responde à ação com onCustomAction().

Kotlin

override fun onCustomAction(action: String, extras: Bundle?) {
    when(action) {
        CUSTOM_ACTION_THUMBS_UP -> {
            ...
        }
    }
}

Java

@Override
public void onCustomAction(@NonNull String action, Bundle extras) {
    if (CUSTOM_ACTION_THUMBS_UP.equals(action)) {
        ...
    }
}

Consulte também Universal Music Player (link em inglês).

Callbacks de sessão de mídia

Os principais métodos de callback de sessão de mídia são onPlay(), onPause() e onStop(). É aqui que você adiciona o código que controla o player.

Como você instancia e define o callback da sessão no tempo de execução (em onCreate()), o app pode definir callbacks alternativos que usam players diferentes e escolher a combinação apropriada de callback/player de acordo com o dispositivo e/ou nível do sistema. Você pode mudar o player sem mudar o restante do app. Por exemplo, você pode usar ExoPlayer ao executar no Android 4.1 (API de nível 16) ou versões posteriores e usar MediaPlayer em sistemas anteriores.

Além de controlar o player e gerenciar as transições de estado da sessão de mídia, os callbacks também ativam e desativam recursos do app e controlam a interação com outros apps e o hardware do dispositivo. Consulte Como controlar a saída de áudio.

A implementação dos métodos de callback da sessão de mídia depende da estrutura do app. Consulte as páginas separadas que descrevem como usar callbacks no apps de áudio e apps de vídeo, descrever como implementar callbacks para cada tipo de app.