wangzhibo
2026-08-31 17ac2ce0ed52874616c79c910667e41e34604826
xiaozhi-esp32-2.2.6/main/boards/sening-xiaozhi-s3/mp3_player.cc
@@ -1,7 +1,9 @@
#include "system.h"
#include "app_task.h"
#include "audio_codec.h"
#include "board.h"
#include "application.h"
#include <esp_log.h>
#include <freertos/FreeRTOS.h>
@@ -27,11 +29,14 @@
typedef struct {
    char path[SDCARD_PATH_MAX_LEN];
    float speed;
    int repeat;
    bool power_off_after;
} mp3_player_task_arg_t;
static TaskHandle_t mp3_player_task_handle;
static volatile bool mp3_stop_requested;
static volatile bool mp3_pause_requested;
static volatile int mp3_repeat_left;
static std::vector<int16_t> convert_channels(const int16_t *input, size_t frame_count, uint8_t src_channels, uint8_t dst_channels)
{
@@ -127,6 +132,8 @@
    char path[SDCARD_PATH_MAX_LEN];
    strlcpy(path, task_arg->path, sizeof(path));
    float speed = task_arg->speed;
    int repeat = task_arg->repeat < 1 ? 1 : task_arg->repeat;
    bool power_off_after = task_arg->power_off_after;
    free(task_arg);
    FILE *fp = fopen(path, "rb");
@@ -134,6 +141,7 @@
        ESP_LOGE(TAG, "open MP3 failed: %s", path);
        mp3_player_task_handle = nullptr;
        mp3_stop_requested = false;
        mp3_repeat_left = 0;
        vTaskDelete(nullptr);
        return;
    }
@@ -144,6 +152,7 @@
        fclose(fp);
        mp3_player_task_handle = nullptr;
        mp3_stop_requested = false;
        mp3_repeat_left = 0;
        vTaskDelete(nullptr);
        return;
    }
@@ -167,6 +176,7 @@
        fclose(fp);
        mp3_player_task_handle = nullptr;
        mp3_stop_requested = false;
        mp3_repeat_left = 0;
        vTaskDelete(nullptr);
        return;
    }
@@ -184,11 +194,27 @@
        ESP_LOGE(TAG, "no memory for MP3 playback");
        ret = ESP_AUDIO_ERR_MEM_LACK;
    } else {
        ESP_LOGI(TAG, "play MP3: %s, speed: %.2fx", path, speed);
        ESP_LOGI(TAG, "play MP3: %s, speed: %.2fx, repeat: %d, power_off_after: %d", path, speed, repeat, power_off_after ? 1 : 0);
        if (wait_if_paused()) {
            codec->EnableOutput(true);
        }
        for (int pass = 0; pass < repeat && ret == ESP_AUDIO_ERR_OK && !mp3_stop_requested; ++pass) {
            mp3_repeat_left = repeat - pass;
            if (pass > 0) {
                if (fseek(fp, 0, SEEK_SET) != 0) {
                    ESP_LOGE(TAG, "rewind MP3 failed: %s", path);
                    break;
                }
                esp_audio_simple_dec_close(decoder);
                decoder = nullptr;
                ret = esp_audio_simple_dec_open(&dec_cfg, &decoder);
                if (ret != ESP_AUDIO_ERR_OK || !decoder) {
                    ESP_LOGE(TAG, "reopen MP3 decoder failed: %d", ret);
                    break;
                }
            }
        while (ret == ESP_AUDIO_ERR_OK && !mp3_stop_requested) {
            if (!wait_if_paused()) {
@@ -287,6 +313,7 @@
                break;
            }
        }
        }
    }
    if (rate_cvt_handle) {
@@ -297,27 +324,44 @@
    }
    free(in_buf);
    free(out_buf);
    esp_audio_simple_dec_close(decoder);
    if (decoder) {
        esp_audio_simple_dec_close(decoder);
    }
    esp_audio_simple_dec_unregister_default();
    esp_audio_dec_unregister_default();
    fclose(fp);
    ESP_LOGI(TAG, "MP3 playback %s: %s", mp3_stop_requested ? "stopped" : "finished", path);
    bool stopped = mp3_stop_requested;
    bool should_power_off = power_off_after && !stopped;
    mp3_player_task_handle = nullptr;
    mp3_stop_requested = false;
    mp3_pause_requested = false;
    mp3_repeat_left = 0;
    if (should_power_off) {
        Application::GetInstance().RequestPowerOffStandby();
    }
    Board_OnSkillPlaybackFinished(stopped, power_off_after);
    vTaskDelete(nullptr);
}
extern "C" esp_err_t SDCard_Play_MP3_File(const char *path)
{
    return SDCard_Play_MP3_File_With_Speed(path, 1.0f);
    return SDCard_Play_MP3_File_With_Speed_Repeat(path, 1.0f, 1, false);
}
extern "C" esp_err_t SDCard_Play_MP3_File_With_Speed(const char *path, float speed)
{
    return SDCard_Play_MP3_File_With_Speed_Repeat(path, speed, 1, false);
}
extern "C" esp_err_t SDCard_Play_MP3_File_With_Speed_Repeat(const char *path, float speed, int repeat, bool power_off_after)
{
    if (!path || path[0] == '\0' || !is_supported_speed(speed)) {
        return ESP_ERR_INVALID_ARG;
    }
    if (repeat < 1) {
        repeat = 1;
    }
    bool start_paused = mp3_pause_requested;
@@ -335,13 +379,17 @@
    }
    strlcpy(arg->path, path, sizeof(arg->path));
    arg->speed = speed;
    arg->repeat = repeat;
    arg->power_off_after = power_off_after;
    mp3_stop_requested = false;
    mp3_pause_requested = start_paused;
    mp3_repeat_left = repeat;
    BaseType_t ret = xTaskCreate(mp3_player_task, "mp3_player", MP3_PLAYER_STACK_SIZE, arg, MP3_PLAYER_PRIORITY, &mp3_player_task_handle);
    if (ret != pdPASS) {
        free(arg);
        mp3_player_task_handle = nullptr;
        mp3_repeat_left = 0;
        return ESP_FAIL;
    }
@@ -378,3 +426,8 @@
{
    return mp3_player_task_handle != nullptr && mp3_pause_requested;
}
extern "C" int SDCard_Get_Repeat_Left(void)
{
    return mp3_repeat_left;
}