Обзор медиаплеера

Мультимедийная платформа Android включает поддержку воспроизведения различных распространенных типов мультимедиа, поэтому вы можете легко интегрировать аудио, видео и изображения в свои приложения. Вы можете воспроизводить аудио или видео из мультимедийных файлов, хранящихся в ресурсах вашего приложения (необработанные ресурсы), из отдельных файлов в файловой системе или из потока данных, поступающего через сетевое соединение, и все это с использованием API MediaPlayer .

В этом документе показано, как использовать MediaPlayer для написания приложения воспроизведения мультимедиа, которое взаимодействует с пользователем и системой для достижения хорошей производительности и приятного взаимодействия с пользователем. В качестве альтернативы вы можете использовать ExoPlayer — настраиваемую библиотеку с открытым исходным кодом, поддерживающую высокопроизводительные функции, недоступные в MediaPlayer

Примечание. Вы можете воспроизводить аудиоданные только на стандартном устройстве вывода. В настоящее время это динамик мобильного устройства или Bluetooth-гарнитура. Вы не можете воспроизводить звуковые файлы в аудио разговора во время вызова.

Основы

Следующие классы используются для воспроизведения звука и видео в платформе Android:

MediaPlayer
Этот класс является основным API для воспроизведения звука и видео.
AudioManager
Этот класс управляет источниками звука и выводом звука на устройстве.

Манифестные декларации

Прежде чем начинать разработку приложения с помощью MediaPlayer, убедитесь, что в вашем манифесте есть соответствующие объявления, позволяющие использовать связанные функции.

  • Разрешение Интернета . Если вы используете MediaPlayer для потоковой передачи сетевого контента, ваше приложение должно запросить доступ к сети.
    <uses-permission android:name="android.permission.INTERNET" />
    
  • Разрешение на блокировку пробуждения . Если вашему проигрывателю необходимо предотвратить затемнение экрана или переход процессора в спящий режим или использовать методы MediaPlayer.setScreenOnWhilePlaying() или MediaPlayer.setWakeMode() , вам необходимо запросить это разрешение.
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    

Использование Медиаплеера

Одним из наиболее важных компонентов медиа-фреймворка является класс MediaPlayer . Объект этого класса может извлекать, декодировать и воспроизводить как аудио, так и видео с минимальной настройкой. Он поддерживает несколько различных источников мультимедиа, таких как:

  • Местные ресурсы
  • Внутренние URI, например те, которые вы можете получить от Content Resolver.
  • Внешние URL-адреса (потоковая передача)

Список медиаформатов, которые поддерживает Android, см. на странице «Поддерживаемые медиаформаты» .

Вот пример того, как воспроизводить аудио, доступное в виде локального необработанного ресурса (сохраненного в каталоге res/raw/ вашего приложения):

Котлин

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

Ява

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

В данном случае «сырой» ресурс — это файл, который система не пытается проанализировать каким-либо конкретным способом. Однако содержимое этого ресурса не должно быть необработанным аудио. Это должен быть правильно закодированный и отформатированный медиафайл в одном из поддерживаемых форматов.

А вот как вы можете играть, используя URI, доступный локально в системе (например, полученный с помощью Content Resolver):

Котлин

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()
}

Ява

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();

Воспроизведение с удаленного URL-адреса через потоковую передачу HTTP выглядит следующим образом:

Котлин

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()
}

Ява

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();

Примечание. Если вы передаете URL-адрес для потоковой передачи мультимедийного файла в Интернете, файл должен поддерживать последовательную загрузку.

Внимание: при использовании setDataSource() необходимо либо перехватить, либо передать IllegalArgumentException и IOException , поскольку файл, на который вы ссылаетесь, может не существовать.

Асинхронная подготовка

Использование MediaPlayer в принципе может быть простым. Однако важно помнить, что для правильной интеграции его с типичным приложением Android необходимо еще несколько вещей. Например, выполнение вызова метода prepare() может занять много времени, поскольку может включать в себя выборку и декодирование мультимедийных данных. Поэтому, как и в случае с любым методом, выполнение которого может занять много времени, вам никогда не следует вызывать его из потока пользовательского интерфейса вашего приложения . Это приводит к зависанию пользовательского интерфейса до тех пор, пока метод не вернется, что очень неприятно для пользователя и может привести к ошибке ANR (приложение не отвечает). Даже если вы ожидаете, что ваш ресурс будет загружаться быстро, помните, что все, что занимает более одной десятой секунды для ответа в пользовательском интерфейсе, вызывает заметную паузу и создает у пользователя впечатление, что ваше приложение работает медленно.

Чтобы избежать зависания потока пользовательского интерфейса, создайте другой поток для подготовки MediaPlayer и уведомите основной поток о завершении. Однако, хотя логику потоковой обработки можно написать самостоятельно, этот шаблон настолько распространен при использовании MediaPlayer , что платформа предоставляет удобный способ выполнения этой задачи с помощью метода prepareAsync() . Этот метод начинает подготовку носителя в фоновом режиме и немедленно завершает работу. Когда подготовка мультимедиа завершена, вызывается метод onPrepared() объекта MediaPlayer.OnPreparedListener , настроенный с помощью setOnPreparedListener() .

Управление государством

Еще один аспект MediaPlayer , о котором следует помнить, — это то, что он основан на состоянии. То есть у MediaPlayer есть внутреннее состояние, о котором вы всегда должны помнить при написании кода, поскольку определенные операции действительны только тогда, когда проигрыватель находится в определенных состояниях. Если вы выполняете операцию в неправильном состоянии, система может выдать исключение или вызвать другое нежелательное поведение.

В документации класса MediaPlayer показана полная диаграмма состояний, поясняющая, какие методы переводят MediaPlayer из одного состояния в другое. Например, когда вы создаете новый MediaPlayer , он находится в состоянии ожидания . На этом этапе вам следует инициализировать его, вызвав setDataSource() , переведя его в состояние «Инициализировано» . После этого вам необходимо подготовить его с помощью метода prepare() или prepareAsync() . Когда MediaPlayer завершает подготовку, он переходит в состояние «Подготовлено» , что означает, что вы можете вызвать start() чтобы воспроизвести медиафайл. В этот момент, как показано на диаграмме, вы можете перемещаться между состояниями Started , Paused и PlaybackCompleted, вызывая, среди прочего, такие методы, как start() , pause() и seekTo() . Однако, когда вы вызываете stop() , обратите внимание, что вы не можете снова вызвать start() , пока не подготовите MediaPlayer снова.

Всегда помните о диаграмме состояний при написании кода, взаимодействующего с объектом MediaPlayer , поскольку вызов его методов из неправильного состояния является распространенной причиной ошибок.

Выпуск медиаплеера

MediaPlayer может потреблять ценные системные ресурсы. Поэтому вам всегда следует принимать дополнительные меры предосторожности, чтобы не удерживать экземпляр MediaPlayer дольше, чем необходимо. Когда вы закончите с этим, вам всегда следует вызывать release() , чтобы убедиться, что все выделенные для нее системные ресурсы освобождены правильно. Например, если вы используете MediaPlayer и ваша активность получает вызов onStop() , вы должны освободить MediaPlayer , поскольку нет смысла удерживать его, пока ваша активность не взаимодействует с пользователем (если только вы не играете в СМИ на заднем плане, что обсуждается в следующем разделе). Конечно, когда ваша деятельность возобновляется или перезапускается, вам необходимо создать новый MediaPlayer и подготовить его снова, прежде чем возобновить воспроизведение.

Вот как вам следует освободить, а затем аннулировать ваш MediaPlayer :

Котлин

mediaPlayer?.release()
mediaPlayer = null

Ява

mediaPlayer.release();
mediaPlayer = null;

В качестве примера рассмотрим проблемы, которые могут возникнуть, если вы забыли освободить MediaPlayer при остановке активности, но создадите новый, когда активность начнется снова. Как вы, возможно, знаете, когда пользователь меняет ориентацию экрана (или изменяет конфигурацию устройства другим способом), система обрабатывает это, перезапуская действие (по умолчанию), поэтому вы можете быстро использовать все системные ресурсы при вращении пользователя. устройство переключается между книжной и альбомной ориентацией, потому что при каждом изменении ориентации вы создаете новый MediaPlayer , который никогда не отпускаете. (Дополнительную информацию о перезапусках среды выполнения см. в разделе «Обработка изменений во время выполнения ».)

Вам может быть интересно, что произойдет, если вы захотите продолжить воспроизведение «фонового мультимедиа», даже когда пользователь покидает вашу активность, во многом так же, как ведет себя встроенное приложение «Музыка». В этом случае вам нужен MediaPlayer управляемый службой, как описано в следующем разделе.

Использование MediaPlayer в сервисе

Если вы хотите, чтобы ваши медиафайлы воспроизводились в фоновом режиме, даже если ваше приложение не отображается на экране, то есть вы хотите, чтобы оно продолжало воспроизводиться, пока пользователь взаимодействует с другими приложениями, вам необходимо запустить службу и оттуда управлять экземпляром MediaPlayer . Вам необходимо встроить MediaPlayer в службу MediaBrowserServiceCompat и заставить его взаимодействовать с MediaBrowserCompat в другом действии.

Вы должны быть осторожны с этой настройкой клиент/сервер. Существуют ожидания относительно того, как игрок, работающий в фоновом режиме, взаимодействует с остальной частью системы. Если ваше приложение не оправдывает этих ожиданий, у пользователя может возникнуть неприятный опыт. Прочтите статью «Создание аудиоприложения» для получения полной информации.

В этом разделе описаны специальные инструкции по управлению MediaPlayer, когда он реализован внутри службы.

Асинхронный запуск

Прежде всего, как и в случае с Activity , вся работа в Service по умолчанию выполняется в одном потоке — фактически, если вы запускаете действие и службу из одного и того же приложения, они используют один и тот же поток («основной поток»). ") по умолчанию. Поэтому сервисам необходимо быстро обрабатывать входящие намерения и никогда не выполнять длительные вычисления при ответе на них. Если ожидается какая-либо тяжелая работа или блокирующие вызовы, вы должны выполнять эти задачи асинхронно: либо из другого потока, который вы реализуете самостоятельно, либо используя множество средств платформы для асинхронной обработки.

Например, при использовании MediaPlayer из вашего основного потока вам следует вызвать prepareAsync() вместо prepare() и реализовать MediaPlayer.OnPreparedListener , чтобы получить уведомление, когда подготовка будет завершена и вы сможете начать играть. Например:

Котлин

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()
    }
}

Ява

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();
    }
}

Обработка асинхронных ошибок

При синхронных операциях ошибки обычно сигнализируются с помощью исключения или кода ошибки, но всякий раз, когда вы используете асинхронные ресурсы, вы должны убедиться, что ваше приложение уведомляется об ошибках соответствующим образом. В случае с MediaPlayer это можно сделать, реализовав MediaPlayer.OnErrorListener и установив его в экземпляре MediaPlayer :

Котлин

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!
    }
}

Ява

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!
    }
}

Важно помнить, что при возникновении ошибки MediaPlayer переходит в состояние Error (полную диаграмму состояний см. в документации к классу MediaPlayer ), и вам необходимо сбросить его, прежде чем вы сможете использовать его снова.

Использование блокировки пробуждения

При разработке приложений, воспроизводящих мультимедиа в фоновом режиме, устройство может перейти в спящий режим во время работы службы. Поскольку система Android пытается экономить заряд батареи, пока устройство находится в спящем режиме, система пытается отключить все ненужные функции телефона, включая процессор и оборудование Wi-Fi. Однако если ваш сервис воспроизводит или передает музыку в потоковом режиме, вы хотите, чтобы система не мешала вашему воспроизведению.

Чтобы гарантировать, что ваша служба продолжит работать в этих условиях, вам необходимо использовать «блокировки пробуждения». Блокировка пробуждения — это способ сообщить системе, что ваше приложение использует некоторую функцию, которая должна оставаться доступной, даже если телефон находится в режиме ожидания.

Примечание. Всегда следует использовать блокировки пробуждения экономно и удерживать их только столько времени, сколько действительно необходимо, поскольку они значительно сокращают срок службы батареи устройства.

Чтобы гарантировать, что процессор продолжает работать во время воспроизведения вашего MediaPlayer , вызовите метод setWakeMode() при инициализации вашего MediaPlayer . Как только вы это сделаете, MediaPlayer удерживает указанную блокировку во время воспроизведения и снимает блокировку при приостановке или остановке:

Котлин

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

Ява

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

Однако блокировка пробуждения, полученная в этом примере, гарантирует только то, что ЦП остается в бодрствующем состоянии. Если вы осуществляете потоковую передачу мультимедиа по сети и используете Wi-Fi, вы, вероятно, также захотите иметь WifiLock , который вам придется получить и отключить вручную. Итак, когда вы начинаете подготовку MediaPlayer с удаленным URL-адресом, вам следует создать и получить блокировку Wi-Fi. Например:

Котлин

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

wifiLock.acquire()

Ява

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

wifiLock.acquire();

Когда вы приостанавливаете или останавливаете воспроизведение мультимедиа или когда сеть вам больше не нужна, вам следует снять блокировку:

Котлин

wifiLock.release()

Ява

wifiLock.release();

Выполнение очистки

Как упоминалось ранее, объект MediaPlayer может потреблять значительный объем системных ресурсов, поэтому вам следует хранить его столько, сколько вам нужно, и вызывать release() когда вы закончите с ним. Важно вызывать этот метод очистки явно, а не полагаться на системную сборку мусора, поскольку сборщику мусора может потребоваться некоторое время, чтобы вернуть MediaPlayer , поскольку он чувствителен только к потребностям памяти, а не к нехватке других ресурсов, связанных с мультимедиа. Итак, в случае использования службы вам всегда следует переопределить метод onDestroy() , чтобы убедиться, что вы освобождаете MediaPlayer :

Котлин

class MyService : Service() {

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

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

Ява

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

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

Вам всегда следует искать другие возможности для освобождения вашего MediaPlayer , помимо его выпуска при выключении. Например, если вы ожидаете, что не сможете воспроизводить мультимедиа в течение длительного периода времени (например, после потери фокуса звука), вам обязательно следует освободить существующий MediaPlayer и создать его снова позже. С другой стороны, если вы планируете остановить воспроизведение только на очень короткое время, вам, вероятно, следует сохранить свой MediaPlayer , чтобы избежать накладных расходов на его повторное создание и подготовку.

Управление цифровыми правами (DRM)

Начиная с Android 8.0 (уровень API 26), MediaPlayer включает API, которые поддерживают воспроизведение материалов, защищенных DRM. Они похожи на низкоуровневый API, предоставляемый MediaDrm , но работают на более высоком уровне и не раскрывают базовый экстрактор, drm и криптографические объекты.

Хотя API MediaPlayer DRM не обеспечивает полную функциональность MediaDrm , он поддерживает наиболее распространенные варианты использования. Текущая реализация может обрабатывать следующие типы контента:

  • Локальные медиафайлы, защищенные Widevine
  • Удаленные/потоковое медиафайлы, защищенные Widevine

В следующем фрагменте кода показано, как использовать новые методы DRM MediaPlayer в простой синхронной реализации.

Чтобы управлять мультимедиа, контролируемым DRM, вам необходимо включить новые методы вместе с обычным потоком вызовов MediaPlayer, как показано ниже:

Котлин

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()
}

Ява

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();

Начните с инициализации объекта MediaPlayer и установки его источника с помощью setDataSource() , как обычно. Затем, чтобы использовать DRM, выполните следующие действия:

  1. Если вы хотите, чтобы ваше приложение выполняло пользовательскую настройку, определите интерфейс OnDrmConfigHelper и прикрепите его к проигрывателю с помощью setOnDrmConfigHelper() .
  2. Вызовите prepare() .
  3. Вызовите getDrmInfo() . Если источник имеет содержимое DRM, метод возвращает ненулевое значение MediaPlayer.DrmInfo .

Если MediaPlayer.DrmInfo существует:

  1. Изучите карту доступных UUID и выберите один.
  2. Подготовьте конфигурацию DRM для текущего источника, вызвав prepareDrm() .
    • Если вы создали и зарегистрировали обратный вызов OnDrmConfigHelper , он вызывается во время выполнения prepareDrm() . Это позволяет вам выполнить пользовательскую настройку свойств DRM перед открытием сеанса DRM. Обратный вызов вызывается синхронно в потоке, вызвавшем prepareDrm() . Чтобы получить доступ к свойствам DRM, вызовите getDrmPropertyString() и setDrmPropertyString() . Избегайте выполнения длительных операций.
    • Если устройство еще не было подготовлено, prepareDrm() также обращается к серверу обеспечения для подготовки устройства. Это может занять разное время в зависимости от сетевого подключения.
  3. Чтобы получить массив байтов запроса непрозрачного ключа для отправки на сервер лицензий, вызовите getKeyRequest() .
  4. Чтобы сообщить механизму DRM об ответе на ключ, полученном от сервера лицензий, вызовите provideKeyResponse() . Результат зависит от типа запроса ключа:
    • Если ответ предназначен для автономного запроса ключа, результатом является идентификатор набора ключей. Вы можете использовать этот идентификатор набора ключей с помощью restoreKeys() для восстановления ключей в новом сеансе.
    • Если ответ предназначен для запроса потоковой передачи или выпуска, результат будет нулевым.

Запуск prepareDrm() асинхронно

По умолчанию prepareDrm() выполняется синхронно, блокируясь до завершения подготовки. Однако самая первая подготовка DRM на новом устройстве также может потребовать подготовки, которая обрабатывается внутри prepareDrm() и может занять некоторое время для завершения из-за задействованной сетевой операции. Вы можете избежать блокировки при prepareDrm() определив и установив MediaPlayer.OnDrmPreparedListener .

Когда вы устанавливаете OnDrmPreparedListener , prepareDrm() выполняет подготовку (при необходимости) и подготовку в фоновом режиме. Когда предоставление и подготовка завершены, вызывается прослушиватель. Не следует делать никаких предположений относительно последовательности вызовов или потока, в котором работает прослушиватель (если только прослушиватель не зарегистрирован в потоке-обработчике). Прослушиватель может быть вызван до или после возврата prepareDrm() .

Асинхронная настройка DRM

Вы можете инициализировать DRM асинхронно, создав и зарегистрировав MediaPlayer.OnDrmInfoListener для подготовки DRM и MediaPlayer.OnDrmPreparedListener для запуска проигрывателя. Они работают совместно с prepareAsync() , как показано ниже:

Котлин

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()
}

Ява

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();
}

Обработка зашифрованных носителей

Начиная с Android 8.0 (уровень API 26), MediaPlayer также может расшифровывать зашифрованные медиафайлы на уровне выборки (METHOD=SAMPLE-AES) по общей схеме шифрования (CENC) и HLS для типов элементарных потоков H.264 и AAC. Ранее поддерживались носители с полносегментным шифрованием (METHOD=AES-128).

Получение мультимедиа из ContentResolver

Еще одна функция, которая может быть полезна в приложении медиаплеера, — это возможность извлекать музыку, хранящуюся на устройстве пользователя. Вы можете сделать это, запросив ContentResolver для внешнего носителя:

Котлин

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()

Ява

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());
}

Чтобы использовать это с MediaPlayer , вы можете сделать это:

Котлин

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...

Ява

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...

Узнать больше

На этих страницах рассматриваются темы, касающиеся записи, хранения и воспроизведения аудио и видео.