IoTLabs

Nghiên cứu, Sáng tạo và Thử nghiệm

Series ESP-WebRTC: Kết Nối Camera DVP và Micro — Pipeline Từ Capture Đến Transmit

Có SDK rồi, hiểu codec rồi — giờ là phần thực tế nhất: cắm camera vào ESP32 đúng cách và cấu hình pipeline để audio/video chạy từ phần cứng lên đến WebRTC packet.

Camera DVP: Giao Thức Và Wiring

DVP (Digital Video Port) là giao thức parallel camera cổ điển, hỗ trợ trên ESP32-S3 và ESP32-P4. Gồm các tín hiệu:

PinTênMô Tả
PCLKPixel ClockClock đồng bộ data
VSYNCVertical SyncBắt đầu frame mới
HREF/HSYNCHorizontal SyncBắt đầu line mới
D0–D7Data8-bit pixel data
XCLKClock OutClock cấp cho camera
SDA/SCLI2CCấu hình register camera
PWDNPower DownTắt camera
RESETResetReset camera

Sơ Đồ Kết Nối OV2640 Với ESP32-P4

OV2640          ESP32-P4 (EV Board)
XCLK    →      GPIO_NUM_0
PCLK    →      GPIO_NUM_5
VSYNC   →      GPIO_NUM_6
HREF    →      GPIO_NUM_7
D0      →      GPIO_NUM_11
D1      →      GPIO_NUM_9
D2      →      GPIO_NUM_8
D3      →      GPIO_NUM_10
D4      →      GPIO_NUM_12
D5      →      GPIO_NUM_18
D6      →      GPIO_NUM_17
D7      →      GPIO_NUM_16
SDA     →      GPIO_NUM_4  (I2C_SDA)
SCL     →      GPIO_NUM_3  (I2C_SCL)
PWDN    →      GPIO_NUM_2
RESET   →      GPIO_NUM_1
3.3V    →      3.3V
GND     →      GND

Lưu ý: Trên ESP32-P4 EV Board, camera module thường đã được kết nối qua FFC connector — không cần wiring thủ công nếu dùng camera module chính hãng của EV Board.

📷 [Hình minh hoạ: Sơ đồ kết nối DVP camera với ESP32-P4 — breadboard hoặc schematic]

Microphone I2S PDM

ESP-WebRTC dùng microphone qua I2S PDM (Pulse Density Modulation). Hầu hết mic module rẻ tiền (INMP441, MAX9814, MSM261) đều hỗ trợ I2S.

Kết Nối INMP441 Với ESP32-P4

INMP441         ESP32-P4
VDD     →      3.3V
GND     →      GND
SD      →      GPIO_NUM_45  (I2S_DATA_IN)
WS      →      GPIO_NUM_46  (I2S_WS)
SCK     →      GPIO_NUM_47  (I2S_BCK)
L/R     →      GND  (Chọn kênh LEFT)

Với ESP32-S3 Korvo-1, microphone đã tích hợp — không cần wiring.

Cấu Hình ESP-Capture

esp_capture là component quản lý toàn bộ pipeline thu audio/video. Cấu hình trong code:

#include "esp_capture.h"
#include "esp_capture_video_dvp.h"
#include "esp_capture_audio_i2s.h"

void init_capture(esp_capture_handle_t *cap_handle) {
    esp_capture_cfg_t cfg = {
        .task_priority = 5,
        .task_stack    = 4096,
    };
    esp_capture_init(&cfg, cap_handle);

    // Cấu hình video DVP
    esp_capture_video_dvp_cfg_t dvp = {
        .pin_pclk  = GPIO_NUM_5,
        .pin_vsync = GPIO_NUM_6,
        .pin_href  = GPIO_NUM_7,
        .pin_d0    = GPIO_NUM_11,
        // ... (các pin còn lại)
        .pin_xclk  = GPIO_NUM_0,
        .xclk_freq = 20000000,  // 20MHz XCLK cho OV2640
        .width     = 1280,
        .height    = 720,
        .fps       = 25,
        .fmt       = VIDEO_FMT_YUV422,
    };
    esp_capture_add_video_source(*cap_handle, ESP_CAPTURE_VIDEO_DVP, &dvp);

    // Cấu hình audio I2S
    esp_capture_audio_i2s_cfg_t i2s = {
        .port         = I2S_NUM_0,
        .pin_bck      = GPIO_NUM_47,
        .pin_ws       = GPIO_NUM_46,
        .pin_data_in  = GPIO_NUM_45,
        .sample_rate  = 16000,  // 16kHz cho Opus
        .bits_per_sample = 16,
        .channel      = 1,      // Mono
    };
    esp_capture_add_audio_source(*cap_handle, ESP_CAPTURE_AUDIO_I2S, &i2s);
}

Pipeline Flow

Khi capture chạy, data flow như sau:

[Camera DVP] → [PPA: scale+convert] → [H.264 HW Encoder] → [RTP Packetizer] → [WebRTC]
[Mic I2S]   → [Resample]           → [Opus Encoder]     → [RTP Packetizer] → [WebRTC]

espcapture và espwebrtc được kết nối qua callback:

// Kết nối capture output vào WebRTC input
esp_webrtc_set_video_source(webrtc_handle, cap_handle);
esp_webrtc_set_audio_source(webrtc_handle, cap_handle);

AV-Render: Nhận Audio/Video Từ Peer

av_render là component ngược lại — nhận RTP stream từ browser và output ra speaker + màn hình.

#include "av_render.h"

av_render_cfg_t render_cfg = {
    // Audio output qua I2S DAC hoặc internal DAC
    .audio = {
        .type         = AV_RENDER_AUDIO_I2S,
        .port         = I2S_NUM_1,
        .pin_bck      = GPIO_NUM_40,
        .pin_ws       = GPIO_NUM_41,
        .pin_data_out = GPIO_NUM_42,
        .sample_rate  = 16000,
    },
    // Video output qua LCD (nếu có)
    .video = {
        .type = AV_RENDER_VIDEO_LCD,
        .lcd_handle = lcd_handle,
    },
};

av_render_handle_t render;
av_render_init(&render_cfg, &render);
esp_webrtc_set_av_render(webrtc_handle, render);

Speaker Kết Nối

Với ESP32-P4 EV Board, speaker kết nối qua audio amplifier NS4168 tích hợp:

ESP32-P4 I2S_DOUT → NS4168 → Speaker 4Ω/2W

Output config cho NS4168:

// I2S transmit cho speaker
.audio_out_port = I2S_NUM_1,
.audio_out_sample_rate = 16000,
.audio_out_bits = 16,

Debug Pipeline

Nếu video không hiển thị hoặc audio không nghe được, kiểm tra log:

# Bật verbose logging
idf.py menuconfig
# → Component config → ESP Capture → Log level → DEBUG

Log thành công trông như:

D (1234) esp_capture: Video DVP init OK, 1280x720@25fps
D (1235) esp_capture: Audio I2S init OK, 16000Hz mono
D (2345) esp_webrtc: RTP video sender started
D (2346) esp_webrtc: RTP audio sender started

Bài tiếp theo: Signaling Server WHIP — Tự Deploy Trong 30 Phút