pipeline_play_multi_source_music

Example of the component espressif/gmf_examples v0.8.0
# Multi-Source Audio Player

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

## Example Brief

This example demonstrates a GMF-based multi-source audio player that can play music from HTTP and SD card, and insert playback of Flash-embedded tones at any time; after a tone finishes, the previous source resumes.

- Interactive control via CLI: play, pause, resume, stop, switch source, volume, status, etc.
- Supports MP3, WAV, FLAC, AAC, M4A, TS, AMRNB, AMRWB; default is MP3.

### Typical Scenarios

- In-car music and navigation prompts, music players with tone prompts, or any scenario that needs multiple sources and CLI control.

### Run Flow

- Multiple sources are managed by the Audio Manager; HTTP and SD each have a pipeline, Flash tones use a separate pipeline. Playing a tone pauses the current source and resumes it when the tone ends. CLI commands and state are updated via task communication.

### File Structure

- Example layout:

```
├── components
│   ├── gen_bmgr_codes                   # Board files (auto-generated)
│   │   ├── board_manager.defaults
│   │   ├── CMakeLists.txt
│   │   ├── gen_board_device_config.c
│   │   ├── gen_board_device_handles.c
│   │   ├── gen_board_info.c
│   │   ├── gen_board_periph_config.c
│   │   ├── gen_board_periph_handles.c
│   │   └── idf_component.yml
│   └── tone                             # Tone resource files
│       ├── alarm.mp3
│       ├── CMakeLists.txt
│       ├── dingdong.mp3
│       ├── esp_embed_tone.cmake
│       ├── esp_embed_tone.h
│       ├── haode.mp3
│       └── new_message.mp3
├── main
│   ├── audio_player                     # Audio control logic
│   │   ├── audio_multi_source_player.c
│   │   └── audio_multi_source_player.h
│   ├── command_interface                # Command set
│   │   ├── audio_commands.c
│   │   └── audio_commands.h
│   ├── common
│   │   ├── audio_config.h
│   │   └── audio_types.h
│   ├── CMakeLists.txt
│   ├── idf_component.yml
│   └── play_multi_source_music.c
├── CMakeLists.txt
├── partitions.csv
├── prebuild.ps1
├── prebuild.sh                          # Pre-build script (generates board code, etc.)
├── pytest_play_multi_source_music.py    # Automation test script
├── README.md
└── README_CN.md
```

## Environment Setup

### Hardware Required

- **Board**: ESP32-S3-Korvo V3 by default; other ESP audio boards are also supported.
- **Resource requirements**: microSD card, Wi-Fi, Audio DAC, speaker.

### Default IDF Branch

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

### Software Requirements

- **HTTP source**: Default URL is `https://dl.espressif.com/dl/audio/ff-16b-2c-44100hz.mp3`; can be changed in config or code.
- **SD source**: Default path `/sdcard/test.mp3`; put your audio on the SD card with the correct name.
- **Flash embedded audio**: Uses [embedding binary data](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-guides/build-system.html#cmake-embed-data). `esp_embed_tone.h` and `esp_embed_tone.cmake` are generated by `gmf_io/mk_flash_embed_tone.py`; rerun the script after changing audio files, e.g.:

```
python $YOUR_GMF_PATH/elements/gmf_io/mk_flash_embed_tone.py -p $YOUR_GMF_PATH/gmf_examples/basic_examples/pipeline_play_multi_source_music/components/tone/
```

## Build and Flash

### Build Preparation

Before building this example, ensure the ESP-IDF environment is set up. If it is already set up, skip this paragraph and go to the project directory and run the pre-build script(s) as follows. If not, run the following in the ESP-IDF root directory to complete the 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
```

Short steps:

- Go to this example's project directory:

```
cd $YOUR_GMF_PATH/gmf_examples/basic_examples/pipeline_play_multi_source_music
```

- Run the pre-build script: follow the prompts to select the target chip, set up the IDF Action extension, and use `esp_board_manager` to select a supported board. For a custom board, see [Custom board](https://github.com/espressif/esp-gmf/blob/main/packages/esp_board_manager/README.md#custom-board).

On Linux / macOS:
```bash/zsh
source prebuild.sh
```

On Windows:
```powershell
.\prebuild.ps1
```

### Project Configuration

- Configure Wi-Fi SSID and password in menuconfig for HTTP playback.
- To adjust audio effect parameters (sample rate, channels, bit depth), configure GMF Audio options in menuconfig.

```bash
idf.py menuconfig
```

In menuconfig:

- `GMF APP Configuration` → `Example Connection Configuration` → `WiFi SSID`
- `GMF APP Configuration` → `Example Connection Configuration` → `WiFi Password`
- `ESP GMF Loader` → `GMF Audio Configurations` → `GMF Audio Effects` → `Channel Convert Destination Channel`
- `ESP GMF Loader` → `GMF Audio Configurations` → `GMF Audio Effects` → `Bit Convert Destination Bits`
- `ESP GMF Loader` → `GMF Audio Configurations` → `GMF Audio Effects` → `Rate Convert Destination Rate`

> Press `s` to save and `Esc` to exit after configuration.

### Build and Flash Commands

- Build the example:

```
idf.py build
```

- Flash the firmware and run the serial monitor (replace PORT with your port name):

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

- To exit the monitor, use `Ctrl-]`

## How to Use the Example

### Functionality and Usage

After startup the example will:
1. Initialize Wi-Fi (for HTTP source)
2. Initialize SD card (for SD source)
3. Create the audio pipeline and register CLI commands
4. Start playing from SD card by default

You can use the following CLI commands in the serial terminal:

- `play` - Start playback from current source
- `pause` - Pause playback
- `resume` - Resume playback
- `stop` - Stop playback
- `switch [http|sdcard]` - Switch source (no argument toggles HTTP/SD)
- `get_vol` - Get current volume (0-100)
- `set_vol <0-100>` - Set volume (0-100)
- `status` - Show playback status
- `tone` - Play Flash embedded tone (pauses current, plays tone, then resumes)
- `exit` - Exit the application
- `help` - List all commands

### Log Output

- After startup the example initializes the audio manager and CLI, starts from SD by default, and prints available commands.

```
I (946) main_task: Calling app_main()
I (947) MULTI_SOURCE_PLAYER: === Multi-Source Audio Player ===
I (952) MULTI_SOURCE_PLAYER: Initializing SD card
I (956) 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: SA32G
Type: SDHC
Speed: 40.00 MHz (limit: 40.00 MHz)
Size: 29544MB
CSD: ver=2, sector_size=512, capacity=60506112 read_bl_len=9
SSR: bus_width=1
I (1017) DEV_FS_FAT: Filesystem mounted, base path: /sdcard
I (1022) BOARD_MANAGER: Device fs_sdcard initialized
I (1027) MULTI_SOURCE_PLAYER: Initializing audio codec
I (1033) PERIPH_I2S: I2S[0] TDM,  TX, ws: 45, bclk: 9, dout: 8, din: 10
I (1038) PERIPH_I2S: I2S[0] initialize success: 0x3c1f7df8
I (1043) DEV_AUDIO_CODEC: DAC is ENABLED
I (1047) DEV_AUDIO_CODEC: Init audio_dac, i2s_name: i2s_audio_out, i2s_rx_handle:0x0, i2s_tx_handle:0x3c1f7df8, data_if: 0x3fcead8c
I (1059) PERIPH_I2C: I2C master bus initialized successfully
I (1069) ES8311: Work in Slave mode
I (1072) DEV_AUDIO_CODEC: Successfully initialized codec: audio_dac
I (1073) DEV_AUDIO_CODEC: Create esp_codec_dev success, dev:0x3fceafe0, chip:es8311
I (1080) BOARD_MANAGER: Device audio_dac initialized
I (1086) I2S_IF: channel mode 2 bits:16/16 channel:2 mask:3
I (1091) I2S_IF: TDM Mode 1 bits:16/16 channel:2 sample_rate:16000 mask:3
I (1112) Adev_Codec: Open codec device OK
I (1112) MULTI_SOURCE_PLAYER: Peripheral devices initialized successfully
I (1119) example_connect: Start example_connect.
I (1119) pp: pp rom version: e7ae62f
I (1120) net80211: net80211 rom version: e7ae62f
I (1125) wifi:wifi driver task: 3fcee81c, prio:23, stack:6656, core=0
I (1132) wifi:wifi firmware version: 4df78f2
I (1133) wifi:wifi certification version: v7.0
I (1138) wifi:config NVS flash: enabled
I (1141) wifi:config nano formatting: disabled
I (1145) wifi:Init data frame dynamic rx buffer num: 32
I (1150) wifi:Init static rx mgmt buffer num: 5
I (1155) wifi:Init management short buffer num: 32
I (1159) wifi:Init dynamic tx buffer num: 32
I (1163) wifi:Init static tx FG buffer num: 2
I (1167) wifi:Init static rx buffer size: 1600
I (1171) wifi:Init static rx buffer num: 10
I (1175) wifi:Init dynamic rx buffer num: 32
I (1180) wifi_init: rx ba win: 6
I (1182) wifi_init: accept mbox: 6
I (1185) wifi_init: tcpip mbox: 32
I (1188) wifi_init: udp mbox: 6
I (1191) wifi_init: tcp mbox: 6
I (1194) wifi_init: tcp tx win: 5760
I (1197) wifi_init: tcp rx win: 5760
I (1201) wifi_init: tcp mss: 1440
I (1204) wifi_init: WiFi IRAM OP enabled
I (1207) wifi_init: WiFi RX IRAM OP enabled
I (1212) phy_init: phy_version 711,97bcf0a2,Aug 25 2025,19:04:10
I (1253) wifi:mode : sta (7c:df:a1:e7:71:6c)
I (1253) wifi:enable tsf
I (1255) example_connect: Connecting to ESP-Audio...
W (1256) wifi:Password length matches WPA2 standards, authmode threshold changes from OPEN to WPA2
I (1263) example_connect: Waiting for IP(s)
I (3733) wifi:new:<4,0>, old:<1,0>, ap:<255,255>, sta:<4,0>, prof:1, snd_ch_cfg:0x0
I (3734) wifi:state: init -> auth (0xb0)
I (3737) wifi:state: auth -> assoc (0x0)
I (3742) wifi:state: assoc -> run (0x10)
I (3749) wifi:<ba-add>idx:0 (ifx:0, 18:31:bf:4b:8b:68), tid:0, ssn:0, winSize:64
I (3760) wifi:connected with ESP-Audio, aid = 4, channel 4, BW20, bssid = 18:31:bf:4b:8b:68
I (3760) wifi:security: WPA2-PSK, phy: bgn, rssi: -30
I (3762) wifi:pm start, type: 1

I (3765) wifi:dp: 1, bi: 102400, li: 3, scale listen interval from 307200 us to 307200 us
I (3773) wifi:set rx beacon pti, rx_bcn_pti: 0, bcn_timeout: 25000, mt_pti: 0, mt_time: 10000
I (3816) wifi:AP's beacon interval = 102400 us, DTIM period = 3
I (5120) example_connect: Got IPv6 event: Interface "example_netif_sta" address: fe80:0000:0000:0000:7edf:a1ff:fee7:716c, type: ESP_IP6_ADDR_IS_LINK_LOCAL
I (5953) esp_netif_handlers: example_netif_sta ip: 162.168.10.35, mask: 255.255.255.0, gw: 162.168.10.1
I (5953) example_connect: Got IPv4 event: Interface "example_netif_sta" address: 162.168.10.35
I (5960) example_common: Connected to example_netif_sta
I (5964) example_common: - IPv4 address: 162.168.10.35,
I (5969) example_common: - IPv6 address: fe80:0000:0000:0000:7edf:a1ff:fee7:716c, type: ESP_IP6_ADDR_IS_LINK_LOCAL
I (5979) MULTI_SOURCE_PLAYER: Initializing audio manager
I (5984) AUDIO_MULTI_SRC_PLAYER: Initializing audio manager
I (5992) AUDIO_MULTI_SRC_PLAYER: Audio manager initialized successfully
I (5996) MULTI_SOURCE_PLAYER: Initializing command interface
I (6002) MULTI_SOURCE_PLAYER: Setting up CLI

Type 'help' to get the list of commands.
Use UP/DOWN arrows to navigate through command history.
Press TAB when typing command name to auto-complete.
I (6064) MULTI_SOURCE_PLAYER: Starting initial playback from SD card
I (6078) ESP_GMF_FILE: Open, dir:1, uri:/sdcard/test.mp3
I (6079) AUDIO_MULTI_SRC_PLAYER: Successfully switched to source 1
I (6082) ESP_GMF_FILE: File size: 39019 byte, file position: 0
I (6093) ESP_GMF_PORT: ACQ IN, new self payload:0x3c1fa934, port:0x3c1fa8dc, el:0x3c1fa268-aud_dec
I (6093) MULTI_SOURCE_PLAYER: === Multi-Source Audio Player Ready ===
I (6102) ESP_ES_PARSER: The verion of es_parser is v1.0.0
W (6111) ESP_GMF_ASMP_DEC: Not enough memory for out, need:2304, old: 1024, new: 2304
Audio>  I (6270) AUDIO_MULTI_SRC_PLAYER: Music info: sample_rates=16000, bits=16, ch=2
I (6112) MULTI_SOURCE_PLAYER: Available commands:
I (6285) MULTI_SOURCE_PLAYER:   play      - Start playback
I (6286) MULTI_SOURCE_PLAYER:   pause     - Pause playback
I (6297) MULTI_SOURCE_PLAYER:   resume    - Resume playback
I (6298) MULTI_SOURCE_PLAYER:   stop      - Stop playback
I (6299) MULTI_SOURCE_PLAYER:   switch    - Switch audio source (http or sdcard, or use without arg to toggle)
I (6311) MULTI_SOURCE_PLAYER:   tone      - Play flash tone (pauses current, plays tone, then resumes)
I (6323) MULTI_SOURCE_PLAYER:   get_vol   - Get current volume (0-100)
I (6324) MULTI_SOURCE_PLAYER:   set_vol   - Set volume (0-100)
I (6337) MULTI_SOURCE_PLAYER:   status    - Show playback status
I (6337) MULTI_SOURCE_PLAYER:   exit      - Exit the application
I (6349) MULTI_SOURCE_PLAYER:   help      - Show all available commands
I (6350) MULTI_SOURCE_PLAYER: Entering main application loop
Audio>
```

### Using CLI commands example

In the serial terminal you can type: `switch http` / `switch sdcard` to switch source, `pause` / `resume` to pause/resume, `set_vol 80` / `get_vol` for volume, `tone` to play the Flash tone (current playback is paused then resumed), `status` for status, `exit` to quit.

```
Audio>  tone
I (10746) AUDIO_MULTI_SRC_PLAYER: Starting flash tone playback
I (10747) AUDIO_MULTI_SRC_PLAYER: Pausing current playback
I (10758) AUDIO_MULTI_SRC_PLAYER: Flash tone playback started
I (10759) ESP_GMF_EMBED_FLASH: The read item is 0, embed://tone/0
I (10760) ESP_GMF_PORT: ACQ IN, new self payload:0x3c206534, port:0x3c206350, el:0x3c1fc97c-aud_dec
I (10772) ESP_ES_PARSER: The verion of es_parser is v1.0.0
W (10785) ESP_GMF_ASMP_DEC: Not enough memory for out, need:4608, old: 1024, new: 4608
Audio>  tonW (13850) ESP_GMF_EMBED_FLASH: No more data, ret:0, pos: 36018/36018
I (13851) ESP_GMF_EMBED_FLASH: Closed, pos: 36018/36018
I (13852) ESP_GMF_CODEC_DEV: CLose, 0x3c206390, pos = 190636/0
I (13865) AUDIO_MULTI_SRC_PLAYER: Flash playback finished, restoring original playback
I (13866) AUDIO_MULTI_SRC_PLAYER: Restoring original playback: source=1, was_playing=1
I (13878) AUDIO_MULTI_SRC_PLAYER: Resuming original playback
Audio>  tone
I (14494) AUDIO_MULTI_SRC_PLAYER: Starting flash tone playback
I (14495) AUDIO_MULTI_SRC_PLAYER: Pausing current playback
I (14507) AUDIO_MULTI_SRC_PLAYER: Flash tone playback started
I (14508) ESP_GMF_EMBED_FLASH: The read item is 1, embed://tone/1
I (14509) ESP_ES_PARSER: The verion of es_parser is v1.0.0
Audio>  W (14987) ESP_GMF_EMBED_FLASH: No more data, ret:0, pos: 8527/8527
I (14989) ESP_GMF_EMBED_FLASH: Closed, pos: 8527/8527
I (14989) ESP_GMF_CODEC_DEV: CLose, 0x3c206390, pos = 25080/0
I (15002) AUDIO_MULTI_SRC_PLAYER: Flash playback finished, restoring original playback
I (15002) AUDIO_MULTI_SRC_PLAYER: Restoring original playback: source=1, was_playing=1
I (15014) AUDIO_MULTI_SRC_PLAYER: Resuming original playback
I (17493) ESP_GMF_FILE: No more data, ret: 0
I (17497) ESP_GMF_FILE: CLose, 0x3c1fc484, pos = 39019/39019
I (17498) ESP_GMF_CODEC_DEV: CLose, 0x3c1faa28, pos = 493816/0
Audio>  switch
I (20119) AUDIO_COMMANDS: Switching from SD card to http
I (20121) AUDIO_MULTI_SRC_PLAYER: Successfully switched to source 0
I (20121) NEW_DATA_BUS: New block buf, num:1, item_cnt:32768, db:0x3c1fa8dc
I (20134) ESP_GMF_HTTP: HTTP Open, URI = https://dl.espressif.com/dl/audio/ff-16b-2c-44100hz.mp3
Audio>  I (21261) esp-x509-crt-bundle: Certificate validated
I (23379) ESP_GMF_HTTP: The total size is 0 bytes
I (23719) esp-x509-crt-bundle: Certificate validated
I (23938) ESP_GMF_HTTP: The total size is 2994349 bytes
I (23940) ESP_GMF_PORT: ACQ IN, new self payload:0x3c2042a0, port:0x3c1fc7f4, el:0x3c1fa268-aud_dec
I (23983) ESP_ES_PARSER: The verion of es_parser is v1.0.0
W (23987) ESP_GMF_ASMP_DEC: Not enough memory for out, need:4608, old: 2304, new: 4608
I (24154) AUDIO_MULTI_SRC_PLAYER: Music info: sample_rates=16000, bits=16, ch=2
Audio>
Audio>  tone
I (31157) AUDIO_MULTI_SRC_PLAYER: Starting flash tone playback
I (31158) AUDIO_MULTI_SRC_PLAYER: Pausing current playback
I (31161) AUDIO_MULTI_SRC_PLAYER: Flash tone playback started
I (31161) ESP_GMF_EMBED_FLASH: The read item is 2, embed://tone/2
I (31175) ESP_ES_PARSER: The verion of es_parser is v1.0.0
Audio>  W (31594) ESP_GMF_EMBED_FLASH: No more data, ret:0, pos: 6384/6384
I (31595) ESP_GMF_EMBED_FLASH: Closed, pos: 6384/6384
I (31596) ESP_GMF_CODEC_DEV: CLose, 0x3c206390, pos = 27896/0
I (31608) AUDIO_MULTI_SRC_PLAYER: Flash playback finished, restoring original playback
I (31609) AUDIO_MULTI_SRC_PLAYER: Restoring original playback: source=0, was_playing=1
I (31621) AUDIO_MULTI_SRC_PLAYER: Resuming original playback
Audio>  status
I (35241) AUDIO_COMMANDS: Playback Status:
I (35242) AUDIO_COMMANDS:   Source: HTTP
I (35242) AUDIO_COMMANDS:   State: Playing
I (35243) AUDIO_COMMANDS:   Flash tone playing: No
I (35254) AUDIO_COMMANDS:   Volume: 80 (range: 0-100)
```

## Troubleshooting

### HTTP playback fails or keeps reconnecting

- Confirm WiFi SSID and Password in menuconfig are correct and the device is on the same network as the router. For HTTPS certificate verification errors, see the SSL troubleshooting in the pipeline_play_http_music example.

### SD or Flash tone does not play

- **SD**: Ensure `/sdcard/test.mp3` (or your configured path) exists on the card and format is correct. **Flash tone**: Ensure you have run `mk_flash_embed_tone.py` to generate `esp_embed_tone.h` and `esp_embed_tone.cmake`, and that the required audio files are under `components/tone/`.

## Technical Support

For technical support, use the links below:

- Technical support: [esp32.com](https://esp32.com/viewforum.php?f=20) forum
- Issue reports and feature requests: [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=0.8.0:pipeline_play_multi_source_music"

or download archive (~99.83 KB)