pipeline_record_audio_muxer

Example of the component espressif/gmf_examples v1.0.0
# Recording Audio to a microSD Card with Muxer

- [中文版](./README_CN.md)
- Example Difficulty: ⭐

## Example Overview

This example captures audio from the codec through CODEC_DEV_RX IO, encodes it with `aud_enc`, then multiplexes the encoded data into multiple container formats with the muxer element and saves it to a microSD card.

- Pipeline architecture: `io_codec_dev` → `aud_enc` → `aud_muxer` (file output).
- Supports multiple container formats
- The muxer can be configured to write files or output through databus; this example uses **file output** mode.

### Typical Scenarios

- Local recording archives that require container encapsulation (MP4/TS/WAV, etc.), such as meeting recording and voice recorder scenarios.
- For **lossless or high-fidelity archiving**, you can use combinations such as **ALAC + MP4/CAF** (ALAC encoder and corresponding muxer support must be enabled in the project first).

## Feature Description

### Containers and Codec Formats

- **Container formats supported by `aud_muxer`**: TS, MP4, FLV, WAV, CAF, OGG, AVI. You can switch by modifying `DEFAULT_RECODER_MUXER_TYPE`
- **Codec-container compatibility is required**: each container supports only part of codec tracks (for example, OGG commonly pairs with OPUS). See [Muxer documentation](https://github.com/espressif/esp-adf-libs/blob/master/esp_muxer/README.md)
- **Lossless recording with ALAC**: with ALAC encoder enabled, set codec to ALAC and select a container that supports this track (such as **MP4**, **CAF**, depending on actual component support) to get **compressed lossless** archives; compared with **uncompressed PCM**, ALAC takes less space.
- **Lossy / lossless (brief)**:
  - **Lossy**: AAC, OPUS, AMR, ADPCM, SBC, LC3, G711, etc. (irreversible approximation after compression).
  - **Lossless**: **ALAC** (compressed lossless), **PCM** / linear PCM encapsulation (such as some WAV cases, with no perceptual codec quality loss).

### Output Modes: Streaming Output vs File Output

`aud_muxer` uses `output_type` (type `esp_gmf_audio_muxer_output_type_t`) to distinguish two output paths:

| Mode | Enum Value | Behavior |
|------|------------|----------|
| **Streaming output** | `ESP_GMF_AUDIO_MUXER_OUTPUT_STREAMING` | Muxed data is sent to pipeline **downstream** through **databus**; output IO **must be attached** when creating the pipeline (such as `io_file`, `io_http`), and this IO reads the stream from databus and writes to file or network. **Setting only `output_type` without attaching output IO cannot complete local write/stream push.** |
| **File output** | `ESP_GMF_AUDIO_MUXER_OUTPUT_FILE` | The muxer writes to storage directly through the **`url_pattern` callback**; output-side IO can be **`NULL`** when creating the pipeline (this example uses `esp_gmf_pool_new_pipeline(..., NULL)`). |

### File Slicing (File Output Mode Only)

- For long-time recording, writing only one huge file is not convenient for copy and abnormal recovery. With slicing enabled, the muxer generates multiple files by time length. The file name/path is decided by the registered **`url_pattern` callback** (this example uses `muxer_file_pattern_cb`; users can modify this function to support custom file names and paths), and usually includes an **incremental `slice_index`** (for example, `esp_gmf_muxer_000.mp4`, `esp_gmf_muxer_001.mp4`).
- **Meaning of `slice_duration`**: the **target duration** of each segment, in **milliseconds (ms)**. When this duration is reached (or component-defined slicing condition is met), the current file is closed and the next segment starts. For example, `60000` means about 60 seconds per file.

## Environment Configuration

### Hardware Requirements

- **Development board**: ESP32-S3-Korvo V3 is used by default; other ESP audio boards are also applicable.
- **Required resources**: microSD card, microphone, Audio ADC.

### Default IDF Branch

This example supports IDF release/v5.4 (>= v5.4.3) and release/v5.5 (>= v5.5.2).

## Build and Flash

### Build Preparation

Before building this example, make sure the ESP-IDF environment is configured. If it is already configured, you can skip this section and directly enter the project directory. If not, run the following scripts in the ESP-IDF root directory to complete environment setup. For full steps, see the [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/index.html).

```
./install.sh
. ./export.sh
```

Quick steps:

- Enter this example project directory:

```
cd $YOUR_GMF_PATH/gmf_examples/basic_examples/pipeline_record_audio_muxer
```

This example uses [ESP Board Manager](https://github.com/espressif/esp-board-manager) to manage board-level resources. The [`esp-bmgr-assist`](https://pypi.org/project/esp-bmgr-assist/) helper tool is recommended as the default entry point.

- Install once in your activated ESP-IDF Python environment:

```bash
pip install esp-bmgr-assist
pip install --upgrade esp-bmgr-assist
```

- List supported boards:

```bash
idf.py bmgr -l
```

  Example output:

```text
ℹ️  Main Boards:
  [1] dual_eyes_board_v1_0
  [2] esp32_c3_lyra
  [3] esp32_c5_spot
  [4] esp32_p4_function_ev
  [5] esp32_s3_korvo2_v3
  [6] esp32_s3_korvo2l
  [7] esp_box_3
  [8] esp_box_lite
  [9] esp_hi
```

- Select a board:

```bash
idf.py bmgr -b <board_index|board_name>
```

  For example, to select `esp32_s3_korvo2_v3`:

```bash
idf.py bmgr -b 5
# or
idf.py bmgr -b esp32_s3_korvo2_v3
```

  On first invocation, the component is downloaded automatically based on the `espressif/esp_board_manager` dependency declared in `main/idf_component.yml`.

> [!NOTE]
> To switch to a different board supported by `esp_board_manager`, repeat the same steps with the new board name or index.
> For a custom board, see [How to customize board](https://github.com/espressif/esp-board-manager/blob/main/esp_board_manager/docs/how_to_customize_board.md).
> For more information about `esp_board_manager`, see the [ESP Board Manager Getting Started Guide](https://github.com/espressif/esp-board-manager/blob/main/esp_board_manager/README.md).

### Project Configuration

In source file `main/record_muxer.c`, behavior can be adjusted through the following macros and related muxer configuration items:

- `DEFAULT_RECORD_SAMPLE_RATE`: sample rate (for example, 48000 Hz)
- `DEFAULT_RECORD_CHANNEL`: channel count (for example, 2ch)
- `DEFAULT_RECORD_BITS`: sample bit depth (for example, 16bit)
- `DEFAULT_RECORD_BITRATE`: encoding bitrate (for example, 90000bps)
- `DEFAULT_RECODER_CODEC_TYPE`: codec type (for example, `ESP_AUDIO_TYPE_ALAC`)
- `DEFAULT_RECODER_MUXER_TYPE`: muxer container type (for example, `ESP_MUXER_TYPE_MP4`)
- `DEFAULT_RECODER_MUXER_SLICE_DURATION`: slice duration (milliseconds), assigned to muxer `slice_duration` (default in example is 60000, about 60 seconds per segment; whether `0` is supported to disable slicing depends on component behavior)

Recorded muxed files are written to microSD (path pattern can be found in `muxer_file_pattern_cb` in source code).

### Build and Flash

- Build the example

```
idf.py build
```

- Flash and run monitor to view serial output (replace PORT with your port name):

```
idf.py -p PORT flash monitor
```

- Exit monitor with `Ctrl+]`

## How to Use the Example

### Function and Usage

- After power-on, the example mounts microSD, initializes recording codec, and starts recording with configured codec and muxer type.
- After recording for a while, it stops automatically, writes encapsulated files to the card (for example, `/sdcard/esp_gmf_muxer_000.mp4`), and then releases resources.

### Log Output

- In normal flow, logs print peripheral initialization, element registration, creation of pipeline with encoder and muxer, muxer configuration, task binding, event listening, pipeline startup, muxer output path, etc.

```
I (844) main_task: Calling app_main()
I (846) REC_MUXER: [ 1 ] Setup peripheral for audio codec device and sdcard
I (853) DEV_FS_FAT_SUB_SDMMC: slot_config: cd=-1, wp=-1, clk=15, cmd=7, d0=4, d1=-1, d2=-1, d3=-1, d4=-1, d5=-1, d6=-1, d7=-1, width=1, flags=0x1
Name: SD
Type: SDHC
Speed: 40.00 MHz (limit: 40.00 MHz)
Size: 29818MB
CSD: ver=2, sector_size=512, capacity=61067264 read_bl_len=9
SSR: bus_width=1
I (913) DEV_FS_FAT: Filesystem mounted, base path: /sdcard
I (918) BOARD_MANAGER: Device fs_sdcard initialized
I (923) DEV_AUDIO_CODEC: ADC is ENABLED
I (927) PERIPH_I2S: I2S[0] TDM, RX, ws: 45, bclk: 9, dout: 8, din: 10
I (932) PERIPH_I2S: I2S[0] initialize success: 0x3c10d194
I (938) DEV_AUDIO_CODEC: Init audio_adc, i2s_name: i2s_audio_in, i2s_rx_handle:0x3c10d194, i2s_tx_handle:0x3c10cfac, data_if: 0x3fcee908
I (950) PERIPH_I2C: I2C master bus initialized successfully
I (958) ES7210: Work in Slave mode
I (965) ES7210: Enable ES7210_INPUT_MIC1
I (967) ES7210: Enable ES7210_INPUT_MIC2
I (970) ES7210: Enable ES7210_INPUT_MIC3
I (973) ES7210: Enable TDM mode
I (976) DEV_AUDIO_CODEC: Successfully initialized codec: audio_adc
I (978) DEV_AUDIO_CODEC: Create esp_codec_dev success, dev:0x3fceeb64, chip:es7210
I (985) BOARD_MANAGER: Device audio_adc initialized
I (990) BOARD_DEVICE: Device handle audio_adc found, Handle: 0x3fcea070 TO: 0x3fcea070
I (1000) I2S_IF: channel mode 2 bits:16/16 channel:2 mask:1
I (1003) I2S_IF: TDM Mode 0 bits:16/16 channel:2 sample_rate:48000 mask:1
I (1009) I2S_IF: channel mode 2 bits:16/16 channel:2 mask:1
I (1014) I2S_IF: TDM Mode 1 bits:16/16 channel:2 sample_rate:48000 mask:1
I (1022) ES7210: Bits 8
I (1030) ES7210: Enable ES7210_INPUT_MIC1
I (1033) ES7210: Enable ES7210_INPUT_MIC2
I (1036) ES7210: Enable ES7210_INPUT_MIC3
I (1039) ES7210: Enable TDM mode
I (1044) ES7210: Unmuted
I (1044) Adev_Codec: Open codec device OK
I (1044) REC_MUXER: [ 2 ] Register all the elements and set audio information to record codec device
I (1052) GMF_SETUP_AUD_MUXER: Muxer config: type=538989396, output_type=0, codec=541278529
I (1060) GMF_SETUP_AUD_MUXER: Audio muxer initialized, type: 538989396, codec: 541278529
I (1068) ESP_GMF_POOL: Registered items on pool:0x3c10d8dc, app_main-120
I (1074) ESP_GMF_POOL: IO, Item:0x3c10d9f4, H:0x3c10d8f0, TAG:io_codec_dev
I (1081) ESP_GMF_POOL: EL, Item:0x3c10db10, H:0x3c10da04, TAG:aud_enc
I (1087) ESP_GMF_POOL: EL, Item:0x3c10dc18, H:0x3c10db20, TAG:aud_muxer
I (1093) REC_MUXER: [ 3 ] Create audio pipeline with encoder and muxer
I (1100) REC_MUXER: [ 3.1 ] Configure muxer element
I (1104) REC_MUXER: [ 3.2 ] Reconfig audio encoder type and report information to the record pipeline
I (1113) REC_MUXER: [ 3.3 ] Create gmf task, bind task to pipeline and load linked element jobs to the bind task
I (1123) ESP_GMF_TASK: Waiting to run... [tsk:gmf_rec_muxer-0x3fcede00, wk:0x0, run:0]
I (1131) ESP_GMF_TASK: Waiting to run... [tsk:gmf_rec_muxer-0x3fcede00, wk:0x3c10f05c, run:0]
I (1139) REC_MUXER: [ 3.4 ] Create event group and listening event from pipeline
I (1146) REC_MUXER: [ 4 ] Start audio_pipeline
I (1150) REC_MUXER: CB: RECV Pipeline EVT: el:NULL-0x3c10dc28, type:8192, sub:ESP_GMF_EVENT_STATE_OPENING, payload:0x0, size:0,0x0
I (1164) ESP_GMF_AENC: Open, type:ALAC, acquire in frame: 8192, out frame: 8200
I (1169) ESP_GMF_TASK: One times job is complete, del[wk:0x3c10f05c, ctx:0x3c10dc6c, label:aud_enc_open]
I (1178) ESP_GMF_PORT: ACQ IN, new self payload:0x3c10f05c, port:0x3c10dff4, el:0x3c10dc6c-aud_enc
I (1187) REC_MUXER: [ 5 ] Wait for a while to stop record pipeline
I (1263) ESP_GMF_MUXER: Open muxer element, type: 540299341, output_type: 1 sample_rate: 48000, channel: 1, bits: 16
I (1263) REC_MUXER: CB: RECV Pipeline EVT: el:aud_muxer-0x3c10dd78, type:8192, sub:ESP_GMF_EVENT_STATE_RUNNING, payload:0x0, size:0,0x0
I (1274) ESP_GMF_TASK: One times job is complete, del[wk:0x3c10f138, ctx:0x3c10dd78, label:aud_muxer_open]
I (1284) REC_MUXER: Muxer file pattern: /sdcard/esp_gmf_muxer_000.mp4 (slice index: 0)
I (1305) MP4_MUXER: Set track limit 6000

I (11220) ESP_GMF_CODEC_DEV: CLose, 0x3c10def0, pos = 901120/0
I (11221) ESP_GMF_TASK: One times job is complete, del[wk:0x3c10f080, ctx:0x3c10dc6c, label:aud_enc_close]
I (11242) ESP_GMF_TASK: One times job is complete, del[wk:0x3c10f0bc, ctx:0x3c10dd78, label:aud_muxer_close]
I (11242) REC_MUXER: CB: RECV Pipeline EVT: el:NULL-0x3c10dc28, type:8192, sub:ESP_GMF_EVENT_STATE_STOPPED, payload:0x0, size:0,0x0
I (11252) ESP_GMF_TASK: Waiting to run... [tsk:gmf_rec_muxer-0x3fcede00, wk:0x0, run:0]
I (11259) ESP_GMF_TASK: Waiting to run... [tsk:gmf_rec_muxer-0x3fcede00, wk:0x0, run:0]
I (11267) REC_MUXER: [ 6 ] Destroy all the resources
W (11272) GMF_SETUP_AUD_CODEC: Unregistering default encoder
I (11277) BOARD_DEVICE: Deinit device audio_adc ref_count: 0 device_handle:0x3fcea070
I (11288) BOARD_DEVICE: Device audio_adc config found: 0x3c0dd86c (size: 92)
I (11291) BOARD_PERIPH: Deinit peripheral i2s_audio_in ref_count: 0
E (11297) i2s_common: i2s_channel_disable(1262): the channel has not been enabled yet
W (11305) PERIPH_I2S: Caution: Releasing RX (0x0).
I (11309) BOARD_PERIPH: Deinit peripheral i2c_master ref_count: 0
I (11315) PERIPH_I2C: I2C master bus deinitialized successfully
I (11321) BOARD_MANAGER: Device audio_adc deinitialized
I (11326) BOARD_DEVICE: Deinit device fs_sdcard ref_count: 0 device_handle:0x3fce9a7c
I (11333) BOARD_DEVICE: Device fs_sdcard config found: 0x3c0dd818 (size: 84)
I (11340) DEV_FS_FAT: Sub device 'sdmmc' deinitialized successfully
I (11346) BOARD_MANAGER: Device fs_sdcard deinitialized
I (11351) main_task: Returned from app_main()
```

## Troubleshooting

### microSD Card Not Mounted or Not Writable

- Make sure the microSD card is inserted correctly and formatted as FAT32.
- If logs show file open failure, check card capacity and write-protect status.

### No Recording, Encoding, or Muxer Initialization Failure

- Make sure board-level recording codec and I2S are configured correctly.
- Make sure the **muxer type and codec type** combination is valid (for example, OGG requires OPUS).
- If encoder initialization fails, check whether the corresponding codec format is enabled in menuconfig.

### Related References

- If you only need encoded raw stream file output without container encapsulation, or if you need low-power features, refer to [pipeline_record_sdcard](../pipeline_record_sdcard/README.md) in the same directory.
- The current example only supports audio recording and encapsulation. If you need packaging support for video-related capability, refer to [esp_capture](../../../packages/esp_capture/README.md).

## Technical Support

Get technical support from the following links:

- Technical support forum: [esp32.com](https://esp32.com/viewforum.php?f=20)
- For issue reports and feature requests, create a [GitHub issue](https://github.com/espressif/esp-gmf/issues)

We will reply as soon as possible.

To create a project from this example, run:

idf.py create-project-from-example "espressif/gmf_examples=1.0.0:pipeline_record_audio_muxer"

or download archive (~17.22 KB)