Содержание статьи +
- Кратко
- Почему это важно
- Сначала – что такое эхо в WebRTC-звонке
- Единственный сигнал, который делает подавление возможным
- Где живёт модуль: Audio Processing Module в WebRTC
- AEC3: модуль внутри каждого браузера
- Число, которое вы реально будете использовать: ERLE
- Переключатели в браузере, которыми вы управляете
- Мобильные – отдельная история: работу делает телефон
- Когда тянуться за пределы встроенного модуля
- Куда ИИ-модуль подключается в WebRTC – и почему это неудобно
- Частая ошибка: два модуля воюют
- Варианты бок о бок
- Где здесь Фора Софт
- Ключевые выводы
- Что почитать дальше
Кратко
Эхо в браузерном звонке возникает, когда динамик одного собеседника проигрывает голос другого, микрофон ловит этот звук и отправляет копию обратно, – и в WebRTC уже встроен бесплатный модуль подавления эха, AEC3, который снимает большую часть проблемы. Эта статья – о том, где именно этот модуль физически расположен внутри WebRTC-звонка, почему единственный нужный ему сигнал – это звук дальнего конца до любого подмешивания, и как один неправильный «провод» превращает чистый звук в петлю обратной связи. Мы разберём пять стадий AEC3, единственный переключатель в браузере, который его включает, что меняется на iPhone и Android, где работу делает собственное «железо» телефона, и когда стоит выйти за пределы встроенного подавления ради нейросетевого – от Krisp, NVIDIA или открытой модели. Главный повторяющийся урок: в WebRTC проблемы с эхом – это почти всегда проблемы проводки и тайминга, а не «модель недостаточно хороша».
Почему это важно
Если ваш продукт ведёт живой двусторонний разговор в браузере – видеоконференция, телемедицина, виртуальный класс, голосовой ИИ-агент, – эхо это дефект, который пользователь замечает в первые десять секунд и винит в нём вас. WebRTC, технология, позволяющая браузерам напрямую обмениваться аудио и видео, уже включает в себя качественный модуль подавления эха бесплатно, поэтому большинству команд не нужно строить свой. Ловушка в том, что «оно встроенное» скрывает три способа всё испортить: подать модулю неправильный сигнал, поставить второй модуль поверх первого и решить, что браузерное решение одинаково работает на телефоне. Эта статья для продакт-менеджера, основателя или техлида, которому нужно выпускать чистые звонки и объяснять инженерам, почему в звонке эхо. К концу вы поймёте, как WebRTC подавляет эхо, какими переключателями это управляется, почему мобильные устройства – отдельная история, и в какой именно момент платный или открытый ИИ-модуль оправдывает своё место. Теорию того, как устроен любой модуль подавления эха, – адаптивные фильтры, double-talk, ИИ-гибрид – смотрите в статье про основы эхоподавления; эта статья – о том, как заставить его работать внутри реального WebRTC-звонка.
Сначала – что такое эхо в WebRTC-звонке
Прежде чем размещать модуль, закрепим проблему, которую он решает. Звук, который возвращается из динамика в микрофон во время двустороннего разговора, называется акустическим эхом. Когда голос дальнего собеседника проигрывается из динамика вашего ноутбука, он пересекает комнату и попадает в ваш микрофон вместе с вашим собственным голосом. Без очистки эта пойманная копия отправляется обратно, и дальний собеседник слышит самого себя с задержкой в доли секунды – а это делает нормальный разговор почти невозможным.
Два слова будут повторяться по всей статье, так что определим их сразу. Сигнал «дальнего конца» (far-end) – это аудио от другого собеседника, то, что ваше устройство собирается проиграть из динамика. Сигнал «ближнего конца» (near-end) – это то, что записывает ваш собственный микрофон: ваш голос плюс, к сожалению, эхо звука дальнего конца, гуляющее по вашей комнате. Вся задача эхоподавления – убрать эхо дальнего конца из микрофонного сигнала ближнего конца, не тронув ваш настоящий голос.
Есть второй вид эха, который стоит назвать, чтобы потом его отложить. Линейное, или сетевое, эхо возникает внутри телефонной сети на электрическом тракте, и ему посвящён старый телеком-стандарт ITU-T G.168. Этот стандарт явно не охватывает акустическое эхо – то, что от комнаты и динамика, – а именно с ним имеет дело любой браузерный звонок. В WebRTC вас интересует акустическое эхо, и профильный стандарт качества терминала – ITU-T P.340 для устройств громкой связи. Держите эти два вида раздельно: сетевое – чужая проблема; комнатное – ваша.
Единственный сигнал, который делает подавление возможным
Вот самая важная идея во всей теме и та, к которой сводится большинство багов с эхом. Чтобы убрать эхо, модулю нужно дать чистую копию звука дальнего конца – ровно тот звук, который ушёл в динамик, – как отдельный вход. Эта копия называется опорным сигналом (reference), а в коде самого WebRTC – сигналом «render». Думайте о ней как о шумоподавляющих наушниках, которым разрешено слушать ту самую музыку, что они пытаются заглушить: знание оригинала и делает вычитание возможным.
Модуль работает, предсказывая эхо по этому опорному сигналу и вычитая его. Он строит модель того, как ваша комната меняет звук дальнего конца по пути от динамика к микрофону – задержку, отражение от стен, приглушение – и по этой модели угадывает, как будет выглядеть эхо в вашем микрофоне. Затем он вычитает догадку из микрофонного сигнала. То, что осталось, должно быть только вашим голосом.
Поэтому одна ошибка в проводке фатальна. Опорным сигналом должен быть звук дальнего конца до того, как к нему подмешано что-либо ещё – до вашего микрофона, до любой музыки или звукового эффекта, который проигрывает ваше приложение. Если очищенный выход случайно подаётся обратно как опорный сигнал, модуль начинает гоняться за собственным хвостом, и звук рассыпается. На практике, когда в WebRTC-звонке упорное эхо, причина гораздо чаще в сломанном опорном «проводе», чем в слабом алгоритме.
Где живёт модуль: Audio Processing Module в WebRTC
WebRTC не рассматривает подавление эха как отдельную коробку. Оно живёт внутри связки аудиоочистки под названием Audio Processing Module, обычно сокращаемой до APM. APM – это часть WebRTC, которая берёт сырое аудио микрофона и делает его пригодным для звонка, и она выполняет три задачи в фиксированном порядке: сначала подавление эха, затем шумоподавление, затем автоматическую регулировку усиления, которая выравнивает вашу громкость.
Порядок задан намеренно, и причина стоит того, чтобы её понять. Подавление эха идёт первым, потому что ему нужен микрофонный сигнал в максимально исходном виде, чтобы выровнять его относительно опорного. Если бы шумоподавление работало первым и изменяло звук, модель комнаты модуля боролась бы с движущейся мишенью. Поэтому подавление эха читает самый сырой звук, убирает эхо, и только потом шумоподавитель чистит шипение, а регулятор усиления выставляет уровень. Именно поэтому здесь важно правило из нашей статьи про шумоподавление в WebRTC: всё, что вы вставляете в аудиотракт, должно соблюдать этот порядок, иначе вы воюете со встроенной цепочкой.
Поскольку подавление эха – первая и самая хрупкая стадия APM, оно же сильнее всего зависит от того, откуда приходит ваш звук и что ещё его касается. Браузер передаёт APM захват микрофона и опорный сигнал воспроизведения, а APM возвращает чистый звук для кодека Opus – Opus это стандартный голосовой кодек WebRTC. Спецификация IETF, управляющая аудио в WebRTC, RFC 7874, рекомендует, чтобы реализации применяли акустическое эхоподавление именно потому, что браузер не может рассчитывать, что пользователь в наушниках. Эта рекомендация и есть причина, по которой модуль включён по умолчанию, – к чему мы перейдём дальше.
AEC3: модуль внутри каждого браузера
Конкретный модуль подавления эха, который WebRTC поставляет сегодня, называется AEC3 – «3» отмечает его как третий дизайн, заменивший более старый десктопный модуль и отдельный облегчённый мобильный под названием AECM примерно в 2017–2018 годах. Он работает в Chrome, Edge и любом приложении на базе библиотеки WebRTC, а значит, протестирован на огромном числе реальных звонков. Вы почти никогда не пишете AEC3 сами; вы его включаете и правильно кормите.
AEC3 чистит звук в пять стадий, и знание этих стадий превращает расплывчатые жалобы на эхо в конкретные диагнозы. Первая стадия – оценка задержки: прежде чем что-либо вычитать, AEC3 должен вычислить временной разрыв между опорным звуком и эхом, приходящим в микрофон. Этот разрыв складывается из буферов воспроизведения, динамика, воздуха в комнате и микрофона – на телефоне он может составлять от двадцати до двухсот миллисекунд и даже плыть во время звонка. AEC3 непрерывно оценивает его, сопоставляя два сигнала друг с другом, и если он зафиксируется на неверном разрыве, ничего ниже по цепочке работать не сможет.
Вторая стадия – линейный адаптивный фильтр, который делает основную работу. «Адаптивный» значит, что он постоянно подстраивает модель комнаты по мере её изменений; «линейный» значит, что он обрабатывает хорошо предсказуемую часть эха. AEC3 запускает этот фильтр в частотной области маленькими блоками – по шестьдесят четыре аудиосэмпла за раз, около четырёх миллисекунд каждый, – что и быстрее считать, и быстрее реагировать, чем обрабатывать по одному сэмплу. Хороший линейный фильтр убирает примерно от двадцати до сорока децибел эха – величину, измеряемую метрикой, которую мы определим чуть ниже.
Третья стадия – детектор double-talk, защищающий от самого трудного случая во всём эхоподавлении: когда оба говорят одновременно. Когда говорит только дальний собеседник, фильтр может безопасно учиться по микрофонному сигналу. Но когда вы говорите в то же время, ваш голос загрязняет то, чему фильтр пытается научиться, и если он подстроится под ваш голос – он сломается. AEC3 следит за double-talk и замораживает обучение фильтра на это время, затем возобновляет его, когда вы замолкаете. Четвёртая стадия, подавление остаточного эха, – это страховочная сеть, которая приглушает то слабое эхо, которое линейный фильтр не смог смоделировать, например искажения, добавляемые дешёвым динамиком на большой громкости. Пятая стадия, комфортный шум, заполняет крошечные паузы, создаваемые агрессивным подавлением, мягким синтетическим шипением, чтобы звонок не звучал так, будто он постоянно обрывается.
Число, которое вы реально будете использовать: ERLE
Инженеры измеряют модуль подавления эха числом ERLE – Echo Return Loss Enhancement. По-простому, это во сколько раз тише стало эхо после подавления по сравнению с тем, что было до, записанное в децибелах. Децибелы сжимают большие отношения в маленькие числа, так что немного арифметики делает их наглядными.
Допустим, эхо, приходящее в микрофон, несёт некоторую мощность, а после работы AEC3 остаточное эхо несёт одну десятитысячную этой мощности. Отношение – 10 000 к 1. ERLE переводит это отношение в децибелы стандартной формулой:
ERLE = 10 × log10(мощность эха до ÷ мощность эха после)
ERLE = 10 × log10(10 000)
ERLE = 10 × 4 = 40 дБИтак, модуль, убирающий эхо в отношении 10 000 к 1, набирает 40 дБ ERLE – верх диапазона, до которого дотягивает хороший линейный фильтр. Практическая ценность этого числа – в отладке. Если вы логируете ERLE у AEC3 и он держится ниже 10 дБ, фильтр не сходится – обычно потому, что оценка задержки неверна или сломан опорный провод. Здоровый звонок показывает, как ERLE забирается к двадцати-тридцати за секунду-две после старта звонка. Когда кто-то говорит «ИИ просто недостаточно хорош», показание ERLE часто вскрывает, что настоящая проблема – в тайминге, а не в интеллекте.
Переключатели в браузере, которыми вы управляете
Для веб-приложения почти всё это управляется одной строкой. Когда вы запрашиваете у браузера доступ к микрофону через getUserMedia – стандартный веб-вызов, дающий странице микрофон, – вы передаёте ограничение под названием echoCancellation. Спецификация W3C Media Capture and Streams его определяет, и оно по умолчанию выставлено в true в Chrome, Firefox и Safari. Если оставить его включённым, вы получаете AEC3 (или собственный модуль системы) без лишней работы.
// Запрашиваем микрофон с включённым подавлением эха (это значение по умолчанию).
const stream = await navigator.mediaDevices.getUserMedia({
audio: { echoCancellation: true, noiseSuppression: true }
});Есть второй, менее известный переключатель, решающий, какой модуль работает. Chrome добавил ограничение echoCancellationType, которое можно выставить в browser или system. «Browser» означает AEC3, программный модуль внутри Chrome. «System» означает отдать работу собственному модулю операционной системы – например, Voice Capture DSP в Windows, который физически расположен ближе к аудиожелезу. По умолчанию Chrome использует системный или аппаратный модуль, когда хороший существует, и откатывается к AEC3 в остальных случаях, так что вручную это выставляют редко. Это важно в основном при отладке устройства, чей аппаратный модуль ведёт себя плохо, и вы хотите принудительно вернуться к предсказуемому программному пути.
Единственный переключатель, который надо соблюдать, а не выставлять, – это согласованность. Если вы включаете echoCancellation в браузере и одновременно запускаете второй собственный модуль в аудиотракте, вы дважды обрабатываете звук и обычно делаете его хуже – та же ловушка наложения, что губит шумоподавление. Правило: один модуль в цепочке, выбранный осознанно. Мы вернёмся к этому, когда будем обсуждать добавление ИИ-модуля.
Мобильные – отдельная история: работу делает телефон
Факт, который удивляет многие команды: на телефоне модуль подавления эха, который вы реально используете, – обычно не AEC3, а собственное «железо» телефона. И Apple, и Google встраивают акустическое эхоподавление в операционную систему, настроенное под динамик и микрофон именно этого устройства, и настроенный аппаратный модуль обычно обыгрывает универсальный программный, потому что знает железо, которое исправляет.
На iPhone и iPad ключевой элемент – системный аудиокомпонент, который Apple называет Voice-Processing I/O unit. Когда приложение выставляет аудиосессию в режим «голосового чата» (voice chat), iOS включает этот компонент, который выполняет подавление эха, шумоподавление и регулировку усиления вместе, настроенные под устройство. Цена – ограничение: этот режим предполагает сценарий, похожий на телефонный звонок, поэтому приложение, которому нужна необычная маршрутизация звука – например, музыка, подмешанная к голосу, – может обнаружить, что системный модуль с ним воюет, и придётся выбирать между настроенным аппаратным путём и полным контролем.
На Android картина той же формы, но более запутанная. Android предоставляет класс AcousticEchoCanceler, включающий встроенный модуль производителя устройства, – но качество этого модуля колоссально разнится по тысячам моделей Android в обиходе. Некоторые флагманы подавляют эхо прекрасно; некоторые бюджетные телефоны едва справляются. Из-за этой непоследовательности многие серьёзные голосовые приложения на Android игнорируют модуль устройства и запускают AEC3 программно, принимая чуть большее потребление батареи в обмен на одинаковое поведение на каждом телефоне. Решающий фактор – задержка звука: флагман может проиграть и заново захватить звук за десять миллисекунд, дешёвый – за более чем сто, и оценщику задержки AEC3 приходится поглощать этот разброс.
Когда тянуться за пределы встроенного модуля
AEC3 и аппаратный модуль телефона справляются с подавляющим большинством звонков, так что честная позиция по умолчанию – выпустить их и идти дальше. Есть, однако, реальный набор случаев, где они оставляют слышимое эхо, и у этих случаев общая причина: нелинейные искажения. Классический фильтр предполагает, что эхо – это аккуратное, предсказуемое преобразование опорного сигнала. Дешёвые или громкие динамики ломают это предположение – они искажают звук так, что никакая линейная модель это не вычтет, – как и жёсткий double-talk, и сильно гулкие комнаты. Именно здесь нейросетевой модуль оправдывает своё место.
Нейросетевой, или ИИ, модуль подавления эха заменяет или дополняет классический фильтр маленькой обученной сетью, которая научилась – на тысячах часов реального эхового звука – распознавать и убирать ту грязную часть эха, что остаётся после математики. Исследовательское сообщество усиленно двигало это через ежегодный конкурс, ICASSP Acoustic Echo Cancellation Challenge, который проходил в 2021, 2022 и 2023 годах и задал современные бенчмарки. Один заметный результат, DeepVQE от Microsoft, – это единая real-time-сеть, которая одновременно делает подавление эха, шумоподавление и устранение реверберации, и о ней сообщалось, что её тестировали для Microsoft Teams, – признак того, что нейросетевые модули перешли из статей в выпускаемые продукты. Более новые работы движутся к крошечным, эффективным моделям, способным работать на телефоне, не разряжая его.
На практике вы такую сеть не обучаете сами; вы её покупаете или берёте. Krisp, самый широко развёрнутый голосовой ИИ-вендор, поставляет подавление эха рядом с шумоподавлением в SDK, который встраивается в WebRTC-конвейер через WebAssembly и работает на устройстве самого пользователя. Maxine от NVIDIA – переименованный в AI for Media в 2026 году – включает эффект акустического эхоподавления, работающий на видеокартах NVIDIA, со сборкой под Windows для машины пользователя и сборкой под Linux для ваших серверов, как это делает облачный конференц-продукт Tencent Meeting. Полное сравнение этих вендоров и решение «строить или покупать» – в нашей статье про Krisp, Maxine и Dolby; про открытый край спектра – в разборе моделей шумоподавления, где те же семейства моделей всё чаще включают обработку эха.
Куда ИИ-модуль подключается в WebRTC – и почему это неудобно
Решить использовать нейросетевой модуль – лёгкая половина; встроить его в WebRTC – трудная, и стоит честно сказать почему. Браузерный AEC3 закопан внутри APM, до того как ваш код вообще увидит звук, и вы не можете просто подменить другую модель в этом слоте из JavaScript. Поэтому собственный модуль должен подключаться там, где вы можете дотянуться, а таких мест всего два.
Первое – на устройстве пользователя, перед собственной обработкой браузера. С помощью AudioWorklet из Web Audio API – стандартного механизма запуска вашего аудиокода вне главного потока – вендорский SDK вроде Krisp сам обрабатывает сырой звук микрофона и опорный сигнал воспроизведения, после чего вы выключаете собственный echoCancellation браузера, чтобы они не складывались. Это путь «на устройстве», и его подвох в том, что теперь вы должны корректно подавать опорный сигнал сами – ту самую дисциплину проводки, которую AEC3 обычно берёт на себя.
Второе место – на сервере. В групповом звонке звук течёт через медиасервер под названием SFU, который пересылает поток каждого участника остальным, – тот же серверный слой, где живут более широкие API интеграции WebRTC и ИИ. Нейросетевой модуль, работающий там – сборка Maxine под Linux или управляемая модель платформы вроде LiveKit, – чистит звук централизованно, что естественно, когда участники звонят с телефонных линий или устройств, которые вы не контролируете и где не можете запустить код. Компромисс – стоимость и задержка: серверная очистка работает на железе, за которое вы платите, и добавляет «прыжок», и то и другое должно укладываться в бюджет задержки до 100 миллисекунд, который требует живой разговор. Какое бы место вы ни выбрали, железное правило держится: ровно один модуль в цепочке. Остальные выключите.
Частая ошибка: два модуля воюют
Самый частый самонанесённый баг с эхом в WebRTC – не слишком слабое подавление, а слишком сильное: два модуля работают на одном звуке. Это происходит само собой, потому что каждый слой по умолчанию «включён». Браузер включает AEC3. Телефон включает свой аппаратный модуль. Разработчик добавляет Krisp на всякий случай. Теперь три модели каждая пытаются смоделировать и вычесть эхо, и поскольку каждая меняет звук, который видит следующая, они путают друг друга.
Симптом характерен и его легко неверно прочитать. Вместо чистого двустороннего звука звонок становится полудуплексным – ведёт себя как рация, обрезая ваш голос всякий раз, когда говорит другой, потому что наложенные подавители суммарно слишком агрессивны и принимают вашу речь за очередное эхо к удалению. Команды часто отвечают добавлением ещё одного слоя, чтобы «починить» это, и делают хуже. Лекарство – вычитание: выключите все модули, кроме одного. Если вы внедряете вендорский SDK, выставьте браузерный echoCancellation в false. Если доверяете аппаратному модулю телефона, не запускайте ещё и AEC3. Один модуль, выбранный намеренно, бьёт три, воюющих по умолчанию.
Варианты бок о бок
С каждым размещённым вариантом сравнение читается как набор компромиссов, а не рейтинг. Правильный выбор зависит от того, откуда приходит ваш звук и сколько контроля вам нужно, а не от того, какой «лучший».
| Вариант | Где работает | Сколько стоит | Кому подходит | На что смотреть |
|---|---|---|---|---|
| Браузерный AEC3 (echoCancellation: true) | В браузере, на устройстве пользователя | Бесплатно, встроено | По умолчанию для любого браузерного звонка | Сбитый опорный сигнал; нелинейное эхо |
| Системный / аппаратный AEC (echoCancellationType: 'system') | ОС / железо устройства | Бесплатно, встроено | Десктопы с хорошим аппаратным AEC | Качество зависит от машины |
| iOS Voice-Processing I/O | Железо iPhone / iPad | Бесплатно, встроено | Нативные голосовые приложения iOS | Режим voice chat ограничивает маршрутизацию |
| Android AcousticEchoCanceler | Железо устройства | Бесплатно, встроено | Нативные приложения на хороших устройствах | Дико непоследовательно по моделям |
| AEC3 программно на мобильном | Ваше приложение, на устройстве | Разработка + батарея | Согласованность на Android | Больше CPU, чем у аппаратного пути |
| Krisp / on-device нейро-SDK | Устройство пользователя (WASM) | Годовая лицензия SDK | Кроссплатформенность, нелинейное эхо, приватность | Опорный сигнал придётся подавать самим |
| NVIDIA Maxine AEC | Ваши GPU NVIDIA (сервер или клиент) | GPU + лицензия | Облачные конференции на GPU, вещание | Стоимость растёт с числом потоков |
Читайте таблицу по своим ограничениям. Если вы в браузере и звонки обычные, первая строка – ваш ответ, и вы закончили. Если вы на iOS, система уже делает правильное. Если вы на Android и качество неровное, программный AEC3 покупает согласованность. Только когда классическое подавление оставляет слышимое эхо – громкие или дешёвые динамики, тяжёлый double-talk, гулкие комнаты – нейросетевой модуль оправдывает свою лицензию и проводку.
Где здесь Фора Софт
Мы строим живые видеопродукты, зависящие от чистого двустороннего звука, – платформы видеоконференций, телемедицинские консультации, где врач должен расслышать каждое слово, классы для онлайн-обучения и голосовые ИИ-агенты, – и эхо одно из первого, что мы настраиваем на любом из них. Паттерн, который мы применяем, – тот, за который выступает эта статья, разрешаемый по порядку: начать с бесплатного браузерного AEC3, проверить его реальным измерением, а не одним тестовым звонком, и относиться к упорному эху как к расследованию проводки и тайминга, прежде чем тянуться за другой моделью. На мобильных мы решаем по платформам – доверяя настроенному железу iOS и выбирая между модулем устройства Android и программным AEC3 в зависимости от устройств, на которые продукт реально нацелен. Мы переходим к нейросетевому модулю только когда нелинейное эхо переживает классический, и когда переходим – держим линию на одном модуле в цепочке, чтобы благонамеренный второй слой никогда не превратил чистый звонок в рацию.
Ключевые выводы
- WebRTC поставляет бесплатный качественный модуль эхоподавления AEC3, включённый по умолчанию через echoCancellation.
- Единственный обязательный вход модуля – опорный сигнал дальнего конца, до любого подмешивания.
- Большинство багов с эхом в WebRTC – это проводка и тайминг, а не слабый алгоритм: сначала смотрите ERLE и задержку.
- На телефонах работу обычно делает собственный аппаратный модуль устройства; качество на Android разнится.
- Тянитесь за нейромодулем (Krisp, Maxine, открытые модели) только ради нелинейного эха, которое фильтр пропускает.
- Никогда не накладывайте два модуля; симптом – полудуплекс «рация». Запускайте ровно один.