Update to 2.0.1
This commit is contained in:
@@ -2,19 +2,21 @@
|
||||
#include "system_info.h"
|
||||
#include "settings.h"
|
||||
#include "display/display.h"
|
||||
#include "display/oled_display.h"
|
||||
#include "assets/lang_config.h"
|
||||
#include "esp32_music.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <esp_ota_ops.h>
|
||||
#include <esp_chip_info.h>
|
||||
#include <esp_random.h>
|
||||
|
||||
#include "esp32_music.h"
|
||||
|
||||
#define TAG "Board"
|
||||
|
||||
Board::Board() {
|
||||
music_ = nullptr; // 先初始化为空指针
|
||||
|
||||
|
||||
Settings settings("board", true);
|
||||
uuid_ = settings.GetString("uuid");
|
||||
if (uuid_.empty()) {
|
||||
@@ -22,10 +24,6 @@ Board::Board() {
|
||||
settings.SetString("uuid", uuid_);
|
||||
}
|
||||
ESP_LOGI(TAG, "UUID=%s SKU=%s", uuid_.c_str(), BOARD_NAME);
|
||||
|
||||
// 初始化音乐播放器
|
||||
music_ = new Esp32Music();
|
||||
ESP_LOGI(TAG, "Music player initialized for all boards");
|
||||
}
|
||||
|
||||
Board::~Board() {
|
||||
@@ -173,6 +171,21 @@ std::string Board::GetSystemInfoJson() {
|
||||
json += R"("label":")" + std::string(ota_partition->label) + R"(")";
|
||||
json += R"(},)";
|
||||
|
||||
// Append display info
|
||||
auto display = GetDisplay();
|
||||
if (display) {
|
||||
json += R"("display":{)";
|
||||
if (dynamic_cast<OledDisplay*>(display)) {
|
||||
json += R"("monochrome":)" + std::string("true") + R"(,)";
|
||||
} else {
|
||||
json += R"("monochrome":)" + std::string("false") + R"(,)";
|
||||
}
|
||||
json += R"("width":)" + std::to_string(display->width()) + R"(,)";
|
||||
json += R"("height":)" + std::to_string(display->height()) + R"(,)";
|
||||
json.pop_back(); // Remove the last comma
|
||||
}
|
||||
json += R"(},)";
|
||||
|
||||
json += R"("board":)" + GetBoardJson();
|
||||
|
||||
// Close the JSON object
|
||||
|
||||
@@ -11,9 +11,10 @@
|
||||
#include "led/led.h"
|
||||
#include "backlight.h"
|
||||
#include "camera.h"
|
||||
#include "music.h"
|
||||
#include "assets.h"
|
||||
|
||||
#include "music.h"
|
||||
|
||||
|
||||
void* create_board();
|
||||
class AudioCodec;
|
||||
@@ -32,6 +33,7 @@ protected:
|
||||
|
||||
// 音乐播放器实例
|
||||
Music* music_;
|
||||
|
||||
public:
|
||||
static Board& GetInstance() {
|
||||
static Board* instance = static_cast<Board*>(create_board());
|
||||
@@ -64,4 +66,4 @@ void* create_board() { \
|
||||
return new BOARD_CLASS_NAME(); \
|
||||
}
|
||||
|
||||
#endif // BOARD_H
|
||||
#endif // BOARD_H
|
||||
|
||||
@@ -63,33 +63,26 @@ bool Esp32Camera::Capture() {
|
||||
// 显示预览图片
|
||||
auto display = dynamic_cast<LvglDisplay*>(Board::GetInstance().GetDisplay());
|
||||
if (display != nullptr) {
|
||||
// Create a new preview image
|
||||
auto img_dsc = (lv_img_dsc_t*)heap_caps_calloc(1, sizeof(lv_img_dsc_t), MALLOC_CAP_8BIT);
|
||||
img_dsc->header.magic = LV_IMAGE_HEADER_MAGIC;
|
||||
img_dsc->header.cf = LV_COLOR_FORMAT_RGB565;
|
||||
img_dsc->header.flags = 0;
|
||||
img_dsc->header.w = fb_->width;
|
||||
img_dsc->header.h = fb_->height;
|
||||
img_dsc->header.stride = fb_->width * 2;
|
||||
img_dsc->data_size = fb_->width * fb_->height * 2;
|
||||
img_dsc->data = (uint8_t*)heap_caps_malloc(img_dsc->data_size, MALLOC_CAP_SPIRAM);
|
||||
if (img_dsc->data == nullptr) {
|
||||
auto data = (uint8_t*)heap_caps_malloc(fb_->len, MALLOC_CAP_SPIRAM);
|
||||
if (data == nullptr) {
|
||||
ESP_LOGE(TAG, "Failed to allocate memory for preview image");
|
||||
heap_caps_free(img_dsc);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto src = (uint16_t*)fb_->buf;
|
||||
auto dst = (uint16_t*)img_dsc->data;
|
||||
auto dst = (uint16_t*)data;
|
||||
size_t pixel_count = fb_->len / 2;
|
||||
for (size_t i = 0; i < pixel_count; i++) {
|
||||
// 交换每个16位字内的字节
|
||||
dst[i] = __builtin_bswap16(src[i]);
|
||||
}
|
||||
display->SetPreviewImage(img_dsc);
|
||||
|
||||
auto image = std::make_unique<LvglAllocatedImage>(data, fb_->len, fb_->width, fb_->height, fb_->width * 2, LV_COLOR_FORMAT_RGB565);
|
||||
display->SetPreviewImage(std::move(image));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Esp32Camera::SetHMirror(bool enabled) {
|
||||
sensor_t *s = esp_camera_sensor_get();
|
||||
if (s == nullptr) {
|
||||
|
||||
@@ -166,11 +166,12 @@ Esp32Music::Esp32Music() : last_downloaded_data_(), current_music_url_(), curren
|
||||
song_name_displayed_(false), current_lyric_url_(), lyrics_(),
|
||||
current_lyric_index_(-1), lyric_thread_(), is_lyric_running_(false),
|
||||
display_mode_(DISPLAY_MODE_LYRICS), is_playing_(false), is_downloading_(false),
|
||||
play_thread_(), download_thread_(), audio_buffer_(), buffer_mutex_(),
|
||||
is_paused_(false), play_thread_(), download_thread_(), audio_buffer_(), buffer_mutex_(),
|
||||
buffer_cv_(), buffer_size_(0), mp3_decoder_(nullptr), mp3_frame_info_(),
|
||||
mp3_decoder_initialized_(false) {
|
||||
ESP_LOGI(TAG, "Music player initialized with default spectrum display mode");
|
||||
InitializeMp3Decoder();
|
||||
// 延迟MP3解码器初始化,避免在构造函数中初始化导致的问题
|
||||
// InitializeMp3Decoder();
|
||||
}
|
||||
|
||||
Esp32Music::~Esp32Music() {
|
||||
@@ -282,9 +283,9 @@ Esp32Music::~Esp32Music() {
|
||||
}
|
||||
|
||||
bool Esp32Music::Download(const std::string& song_name, const std::string& artist_name) {
|
||||
ESP_LOGI(TAG, "Starting to get music details for: %s", song_name.c_str());
|
||||
ESP_LOGI(TAG, "云端由MeowEmbeddedMusicServer喵波音律嵌入式提供");
|
||||
ESP_LOGI(TAG, "喵波音律QQ交流群:865754861");
|
||||
ESP_LOGI(TAG, "Starting to get music details for: %s", song_name.c_str());
|
||||
|
||||
// 清空之前的下载数据
|
||||
last_downloaded_data_.clear();
|
||||
@@ -357,21 +358,17 @@ bool Esp32Music::Download(const std::string& song_name, const std::string& artis
|
||||
if (cJSON_IsString(audio_url) && audio_url->valuestring && strlen(audio_url->valuestring) > 0) {
|
||||
ESP_LOGI(TAG, "Audio URL path: %s", audio_url->valuestring);
|
||||
|
||||
// 第二步:直接使用audio_url播放音乐
|
||||
std::string audio_path = audio_url->valuestring;
|
||||
current_music_url_ = audio_path;
|
||||
// 第二步:直接使用音频URL开始流式播放
|
||||
std::string current_music_url_ = audio_url->valuestring;
|
||||
|
||||
ESP_LOGI(TAG, "云端由MeowEmbeddedMusicServer喵波音律嵌入式提供");
|
||||
ESP_LOGI(TAG, "喵波音律QQ交流群:865754861");
|
||||
ESP_LOGI(TAG, "Starting streaming playback for: %s", song_name.c_str());
|
||||
song_name_displayed_ = false; // 重置歌名显示标志
|
||||
StartStreaming(current_music_url_);
|
||||
|
||||
// 处理歌词URL - 只有在歌词显示模式下才启动歌词
|
||||
if (cJSON_IsString(lyric_url) && lyric_url->valuestring && strlen(lyric_url->valuestring) > 0) {
|
||||
// 直接使用歌词URL
|
||||
std::string lyric_path = lyric_url->valuestring;
|
||||
current_lyric_url_ = lyric_path;
|
||||
// 使用歌词URL获取歌词
|
||||
std::string current_lyric_url_ = lyric_url->valuestring;
|
||||
|
||||
// 根据显示模式决定是否启动歌词
|
||||
if (display_mode_ == DISPLAY_MODE_LYRICS) {
|
||||
@@ -431,6 +428,14 @@ bool Esp32Music::StartStreaming(const std::string& music_url) {
|
||||
|
||||
ESP_LOGD(TAG, "Starting streaming for URL: %s", music_url.c_str());
|
||||
|
||||
// 确保MP3解码器已初始化
|
||||
if (!mp3_decoder_initialized_) {
|
||||
if (!InitializeMp3Decoder()) {
|
||||
ESP_LOGE(TAG, "Failed to initialize MP3 decoder");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 停止之前的播放和下载
|
||||
is_downloading_ = false;
|
||||
is_playing_ = false;
|
||||
@@ -491,6 +496,7 @@ bool Esp32Music::StopStreaming() {
|
||||
// 停止下载和播放标志
|
||||
is_downloading_ = false;
|
||||
is_playing_ = false;
|
||||
is_paused_ = false; // 重置暂停状态
|
||||
|
||||
// 清空歌名显示
|
||||
auto& board = Board::GetInstance();
|
||||
@@ -723,8 +729,6 @@ void Esp32Music::PlayAudioStream() {
|
||||
});
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "云端由MeowEmbeddedMusicServer喵波音律嵌入式提供");
|
||||
ESP_LOGI(TAG, "喵波音律QQ交流群:865754861");
|
||||
ESP_LOGI(TAG, "Starting playback with buffer size: %d", buffer_size_);
|
||||
|
||||
size_t total_played = 0;
|
||||
@@ -744,18 +748,20 @@ void Esp32Music::PlayAudioStream() {
|
||||
bool id3_processed = false;
|
||||
|
||||
while (is_playing_) {
|
||||
// 检查是否被暂停
|
||||
if (is_paused_) {
|
||||
ESP_LOGD(TAG, "Music playback paused, waiting...");
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
continue;
|
||||
}
|
||||
|
||||
// 检查设备状态,只有在空闲状态才播放音乐
|
||||
auto& app = Application::GetInstance();
|
||||
DeviceState current_state = app.GetDeviceState();
|
||||
|
||||
// 状态转换:说话中-》聆听中-》待机状态-》播放音乐
|
||||
if (current_state == kDeviceStateListening || current_state == kDeviceStateSpeaking) {
|
||||
if (current_state == kDeviceStateSpeaking) {
|
||||
ESP_LOGI(TAG, "Device is in speaking state, switching to listening state for music playback");
|
||||
}
|
||||
if (current_state == kDeviceStateListening) {
|
||||
ESP_LOGI(TAG, "Device is in listening state, switching to idle state for music playback");
|
||||
}
|
||||
// 等小智把话说完了,变成聆听状态之后,马上转成待机状态,进入音乐播放
|
||||
if (current_state == kDeviceStateListening) {
|
||||
ESP_LOGI(TAG, "Device is in listening state, switching to idle state for music playback");
|
||||
// 切换状态
|
||||
app.ToggleChatState(); // 变成待机状态
|
||||
vTaskDelay(pdMS_TO_TICKS(300));
|
||||
@@ -1133,8 +1139,6 @@ bool Esp32Music::DownloadLyrics(const std::string& lyric_url) {
|
||||
add_auth_headers(http.get());
|
||||
|
||||
// 打开GET连接
|
||||
ESP_LOGI(TAG, "云端由MeowEmbeddedMusicServer喵波音律嵌入式提供");
|
||||
ESP_LOGI(TAG, "喵波音律QQ交流群:865754861");
|
||||
if (!http->Open("GET", current_url)) {
|
||||
ESP_LOGE(TAG, "Failed to open HTTP connection for lyrics");
|
||||
// 移除delete http; 因为unique_ptr会自动管理内存
|
||||
@@ -1426,4 +1430,99 @@ void Esp32Music::SetDisplayMode(DisplayMode mode) {
|
||||
ESP_LOGI(TAG, "Display mode changed from %s to %s",
|
||||
(old_mode == DISPLAY_MODE_SPECTRUM) ? "SPECTRUM" : "LYRICS",
|
||||
(mode == DISPLAY_MODE_SPECTRUM) ? "SPECTRUM" : "LYRICS");
|
||||
}
|
||||
|
||||
// MCP工具需要的方法实现
|
||||
bool Esp32Music::SetVolume(int volume) {
|
||||
ESP_LOGI(TAG, "SetVolume called with volume: %d", volume);
|
||||
|
||||
// 验证音量范围
|
||||
if (volume < 0 || volume > 100) {
|
||||
ESP_LOGW(TAG, "Invalid volume level: %d, must be between 0-100", volume);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 通过Board获取AudioCodec并设置音量
|
||||
auto& board = Board::GetInstance();
|
||||
auto codec = board.GetAudioCodec();
|
||||
if (codec) {
|
||||
codec->SetOutputVolume(volume);
|
||||
ESP_LOGI(TAG, "Volume set to %d%%", volume);
|
||||
return true;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "No audio codec available");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Esp32Music::PlaySong() {
|
||||
ESP_LOGI(TAG, "PlaySong called");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Esp32Music::StopSong() {
|
||||
ESP_LOGI(TAG, "StopSong called");
|
||||
return StopStreaming();
|
||||
}
|
||||
|
||||
bool Esp32Music::PauseSong() {
|
||||
ESP_LOGI(TAG, "PauseSong called");
|
||||
|
||||
// 检查是否正在播放
|
||||
if (!is_playing_) {
|
||||
ESP_LOGW(TAG, "No music is currently playing");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查是否已经暂停
|
||||
if (is_paused_) {
|
||||
ESP_LOGW(TAG, "Music is already paused");
|
||||
return true;
|
||||
}
|
||||
|
||||
// 设置暂停标志
|
||||
is_paused_ = true;
|
||||
ESP_LOGI(TAG, "Music playback paused");
|
||||
|
||||
// 更新显示状态
|
||||
auto& board = Board::GetInstance();
|
||||
auto display = board.GetDisplay();
|
||||
if (display && !current_song_name_.empty()) {
|
||||
std::string formatted_song_name = "《" + current_song_name_ + "》已暂停";
|
||||
display->SetMusicInfo(formatted_song_name.c_str());
|
||||
ESP_LOGI(TAG, "Updated display: %s", formatted_song_name.c_str());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Esp32Music::ResumeSong() {
|
||||
ESP_LOGI(TAG, "ResumeSong called");
|
||||
|
||||
// 检查是否正在播放
|
||||
if (!is_playing_) {
|
||||
ESP_LOGW(TAG, "No music is currently playing");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查是否已经恢复
|
||||
if (!is_paused_) {
|
||||
ESP_LOGW(TAG, "Music is not paused");
|
||||
return true;
|
||||
}
|
||||
|
||||
// 清除暂停标志
|
||||
is_paused_ = false;
|
||||
ESP_LOGI(TAG, "Music playback resumed");
|
||||
|
||||
// 更新显示状态
|
||||
auto& board = Board::GetInstance();
|
||||
auto display = board.GetDisplay();
|
||||
if (display && !current_song_name_.empty()) {
|
||||
std::string formatted_song_name = "《" + current_song_name_ + "》播放中...";
|
||||
display->SetMusicInfo(formatted_song_name.c_str());
|
||||
ESP_LOGI(TAG, "Updated display: %s", formatted_song_name.c_str());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -38,7 +38,6 @@ private:
|
||||
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_;
|
||||
@@ -51,6 +50,7 @@ private:
|
||||
std::atomic<DisplayMode> display_mode_;
|
||||
std::atomic<bool> is_playing_;
|
||||
std::atomic<bool> is_downloading_;
|
||||
std::atomic<bool> is_paused_;
|
||||
std::thread play_thread_;
|
||||
std::thread download_thread_;
|
||||
int64_t current_play_time_ms_; // 当前播放时间(毫秒)
|
||||
@@ -102,11 +102,20 @@ public:
|
||||
virtual bool StopStreaming() override; // 停止流式播放
|
||||
virtual size_t GetBufferSize() const override { return buffer_size_; }
|
||||
virtual bool IsDownloading() const override { return is_downloading_; }
|
||||
virtual bool IsPlaying() const override { return is_playing_; }
|
||||
virtual bool IsPaused() const override { return is_paused_; }
|
||||
virtual int16_t* GetAudioData() override { return final_pcm_data_fft; }
|
||||
|
||||
// 显示模式控制方法
|
||||
void SetDisplayMode(DisplayMode mode);
|
||||
DisplayMode GetDisplayMode() const { return display_mode_.load(); }
|
||||
|
||||
// MCP工具需要的方法
|
||||
virtual bool PlaySong() override;
|
||||
virtual bool SetVolume(int volume) override;
|
||||
virtual bool StopSong() override;
|
||||
virtual bool PauseSong() override;
|
||||
virtual bool ResumeSong() override;
|
||||
};
|
||||
|
||||
#endif // ESP32_MUSIC_H
|
||||
@@ -15,7 +15,16 @@ public:
|
||||
virtual bool StopStreaming() = 0; // 停止流式播放
|
||||
virtual size_t GetBufferSize() const = 0;
|
||||
virtual bool IsDownloading() const = 0;
|
||||
virtual bool IsPlaying() const = 0;
|
||||
virtual bool IsPaused() const = 0;
|
||||
virtual int16_t* GetAudioData() = 0;
|
||||
|
||||
// MCP工具需要的方法
|
||||
virtual bool PlaySong() = 0;
|
||||
virtual bool SetVolume(int volume) = 0;
|
||||
virtual bool StopSong() = 0;
|
||||
virtual bool PauseSong() = 0;
|
||||
virtual bool ResumeSong() = 0;
|
||||
};
|
||||
|
||||
#endif // MUSIC_H
|
||||
Reference in New Issue
Block a user