Run audio in android

Звук Android

ОС Android обеспечивает расширенную поддержку мультимедиа, охватывающую как аудио, так и видео. В этом руководстве рассказывается о звуках в Android и рассматривается воспроизведение и запись звука с помощью встроенных классов аудио Player и записывающего класса, а также низкоуровневого аудио API. Кроме того, в нем рассматривается работа с звуковыми событиями в других приложениях, что позволяет разработчикам создавать хорошо работающие приложения.

Обзор

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

Android обеспечивает расширенную поддержку мультимедиа. В этой статье рассматривается работа с аудио в Android и рассматриваются следующие темы.

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

Запись звука — использование встроенного класса для записи звука.

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

Работа с Low-Level звуком — воспроизведение звука с помощью класса путем записи непосредственно в буферы памяти. Запись звука с помощью AudioRecord класса и чтение непосредственно из буферов памяти.

Требования

Для работы с этим руководством требуется Android 2,0 (API уровня 5) или более поздней версии. Обратите внимание, что отладка звука на Android должна выполняться на устройстве.

Необходимо запросить RECORD_AUDIO разрешения в RECORD_AUDIO :

Воспроизведение звука с помощью класса MediaPlayer

Самым простым способом воспроизведения звука в Android является встроенный класс MediaPlayer . MediaPlayer может играть как локальные, так и удаленные файлы, передав путь к файлу. Однако MediaPlayer является очень чувствительным к состоянию, и вызов одного из его методов в неправильном состоянии приведет к возникновению исключения. Чтобы избежать ошибок, важно взаимодействовать с MediaPlayer в порядке, описанном ниже.

Инициализация и воспроизведение

Для воспроизведения звука MediaPlayer требуется следующая последовательность:

Создайте экземпляр нового объекта MediaPlayer .

Настройте файл для воспроизведения с помощью метода сетдатасаурце .

Вызовите метод Prepare , чтобы инициализировать проигрыватель.

Вызовите метод Start , чтобы начать воспроизведение звука.

Это использование показано в приведенном ниже примере кода.

Приостановка и возобновление воспроизведения

Воспроизведение можно приостановить, вызвав метод Pause :

Чтобы возобновить приостановленное воспроизведение, вызовите метод Start . Это будет возобновлено из приостановленного места воспроизведения:

Вызов метода останавливает на проигрывателе завершает текущее воспроизведение:

Если проигрыватель больше не нужен, необходимо освободить ресурсы, вызвав метод Release :

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

Для MediaPlayer записи звука в Android используется класс MediaPlayer . Как и MediaPlayer , оно зависит от состояния и переходит по нескольким состояниям, чтобы получить точку, с которой он может начать запись. Для записи звука RECORD_AUDIO необходимо задать разрешение. Инструкции по настройке разрешений приложений см. в разделе Работа с AndroidManifest.xml.

Инициализация и запись

Для записи звука в MediaRecorder необходимо выполнить следующие действия.

Создайте экземпляр нового объекта Медиарекордер .

Укажите, какое аппаратное устройство следует использовать для записи звуковых данных с помощью метода сетаудиосаурце .

Задайте звуковой формат выходного файла с помощью метода сетаутпутформат . Список поддерживаемых типов аудио см. в статье форматы мультимедиа, поддерживаемые Android.

Вызовите метод сетаудиоенкодер , чтобы задать тип кодирования звука.

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

Вызовите метод Prepare , чтобы инициализировать средство записи.

Чтобы начать запись, вызовите метод Start .

Эта последовательность показана в следующем образце кода:

Остановка записи

Чтобы прерывать запись, вызовите Stop метод для MediaRecorder :

Очистка

После MediaRecorder остановки, вызовите метод MediaRecorder , чтобы вернуть его в состояние простоя:

Если объект MediaRecorder больше не нужен, его ресурсы необходимо освободить, вызвав метод MediaRecorder :

Управление звуковыми уведомлениями

Класс Аудиоманажер

Класс аудиоманажер предоставляет доступ к звуковым уведомлениям, которые позволяют приложениям узнавать о возникновении звуковых событий. Эта служба также предоставляет доступ к другим звуковым функциям, таким как управление режимами громкости и звонка. AudioManager Позволяет приложению работать с звуковыми уведомлениями для управления воспроизведением звука.

Управление фокусом звука

Звуковые ресурсы устройства (встроенные проигрыватель и устройство записи) совместно используются всеми работающими приложениями.

Читайте также:  Прошивка самсунг а10 a105fpuu6bud1 android 9

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

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

Фокус звука может быть предоставлен немедленно или изначально отклонен и предоставлен позже. Например, если приложение запрашивает фокус ввода во время звонка, оно будет отклонено, но после завершения звонка фокус может быть предоставлен. В этом случае прослушиватель регистрируется, чтобы ответить соответствующим образом при отсутствии звука. Запрос на запись звука используется для определения того, можно ли воспроизвести или записать звук.

Дополнительные сведения о звуковых фокусах см. в разделе Управление звуковым фокусом.

Регистрация обратного вызова для звукового фокуса

Регистрация FocusChangeListener обратного вызова из IOnAudioChangeListener является важной частью получения и снятия фокуса звука. Это связано с тем, что предоставление фокуса звука может быть отложено до последующего времени. Например, приложение может запрашивать воспроизведение музыки, пока выполняется телефонный звонок. Фокус звука не будет предоставляться до завершения звонка.

По этой причине объект обратного вызова передается как параметр в GetAudioFocus метод объекта AudioManager , и этот вызов регистрирует обратный вызов. Если фокус аудио изначально был отклонен, но позже предоставлен, приложение уведомляется о вызове OnAudioFocusChange по обратному вызову. Этот же метод используется для информирования приложения о том, что он находится в процессе записи.

Когда приложение завершит использование звуковых ресурсов, оно вызывает AbandonFocus метод AudioManager и снова передает обратный вызов. Это отменит обратный вызов и освободит звуковые ресурсы, чтобы другие приложения могли получить фокус звука.

Запрос фокуса звука

Ниже приведены шаги, необходимые для запроса звуковых ресурсов устройства.

Получение маркера для AudioManager системной службы.

Создайте экземпляр класса обратного вызова.

Запросите звуковые ресурсы устройства, вызвав RequestAudioFocus метод в AudioManager . Параметры — это объект обратного вызова, тип потока (музыка, голосовое обращение, кольцо и т. д.). и тип запрашиваемого права доступа (например, звуковые ресурсы можно запросить мгновенно или в течение неопределенного периода времени).

Если запрос предоставлен, playMusic метод вызывается немедленно, и начнется воспроизведение звука.

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

Следующие шаги показаны в примере кода ниже.

Освобождение фокуса звука

После завершения воспроизведения записи AbandonFocus AudioManager вызывается метод On. Это позволяет другому приложению получить звуковые ресурсы устройства. Другие приложения получат уведомление об изменении фокуса звука, если они зарегистрировали свои собственные прослушиватели.

Аудио API низкого уровня

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

При воспроизведении из зашифрованных звуковых файлов.

При воспроизведении коротких клипов.

Потоковая передача звука.

Класс AudioTrack

Класс AudioTrack использует низкоуровневые интерфейсы аудио API для записи и является аналогом класса нижнего уровня .

Инициализация и воспроизведение

Для воспроизведения звука AudioTrack должен быть создан экземпляр нового экземпляра. В списке аргументов, переданном в конструктор , указывается способ воспроизведения звукового примера, содержащегося в буфере. Аргументы:

Тип потока — речь, Мелодия звонка, музыка, система или будильник.

Частота — частота дискретизации, выраженная в Гц.

Конфигурация канала — моно или стерео.

Формат аудио — 8 бит или 16-разрядная кодировка.

Размер буфера — в байтах.

Режим буфера — потоковая передача или статическая.

После создания вызывается метод Play для начала воспроизведения. Запись аудио буфера в AudioTrack запускает воспроизведение:

Приостановка и остановка воспроизведения

Чтобы приостановить воспроизведение, вызовите метод Pause :

Вызов метода остановить приведет к окончательному завершению воспроизведения:

Очистка

Если объект AudioTrack больше не нужен, его ресурсы должны быть освобождены вызовом AudioTrack :

Класс Аудиорекорд

Класс аудиорекорд эквивалентен на стороне записи. Как и AudioTrack в случае с файлами и URI, он использует буферы памяти непосредственно. Для этого требуется, чтобы RECORD_AUDIO разрешение было задано в манифесте.

Инициализация и запись

Первым шагом является создание нового объекта аудиорекорд . Список аргументов, переданный в конструктор , предоставляет всю информацию, необходимую для записи. В отличие от AudioTrack , где аргументы являются главными перечислениями, эквивалентные аргументы в AudioRecord являются целыми числами. Сюда входит следующее.

Читайте также:  Public abstract class android

Аппаратный источник входных данных, например микрофон.

Тип потока — речь, Мелодия звонка, музыка, система или будильник.

Частота — частота дискретизации, выраженная в Гц.

Конфигурация канала — моно или стерео.

Формат аудио — 8 бит или 16-разрядная кодировка.

Размер буфера — в байтах

После создания AudioRecord метода вызывается его метод AudioRecord . Теперь она готова начать запись. Объект AudioRecord постоянно считывает звуковой буфер для входных данных и записывает его в звуковой файл.

Остановка записи

Вызов метода остановить завершает запись:

Очистка

Если AudioRecord объект больше не нужен, вызов метода AudioRecord освобождает все связанные с ним ресурсы:

Итоги

ОС Android предоставляет мощную платформу для воспроизведения, записи и управления аудио. В этой статье мы рассмотрели, как воспроизвести и записать звук с помощью высокоуровневых MediaPlayer MediaRecorder классов и. Далее рассматривается использование звуковых уведомлений для совместного использования звуковых ресурсов устройства различными приложениями. Наконец, она посвящена тому, как воспроизводить и записывать аудио с помощью низкоуровневых интерфейсов API, интерфейс которых напрямую использует буферы памяти.

Источник

Android и звук: как делать правильно

В статье рассматривается архитектура и API для создания приложений, воспроизводящих музыку. Мы напишем простое приложение, которое будет проигрывать небольшой заранее заданный плейлист, но «по-взрослому» — с использованием официально рекомендуемых практик. Мы применим MediaSession и MediaController для организации единой точки доступа к медиаплееру, и MediaBrowserService для поддержки Android Auto. А также оговорим ряд шагов, которые обязательны, если мы не хотим вызвать ненависти пользователя.

В первом приближении задача выглядит просто: в activity создаем MediaPlayer, при нажатии кнопки Play начинаем воспроизведение, а Stop — останавливаем. Все прекрасно работает ровно до тех пор, пока пользователь не выйдет из activity. Очевидным решением будет перенос MediaPlayer в сервис. Однако теперь у нас встают вопросы организации доступа к плееру из UI. Нам придется реализовать binded-сервис, придумать для него API, который позволил бы управлять плеером и получать от него события. Но это только половина дела: никто, кроме нас, не знает API сервиса, соответственно, наша activity будет единственным средством управления. Пользователю придется зайти в приложение и нажать Pause, если он хочет позвонить. В идеале нам нужен унифицированный способ сообщить Android, что наше приложение является плеером, им можно управлять и что в настоящий момент мы играем такой-то трек из такого-то альбома. Чтобы система со своей стороны подсобила нам с UI. В Lollipop (API 21) был представлен такой механизм в виде классов MediaSession и MediaController. Немногим позже в support library появились их близнецы MediaSessionCompat и MediaControllerCompat.

Следует сразу отметить, что MediaSession не имеет отношения к воспроизведению звука, он только об управлении плеером и его метаданными.

MediaSession

Итак, мы создаем экземпляр MediaSession в сервисе, заполняем его сведениями о нашем плеере, его состоянии и отдаем MediaSession.Callback, в котором определены методы onPlay, onPause, onStop, onSkipToNext и прочие. В эти методы мы помещаем код управления MediaPlayer (в примере воспользуемся ExoPlayer). Наша цель, чтобы события и от аппаратных кнопок, и из окна блокировки, и с часов под Android Wear вызывали эти методы.

Полностью рабочий код доступен на GitHub (ветка master). В статьи приводятся только переработанные выдержки из него.

Для доступа извне к MediaSession требуется токен. Для этого научим сервис его отдавать

и пропишем в манифест

MediaController

Теперь реализуем activity с кнопками управления. Создаем экземпляр MediaController и передаем в конструктор полученный из сервиса токен.

MediaController предоставляет как методы управления плеером play, pause, stop, так и коллбэки onPlaybackStateChanged(PlaybackState state) и onMetadataChanged(MediaMetadata metadata). К одному MediaSession могут подключиться несколько MediaController, таким образом можно легко обеспечить консистентность состояний кнопок во всех окнах.

Наша activity работает, но ведь идея исходно была, чтобы из окна блокировки тоже можно было управлять. И тут мы приходим к важному моменту: в API 21 полностью переделали окно блокировки, теперь там отображаются уведомления и кнопки управления плеером надо делать через уведомления. К этому мы вернемся позже, давайте пока рассмотрим старое окно блокировки.

Как только мы вызываем mediaSession.setActive(true), система магическим образом присоединяется без всяких токенов к MediaSession и показывает кнопки управления на фоне картинки из метаданных.

Однако в силу исторических причин события о нажатии кнопок приходят не напрямую в MediaSession, а в виде бродкастов. Соответственно, нам надо еще подписаться на эти бродкасты и перебросить их в MediaSession.

MediaButtonReceiver

Для этого разработчики Android любезно предлагают нам воспользоваться готовым ресивером MediaButtonReceiver.

Добавим его в манифест

MediaButtonReceiver при получении события ищет в приложении сервис, который также принимает «android.intent.action.MEDIA_BUTTON» и перенаправляет его туда. Поэтому добавим аналогичный интент-фильтр в сервис

Читайте также:  Resident evil 5 android как установить

Если подходящий сервис не найден или их несколько, будет выброшен IllegalStateException.

Теперь в сервис добавим

Метод handleIntent анализирует коды кнопок из intent и вызывает соответствующие коллбэки в mediaSession. Получилось немного плясок с бубном, но зато почти без написания кода.

На системах с API >= 21 система не использует бродкасты для отправки событий нажатия на кнопки и вместо этого напрямую обращается в MediaSession. Однако, если наш MediaSession неактивен (setActive(false)), его пробудят бродкастом. И для того, чтобы этот механизм работал, надо сообщить MediaSession, в какой ресивер отправлять бродкасты.
Добавим в onCreate сервиса

На системах с API Так это выглядит

Android 4.4

MIUI 8 (базируется на Android 6, то есть теоретически окно блокировки не должно отображать наш трек, но здесь уже сказывается кастомизация MIUI).

Уведомления

Однако, как ранее упоминалось, начиная с API 21 окно блокировки научилось отображать уведомления. И по этому радостному поводу, вышеописанный механизм был выпилен. Так что теперь давайте еще формировать уведомления. Это не только требование современных систем, но и просто удобно, поскольку пользователю не придется выключать и включать экран, чтобы просто нажать паузу. Заодно применим это уведомление для перевода сервиса в foreground-режим.

Нам не придется рисовать кастомное уведомление, поскольку Android предоставляет специальный стиль для плееров — Notification.MediaStyle.

Добавим в сервис два метода

И добавим вызов refreshNotificationAndForegroundStatus(int playbackState) во все коллбэки MediaSession.

Android 4.4

Android 7.1.1

Android Wear

Started service

В принципе у нас уже все работает, но есть засада: наша activity запускает сервис через binding. Соответственно, после того, как activity отцепится от сервиса, он будет уничтожен и музыка остановится. Поэтому нам надо в onPlay добавить

Никакой обработки в onStartCommand не надо, наша цель не дать системе убить сервис после onUnbind.

А в onStop добавить

В случае, если к сервису привязаны клиенты, stopSelf ничего не делает, только взводит флаг, что после onUnbind сервис можно уничтожить. Так что это вполне безопасно.

ACTION_AUDIO_BECOMING_NOISY

Продолжаем полировать сервис. Допустим пользователь слушает музыку в наушниках и выдергивает их. Если эту ситуацию специально не обработать, звук переключится на динамик телефона и его услышат все окружающие. Было бы хорошо в этом случае встать на паузу.
Для этого в Android есть специальный бродкаст AudioManager.ACTION_AUDIO_BECOMING_NOISY.
Добавим в onPlay

В onPause и onStop

И по факту события встаем на паузу

Android Auto

Начиная с API 21 появилась возможность интегрировать телефон с экраном в автомобиле. Для этого необходимо поставить приложение Android Auto и подключить телефон к совместимому автомобилю. На экран автомобиля будет выведены крупные контролы для управления навигацией, сообщениями и музыкой. Давайте предложим Android Auto наше приложение в качестве поставщика музыки.

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

Исходный код выложен на GitHub (ветка MediaBrowserService).

Прежде всего надо указать в манифесте, что наше приложение совместимо с Android Auto.
Добавим в манифест

Здесь automotive_app_desc — это ссылка на файл automotive_app_desc.xml, который надо создать в папке xml

Преобразуем наш сервис в MediaBrowserService. Его задача, помимо всего ранее сделанного, отдавать токен в Android Auto и предоставлять плейлисты.

Поправим декларацию сервиса в манифесте

Во-первых, теперь наш сервис экспортируется, поскольку к нему будут подсоединяться снаружи.

И, во-вторых, добавлен интент-фильтр android.media.browse.MediaBrowserService.

Меняем родительский класс на MediaBrowserServiceCompat.

Поскольку теперь сервис должен отдавать разные IBinder в зависимости от интента, поправим onBind

Имплементируем два абстрактных метода, возвращающие плейлисты

И, наконец, имплементируем новый коллбэк MediaSession

Здесь mediaId — это тот, который мы отдали в setMediaId в onLoadChildren.

Плейлист

Трек

UPDATE от 27.10.2017: Пример на GitHub переведен на targetSdkVersion=26. Из релевантных теме статьи изменений необходимо отметить следующее:

  • android.support.v7.app.NotificationCompat.MediaStyle теперь deprecated. Вместо него следует использовать android.support.v4.media.app.NotificationCompat.MediaStyle. Соответственно, больше нет необходимости использовать android.support.v7.app.NotificationCompat, теперь можно использовать android.support.v4.app.NotificationCompat
  • Метод AudioManager.requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint) теперь тоже deprecated. Вместо него надо использовать AudioManager.requestAudioFocus(AudioFocusRequest focusRequest). AudioFocusRequest — новый класс, добавленный с API 26, поэтому не забывайте проверять на API level.
    Создание AudioFocusRequest выглядит следующим образом

Теперь запрашиваем фокус

Разумеется, все вышеописанные изменения вносить необязательно, старые методы работать не перестали.

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

Еще очень рекомендую к просмотру доклад Ian Lake. Доклад от 2015 года, но вполне актуален.

Источник

Оцените статью