Files
xiaozhi-esp32/main/boards/common/esp32_music.h
2025-12-09 17:20:01 +08:00

151 lines
5.2 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#ifndef ESP32_MUSIC_H
#define ESP32_MUSIC_H
#include <string>
#include <thread>
#include <atomic>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <vector>
#include "music.h"
// MP3解码器支持
extern "C" {
#include "mp3dec.h"
}
// 音频数据块结构
struct AudioChunk {
uint8_t* data;
size_t size;
AudioChunk() : data(nullptr), size(0) {}
AudioChunk(uint8_t* d, size_t s) : data(d), size(s) {}
};
// 歌曲信息结构
struct SongInfo {
std::string title;
std::string artist;
SongInfo() : title(""), artist("") {}
SongInfo(const std::string& t, const std::string& a) : title(t), artist(a) {}
};
class Esp32Music : public Music {
public:
// 显示模式控制 - 移动到public区域
enum DisplayMode {
DISPLAY_MODE_SPECTRUM = 0, // 默认显示频谱
DISPLAY_MODE_LYRICS = 1 // 显示歌词
};
private:
std::string last_downloaded_data_;
std::string current_music_url_;
std::string current_song_name_;
bool song_name_displayed_;
std::atomic<bool> stop_flag_{false}; // 停止播放标志位
// 歌词相关
std::string current_lyric_url_;
std::vector<std::pair<int, std::string>> lyrics_; // 时间戳和歌词文本
std::mutex lyrics_mutex_; // 保护lyrics_数组的互斥锁
std::atomic<int> current_lyric_index_;
std::thread lyric_thread_;
std::atomic<bool> is_lyric_running_;
std::atomic<DisplayMode> display_mode_;
std::atomic<bool> is_playing_;
std::atomic<bool> is_downloading_;
std::thread play_thread_;
std::thread download_thread_;
int64_t current_play_time_ms_; // 当前播放时间(毫秒)
int64_t last_frame_time_ms_; // 上一帧的时间戳
int total_frames_decoded_; // 已解码的帧数
int current_song_duration_seconds_; // 当前歌曲总时长(秒)
// 音频缓冲区
std::queue<AudioChunk> audio_buffer_;
std::mutex buffer_mutex_;
std::condition_variable buffer_cv_;
size_t buffer_size_;
static constexpr size_t MAX_BUFFER_SIZE = 256 * 1024; // 256KB缓冲区降低以减少brownout风险
static constexpr size_t MIN_BUFFER_SIZE = 32 * 1024; // 32KB最小播放缓冲降低以减少brownout风险
// MP3解码器相关
HMP3Decoder mp3_decoder_;
MP3FrameInfo mp3_frame_info_;
bool mp3_decoder_initialized_;
// 播放队列相关
std::vector<SongInfo> playlist_;
mutable std::mutex playlist_mutex_;
std::atomic<int> current_playlist_index_;
std::atomic<bool> playlist_mode_;
std::thread playlist_thread_;
// 私有方法
void DownloadAudioStream(const std::string& music_url);
void PlayAudioStream();
void ClearAudioBuffer();
bool InitializeMp3Decoder();
void CleanupMp3Decoder();
void ResetSampleRate(); // 重置采样率到原始值
// 歌词相关私有方法
bool DownloadLyrics(const std::string& lyric_url);
bool ParseLyrics(const std::string& lyric_content);
void LyricDisplayThread();
void UpdateLyricDisplay(int64_t current_time_ms);
// ID3标签处理
size_t SkipId3Tag(uint8_t* data, size_t size);
// 播放队列管理私有方法
void PlaylistManagerThread();
void PlayCurrentSong();
int16_t* final_pcm_data_fft = nullptr;
public:
Esp32Music();
~Esp32Music();
virtual bool Download(const std::string& song_name, const std::string& artist_name) override;
virtual std::string GetDownloadResult() override;
// 新增方法
virtual bool StartStreaming(const std::string& music_url) override;
virtual bool StopStreaming() override; // 停止流式播放
virtual size_t GetBufferSize() const override { return buffer_size_; }
virtual bool IsDownloading() const override { return is_downloading_; }
virtual int16_t* GetAudioData() override { return final_pcm_data_fft; }
// 显示模式控制方法
void SetDisplayMode(DisplayMode mode);
DisplayMode GetDisplayMode() const { return display_mode_.load(); }
// 音乐播放信息获取方法
virtual int GetCurrentSongDurationSeconds() const override { return current_song_duration_seconds_; }
virtual int GetCurrentPlayTimeSeconds() const override { return (int)(current_play_time_ms_ / 1000); }
virtual float GetPlayProgress() const override {
if (current_song_duration_seconds_ <= 0) return 0.0f;
return (float)(current_play_time_ms_ / 1000) / current_song_duration_seconds_ * 100.0f;
}
// 播放队列相关方法
virtual bool PlayPlaylist(const std::vector<SongInfo>& songs) override;
virtual bool NextSong() override;
virtual bool PreviousSong() override;
virtual void StopPlaylist() override;
virtual bool IsPlaylistMode() const override { return playlist_mode_.load(); }
virtual int GetCurrentPlaylistIndex() const override { return current_playlist_index_.load(); }
virtual size_t GetPlaylistSize() const override;
virtual SongInfo GetCurrentSong() const override;
};
#endif // ESP32_MUSIC_H