AI шумоподавлення для звонків у мобільних додатках
Коли ви відкриваєте мікрофон через AVAudioSession на iOS або AudioRecord на Android, ви отримуєте сирий PCM потік—все навколо користувача. Будівельні роботи за вікном, кавомашина, діти—все йде у звонок. Стандартне Acoustic Echo Cancellation (AEC) з WebRTC видаляє відлуння, але не фоновий шум. ML-модель для подавлення шуму потрібна тут.
Як AI шумоподавлення відрізняється від стандартного DSP
Класичний підхід—спектральне віднімання або Wiener фільтр: модель шуму оцінюється під час пауз мовлення, потім віднімається зі спектру. Працює для стаціонарного шуму (гул вентилятора), не працює для нестаціонарного (голос у метро, клавіатура поруч).
AI підхід—нейронна мережа, навчена на парах «чисте мовлення + шумне мовлення», передбачає маску для кожного спектрограми кадру. Моделі типу RNNoise, DTLN або DistilledRNNoise працюють в реальному часі, обробляючи кадри 10–20 мс з затримкою менше одного кадру.
RNNoise: швидкий старт на обох платформах
RNNoise від Mozilla—C бібліотека, 90 KB, ~2 MFLOPS на кадр. Компілюється в статичну бібліотеку для iOS (xcframework) та Android (AAR з нативною частиною через NDK).
// Ініціалізація
DenoiseState *st = rnnoise_create(NULL);
// Обробка кадру (480 сэмплів = 10 мс при 48 kHz)
float frame[480];
// ... заповніть з буфера мікрофону
float vad_prob = rnnoise_process_frame(st, frame, frame);
// frame тепер містить очищений сигнал
// vad_prob > 0.5—ймовірно мовлення
Інтеграція iOS: AVAudioEngine з користувацьким AVAudioSinkNode або tap на вхідному ноді. Формат—Float32, 48 kHz, моно. AVAudioSession повинна бути налаштована з mode: .voiceChat та явно відключити системну обробку, інакше iOS застосовує власне шумоподавлення поверх вашого.
let inputNode = audioEngine.inputNode
let format = inputNode.outputFormat(forBus: 0)
inputNode.installTap(onBus: 0, bufferSize: 480, format: format) { [weak self] buffer, _ in
guard let self = self else { return }
let channelData = buffer.floatChannelData![0]
// Передайте в rnnoise_process_frame через C-bridge
self.rnnoiseProcessor.process(channelData, frameLength: Int(buffer.frameLength))
}
На Android—AudioRecord з AudioFormat.ENCODING_PCM_FLOAT, розмір буфера 480 сэмплів, обробка в окремому потоці з Process.THREAD_PRIORITY_URGENT_AUDIO. Викличте ту ж C бібліотеку через JNI.
DTLN та важчі моделі
Якщо RNNoise недостатньо (складний багатокомпонентний шум, кілька джерел), використовуйте DTLN—двошарова LSTM модель. Конвертується в TFLite (Android) або Core ML (iOS).
На практиці: DTLN при 16 kHz займає 8–14 мс на кадр на iPhone 12, укладається в реальний час. Android Snapdragon 778G—аналогічно. На бюджетних Helio G85—25–35 мс, створюючи накопичувальну затримку.
Для мобільного, вибір частоти дискретизації важливий: 16 kHz замість 48 kHz скорочує обчислювальне навантаження у 4 рази, а для мовлення пропускна здатність до 8 kHz достатня для розбірливості.
Інтеграція в WebRTC
WebRTC SDK (LiveKit, Agora, Daily) забезпечують AudioProcessingModule або hook перед кодуванням. У нативному WebRTC для iOS—користувацький RTCAudioProcessingModule:
// Реєструємо користувацьку обробку
let config = RTCConfiguration()
// Створіть RTCPeerConnectionFactory з користувацьким AudioDeviceModule
// або використовуйте AudioProcessingConfig для заміни WebRTC built-in
Важливий нюанс: WebRTC уже містить AECM та NS (Noise Suppression). При включенні власного AI шумоподавлення, вимкніть вбудований NS через AudioProcessingConfig, інакше подвійна обробка створює артефакти—«металічний» звук, зрізані приголосні.
Процес
Аудит аудіопайплайну додатку, вибір моделі під вимоги (затримка vs якість), компіляція нативної бібліотеки під цільові архітектури (arm64, x86_64 для симулятора), інтеграція в існуючий аудіостек, тестування на реальних шумах.
Кошторис за часом
Інтеграція RNNoise в існуючий WebRTC стек займає 1–2 тижні. Реалізація з DTLN/TFLite, налаштування VAD, підтримка обох платформ вимагає 3–5 тижнів.







