播放本地音频的代码

首先要在芯片存储区建立存储区域,这个加到partitions.csvz最后

复制代码
spiffs,   data, spiffs,  0xD00000,  1M

下来就是在CMakeLists.txt中增加自动烧录配置

复制代码
# 配置 SPIFFS 自动烧录(关键代码)
spiffs_create_partition_image(spiffs data FLASH_IN_PROJECT)

音频文件放在data文件夹下面

这个文件夹是我置顶的烧录到映像区域的文件

下面这个是头文件和配置硬件,我用的是ns416

8

复制代码
// *************************************************************/

#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/i2s_std.h"
#include "driver/gpio.h"
#include "esp_err.h"
#include "esp_log.h"
#include "sdkconfig.h"
#include "esp_vfs.h"
#include "esp_spiffs.h"  // 添加SPIFFS支持

// -------------------------- 配置参数(根据硬件修改) --------------------------
#define I2S_BCLK        GPIO_NUM_15  // I2S时钟线引脚
#define I2S_WS          GPIO_NUM_16  // I2S声道选择线(LRCK)引脚
#define I2S_DOUT        GPIO_NUM_7   // I2S数据输出引脚
#define PLAY_BUFFER_SIZE 2048        // 播放缓冲区大小(2KB,可按需调整)
#define WAV_SAMPLE_RATE 16000        // 目标WAV采样率(16kHz,需与播放文件匹配)
#define WAV_BIT_DEPTH   16           // 目标WAV位深(16bit,需与播放文件匹配)

/***************************************************************/

下面是播放和测试分区文件的代码

头文件

复制代码
    /*******************************************************/
    void list_spiffs_files();
    int init_ok = 0;
    esp_err_t spiffs_init();
    // 新增:WAV播放相关配置(需与你的WAV文件匹配)
    static const int WAV_BUFFER_SIZE = 2048;  // 播放缓冲区大小(2KB,可调整)
    static const int WAV_HEADER_SIZE = 44;    // 标准WAV文件头大小(固定44字节)
    // 新增:核心函数声明(读取WAV并播放)
    bool read_wav_and_play(const char* wav_path);  // 读取WAV文件并调用Write播放
    /*******************************************************/

类文件

复制代码
void AudioCodec::OutputData(std::vector<int16_t>& data) {
    //Write(data.data(), data.size());

    ESP_LOGE(TAG, "++++++++++++OutputData+++++++++++++");
    // 确保先初始化(只在首次调用时执行)
    if (this->spiffs_init() != ESP_OK) {
        return;  // 初始化失败则退出
    }

    // 2. 调用核心函数:读取WAV并播放(路径替换为你的WAV文件名)
    const char* wav_path = "/spiffs/hi_idf_audio.wav";  // SPIFFS中的WAV路径
    this->read_wav_and_play(wav_path);
}
/****************************************************************************/
// -------------------------- SPIFFS初始化 --------------------------
esp_err_t AudioCodec::spiffs_init(void) {
    if (this->init_ok) return ESP_OK;  // 已初始化直接返回

    // SPIFFS配置(指定spiffs分区)
    esp_vfs_spiffs_conf_t conf = {
        .base_path = "/spiffs",
        .partition_label = "spiffs",
        .max_files = 5,
        .format_if_mount_failed = true
    };

    // 执行初始化
    esp_err_t ret = esp_vfs_spiffs_register(&conf);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "SPIFFS初始化失败: %s", esp_err_to_name(ret));
        return ret;
    }

    this->init_ok = 1;  // 标记为已初始化
    ESP_LOGI(TAG, "SPIFFS初始化成功");

    // 每次调用都打印文件清单
    DIR *dir = opendir("/spiffs");
    if (!dir) {
        ESP_LOGE(TAG, "无法打开SPIFFS目录");
        return ret;
    }

    struct dirent *entry;
    int count = 0;
    ESP_LOGI(TAG, "=== 文件清单 ===");
    while ((entry = readdir(dir))) {
        if (entry->d_name[0] == '.') continue;  // 跳过.和..
        ESP_LOGI(TAG, "文件: %s", entry->d_name);
        count++;
    }
    closedir(dir);
    ESP_LOGI(TAG, "共%d个文件 ====", count);
    return ESP_OK;
}


// 核心函数:读取SPIFFS中的WAV文件,调用Write播放
bool AudioCodec::read_wav_and_play(const char* wav_path) {
    // 1. 打开WAV文件(SPIFFS路径,只读模式)
    FILE* wav_fp = fopen(wav_path, "rb");
    if (wav_fp == NULL) {
        ESP_LOGE(TAG, "打开WAV失败: %s", wav_path);
        return false;
    }

    // 2. 跳过WAV文件头(前44字节是格式信息,不是PCM数据)
    if (fseek(wav_fp, WAV_HEADER_SIZE, SEEK_SET) != 0) {
        ESP_LOGE(TAG, "跳过WAV头失败");
        fclose(wav_fp);
        return false;
    }

    // 3. 分配缓冲区(栈外分配,避免栈溢出)
    int16_t* wav_buffer = (int16_t*)malloc(WAV_BUFFER_SIZE);
    if (wav_buffer == NULL) {
        ESP_LOGE(TAG, "分配WAV缓冲区失败");
        fclose(wav_fp);
        return false;
    }

    // 4. 循环读取WAV数据并播放(核心逻辑)
    size_t read_samples = 0;  // 每次读取的PCM样本数(16bit=1个样本)
    bool play_success = true;
    while (1) {
        // 读取数据:fread返回字节数,转成样本数(1样本=2字节)
        read_samples = fread(wav_buffer, sizeof(int16_t), WAV_BUFFER_SIZE / sizeof(int16_t), wav_fp);
        if (read_samples == 0) {
            // 读取到文件末尾,播放完成
            ESP_LOGI(TAG, "WAV播放完成");
            break;
        }

        // 调用Write函数,将PCM数据写入I2S(播放)
        int written_samples = Write(wav_buffer, read_samples);
        if (written_samples != read_samples) {
            ESP_LOGE(TAG, "播放数据丢失:读取%d样本,写入%d样本", read_samples, written_samples);
            play_success = false;
            break;
        }

        // (可选)打印播放进度(调试用)
        ESP_LOGD(TAG, "播放进度:已读%d样本", read_samples);
    }

    // 5. 释放资源
    free(wav_buffer);
    fclose(wav_fp);
    return play_success;
}

/****************************************************************************/

大体就是这样,因为嵌入别的代码的一部分,不能直接使用,可以借鉴。

相关推荐
悟纤1 小时前
Seedance 2.0 API 已上线 | 支持「人像视频生成」|支持100并发 | 满血版 [灵龙AI API]
人工智能·音视频·seedance 2.0
这儿有一堆花2 小时前
深入解析 Video.js:现代 Web 视频播放的工程实践
前端·javascript·音视频
人工智能研究所5 小时前
Claude + HyperFrames:用 HTML 方式制作视频,AI 时代一切皆可 HTML?
人工智能·html·音视频·ai 视频·hyperframes·claude-
zzh9206 小时前
基于51单片机的流水灯Proteus仿真按键切换 上到下下到上 2个灯(可定做)(免费代码+视频讲解)
51单片机·proteus·音视频
Shang180989357267 小时前
T31ZX 君正/INGENIC智能视频处理器T31ZX可提供软硬件资料T31Z采用先进的低功耗设计
嵌入式硬件·fpga开发·音视频·t31zx智能视频处理器
音视频牛哥8 小时前
纯血鸿蒙(HarmonyOS NEXT)下,如何实现低延迟RTSP、RTMP播放器音视频解码?
华为·音视频·harmonyos·鸿蒙rtmp播放器·鸿蒙rtsp播放器·harmonyos rtsp·鸿蒙next播放器
@hhr8 小时前
使用java对接火山方舟doubao-seedance-1.5-pro 模型进行视频生成
java·python·音视频
轻口味9 小时前
HarmonyOS 6 轻相机应用开发2:贴纸效果实现
音视频·harmonyos·鸿蒙·播放器
2601_9495936510 小时前
Flutter OpenHarmony 三方库 video_player 视频播放器适配详解
flutter·音视频
王者鳜錸10 小时前
企业解决方案三-讯飞音频文件转文字+豆包智能体实现音频信息提炼
音视频