ln:解决日程音频不播放问题,播放完后销毁播放线程 2576/1 2576/head 2577/target/1
authorluozheng <1732036298@qq.com>
Tue, 21 Oct 2025 04:07:20 +0000 (12:07 +0800)
committerluozheng <1732036298@qq.com>
Tue, 21 Oct 2025 04:07:20 +0000 (12:07 +0800)
code/sdk/zhihui/leiniao/imsl_ln/ln_api_schedule.c
code/sdk/zhihui/leiniao/ln_api_cpp/CMakeLists.txt
code/sdk/zhihui/leiniao/ln_api_cpp/audio_stream_player.cpp
code/sdk/zhihui/leiniao/ln_api_cpp/audio_stream_player.h

index 9b79fde..519afb6 100644 (file)
@@ -6,6 +6,7 @@
 #include "vibrator_service.h"
 #include "wearable_log.h"
 #include "ai_media.h"
+#include "audio_stream_player.h"
 
 ScheduleReminder g_schedule_reminder = {0};
 ScheduleReminderConfig g_schedule_reminder_config = {0};
@@ -225,7 +226,9 @@ void ln_parse_schedule_reminder(const char *json_buf, int json_len)
                 WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[JSON_PARSE] vibration:不执行震动\n");
             }
             // 从文件中读取数据放到音频流内
-            play_mp3_audio_from_file(LN_REMINDER_AUDIO_FILE);
+            // play_mp3_audio_from_file(LN_REMINDER_AUDIO_FILE);
+            // 下载成功后
+            ln_audio_player_play_file(LN_REMINDER_AUDIO_FILE);
         }
         else
         {
index 3db202a..2ac4dd9 100644 (file)
@@ -21,6 +21,7 @@ ${ROOT_DIR}/application/wearable/ln/nativeapp/nativeui/
 set(AI_SOURCES
 ${CMAKE_CURRENT_SOURCE_DIR}/audio_stream_player.cpp
 ${CMAKE_CURRENT_SOURCE_DIR}/ln_api_interface.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/audio_stream_player.cpp
 )
 
 set(SOURCES
index 5b6b6a9..a365014 100644 (file)
@@ -7,10 +7,10 @@
 
 #include "audio_stream_player.h"
 #include <stdlib.h>
+#include <stdio.h>
 #include <string.h>
 #include <unistd.h>
 #include <time.h>
-#include <errno.h>
 
 // 包含音频管理相关头文件
 #include "audio_manager_c_wrapper.h"
@@ -246,7 +246,7 @@ int32_t AudioStreamPlayerInit(AudioStreamPlayerHandle handle,
     }
 
     // 激活音频中断
-    if (AudioManagerActivateInterrupt(AUDIO_STREAM_VOICE_ASSISTANT, sessionId) == INTERRUPT_FAILED)
+    if (AudioManagerActivateInterrupt(AUDIO_STREAM_ALARM_CLOCK, sessionId) == INTERRUPT_FAILED)
     {
         MEDIA_ERR_LOG("AudioStreamPlayerInit: failed to activate audio interrupt");
         return -1;
@@ -259,7 +259,7 @@ int32_t AudioStreamPlayerInit(AudioStreamPlayerHandle handle,
     renderConfig.linkDir = AUDIO_UP_LINK; // 上行链路,用于播放
     renderConfig.sampleRate = ctx->config.sampleRate;
     renderConfig.sessionID = sessionId;
-    renderConfig.streamType = AUDIO_STREAM_VOICE_ASSISTANT;
+    renderConfig.streamType = AUDIO_STREAM_ALARM_CLOCK;
 
     // 初始化音频输出流
     int32_t ret = AudioStreamOutInit(renderConfig);
@@ -311,7 +311,7 @@ int32_t AudioStreamPlayerStart(AudioStreamPlayerHandle handle)
     task_cfg.create_queue_handle = CreateAudioStreamQueue;
     task_cfg.attr.name = "AudioStreamPlayThread";
     task_cfg.attr.priority = (osPriority_t)16;
-    task_cfg.attr.stack_size = 0x2000; // 8KB
+    task_cfg.attr.stack_size = 0x1000; // 8KB
     task_cfg.func = AudioStreamPlayThread;
     task_cfg.use_mem = USE_EXTEND_MEM;
     extern errcode_t uapi_create_osThread_custom(app_task_definition_t * task_cfg);
@@ -587,7 +587,7 @@ int32_t AudioStreamPlayerSetVolume(AudioStreamPlayerHandle handle, float volume)
     AudioStreamPlayerContext *ctx = (AudioStreamPlayerContext *)handle;
     ctx->volume = volume;
     // 设置音频流音量 - 使用AudioManagerSetVolume
-    AudioManagerSetVolume(AUDIO_STREAM_VOICE_ASSISTANT, (int32_t)(volume * 100));
+    AudioManagerSetVolume(AUDIO_STREAM_ALARM_CLOCK, (int32_t)(volume * 100));
     WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"AudioStreamPlayerSetVolume: set to %.2f", volume);
     return 0;
 }
@@ -713,6 +713,74 @@ int32_t ln_audio_player_get_stats(AudioStreamStats* stats)
     return AudioStreamPlayerGetStats(g_ln_audio_player, stats);
 }
 
+uint32_t ln_audio_player_stop(void)
+{
+    if (g_ln_audio_player == nullptr) {
+        return ERRCODE_SUCC;
+    }
+    (void)AudioStreamPlayerDestroy(g_ln_audio_player);
+    g_ln_audio_player = nullptr;
+    return ERRCODE_SUCC;
+}
+
+uint32_t ln_audio_player_play_file(const char *file_path)
+{
+    if (file_path == nullptr) {
+        return ERRCODE_FAIL;
+    }
+
+    FILE *file = fopen(file_path, "rb");
+    if (file == nullptr) {
+        return ERRCODE_FAIL;
+    }
+
+    if (ln_audio_player_init() != ERRCODE_SUCC) {
+        fclose(file);
+        return ERRCODE_FAIL;
+    }
+
+    // 获取文件大小(可用于完成判定的辅助)
+    long file_size = 0;
+    long current_pos = ftell(file);
+    if (current_pos >= 0) {
+        (void)fseek(file, 0, SEEK_END);
+        file_size = ftell(file);
+        (void)fseek(file, 0, SEEK_SET);
+    }
+
+    const size_t CHUNK_SIZE = 1024; // 与现有用法一致
+    uint8_t buffer[CHUNK_SIZE];
+    size_t read_len;
+    while ((read_len = fread(buffer, 1, CHUNK_SIZE, file)) > 0) {
+        if (ln_audio_player_write(buffer, (uint32_t)read_len) != 0) {
+            fclose(file);
+            (void)ln_audio_player_stop();
+            return ERRCODE_FAIL;
+        }
+    }
+    fclose(file);
+
+    // 先等待播放队列清空
+    const int wait_step_us = 50 * 1000; // 50ms
+    for (;;) {
+        AudioStreamStats stats = {0};
+        if (ln_audio_player_get_stats(&stats) == 0) {
+            if (stats.queueCurrentSize == 0) {
+                break;
+            }
+        }
+        usleep(wait_step_us);
+    }
+
+    // 再额外等待尾部缓冲播放完成,避免被立即Stop打断结尾
+    const int tail_grace_us = 2000 * 1000; // 2s
+    usleep(tail_grace_us);
+
+    // 停止并销毁,确保线程回收
+    (void)ln_audio_player_stop();
+    return ERRCODE_SUCC;
+}
+
 #ifdef __cplusplus
 };
 #endif
\ No newline at end of file
index 2da9121..8cf03d2 100644 (file)
@@ -153,6 +153,19 @@ int32_t ln_audio_player_get_stats(AudioStreamStats* stats);
 uint32_t ln_audio_player_pause(void);
 uint32_t ln_audio_player_resume(void);
 
+/**
+ * @brief 播放指定音频文件(阻塞至播放完成并关闭播放线程)
+ * @param file_path 音频文件路径
+ * @return ERRCODE_SUCC 成功,ERRCODE_FAIL 失败
+ */
+uint32_t ln_audio_player_play_file(const char *file_path);
+
+/**
+ * @brief 立即停止并销毁播放器(如已初始化)
+ * @return ERRCODE_SUCC
+ */
+uint32_t ln_audio_player_stop(void);
+
 #ifdef __cplusplus
 }
 #endif