From 17ac2ce0ed52874616c79c910667e41e34604826 Mon Sep 17 00:00:00 2001
From: wangzhibo <wangzhibo@shsening.com>
Date: 星期一, 31 八月 2026 13:14:12 +0800
Subject: [PATCH] add translation app

---
 xiaozhi-esp32-2.2.6/main/boards/sening-xiaozhi-s3/mp3_player.cc |   59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 56 insertions(+), 3 deletions(-)

diff --git a/xiaozhi-esp32-2.2.6/main/boards/sening-xiaozhi-s3/mp3_player.cc b/xiaozhi-esp32-2.2.6/main/boards/sening-xiaozhi-s3/mp3_player.cc
index 0cf4cf0..cc87034 100644
--- a/xiaozhi-esp32-2.2.6/main/boards/sening-xiaozhi-s3/mp3_player.cc
+++ b/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;
+}

--
Gitblit v1.9.1