Старый README сохранён как README.upstream.md.
SMKDMR XLX Client — Android-клиент подключения к XLX-рефлектору
Заготовка мобильного приложения на Kotlin/Jetpack Compose для подключения смартфона к XLX-рефлектору (мультипротокольный рефлектор XLX, используемый в DMR-сетях) без хотспота и радиостанции. Сейчас приложение содержит один экран: ввод адреса и порта рефлектора, выбор комнаты/модуля, позывного и DMR ID, отправку тестовой UDP-датаграммы и режим PTT, который передаёт сырой PCM-звук с микрофона по UDP.
Полноценным DMR-клиентом приложение не является и в текущем виде стать не может: как прямо сказано в тексте на главном экране, для настоящего DMR нужны вокодер AMBE+2 и кадры протокола MMDVM Homebrew, ни того ни другого в коде нет. Проект — испытательный стенд для будущего транспортного слоя.
Стек
- Kotlin, Jetpack Compose (Material 3, Compose BOM 2026.01.00),
activity-compose. - Android Gradle Plugin 9.0.1, Kotlin Compose compiler plugin 2.2.21, Gradle Kotlin DSL.
compileSdk/targetSdk36,minSdk26, applicationIdru.smkdmr.xlxclient.- Android SDK напрямую:
AudioRecord(PCM 16 бит, 8 кГц, моно),DatagramSocket/DatagramPacket,kotlinx.coroutines. - Внешнее «железо»/сеть: XLX-рефлектор по UDP (в тестовом профиле — порт 62030, модуль F).
Структура
| Путь | Назначение |
|---|---|
settings.gradle.kts |
Имя проекта SMKDMR, модуль :app, репозитории google/mavenCentral. |
build.gradle.kts |
Корневой файл: объявление плагинов AGP и Compose compiler. |
app/build.gradle.kts |
Конфигурация модуля: SDK, версия 0.1.0, Compose, зависимости. |
app/src/main/AndroidManifest.xml |
Разрешения INTERNET и RECORD_AUDIO, единственная activity-лаунчер. |
app/src/main/java/ru/smkdmr/xlxclient/MainActivity.kt |
Весь код приложения (469 строк): экран XlxConnectionScreen, выпадающий список комнат RoomPicker, блок статуса, функция sendUdpProbe, класс UdpVoiceTestClient с фоновым потоком записи и отправки звука. |
app/src/main/res/values/styles.xml |
Тема Theme.SMKDMR. |
app/proguard-rules.pro |
Пустая заготовка. |
README.upstream.md |
Прежний README автора. |
Как запустить
Gradle wrapper в репозитории отсутствует (gradlew, gradle/wrapper/ не закоммичены), поэтому сборка из командной строки «как есть» невозможна.
Способ из авторского README:
- Открыть каталог проекта в Android Studio (версия с поддержкой AGP 9.0.1).
- Дать среде синхронизировать Gradle и создать wrapper.
- Собрать и запустить модуль
appна устройстве или эмуляторе с Android 8.0+.
После установки wrapper'а сборка из консоли: ./gradlew :app:assembleDebug.
На экране: заполнить IP/домен, порт, комнату, позывной и DMR ID, кнопкой «Проверить UDP подключение» отправить пробную датаграмму, удержанием кнопки PTT — начать передачу PCM-потока. При первом нажатии PTT запрашивается разрешение на микрофон.
Конфигурация
Файлов настроек, переменных окружения и сохранения состояния нет. Параметры вводятся на экране и живут только в памяти процесса (rememberSaveable). Значения по умолчанию зашиты константами в MainActivity.kt:
| Константа | Назначение | Значение |
|---|---|---|
TEST_HOST |
Адрес рефлектора | 212.3.149.253 (тот же адрес, что у XLX 391 / SMK в репозитории pistar) |
TEST_PORT |
UDP-порт | 62030 (порт DMR master для MMDVM) |
TEST_ROOM |
Комната/модуль | F (по подписи в UI — тестовый модуль) |
TEST_CALLSIGN |
Позывной | PHOENIX |
TEST_DMR_ID |
DMR ID | 1030217 |
AUDIO_SAMPLE_RATE |
Частота дискретизации | 8000 |
AUDIO_PACKET_SIZE |
Размер аудиопакета, байт | 320 |
defaultRooms |
Список модулей в выпадающем списке | A–H |
Формат отправляемых пакетов — самодельный текстовый: SMKDMR-PROBE|CALL=…|ID=…|ROOM=… для пробы и заголовок SMKDMR-PCM|CALL=…|ID=…|ROOM=…|SEQ=…| плюс сырой PCM для PTT. Протоколом XLX/MMDVM это не является, рефлектор такие пакеты отбросит.
Состояние
Прототип одного дня, работа не продолжена. Все 17 коммитов сделаны 2026-05-08, последний коммит — 2026-05-08. Версия приложения 0.1.0.
Из заявленного в авторском README сделаны только экран подключения и валидация ввода; далее добавлен экспериментальный режим PTT с передачей PCM по UDP.
Что не доделано
- Нет транспортного слоя XLX/DMR: не реализованы кадры MMDVM Homebrew (login/RPTL, RPTK, DMRD), нет вокодера AMBE+2, нет приёма входящего звука и воспроизведения. Передаётся несовместимый самодельный формат.
- Нет обратной связи о соединении:
sendUdpProbeсчитает отправку датаграммы успехом, ответ не читается (soTimeoutвыставлен, ноreceiveне вызывается). Экрана состояния соединения и журнала событий, заявленных в авторском README, нет. - Нет модели настроек и сохранения последнего сервера/порта/комнаты между запусками — соответствующие пункты плана автора не выполнены.
- Весь код в одном файле
MainActivity.kt, архитектурного разделения (ViewModel, репозиторий) нет. - Не закоммичен Gradle wrapper, из-за чего сборка вне Android Studio невозможна; нет CI.
- Тестов нет ни одного, при этом в зависимостях объявлен
androidTestImplementation(composeBom). - Нет иконки приложения (ссылки на launcher-иконки удалены отдельным коммитом), нет строковых ресурсов и локализации — тексты зашиты в код по-русски.
- В коде остались личные тестовые данные: реальный IP рефлектора, позывной и DMR ID, подставляемые в поля по умолчанию.
- Маркеров TODO/FIXME в коде нет.