74 lines
5.4 KiB
Markdown
74 lines
5.4 KiB
Markdown
# TASK: debug-дампы аудио-пути очки→телефон (PCM-записи для диагностики STT-качества)
|
||
|
||
## Подозреваемые (по фактам разведки)
|
||
(a) убогий микрофон очков (AudioRecord MIC 16 кГц s16 mono, buf 6400, чтение 3200 Б = 100 мс);
|
||
(b) транспорт: PCM идёт как **base64 в JSON-строке** (`SttAudio.data` → kotlinx-serialization
|
||
default ByteArray-сериализатор = base64) по NEWLINE-каналу SPP/WiFi (readLines/readLine);
|
||
100-мс-чанк 3200 Б s16 → ~4300 Б base64+JSON. Потери/задержки/перепутанный порядок кусков
|
||
по шкатулке — верный кандидат «убожества»;
|
||
(c) VAD/Whisper на телефоне (настройки: VAD 0.5/0.25с/0.25с/20с, Whisper-small int8, CPU, 4
|
||
потока — на старом HONOR CPU-распознавание медленное и может «не успевать»).
|
||
|
||
## Цель
|
||
Запись сырого PCM в двух точках (очки: ДО отправки; телефон: ПОСЛЕ приёма и декода) +
|
||
сравнение: объёмы/RMS/порядок. Дальше (утром, агент+user): снять с устройств, снять
|
||
офлайн-ASR-картину, решить (a)/(b)/(c).
|
||
|
||
## Оковы
|
||
- Пути только относительные от корня репо /root/WORK/view-mate. Никаких /tmp.
|
||
- НЕ ТРОГАТЬ: HostToGlasses.kt, GlassesServer.kt, HostConnection.kt, MainActivity.kt (оба модуля).
|
||
- Правим: SttMicStream.kt (очки), SttStreamer.kt (телефон), PhoneApp.kt (телефон, НЕ охраняется), новый WavWriter.kt (очки).
|
||
|
||
## Изменения
|
||
|
||
### 1. app-glasses/src/main/kotlin/pw/binom/viewmate/glasses/stt/WavWriter.kt (новый)
|
||
Минимальный WAV-райтер (PCM s16le, 16000 Hz, mono):
|
||
- `class WavWriter(path: File, sampleRate: Int = 16000, channels: Int = 1)`
|
||
- `fun write(pcm: ByteArray)` — appends (header пишется один раз при создании файла).
|
||
- `close()`. Стандартный RIFF/PCM header 44 байта.
|
||
|
||
### 2. app-glasses: SttMicStream.kt
|
||
- В `start(filesDir, shouldRun)`: перед запуском потока проверить маркер
|
||
`File(filesDir, "stt_dump.marker")`. Если есть:
|
||
- создать `File(filesDir, "stt_dump_" + java.time формат HHmmss + ".wav")` через WavWriter;
|
||
- ВСЕ чанки, уходящие в onChunk (только ветка ЖИВОГО микрофона, эмуляторную не трогаем),
|
||
дописывать в WavWriter;
|
||
- log("stt", "dump микрофона: <path>").
|
||
- При `stop()` — закрыть WavWriter (runCatching).
|
||
- Все операции с dump — runCatching, сбои — только log, поток звука не прерывать.
|
||
|
||
### 3. app-phone: SttStreamer.kt
|
||
- Конструктор: добавить опциональный параметр `dumpPcmTo: File? = null`
|
||
(хвост конструктора, чтобы не сломать существующие вызовы).
|
||
- В `accept(pcm)`: если `dumpPcmTo != null` — дописать `pcm` в файл
|
||
(DataOutputStream/FileOutputStream append, raw s16le, header НЕ нужен — файл помечен как
|
||
16кГц s16 mono в логе). Все runCatching.
|
||
- В `close()`: закрыть поток дампа.
|
||
- Лог: "stt" логгер — "PCM-дампа: <path>".
|
||
|
||
### 4. app-phone: PhoneApp.kt (ensureStt(), ~строка 368)
|
||
- При создании SttStreamer передать `dumpPcmTo`:
|
||
```kotlin
|
||
val dumpMarker = File(filesDir, "stt_dump.marker")
|
||
val dumpPcm = if (dumpMarker.exists()) File(filesDir, "stt_phone_dump.raw") else null
|
||
```
|
||
(посмотреть по факту, какой context/filesDir в области видимости).
|
||
- Лог: "stt" — "PCM-дампа (телефон): <path или off>".
|
||
|
||
### 5. Прогон
|
||
- `./gradlew :app-glasses:testDebugUnitTest :app-phone:testDebugUnitTest :lib-core:jvmTest` — зелёные.
|
||
- `./gradlew :app-glasses:assembleDebug :app-phone:assembleDebug` — BUILD SUCCESSFUL.
|
||
|
||
### 6. Коммит
|
||
- `git add -A && git commit -m "stt: debug-дампы аудио-пути (очки: сырой микрофон в WAV; телефон: принятые PCM) — старт по stt_dump.marker"`
|
||
- PUSH не делать.
|
||
|
||
## Для утренней диагностики (агент + user)
|
||
- На очках: `touch` маркера (adb shell run-as или в самом каталоге /sdcard/Android/data/.../files/stt_dump.marker — агент уточнит path).
|
||
- На телефоне: аналогично.
|
||
- Пользователь произносит фразы в очки → очки делают dump; после сессии — adb pull обоих файлов.
|
||
- Сравнение: (1) объём/продолжительность (должны совпадать с точностью на куски),
|
||
(2) RMS/клиппинг в очках-файле (диагноз (a)), (3) побайтовое/почанковое сравнение
|
||
очков↔телефон (диагноз (b)), (4) запустить обе записи через серверный ASR (88.125:8006) —
|
||
«убожество» воспроизводимо в оффлайне?
|