Диагностика проблем со звуком в рабочей системе: runbook

Автор: Николай СапуновОбновлено: август 202624 мин чтения
Содержание статьи +

Коротко

Когда пользователь сообщает, что на живом звонке «не работает звук», причина почти всегда одна из пяти, и найти её можно за минуты, если проверять в правильном порядке: права и маршрутизация устройства, сетевой путь, сходимость эхоподавления, рассинхрон частоты дискретизации или молчащий источник захвата. Самый полезный инструмент уже встроен в браузер – getStats() возвращает числа, по которым видно, уходит ли звук от отправителя, приходит ли к получателю и переживает ли он буфер джиттера. Этот runbook задаёт точный порядок проверок, конкретное число для чтения на каждом шаге и фикс для каждого отказа. Идите сверху вниз и останавливайтесь на первой проверке, которая сработала, – шаги выстроены так, что самые частые и дешёвые причины идут первыми.

Почему это важно

Сбои звука – это те тикеты в поддержку, из-за которых пользователи бросают продукт: глитч в видео раздражает, но звонок, на котором вас не слышно, бесполезен. Если вы строите или эксплуатируете видеоконференцию, телемедицинскую платформу, онлайн-класс или live-shopping, вашему дежурному инженеру нужна спокойная упорядоченная процедура на случай, когда звук ломается в два часа ночи, а не догадки. Этот runbook написан для инженера с пейджером и для продакт-менеджера, которому надо понимать, что этот инженер делает. Он превращает расплывчатое «нет звука» в диагностику из пяти шагов с названной причиной и известным фиксом, так что инцидент заканчивается за минуты, а не за день перебора вариантов.

Как пользоваться этим runbook

Сбой звука в продакшене выглядит как хаос, потому что симптом – «я их не слышу» – одинаков для десятков разных корневых причин. Лекарство от хаоса – чёткий порядок действий. В этом runbook пять проверок, и последовательность выбрана не случайно: ранние шаги ловят самые частые и простые в исправлении проблемы, поэтому большинство инцидентов закрывается ещё до третьего шага. Проверяйте сверху вниз. На каждом этапе читайте конкретное число или флаг, сравнивайте с ожидаемым значением и либо устраняйте проблему, либо переходите к следующей проверке. Не пропускайте шаги и не начинайте с анализа пакетов – пятый шаг стоит на своём месте не просто так.

Прежде всего соберите у сообщившего пользователя два факта – они вдвое сужают пространство поиска.

Первое: отказ односторонний или двусторонний? «Я их слышу, а они меня – нет» – это совсем другая проблема, чем «никто никого не слышит». Односторонний отказ указывает на захват у одного конкретного участника или на проблему в одном направлении; двусторонний – на общую причину, например, сбой сервера или несовпадение кодеков.

Второе: это полная тишина, искажённый звук или эхо? Полная тишина означает, что сигнал не поступает или не воспроизводится. Искажение (роботизированный, рваный, «подводный» звук) говорит о том, что сигнал приходит, но повреждается по пути – это проблема сети. Эхо указывает на то, что сигнал передаётся нормально, но не работает одна из стадий обработки. Эти три симптома требуют разных действий – как показано в дереве решений ниже.

Рисунок 1. 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. Высокий джиттер – признак нестабильного канала: буфер увеличится, чтобы компенсировать колебания, ценой роста задержки, и приложение может сделать мало что, кроме как позволить буферу адаптироваться. Если оба показателя высоки одновременно – путь насыщен или перегружен, и это отсылает к истории управления битрейтом в статье Битрейт и полоса пропускания в реальном времени.

Рисунок 2. Проверка сети в числах. Потери случаются в облаке; джиттер – неровный приход; буфер поглощает джиттер ценой задержки; concealed samples – получатель выдумывает звук, когда буфер пуст. Каждое – именованное поле getStats.

Проверка 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, потому что путаница с устройством и плохие сети – самое частое, что ломается. Каждый следующий шаг в списке встречается реже и требует всё больше усилий на расследование. Соблюдение порядка – вот что превращает двухчасовую отладку в двухминутную диагностику.

Рисунок 3. Почему важен порядок. Большинство инцидентов решаются на первых двух проверках; каждая следующая – реже и дороже. Идти по порядку – вот разница между двухминутной и двухчасовой диагностикой.

Разбор инцидента: «пациент не слышит врача»

Конкретное побеждает абстрактное, поэтому вот 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 только в последнюю очередь, а не в первую – это самая ресурсоёмкая и дорогая проверка.

Что почитать дальше

Строите такую систему?

Подберём параметры кодирования под ваш контент и посчитаем стоимость доставки до старта разработки.