Record desktop voice checks and reproduce Android mute signal after AEC
This commit is contained in:
1 parent
5fee00c451
commit
03be46c339
3 files changed
+151
-2
No files matched your search
+137
-1
@@ -8,7 +8,7 @@ call_audio уменьшали pending новой привязки и обход
|
||||
эпоха владельца, постоянные регрессии13/13 и голосовой профиль4/4 PASS.
|
||||
Ложный отказ test_radio_mesh (dupC=0) также исправлен: место дедупликации
|
||||
зависит от порядка прихода. После rebase сборки и voice17/17 PASS,
|
||||
check202/202 PASS,proxy9/9,burst1/1,load8/8,176с. Актуальный результат — раздел10;
|
||||
check202/202 PASS,proxy9/9,burst1/1,load8/8,176с. Результат этого этапа — раздел10;
|
||||
история/план — разделы6–7, внедрение TX — раздел8, диагностика mesh — раздел9.
|
||||
Полная проверка аудио, видео и платформенных разделов не завершена.
|
||||
При продолжении подтверждён и по запросу пользователя исправлен дефект
|
||||
@@ -17,6 +17,11 @@ check202/202 PASS,proxy9/9,burst1/1,load8/8,176с. Актуальный резу
|
||||
Новая постоянная регрессия11/11 и штатный headless e2e1/1 PASS;
|
||||
native build и check203/203 PASS,proxy9/9,burst1/1,load8/8,188с.
|
||||
Диагностика/план — раздел11, внедрение/актуальная проверка — раздел12.
|
||||
По запросу «пуш и продолжай» опубликованы6 коммитов до54a7522d. При продолжении
|
||||
desktop-профиль25/25 PASS; подтверждён дефект Android mute до AEC:
|
||||
занулённый Kotlin-вход превращается в ненулевой PCM перед Opus.
|
||||
Компонентные контроли PASS, текущий mute ожидаемо FAIL,allocations0->0.
|
||||
Реализация не менялась, аудит остановлен по AGENTS.md:10; план/доказательства — раздел13.
|
||||
База проверки: f79b9261, чистое рабочее дерево после предыдущего push stream.
|
||||
|
||||
1. Подтверждённый дефект: call_start не проверяет обычную занятость
|
||||
@@ -793,3 +798,134 @@ radio_headless остаётся на диагностику, runtime-дефек
|
||||
Аудит остальных call-контрактов/платформ остаётся частичным:call0[V]/11[~]/10[ ],
|
||||
call_headless.h[~], архитектура[~],видео[ ]. Новые sanitizer/аппаратные GUI,
|
||||
Android, Windows и FreeBSD проверки этим шагом не выполнялись. Push не выполнялся.
|
||||
|
||||
13. Desktop I/O и Android mute до AEC — 26.10.2026
|
||||
|
||||
Публикация завершённого исправления
|
||||
|
||||
По запросу «пуш и продолжай» git push origin master PASS:
|
||||
03b05094..54a7522d, все6 локальных коммитов отправлены. git ls-remote подтвердил
|
||||
refs/heads/master=54a7522dd93934bd3f082990550e971339bdb4f7;
|
||||
на момент push HEAD==origin/master, дерево чистое. Прежний полный check203/203
|
||||
и headless11/11 из раздела12 относятся к уже опубликованной реализации.
|
||||
|
||||
Продолжение desktop-аудита
|
||||
|
||||
Полностью прочитаны CallAudioEngine.cpp/.h167+76 строк, VoiceAudioIo.cpp/.h525+76,
|
||||
AudioDevice.cpp/.h225+68, AudioEventQueue, AudioCaptureLease, VoiceCaptureClock,
|
||||
VoicePlaybackBuffer; относящиеся к start/end/stop handlers MainWindow и lifecycle
|
||||
utun_node, attach/detach/render/recovery SoundManager. Остальные SoundManager
|
||||
функции и все потребители общего I/O этим этапом целиком не проверены.
|
||||
Повторно сверены call_audio feed/pull, call_jitter/reset/window, CallTimeline
|
||||
и tones; их прежние частичные отметки не закрываются преждевременно.
|
||||
|
||||
Capture callback копирует PCM в ограниченную MPSC-очередь, capture worker
|
||||
выполняет AEC и сохраняет границы mute. Независимый RX worker получает PCM;
|
||||
SoundManager смешивает все источники того же выхода и возвращает итоговое
|
||||
stereo как reference. Stop: закрыть/отменить capture, join capture worker,
|
||||
detach output, join RX, release core. Async uninit сохраняет callback/backend
|
||||
и microphone lease до завершения закрытия; отсутствие PCM не останавливает RX.
|
||||
start подтверждает подготовленную сессию, recovery устройств может продолжаться.
|
||||
|
||||
Штатный CMake configure/build PASS, профиль25/25 PASS,20,89с:
|
||||
- прежние call_jitter/delay/timeline/voice_tx и13 call_audio_tx —17 тестов;
|
||||
- audio_event_queue,voice_audio_io,audio_timing,soundtouch_clock,
|
||||
audio_recovery,microphone_watchdog,audio_buffer_tuning,audio_diagnostics —8.
|
||||
Очередь проверена на80000 упорядоченных сообщениях; VoiceAudioIo проверяет
|
||||
настоящие workers/stereo AEC с заменой сервисной PCM-границы наблюдателями.
|
||||
Recovery/watchdog используют настоящий miniaudio null backend, Qt timers,
|
||||
core voice и введённые отказы/задержки, без сетевого звонка/микрофона.
|
||||
ERROR/WARN новых I/O-тестов соответствуют намеренным init/start/context/
|
||||
PCM/watchdog faults, старвированию выхода при recovery и недостающему reference.
|
||||
В recovery есть WARN о паузе uasync: fixture специально не выполняет poll
|
||||
во время работы виртуальных устройств. Все25 завершились Passed.
|
||||
Логи /tmp/call-desktop-audit-{configure,build,tests,last-test}.log;
|
||||
вывод новых I/O-тестов прочитан полностью. Предупреждение компилятора из
|
||||
существующего miniaudio.h не относится к новым исходникам этого аудита.
|
||||
Это не проверка реального PulseAudio/ALSA, Windows/FreeBSD или акустики устройства.
|
||||
|
||||
Подтверждённый Android-дефект
|
||||
|
||||
В CallAudioEngine.kt прочитаны start/stop/runWorker/reportFailure и полный
|
||||
captureLoop (строки1–454), а также syncAecForRoute/measureAecDelay и хвост
|
||||
796–856. Kotlin playback/recovery середины файла и остальной Android lifecycle
|
||||
целиком ещё не проверены. Сверена полная цепочка feed в NativeLib.kt,
|
||||
nativeCallAudioFeed и utun_bridge_call_audio_feed, core call_audio_feed_impl.
|
||||
|
||||
captureLoop (строка414) делает out=if(muted) silence else buf, затем
|
||||
NativeLib.callAudioFeed(callId,out,ptsUs). В NativeLib/JNI/C bridge флага mute
|
||||
нет: bridge вызывает call_audio_feed_pcm. Core получает нулевой raw-вход,
|
||||
после чего выполняет AEC, затем AGC и Opus. AEC с прогретым фильтром/ненулевым
|
||||
reference может создать ненулевой результат даже из этого нулевого входа.
|
||||
syncAecForRoute включает core AEC на SPEAKER; разрешённый delay1..20 кадров.
|
||||
Таким образом раннее зануление не гарантирует нулевого PCM перед Opus.
|
||||
Кроме того AEC/AGC лишаются настоящего микрофонного входа во время mute;
|
||||
деградация на реальном устройстве отдельно не измерялась.
|
||||
|
||||
Core уже имеет call_audio_feed_pcm_muted: настоящий PCM проходит AEC/AGC,
|
||||
muted применяется непосредственно перед encode. Desktop prepared path
|
||||
применяет свою маску после AGC и этого дефекта не имеет.
|
||||
|
||||
Компонентная диагностика без замены production
|
||||
|
||||
/tmp/call-android-mute-audit.cpp и ...-build.py используют текущие CMake
|
||||
libutun_voice/libutun/libuasync/Opus. Настоящий android_jni_bridge.c собран
|
||||
отдельным host-объектом с function/data sections и gc-sections, как штатный
|
||||
test_android_replies. __ANDROID__ выключен: реально выполняется C bridge,
|
||||
JNI-маршалинг/Kotlin/AudioRecord/AudioTrack на устройстве не запускаются.
|
||||
Проектные исходники, архивы и объекты не заменяются.
|
||||
|
||||
Один настоящий uasync/минимальный instance, call_audio_init/start, реальные
|
||||
remote Opus encode → on_media → jitter/CallDelay → pull PCM → core AEC reference.
|
||||
Синтетический микрофон = половина фактически полученного render; прогрев300
|
||||
кадров, затем20 наблюдаемых. Через публичный API выбран AEC delay1; AGC
|
||||
отключён настройкой для изоляции AEC. Начальный FIFO заполнен обычными
|
||||
on_media, приватные поля/фильтр не подменяются. Синтетический get_time_tb
|
||||
продвигается на20мс/кадр; настоящий uasync исполняет TX после каждого feed.
|
||||
Сетевая граница call_send_media заменена счётчиком; соединение двух ядер
|
||||
не создаётся. Wrapper AEC/encode только читает PCM до/после настоящих функций
|
||||
и сохраняет их результат. Звук не записывается, используются искусственные данные.
|
||||
|
||||
Результаты (в20 кадрах всего19200 отсчётов):
|
||||
- unmuted: bridge получает настоящий микрофон; AEC in19193/out18445 ненулевых,
|
||||
Opus input18445,peak46,RMS10,500; control PASS,exit0;
|
||||
- no_aec: текущий ранний mute, AEC отключён; Opus input0,peak0,RMS0;
|
||||
control PASS,exit0;
|
||||
- legacy: текущий ранний mute, AEC включён; AEC in0/out19191,
|
||||
Opus input19191,peak7515,RMS1602,348. Проверка нулевого входа Opus ожидаемо
|
||||
FAIL,exit1; наблюдение завершилось с полноценным cleanup;
|
||||
- final_mute: существующий core API получает настоящий микрофон+muted1;
|
||||
AEC in19193/out18445, но Opus input0,peak0,RMS0; control PASS,exit0.
|
||||
Во всех4 запусках warm render RMS3878,247; все320 TX callbacks исполнены,
|
||||
pending0 при destroy, u allocations0->0. Сырые входы AEC в unmuted/final_mute
|
||||
совпадают; ошибочный legacy имеет именно нулевой вход и ненулевой выход.
|
||||
Обычное последействие Opus-декодера здесь не измеряется: дефект доказан
|
||||
до lossy encode. Прослушивание/утечка речи микрофона на устройстве не заявляются.
|
||||
Логи /tmp/call-android-mute-audit-{build,results,unmuted,no_aec,legacy,final_mute}.log
|
||||
прочитаны полностью. Build PASS; предупреждение snprintf относится к
|
||||
существующей неиспользуемой здесь функции формирования списка каналов bridge.
|
||||
|
||||
План исправления для согласования
|
||||
|
||||
1) Убрать silence/out подмену в captureLoop: передавать настоящий buf и один
|
||||
snapshot muted на готовый20мс кадр, сохранив capture PTS и порядок PCM.
|
||||
2) Добавить флаг в NativeLib.callAudioFeed/nativeCallAudioFeed, JNI и объявление/
|
||||
реализацию C bridge. Bridge вызывает существующий call_audio_feed_pcm_muted.
|
||||
Сверены все production callers: один Kotlin captureLoop и один JNI вызов.
|
||||
Не нужны новый глобальный mute, новый режим DSP или изменение wire.
|
||||
3) Закрепить настоящий bridge→AEC/AGC→Opus постоянной регрессией: unmuted,
|
||||
текущий ранний mute как негативный контроль, итоговый mute, AEC on/off,
|
||||
AGC on/off, следующий unmute и cleanup. Наблюдать точный PCM перед encode;
|
||||
raw-вход фильтра должен оставаться исходным, muted-вход Opus строго нулевым.
|
||||
4) Собрать native/voice-профиль и Android assembleDebug для проверки общей
|
||||
JNI/Kotlin сигнатуры; затем check. Реальное переключение mute на громкой
|
||||
связи и AEC после unmute — отдельный аппаратный контроль.
|
||||
|
||||
По AGENTS.md:10 новый логический дефект требует остановки перед исправлением.
|
||||
Изменены только комментарии call_audio.h и документация/внешний чек-лист.
|
||||
Уточнены актуальные event IDs, состав C/C++ сборки, отдельный headless DSP,
|
||||
desktop stop-порядок и reset FIFO; runtime/API/протокол/штатные тесты не менялись.
|
||||
Call0[V]/11[~]/10[ ],chat_call_arch.md[~],видео[ ] сохранены;8 затронутых
|
||||
desktop headers отмечены[~]. Общий голосовой/платформенный аудит ещё частичный.
|
||||
Новый fullcheck/sanitizers/Gradle/аппаратный Android/desktop/Windows/FreeBSD
|
||||
этим продолжением не выполнялись. Новый дефект не исправлен; задача открыта.
|
||||
@@ -483,7 +483,8 @@ AEC/AGC обрабатывают микрофон, перед Opus примен
|
||||
Capture callback только копирует PCM; capture worker выполняет stereo-reference AEC и передаёт
|
||||
prepared PCM с маской mute в core AGC/Opus. RX worker независимо вызывает `call_audio_pull_pcm`.
|
||||
`SoundManager` смешивает голос с остальными источниками на общем выходе и возвращает тот же итоговый
|
||||
stereo PCM как AEC-reference. Stop закрывает capture, останавливает workers, отсоединяет выход и освобождает core.
|
||||
stereo PCM как AEC-reference. Stop закрывает capture, ждёт capture worker, отсоединяет выход,
|
||||
ждёт RX worker и освобождает core.
|
||||
При неисправном capture async close сохраняет объекты и lease до завершения uninit; RX остаётся активным.
|
||||
- **Android:** JNI `nativeCall*` + Kotlin `AudioRecord`/`AudioTrack`.
|
||||
**Переключение источника:** `AudioManager` (API31+ `setCommunicationDevice` +
|
||||
|
||||
@@ -4,6 +4,18 @@
|
||||
|
||||
## Текущие задачи
|
||||
|
||||
[ ] **Android call mute: передавать настоящий PCM и флаг mute через JNI до core** — подтверждено 26.10.2026.
|
||||
CallAudioEngine.captureLoop заменяет микрофон тишиной до nativeCallAudioFeed; bridge вызывает feed_pcm.
|
||||
Включённый AEC после этого снова создаёт ненулевой сигнал перед Opus. Стенд с настоящими bridge/Opus/AEC,
|
||||
прогревом300 кадров и20 muted кадрами:19191/19200 ненулевых отсчётов, peak7515,RMS1602,348; ожидаемый FAIL.
|
||||
AEC отключён:0; существующий call_audio_feed_pcm_muted с настоящим микрофоном:0; unmuted-контроль PASS.
|
||||
Во всех4 запусках320 TX callbacks, allocations0->0. AGC отключён для изоляции причины; Android runtime не запускался.
|
||||
План: убрать раннее зануление Kotlin, передавать snapshot mute через NativeLib/JNI/C bridge в feed_pcm_muted.
|
||||
Не менять wire, общий DSP или desktop prepared path; добавить постоянную регрессию raw/final mute с AEC/AGC.
|
||||
Проверить сигнатуры assembleDebug и native/voice-профиль; аппаратный контроль громкой связи отдельно.
|
||||
До согласования реализация не меняется по AGENTS.md:10. Подробности: [call_audit_findings.txt](call_audit_findings.txt),раздел13;
|
||||
/tmp/call-android-mute-audit-{build,results,unmuted,no_aec,legacy,final_mute}.log.
|
||||
|
||||
[+] **call_headless: целостность PCM-кадра при переполнении TCP-очереди** — исправлено 26.10.2026.
|
||||
Header/PCM собираются до отправки; очередь принимает целый кадр или отбрасывает его целиком.
|
||||
Частичная запись сохраняет хвост перед следующими кадрами. Потери учитываются отдельно для клиента/сервиса;
|
||||
|
||||
Reference in new issue
Block a user