Содержание статьи +
- Коротко
- Почему это важно
- Как пользоваться этим runbook
- Браузер уже всё знает: минутный ввод в getStats
- Проверка 1 – устройство, права и маршрутизация (самая частая причина)
- Проверка 2 – сетевой путь: потери, джиттер и буфер
- Проверка 3 – сходимость эхоподавления
- Проверка 4 – рассинхрон частоты дискретизации
- Проверка 5 – захват пакетов: последнее средство
- Пять проверок рядом
- Разбор инцидента: «пациент не слышит врача»
- Где здесь Фора Софт
- Главное
- Что почитать дальше
Коротко
Когда пользователь сообщает, что на живом звонке «не работает звук», причина почти всегда одна из пяти, и найти её можно за минуты, если проверять в правильном порядке: права и маршрутизация устройства, сетевой путь, сходимость эхоподавления, рассинхрон частоты дискретизации или молчащий источник захвата. Самый полезный инструмент уже встроен в браузер – getStats() возвращает числа, по которым видно, уходит ли звук от отправителя, приходит ли к получателю и переживает ли он буфер джиттера. Этот runbook задаёт точный порядок проверок, конкретное число для чтения на каждом шаге и фикс для каждого отказа. Идите сверху вниз и останавливайтесь на первой проверке, которая сработала, – шаги выстроены так, что самые частые и дешёвые причины идут первыми.
Почему это важно
Сбои звука – это те тикеты в поддержку, из-за которых пользователи бросают продукт: глитч в видео раздражает, но звонок, на котором вас не слышно, бесполезен. Если вы строите или эксплуатируете видеоконференцию, телемедицинскую платформу, онлайн-класс или live-shopping, вашему дежурному инженеру нужна спокойная упорядоченная процедура на случай, когда звук ломается в два часа ночи, а не догадки. Этот runbook написан для инженера с пейджером и для продакт-менеджера, которому надо понимать, что этот инженер делает. Он превращает расплывчатое «нет звука» в диагностику из пяти шагов с названной причиной и известным фиксом, так что инцидент заканчивается за минуты, а не за день перебора вариантов.
Как пользоваться этим runbook
Сбой звука в продакшене выглядит как хаос, потому что симптом – «я их не слышу» – одинаков для десятков разных корневых причин. Лекарство от хаоса – чёткий порядок действий. В этом runbook пять проверок, и последовательность выбрана не случайно: ранние шаги ловят самые частые и простые в исправлении проблемы, поэтому большинство инцидентов закрывается ещё до третьего шага. Проверяйте сверху вниз. На каждом этапе читайте конкретное число или флаг, сравнивайте с ожидаемым значением и либо устраняйте проблему, либо переходите к следующей проверке. Не пропускайте шаги и не начинайте с анализа пакетов – пятый шаг стоит на своём месте не просто так.
Прежде всего соберите у сообщившего пользователя два факта – они вдвое сужают пространство поиска.
Первое: отказ односторонний или двусторонний? «Я их слышу, а они меня – нет» – это совсем другая проблема, чем «никто никого не слышит». Односторонний отказ указывает на захват у одного конкретного участника или на проблему в одном направлении; двусторонний – на общую причину, например, сбой сервера или несовпадение кодеков.
Второе: это полная тишина, искажённый звук или эхо? Полная тишина означает, что сигнал не поступает или не воспроизводится. Искажение (роботизированный, рваный, «подводный» звук) говорит о том, что сигнал приходит, но повреждается по пути – это проблема сети. Эхо указывает на то, что сигнал передаётся нормально, но не работает одна из стадий обработки. Эти три симптома требуют разных действий – как показано в дереве решений ниже.
Остальная часть статьи – это пять проверок, у каждой из которых свой симптом, показатель, инструмент и способ исправления.
Браузер уже всё знает: минутный ввод в getStats
Четыре из пяти проверок считывают число из одного и того же места, поэтому стоит разобраться, что это за место, прежде чем ими пользоваться. Каждое активное WebRTC-соединение – технология, с помощью которой браузеры передают звук и видео в реальном времени, – ведёт о себе текущую сводку. Чтобы получить её, нужно вызвать на соединении функцию getStats(), определённую в спецификации W3C «Identifiers for WebRTC's Statistics API». Она возвращает отчёт, содержащий десятки именованных значений, и несколько из них дают полную картину того, идёт ли передача звука.
Думайте о getStats() как о приборной панели автомобиля. Вам не нужно открывать капот – панель уже показывает уровень топлива, скорость и индикаторы. Сбой звука почти всегда виден на панели, если знать, какие три датчика смотреть.
Вот минимальный код, который читает панель с уровнем звука, приходящим к получателю. Он работает в консоли разработчика любого современного браузера при активном звонке.
// Читаем входящую статистику звука для живого RTCPeerConnection с именем `pc`.
const report = await pc.getStats();
report.forEach((stat) => {
if (stat.type === "inbound-rtp" && stat.kind === "audio") {
console.log("получено пакетов:", stat.packetsReceived);
console.log("потеряно пакетов:", stat.packetsLost);
console.log("jitter (с):", stat.jitter);
console.log("задержка буфера джиттера (с):", stat.jitterBufferDelay);
console.log("concealed samples:", stat.concealedSamples);
}
});Пять чисел, которые выводит система, практически полностью соответствуют классам отказов в этом runbook. Рост packetsReceived означает, что звук всё ещё поступает; рост packetsLost и jitter – проблема в сети; быстро растущее значение concealedSamples говорит о том, что получатель генерирует звук для заполнения пропусков – именно так и проявляется искажение. Спецификация W3C чётко определяет concealed sample как «сэмпл, который был потерян или пришёл слишком поздно для воспроизведения и поэтому был заменён локально синтезированным сэмплом». Каждое из этих чисел используется в проверках ниже. В сопутствующей статье WebRTC-конвейер звука целиком подробно описывается вся цепочка, которую отражают эти числа.
«О чтении накопителей. Большинство чисел getStats() – это итоги, накопленные с начала звонка: concealedSamples, packetsLost, totalAudioEnergy. Одно измерение почти ничего не говорит; всё определяет скорость изменения между двумя измерениями, сделанными с интервалом в секунду. Всегда делайте два замера и вычитайте одно из другого. packetsLost, равный 4000, может показаться тревожным, пока не станет ясно, что он накопился за двухчасовой звонок без видимых последствий; те же 4000 за десять секунд – уже признак мёртвого звонка.»
Проверка 1 – устройство, права и маршрутизация (самая частая причина)
Какой симптом объясняет: полная тишина, обычно односторонняя, часто «вчера работало». Какое число читать: audioLevel на источнике у отправителя и состояние разрешения на микрофон. Инструмент: navigator.permissions, ограничения getUserMedia, отчёт media-source в getStats().
Больше тикетов по звуку вызвано операционной системой, браузером и железом, чем вашим кодом. Микрофон выключен в ОС, разрешение в браузере отклонено, пользователь выбрал не то устройство ввода или звук уходит на Bluetooth-гарнитуру, которая подключена, но не выбрана. Ни одно из этого не баг вашего приложения, и всё маскируется под «у вас всё сломалось».
Начните с источника: производит ли микрофон сигнал вообще? Ответ даёт собственная статистика отправителя. API статистики W3C возвращает audioLevel для источника звука – «число от 0 до 1 (линейно), где 1.0 соответствует 0 dBov, а 0 – полной тишине». Если пользователь говорит, но audioLevel остаётся на нуле или близко к нему, в конвейер ничего не поступает, и никакие последующие этапы не исправят ситуацию. Перед вами проблема либо с выключенным, либо с неправильным устройством – а не с транспортом.
// Производит ли микрофон сигнал? Читаем источник на стороне отправителя.
const report = await pc.getStats();
report.forEach((stat) => {
if (stat.type === "media-source" && stat.kind === "audio") {
console.log("уровень звука (0-1):", stat.audioLevel);
console.log("суммарная энергия звука:", stat.totalAudioEnergy);
}
});Если audioLevel ровно на нуле, проверяйте цепочку источников снаружи внутрь в таком порядке – каждый следующий пункт встречается реже: микрофон отключён на уровне ОС (физический переключатель или системные настройки звука); вкладка браузера заглушена или разрешение на доступ к микрофону отозвано; выбрано не то устройство ввода (встроенный микрофон ноутбука вместо гарнитуры); или выбранное устройство было отключено посреди звонка, а браузер не переключился автоматически. Состояние разрешения можно проверить одной строкой:
// Действительно ли странице разрешено пользоваться микрофоном?
const status = await navigator.permissions.query({ name: "microphone" });
console.log("разрешение на микрофон:", status.state); // "granted" | "denied" | "prompt"Фиксы операционные, а не кодовые: попросите пользователя проверить mute в ОС, заново выдать разрешение или выбрать нужное устройство в селекторе приложения. Долгосрочный фикс – это дизайн продукта: каждое серьёзное приложение для звонков показывает живой индикатор уровня входа на экране перед звонком, питаемый ровно тем же audioLevel, чтобы пользователь видел мёртвый микрофон до звонка, а не во время. Ограничения, запрашивающие микрофон, и флаги echoCancellation, autoGainControl, noiseSuppression определены в спецификации W3C «Media Capture and Streams»; правильный выбор устройства и его ограничений на этапе getUserMedia() предотвращает большинство таких тикетов.
«Частая ошибка: винить сеть за выключенный микрофон. При тикете «нет звука» инстинкт подсказывает проверить соединение. Но если audioLevel отправителя равен нулю, сеть здесь ни при чём – просто нечего передавать. Чтение уровня источника в первую очередь помогает избежать бесполезного анализа пакетов. Поэтому устройство – это Проверка 1, а захват – Проверка 5.»
Проверка 2 – сетевой путь: потери, джиттер и буфер
Какой симптом объясняет: рваный, роботизированный, «подводный» или прерывистый звук – сигнал есть, но повреждён. Какое число читать: скорость packetsLost, jitter, jitterBufferDelay и скорость concealedSamples. Инструмент: отчёт inbound-rtp в getStats(), снятый дважды.
Если звук поступает, но звучит неправильно, главный подозреваемый – сеть, и входящая статистика получателя точно указывает на проблему. Три числа работают вместе, и умение читать их в совокупности – и есть весь навык.
Потеря пакетов – доля аудиопакетов, которые не дошли. Прочитайте packetsLost и packetsReceived дважды с интервалом в несколько секунд и посчитайте долю потерь за это окно:
доля потерь = (packetsLost_сейчас - packetsLost_до)
/ (packetsReceived_сейчас - packetsReceived_до
+ packetsLost_сейчас - packetsLost_до)Подставим реальные цифры. Допустим, между двумя измерениями с интервалом в 10 секунд вы наблюдаете 120 новых потерянных пакетов и 4880 новых полученных: доля потерь = 120 / (4880 + 120) = 120 / 5000 = 0,024, или 2,4%. Для голосовой связи потери ниже примерно 1% остаются незаметными благодаря маскировке; 2–5% воспринимаются как редкие щелчки; выше 5% качество звонка резко ухудшается, если не используется избыточность. Методы восстановления потерь описаны в двух смежных статьях: Packet loss concealment (PLC) скрывает пропавшие фреймы постфактум, а FEC и RED-избыточность предотвращают потерю, отправляя звук дважды.
Джиттер – это разброс во времени прихода пакетов: пакеты, которые должны поступать ровно каждые 20 миллисекунд, вместо этого приходят с задержками и скапливаются. Поле jitter сообщает об этом, а его расчёт определён в IETF RFC 3550, Приложение A.8, как скользящее среднее разницы во времени между соседними пакетами. Одна тонкость подводит всех: джиттер указывается в getStats() в секундах, но RTP измеряет время в тактах, соответствующих частоте дискретизации. Для кодека Opus – используемого почти во всех WebRTC-звонках – эта частота фиксирована на уровне 48 000 тактов в секунду согласно IETF RFC 7587. Джиттер 0,03 в статистике означает разброс в 30 миллисекунд, который буфер джиттера должен поглотить.
Буфер джиттера – это амортизатор на стороне получателя. Он временно удерживает входящие пакеты, чтобы выдавать их в равномерном темпе, несмотря на неравномерный приход – как зал ожидания в аэропорту, где задерживаются пассажиры с нерегулярных рейсов, чтобы автобус отправился по фиксированному расписанию. Отношение поля jitterBufferDelay к jitterBufferEmittedCount даёт среднее время ожидания звука. Чем больше буфер, тем больше джиттера он скрывает, но тем выше задержка: он автоматически жертвует задержкой ради плавности. Когда потери или джиттер превышают его возможности, буфер сдаётся, и получатель генерирует замену, фиксируя её в concealedSamples. Быстро растущий concealedSamples – более чем на 1–2% от totalSamplesReceived за окно – является числовой подписью слышимого искажения. Вся эта механика подробно описана в статье Буфер джиттера: NetEQ.
Фикс зависит от того, какой показатель высок. Высокие потери при низком джиттере – это канал с потерями: включите FEC или RED. Высокий джиттер – признак нестабильного канала: буфер увеличится, чтобы компенсировать колебания, ценой роста задержки, и приложение может сделать мало что, кроме как позволить буферу адаптироваться. Если оба показателя высоки одновременно – путь насыщен или перегружен, и это отсылает к истории управления битрейтом в статье Битрейт и полоса пропускания в реальном времени.
Проверка 3 – сходимость эхоподавления
Какой симптом объясняет: эхо – одна сторона слышит собственный голос с задержкой. Какое число читать: настройку echoCancellation на дорожке захвата; используются ли наушники. Инструмент: MediaStreamTrack.getSettings() плюс быстрый вопрос об окружении.
Эхо – не сетевая проблема и не проблема отсутствия звука на устройстве; это проблема обработки, и её выделяют в отдельную проверку, потому что её симптом невозможно спутать с чем-либо другим. Эхо возникает, когда динамик одного участника воспроизводит голос другого, этот звук попадает обратно в микрофон первого и отправляется ему – в результате второй слышит свой собственный голос с задержкой. Задача акустического эхоподавления (AEC) – распознать сигнал с динамика в потоке с микрофона и вычесть его. Современная реализация WebRTC – AEC3 – справляется с этим хорошо, но у неё есть режим отказа, о котором стоит знать.
Сначала убедитесь, что AEC вообще включён. Дорожка захвата несёт свои текущие настройки, и спецификация W3C Media Capture and Streams определяет echoCancellation как булево значение, которое можно прочитать обратно:
// Убеждаемся, что эхоподавление действительно включено на живой дорожке захвата.
const [track] = localStream.getAudioTracks();
const settings = track.getSettings();
console.log("echoCancellation:", settings.echoCancellation); // ожидаем trueЕсли вы видите false, значит, в вашем коде захвата был запрошен сырой звук – типичная ошибка, когда разработчик копирует фрагмент getUserMedia, предназначенный для записи музыки, где эхоподавление намеренно отключено. Запросите дорожку заново с включённым эхоподавлением echoCancellation: true.
Если AEC включён, а эхо всё ещё остаётся, причина, как правило, одна из трёх проблем сходимости – вся механика подробно описана в статье Акустическое эхоподавление (AEC): как это работает. Подавителю требуется некоторое время в начале звонка, чтобы «сойтись» – то есть определить акустическую задержку между динамиком и микрофоном, – и в первые секунды эхо может прорываться. Долгую или переменную задержку он не справляется: Bluetooth-громкая связь добавляет более сотни миллисекунд непредсказуемой задержки между опорным сигналом и эхом – а именно в таких условиях классические алгоритмы AEC перестают работать. А «двойной разговор» – когда оба собеседника говорят одновременно – является самым сложным сценарием для поддержания точной оценки. Подробности проблемы с Bluetooth и громкой связью – в статье Эхоподавление на громкой связи, Bluetooth и AirPods.
Надёжный операционный фикс – самый старый: наушники устраняют эхо в источнике, потому что выход динамика не доходит до микрофона. Проектируйте под пользователя, который откажется их надеть – держите AEC включённым, предпочитайте проводные или низколатентные пути, – но когда приходит тикет про эхо, вопрос «вы на громкой связи или на Bluetooth?» решает его чаще любого изменения кода.
Проверка 4 – рассинхрон частоты дискретизации
Какой симптом объясняет: стойкое искажение или сдвиг тона, которое не удаётся выявить при проверке сети – звук слегка ускоренный, замедленный или «бурундучий». Какое число читать: частоту дискретизации на захвате, в кодеке и в аудиоконтексте. Инструмент: AudioContext.sampleRate, настройки дорожки и конфигурация кодека на сервере.
Это тонкий случай, и он относится к проверке 4, потому что встречается реже, чем первые три, но для них остаётся невидимым. Цифровой звук – это поток сэмплов, взятых с фиксированной частотой; для видео и WebRTC стандартом является 48 000 сэмплов в секунду, или 48 кГц. Проблема возникает, когда одна стадия конвейера ожидает другую частоту, чем та, с которой работает другая. Если звук записан на 44,1 кГц, а следующая стадия обрабатывает его как 48 кГц, каждая секунда звука проигрывается быстрее, чем за секунду, и тон повышается – это эффект «бурундука». Обратная ситуация приводит к понижению тона. Более тонкая версия проблемы может вызывать периодические щелчки или медленный дрейф, пока две частоты постепенно расходятся.
WebRTC стандартизирует 48 кГц именно для того, чтобы избежать рассинхрона – Opus работает на частоте 48 кГц, а тактовая частота его RTP-полезной нагрузки зафиксирована на уровне 48 000 Гц в RFC 7587. Поэтому в чистом WebRTC-звонке рассинхрон обычно возникает на границах: граф Web Audio работает на нативной частоте оборудования, ветка записи может быть настроена на неправильной частоте или шлюз в сторону PSTN-плеча использует 8 кГц. Проверка проста: нужно прочитать частоту на каждой границе и убедиться, что они совпадают или между ними стоит явный ресэмплер:
// На какой частоте дискретизации реально работает граф Web Audio?
const ctx = new AudioContext();
console.log("частота AudioContext:", ctx.sampleRate); // обычно 48000, иногда 44100Фикс – никогда не «форсировать» частоту в надежде на лучшее. Нужно правильно поставить ресэмплер на границе, где частота законно меняется, чтобы сигнал 44,1 кГц был пересэмплирован в 48 кГц до подачи на кодек, работающий на 48 кГц. Фон о том, почему 48 кГц стали стандартом в видео и сколько стоит ресэмплинг, – в статье Частота дискретизации: 44,1, 48, 96, 192 кГц. Ветка записи или транскрипции – частая причина проблем, потому что она подключается уже после того, как звонок заработал; подробности – в Запись и транскрипция: ASR-конвейер.
«Частая ошибка: читать искажение как сетевую проблему. Рваный звук с высоким concealedSamples – это проблема сети. Звук, постоянно неправильный по тону или скорости, при чистой сетевой статистике – это рассинхрон частоты. Признак в том, что проверка сети на Шаге 2 показывает хорошие показатели – низкие потери, низкий джиттер, – а звук всё равно искажён. Когда цифры говорят, что путь здоров, а уши слышат обратное, подозревайте рассинхрон частоты.»
Проверка 5 – захват пакетов: последнее средство
Какой симптом объясняет: всё, что не удалось объяснить первыми четырьмя проверками, особенно проблемы на стороне сервера и с сигнализацией. Инструмент: chrome://webrtc-internals (или браузерный аналог) и Wireshark для анализа PCAP, если требуется работа на уровне сети.
Если проблема прошла первые четыре проверки, вы исчерпали возможности анализа на уровне приложения, и пора переходить к анализу байтов. Здесь есть два уровня.
Первая и наиболее простая – дамп браузера. Chrome позволяет получить chrome://webrtc-internals – живую страницу, отображающую значение getStats() в виде графика для каждого активного соединения и дающую возможность экспортировать всю сессию в файл. Это те же данные, что обрабатывает код выше, но представленные во времени и собранные автоматически – бесценный инструмент, когда проблема возникает эпизодически и не воспроизводится по требованию. Попросите пользователя открыть chrome://webrtc-internals во вкладке до звонка, воспроизвести сбой и прислать дамп. График concealedSamples или packetsLost за ту самую секунду, когда пропал звук, обычно сразу указывает на причину без дополнительных действий.
Вторая глубина – настоящий захват пакетов в Wireshark, стандартном анализаторе сетевых протоколов. К нему обращаются, когда вопрос выходит за пределы приложения: уходят ли RTP-пакеты с машины вообще, содержат ли они ожидаемый кодек, договорились ли стороны о формате полезной нагрузки через SDP. Wireshark декодирует RTP и RTCP, позволяет оценить потери и джиттер по потоку независимо от браузера, а при захвате аудиопотока даже воспроизвести RTP-стрим, чтобы услышать, что реально передавалось по сети. Именно так выявляются сбои, которые не доходят до getStats(): файрвол, блокирующий медиа, пока сигналинг проходит (звонок «соединяется», но молчит), несоответствие кодеков из-за ошибочного согласования SDP или односторонняя передача медиа из-за асимметричного NAT. Архитектура, определяющая, куда направляются эти пакеты и где их перехватывать, подробно разобрана в статье Аудио в SFU, MCU и P2P.
Захват – это Проверка 5, потому что он требует больше всего времени и навыков, а в четырёх случаях из пяти одна из предыдущих проверок уже даёт ответ. Использовать Wireshark в первую очередь – типичная ошибка новичка: это всё равно что разбирать двигатель, чтобы понять, что машина просто стояла на нейтрали.
Пять проверок рядом
Таблица – это runbook в одном файле. Распечатайте её, прикрепите рядом с дежурной панелью и действуйте сверху вниз.
| № | Проверка | Симптом | Число / сигнал для чтения | Типичный фикс |
|---|---|---|---|---|
| 1 | Устройство и права | Полная тишина, односторонняя | audioLevel отправителя ≈ 0; разрешение denied | Снять mute в ОС, выдать заново, выбрать устройство |
| 2 | Сетевой путь | Рваный, роботизированный, прерывистый | скорость packetsLost, jitter, скорость concealedSamples | Включить FEC/RED; дать буферу адаптироваться |
| 3 | Эхоподавление | Звонящий слышит себя | echoCancellation = false; на громкой связи? | Включить AEC; наушники |
| 4 | Рассинхрон частоты | Неправильный тон/скорость, чистая сеть | частоты на захвате vs кодеке vs контексте | Вставить ресэмплер на границе |
| 5 | Захват пакетов | Всё необъяснённое | дамп webrtc-internals; RTP в Wireshark | Найти дропнутую/несовпадающую медиа на проводе |
Порядок кодирует накопленный полевой опыт: примерно семь из десяти тикетов «сломался звук» закрываются уже на Проверке 1 или 2, потому что путаница с устройством и плохие сети – самое частое, что ломается. Каждый следующий шаг в списке встречается реже и требует всё больше усилий на расследование. Соблюдение порядка – вот что превращает двухчасовую отладку в двухминутную диагностику.
Разбор инцидента: «пациент не слышит врача»
Конкретное побеждает абстрактное, поэтому вот runbook, применённый к реальной форме тикета из телемедицинского звонка. Обращение: врач слышит пациента, но пациент утверждает, что врач молчит. Сам по себе этот факт – односторонний, от врача к пациенту – уже указывает на проблему либо в приёмном канале пациента, либо в передающем канале врача. При этом сеть в обратную сторону работает нормально.
Проверка 1, на стороне врача: читаем значение audioLevel у отправителя, пока врач говорит. Отображается 0,34 – это нормальный уровень. Микрофон выдаёт сигнал, значит, он включён и работает. Продолжаем.
Проверка 2, со стороны пациента: смотрим входящую статистику inbound-rtp пациента по аудиопотоку врача. packetsReceived не растёт между двумя замерами. Пакеты не поступают вообще. Это не потери и не джиттер – они проявились бы в виде приходящих, но повреждённых пакетов. Отсутствие пакетов при активном соединении указывает не на приложение, а на саму транспортную линию.
Перепрыгиваем к Проверке 5, потому что нулевой приём пакетов при «соединённом» звонке – классическая картина блокировки медиа при успешном сигналинге. Дамп webrtc-internals у пациента подтверждает: входящий поток звука существует, но показывает ноль полученных байт. Короткий захват Wireshark в сети пациента показывает, что RTP-поток от врача не приходит – корпоративный файрвол в больничной сети пропускает сигнальный канал, но блокирует UDP-медиа. Решение – операционное: использование TURN-релея через TCP/443 для обхода файрвола, а не изменение кода обработки звука. Общее время до выявления причины – меньше десяти минут, потому что односторонняя классификация и интерпретация «пакеты не растут» сразу направили нас на нужную глубину анализа.
Урок – весь тезис runbook: классификация симптома плюс одно-два чтения getStats() почти всегда указывают на нужную проверку, а та, в свою очередь, выявляет причину.
Где здесь Фора Софт
Мы используем звук в реальном времени в телемедицине, видеоконференциях, онлайн-обучении и прямых трансляциях с 2005 года – за это время мы проверили наш чек-лист в реальных условиях больше раз, чем можем сосчитать. Эта закономерность подтверждается во всех направлениях: подавляющее большинство обращений «звук не работает» вызвано проблемами с устройством, правами доступа или сетью – то есть факторами, зависящими от окружения пользователя, а не дефектами медиакода. Сложности возникают у тех команд, у которых нет чётко установленного порядка проверок. В наших продуктах перед началом звонка на экране всегда отображается живой индикатор микрофона, чтобы неисправное устройство выявлялось заранее, а во время звонка клиент непрерывно собирает getStats(), чтобы служба поддержки могла проанализировать показатели потерь и concealment по завершённой сессии. Встроенная с самого начала система наблюдения – вот что отличает диагностику на основе данных от догадок по скриншотам.
Главное
- Сначала определите тип проблемы: односторонняя или двусторонняя связь, а также характер дефекта – тишина, искажение или эхо.
- Выполняйте пять проверок строго по порядку; большинство обращений решаются уже на первой или второй.
- getStats() – это панель управления: сначала изучите источник из audioLevel, затем проверьте потери и скрытие сигнала на входе.
- Сравнивайте два измерения с интервалом в одну секунду; важна скорость изменения параметров, а не конечное значение.
- Эхо возникает из-за наушников или неисправности AEC; если тон неправильный при стабильном соединении – проверьте частоту дискретизации.
- Используйте Wireshark только в последнюю очередь, а не в первую – это самая ресурсоёмкая и дорогая проверка.