wangzhibo
2026-08-31 17ac2ce0ed52874616c79c910667e41e34604826
xiaozhi-esp32-2.2.6/main/boards/sening-xiaozhi-s3/sening_xiaozhi_s3.cc
@@ -9,6 +9,7 @@
#include "power_save_timer.h"
#include "adc_battery_monitor.h"
#include "wifi_manager.h"
#include "app_task.h"
#include <esp_log.h>
#include <esp_efuse_table.h>
@@ -722,20 +723,27 @@
        static float last_mp3_play_speed = 1.0f;
        static int64_t last_mp3_play_time = 0;
        mcp_server.AddTool("self.mp3.play",
            "Play one MP3 file from the SD card. The name argument must exactly match a files[].name from self.mp3.get_list. Optional speed supports only 0.5, 0.75, 1.0, 1.25, 1.5, or 2.0; non-1.0 speeds change pitch and affect only SD card MP3 playback. For play, random play, switch song, or named-song requests, call this tool before telling the user playback has started. Do not call this tool repeatedly for the same user request after it has returned accepted=true.",
            "Play one MP3 file from the SD card. The name argument must exactly match a files[].name from self.mp3.get_list. Optional speed supports only 0.5, 0.75, 1.0, 1.25, 1.5, or 2.0; non-1.0 speeds change pitch and affect only SD card MP3 playback. Optional repeat is the number of full-file loops (default 1). Optional power_off_after requests existing power-off standby after a natural finish, not after stop. For play, random play, switch song, or named-song requests, call this tool before telling the user playback has started. Do not call this tool repeatedly for the same user request after it has returned accepted=true.",
            PropertyList({
                Property("name", kPropertyTypeString),
                Property("speed", kPropertyTypeNumber, 1.0)
                Property("speed", kPropertyTypeNumber, 1.0),
                Property("repeat", kPropertyTypeInteger, 1, 1, 99),
                Property("power_off_after", kPropertyTypeBoolean, false)
            }),
            [](const PropertyList& properties) -> ReturnValue {
                std::string name = properties["name"].value<std::string>();
                float speed = static_cast<float>(properties["speed"].value<double>());
                int repeat = properties["repeat"].value<int>();
                bool power_off_after = properties["power_off_after"].value<bool>();
                if (repeat < 1) {
                    repeat = 1;
                }
                int64_t now = esp_timer_get_time();
                if (name == last_mp3_play_name && std::fabs(speed - last_mp3_play_speed) < 0.001f && now - last_mp3_play_time < 15000000) {
                    return std::string("{\"accepted\":true,\"duplicate_ignored\":true}");
                }
                esp_err_t err = SDCard_Play_MP3_With_Speed(name.data(), speed);
                esp_err_t err = SDCard_Play_MP3_With_Speed_Repeat(name.data(), speed, repeat, power_off_after);
                if (err != ESP_OK) {
                    return std::string("{\"accepted\":false,\"error\":\"") + esp_err_to_name(err) +
                        "\",\"retry\":\"use exact files[].name from self.mp3.get_list\"}";
@@ -743,7 +751,8 @@
                last_mp3_play_name = name;
                last_mp3_play_speed = speed;
                last_mp3_play_time = now;
                return std::string("{\"accepted\":true}");
                return std::string("{\"accepted\":true,\"repeat\":") + std::to_string(repeat) +
                    ",\"power_off_after\":" + (power_off_after ? "true" : "false") + "}";
            });
        mcp_server.AddTool("self.mp3.get_status",
@@ -751,7 +760,8 @@
            PropertyList(),
            [](const PropertyList& properties) -> ReturnValue {
                return std::string("{\"playing\":") + (SDCard_Is_Playing() ? "true" : "false") +
                    ",\"tts_paused\":" + (SDCard_Is_Paused() ? "true" : "false") + "}";
                    ",\"tts_paused\":" + (SDCard_Is_Paused() ? "true" : "false") +
                    ",\"repeat_left\":" + std::to_string(SDCard_Get_Repeat_Left()) + "}";
            });
        mcp_server.AddTool("self.mp3.stop",
@@ -855,6 +865,21 @@
        InitializeTools();
    }
    void OnDeviceReady() override {
        xTaskCreate([](void *arg) {
            (void)arg;
            vTaskDelay(pdMS_TO_TICKS(1500));
            Board_ResolveBootOrRestore(false);
            vTaskDelete(nullptr);
        }, "boot_app_task", 4096, nullptr, 3, nullptr);
    }
    bool OnRestoredFromPowerOff(bool network_ready) override {
        (void)network_ready;
        Board_ResolveBootOrRestore(true);
        return true;
    }
    virtual void SetNetworkEventCallback(NetworkEventCallback callback) override {
        WifiBoard::SetNetworkEventCallback([this, callback](NetworkEvent event, const std::string& data) {
            if (event == NetworkEvent::Connected) {