Visão geral do MediaPlayer

O framework multimídia do Android inclui suporte à reprodução de vários tipos de mídia comuns. Assim, você pode integrar facilmente áudio, vídeo e imagens aos seus apps. É possível reproduzir áudio ou vídeo de arquivos de mídia armazenados nos recursos do aplicativo (recursos brutos), de arquivos independentes no sistema de arquivos ou de um fluxo de dados que chega por uma conexão de rede, tudo isso usando APIs MediaPlayer.

Este documento mostra como usar o MediaPlayer para criar um aplicativo de reprodução de mídia que interage com o usuário e o sistema para conseguir um bom desempenho e uma experiência agradável. Como alternativa, você pode usar a ExoPlayer, uma biblioteca de código aberto personalizável com suporte a recursos de alto desempenho não disponíveis em MediaPlayer

Observação:só é possível tocar os dados de áudio para o dispositivo de saída padrão. que atualmente é o alto-falante do dispositivo móvel ou um fone de ouvido Bluetooth. Não é possível reproduzir arquivos de som no áudio da conversa durante uma chamada.

Noções básicas

As seguintes classes são usadas para reproduzir som e vídeo no framework do Android:

MediaPlayer
Esta classe é a principal API para reprodução de som e vídeo.
AudioManager
Esta classe gerencia fontes e saída de áudio em um dispositivo.

Declarações do manifesto

Antes de iniciar o desenvolvimento no seu aplicativo usando o MediaPlayer, verifique se o manifesto tem as declarações adequadas para permitir o uso de recursos relacionados.

  • Permissão de Internet: se você estiver usando o MediaPlayer para fazer streaming de conteúdo baseado em rede, seu aplicativo precisará solicitar acesso à rede.
    <uses-permission android:name="android.permission.INTERNET" />
    
  • Permissão de wake lock: se o aplicativo do player precisar impedir que a tela esmaeça ou o processador entre em suspensão ou usar os métodos MediaPlayer.setScreenOnWhilePlaying() ou MediaPlayer.setWakeMode(), será necessário solicitar essa permissão.
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    

Usar a MediaPlayer

Um dos componentes mais importantes do framework de mídia é a classe MediaPlayer. Um objeto dessa classe pode buscar, decodificar e reproduzir áudio e vídeo com uma configuração mínima. Ela é compatível com várias fontes de mídia diferentes, como:

  • Recursos locais
  • URIs internos, como um que você possa conseguir a partir de um resolvedor de conteúdo
  • URLs externos (streaming)

Para ver uma lista de formatos de mídia com suporte no Android, consulte a página Formatos de mídia compatíveis.

Confira um exemplo de como reproduzir o áudio disponível como um recurso bruto local (salvo no diretório res/raw/ do aplicativo):

Kotlin

var mediaPlayer = MediaPlayer.create(context, R.raw.sound_file_1)
mediaPlayer.start() // no need to call prepare(); create() does that for you

Java

MediaPlayer mediaPlayer = MediaPlayer.create(context, R.raw.sound_file_1);
mediaPlayer.start(); // no need to call prepare(); create() does that for you

Nesse caso, um recurso "bruto" é um arquivo que o sistema não tenta analisar de nenhuma maneira específica. No entanto, o conteúdo desse recurso não pode ser áudio bruto. Ele precisa ser um arquivo de mídia codificado e formatado corretamente em um dos formatos compatíveis.

Veja como você pode reproduzir a partir de um URI disponível localmente no sistema (recebido por um resolvedor de conteúdo, por exemplo):

Kotlin

val myUri: Uri = .... // initialize Uri here
val mediaPlayer = MediaPlayer().apply {
    setAudioAttributes(
        AudioAttributes.Builder()
            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
            .setUsage(AudioAttributes.USAGE_MEDIA)
            .build()
    )
    setDataSource(applicationContext, myUri)
    prepare()
    start()
}

Java

Uri myUri = ....; // initialize Uri here
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioAttributes(
    new AudioAttributes.Builder()
        .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
        .setUsage(AudioAttributes.USAGE_MEDIA)
        .build()
);
mediaPlayer.setDataSource(getApplicationContext(), myUri);
mediaPlayer.prepare();
mediaPlayer.start();

A reprodução a partir de um URL remoto por streaming HTTP é assim:

Kotlin

val url = "http://........" // your URL here
val mediaPlayer = MediaPlayer().apply {
    setAudioAttributes(
        AudioAttributes.Builder()
            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
            .setUsage(AudioAttributes.USAGE_MEDIA)
            .build()
    )
    setDataSource(url)
    prepare() // might take long! (for buffering, etc)
    start()
}

Java

String url = "http://........"; // your URL here
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioAttributes(
    new AudioAttributes.Builder()
        .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
        .setUsage(AudioAttributes.USAGE_MEDIA)
        .build()
);
mediaPlayer.setDataSource(url);
mediaPlayer.prepare(); // might take long! (for buffering, etc)
mediaPlayer.start();

Observação:se você estiver transmitindo um URL para fazer streaming de um arquivo de mídia on-line, o arquivo precisa ter a capacidade de download progressivo.

Cuidado:é necessário capturar ou transmitir IllegalArgumentException e IOException ao usar setDataSource(), porque o arquivo que você está referenciando pode não existir.

Preparação assíncrona

O uso de MediaPlayer pode ser simples em princípio. No entanto, é importante ter em mente que mais algumas coisas são necessárias para integrá-lo corretamente a um app Android típico. Por exemplo, a chamada para prepare() pode levar muito tempo para ser executada, porque envolve a busca e a decodificação de dados de mídia. Portanto, como acontece com qualquer método de execução muito demorado, nunca o chame na linha de execução de IU do app. Isso faz com que a interface trave até que o método seja retornado, o que é uma experiência muito ruim para o usuário e pode causar um erro "O app não está respondendo" (ANR, na sigla em inglês). Mesmo que você espere que o recurso seja carregado rapidamente, lembre-se de que qualquer ação que leve mais de um décimo de segundo para responder na interface causa uma pausa perceptível e dá ao usuário a impressão de que o aplicativo está lento.

Para evitar a suspensão da linha de execução de IU, gere outra linha de execução para preparar a MediaPlayer e notifique a linha principal quando terminar. No entanto, embora você possa criar a lógica de linha de execução por conta própria, esse padrão é tão comum ao usar MediaPlayer que o framework fornece uma maneira conveniente de realizar essa tarefa usando o método prepareAsync(). Esse método começa a preparar a mídia em segundo plano e é retornado imediatamente. Quando a preparação da mídia é concluída, o método onPrepared() da MediaPlayer.OnPreparedListener, configurado por setOnPreparedListener(), é chamado.

Gerenciar estados

Outro aspecto de uma MediaPlayer que você precisa ter em mente é que ela é baseada em estado. Ou seja, a MediaPlayer tem um estado interno que você precisa sempre conhecer ao escrever o código, porque algumas operações só são válidas quando o player está em estados específicos. Se você executar uma operação no estado errado, o sistema poderá gerar uma exceção ou causar outros comportamentos indesejáveis.

A documentação na classe MediaPlayer mostra um diagrama de estado completo, que esclarece quais métodos movem MediaPlayer de um estado para outro. Por exemplo, quando você cria um novo MediaPlayer, ele está no estado Inativo. Nesse ponto, inicialize-o chamando setDataSource() e trazendo-o para o estado Initialized (inicializado). Depois disso, é necessário prepará-lo usando o método prepare() ou prepareAsync(). Quando o MediaPlayer é concluído, ele entra no estado Prepared (preparado), o que significa que você pode chamar start() para que ele reproduza a mídia. Nesse ponto, como ilustra o diagrama, é possível alternar entre os estados Started, Pause e PlaybackConcluído chamando métodos como start(), pause() e seekTo(), entre outros. No entanto, ao chamar stop(), observe que não é possível chamar start() novamente até preparar o MediaPlayer de novo.

Sempre tenha em mente o diagrama de estado ao escrever um código que interage com um objeto MediaPlayer, porque chamar os métodos do estado errado é uma causa comum de bugs.

Liberar a MediaPlayer

Um MediaPlayer pode consumir recursos valiosos do sistema. Portanto, sempre tome precauções extras para não ficar atravando uma instância MediaPlayer por mais tempo que o necessário. Quando terminar, chame sempre release() para garantir que todos os recursos do sistema alocados para ele sejam liberados corretamente. Por exemplo, se você estiver usando um MediaPlayer e sua atividade receber uma chamada para onStop(), será necessário liberar a MediaPlayer, porque faz pouco sentido mantê-la enquanto a atividade não estiver interagindo com o usuário, a menos que você esteja reproduzindo mídia em segundo plano, o que será discutido na próxima seção. Obviamente, quando a atividade for retomada ou reiniciada, será necessário criar um novo MediaPlayer e prepará-lo novamente antes de retomar a reprodução.

Veja como liberar e anular sua MediaPlayer:

Kotlin

mediaPlayer?.release()
mediaPlayer = null

Java

mediaPlayer.release();
mediaPlayer = null;

Por exemplo, considere os problemas que podem acontecer se você se esquecer de liberar a MediaPlayer quando a atividade for interrompida, mas criar uma nova quando a atividade for reiniciada. Como você deve saber, quando o usuário muda a orientação da tela (ou a configuração do dispositivo de outra forma), o sistema reinicia a atividade (por padrão). Assim, é possível consumir rapidamente todos os recursos do sistema à medida que o usuário gira o dispositivo entre retrato e paisagem, porque a cada mudança de orientação, você cria uma MediaPlayer que nunca é liberada. Para saber mais sobre reinicializações durante a execução, consulte Gerenciar alterações de configuração.

Você pode estar se perguntando o que acontecerá se quiser continuar reproduzindo "mídia em segundo plano" mesmo quando o usuário sair da atividade, da mesma forma que o aplicativo de música integrado se comporta. Nesse caso, você precisa de um MediaPlayer controlado por um serviço, conforme discutido na próxima seção

Usar o MediaPlayer em um serviço

Se você quiser que sua mídia seja reproduzida em segundo plano mesmo quando o aplicativo não estiver na tela, ou seja, se quiser que ela continue a ser reproduzida enquanto o usuário interage com outros aplicativos, inicie um serviço e controle a instância MediaPlayer nele. Você precisa incorporar o MediaPlayer a um serviço de MediaBrowserServiceCompat e fazer com que ele interaja com um MediaBrowserCompat em outra atividade.

Tenha cuidado com essa configuração de cliente/servidor. Há expectativas sobre como um player em execução em um serviço em segundo plano interage com o restante do sistema. Se o aplicativo não atender a essas expectativas, o usuário poderá ter uma experiência ruim. Leia Como criar um app de áudio para ver todos os detalhes.

Esta seção descreve instruções especiais para gerenciar uma MediaPlayer quando ela é implementada dentro de um serviço.

Executar de forma assíncrona

Em primeiro lugar, como em uma Activity, todo o trabalho em uma Service é feito em uma única linha de execução por padrão. Na verdade, se você estiver executando uma atividade e um serviço do mesmo aplicativo, eles usarão a mesma linha de execução (a "linha de execução principal") por padrão. Portanto, os serviços precisam processar intents recebidas rapidamente e nunca realizar cálculos longos ao responder a elas. Se algum trabalho pesado ou chamadas de bloqueio for esperado, execute essas tarefas de forma assíncrona: em outra linha de execução implementada por você ou usando os vários recursos do framework para processamento assíncrono.

Por exemplo, ao usar um MediaPlayer da linha de execução principal, chame prepareAsync() em vez de prepare() e implemente um MediaPlayer.OnPreparedListener para receber uma notificação quando a preparação for concluída e você puder começar a jogar. Por exemplo:

Kotlin

private const val ACTION_PLAY: String = "com.example.action.PLAY"

class MyService: Service(), MediaPlayer.OnPreparedListener {

    private var mMediaPlayer: MediaPlayer? = null

    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        ...
        val action: String = intent.action
        when(action) {
            ACTION_PLAY -> {
                mMediaPlayer = ... // initialize it here
                mMediaPlayer?.apply {
                    setOnPreparedListener(this@MyService)
                    prepareAsync() // prepare async to not block main thread
                }

            }
        }
        ...
    }

    /** Called when MediaPlayer is ready */
    override fun onPrepared(mediaPlayer: MediaPlayer) {
        mediaPlayer.start()
    }
}

Java

public class MyService extends Service implements MediaPlayer.OnPreparedListener {
    private static final String ACTION_PLAY = "com.example.action.PLAY";
    MediaPlayer mediaPlayer = null;

    public int onStartCommand(Intent intent, int flags, int startId) {
        ...
        if (intent.getAction().equals(ACTION_PLAY)) {
            mediaPlayer = ... // initialize it here
            mediaPlayer.setOnPreparedListener(this);
            mediaPlayer.prepareAsync(); // prepare async to not block main thread
        }
    }

    /** Called when MediaPlayer is ready */
    public void onPrepared(MediaPlayer player) {
        player.start();
    }
}

Processar erros assíncronos

Em operações síncronas, os erros normalmente seriam sinalizados com uma exceção ou um código de erro, mas sempre que você usar recursos assíncronos, verifique se o aplicativo está notificado sobre erros adequadamente. No caso de um MediaPlayer, é possível fazer isso implementando um MediaPlayer.OnErrorListener e configurando-o na sua instância de MediaPlayer:

Kotlin

class MyService : Service(), MediaPlayer.OnErrorListener {

    private var mediaPlayer: MediaPlayer? = null

    fun initMediaPlayer() {
        // ...initialize the MediaPlayer here...
        mediaPlayer?.setOnErrorListener(this)
    }

    override fun onError(mp: MediaPlayer, what: Int, extra: Int): Boolean {
        // ... react appropriately ...
        // The MediaPlayer has moved to the Error state, must be reset!
    }
}

Java

public class MyService extends Service implements MediaPlayer.OnErrorListener {
    MediaPlayer mediaPlayer;

    public void initMediaPlayer() {
        // ...initialize the MediaPlayer here...
        mediaPlayer.setOnErrorListener(this);
    }

    @Override
    public boolean onError(MediaPlayer mp, int what, int extra) {
        // ... react appropriately ...
        // The MediaPlayer has moved to the Error state, must be reset!
    }
}

É importante lembrar que, quando ocorre um erro, o MediaPlayer muda para o estado Erro. Consulte a documentação da classe MediaPlayer para ver o diagrama de estado completo. Você precisa redefini-lo antes de usá-lo novamente.

Usar wake locks

Ao projetar aplicativos que reproduzem mídia em segundo plano, o dispositivo pode entrar no modo de suspensão enquanto o serviço está em execução. Como o sistema Android tenta economizar bateria enquanto o dispositivo está em suspensão, ele tenta desligar todos os recursos do smartphone que não são necessários, incluindo a CPU e o hardware Wi-Fi. No entanto, se o serviço estiver tocando ou fazendo streaming de música, é recomendado evitar que o sistema interfira na reprodução.

Para garantir que o serviço continue sendo executado nessas condições, você precisa usar "wake locks". Um wake lock é uma maneira de sinalizar ao sistema que o app está usando algum recurso que precisa permanecer disponível, mesmo que o smartphone esteja inativo.

Aviso:sempre use wake locks com moderação e mantenha-os apenas pelo tempo realmente necessário, porque eles reduzem significativamente a duração da bateria do dispositivo.

Para garantir que a CPU continue em execução enquanto o MediaPlayer é reproduzido, chame o método setWakeMode() ao inicializar o MediaPlayer. Depois disso, o MediaPlayer mantém o bloqueio especificado durante a reprodução e o libera quando pausado ou interrompido:

Kotlin

mediaPlayer = MediaPlayer().apply {
    // ... other initialization here ...
    setWakeMode(applicationContext, PowerManager.PARTIAL_WAKE_LOCK)
}

Java

mediaPlayer = new MediaPlayer();
// ... other initialization here ...
mediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);

No entanto, o wake lock adquirido nesse exemplo garante apenas que a CPU permaneça ativa. Se você estiver fazendo streaming de mídia pela rede e usando o Wi-Fi, provavelmente também vai precisar manter um WifiLock, que precisa ser adquirido e liberado manualmente. Portanto, ao começar a preparar o MediaPlayer com o URL remoto, crie e adquira o bloqueio de Wi-Fi. Por exemplo:

Kotlin

val wifiManager = getSystemService(Context.WIFI_SERVICE) as WifiManager
val wifiLock: WifiManager.WifiLock =
    wifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, "mylock")

wifiLock.acquire()

Java

WifiLock wifiLock = ((WifiManager) getSystemService(Context.WIFI_SERVICE))
    .createWifiLock(WifiManager.WIFI_MODE_FULL, "mylock");

wifiLock.acquire();

Ao pausar ou interromper a mídia ou quando não precisar mais da rede, libere o bloqueio:

Kotlin

wifiLock.release()

Java

wifiLock.release();

Realizar uma limpeza

Como mencionado anteriormente, um objeto MediaPlayer pode consumir uma quantidade significativa de recursos do sistema. Portanto, mantenha-o apenas pelo tempo necessário e chame release() quando terminar de usá-lo. É importante chamar esse método de limpeza explicitamente, em vez de depender da coleta de lixo do sistema, porque pode levar algum tempo até que o coletor de lixo recupere o MediaPlayer, já que ele é sensível apenas às necessidades de memória, e não à escassez de outros recursos relacionados à mídia. Portanto, no caso de usar um serviço, sempre substitua o método onDestroy() para garantir que você esteja liberando o MediaPlayer:

Kotlin

class MyService : Service() {

    private var mediaPlayer: MediaPlayer? = null
    // ...

    override fun onDestroy() {
        super.onDestroy()
        mediaPlayer?.release()
    }
}

Java

public class MyService extends Service {
   MediaPlayer mediaPlayer;
   // ...

   @Override
   public void onDestroy() {
       super.onDestroy();
       if (mediaPlayer != null) mediaPlayer.release();
   }
}

Procure sempre outras oportunidades para liberar a MediaPlayer, além de fazer a liberação durante o desligamento. Por exemplo, se você acha que não poderá tocar mídia por um longo período (depois de perder a seleção de áudio, por exemplo), libere a MediaPlayer existente e a crie novamente mais tarde. Por outro lado, se você pretende interromper a reprodução por um período muito curto, provavelmente mantenha a MediaPlayer para evitar a sobrecarga de criar e prepará-la novamente.

Gerenciamento de direitos digitais (DRM, na sigla em inglês)

No Android 8.0 (nível 26 da API) e versões mais recentes, a MediaPlayer inclui APIs que oferecem suporte para a reprodução de material protegido por DRM. Elas são semelhantes à API de baixo nível fornecida por MediaDrm, mas operam em um nível superior e não expõem o extrator, o drm e os objetos criptográficos subjacentes.

Embora a API MediaPlayer DRM não forneça a funcionalidade completa de MediaDrm, ela oferece suporte aos 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/de streaming protegidos pelo Widevine

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

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

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 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 a anexe ao jogador usando setOnDrmConfigHelper().
  2. Chame o método prepare().
  3. Chame o método 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 que você execute 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, o prepareDrm() também acessará o servidor de provisionamento para provisionar o dispositivo. Isso pode levar um tempo variável, dependendo da conectividade da rede.
  3. Para receber uma matriz de bytes de solicitação de chave opaca a ser enviada 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. É possível usar esse identificador de conjunto de chaves com restoreKeys() para restaurar as chaves a uma nova sessão.
    • Se a resposta for para uma solicitação de streaming ou liberação, o resultado será nulo.

Executar prepareDrm() de forma assíncrona

Por padrão, prepareDrm() é executado de maneira 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 pelo prepareDrm() e pode levar algum tempo para ser concluído devido à operação de rede envolvida. Para evitar o bloqueio em prepareDrm(), defina e configure um MediaPlayer.OnDrmPreparedListener.

Quando você define um OnDrmPreparedListener, o 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 listener será chamado. 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 o listener esteja registrado com uma linha de execução de gerenciador. O listener pode ser chamado 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 do DRM e o MediaPlayer.OnDrmPreparedListener para iniciar o player. Elas funcionam em conjunto com prepareAsync(), conforme mostrado abaixo:

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

No Android 8.0 (nível 26 da API) e versões mais recentes, o MediaPlayer também pode descriptografar um esquema de criptografia comum (CENC, na sigla em inglês) e mídia criptografada no nível de amostra de HLS (METHOD=início teste - AES) para os tipos básicos de fluxo H.264 e AAC. A mídia criptografada de segmento completo (METHOD=AES-128) era compatível anteriormente.

Recuperar mídia de um ContentResolver

Outro recurso que pode ser útil em um app de player de mídia é a capacidade de extrair músicas que o usuário tem no dispositivo. Você pode fazer isso consultando ContentResolver para mídia externa:

Kotlin

val resolver: ContentResolver = contentResolver
val uri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
val cursor: Cursor? = resolver.query(uri, null, null, null, null)
when {
    cursor == null -> {
        // query failed, handle error.
    }
    !cursor.moveToFirst() -> {
        // no media on the device
    }
    else -> {
        val titleColumn: Int = cursor.getColumnIndex(android.provider.MediaStore.Audio.Media.TITLE)
        val idColumn: Int = cursor.getColumnIndex(android.provider.MediaStore.Audio.Media._ID)
        do {
            val thisId = cursor.getLong(idColumn)
            val thisTitle = cursor.getString(titleColumn)
            // ...process entry...
        } while (cursor.moveToNext())
    }
}
cursor?.close()

Java

ContentResolver contentResolver = getContentResolver();
Uri uri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
Cursor cursor = contentResolver.query(uri, null, null, null, null);
if (cursor == null) {
    // query failed, handle error.
} else if (!cursor.moveToFirst()) {
    // no media on the device
} else {
    int titleColumn = cursor.getColumnIndex(android.provider.MediaStore.Audio.Media.TITLE);
    int idColumn = cursor.getColumnIndex(android.provider.MediaStore.Audio.Media._ID);
    do {
       long thisId = cursor.getLong(idColumn);
       String thisTitle = cursor.getString(titleColumn);
       // ...process entry...
    } while (cursor.moveToNext());
}

Para usar isso com MediaPlayer, faça o seguinte:

Kotlin

val id: Long = /* retrieve it from somewhere */
val contentUri: Uri =
    ContentUris.withAppendedId(android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id )

mediaPlayer = MediaPlayer().apply {
    setAudioAttributes(
        AudioAttributes.Builder()
            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
            .setUsage(AudioAttributes.USAGE_MEDIA)
            .build()
    )
    setDataSource(applicationContext, contentUri)
}

// ...prepare and start...

Java

long id = /* retrieve it from somewhere */;
Uri contentUri = ContentUris.withAppendedId(
        android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id);

mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioAttributes(
    new AudioAttributes.Builder()
        .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
        .setUsage(AudioAttributes.USAGE_MEDIA)
        .build()
);
mediaPlayer.setDataSource(getApplicationContext(), contentUri);

// ...prepare and start...

Saiba mais

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