Trabalhar com MediaPlayer e Gerenciamento de direitos digitais (DRM)

A partir do Android 8.0 (nível 26 da API), MediaPlayer inclui APIs que oferecem suporte à 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 subjacentes.

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 remotos ou de streaming protegidos pelo Widevine

O snippet de código a seguir 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 por meio de 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 OnDrmConfigHelper interface 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 OnDrmConfigHelper callback, 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 correspondente. 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 conexão 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 de 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 prepareDrm() processa internamente e pode demorar para ser concluído devido à operação de rede envolvida. Você pode 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 forem concluídos, o sistema vai chamar o listener. Não faça nenhuma suposição 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), a MediaPlayer também pode descriptografar mídia criptografada em nível de amostra com 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 reprodução de mídia no seu app. Saiba mais.

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