Воспроизведение звуковых эффектов в Android с помощью SoundPool
View more Tutorials:
1- SoundPool & AudioManager
Для начала, я создам ситуацию, вы создаете игру, игра проигрывает такие звуки как выстрелы, бомбы, это звуковые эффекты в игре. Android предоставляет вам класс SoundPool, похожий на хранилице звуков и готовый проигрывать их при запросе.
SoundPool содержит набор музыки, звуков из файла музыки в приложении или из файла в системе. SoundPool помогает проигрывать разные звуки одновременно.
SourcePool использует сервис MediaPlayer, чтобы сделать звуки.
Вид потока звуков | Описание |
AudioManager.STREAM_ALARM | Аудио звуков сирены |
AudioManager.STREAM DTMF | Аудио DTMF тонов |
AudioManager.STREAM_MUSIC | Аудио для перепроигрывания звуков |
AudioManager.STREAM_NOTIFICATION | Аудио звука уведомления |
AudioManager.STREAM_RING | Аудио звука звона телефона |
AudioManager.STREAM_SYSTEM | Аудио системных звуков |
AudioManager.STREAM_VOICE_CALL | Аудио телефонного вызова |
Другой вопрос это какое устройство производит звук.
Используя STREAM_MUSIC звук будет произведен через одно звуковое устройтсво (телефонный динамик, наушники, динамик bluetooth и др.) соединенные с телефоном.
Используя STREAM_RING звук будет произведен через все звуковые устройтсва соединенные с телефоном. Это поведение может отличаться на каждом устройстве.
Метод | Описание |
int play(int soundID, float leftVolume, float rightVolume, int priority, int loop, float rate) | Воспроизведение источника звука, с возвращением ID нового воспроизведенного потока (streamID). |
void pause(int streamID) | Пауза звукового потока с ID streamID. |
void stop(int streamID) | Остановка звукового потока с streamID. |
void setVolume(int streamID, float leftVolume, float rightVolume) | Установка громкости звукового потока с ID streamID |
void setLoop(int streamID, int loop) | Установка номер цикла для звукового потока с ID streamID. |
2- Пример с SoundPool
- Name: SoundPoolDemo
- Package name: org.o7planning.soundpooldemo
View more Tutorials:
Это онлайн курс вне вебсайта o7planning, который мы представляем, он включает бесплатные курсы или курсы со скидкой.
Источник
Класс SoundPool
Основное отличие класса SoundPool от класса MediaPlayer — поддержка одновременного проигрывания нескольких аудиопотоков, что широко используется в играх.
Обычно SoundPool используют для проигрывания маленьких аудиоклипов. SoundPool может играть несколько звуков одновременно. Звуки также можно повторять (зациклить). В этом случае для остановки проигрывания нужно явно вызывать метод остановки. Размер файла, который может проиграть SoundPool не должен превышать 1 мегабайт.
Поддерживаются файлы практически всех популярных форматов: mp3, ogg, wav, aac, 3gp, flac. После загрузки файлы перекодируются (в 16-bit PCM моно или стерео) для упрощения воспроизведения.
Можно управлять скоростью воспроизведения аудио файла. Скорость 1,0 означает воспроизведение звука в исходном виде, 2,0 — воспроизведение в два раза быстрее, а 0,5 в два раза медленнее. Диапазон скорости воспроизведения составляет от 0,5 до 2,0.
Можно программно задать количество аудио потоков, проигрываемых одновременно. Если максимальное число потоков будет превышено, автоматически остановится поток с самым низкий приоритетом. При наличии нескольких потоков с тем же низким приоритетом, будет выбран старейший из них. В случае, если приоритет нового потока ниже, чем все активные потоки, новый звук не будет проигран. Ограничение максимального числа потоков помогает снизить загрузку процессора.
Конструктор класса SoundPool
- maxStreams — максимальное количество потоков, который могут воспроизводится одновременно
- streamType — тип аудиопотока, это константа из класса AudioManager. Здесь чаще всего используется AudioManager.STREAM_MUSIC.
- srcQuality — качество кодирования. Сейчас этот параметр не используется, поэтому всегда будем передавать 0.
В API 21 конструктор считается устаревшим. Смотри ниже.
Методы
Загрузить аудио файлы в SoundPool можно с помощью четырёх методов:
Загрузка из папки assets. Нужно знать путь к файлу. AssetManager — класс, предоставляющий доступ к файлам в директории assets. Получить экземпляр класса для данного приложения можно методом getAssets(). AssetFileDescriptor — файловый дескриптор для файла из директории assets.
Загрузка файла по идентификатору ресурса. Звуковые файлы могут находиться в каталоге res/raw, и соответственно идентификатор будет R.raw.sound.
Загрузка файла из указанного пути.
Загрузка файла из файловой системы устройства. Этот вариант полезен, если вы храните несколько звуков в одном двоичном файле. Параметр offset определяет смещение от начала файла, а length определяет длину звука.
В каждом методе мы передаём priority — приоритет файла. Методы возвращают идентификатор загруженного звука, который позже используется для воспроизведения.
Загрузка файлов происходит асинхронно, то есть после вызова метода load() файл не сразу будет доступен для воспроизведения, так как необходимо время для его загрузки и перекодирования. Для того чтобы отследить окончание загрузки нужно обработать событие OnLoadCompleteListener. Для этого устанавливаем обработчик события с помощью метода void setOnLoadCompleteListener(SoundPool.OnLoadCompleteListener listener), где SoundPool.OnLoadCompleteListener — это интерфейс с единственным методом void onLoadComplete(SoundPool soundPool, int sampleId, int status), который вызывается когда файл загружен. Здесь sampleId — идентификатор загруженного файла (то есть то, что вернул метод load()), а status — статус загрузки (значение 0 обозначает успешную загрузку).
Метод для проигрывания звука
- soundID — идентификатор звука (который вернул load())
- leftVolume — уровень громкости для левого канала (от 0.0 до 1.0)
- rightVolume — уровень громкости для правого канала (от 0.0 до 1.0)
- priority — приоритет потока (0 — самый низкий)
- loop — количество повторов (0 — без повторов, (-1) — зациклен)
- rate — скорость воспроизведения (от 0.5 до 2.0)
Метод возвращает целое число int, которое используется в других методах в качестве параметра streamID.
Возобновить приостановленный поток (если поток был не на паузе, то метод не даст никакого результата)
Установка количество повторов для потока
Установка приоритета для потока
Установка скорости для потока
Установка громкости для потока
Приостановить все активные потоки
Возобновить все потоки
Удаляет звук из SoundPool. Метод возвращает true, если операция прошла успешно, и false, если такого SoundID не существует
Удаляет все загруженные звуки из SoundPool и освобождает память. После вызова этого метода экземпляр класса SoundPool уже нельзя использовать. Метод используется при выходе из программы, чтобы освободить ресурсы.
Пример
Добавим на форму две кнопки, а также звуковой файл в папку ресурсов res/raw. Образцы бесплатных звуков можно взять в разделе Звуки.
Кнопку управления громкостью телефона можно настроить для управления громкости звуков:
SoundPool.Builder (API 21)
В Android 5.0 (API 21) вызов конструктора считается устаревшим. На смену ему пришёл класс SoundPool.Builder. Ниже приводится код из одного проекта.
Пример использования старого и нового способа показан в примере Кто сказал Мяу? — работаем со звуками Му, Мяу, Гав
Источник
Полный список
MediaPlayer – класс, который позволит вам проигрывать аудио/видео файлы с возможностью сделать паузу и перемотать в нужную позицию. MediaPlayer умеет работать с различными источниками, это может быть: путь к файлу (на SD или в инете), адрес потока, Uri или файл из папки res/raw.
Напишем небольшое приложение аудио-плеер и используем в нем все эти возможности.
Project name: P1261_MediaPlayer
Build Target: Android 2.3.3
Application name: MediaPlayer
Package name: ru.startandroid.develop.p1261mediaplayer
Create Activity: MainActivity
Добавляем строки в strings.xml:
Так это выглядит на экране
Кнопки верхнего ряда запускают проигрывание треков из различных источников. Кнопки среднего ряда – это пауза, возобновление, стоп и чекбокс повторения трека. А в нижнем ряду кнопки перемотки назад/вперед и вывод в лог текущей информации.
Создайте папку res/raw и положите в нее какой-нить звуковой файл с именем explosion.mp3. Например, его можно скачать здесь — http://dl.dropboxusercontent.com/u/6197740/explosion.mp3.
Разбираемся. Сначала создаем константы-пути, которые будет использовать проигрыватель. Это файл в инете (DATA_HTTP), поток в инете (DATA_STREAM), файл на флэшке (DATA_SD) и Uri на мелодию из системы (DATA_URI). Для SD и Uri укажите ваши значения, чтобы такие файлы существовали. (По получению Uri в конце урока есть вспомогательный код)
В onCreate получаем AudioManager, находим на экране чекбокс и настраиваем так, чтобы он включал/выключал режим повтора для плеера.
onClickStart – метод для обработки нажатий на кнопки верхнего ряда. Сначала мы освобождаем ресурсы текущего проигрывателя. Затем в зависимости от нажатой кнопки стартуем проигрывание. Какие методы для этого используются?
setDataSource – задает источник данных для проигрывания
setAudioStreamType – задает аудио-поток, который будет использован для проигрывания. Их существует несколько: STREAM_MUSIC, STREAM_NOTIFICATION и п. Подробнее их можно посмотреть в доках по AudioManager. Предполагаю, что созданы они для того, чтобы можно было задавать разные уровни громкости, например, играм, звонкам и уведомлениям. Этот метод можно и пропустить, если вам не надо явно указывать какой-то поток. Насколько я понял, по умолчанию используется STREAM_MUSIC.
Далее используется метод prepare или prepareAsync (в паре с OnPreparedListener). Эти методы подготавливают плеер к проигрыванию. И, как понятно из названия, prepareAsync делает это асинхронно, и, когда все сделает, сообщит об этом слушателю из метода setOnPreparedListener. А метод prepare работает синхронно. Соотвественно, если хотим прослушать файл из инета, то используем prepareAsync, иначе наше приложение повесится, т.к. заблокируется основной поток, который обслуживает UI.
Ну и метод start запускает проигрывание.
В случае с raw-файлом мы используем метод create. В нем уже будет выполнен метод prepare и нам остается только выполнить start.
Далее мы для плеера включаем/выключаем повтор (setLooping) в зависимости от текущего значения чекбокса. И вешаем слушателя (setOnCompletionListener), который получит уведомление, когда проигрывание закончится.
В методе releaseMP мы выполняем метод release. Он освобождает используемые проигрывателем ресурсы, его рекомендуется вызывать когда вы закончили работу с плеером. Более того, хелп рекомендует вызывать этот метод и при onPause/onStop, если нет острой необходимости держать объект.
В методе onClick мы обрабатываем нажатия на кнопки управления проигрывателем. Какие здесь используются методы?
start – возобновляет проигрывание
seekTo – переход к определенной позиции трека (в милисекундах)
getCurrentPosition – получить текущую позицию (в милисекундах)
getDuration – общая продолжительность трека
isLooping – включен ли режим повтора
getStreamVolume – получить уровень громкости указанного потока
Далее идут методы
onPrepared – метод слушателя OnPreparedListener. Вызывается, когда плеер готов к проигрыванию.
onCompletion – метод слушателя OnCompletionListener. Вызывается, когда достигнут конец проигрываемого содержимого.
В методе onDestroy обязательно освобождаем ресурсы проигрывателя.
В манифесте добавляем права на интернет — android.permission.INTERNET.
Все сохраняем, запускаем приложение. Дизайн получившегося плеера, конечно, не ахти какой :), но нас сейчас интересует функционал.
Еще раз перечислю возможные действия. Нажимая верхние кнопки, мы запускаем проигрывание из различных источников. Кнопки среднего ряда позволят нам поставить паузу, возобновить/остановить проигрывание и включить режим повтора. Кнопки нижнего ряда перематывают назад/вперед на 3 сек (3000 мсек) и выводят инфу в лог.
Я включу проигрывание файла с SD и выведу инфу в лог (кнопка Info).
start SD
Playing true
Time 4702 / 170588
Looping false
Volume 10
Проигрывание идет, текущая позиция – 4-я секунда из 170, режим повтора выключен, громкость — 10.
Уменьшу громкость (кнопками устройства или эмулятора), включу режим повтора (чекбокс Loop), поставлю паузу (кнопка Pause) и снова выведу инфу в лог:
Playing false
Time 46237 / 170588
Looping true
Volume 6
Видим, что проигрывание остановилось, текущая позиция уже 46 секунд, режим повтора включен, а громкость уменьшилась до 6.
Теперь включу проигрывание потока (кнопка Stream). Смотрим лог:
08:49:13.799: D/myLogs(18805): start Stream
08:49:13.809: D/myLogs(18805): prepareAsync
08:49:27.589: D/myLogs(18805): onPrepared
Обратите внимание, сколько прошло времени с начала (prepareAsync) до завершения (onPrepared) подготовки проигрывателя – 14 секунд. Если бы мы использовали метод prepare, а не prepareAsync, то наше приложение было бы недоступно все это время.
Расскажу еще про несколько методов, которые я не использовал в примере, но о которых стоит знать.
Метод reset – сбрасывает плеер в начальное состояние, после него необходимо снова вызвать setDataSource и prepare. Похож на onRelease, но позволяет продолжить работу с этим же объектом. А вот после onRelease надо создавать новый объект MediaPlayer.
Метод setOnBufferingUpdateListener устанавливает слушателя буферизации проигрываемого потока. По идее слушатель будет получать процент буферизации, но у меня оно как-то странно работает — показывает или 0 или 100.
Метод setOnErrorListener устанавливает слушателя для получения ошибок. Особенно это полезно при методe prepareAsync. Если в ходе этого метода возникнут ошибки, то их можно поймать только так.
Метод setWakeMode позволяет ставить стандартную (PowerManager.WakeLock) блокировку на время проигрывания, указав тип блокировки. Не забудьте в манифесте добавить права на WAKE_LOCK.
По поводу видео. Метод setDisplay позволяет указать плееру, куда выводить изображение. Размещаете на экране компонент SurfaceView (вкладка Advanced), вызываете его метод getHolder и полученный объект передаете в setDisplay. Плеер выведет изображение на этот компонент.
Чтобы узнать размер проигрываемого изображения можно использовать методы getVideoHeight и getVideoWidth.
В хелпе класса MediaPlayer есть хорошая схема состояний плеера. Она кажется запутанной, но если посидеть и поразбираться, то вполне можно все понять. Схема полезная, советую вникнуть.
А здесь можно посмотреть какие форматы поддерживаются системой.
Также хелп любезно предоставляет нам код, который позволит просмотреть существующие медиа-файлы в системе:
На следующем уроке:
— работаем с SoundPool
Присоединяйтесь к нам в Telegram:
— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.
— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование
— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня
— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме
Источник