播放本地音频的代码

首先要在芯片存储区建立存储区域,这个加到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;
}

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

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

相关推荐
撬动未来的支点6 小时前
【音视频】通俗讲SDP会话描述/协商协议
音视频
沉迷单车的追风少年7 小时前
Diffusion Model与视频超分(2):解读字节开源视频增强模型SeedVR2
人工智能·深度学习·aigc·音视频·强化学习·视频生成·视频超分
给大佬递杯卡布奇诺8 小时前
FFmpeg 基本数据结构 AVPacket分析
数据结构·c++·ffmpeg·音视频
无线图像传输研究探索8 小时前
应急救援 “眼观六路”:SA/NSA 双模覆盖,偏远灾区也能实时传视频
5g·音视频·无人机·5g单兵图传·单兵图传·无人机图传
Fuly10248 小时前
AI 大模型应用中的图像,视频,音频的处理
人工智能·音视频
小白学过的代码8 小时前
videojs增加视频源选择框小工具
javascript·vue.js·音视频
IDC02_FEIYA8 小时前
视频网站服务器带宽需要多少?视频网站服务器配置要求
运维·服务器·音视频
碧海银沙音频科技研究院10 小时前
i2s的LRCK时钟有毛刺以及BCLK数据在高采样率有变形数据解析错误问题原因以及解决方法
人工智能·深度学习·算法·分类·音视频
音视频牛哥12 小时前
AI智能体从系统智能到生态智能:SmartMediaKit 如何成为智能体时代的视频神经系统
人工智能·计算机视觉·音视频·大牛直播sdk·多智能体协同·rtsp播放器rtmp播放器·视频感知低延迟音视频