333 lines
14 KiB
Markdown
333 lines
14 KiB
Markdown
# AV Processor Component (Audio/Video Processing)
|
|||
|
|
|
||
|
|
This component provides a unified encapsulation for audio recording/playback/data feeding and video capture/decoding/rendering on ESP platforms, implemented based on middleware such as GMF (General Media Framework), esp-audio-render, esp-video-codec, and esp-capture.
|
||
|
|
|
||
|
|
## Feature Overview 🎛️
|
||
|
|
|
||
|
|
- **Audio 🎧**:
|
||
|
|
- Recording (AEC/VAD/AFE optional)
|
||
|
|
- Playback (supports URL and local files, decoding depends on configuration)
|
||
|
|
- Data feeding (feeder, suitable for scenarios like RTC/streaming where receiving and playing happen simultaneously)
|
||
|
|
- Optional mixer with volume fade and focus control between multiple streams
|
||
|
|
- **Video 🎥**:
|
||
|
|
- Multi-channel video capture
|
||
|
|
- Video decoding and rendering callbacks
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Quick Start
|
||
|
|
|
||
|
|
### 1. Audio Usage
|
||
|
|
|
||
|
|
1. Initialize audio manager:
|
||
|
|
|
||
|
|
```c
|
||
|
|
// Method 1: Use default configuration macro (recommended)
|
||
|
|
audio_manager_config_t cfg = DEFAULT_AUDIO_MANAGER_CONFIG();
|
||
|
|
cfg.play_dev = your_play_dev;
|
||
|
|
cfg.rec_dev = your_rec_dev;
|
||
|
|
strcpy(cfg.mic_layout, "RMNM"); // Microphone layout (optional, for AFE configuration)
|
||
|
|
cfg.board_sample_rate = 16000;
|
||
|
|
cfg.board_bits = 32;
|
||
|
|
cfg.board_channels = 2;
|
||
|
|
cfg.play_volume = 80;
|
||
|
|
cfg.rec_volume = 60;
|
||
|
|
cfg.rec_ref_volume = 60;
|
||
|
|
cfg.enable_mixer = true; // Enable when mixing feeder and playback is needed
|
||
|
|
|
||
|
|
audio_manager_init(&cfg);
|
||
|
|
```
|
||
|
|
|
||
|
|
2. Recording (polling read):
|
||
|
|
|
||
|
|
```c
|
||
|
|
// Recording event callback (optional)
|
||
|
|
void recorder_event_cb(void *event, void *ctx) {
|
||
|
|
// Handle recording events (e.g., AFE events)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Configure recorder (using default configuration macro)
|
||
|
|
audio_recorder_config_t recorder_cfg = DEFAULT_AUDIO_RECORDER_CONFIG();
|
||
|
|
// Optional: Configure AFE (runtime configuration, takes priority over Kconfig)
|
||
|
|
recorder_cfg.afe_config.vad_enable = true;
|
||
|
|
recorder_cfg.afe_config.vad_mode = 4;
|
||
|
|
recorder_cfg.afe_config.agc_enable = true;
|
||
|
|
recorder_cfg.recorder_event_cb = recorder_event_cb;
|
||
|
|
|
||
|
|
// Open recorder
|
||
|
|
audio_recorder_open(&recorder_cfg);
|
||
|
|
uint8_t buf[2048];
|
||
|
|
audio_recorder_read_data(buf, sizeof(buf));
|
||
|
|
|
||
|
|
audio_recorder_close();
|
||
|
|
```
|
||
|
|
|
||
|
|
3. Feeder playback (suitable for external stream → local playback):
|
||
|
|
|
||
|
|
```c
|
||
|
|
// Configure feeder (using default configuration macro)
|
||
|
|
audio_feeder_config_t feeder_cfg = DEFAULT_AUDIO_FEEDER_CONFIG();
|
||
|
|
// Optional: When using OPUS decoder, task_stack is recommended to be >= 4096 * 10
|
||
|
|
// feeder_cfg.feeder_task_config.task_stack = 4096 * 10;
|
||
|
|
|
||
|
|
audio_feeder_open(&feeder_cfg);
|
||
|
|
audio_feeder_run();
|
||
|
|
// Feed external data blocks multiple times as needed
|
||
|
|
audio_feeder_feed_data(pkt, pkt_len);
|
||
|
|
|
||
|
|
audio_feeder_stop();
|
||
|
|
audio_feeder_close();
|
||
|
|
```
|
||
|
|
|
||
|
|
4. Normal playback (URL or local):
|
||
|
|
|
||
|
|
```c
|
||
|
|
// Configure player (using default configuration macro)
|
||
|
|
audio_playback_config_t playback_cfg = DEFAULT_AUDIO_PLAYBACK_CONFIG();
|
||
|
|
|
||
|
|
audio_playback_open(&playback_cfg);
|
||
|
|
audio_playback_play("http://<ip>:<port>/audio.mp3");
|
||
|
|
|
||
|
|
audio_playback_pause();
|
||
|
|
audio_playback_resume();
|
||
|
|
audio_playback_stop();
|
||
|
|
audio_playback_close();
|
||
|
|
```
|
||
|
|
|
||
|
|
5. Focus/fade control (when mixer is enabled):
|
||
|
|
|
||
|
|
```c
|
||
|
|
// Note: Mixer must be opened after both playback and feeder are opened
|
||
|
|
audio_processor_mixer_open();
|
||
|
|
audio_processor_ramp_control(AUDIO_MIXER_FOCUS_FEEDER); // Focus on feeder audio
|
||
|
|
audio_processor_ramp_control(AUDIO_MIXER_FOCUS_PLAYBACK); // Focus on playback audio
|
||
|
|
audio_processor_mixer_close();
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. Video Usage
|
||
|
|
|
||
|
|
1. Render (decode) callback:
|
||
|
|
|
||
|
|
```c
|
||
|
|
void decoded_cb(void *ctx, const uint8_t *data, size_t size) {
|
||
|
|
// Handle decoded frame data
|
||
|
|
}
|
||
|
|
|
||
|
|
video_render_config_t rcfg = {
|
||
|
|
.decode_cfg = your_vdec_cfg,
|
||
|
|
.resolution = {.width = 640, .height = 480},
|
||
|
|
.decode_cb = decoded_cb,
|
||
|
|
};
|
||
|
|
video_render_handle_t r = video_render_open(&rcfg);
|
||
|
|
video_render_start(r);
|
||
|
|
|
||
|
|
video_frame_t f = {.data = enc_frame, .size = enc_size};
|
||
|
|
video_render_frame_feed(r, &f);
|
||
|
|
|
||
|
|
video_render_stop(r);
|
||
|
|
video_render_close(r);
|
||
|
|
```
|
||
|
|
|
||
|
|
1. Capture (multi-channel):
|
||
|
|
|
||
|
|
```c
|
||
|
|
void capture_cb(void *ctx, int index, video_frame_t *frame) {
|
||
|
|
// Handle captured video frame
|
||
|
|
}
|
||
|
|
|
||
|
|
video_capture_config_t ccfg = {0};
|
||
|
|
ccfg.camera_config = &your_cam_cfg;
|
||
|
|
ccfg.sink_num = 2;
|
||
|
|
ccfg.sink_cfg[0] = your_sink0_cfg;
|
||
|
|
ccfg.sink_cfg[1] = your_sink1_cfg;
|
||
|
|
ccfg.capture_frame_cb = capture_cb;
|
||
|
|
|
||
|
|
video_capture_handle_t c = video_capture_open(&ccfg);
|
||
|
|
video_capture_start(c);
|
||
|
|
video_capture_stop(c);
|
||
|
|
video_capture_close(c);
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Media Dump 💾
|
||
|
|
|
||
|
|
- Enable condition ✅: Takes effect after enabling `MEDIA_DUMP_ENABLE` in `menuconfig`.
|
||
|
|
- Save methods 📤: Supports SD card and UDP outputs (choose one).
|
||
|
|
- SD card 💾: Enable `CONFIG_MEDIA_DUMP_SINK_SDCARD`, output to file `CONFIG_MEDIA_DUMP_SDCARD_FILENAME`, duration controlled by `CONFIG_MEDIA_DUMP_DURATION_SEC`.
|
||
|
|
- UDP 📡: Enable `CONFIG_MEDIA_DUMP_SINK_UDP`, send raw media data via `CONFIG_MEDIA_DUMP_UDP_IP` and `CONFIG_MEDIA_DUMP_UDP_PORT` (can use `script/udp_reciver.py` script).
|
||
|
|
- Save point 🎚️ (before/after AEC processing): Select in "Audio Save Mode (AEC point)" in `menuconfig`
|
||
|
|
- `MEDIA_DUMP_AUDIO_BEFORE_AEC` (Save Before AEC): Save raw microphone audio before AEC (for analyzing noise/feedback)
|
||
|
|
- `MEDIA_DUMP_AUDIO_AFTER_AEC` (Save After AEC): Save audio after AEC processing (for evaluating AEC effectiveness)
|
||
|
|
- Typical usage 🔍: Export raw audio/video data when reproducing issues, check saturation, feedback, and format correctness offline using tools like Audacity.
|
||
|
|
|
||
|
|
## Configuration ⚙️
|
||
|
|
|
||
|
|
### Runtime Configuration (Recommended)
|
||
|
|
|
||
|
|
AFE configuration can be set at runtime via the `afe_config` field in the `audio_recorder_config_t` structure, which takes priority over Kconfig configuration:
|
||
|
|
|
||
|
|
```c
|
||
|
|
audio_recorder_config_t recorder_cfg = DEFAULT_AUDIO_RECORDER_CONFIG();
|
||
|
|
// Configure AFE
|
||
|
|
recorder_cfg.afe_config.ai_mode_wakeup = false; // AI mode: true=wakeup mode, false=direct mode
|
||
|
|
recorder_cfg.afe_config.vad_enable = true; // Enable VAD
|
||
|
|
recorder_cfg.afe_config.vad_mode = 4; // VAD mode (1-4), larger values are more sensitive
|
||
|
|
recorder_cfg.afe_config.vad_min_speech_ms = 64; // Minimum speech duration (ms)
|
||
|
|
recorder_cfg.afe_config.vad_min_noise_ms = 1000; // Minimum noise duration (ms)
|
||
|
|
recorder_cfg.afe_config.agc_enable = true; // Enable AGC
|
||
|
|
recorder_cfg.afe_config.enable_vcmd_detect = false; // Enable VCMD
|
||
|
|
recorder_cfg.afe_config.vcmd_timeout_ms = 5000; // VCMD timeout (ms)
|
||
|
|
recorder_cfg.afe_config.mn_language = "cn"; // Model language: "cn" or "en"
|
||
|
|
recorder_cfg.afe_config.wakeup_time_ms = 10000; // Wakeup time (ms)
|
||
|
|
recorder_cfg.afe_config.wakeup_end_time_ms = 2000; // Wakeup end time (ms)
|
||
|
|
|
||
|
|
// Pass configuration when opening recorder
|
||
|
|
audio_recorder_open(&recorder_cfg);
|
||
|
|
```
|
||
|
|
|
||
|
|
### Kconfig Configuration (Alternative)
|
||
|
|
|
||
|
|
If fields in `audio_recorder_config_t.afe_config` use default values or are not set, Kconfig configuration will be used. Configure via `idf.py menuconfig`:
|
||
|
|
|
||
|
|
#### 💾 Media Dump Configuration
|
||
|
|
|
||
|
|
Configure under **"Component config" -> "Audio/Video Processor Configuration" -> "Media Dump"** in `menuconfig`:
|
||
|
|
|
||
|
|
- **`MEDIA_DUMP_ENABLE`**: Enable media data dump functionality, disabled by default
|
||
|
|
- When enabled, raw audio/video data can be saved for debugging and analysis
|
||
|
|
|
||
|
|
- **`MEDIA_DUMP_AUDIO_POINT`**: Audio save point selection (choice type)
|
||
|
|
- **`MEDIA_DUMP_AUDIO_BEFORE_AEC`**: Save raw audio before AEC processing
|
||
|
|
- Useful for analyzing noise and feedback issues
|
||
|
|
- **`MEDIA_DUMP_AUDIO_AFTER_AEC`**: Save audio after AEC processing
|
||
|
|
- Useful for evaluating AEC processing effectiveness
|
||
|
|
- **`MEDIA_DUMP_AUDIO_NONE`**: Do not save audio (default)
|
||
|
|
|
||
|
|
- **`MEDIA_DUMP_DURATION_SEC`**: Save duration in seconds, default 20
|
||
|
|
- Type: integer (int)
|
||
|
|
- Range: 1-3600 seconds
|
||
|
|
|
||
|
|
- **`MEDIA_DUMP_SINK`**: Save method selection (choice type)
|
||
|
|
- **`MEDIA_DUMP_SINK_SDCARD`**: Save to SD card file (default)
|
||
|
|
- File path configuration: `CONFIG_MEDIA_DUMP_SDCARD_FILENAME` (default: `/sdcard/media_dump.bin`)
|
||
|
|
- Ensure SD card is properly mounted
|
||
|
|
- **`MEDIA_DUMP_SINK_UDP`**: Send via UDP
|
||
|
|
- Target IP configuration: `CONFIG_MEDIA_DUMP_UDP_IP` (default: `192.168.1.100`)
|
||
|
|
- Target port configuration: `CONFIG_MEDIA_DUMP_UDP_PORT` (default: 5000)
|
||
|
|
- Can use `script/udp_reciver.py` script to receive data
|
||
|
|
|
||
|
|
### Task Configuration
|
||
|
|
|
||
|
|
The audio processing component uses multiple FreeRTOS tasks internally, which can be customized via task configuration fields in each module's configuration structure:
|
||
|
|
|
||
|
|
#### Task Configuration for Each Module
|
||
|
|
|
||
|
|
- **Recorder** (`audio_recorder_config_t`):
|
||
|
|
- `afe_feed_task_config`: AFE feed task configuration (default stack size 3KB)
|
||
|
|
- `afe_fetch_task_config`: AFE fetch task configuration (default stack size 3KB)
|
||
|
|
- `recorder_task_config`: Recorder task configuration (default stack size 5KB, recommend >= 40KB when using OPUS encoder)
|
||
|
|
|
||
|
|
- **Player** (`audio_playback_config_t`):
|
||
|
|
- `playback_task_config`: Playback task configuration (default stack size 4KB)
|
||
|
|
|
||
|
|
- **Feeder** (`audio_feeder_config_t`):
|
||
|
|
- `feeder_task_config`: Feeder task configuration (default stack size 5KB, recommend >= 40KB when using OPUS decoder)
|
||
|
|
|
||
|
|
**Important Notes**:
|
||
|
|
- When using OPUS encoder or decoder, `task_stack` of `recorder_task_config` and `feeder_task_config` should be set to at least `4096 * 10` bytes (40KB).
|
||
|
|
- When `task_stack` in task configuration is set to 0, default values will be used.
|
||
|
|
- When `task_stack_in_ext` is set to `true`, task stack will be allocated in external memory, helping to save internal RAM.
|
||
|
|
- Task configuration should be set in each module's configuration structure (e.g., `audio_recorder_config_t`, `audio_playback_config_t`, `audio_feeder_config_t`), not in `audio_manager_config_t`.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## API Reference 📚
|
||
|
|
|
||
|
|
Header files:
|
||
|
|
|
||
|
|
- `include/audio_processor.h`
|
||
|
|
- `include/video_processor.h`
|
||
|
|
- `include/av_processor_type.h`
|
||
|
|
|
||
|
|
Common functions (selection):
|
||
|
|
|
||
|
|
- Audio management:
|
||
|
|
- `audio_manager_init`/`audio_manager_deinit`: Initialize/deinitialize audio manager
|
||
|
|
- Recording:
|
||
|
|
- `audio_recorder_open`: Open recorder (supports encoder configuration and event callback)
|
||
|
|
- `audio_recorder_read_data`: Read recording data
|
||
|
|
- `audio_recorder_pause`/`audio_recorder_resume`: Pause/resume recording
|
||
|
|
- `audio_recorder_get_afe_manager_handle`: Get AFE manager handle
|
||
|
|
- `audio_recorder_close`: Close recorder
|
||
|
|
- Feeder:
|
||
|
|
- `audio_feeder_open`: Open feeder (supports decoder configuration)
|
||
|
|
- `audio_feeder_run`: Start feeder
|
||
|
|
- `audio_feeder_feed_data`: Feed audio data
|
||
|
|
- `audio_feeder_stop`: Stop feeder
|
||
|
|
- `audio_feeder_close`: Close feeder
|
||
|
|
- Playback:
|
||
|
|
- `audio_playback_open`/`audio_playback_close`: Open/close player
|
||
|
|
- `audio_playback_play`: Play audio (supports URL or local file, e.g., `http://...` or `file:///sdcard/...`)
|
||
|
|
- `audio_playback_stop`: Stop playback
|
||
|
|
- `audio_playback_pause`/`audio_playback_resume`: Pause/resume playback
|
||
|
|
- `audio_playback_get_state`: Get playback state
|
||
|
|
- Mixer:
|
||
|
|
- `audio_processor_mixer_open`: Open mixer (must be called after both playback and feeder are opened)
|
||
|
|
- `audio_processor_mixer_close`: Close mixer
|
||
|
|
- `audio_processor_ramp_control`: Control audio focus and volume fade
|
||
|
|
- Video rendering:
|
||
|
|
- `video_render_open`/`video_render_close`: Open/close video renderer
|
||
|
|
- `video_render_start`/`video_render_stop`: Start/stop rendering
|
||
|
|
- `video_render_frame_feed`: Feed video frame
|
||
|
|
- Video capture:
|
||
|
|
- `video_capture_open`/`video_capture_close`: Open/close video capturer
|
||
|
|
- `video_capture_start`/`video_capture_stop`: Start/stop capture
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## FAQ ❓
|
||
|
|
|
||
|
|
### Audio Issues
|
||
|
|
|
||
|
|
- **"Self-questioning" phenomenon occurs (device playback sound is repeatedly captured by microphone)**:
|
||
|
|
- Enable `MEDIA_DUMP_ENABLE` in `menuconfig`, reproduce the issue and export saved audio data for further analysis
|
||
|
|
- Open the exported audio file using [Audacity](https://www.audacityteam.org/download/), observe waveform/spectrum to determine if saturation or feedback exists
|
||
|
|
- If saturation clipping occurs, reduce microphone gain (`esp_codec_dev_set_in_gain`); or appropriately reduce speaker volume (`esp_codec_dev_set_out_vol`) to avoid excessive feedback
|
||
|
|
|
||
|
|
- **Stack overflow when using OPUS encoder/decoder**:
|
||
|
|
- Ensure `task_stack` of `recorder_task_config` and `feeder_task_config` is set to at least `4096 * 10` bytes (40KB)
|
||
|
|
- Consider allocating task stack in external memory (set `task_stack_in_ext = true`)
|
||
|
|
|
||
|
|
- **Mixer not working properly**:
|
||
|
|
- Ensure that both player (`audio_playback_open`) and feeder (`audio_feeder_open`) are opened before calling `audio_processor_mixer_open()`
|
||
|
|
- Ensure `enable_mixer = true` is set when calling `audio_manager_init`
|
||
|
|
|
||
|
|
### Development and Debugging
|
||
|
|
|
||
|
|
- **Modifying component source code (espressif__av_processor)**:
|
||
|
|
- If you need to modify code within `espressif__av_processor`, you can execute the `script/move_av_processor.py` script
|
||
|
|
- The script will copy `managed_components/espressif__av_processor` to your project's `PROJECT_DIR/components/espressif__av_processor` directory
|
||
|
|
- The script will automatically delete the original directory under `managed_components` and update `idf_component.yml`
|
||
|
|
- Before using, set the environment variable: `export PROJECT_DIR=/path/to/project`
|
||
|
|
|
||
|
|
- **Media data dump (Media Dump)**:
|
||
|
|
- UDP method: Can use `script/udp_reciver.py` script to receive UDP data
|
||
|
|
- SD card method: Ensure SD card is properly mounted and file path is accessible
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Version Information
|
||
|
|
|
||
|
|
Current version: v0.5.0
|
||
|
|
|
||
|
|
## License
|
||
|
|
|
||
|
|
This component follows the Apache-2.0 license. See the `LICENSE` file included in the repository for details.
|
||
|
|
|
||
|
|
## Related Resources
|
||
|
|
|
||
|
|
- Project repository: https://github.com/espressif/esp-gmf/tree/main/components/av_processor
|
||
|
|
- Issue reporting: https://github.com/espressif/esp-gmf/issues
|
||
|
|
- Documentation: https://github.com/espressif/esp-gmf/blob/main/components/av_processor/README.md
|