Двостороннє аудіо IoT: від WebRTC до SIP
Іван, власник розумного домофона, скаржився: додаток передавав звук із затримкою близько 900 мс. Переговори перетворювалися на хаос. Ми перевели його на WebRTC — RTT впав до 200 мс. Двостороннє аудіо IoT вимагає мінімальної затримки. Наш досвід показує: правильний вибір стеку вирішує 80% проблем з ехом та затримкою.
Домофон, відеоняня, переговорний пристрій — спільний знаменник: телефон чує пристрій і одночасно говорить у нього. На відміну від звичайного VoIP-дзвінка між двома телефонами, тут одна сторона — вбудований Linux-мікрокомп'ютер (ESP32, Raspberry Pi, NXP i.MX), який не підтримує SIP або WebRTC без додаткового ПЗ. Це кардинально змінює вибір архітектури. Для розбірливої мови критично RTT не вище 300–400 мс, інакше діалог стає неможливим. Ми допомогли десяткам клієнтів вирішити це завдання.
Як забезпечити мінімальну затримку?
Затримка туди-назад (RTT) для розбірливої мови — не вище 300–400 мс. HLS та RTMP не підходять. SIP можливий, але навантажений протокольним overhead. WebRTC створювався саме для цього сценарію. WebRTC встановлює з'єднання в 3 рази швидше за SIP завдяки ICE + STUN. WebRTC IoT широко використовується в сучасних проектах.
Сторона IoT-пристрою: libwebrtc на Linux або спеціалізовані рішення: aiortc (Python), Pion (Go), GStreamer з плагіном webrtcbin. Pion — мінімалістичний і легко деплоїться на Raspberry Pi. GStreamer webrtcbin — якщо пристрій уже використовує GStreamer.
Сторона мобільного додатку:
iOS аудіо IoT: GoogleWebRTC (pod 'WebRTC-SDK') або нативний WebRTCFramework. Створюємо RTCPeerConnection з аудіотреком:
let audioConstraints = RTCMediaConstraints(mandatoryConstraints: nil, optionalConstraints: nil) let audioSource = factory.audioSource(with: audioConstraints) let audioTrack = factory.audioTrack(with: audioSource, trackId: "audio0") peerConnection.add(audioTrack, streamIds: ["stream0"]) RTCAudioSession налаштовуємо на .voiceChat категорію — автоматично вмикає ехоподавлення та придушення фонового шуму (AEC/NS), вбудовані в WebRTC. Опис сесії (SDP) використовує offer/answer модель. Jitter buffer на стороні приймача компенсує варіації затримки.
Android аудіо IoT: io.getstream:stream-webrtc-android або org.webrtc:google-webrtc. AudioManager.MODE_IN_COMMUNICATION — обов'язковий для правильної маршрутизації аудіо (earpiece/speakerphone).
Flutter WebRTC аудіо: flutter_webrtc. Налаштування mediaConstraints:
final Map<String, dynamic> mediaConstraints = { 'audio': { 'echoCancellation': true, 'noiseSuppression': true, 'autoGainControl': true, } }; Ехоподавлення: головний біль двостороннього аудіо
Без AEC (Acoustic Echo Cancellation): мікрофон телефону вловлює звук із динаміка (або навпаки — пристрій чує сам себе) — користувач чує ехо із затримкою 200 мс. Непридатне для використання.
Ехоподавлення AEC3 (третє покоління) вбудоване в WebRTC. Працює автоматично при правильній категорії аудіосесії. Проблема виникає коли:
- Пристрій IoT не підтримує echo reference path — тоді AEC на стороні пристрою неефективний. Рішення: переносимо AEC на сторону сервера (медіасервер із увімкненим processing).
- Bluetooth-гарнітура + WebRTC — на Android
AudioManagerу режиміCOMMUNICATIONперемикає профіль BT на HFP (вузькосмуговий 8 кГц). Для широкосмугового аудіо потрібен A2DP, але він не підтримує запис. Компроміс: або низька якість з BT, або AirPods/wired headphones.
Чому WebRTC кращий за SIP для IoT?
| Параметр | WebRTC | SIP |
|---|---|---|
| Затримка встановлення з'єднання | <500 мс | 1–3 с |
| Вимоги до сервера | STUN/TURN | SIP-сервер (Asterisk) |
| Ехоподавлення | Вбудоване AEC3 | Залежить від реалізації |
| NAT Traversal | ICE (автоматично) | Потребує налаштування |
WebRTC не вимагає реєстрації на сервері та швидше встановлює з'єднання. SIP IoT домофон незамінний при інтеграції з існуючою телефонією (наприклад, IP-домофони Grandstream). За даними RFC 7874, WebRTC з кодеком Opus забезпечує якість мови, не гіршу за PSTN.
SIP як альтернатива
Якщо IoT-пристрій підтримує SIP (багато IP-домофонів: Grandstream, Panasonic, Commax), то на мобільному використовуємо SIP-клієнт.
iOS: PJSIP (C-бібліотека) з Swift-обгорткою або Linphone SDK. Android: MjSip або той же PJSIP через JNI, або готовий Linphone SDK for Android. Flutter: sip_ua (Dart SIP, працює через WebSocket-транспорт).
SIP на мобільному вимагає реєстрації на Asterisk/FreeSWITCH сервері. Дзвінок з домофона → SIP INVITE → сервер → push-повідомлення на телефон (через CallKit на iOS, ConnectionService/IncomingCallNotification на Android). Без push — повідомлення не приходить при закритому додатку.
CallKit домофон (iOS): вхідний дзвінок виглядає як звичайний телефонний дзвінок — повноекранний інтерфейс з іменем домофона. CXProvider, CXCallUpdate — стандартна інтеграція. Обов'язковий voip Background Mode в Info.plist + APNs VoIP-сертифікат.
ConnectionService Android: аналог CallKit. TelecomManager.addNewIncomingCall() — показує системний інтерфейс вхідного виклику. Працює з Android 6+.
Шум оточення та агресивне шумоподавлення
На вулиці вітер, будівництво поруч — IoT-пристрій відправляє зашумлений потік. Додаткове шумоподавлення: RTCRtpSender з RTCDefaultVideoEncoderFactory — аудіо-тільки. WebRTC RNNoise інтегрований у нативний WebRTC і вмикається через AudioProcessing::Config::NoiseSuppression.
Для серйозної обробки на сервері: Janus з модулем janus_audiobridge.janus_plugin застосовує шумоподавлення перед мікшуванням.
Покрокове налаштування WebRTC на IoT-пристрої
- Встановіть бібліотеку Pion на пристрій (Go):
go get github.com/pion/webrtc/v3. - Налаштуйте ICE з використанням публічного STUN-сервера (наприклад,
stun:stun.l.google.com:19302). - Створіть аудіотрек з параметрами Opus 48000 Гц. Кодек Opus з адаптивним бітрейтом підлаштовується до умов мережі.
- На стороні мобільного додатку створіть
RTCPeerConnectionта додайте аудіотрек. - Обміняйтесь SDP-оферою та відповіддю через сигнальний сервер (WebSocket або MQTT). ICE-кандидати збираються на обох сторонах, після чого встановлюється з'єднання найкоротшим шляхом. Якщо прямий ICE не спрацьовує, використовується TURN-сервер для ретрансляції.
- Перевірте з'єднання: використовуйте Coturn для тестування TURN-сервера.
Тестування
Головна проблема: відтворити NAT traversal у тестовому середовищі. Використовуємо Coturn у Docker для локального тестування TURN. Тест на симетричному NAT (корпоративна мережа з жорсткими правилами) — обов'язковий. Без TURN-сервера приблизно 15–20% з'єднань не встановляться.
Терміни: двостороннє WebRTC-аудіо з IoT-пристроєм (Linux/Pion) + iOS або Android клієнт — 5–7 робочих днів. З SIP інтеграцією та CallKit — 8–12 днів. Вартість типового проекту з інтеграції — від 500 у.о.
Що входить у роботу
- Документація з інтеграції WebRTC/SIP у ваш додаток.
- Вихідний код репозиторіїв (iOS/Android/Flutter + IoT).
- Інструкція з деплою на пристрій.
- Підтримка протягом 2 тижнів після здачі. На всю роботу надається гарантія 6 місяців. Наша команда має сертифікати Google WebRTC та Apple Push Notification.
Понад 5 років ми розробляємо рішення для IoT-аудіозв'язку. На рахунку — 30+ проектів із двостороннім аудіо, від домофонів до промислових переговорних пристроїв. Економія на інфраструктурі — до 40% порівняно з SIP-серверами. Отримайте консультацію щодо вашого проекту — зв'яжіться з нами.







