Trabalhar com MediaPlayer e Gerenciamento de direitos digitais (DRM)

A partir do Android 8.0 (nível 26 da API), a MediaPlayer inclui APIs compatíveis com a reprodução de material protegido por DRM. As APIs MediaPlayer DRM são semelhantes à API de baixo nível fornecida por MediaDrm, mas operam em um nível mais alto e não expõem o extrator, o DRM e os objetos criptografados.

Embora a API MediaPlayer DRM não ofereça a funcionalidade completa de MediaDrm, ela é compatível com os casos de uso mais comuns. A implementação atual pode processar os seguintes tipos de conteúdo:

  • Arquivos locais de mídia protegidos pelo Widevine
  • Arquivos de mídia remota ou de streaming protegidos pelo Widevine

O snippet de código abaixo demonstra como usar os novos métodos MediaPlayer DRM em uma implementação síncrona.

Para gerenciar mídia controlada por DRM, é preciso incluir os novos métodos junto do fluxo normal de chamadas da MediaPlayer, conforme mostrado neste exemplo:

Kotlin

mediaPlayer?.apply {
    setDataSource()
    setOnDrmConfigHelper() // optional, for custom configuration
    prepare()
    drmInfo?.also {
        prepareDrm()
        getKeyRequest()
        provideKeyResponse()
    }

    // MediaPlayer is now ready to use
    start()
    // ...play/pause/resume...
    stop()
    releaseDrm()
}

Java

setDataSource();
setOnDrmConfigHelper(); // optional, for custom configuration
prepare();
if (getDrmInfo() != null) {
  prepareDrm();
  getKeyRequest();
  provideKeyResponse();
}

// MediaPlayer is now ready to use
start();
// ...play/pause/resume...
stop();
releaseDrm();

Comece inicializando o objeto MediaPlayer e definindo a origem dele usando setDataSource(), como de costume. Em seguida, siga estas etapas para usar o DRM:

  1. Se você quiser que seu app faça uma configuração personalizada, defina uma interface OnDrmConfigHelper e anexe-a ao player usando setOnDrmConfigHelper().
  2. Chame prepare().
  3. Chame getDrmInfo(). Se a origem tiver conteúdo DRM, o método retornará um valor MediaPlayer.DrmInfo não nulo.

Se MediaPlayer.DrmInfo existir:

  1. analise o mapa dos UUIDs disponíveis e escolha um;
  2. Prepare a configuração de DRM para a origem atual chamando prepareDrm().
    • Se você criou e registrou um callback OnDrmConfigHelper, ele será chamado enquanto prepareDrm() estiver em execução. Isso permite fazer a configuração personalizada das propriedades de DRM antes de abrir a sessão de DRM. O callback é chamado de forma síncrona na linha de execução que chamou prepareDrm(). Para acessar as propriedades de DRM, chame getDrmPropertyString() e setDrmPropertyString(). Evite realizar operações demoradas.
    • Se o dispositivo ainda não tiver sido provisionado, prepareDrm() também acessará o servidor de provisionamento para fazer isso. Isso pode levar um tempo variável, dependendo da conectividade de rede.
  3. Para conseguir uma matriz de bytes de solicitação de chave opaca para enviar a um servidor de licença, chame getKeyRequest().
  4. Para informar o mecanismo de DRM sobre a resposta de chave recebida do servidor de licença, chame provideKeyResponse(). O resultado depende do tipo de solicitação de chave:
    • Se a resposta for para uma solicitação de chave off-line, o resultado será um identificador de conjunto de chaves. Você pode usar esse identificador de conjunto de chaves com restoreKeys() para restaurar as chaves em uma nova sessão.
    • Se a resposta for para uma solicitação de streaming ou liberação, o resultado será nulo.

Preparar o DRM de forma assíncrona

Por padrão, prepareDrm() é executado de forma síncrona, bloqueando até que a preparação seja concluída. No entanto, a primeira preparação de DRM em um novo dispositivo também pode exigir provisionamento, que é processado internamente por prepareDrm() e pode demorar para ser concluído devido à operação de rede envolvida. É possível evitar o bloqueio em prepareDrm() definindo e configurando um MediaPlayer.OnDrmPreparedListener.

Defina um OnDrmPreparedListener. prepareDrm() realiza o provisionamento (se necessário) e a preparação em segundo plano. Quando o provisionamento e a preparação são concluídos, o sistema chama o listener. Não faça suposições sobre a sequência de chamada ou a linha de execução em que o listener é executado (a menos que você registre o listener com uma linha de execução gerenciadora). O sistema pode chamar o listener antes ou depois do retorno de prepareDrm().

Configurar o DRM de forma assíncrona

Você pode inicializar o DRM de forma assíncrona criando e registrando o MediaPlayer.OnDrmInfoListener para preparação de DRM e o MediaPlayer.OnDrmPreparedListener para iniciar o player. Eles funcionam em conjunto com prepareAsync(), conforme mostrado neste exemplo:

Kotlin

setOnPreparedListener()
setOnDrmInfoListener()
setDataSource()
prepareAsync()
// ...

// If the data source content is protected you receive a call to the onDrmInfo() callback.
override fun onDrmInfo(mediaPlayer: MediaPlayer, drmInfo: MediaPlayer.DrmInfo) {
    mediaPlayer.apply {
        prepareDrm()
        getKeyRequest()
        provideKeyResponse()
    }
}

// When prepareAsync() finishes, you receive a call to the onPrepared() callback.
// If there is a DRM, onDrmInfo() sets it up before executing this callback,
// so you can start the player.
override fun onPrepared(mediaPlayer: MediaPlayer) {
    mediaPlayer.start()
}

Java

setOnPreparedListener();
setOnDrmInfoListener();
setDataSource();
prepareAsync();
// ...

// If the data source content is protected you receive a call to the onDrmInfo() callback.
onDrmInfo() {
  prepareDrm();
  getKeyRequest();
  provideKeyResponse();
}

// When prepareAsync() finishes, you receive a call to the onPrepared() callback.
// If there is a DRM, onDrmInfo() sets it up before executing this callback,
// so you can start the player.
onPrepared() {

start();
}

Processar mídia criptografada

A partir do Android 8.0 (nível 26 da API), MediaPlayer também pode descriptografar mídia criptografada em nível de amostra com o Common Encryption Scheme (CENC) e HLS (METHOD=SAMPLE-AES) para os tipos básicos de streaming H.264 e AAC. A mídia criptografada de segmento completo (METHOD=AES-128) era compatível anteriormente.

Saiba mais

O Jetpack Media3 é a solução recomendada para a reprodução de mídia no seu app. Saiba mais.

Estas páginas abrangem tópicos relacionados à gravação, ao armazenamento e à reprodução de áudio e vídeo: