Simple Record: запись звонков на Android без root и без облака
Написал своё приложение для записи звонков: пишет обе стороны разговора без root, честно говорит, когда запись не идёт, и расшифровывает разговоры прямо на телефоне. Ничего не уходит в облако. Открытый код, Apache-2.0.
Что было
Мне нужна запись звонков на своём телефоне. Телефон OnePlus 15R, звонилка по умолчанию Google Phone, и в российском регионе встроенной записи в ней нет. Звонилку OnePlus с записью поставить нельзя: её не пускает проверка целостности Google. Готовые приложения для записи звонков на современном Android либо пишут только свой голос через микрофон, либо требуют root, либо отправляют разговоры в облако для расшифровки.
Идею подсмотрел у открытого ShizuCallRecorder: звук звонка можно забрать через scrcpy-server с источником voice-call, если запустить его от имени системного пользователя shell. Механизм взял, код и архитектуру написал свои, с главным требованием: приложение не должно врать, что идёт запись, когда её нет.
Как устроено
Свой служебный процесс вместо root. Звук звонка Android отдаёт только системе и пользователю shell. Обычно до shell добираются через Shizuku, но на OxygenOS он не работает: его приложение не получает связь со своим же сервером. Поэтому в приложение встроен свой маленький ADB-клиент. Он один раз сопрягается с беспроводной отладкой телефона и запускает служебный процесс. Процесс живёт сам по себе: переживает перезапуски приложения, сам находит его, когда система поднимет его снова, и включает обратно беспроводную отладку в знакомых сетях, если Android её выключил при смене Wi-Fi.
Запись - машина состояний, а не флаг. Сессия записи проходит через явные состояния: ожидание, старт, запись, остановка, ошибка. Если захват оборвался посреди звонка, это переход в состояние, а не строчка в логе: запись продолжается в новую часть файла, и в списке части одного звонка показываются одной строкой и играют подряд. Если приложение упало, при следующем запуске недописанный файл восстанавливается и помечается как прерванный. Пустых файлов не остаётся. Уведомление показывает не "приложение работает", а реальное состояние записи.
Расшифровка на телефоне. Распознавание речи идёт прямо на телефоне, без сети: модель GigaAM v3 от Сбера с пунктуацией через движок sherpa-onnx. Перед выбором я прогнал восемь вариантов на своих реальных звонках и сверил результат с оригинальной реализацией GigaAM. Звук режется на куски по 15-22 секунды по паузам в речи, как это делает сам GigaAM, и под каждое слово сохраняется время. Касание слова включает запись с этого места. Минута разговора распознаётся примерно за 4 секунды на Snapdragon 8 Elite, звонок на 46 минут - за три минуты. Работа идёт в отдельном процессе: если распознавание упадёт или ему не хватит памяти, идущая запись звонка не пострадает. Новые звонки расшифровываются на зарядке, а если система прервёт работу, она продолжится с того же места.
Поиск по тому, что сказали. Тексты лежат в SQLite с полнотекстовым поиском, так что звонок можно найти по слову из разговора, а не только по имени и номеру. Плюс фильтры: период, месяцы с числом звонков, входящие и исходящие, с расшифровкой, прерванные.
Свой Мак как второе место для записей. Если дома стоит Мак с моим же приложением Simple Talk, телефон находит его в сети, сопрягается по шестизначному коду один раз и дальше сам отправляет записи после каждого звонка и при возвращении домой. Только по Wi-Fi и только на адреса домашней сети. Мак расшифровывает разговоры более крупными моделями, разделяет говорящих и присылает текст обратно на телефон.
Ничего не уходит в облако. Записи, тексты и номера не покидают телефон и домашнюю сеть. Единственный выход в интернет - скачивание файла модели распознавания (170 МБ) по кнопке, с проверкой каждого файла по контрольной сумме.
Что вышло
Пользуюсь каждый день. Приложение пишет обе стороны разговора чисто, начинает запись через полсекунды после начала звонка, переживает обрывы, падения и перезапуски, а запись звонка после окончания уже через секунду лежит на Маке.
Код открыт под Apache-2.0: github.com/TimurTurdyev/simple-record.
Вывод
Самым трудным оказалась не запись звука, а честность: на каждом шаге легко сделать вид, что всё работает. Поэтому статус записи показывает только то, что реально происходит, а каждый способ сломаться (обрыв, падение, перезапуск системой, звонок без Wi-Fi) я проверял на живых звонках, а не в тестах.
Скриншоты
Снято на эмуляторе на демо-данных: разговор озвучен синтезатором речи, номера вымышленные.





Скачать
- Исходный код: github.com/TimurTurdyev/simple-record
- APK появится здесь с первым релизом.
Что нужно:
- Android 11 или новее. Проверено на OnePlus 15R (OxygenOS 16, Android 16); на других телефонах доступ к звуку звонка зависит от прошивки.
- Один раз включить беспроводную отладку в настройках разработчика и ввести код сопряжения в уведомлении приложения.
- После перезагрузки телефона - Wi-Fi, чтобы приложение снова запустило свой служебный процесс. Дальше запись работает и без Wi-Fi.
- Для расшифровки - 230 МБ свободного места под модель.
Записывать разговоры можно не везде и не всегда без согласия собеседника: это зависит от закона вашей страны.