# ESP Playlist

[English]

## 简介

ESP Playlist 是面向乐鑫多媒体应用的媒体库与播放列表管理组件，由媒体库与播放列表两个独立模块组成。媒体库记录设备上有哪些媒体文件的名称与地址，播放列表记录播放顺序与当前播放位置。组件提供目录扫描、媒体库持久化、播放列表 JSON 导出与导入、多实例管理，以及顺序、单曲循环、列表循环和随机播放等模式，适用于本地音乐播放器与有声内容设备。

## 功能清单

- 目录扫描：按递归深度、扩展名和自定义回调过滤指定目录下的媒体文件，批量加入媒体库

- 媒体库持久化：文件系统存储时数据落盘，重启后可重新加载；RAM 存储时仅在运行期有效

- 播放列表构建：从媒体库按条件过滤导入，或从 JSON 文件/内存缓冲区加载

- 播放列表导出：生成 JSON 格式，可保存到文件、NVS 或用于网络下发

- 多实例管理：可同时创建多个媒体库和播放列表句柄，独立维护各自状态

- 条件过滤：按 `name`、`url`、`id` 等字段做精确匹配、包含匹配或前缀匹配，并支持 AND/OR 组合

- 播放模式：不循环、单曲循环、列表循环、随机播放，配合当前曲目导航接口切换

## 技术拆解

### 媒体库（esp_media_db）

媒体库是媒体文件的目录索引，只保存 `name` 和 `url`，不解析媒体内容本身。`esp_media_db_init()` 创建句柄时通过 `esp_media_db_cfg_t` 的 `storage_type` 选择存储方式：`esp_db_storage_type_t` 取值 `ESP_DB_STORAGE_FS` 表示数据落盘到 `storage_path` 指向的文件系统三文件数据库，重启后可用 `esp_media_db_load()` 重新加载；取值 `ESP_DB_STORAGE_RAM` 表示数据只保存在堆内存中，适合无需持久化、频繁重建的场景。

    esp_media_db_cfg_t db_cfg = {
        .storage_type = ESP_DB_STORAGE_FS,
        .storage_path = "/sdcard/__playlist",
    };
    esp_media_db_handle_t media_db = NULL;
    esp_media_db_init(&db_cfg, &media_db);
    esp_media_db_load(media_db);  /* storage_path 下已有数据库文件时先加载 */

收录文件有两种方式：`esp_media_db_scan()` 按 `esp_media_db_scan_cfg_t` 中的 `path`、`scan_depth`、`file_extensions` 递归扫描目录，可选 `filter_cb` 对扫描到的每个 URL 做二次判定；`esp_media_db_add()` 则直接写入调用方已知的 `name` / `url` 条目。 `skip_duplicate` 只作用于 scan：媒体库为空时始终正常加入；媒体库已有条目时，`skip_duplicate = true` 表示不比较 URL、全部加入，`skip_duplicate = false` 表示按 URL 跳过已存在的条目。对已有内容的媒体库做增量扫描，通常设置 `skip_duplicate = false` 以避免重复条目。`esp_media_db_add()` 始终按 URL 跳过已存在的条目，没有 `skip_duplicate` 参数。

`esp_media_db_remove()` 按 URL 删除指定条目；`esp_media_db_clean()` 只清空当前进程内的媒体库视图，不删除文件系统中的数据库文件，需要恢复时再次调用 `esp_media_db_load()` 即可；`esp_media_db_get_count()` 返回当前条目数。

### 播放列表（esp_playlist）

播放列表在 RAM 中维护一个有序条目序列和当前索引，由 `esp_playlist_new()` 创建空实例。填充播放列表有两条独立路径，行为不同：

- `esp_playlist_import_media()` 从一个媒体库追加条目，`filter` 为 `NULL` 时导入全部，带 `esp_media_filter_t` 时按条件筛选；导入后播放列表绑定该媒体库句柄，之后从不同句柄导入会返回 `ESP_ERR_INVALID_STATE`。这类条目在播放列表内部只保存到媒体库的引用（DB 条目），导航时需要回查媒体库获取 `name` / `url`

- `esp_playlist_load()` / `esp_playlist_import_ram()` 从 JSON 文件或内存缓冲区清空并替换当前列表，与媒体库无关；解析出的条目直接携带自己的 `name` / `url`（inline 条目），导航时不需要回查媒体库

    esp_playlist_handle_t playlist = NULL;
    esp_playlist_new(&(esp_playlist_cfg_t) { .playlist_name = "default" }, &playlist);
    esp_playlist_import_media(playlist, media_db, NULL);  /* 导入媒体库全部条目 */

`esp_playlist_save()` / `esp_playlist_export_ram()` 只导出播放列表自身的 JSON（名称、顺序、条目），不涉及媒体库文件；两者与 `esp_playlist_load()` / `esp_playlist_import_ram()` 共用同一种 JSON 格式，可互相读写。`esp_playlist_export_ram()` 返回的缓冲区需由调用方 `free()` 释放。`esp_playlist_clean()` 清空当前列表条目，不删除磁盘上的 JSON 或媒体库文件。

### 当前曲目与循环模式

播放列表维护一个从 0 开始的当前索引，默认指向第 0 项。`esp_playlist_set_curr_index()` 可跳转到指定索引；`esp_playlist_curr()`、`esp_playlist_next()`、`esp_playlist_prev()` 和 `esp_playlist_get_info()` 用于读取条目信息并填充到调用方提供的 `esp_playlist_info_t`。其中 `get_info` 按指定 `index` 读取且不改变当前索引，其余三个都会更新或依赖当前索引。

`next` / `prev` 的边界行为由 `esp_playlist_set_repeat_mode()` 设置的 `esp_playlist_repeat_mode_t` 决定：

模式 | 行为
--- | ---
`ESP_PLAYLIST_REPEAT_NONE` | 到达列表边界后返回 `ESP_ERR_NOT_FOUND`，不循环
`ESP_PLAYLIST_REPEAT_ONE` | 保持在当前索引，反复读取同一条目
`ESP_PLAYLIST_REPEAT_ALL` | 到达边界后回绕到列表另一端
`ESP_PLAYLIST_REPEAT_SHUFFLE` | 每次调用 `next` / `prev` 时随机选取一个索引

条目为 DB 条目但绑定的媒体库已失效时，导航接口返回 `ESP_ERR_INVALID_STATE`；列表为空或到达非循环边界时返回 `ESP_ERR_NOT_FOUND`。

### 过滤器（esp_media_filter_t）

`esp_media_filter_t` 由若干 `esp_media_filter_item_t` 条件组成，每个条件指定字段名（如 `name`、`url`、`id`）、期望值和 `esp_media_match_type_t` 匹配方式（精确匹配 `ESP_MEDIA_MATCH_EXACT`、包含匹配 `ESP_MEDIA_MATCH_CONTAINS`、前缀匹配 `ESP_MEDIA_MATCH_PREFIX`），并通过 `match_all` 决定条件间是 AND 还是 OR 组合。该过滤器同时用于 `esp_playlist_import_media()` 的导入筛选。

    esp_media_filter_item_t items[] = {
        { .key = "url", .expected = { .type = ESP_DB_FIELD_TYPE_STRING, .value.strv = ".mp3", .size = 5 },
          .match_type = ESP_MEDIA_MATCH_CONTAINS },
    };
    esp_media_filter_t filter = {
        .items = items,
        .item_count = 1,
        .match_all = true,
    };
    esp_playlist_import_media(playlist, media_db, &filter);

## 性能

playlist_benchmark 例程在 ESP32-P4 Function EV Board（SD 卡、1000 条目）上的实测单次平均耗时如下，实际数值随 SoC、SD 卡速度和媒体数量变化：

操作 | 场景 | 平均耗时
--- | --- | ---
`esp_media_db_scan`（冷扫描，不去重） | 1000 个文件 | 664.71 us/item
`esp_media_db_load` | 1000 条目 | 66.34 us/item
`esp_playlist_import_media` | 1000 条目 | 176.76 us/item
`esp_playlist_next` / `prev`（DB 条目） | 单次调用 | 156.71 / 205.23 us
`esp_playlist_next` / `prev`（inline 条目） | 单次调用 | 2.53 / 2.49 us
`esp_playlist_save` | 1000 条目，73045 字节 | 366.81 us/item
`esp_playlist_load`（JSON） | 1000 条目，73045 字节 | 105.63 us/item

DB 条目导航（`import_media` 导入）比 inline 条目导航（`load` / `import_ram` 导入）慢约两个数量级，原因是前者每次都要回查媒体库获取 `name` / `url`，后者条目自身已携带完整信息。频繁切换曲目的场景可优先考虑 inline 条目路径。

## 应用示例

- playlist_benchmark 演示媒体库扫描/加载、播放列表导入与导航、JSON 保存/加载的完整流程，并输出各接口的压测耗时

典型场景与对应接口如下：

场景 | 建议流程
--- | ---
SD 卡本地音乐 | 挂载 SD 卡，`esp_media_db_scan` 扫描目录，`esp_playlist_import_media` 导入，`esp_playlist_save` 保存播放列表
Flash 固定 URL 列表 | `esp_media_db_add` 写入固定条目后 `esp_playlist_import_media` 导入
开机恢复 | `esp_media_db_load` 恢复媒体库，`esp_playlist_load` 恢复播放列表 JSON
NVS / 网络下发列表 | `esp_playlist_export_ram` 得到 JSON 后自行存储；恢复时用 `esp_playlist_import_ram`
按名称或 URL 筛选 | 构造 `esp_media_filter_t`，配合 `ESP_MEDIA_MATCH_EXACT`、`ESP_MEDIA_MATCH_CONTAINS`、`ESP_MEDIA_MATCH_PREFIX` 匹配方式

## FAQ

Q1：媒体库和播放列表 JSON 有什么区别？

媒体库（文件系统存储时为 `storage_path` 下的数据库文件）保存扫描或手动添加得到的 `name` / `url` 条目集合，记录设备上有哪些媒体文件。播放列表 JSON 只保存一个播放列表的名称、顺序和条目，记录以什么顺序播放，两者是不同的持久化对象。

Q2：只加载 playlist.json，还需要媒体库吗？

不需要。JSON 条目本身已包含 `name` 和 `url`，加载后可直接通过 `curr` / `next` / `prev` / `get_info` 取出 URL 播放，这类条目属于 inline 条目，不回查媒体库。

Q3：能否按专辑或歌手导入？

当前公开接口不会从媒体文件内解析 `album`、`artist` 等元数据。若媒体库条目中已包含这类扩展字段，可以通过 `esp_media_filter_t` 匹配对应字段实现筛选。

## API 参考

### Header File

- components/esp_playlist/include/esp_playlist.h

### Functions

esp_err_t esp_playlist_new(const esp_playlist_cfg_t *cfg, esp_playlist_handle_t *handle)

  Create an empty in-RAM playlist.

          Populate with esp_playlist_import_media(), esp_playlist_import_ram(), or
          esp_playlist_load(). RAM buffer export/import uses a separate format from the media DB
          three-file persistence.

  参数:

    - cfg – [in] Configuration; playlist_name must be non-NULL and non-empty

    - handle – [out] Receives the new handle on success

  返回:

    - ESP_OK On success

    - ESP_ERR_INVALID_ARG If cfg, handle, or playlist_name is invalid

    - ESP_ERR_NO_MEM If allocation fails

esp_err_t esp_playlist_del(esp_playlist_handle_t handle)

  Destroy a playlist handle and free its resources.

  参数:

    handle – [in] Playlist handle

  返回:

    - ESP_OK On success

    - ESP_ERR_INVALID_ARG If handle is NULL

esp_err_t esp_playlist_import_media(esp_playlist_handle_t handle, esp_media_db_handle_t media_db_handle, const esp_media_filter_t *filter)

  Import media entries from a catalog into the playlist.

          Appends matching catalog rows to the playlist (no dedup by media_id).
          On failure, entries appended during this call are removed before returning.
          Binds the playlist to media_db_handle; a later import from a different handle
          returns ESP_ERR_INVALID_STATE.

  参数:

    - handle – [in] Playlist handle

    - media_db_handle – [in] Source media catalog

    - filter – [in] Optional filter; NULL appends all catalog rows

  返回:

    - ESP_OK On success

    - ESP_ERR_INVALID_ARG If handle or media_db_handle is NULL, or filter is invalid

    - ESP_ERR_INVALID_STATE If the playlist is bound to another media DB

    - ESP_ERR_NOT_FOUND If the catalog is empty or no rows matched the filter

    - ESP_ERR_NO_MEM If allocation fails

    - ESP_FAIL On other internal media lookup errors

esp_err_t esp_playlist_load(esp_playlist_handle_t handle, const char *load_path)

  Replace the in-memory playlist from a JSON file.

          Not append semantics. JSON playlist format matches esp_playlist_save(),
          esp_playlist_export_ram(), and esp_playlist_import_ram(). Independent of
          esp_media_db VFS catalog files.

  参数:

    - handle – [in] Playlist handle

    - load_path – [in] Path to JSON playlist file

  返回:

    - ESP_OK On success

    - ESP_ERR_INVALID_ARG If handle or load_path is NULL

    - ESP_ERR_NO_MEM If allocation fails while parsing or building items

    - ESP_FAIL If the file cannot be read or JSON is invalid

esp_err_t esp_playlist_save(esp_playlist_handle_t handle, const char *save_path)

  Write the current playlist to a JSON file.

          JSON playlist format matches esp_playlist_export_ram(), esp_playlist_load(),
          and esp_playlist_import_ram().

  参数:

    - handle – [in] Playlist handle

    - save_path – [in] Path to JSON playlist file

  返回:

    - ESP_OK On success

    - ESP_ERR_INVALID_ARG If handle or save_path is NULL

    - ESP_ERR_NO_MEM If JSON allocation fails

    - ESP_FAIL If the file cannot be written

esp_err_t esp_playlist_import_ram(esp_playlist_handle_t handle, const char *buf, size_t buf_len)

  Replace the in-memory playlist from a JSON buffer in RAM.

          Same replace semantics as esp_playlist_load(). The buffer must contain JSON in
          the same playlist format as the file read by esp_playlist_load() (and as written
          by esp_playlist_save() / esp_playlist_export_ram()). Parsed entries become inline
          items with copied name and url strings.

  参数:

    - handle – [in] Playlist handle

    - buf – [in] JSON playlist text buffer

    - buf_len – [in] Byte length of buf; if 0, buf is treated as a NUL-terminated string

  返回:

    - ESP_OK On success

    - ESP_ERR_INVALID_ARG If handle or buf is NULL

    - ESP_ERR_NO_MEM If allocation fails while parsing or building items

    - ESP_FAIL If buffer content is invalid or missing required fields

esp_err_t esp_playlist_export_ram(esp_playlist_handle_t handle, char **out_buf, size_t *out_len)

  Export the current playlist to a heap-allocated JSON buffer.

          JSON uses the same playlist format as esp_playlist_save() writes to a file and
          as esp_playlist_load() / esp_playlist_import_ram() accept. The returned string is
          NUL-terminated. Caller must release it with free().

  参数:

    - handle – [in] Playlist handle

    - out_buf – [out] Receives the JSON buffer on success; set to NULL on failure

    - out_len – [out] Optional; receives strlen(out_buf); may be NULL

  返回:

    - ESP_OK On success

    - ESP_ERR_INVALID_ARG If handle or out_buf is NULL

    - ESP_ERR_NO_MEM If allocation fails

    - ESP_FAIL If serialization fails

esp_err_t esp_playlist_clean(esp_playlist_handle_t handle)

  Clear all items from the in-RAM playlist.

          Does not delete JSON or media DB files on disk.

  参数:

    handle – [in] Playlist handle

  返回:

    - ESP_OK On success

    - ESP_ERR_INVALID_ARG If handle is NULL

esp_err_t esp_playlist_set_repeat_mode(esp_playlist_handle_t handle, esp_playlist_repeat_mode_t repeat_mode)

  Set repeat mode for navigation APIs.

  参数:

    - handle – [in] Playlist handle

    - repeat_mode – [in] Repeat behavior

  返回:

    - ESP_OK On success

    - ESP_ERR_INVALID_ARG If handle is NULL or repeat_mode is out of range

esp_err_t esp_playlist_set_curr_index(esp_playlist_handle_t handle, int index)

  Set the current playback index without loading item info.

          Invalidates the esp_playlist_curr() cache. Default index after esp_playlist_new()
          is 0.

  参数:

    - handle – [in] Playlist handle

    - index – [in] Zero-based index; must be < item count

  返回:

    - ESP_OK On success

    - ESP_ERR_INVALID_ARG If handle is NULL or index < 0

    - ESP_ERR_NOT_FOUND If index >= item count

esp_err_t esp_playlist_next(esp_playlist_handle_t handle, esp_playlist_info_t *info)

  Advance to the next item and fill info.

          Updates current index according to repeat_mode. REPEAT_ALL wraps at the end;
          REPEAT_NONE returns ESP_ERR_NOT_FOUND at the last item.

  参数:

    - handle – [in] Playlist handle

    - info – [out] Caller buffer; strings are copied on success

  返回:

    - ESP_OK On success

    - ESP_ERR_INVALID_ARG If handle or info is NULL

    - ESP_ERR_NOT_FOUND If the list is empty or the boundary is reached

    - ESP_ERR_INVALID_STATE If a DB item has no bound media catalog

    - ESP_FAIL On internal media lookup failure

esp_err_t esp_playlist_prev(esp_playlist_handle_t handle, esp_playlist_info_t *info)

  Move to the previous item and fill info.

          Updates current index according to repeat_mode. REPEAT_ALL wraps at the start;
          REPEAT_NONE returns ESP_ERR_NOT_FOUND at the first item.

  参数:

    - handle – [in] Playlist handle

    - info – [out] Caller buffer; strings are copied on success

  返回:

    - ESP_OK On success

    - ESP_ERR_INVALID_ARG If handle or info is NULL

    - ESP_ERR_NOT_FOUND If the list is empty or the boundary is reached

    - ESP_ERR_INVALID_STATE If a DB item has no bound media catalog

    - ESP_FAIL On internal media lookup failure

esp_err_t esp_playlist_curr(esp_playlist_handle_t handle, esp_playlist_info_t *info)

  Read the current item without changing the index.

          Uses an in-RAM cache when valid; otherwise loads from the bound media catalog
          or inline JSON items.

  参数:

    - handle – [in] Playlist handle

    - info – [out] Caller buffer; strings are copied on success

  返回:

    - ESP_OK On success

    - ESP_ERR_INVALID_ARG If handle or info is NULL

    - ESP_ERR_NOT_FOUND If the list is empty

    - ESP_ERR_INVALID_STATE If a DB item has no bound media catalog

    - ESP_FAIL On internal media lookup failure

esp_err_t esp_playlist_get_info(esp_playlist_handle_t handle, int index, esp_playlist_info_t *info)

  Read one item by index without changing the current playback index.

  参数:

    - handle – [in] Playlist handle

    - index – [in] Zero-based index; must be < item count

    - info – [out] Caller buffer; strings are copied on success

  返回:

    - ESP_OK On success

    - ESP_ERR_INVALID_ARG If handle or info is NULL, or index < 0

    - ESP_ERR_NOT_FOUND If index >= item count

    - ESP_ERR_INVALID_STATE If a DB item has no bound media catalog

    - ESP_FAIL On internal media lookup failure

esp_err_t esp_playlist_get_count(esp_playlist_handle_t handle, int *count)

  Get the number of items in the playlist.

  参数:

    - handle – [in] Playlist handle

    - count – [out] Receives item count on success

  返回:

    - ESP_OK On success

    - ESP_ERR_INVALID_ARG If handle or count is NULL

### Structures

struct esp_playlist_info_t

  Snapshot of one playlist entry for navigation APIs.

          Caller supplies the structure; APIs copy strings into fixed buffers.
          URLs longer than ESP_PLAYLIST_URL_MAX - 1 are truncated with a trailing NUL.

  Public Members

  char playlist_name[ESP_PLAYLIST_NAME_MAX]

    Playlist name

  char media_name[ESP_PLAYLIST_MEDIA_NAME_MAX]

    Media display name

  char media_url[ESP_PLAYLIST_URL_MAX]

    Media URL

  int index

    Zero-based index in the list

struct esp_playlist_cfg_t

  Playlist creation configuration.

  Public Members

  const char *playlist_name

    Non-empty playlist name; copied internally

### Macros

ESP_PLAYLIST_NAME_MAX

  Maximum length of playlist name string (including NUL). Configurable via menuconfig.

ESP_PLAYLIST_MEDIA_NAME_MAX

  Maximum length of media display name in esp_playlist_info_t (including NUL). Configurable via menuconfig.

ESP_PLAYLIST_URL_MAX

  Maximum length of media URL in esp_playlist_info_t (including NUL). Configurable via menuconfig.

### Type Definitions

typedef void *esp_playlist_handle_t

  Opaque handle for a playlist instance.

### Enumerations

enum esp_playlist_repeat_mode_t

  Repeat mode for esp_playlist_next() and esp_playlist_prev().

  Values:

  enumerator ESP_PLAYLIST_REPEAT_NONE

    Stop at list boundary (ESP_ERR_NOT_FOUND)

  enumerator ESP_PLAYLIST_REPEAT_ONE

    Stay on current index

  enumerator ESP_PLAYLIST_REPEAT_ALL

    Wrap at list ends

  enumerator ESP_PLAYLIST_REPEAT_SHUFFLE

    Pick a random index on next/prev

### Header File

- components/esp_playlist/include/esp_media_db.h

### Functions

esp_err_t esp_media_db_init(const esp_media_db_cfg_t *cfg, esp_media_db_handle_t *handle)

  Create a media catalog handle and empty runtime state.

          Does not load existing filesystem data. Call esp_media_db_load(), esp_media_db_scan(),
          or esp_media_db_add() to populate the catalog.

  参数:

    - cfg – [in] Storage type and path; must not be NULL

    - handle – [out] Receives the new handle on success; set to NULL on failure

  返回:

    - ESP_OK On success

    - ESP_ERR_INVALID_ARG If cfg or handle is NULL, or storage_type is invalid

    - ESP_ERR_NO_MEM If allocation fails

    - ESP_FAIL If storage backend setup fails

esp_err_t esp_media_db_deinit(esp_media_db_handle_t handle)

  Release a catalog handle created by esp_media_db_init().

  参数:

    handle – [in] Catalog handle

  返回:

    - ESP_OK On success

    - ESP_ERR_INVALID_ARG If handle is NULL

esp_err_t esp_media_db_load(esp_media_db_handle_t handle)

  Load catalog data from the filesystem three-file database.

          If loading fails, an empty catalog is created and ESP_OK is still returned
          after recreation (see implementation log).

  参数:

    handle – [in] Catalog handle

  返回:

    - ESP_OK On success

    - ESP_ERR_INVALID_ARG If handle is NULL

    - ESP_ERR_NO_MEM If opening or recreating the internal library fails

esp_err_t esp_media_db_clean(esp_media_db_handle_t handle)

  Clear the in-memory catalog without deleting filesystem files.

  参数:

    handle – [in] Catalog handle

  返回:

    - ESP_OK On success

    - ESP_ERR_INVALID_ARG If handle is NULL

esp_err_t esp_media_db_scan(esp_media_db_handle_t handle, const esp_media_db_scan_cfg_t *scan_cfg)

  Scan a directory tree and add matching files to the catalog.

          When skip_duplicate is false, URL deduplication applies only if the catalog
          already has entries; an empty catalog is scanned without deduplication.
          May be called multiple times (e.g. different mount points). Changes persist
          on the filesystem when storage_type is ESP_DB_STORAGE_FS.

  参数:

    - handle – [in] Catalog handle

    - scan_cfg – [in] Scan path, scan_depth, extensions, skip_duplicate, and callback

  返回:

    - ESP_OK On success

    - ESP_ERR_INVALID_ARG If handle or scan_cfg is NULL, or scan_cfg fields are invalid

    - ESP_ERR_NO_MEM If the internal library cannot be opened or scan fails

    - ESP_FAIL On other internal scan errors

esp_err_t esp_media_db_add(esp_media_db_handle_t handle, const esp_media_db_item_t *items, int count)

  Add one or more items to the catalog.

          Skips items whose URL already exists. name and url pointers are stored by
          reference (not copied into a separate RAM cache). Persists on filesystem after add.

  参数:

    - handle – [in] Catalog handle

    - items – [in] Array of count items; each url must be non-NULL

    - count – [in] Number of entries in items; must be > 0

  返回:

    - ESP_OK On success

    - ESP_ERR_INVALID_ARG If handle, items is NULL, or count <= 0

    - ESP_ERR_NO_MEM If the internal library cannot be opened or add fails

    - ESP_FAIL On other internal add errors

esp_err_t esp_media_db_remove(esp_media_db_handle_t handle, const esp_media_db_item_t *items, int count)

  Remove catalog items matching the given URLs.

  参数:

    - handle – [in] Catalog handle

    - items – [in] Array of count items; each url must be non-NULL

    - count – [in] Number of entries in items; must be > 0

  返回:

    - ESP_OK On success (including when no rows matched)

    - ESP_ERR_INVALID_ARG If handle, items is NULL, count <= 0, or an item url is NULL

    - ESP_ERR_NO_MEM If allocation or internal library access fails

    - ESP_FAIL On other internal remove errors

esp_err_t esp_media_db_get_count(esp_media_db_handle_t handle, int *count)

  Get the number of rows in the catalog.

  参数:

    - handle – [in] Catalog handle

    - count – [out] Receives the item count on success

  返回:

    - ESP_OK On success

    - ESP_ERR_INVALID_ARG If handle or count is NULL

    - ESP_ERR_NO_MEM If the internal library cannot be opened

    - ESP_FAIL On other internal query errors

### Structures

struct esp_media_db_cfg_t

  Media catalog initialization configuration.

  Public Members

  esp_db_storage_type_t storage_type

    FS persistence or RAM-only

  const char *storage_path

    Filesystem base path (e.g. /sdcard/__playlist), or logical name for RAM backend

### Type Definitions

typedef void *esp_media_db_handle_t

  Opaque handle for a media catalog instance.

### Header File

- components/esp_playlist/include/esp_media_db_types.h

### Structures

struct esp_db_field_value_t

  Typed value container for catalog columns and filter operands.

  Public Members

  esp_db_field_type_t type

    Active member of value

  int intv

    ESP_DB_FIELD_TYPE_INT

  float floatv

    ESP_DB_FIELD_TYPE_FLOAT

  bool boolv

    ESP_DB_FIELD_TYPE_BOOL

  const char *strv

    ESP_DB_FIELD_TYPE_STRING; lifetime per API contract

  const int *intarrv

    ESP_DB_FIELD_TYPE_INT_ARRAY

  union esp_db_field_value_t::[anonymous] value

    Payload selected by type

  int size

    STRING: byte length (often strlen+1); INT_ARRAY: n*sizeof(int); scalars: sizeof(int), sizeof(float), or sizeof(bool)

struct esp_media_db_item_t

  Media catalog item passed to add/remove APIs.

  Public Members

  const char *name

    Display name (catalog column “name”)

  const char *url

    Media locator (catalog column “url”)

struct esp_media_filter_item_t

  Single filter condition on a catalog column.

  Public Members

  const char *key

    Column name, e.g. “name”, “url”, or “id”

  esp_db_field_value_t expected

    Expected value; type must match the column

  esp_media_match_type_t match_type

    Comparison mode

struct esp_media_filter_t

  Combined filter with AND or OR semantics.

  Public Members

  const esp_media_filter_item_t *items

    Array of item_count conditions

  uint8_t item_count

    Number of entries in items

  bool match_all

    true: AND all conditions; false: OR

struct esp_media_db_scan_cfg_t

  Directory scan configuration for esp_media_db_scan().

  Public Members

  bool skip_duplicate

    true: skip URL dedup; false: dedup when catalog is non-empty

  const char *path

    Scan root directory

  uint8_t scan_depth

    Max recursion depth under path (0 = path only)

  const char *const *file_extensions

    Allowed extensions; NULL if count is 0

  uint8_t file_extension_count

    Length of file_extensions; 0 disables filter

  esp_media_scan_filter_cb_t filter_cb

    Optional post-scan callback; NULL to disable

  void *filter_cb_ctx

    Context for filter_cb

### Macros

ESP_MEDIA_INVALID_ID

  Invalid media ID; valid row IDs are non-negative (0, 1, 2, …).

### Type Definitions

typedef int esp_media_id_t

  Media catalog row identifier.

typedef bool (*esp_media_scan_filter_cb_t)(void *ctx, const char *url)

  Scan callback to accept or reject a discovered file URL.

  Param ctx:

    [in] Opaque context from esp_media_db_scan_cfg_t::filter_cb_ctx

  Param url:

    [in] File URL discovered during scan

  Return:

    - true to add the file to the catalog, false to skip it

### Enumerations

enum esp_db_storage_type_t

  Storage backend kind for the media catalog.

  Values:

  enumerator ESP_DB_STORAGE_FS

    Persist catalog under storage_path on filesystem

  enumerator ESP_DB_STORAGE_RAM

    Runtime-only; heap-backed, not on filesystem

enum esp_db_field_type_t

  Typed field value used in filters and playlist metadata.

  Values:

  enumerator ESP_DB_FIELD_TYPE_INVALID

    Invalid or unset type

  enumerator ESP_DB_FIELD_TYPE_INT

    Single integer

  enumerator ESP_DB_FIELD_TYPE_FLOAT

    Single-precision float

  enumerator ESP_DB_FIELD_TYPE_STRING

    NUL-terminated C string

  enumerator ESP_DB_FIELD_TYPE_BOOL

    Boolean

  enumerator ESP_DB_FIELD_TYPE_INT_ARRAY

    Dense int array

enum esp_media_match_type_t

  String comparison mode for a single filter condition.

  Values:

  enumerator ESP_MEDIA_MATCH_EXACT

    Exact match for string or scalar

  enumerator ESP_MEDIA_MATCH_CONTAINS

    Substring match (strings only)

  enumerator ESP_MEDIA_MATCH_PREFIX

    Prefix match (strings only)

提供有关此文档的反馈