Files
Bionic_sphere/Bionic_Core/ToolsClass/AudioOutput/AudioOutput.h
T
Misaki ba5e47bc77 这是一次长久的提交:
1. 应用界面增加了返回主页的按钮
2. 修复了gif渲染内存泄漏的严重bug
3. 将PetDao当中的cJSON API替换为cpp_json,完美通过测试
4. 整合已经实现的各种上层建筑,实现了一个宠物对话基本业务应用,用于样品测试展示用
5. 重构了音频播放类,使其更modern,更加便于移植和拓展
2025-10-16 11:36:45 +08:00

252 lines
6.5 KiB
C++

//
// Created by misaki on 2025/9/9.
//
#pragma once
#include <mutex>
#include <functional>
#include <string>
#include <hal/i2s_types.h>
#include "ThreadManager.h"
#include "SDFileManager.h"
// 音频播放状态枚举
enum class AudioState {
IDLE, // 音频未播放
PLAYING, // 音频播放中
PAUSED, // 音频暂停中
STOPPED, // 音频已停止
ERROR // 音频播放错误
};
// 音频播放回调函数类型
using AudioCallback = std::function<void(AudioState state, const char* filePath)>;
/*
* 回调函数示例:
void audioCallback(AudioState state, const char* filePath) {
switch (state) {
case AudioState::PLAYING:
ESP_LOGI("Example", "Started playing: %s", filePath);
break;
case AudioState::PAUSED:
ESP_LOGI("Example", "Paused: %s", filePath);
break;
case AudioState::STOPPED:
ESP_LOGI("Example", "Stopped: %s", filePath);
break;
case AudioState::ERROR:
ESP_LOGE("Example", "Error playing: %s", filePath);
break;
default:
break;
}
}
*/
/**
* 本模块为音频输出模块
* 支持同步,异步音频输出
*
* 注意:底层C驱动任务运行在核0, 请不要把例如lvgl这种高CPU占比的任务放在核0中,避免资源抢占导致播放卡顿
*/
class AudioOutput {
public:
// 删除拷贝构造函数和赋值运算符
AudioOutput(AudioOutput const&) = delete;
AudioOutput& operator=(AudioOutput const&) = delete;
/**
* 获取单例实例
* @return AudioOutput实例
*/
static AudioOutput* getInstance();
/**
* 初始化音频输出
* @return 是否成功
*/
bool init();
// try to init AudioOutput
void tryInitAudioOutput();
/**
* 同步播放音频文件
* @param directory 目录路径
* @param fileName 文件名
* @return 是否成功
*/
bool playSync(const char* directory, const char* fileName);
/**
* 异步播放音频文件
* @param directory 目录路径
* @param fileName 文件名
* @param callback 回调函数
*/
void playAsync(const char* directory, const char* fileName, const AudioCallback& callback = nullptr);
/**
* 暂停播放
* @return 是否成功
*/
bool pause();
/**
* 恢复播放
* @return 是否成功
*/
bool resume();
/**
* 停止播放
* @return 是否成功
*/
bool stop();
/**
* 设置音量
* @param volume 音量值 (0-100)
* @return 是否成功
*/
bool setVolume(uint8_t volume);
/**
* 获取当前音量
* @return 音量值
*/
uint8_t getVolume() const;
/**
* 获取最大音量
* @return 最大音量值
*/
uint8_t getMaxVolume() const;
/**
* 获取音频总时长
* @return 总时长(毫秒)
*/
uint32_t getDuration() const;
/**
* 获取已播放时长
* @return 已播放时长(毫秒)
*/
uint32_t getElapsed() const;
/**
* 获取音频能量值
* @return 能量值
*/
uint16_t getEnergy() const;
/**
* 获取当前播放状态
* @return 播放状态
*/
AudioState getState() const;
/**
* 检查是否正在播放
* @return 是否正在播放
*/
bool isPlaying() const;
/**
* 检查是否暂停
* @return 是否暂停
*/
bool isPaused() const;
/**
* 检查是否停止
* @return 是否停止
*/
bool isStopped() const;
/**
* 检查播放是否完成
* @return 是否完成
*/
bool isFinished() const;
/**
* 播放 PCM 文件(阻塞)
* @param filePath PCM 文件路径
* @param sampleRate 采样率
* @param bits 数据位宽
* @param ch 插槽模式
* @return 是否成功
*/
bool playPcmFile(const char* filePath,
uint32_t sampleRate = 16000,
i2s_data_bit_width_t bits = I2S_DATA_BIT_WIDTH_16BIT,
i2s_slot_mode_t ch = I2S_SLOT_MODE_MONO);
// 异步播放 PCM 文件
void playPcmFileAsync(const char* filePath,
uint32_t sampleRate = 16000,
i2s_data_bit_width_t bits = I2S_DATA_BIT_WIDTH_16BIT,
i2s_slot_mode_t ch = I2S_SLOT_MODE_MONO,
const AudioCallback& cb = nullptr);
/**
* 播放内存 PCM 流(阻塞)
* @param pcmData PCM 数据
* @param dataBytes 数据字节数
* @param sampleRate 采样率
* @param bits 数据位宽
* @param ch 插槽模式
* @return 是否成功
*/
bool playPcmStream(const uint8_t* pcmData,
size_t dataBytes,
uint32_t sampleRate = 16000,
i2s_data_bit_width_t bits = I2S_DATA_BIT_WIDTH_16BIT,
i2s_slot_mode_t ch = I2S_SLOT_MODE_MONO);
// 异步播放 PCM 流
void playPcmStreamAsync(const uint8_t* pcmData,
size_t dataBytes,
uint32_t sampleRate = 16000,
i2s_data_bit_width_t bits = I2S_DATA_BIT_WIDTH_16BIT,
i2s_slot_mode_t ch = I2S_SLOT_MODE_MONO,
const AudioCallback& cb = nullptr);
private:
// 通用 PCM 播放实现
void playPcmCommon(const void* source,
size_t bytes,
bool isFile,
uint32_t sampleRate,
i2s_data_bit_width_t bits,
i2s_slot_mode_t ch,
const AudioCallback& cb);
private:
// 私有构造函数
AudioOutput();
~AudioOutput();
// 初始化线程配置
ThreadConfig getThreadConfig(const char* operation);
// 内部播放实现
void playInternal(const char* directory, const char* fileName, const AudioCallback& callback);
// 状态转换辅助方法
void setState(AudioState newState);
// 单例实例指针
static AudioOutput* instance;
static std::mutex instanceMutex;
// 成员变量
mutable std::mutex stateMutex;
AudioState currentState;
std::string currentFilePath;
uint8_t currentVolume;
bool hardwareInitialized;
};