播放本地音频的代码

首先要在芯片存储区建立存储区域,这个加到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 小时前
批量图片OCR识别重命名工具完全免费
随机森林·智能手机·ocr·电脑·word·音视频·最小二乘法
俊哥工具3 小时前
文件批量转换工具 本地运行更快更安全
运维·服务器·django·音视频·tornado
weixin_4952484016 小时前
短剧视频翻译配音指南:古装、甜宠与悬疑如何本地化?
音视频
禹亮科技17 小时前
制造业100㎡跨国技术评审会议室音视频整体解决方案(亿联+思必驰+讯飞AI落地实践)
人工智能·音视频·视频会议系统集成
潜创微科技17 小时前
HDMI 分配器芯片方案商 IT66630 有源分配芯片方案
音视频
不爱记笔记18 小时前
多模态AI如何理解视频内容?从视觉、语音到语义的三层技术拆解
人工智能·自然语言处理·nlp·音视频·多模态
论迹复利20 小时前
Sniff 省电模式参数调优——续航与音频稳定性平衡实操
音视频·sniff·bt·功耗、
星核0penstarry1 天前
从 Dialog-RSN-1 看语音 Agent 走向:企业如何评估音频原生模型与 API 服务
人工智能·音视频·音频·api
明如正午1 天前
【python】Python + OpenCV 实现视频关键帧提取与智能去重
python·opencv·音视频
呆呆敲代码的小Y1 天前
5 分钟上手 OpenMontage:把 AI 编程助手变成视频工作室
人工智能·aigc·音视频·ai视频生成·claude code·openmontage