Visão geral do MediaPlayer

O framework multimídia do Android inclui compatibilidade com diversos tipos de mídia comuns. Assim, você pode integrar facilmente áudio, vídeo e imagens aos seus aplicativos. É 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 meio de uma conexão de rede, tudo isso com APIs MediaPlayer.

Este documento mostra como criar um aplicativo de mídia que interage com o usuário e o sistema para ter um bom desempenho e uma experiência de usuário agradável.

Observação: só é possível abrir 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 abrir 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 apropriadas para permitir o uso de recursos relacionados.

  • Permissão de Internet: se você estiver usando o MediaPlayer para fazer streaming de conteúdo on-line, seu aplicativo precisará solicitar acesso à rede.
        <uses-permission android:name="android.permission.INTERNET" />
        
  • Permissão de wake lock: se seu aplicativo precisar impedir que a tela seja escurecida ou que o processador entre em suspensão, ou se ele usar os métodos MediaPlayer.setScreenOnWhilePlaying() ou MediaPlayer.setWakeMode(), será necessário solicitar esta 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 quantidade mínima de configuração. 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 compatíveis com o Android, consulte a página Formatos de mídia compatíveis.

Veja 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? = 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 deve ser áudio bruto. Ele deve ser um arquivo de mídia corretamente codificado e formatado em um dos formatos compatíveis.

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

Kotlin

    val myUri: Uri = .... // initialize Uri here
    val mediaPlayer: MediaPlayer? = MediaPlayer().apply {
        setAudioStreamType(AudioManager.STREAM_MUSIC)
        setDataSource(applicationContext, myUri)
        prepare()
        start()
    }
    

Java

    Uri myUri = ....; // initialize Uri here
    MediaPlayer mediaPlayer = new MediaPlayer();
    mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
    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? = MediaPlayer().apply {
        setAudioStreamType(AudioManager.STREAM_MUSIC)
        setDataSource(url)
        prepare() // might take long! (for buffering, etc)
        start()
    }
    

Java

    String url = "http://........"; // your URL here
    MediaPlayer mediaPlayer = new MediaPlayer();
    mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
    mediaPlayer.setDataSource(url);
    mediaPlayer.prepare(); // might take long! (for buffering, etc)
    mediaPlayer.start();
    

Observação: se você estiver passando um URL para fazer streaming de um arquivo de mídia on-line, o arquivo precisará fazer o download progressivo.

Cuidado: é necessário pegar ou passar 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 é teoricamente simples. No entanto, é importante lembrar que outros fatores são necessários para integrá-lo corretamente a um aplicativo para Android típico. Por exemplo, a execução da chamada para prepare() pode ser muito demorada, porque envolve a busca e a decodificação de dados de mídia. Portanto, assim como com qualquer método de execução lenta, nunca o chame na linha de execução de IU do aplicativo. Isso fará a IU ser interrompida até que o método retorne, o que é uma experiência muito desagradável para o usuário e pode gerar 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 de mais de um décimo de segundo na IU causa uma pausa perceptível e dá ao usuário a impressão de que o aplicativo está lento.

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

Gerenciar estados

Outro aspecto importante de uma MediaPlayer é que ela é baseada em estado. Ou seja, a MediaPlayer tem um estado interno que você precisa levar sempre em consideração ao escrever seu código, já que determinadas operações são válidas apenas 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 indesejados.

A documentação na classe MediaPlayer mostra um diagrama de estado completo, que esclarece quais métodos movem de um estado para outro. Por exemplo, quando você cria uma nova MediaPlayer, ela está no estado Idle (inativo). Nesse ponto, inicialize-a chamando setDataSource(), trazendo-a para o estado Initialized (inicializado). Depois disso, prepare-a com o método prepare() ou prepareAsync(). Quando a preparação da MediaPlayer é concluída, a classe entra no estado Prepared (preparado), o que significa que você pode chamar start() para abrir a mídia. Nesse ponto, como o diagrama ilustra, você pode alternar entre os estados Started (iniciado), Paused (pausado) e PlaybackCompleted (reprodução concluída) 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 a MediaPlayer mais uma vez.

Lembre-se sempre do diagrama de estado ao escrever um código que interage com um objeto MediaPlayer, já que chamar os métodos do estado errado é uma causa comum de bugs.

Liberar a MediaPlayer

Uma MediaPlayer pode consumir recursos valiosos do sistema. Portanto, sempre adote precauções extras para garantir que você não esteja retendo uma instância MediaPlayer por mais tempo que o necessário. Ao terminar, chame sempre release() para garantir que os recursos do sistema alocados para ele sejam liberados de forma correta. Por exemplo, se você estiver usando uma MediaPlayer e sua atividade receber uma chamada para onStop(), libere a MediaPlayer, porque não faz sentido mantê-la enquanto sua atividade não está interagindo com o usuário (a menos que você esteja reproduzindo mídia em segundo plano, o que é discutido na próxima seção). Evidentemente, quando sua atividade for retomada ou reiniciada, será necessário criar uma nova MediaPlayer e prepará-la novamente antes de retomar a reprodução.

Veja como liberar e anular sua MediaPlayer:

Kotlin

    mediaPlayer?.release()
    mediaPlayer = null
    

Java

    mediaPlayer.release();
    mediaPlayer = null;
    

Como exemplo, considere os problemas que poderiam acontecer se você se esquecesse de liberar a MediaPlayer quando a atividade fosse interrompida, mas criasse uma nova quando a atividade começasse novamente. Como você deve saber, quando o usuário muda a orientação da tela (ou a configuração do dispositivo de alguma outra maneira), o sistema responde reiniciando a atividade (por padrão). Isso significa que você pode consumir rapidamente todos os recursos do sistema enquanto o usuário alterna o dispositivo entre retrato e paisagem, uma vez que, a cada mudança de orientação, você cria uma nova 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 depois que o usuário sair da atividade, da mesma forma que o aplicativo integrado de música faz. Nesse caso, você precisa de uma MediaPlayer controlada por um serviço, como 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, que a reprodução continue enquanto o usuário interage com outros aplicativos, será necessário iniciar um serviço e controlar a instância MediaPlayer a partir dele. É necessário incorporar a MediaPlayer em um serviço MediaBrowserServiceCompat e fazê-la interagir 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 seu aplicativo não atender a essas expectativas, o usuário poderá ter uma experiência negativa. Leia Visão geral para um aplicativo 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 uma Activity, todo o trabalho em um Service é feito, por padrão, em uma única linha de execuçã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 principal). Portanto, os serviços precisam processar intents de entrada rapidamente e nunca realizar cálculos demorados durante as respostas. Se algum trabalho pesado ou chamadas de bloqueio forem esperados, será preciso realizar essas tarefas de forma assíncrona: de outra linha de execução implementada por você ou por meio das diversas facilidades do framework para processamento assíncrono.

Por exemplo, ao usar uma MediaPlayer na 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 reprodução. 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 são sinalizados com uma exceção ou um código de erro, mas sempre que você usar recursos assíncronos, verifique se seu aplicativo é corretamente notificado sobre erros. No caso de uma MediaPlayer, faça isso implementando um MediaPlayer.OnErrorListener e definindo-o na instância da sua 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 um erro ocorre, a MediaPlayer entra no estado Error (erro) e você precisa redefini-la para usá-la novamente. Consulte a documentação da classe para ver o diagrama de estado completo.

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 é executado. Como o sistema Android tenta economizar bateria enquanto o dispositivo está inativo, ele tenta desligar os recursos desnecessários para o smartphone, incluindo a CPU e o hardware Wi-Fi. No entanto, se o serviço estiver reproduzindo ou fazendo streaming de música, evite que o sistema interfira na reprodução.

Para que o serviço continue sendo executado nessas condições, é necessário usar "wake locks". Um wake lock é uma maneira de sinalizar para o sistema que seu aplicativo está usando algum recurso que deveria permanecer disponível, mesmo se o telefone estivesse ocioso.

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

Para que a CPU continue em execução enquanto sua MediaPlayer é reproduzida, chame o método setWakeMode() ao inicializar sua . Depois de fazer isso, a MediaPlayer mantém o wake lock especificado durante a reprodução e o libera quando é pausada ou interrompida:

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 on-line e estiver usando o Wi-Fi, também manterá um WifiLock, que precisará ser adquirido e liberado manualmente. Então, quando você começar a preparar a MediaPlayer com o URL remoto, crie e adquira o wake lock 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();
    

Quando você pausar ou interromper a mídia ou quando não precisar mais da rede, libere o wake lock:

Kotlin

    wifiLock.release()
    

Java

    wifiLock.release();
    

Realizar uma limpeza

Como mencionado anteriormente, um objeto MediaPlayer pode consumir uma quantidade significativa de recursos do sistema. Por isso, mantenha-o apenas durante o tempo necessário e chame release() quando terminar de usá-lo. É importante chamar esse método de limpeza explicitamente, em vez de contar com a coleta de lixo do sistema, uma vez que pode demorar até que o coletor de lixo recupere a MediaPlayer. Isso acontece porque o coletor é sensível apenas às necessidades de memória, não à falta de outros recursos relacionados à mídia. Sendo assim, caso você esteja usando um serviço, modifique sempre o método onDestroy() para liberar a 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, não somente durante o desligamento. Por exemplo, se você acha que não conseguirá reproduzir mídia por um longo período (por exemplo, depois de perder a seleção de áudio), libere a MediaPlayer existente e crie-a de novo mais tarde. Por outro lado, se você acha que só interromperá a reprodução por um período muito curto, mantenha a MediaPlayer para evitar a sobrecarga de repetir a criação e a preparação.

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

A partir do Android 8.0 (API nível 26), a MediaPlayer inclui APIs compatíveis com a reprodução de material protegido por DRM. Elas são semelhantes à API de nível inferior disponibilizada por MediaDrm, mas operam em um nível superior e não expõem o extrator subjacente, 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 remotos/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 simples.

Para gerenciar mídia controlada por DRM, é preciso incluir os novos métodos junto do fluxo normal de chamadas da 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 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 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 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.

Executar prepareDrm() 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. Você pode evitar o bloqueio em prepareDrm() definindo e configurando um MediaPlayer.OnDrmPreparedListener.

Quando você define 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 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 gerenciadora). 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 MediaPlayer.OnDrmInfoListener para preparação de DRM e MediaPlayer.OnDrmPreparedListener para iniciar o player. Eles 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

A partir do Android 8.0 (API nível 26), 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.

Recuperar mídia de um ContentResolver

Outro recurso que pode ser útil em um aplicativo de player de mídia é a capacidade de recuperar 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 {
        setAudioStreamType(AudioManager.STREAM_MUSIC)
        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.setAudioStreamType(AudioManager.STREAM_MUSIC);
    mediaPlayer.setDataSource(getApplicationContext(), contentUri);

    // ...prepare and start...
    

Amostra de código

As amostras BasicMediaDecoder e DeviceOwner (links em inglês) demonstram o uso das APIs abordadas nesta página.

Saiba mais

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