🎧

OshaPlay: аудиофильский плеер для Android

bit-perfect вывод на USB-ЦАП и аудиокниги — собственный продукт, версия 0.10.0

Аудиофильский плеер для Android: bit-perfect вывод на USB-ЦАП по UAC2 в обход системного микшера, свой ресемплер с искажениями ниже −130 дБ, проверка подделок Hi-Res и раздел аудиокниг.

В разработке · собственный продукт
Бит в бит
трек доходит до ЦАПа без ресемплинга системным микшером
−130 дБ
уровень искажений собственного ресемплера для частот 88,2 и 176,4 кГц
4 источника
RuTracker, Bandcamp, Jamendo и Live Music Archive в одном поиске
OshaPlay, аудиоплеер DevUnit Lab для Android: экран «Сейчас играет» с проверкой Hi-Res и настройки наушников
OshaPlay, аудиоплеер DevUnit Lab для Android: экран «Сейчас играет» с проверкой Hi-Res и настройки наушников

Задача

Системный микшер Android (AudioFlinger) пропускает любой звук через ресемплинг до своей частоты вывода, обычно 48 кГц. Поэтому 24-битный FLAC 96 кГц доходит до ЦАПа уже изменённым, а обычные плееры об этом молчат. На Android 12 штатного способа обойти микшер нет: режим bit-perfect для USB появился только в Android 14.

Вторая проблема — доверие к файлам. Под видом Hi-Res часто продают перекодированный MP3 или растянутый CD, и на слух это не всегда очевидно. Третья — обычный плеер плохо подходит для аудиокниг: не помнит место в каждой книге, не даёт отдельную скорость на книгу и не оставляет следов о том, где человек уснул.

Решение

OshaPlay — плеер для своей фонотеки. Он сам говорит с USB-ЦАПом по протоколу USB Audio Class (UAC2), отдаёт трек в исходных частоте и разрядности, а громкость регулирует силами ЦАПа. Вокруг этого построен полноценный плеер. Что сделано по журналу выпусков:

  • Фонотека: альбомы с обложками, исполнители, все треки, обзор по папкам, поиск. Сканер читает только новые и изменённые файлы.
  • Плейлисты со своей обложкой и перетаскиванием треков; очередь с подписью «откуда играет».
  • Фоновое воспроизведение FLAC, m4a, MP3 и Opus, уведомление, экран блокировки.
  • Прямой вывод на USB-ЦАП бит в бит, свой ресемплер для частот 88,2 и 176,4 кГц.
  • Проверка настоящего lossless и фильтр «Подделки».
  • Раздел «Книги»: полка с прогрессом, порядок глав, скорость на каждую книгу, таймер сна с метками.
  • Единый поиск по RuTracker, Bandcamp, Jamendo и Live Music Archive со встроенным торрент-клиентом.
  • Самообновление по воздуху с проверкой подписи и отчёты разработчику.
  • «Не музыка»: скрыть диктофон, записи звонков и голосовые из фонотеки, поиска и подборок.

Как это устроено

Прямой вывод на USB-ЦАП в обход микшера

Приложение забирает ЦАП через USB Host API и отправляет звук изохронными передачами через usbfs. Изохронная передача — режим USB с гарантированной скоростью потока, как у аудио. Вывод написан на C++ (NDK) с кольцевым буфером и подключён к Media3 как собственный AudioSink. Частота подстраивается под трек, громкость меняется кнопками телефона и применяется на стороне ЦАПа. Кнопки «Отдать ЦАП системе» и «Забрать ЦАП» переключают режим, а после минуты паузы ЦАП отдаётся системе автоматически.

Свой ресемплер с искажениями ниже −130 дБ

Ресемплер пересчитывает частоту дискретизации. Если у ЦАПа нет частот 88,2 и 176,4 кГц, работает собственный многофазный ресемплер: искажения ниже −130 дБ. Пока ЦАП у плеера, Android его не видит, и уведомления и звонки звучат из динамика телефона.

Проверка подделок Hi-Res по спектру

Плеер разбирает кадры FLAC, декодирует их во float и строит спектр (быстрое преобразование Фурье, БПФ, на Kotlin). Перекодировка из MP3 видна по срезу частот, растянутый CD — по обрыву спектра у 19–24,5 кГц, а у 24-битных файлов проверяются пустые младшие биты. Вердикт показывается значком у каждого трека, а нажатие открывает разбор: числа трека и объяснение, почему спектр до 22 кГц у 44,1 и 48 кГц — предел формата, а не подделка.

Аудиокниги: место, скорость и метки сна

Книги определяются по жанру и папкам «Аудиокниги», «Книги», «Audiobooks». Главы идут по номерам в тегах или по числам в именах файлов («2» раньше «10»); если порядок угадан неверно, главу можно перетащить. Скорость 0,8–2,5× сохраняется на каждую книгу и работает в том числе в прямом выводе на ЦАП. Таймер сна ставит закладки «Поставлен таймер сна» и «Уснул», хранятся последние пять ночей. После долгой паузы книга отматывается назад: минута — 5 секунд, полчаса — 15, сутки — 30.

Стабильность на Huawei при погасшем экране

Заикание звука при выключенном экране нашли по отчётам с телефона: оболочка EMUI замораживала плеер на секунды. Очередь звука в ЦАП вернули к 0,4 с, а в настройках добавили кнопки «Запуск приложений EMUI» и «Экономия батареи» с пояснением. Если плеер всё же усыпили посреди вывода, раз в сутки приходит уведомление «Музыка может прерываться».

Самообновление и отчёты

Список выпусков подписан ключом ECDSA P-256; приложение скачивает выпуск и ставит его тихо, когда музыка не играет. Журнал до 5 МБ, звуковой профиль телефона, наушники и статистика прослушивания уходят на приёмник разработчика; подробнее — в кейсе про приёмник отчётов.

Результат

  • Трек уходит на ЦАП бит в бит: частота подстраивается под трек, громкость регулирует сам ЦАП (по README проверено по отчётам с телефона заказчика).
  • Собственный ресемплер с искажениями ниже −130 дБ для частот 88,2 и 176,4 кГц.
  • Поддельный Hi-Res не попадает в раздел «Hi-Res».
  • Один поиск по четырём источникам музыки со встроенной загрузкой.
  • Раздел «Книги» с отдельной скоростью и местом для каждой книги.

Технологии: что и зачем

  • Kotlin, Jetpack Compose, Material 3 — интерфейс приложения.
  • Media3 (ExoPlayer, MediaSessionService) — воспроизведение и фоновая служба.
  • C++ (NDK) — поток на ЦАП и ресемплер, где важны время и точность.
  • Android USB Host API — доступ к ЦАПу и запросы аудиокласса UAC1/UAC2.
  • libtorrent4j — встроенный торрент-клиент для загрузки в фонотеку.
  • SQLite — индекс фонотеки; WorkManager, PackageInstaller — самообновление.

Статус

Версия 0.10.0 от 28 сентября 2026 года, разработка идёт, собственный продукт. Приложение обновляется по воздуху. Дальше в планах ToshaMusic как ещё один источник Hi-Res и сборка под Windows с WASAPI Exclusive.

Ограничения по README: прямой вывод проверен в эмуляторе только на отсутствие ЦАПа, работа с настоящим донглом видна по отчётам с телефона; вход на RuTracker проходит сам пользователь во встроенном браузере из-за проверки Cloudflare; Bandcamp проверен поиском на эмуляторе, покупка и скачивание — только на телефоне заказчика; Jamendo без ключа не проверялся. Проверка качества эвристическая.

Вопросы по проекту

Что такое bit-perfect и почему Android его портит?
Bit-perfect значит, что трек доходит до ЦАПа (цифро-аналогового преобразователя) без изменений, с исходными частотой и разрядностью. Системный микшер Android ресемплирует любой звук до своей частоты вывода, обычно 48 кГц, поэтому 24-битный FLAC 96 кГц приходит к ЦАПу уже изменённым. OshaPlay говорит с ЦАПом напрямую по USB Audio Class, минуя микшер.
Как получить bit-perfect на Android 12, если штатного режима нет?
Штатный bit-perfect для USB появился только в Android 14. На Android 12 приложение само захватывает ЦАП через USB Host API и отправляет звук изохронными передачами через usbfs. Частота подстраивается под трек, громкость меняется кнопками телефона и применяется на стороне ЦАПа.
Какие ЦАПы и телефоны подходят?
Приложение написано для Android 12 и новее (minSdk 31) и делалось под комплект: Huawei P60 Pro, донгл на Realtek ALC5686, наушники Simgot EM6L. Прямой вывод умеет только UAC2 с адаптивной или синхронной передачей; асинхронные ЦАПы с обратной связью и UAC1 пока играют через систему.
Как проверить, что lossless настоящий, а не перекодированный MP3?
Плеер разбирает спектр файла: ловит перекодировку из MP3 и растянутый CD под видом Hi-Res, а у 24-битных файлов проверяет пустые младшие биты. Подделки попадают в фильтр «Подделки» и не показываются в разделе «Hi-Res». Проверка эвристическая, поэтому вердикт можно открыть и прочитать разбор.
Можно ли слушать аудиокниги с запоминанием места и скоростью?
Да, в разделе «Книги» с версии 0.10.0. Книги находятся сами по жанру и папкам, место запоминается для каждой книги, скорость 0,8–2,5× со своим значением на книгу и сохранением тона, есть таймер сна с метками. Музыка при этом всегда играет на 1× бит в бит.
Можно ли заказать плеер или USB-вывод под другое устройство?
Да, такие работы берутся под заказ. В коде слои разделены по каталогам: разбор дескрипторов USB, прямой вывод на C++, ресемплер, проверка качества, самообновление. Их можно адаптировать под другой ЦАП или сценарий.

Нужно похожее?

Расскажите о задаче — покажем, как решали такое, и прикинем объём работ.