Всем привет! Меня зовут Дмитрий Булгаков, я Android-разработчик в HiFi-стриминге Звук, и я расскажу, как можно создать аудиоплеер в приложении. Поговорим об инструментах разработки и устройстве плеера — разберем его «анатомию», компоненты и их применение, а также способы улучшения звука с помощью эквалайзера.
Для вашего удобства гайд разделён на несколько основных частей.
Часть 2 — про то, как использовать ExoPlayer.
Часть 3 — про дополнительные настройки приложения с аудиоплеером и аудио эффекты, которые можно применять к звуку.
А в первой части я расскажу об актуальных инструментах разработки плеера и о том, что у него «под капотом».
Поехали!
Актуальные инструменты разработки плеера
Jetpack Media 3
Первое, что вам нужно — набор библиотек Jetpack Media 3. С его помощью в приложении можно сделать воспроизведение аудио и видеоконтента как на смартфоне, так и на удалённо подключенных устройствах (например, на ТВ-приставке, аудио ресивере или даже в вашем автомобиле и на часах). Кроме того, Jetpack Media 3 позволяет разрабатывать приложения для записи и обработки музыки и видео.
Можно с уверенностью сказать, что любое современное Android-приложение, в котором есть работа с контентом, не обходится без использования набора библиотек Media, так как они зачастую избавляют разработчика от необходимости углубляться в низкоуровневую реализацию алгоритмов обработки медиа. Это особенно важно для разработчиков без опыта работы с медиа: готовый набор инструментов даёт шанс сделать богатое функционалом и производительное приложение без изобретения велосипедов.
Мы в Звуке отдали предпочтение Jetpack Media и поэтому можем больше времени уделять работе над улучшением пользовательского опыта и не тратить время на изучение и поддержку стандартов различных аудиоформатов.
Архитектура приложения с Jetpack Media 3
Для воспроизведения контента в Jetpack Media 3 существует множество классов, использование которых позволит упростить разработку плеера. Например MediaSession, MediaController, MediaBrowser и непосредственно плееры. Разберём их взаимодействие.
Приложение состоит из пользовательского интерфейса, представленного экранами, и сервиса воспроизведения. Каждый экран может использовать некий контроллер, который позволяет управлять воспроизведением, например, отдавая команды «плей» или «паузы». Сервис воспроизведения, существующий отдельно от интерфейса, управляет медиа сессией и плеером, что позволяет наладить воспроизведение в фоновом режиме. Помимо команд из пользовательского интерфейса приложения плеер может получать команды из системы. Это нужно для того, чтобы воспроизведение в нашем приложении могло работать согласованно со всей системой и другими приложениями.
MediaPlayer и ExoPlayer
Когда речь заходит про простое воспроизведение аудио и видео, то для этого можно использовать две основные библиотеки: MediaPlayer и ExoPlayer.
Это база. MediaPlayer — удобная реализация плеера для самых простых случаев. Например, когда в приложении необходимо только проигрывать аудиофайл или стрим с данными популярных форматов. Это может быть мессенджер с возможностью прослушивания аудиосообщений или приложение для тренировок, в котором вам нужно лишь воспроизводить звуковые команды для спортсмена.
Однако для большего контроля над процессом воспроизведения MediaPlayer едва ли сгодится. Чтобы сделать крутой плеер на уровне YouTube и других популярных приложений, нужен ExoPlayer, который совсем недавно полноценно появился в Jetpack Media.
Факт
На самом деле open-source проекту ExoPlayer уже более 10 лет, его первый стабильный релиз датируется 2014-ым. В том же году библиотека была представлена Оливером Вудманом на конференции Google I/O. С тех пор проект пережил глубокий рефакторинг, обновился до второй версии и интенсивно развивается и поддерживается сотнями разработчиков. На странице проекта в Github создано более тысячи Pull-реквестов, что внесло неизмеримый вклад в развитие проекта и позволило многим приложениям обзавестись крутым плеером. В 2023 году мы получили полноценную поддержку ExoPlayer в Jetpack Media 3.
На перечисление всех возможностей ExoPlayer уйдёт много времени, поэтому упомяну лишь некоторые из них, значимые для аудиоплеера:
Поддержка всех популярных форматов и кодеков аудио контента (mp3, mp4, flac, wav и так далее)
Широкие возможности кастомизации плеера
Бесшовное воспроизведение, контроль очереди воспроизведения
Поддержка нескольких аудиодорожек и переключения между ними
Настройка скорости и громкости воспроизведения
Набор эффектов эквализации звука (для любителей добавить баса, убавить верхи)
Набор для построения интерфейса плеера (Playback UI)
Воспроизведения контента на устройствах с поддержкой chromecast
Мы в Звуке используем многие из этих функций, но, конечно, самое большое преимущество, которое ExoPlayer даёт разработчику — гибкость.
ExoPlayer подходит для выполнения любых задач, так как практически не ограничивает разработчика в модификации плеера. Нужно воспроизводить рекламу в плеере — пожалуйста (для Exoplayer существует расширение Interactive Media Ads). Нужно воспроизводить трансляции с адаптивным качеством — возьмите расширение HLS, DASH или другое подходящее под ваши задачи.
Если какой-то функционал в ExoPlayer ещё не был реализован — это не проблема, вы легко можете переопределить существующие интерфейсы и встроить требуемое поведение. Например, таким образом в Звуке удалось добавить в плеер поддержку воспроизведения музыки HiFi-качества и стать единственным на рынке аудиосервисом, у которого оно есть.
Основные компоненты плеера. Строим плеер по частям
Конечно, при разработке собственного приложения с продвинутыми функциями плеера необходимо понимание того, как плеер работает «под капотом». Давайте разберемся в этом вместе.
Начнём по порядку. Плеер воспроизводит, например, музыку.
Что вообще такое музыка? Это акустические волны, которые мы улавливаем своими ушами и получаем звуковую информацию. Каждая волна разная, и, чтобы сохранить определённую последовательность волн, человечество придумало звукозапись. Исторически носители звуковой информации претерпели серьезные изменения: от самых первых нотных записей до современных цифровых форматов хранения и передачи звука. Цифровая звукозапись в наше время стала самым популярным способом хранения звука: исходная звуковая волна записывается, оцифровывается и сохраняется в файл.
Источник данных
Файл — это источник данных, с которым работает плеер. Он хранит и предоставляет плееру некоторый набор нулей и единиц, которые каким-то образом описывают наш исходный звук. Но звук может храниться с разными параметрами. И для предоставления информации, с какими параметрами хранится звук, существуют форматы. Например форматы файлов mp3, flac, wav, ogg и многие другие. Каждый из них имеет свою собственную, особую структуру и порядок записи данных. И по этой причине наш плеер должен уметь работать с этими форматами, извлекая необходимые данные из них.
Экстрактор
Ещё одна часть системы — экстрактор. Например, плееру для воспроизведения необходимо знать, с какой частотой дискретизации был записан звук (то есть сколько измерений акустического давления в секунду было сделано микрофоном во время звукозаписи), с какой глубиной кодирования (то есть с какой точностью измерялось акустическое давление) или в целом — какой контент был записан. Чтобы это выяснить, в большинстве форматов предусмотрено хранение метаданных: от даты записи, выпуска альбома, до названия трека и номера трека в альбоме. Элемент плеера, который занимается извлечением этой информации из файла, называется экстрактором.
Декодер
Ну и конечно, в каждом формате предусмотрено хранение самого звукового сигнала — то, что мы намерены воспроизводить. Но если бы звуковые данные хранились в файле в исходном виде, они занимали бы очень много цифровой памяти. Путём нехитрых вычислений, можно получить десятки мегабайт для обычной музыкальной композиции длительностью в 3 минуты, а это слишком много, особенно для стриминга. С использованием кодирования mp3 можно уменьшить размер файла с 31 до 7 мегабайт. По этой причине существуют различные способы кодирования и декодирования звука, а алгоритмы кодирования называются кодеками (англ. codec, от coder/decoder — шифратор/дешифратор).
Незакодированный звук займёт много памяти 44100 КГц * 16 бит * 180 с * 2 ≈ 32 МБ Закодированный звук экономит память в разы 320 Кбит/c * 180 с ≈ 7 МБ |
Поэтому нам нужен декодер, еще один элемент в нашей схеме. С его помощью можно кодировать информацию, а значит делать ее компактней.
Факт
Кодирование звукового сигнала бывает с потерями (когда звуковой сигнал после кодирования и последующего декодирования восстанавливается не до конца, а с некоторыми потерями в качестве звука) и без потерь — когда звуковой сигнал после преобразований не меняется.
Микшер
Таким образом информация, проходящая через всю эту схему наконец-то преобразуется в цифровой звуковой сигнал, с которым можно работать практически как с физическим звуком. Можно накладывать один звук на другой, добавлять различные эффекты, вроде бас-бустера или «эффекта комнаты», делать звук тише или громче. Этим занимается микшер.
Слева направо: файл, экстрактор, декодер, микшер, озвучивание
Далее буквально дело техники — в самом простом случае готовый сигнал отправляется на аудиодрайвер устройства (так называемый цифро-аналоговый преобразователь или ЦАП). Благодаря ЦАП-у цифровое представление сигнала преобразуется в аналоговое, а аналоговое — в акустическое. После этого мы наконец слышим звук из динамиков.
Вот мы и разобрали все основные этапы работы плеера. Напомню, это загрузка файла, извлечение из него данных, декодирование звука, микширование и озвучивание. Не так уж и сложно?
В следующих статьях я подробно расскажу, как использовать ExoPlayer и как еще можно настроить приложение с аудиоплеером (поговорим о дополнительных опциях).
Если есть вопросы по первой части нашего большого гайда — пишите в комментариях! С радостью отвечу.