Voice10 phút đọc

AEC: Tại sao AI Voice Assistant Cần Khử Echo

Giải thích Acoustic Echo Cancellation từ thuật toán NLMS đến thực tế triển khai trên browser (AEC3) và ESP32 (ESP-ADF). Bao gồm so sánh AEC support giữa OpenAI, Gemini Live và xAI Grok.

AECVoice AIESP32WebRTCRealtime
AC

Assistant Core Team

Voice & Hardware

Acoustic Echo Cancellation — Luồng tín hiệu
Acoustic Echo Cancellation — Luồng tín hiệu

Khi xây dựng voice assistant, bạn sẽ gặp ngay vấn đề: micro thu lại giọng của chính assistant đang phát qua loa, tạo vòng lặp echo vô hạn. Đây là bài toán Acoustic Echo Cancellation (AEC) — một lĩnh vực xử lý tín hiệu số đã tồn tại hơn 50 năm nhưng vẫn cực kỳ quan trọng trong thời đại AI voice.

Bài viết này giải thích AEC hoạt động như thế nào, cách browser và thiết bị phần cứng xử lý, và những bài học từ việc tích hợp AEC vào Assistant Core trên cả web lẫn ESP32.

Vấn đề: Vòng lặp Echo

Hình dung: bạn hỏi assistant một câu. Assistant phát câu trả lời qua loa. Micro đang mở thu lại giọng assistant. Server nhận audio này, nghĩ đó là user nói, xử lý và phát tiếp... Kết quả là assistant nói chuyện với chính mình.

Với các model realtime (OpenAI Realtime, Gemini Live, xAI Grok), vấn đề càng nghiêm trọng hơn vì micro luôn mở trong chế độ full-duplex. Không như auto mode — nơi mic tắt khi TTS đang phát — realtime mode truyền audio liên tục cả hai chiều.

AEC hoạt động như thế nào?

AEC dựa trên một ý tưởng đơn giản: nếu biết âm thanh nào đang phát qua loa, ta có thể trừ nó ra khỏi tín hiệu micro. Quy trình gồm 3 bước:

  1. Reference signal — Lấy audio đang gửi đến loa làm tín hiệu tham chiếu
  2. Adaptive filter — Mô hình hóa cách âm thanh truyền từ loa → phòng → micro (echo path)
  3. Subtraction — Trừ echo ước tính ra khỏi tín hiệu micro, chỉ giữ lại giọng user
# Simplified AEC pipeline
def aec_process(mic_signal, reference_signal, filter_state):
    # 1. Adaptive filter dự đoán echo
    estimated_echo = adaptive_filter(reference_signal, filter_state)

    # 2. Trừ echo khỏi mic
    clean_signal = mic_signal - estimated_echo

    # 3. Cập nhật filter (NLMS algorithm)
    error = mic_signal - estimated_echo
    filter_state = update_nlms(filter_state, reference_signal, error)

    return clean_signal, filter_state

Thuật toán NLMS (Normalized Least Mean Squares) được dùng phổ biến nhất. So với LMS gốc, NLMS chuẩn hóa step size theo năng lượng tín hiệu — giúp hội tụ nhanh hơn và ổn định hơn khi âm lượng thay đổi liên tục (đặc thù của giọng nói).

Ngoài ra, sau khi trừ echo tuyến tính, vẫn còn residual echo do biến dạng phi tuyến (loa rẻ, clipping). Bước Non-Linear Processing (NLP) sẽ phát hiện và suppress phần echo còn sót lại.

AEC trên Browser — Miễn phí và đủ tốt

Tin tốt: trên web, bạn không cần tự implement AEC. Browser (Chrome, Firefox, Safari) đã tích hợp AEC thông qua Web Audio API:

// Bật AEC khi capture micro
const stream = await navigator.mediaDevices.getUserMedia({
  audio: {
    echoCancellation: true,    // AEC
    noiseSuppression: true,    // Noise reduction
    autoGainControl: true,     // Normalize volume
  }
})

// Chrome sử dụng AEC3 — adaptive filter trong frequency domain
// Reference signal = audio đang phát qua speaker
// Tất cả xử lý ở kernel level, không cần code thêm

Chrome cụ thể sử dụng AEC3 — module xử lý trong frequency domain (FFT) thay vì time domain, cho phép mô hình hóa phòng phức tạp hiệu quả hơn. Quy trình:

  1. Capture reference signal từ audio output device
  2. Adaptive filter (PBFDAF) ước tính room impulse response
  3. Trừ echo và áp dụng Non-Linear Processor cho residual

Bạn có thể debug AEC trên Chrome tại chrome://webrtc-internals — xem trạng thái AEC real-time và tải raw audio dumps để phân tích.

AEC trên ESP32 — Phức tạp hơn nhiều

ESP32 không có browser, không có AEC sẵn. Bạn phải tự xử lý, và có 3 hướng:

Giải phápRAMChất lượngThiết bị
ESP-ADF aec_stream~50KBTốtESP32-S3 + dual mic
Codec hardware AEC~0KBRất tốtBoard có ES8311/ES7210
Mute mic khi phát~0KBCơ bảnMọi board (half-duplex)

ESP-ADF (Espressif Audio Development Framework) cung cấp algorithm_stream với AEC tích hợp. Điểm quan trọng là reference signal phải khớp chính xác với audio đang phát qua loa — nếu bị delay, compress, hay biến dạng, adaptive filter sẽ không hội tụ.

// ESP-ADF: cấu hình AEC cho ESP32-S3
algorithm_stream_cfg_t algo_cfg = {
    .input_type = ALGORITHM_STREAM_INPUT_TYPE2,
    .algo_mask = ALGORITHM_STREAM_USE_AEC
               | ALGORITHM_STREAM_USE_NS    // Noise suppression
               | ALGORITHM_STREAM_USE_AGC,  // Auto gain
    .sample_rate = 16000,
    .mic_ch = 1,
    .ref_ch = 1,        // Reference = speaker output
    .debug_input = true, // Bật để calibrate delay
};

// Delay calibration: recording nên trễ 0-10ms so với reference
algo_stream_set_delay(algo_stream, 5);  // 5ms

Board ESP32-S3-BOXKorvo-2 có hardware AEC sẵn qua codec chip — hoạt động tốt nhất. Board tự thiết kế với INMP441 + MAX98357A thì cần dùng software AEC hoặc chấp nhận mute mic khi phát (half-duplex).

Realtime AI Provider — Không ai hỗ trợ server-side AEC

Một sự thật quan trọng: cả ba realtime provider lớn đều không xử lý AEC trên server.

ProviderServer AECServer VADGhi chú
OpenAI RealtimeCó WebRTC endpoint (AEC trong browser)
Gemini LiveVAD rất nhạy — dễ interrupt loop
xAI GrokFull-duplex, phụ thuộc client AEC

Hệ quả: nếu echo lọt qua client AEC, server VAD sẽ nhầm echo là giọng user — dẫn đến interrupt loop (model tự ngắt liên tục, đặc biệt với Gemini Live vì VAD rất nhạy).

Bài học thực tế từ Assistant Core

  • Web client: 0 dòng code AECechoCancellation: true trong getUserMedia là đủ. Laptop/Desktop đều có AEC tốt ở hardware + browser level.
  • ESP32: chọn board cẩn thận — Board có codec chip với reference channel (ES8311) cho AEC tốt nhất. Board đơn giản (INMP441 + MAX98357A) sẽ phải trade-off: software AEC tốn RAM hoặc half-duplex tốn UX.
  • Headphone = AEC hoàn hảo — Khi dùng tai nghe, echo bị loại bỏ vật lý. Đây là khuyến nghị tốt nhất cho user gặp vấn đề echo, đặc biệt trên mobile.
  • Gemini cần đặc biệt chú ý — VAD sensitivity cao hơn OpenAI/xAI. Nếu gặp interrupt loop, tăng prefixPaddingMs trong session config giúp buffer thêm thời gian trước khi VAD trigger.

Khi nào cần lo về AEC?

Quy tắc đơn giản:

  • Web app trên laptop/desktop → Không cần lo, browser xử lý
  • Web app trên mobile (loa ngoài) → AEC yếu hơn, khuyên dùng tai nghe
  • ESP32 với loa gần micro → Cần hardware AEC hoặc software AEC
  • Bluetooth headset → Có thể có latency cao, AEC đôi khi không compensate đúng

AEC là một bài toán đã có lời giải ở hầu hết platform hiện đại. Việc của developer là hiểu nó hoạt động như thế nào để chọn đúng giải pháp cho từng loại client — không phải tự implement từ đầu.

Sẵn sàng thử Assistant Core?

Tạo AI assistant trong vài phút — RAG, voice, MCP tools và edge device.

Tìm hiểu thêm