删除冗余代码
authorcheng <chengyf@zhihuishixun.com>
Thu, 18 Sep 2025 11:52:16 +0000 (19:52 +0800)
committercheng <chengyf@zhihuishixun.com>
Thu, 18 Sep 2025 11:52:16 +0000 (19:52 +0800)
15 files changed:
code/sdk/application/wearable/fd272/nativeapp/nativeui/leiniao/include/ln_story_player_simple.h [deleted file]
code/sdk/application/wearable/fd272/nativeapp/nativeui/leiniao/src/ln_story_player_simple.cpp [deleted file]
code/sdk/application/wearable/n9/nativeapp/nativeui/leiniao/include/ln_story_player_simple.h [deleted file]
code/sdk/application/wearable/n9/nativeapp/nativeui/leiniao/src/ln_story_player_simple.cpp [deleted file]
code/sdk/zhihui/leiniao/imsl_ln/ln_api.c
code/sdk/zhihui/leiniao/imsl_ln/ln_api_emoji.c [new file with mode: 0644]
code/sdk/zhihui/leiniao/imsl_ln/ln_api_ota.c
code/sdk/zhihui/leiniao/imsl_ln/ln_api_token.c
code/sdk/zhihui/leiniao/leiniao_python_test/device_info_apis_4.py
code/sdk/zhihui/leiniao/leiniao_python_test/device_websocket_client_6.py
code/sdk/zhihui/leiniao/leiniao_python_test/get_device_token_1.py
code/sdk/zhihui/leiniao/leiniao_python_test/integrated_speech_chatstream_2.py
code/sdk/zhihui/leiniao/leiniao_python_test/story_apis_test_3.py
code/sdk/zhihui/leiniao/ln_api_cpp/ln_story_player_simple.cpp [moved from code/sdk/application/wearable/fd230/nativeapp/nativeui/leiniao/src/ln_story_player_simple.cpp with 100% similarity]
code/sdk/zhihui/leiniao/ln_api_cpp/ln_story_player_simple.h [moved from code/sdk/application/wearable/fd230/nativeapp/nativeui/leiniao/include/ln_story_player_simple.h with 100% similarity]

diff --git a/code/sdk/application/wearable/fd272/nativeapp/nativeui/leiniao/include/ln_story_player_simple.h b/code/sdk/application/wearable/fd272/nativeapp/nativeui/leiniao/include/ln_story_player_simple.h
deleted file mode 100644 (file)
index e5ba5d8..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-#ifndef LN_STORY_PLAYER_SIMPLE_H
-#define LN_STORY_PLAYER_SIMPLE_H
-
-#ifdef __cplusplus
-#if __cplusplus
-extern "C"
-{
-#endif
-#endif
-
-#include "stdint.h"
-#include "errcode.h"
-#include <stdbool.h>
-
-/* ============================== 精简版故事播放器接口 ============================== */
-
-/**
- * @brief 开始播放指定目录下的音频文件(顺序播放)
- * @param story_dir 故事文件目录路径
- * @return true 成功,false 失败
- * 
- * 功能说明:
- * - 自动扫描目录下的音频文件(支持mp3, wav, aac, m4a格式)
- * - 按文件名顺序播放所有音频文件
- * - 播放完一个文件后自动播放下一个文件
- * - 音频系统只初始化一次,提高效率
- */
-bool ln_story_player_simple_start(const char *story_dir);
-
-/**
- * @brief 停止播放并清理所有资源
- * @return 无返回值
- * 
- * 功能说明:
- * - 立即停止当前播放
- * - 清理所有音频资源
- * - 重置播放器状态
- */
-void ln_story_player_simple_stop(void);
-
-/**
- * @brief 检查是否正在播放
- * @return true 正在播放,false 未播放
- */
-bool ln_story_player_simple_is_playing(void);
-
-/**
- * @brief 获取当前播放的文件索引
- * @return 当前播放的文件索引(从0开始),-1表示未播放
- */
-int ln_story_player_simple_get_current_index(void);
-
-/**
- * @brief 获取总文件数
- * @return 扫描到的音频文件总数
- */
-int ln_story_player_simple_get_file_count(void);
-
-/**
- * @brief 播放指定音频文件
- * @param file_path 音频文件完整路径
- * @return true 成功,false 失败
- * 
- * 功能说明:
- * - 播放指定的单个音频文件
- * - 不会自动播放下一个文件
- * - 需要手动调用停止或暂停
- */
-bool ln_story_player_simple_play_file(const char *file_path);
-
-/**
- * @brief 暂停播放
- * @return true 成功,false 失败
- * 
- * 功能说明:
- * - 暂停当前正在播放的音频
- * - 保持播放器状态,可以恢复播放
- * - 不会清理音频资源
- */
-bool ln_story_player_simple_pause(void);
-
-/**
- * @brief 恢复播放
- * @return true 成功,false 失败
- * 
- * 功能说明:
- * - 恢复之前暂停的音频播放
- * - 只能在暂停状态下调用
- * - 如果当前没有暂停的音频,返回失败
- */
-bool ln_story_player_simple_resume(void);
-
-/**
- * @brief 检查是否暂停
- * @return true 已暂停,false 未暂停
- */
-bool ln_story_player_simple_is_paused(void);
-
-/**
- * @brief 处理播放器消息队列命令(内部使用)
- * @param cmd 命令类型
- * @param data 数据指针
- * @param len 数据长度
- */
-void ln_story_player_simple_handle_message(int cmd, char *data, uint32_t len);
-
-/* ============================== 使用示例 ============================== */
-
-/*
-// 开始播放
-if (ln_story_player_simple_start("/user/leiniao/story/choose"))
-{
-    printf("播放开始成功\n");
-}
-
-// 检查播放状态
-if (ln_story_player_simple_is_playing())
-{
-    printf("正在播放第 %d 个文件,共 %d 个文件\n", 
-           ln_story_player_simple_get_current_index(),
-           ln_story_player_simple_get_file_count());
-}
-
-// 停止播放
-ln_story_player_simple_stop();
-*/
-
-#ifdef __cplusplus
-#if __cplusplus
-}
-#endif
-#endif
-#endif
diff --git a/code/sdk/application/wearable/fd272/nativeapp/nativeui/leiniao/src/ln_story_player_simple.cpp b/code/sdk/application/wearable/fd272/nativeapp/nativeui/leiniao/src/ln_story_player_simple.cpp
deleted file mode 100644 (file)
index 441ae6e..0000000
+++ /dev/null
@@ -1,731 +0,0 @@
-#include "leiniao/include/ln_story_player_simple.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <dirent.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <errno.h>
-#include <service/graphic_service.h>
-/* 引入播放器相关头文件 */
-#include "player.h"
-#include "source.h"
-#include "audio_manager.h"
-#include <audio_base_type.h>
-#include <audio_player_service.h>
-#include <custom_utils.h>
-#include <los_base.h>
-/* 引入消息队列相关头文件 */
-#include "ln_api.h"
-
-#ifdef __cplusplus
-#if __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-#endif /* __cplusplus */
-
-using OHOS::Media::Player;
-using OHOS::Media::Source;
-using namespace OHOS::Media;
-using namespace::Audio;
-using Audio::AudioManager;
-
-/* ============================== 精简版播放器结构体 ============================== */
-
-/* 播放器消息命令定义 */
-
-
-typedef struct
-{
-    /* 文件列表 */
-    char file_paths[100][256];  // 最多100个文件
-    int file_count;
-    int current_index;
-    
-    /* 播放器对象 */
-    std::shared_ptr<Player> player;
-    std::shared_ptr<Source> source;
-    std::map<std::string, std::string> header;
-    
-    /* 音频管理 */
-    AudioSession sessionId;
-    std::shared_ptr<AudioInterrupt> interrupt;
-    std::shared_ptr<InterruptListener> interruptListener;
-    bool audio_initialized;
-    bool is_activate_audio_interrupt;  // 音频中断激活标志
-    
-    /* 状态标志 */
-    bool is_playing;
-    bool should_stop;
-    bool is_paused;  // 暂停状态标志
-} ln_story_player_simple_t;
-
-
-static bool ln_story_player_simple_play_file(ln_story_player_simple_t *impl, int file_index);
-static bool ln_story_player_simple_player_stat(ln_story_player_simple_t *impl, int file_index);
-
-/* ============================== 播放器回调类 ============================== */
-
-class SimplePlayerCallback : public PlayerCallback
-{
-public:
-    SimplePlayerCallback(ln_story_player_simple_t *impl) : impl_(impl) {}
-
-    void OnPlaybackComplete() override
-    {
-        if (impl_ && !impl_->should_stop)
-        {
-            printf("[SIMPLE_PLAYER] playback completed, scheduling next file\n");
-            // 通过消息队列播放下一个文件,避免在回调中直接调用
-            impl_->current_index++;
-            if (impl_->current_index < impl_->file_count)
-            {
-                // 发送消息到 ln_http_server_send_task 线程
-                do_ln_http_server_send_data(LN_HTTP_SERVICE_CMD_AUDIO_PLAY_NEXT, NULL, 0);
-            }
-            else
-            {
-                printf("[SIMPLE_PLAYER] all files played, stopping(所有文件播放完成)\n");
-                do_ln_http_server_send_data(LN_HTTP_SERVICE_CMD_AUDIO_STOP, NULL, 0);
-                impl_->is_playing = false;
-            }
-        }
-    }
-
-    void OnError(int32_t errorType, int32_t errorCode) override
-    {
-        printf("[SIMPLE_PLAYER] playback error: type=%d, code=%d\n", errorType, errorCode);
-        if (impl_)
-        {
-            impl_->is_playing = false;
-        }
-    }
-
-    void OnInfo(int32_t type, int32_t extra) override {}
-    void OnRewindToComplete() override {}
-
-private:
-    ln_story_player_simple_t *impl_;
-};
-
-/* ============================== 中断监听器类 ============================== */
-
-class SimplePlayerInterruptListener : public InterruptListener
-{
-public:
-    SimplePlayerInterruptListener(ln_story_player_simple_t *impl) : impl_(impl) {}
-
-    void OnInterrupt(int32_t type, int32_t hint) override
-    {
-        if (!impl_)
-            return;
-
-        printf("[SIMPLE_PLAYER] OnInterrupt: type=%d, hint=%d\n", type, hint);
-
-        if (type == INTERRUPT_TYPE_BEGIN && hint == INTERRUPT_HINT_PAUSE)
-        {
-            if (impl_->is_playing && impl_->player)
-            {
-                impl_->player->Pause();
-            }
-        }
-        else if (type == INTERRUPT_TYPE_END && hint == INTERRUPT_HINT_RESUME)
-        {
-            if (impl_->is_playing && impl_->player)
-            {
-                impl_->player->Play();
-            }
-        }
-        else if (type == INTERRUPT_TYPE_BEGIN && hint == INTERRUPT_HINT_STOP)
-        {
-            if (impl_->is_playing)
-            {
-                impl_->player->Stop();
-                impl_->is_playing = false;
-            }
-        }
-    }
-
-private:
-    ln_story_player_simple_t *impl_;
-};
-
-/* ============================== 全局变量 ============================== */
-
-static ln_story_player_simple_t g_simple_player = {0};
-static std::shared_ptr<SimplePlayerCallback> g_player_callback = nullptr;
-static std::shared_ptr<SimplePlayerInterruptListener> g_interrupt_listener = nullptr;
-
-/* ============================== 内部函数 ============================== */
-
-// 处理播放器消息队列命令
-void ln_story_player_simple_handle_message(int cmd, char *data, uint32_t len)
-{
-    if (cmd == LN_HTTP_SERVICE_CMD_AUDIO_PLAY_NEXT)
-    {
-        printf("[SIMPLE_PLAYER] received play next command\n");
-        if (g_simple_player.is_playing && !g_simple_player.should_stop)
-        {
-            if (g_simple_player.current_index < g_simple_player.file_count)
-            {
-                ln_story_player_simple_play_file(&g_simple_player, g_simple_player.current_index);
-            }
-        }
-    }
-}
-
-// 音频初始化(只初始化一次)
-static bool AudioInit(void)
-{
-    if (g_simple_player.audio_initialized)
-    {
-        return true;
-    }
-    
-    AudioManager& amInstance = AudioManager::GetInstance();
-    if (!amInstance.Initialize())
-    {
-        printf("[SIMPLE_PLAYER] AudioManager Initialize failed\n");
-        return false;
-    }
-    
-    g_simple_player.player = std::make_shared<Player>();
-    if (!g_simple_player.player)
-    {
-        printf("[SIMPLE_PLAYER] Player create failed\n");
-        return false;
-    }
-    
-    g_player_callback = std::make_shared<SimplePlayerCallback>(&g_simple_player);
-    if (!g_player_callback)
-    {
-        printf("[SIMPLE_PLAYER] PlayerCallback create failed\n");
-        return false;
-    }
-    
-    g_simple_player.audio_initialized = true;
-    g_simple_player.is_activate_audio_interrupt = false;
-    
-    printf("[SIMPLE_PLAYER] Audio initialized successfully\n");
-    return true;
-}
-
-// 比较函数,用于文件名排序
-static int CompareFileNames(const void *a, const void *b)
-{
-    const char *file_a = (const char *)a;
-    const char *file_b = (const char *)b;
-    
-    // 提取文件名(去掉路径)
-    const char *name_a = strrchr(file_a, '/');
-    const char *name_b = strrchr(file_b, '/');
-    
-    if (name_a) name_a++;
-    else name_a = file_a;
-    if (name_b) name_b++;
-    else name_b = file_b;
-    
-    // 提取数字部分进行比较
-    int num_a = atoi(name_a);
-    int num_b = atoi(name_b);
-    
-    return num_a - num_b;
-}
-
-// 扫描目录获取音频文件
-static bool ScanAudioFiles(const char *story_dir)
-{
-    printf("[SIMPLE_PLAYER] scanning directory: %s\n", story_dir);
-    
-    // 检查目录是否存在
-    if (access(story_dir, F_OK) == -1)
-    {
-        printf("[SIMPLE_PLAYER] directory does not exist: %s\n", story_dir);
-        return false;
-    }
-    
-    DIR *dir = opendir(story_dir);
-    if (!dir)
-    {
-        printf("[SIMPLE_PLAYER] failed to open directory: %s\n", story_dir);
-        return false;
-    }
-    
-    g_simple_player.file_count = 0;
-    struct dirent *entry;
-    
-    while ((entry = readdir(dir)) != NULL && g_simple_player.file_count < 100)
-    {
-        // 跳过 . 和 .. 目录
-        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
-        {
-            continue;
-        }
-        
-        // 检查是否是音频文件
-        const char *ext = strrchr(entry->d_name, '.');
-        if (ext && (strcasecmp(ext, ".mp3") == 0 || strcasecmp(ext, ".wav") == 0 || 
-                    strcasecmp(ext, ".aac") == 0 || strcasecmp(ext, ".m4a") == 0))
-        {
-            snprintf(g_simple_player.file_paths[g_simple_player.file_count], 
-                    sizeof(g_simple_player.file_paths[g_simple_player.file_count]),
-                    "%s/%s", story_dir, entry->d_name);
-            g_simple_player.file_count++;
-            printf("[SIMPLE_PLAYER] found audio file: %s\n", entry->d_name);
-        }
-    }
-    
-    closedir(dir);
-    
-    // 对文件路径进行排序(按文件名中的数字排序)
-    if (g_simple_player.file_count > 1)
-    {
-        qsort(g_simple_player.file_paths, g_simple_player.file_count, 
-              sizeof(g_simple_player.file_paths[0]), CompareFileNames);
-        printf("[SIMPLE_PLAYER] files sorted by name\n");
-    }
-    
-    printf("[SIMPLE_PLAYER] found %d audio files\n", g_simple_player.file_count);
-    return g_simple_player.file_count > 0;
-}
-
-// 播放指定文件
-static bool ln_story_player_simple_play_file(ln_story_player_simple_t *impl, int file_index)
-{
-    if (file_index < 0 || file_index >= impl->file_count)
-    {
-        printf("[SIMPLE_PLAYER] invalid file index: %d\n", file_index);
-        return false;
-    }
-    
-    printf("[SIMPLE_PLAYER] playing file %d: %s\n", file_index, impl->file_paths[file_index]);
-    
-    // 检查播放器状态
-    int32_t player_state;
-    impl->player->GetPlayerState(player_state);
-    printf("[SIMPLE_PLAYER] current player state: %d\n", player_state);
-    
-    // 根据播放器状态进行处理
-    if (player_state == PLAYER_STARTED || player_state == PLAYER_PLAYBACK_COMPLETE)
-    {
-        printf("[SIMPLE_PLAYER] stopping and resetting player before switching\n");
-        impl->player->Stop();
-        impl->player->Reset();
-        // 然后调用PlayerStat来重新播放
-        return ln_story_player_simple_player_stat(impl, file_index);
-    }
-    else if (player_state == PLAYER_PAUSED || player_state == PLAYER_IDLE)
-    {
-        printf("[SIMPLE_PLAYER] player is ready, calling PlayerStat\n");
-        impl->player->Reset();
-        return ln_story_player_simple_player_stat(impl, file_index);
-    }
-    else
-    {
-        printf("[SIMPLE_PLAYER] unknown state, forcing reset and calling PlayerStat\n");
-        impl->player->Stop();
-        impl->player->Reset();
-        return ln_story_player_simple_player_stat(impl, file_index);
-    }
-}
-
-// 播放器状态设置和播放(类似PlayersModel::PlayerStat)
-static bool ln_story_player_simple_player_stat(ln_story_player_simple_t *impl, int file_index)
-{
-    printf("[SIMPLE_PLAYER] ln_story_player_simple_player_stat\n");
-    int32_t ret;
-
-    // 设置回调函数
-    impl->player->SetPlayerCallback(g_player_callback);
-
-    // 设置音频源
-    impl->source = std::make_shared<Source>(impl->file_paths[file_index], impl->header);
-    if (!impl->source)
-    {
-        printf("[SIMPLE_PLAYER] failed to create source\n");
-        return false;
-    }
-    
-    ret = impl->player->SetSource(*impl->source);
-    if (ret != 0)
-    {
-        printf("[SIMPLE_PLAYER] set source failed: %d\n", ret);
-        impl->player->Reset();  // 只在SetSource失败时Reset
-        return false;
-    }
-    
-    // 配置播放器
-    impl->player->SetAudioStreamType(AUDIO_STREAM_MUSIC);
-    
-    // 准备播放
-    ret = impl->player->Prepare();
-    if (ret != 0)
-    {
-        printf("[SIMPLE_PLAYER] prepare failed: %d\n", ret);
-        impl->player->Reset();  // 只在Prepare失败时Reset
-        return false;
-    }
-    
-    // 设置音频会话和中断监听(只在第一次播放时申请)
-    AudioManager &amInstance = AudioManager::GetInstance();
-    
-    if (!impl->is_activate_audio_interrupt)
-    {
-        // 创建新的会话和中断(只在第一次播放时创建)
-        impl->sessionId = amInstance.MakeSessionId();
-        if (impl->sessionId == AUDIO_SESSION_ID_NONE)
-        {
-            printf("[SIMPLE_PLAYER] failed to create session\n");
-            impl->player->Reset();
-            return false;
-        }
-        
-        impl->interruptListener = std::make_shared<SimplePlayerInterruptListener>(impl);
-        impl->interrupt = std::make_shared<AudioInterrupt>();
-        impl->interrupt->streamType = AUDIO_STREAM_MUSIC;
-        impl->interrupt->sessionID = impl->sessionId;
-        impl->interrupt->interruptListener = impl->interruptListener;
-        
-        if (amInstance.ActivateAudioInterrupt(*impl->interrupt) == INTERRUPT_FAILED)
-        {
-            printf("[SIMPLE_PLAYER] failed to activate audio interrupt\n");
-            impl->player->Reset();
-            return false;
-        }
-        
-        impl->is_activate_audio_interrupt = true;
-        printf("[SIMPLE_PLAYER] audio interrupt activated for first file\n");
-    }
-    else
-    {
-        printf("[SIMPLE_PLAYER] reusing existing audio interrupt for file %d\n", file_index);
-    }
-    
-    // 设置音频会话ID
-    ret = impl->player->SetAudioSessionId(impl->sessionId);
-    if (ret != 0)
-    {
-        printf("[SIMPLE_PLAYER] SetAudioSessionId failed: %d\n", ret);
-        impl->player->Reset();
-        // 只在第一次播放失败时才清理音频中断
-        if (impl->is_activate_audio_interrupt)
-        {
-            amInstance.DeactivateAudioInterrupt(*impl->interrupt);
-            impl->is_activate_audio_interrupt = false;
-        }
-        return false;
-    }
-    
-    // 开始播放
-    ret = impl->player->Play();
-    if (ret != 0)
-    {
-        printf("[SIMPLE_PLAYER] play failed: %d\n", ret);
-        impl->player->Stop();
-        impl->player->Reset();
-        // 只在第一次播放失败时才清理音频中断
-        if (impl->is_activate_audio_interrupt)
-        {
-            amInstance.DeactivateAudioInterrupt(*impl->interrupt);
-            impl->is_activate_audio_interrupt = false;
-        }
-        return false;
-    }
-    
-    impl->is_playing = true;
-    impl->is_paused = false;  // 重置暂停状态
-    printf("[SIMPLE_PLAYER] started playing file %d\n", file_index);
-    return true;
-}
-
-// 清理音频中断
-static void ClearActivateAudioInterrupt(void)
-{
-    if (g_simple_player.is_activate_audio_interrupt && g_simple_player.interrupt && g_simple_player.sessionId != AUDIO_SESSION_ID_NONE)
-    {
-        AudioManager &amInstance = AudioManager::GetInstance();
-        amInstance.DeactivateAudioInterrupt(*g_simple_player.interrupt);
-        g_simple_player.is_activate_audio_interrupt = false;
-        printf("[SIMPLE_PLAYER] audio interrupt cleared\n");
-    }
-}
-
-// 清理资源
-static void CleanupResources(void)
-{
-    if (g_simple_player.player)
-    {
-        g_simple_player.player->Stop();
-        g_simple_player.player->Reset();
-        g_simple_player.player->Release();
-        g_simple_player.player.reset();
-    }
-    
-    if (g_simple_player.is_activate_audio_interrupt && g_simple_player.interrupt && g_simple_player.sessionId != AUDIO_SESSION_ID_NONE)
-    {
-        AudioManager &amInstance = AudioManager::GetInstance();
-        amInstance.DeactivateAudioInterrupt(*g_simple_player.interrupt);
-        g_simple_player.is_activate_audio_interrupt = false;
-        printf("[SIMPLE_PLAYER] audio interrupt deactivated\n");
-    }
-    
-    g_simple_player.interrupt.reset();
-    g_simple_player.interruptListener.reset();
-    g_player_callback.reset();
-    
-    memset(&g_simple_player, 0, sizeof(g_simple_player));
-    printf("[SIMPLE_PLAYER] resources cleaned up\n");
-}
-
-/* ============================== 公共接口 ============================== */
-
-// 开始播放指定目录下的音频文件(顺序播放)
-bool ln_story_player_simple_start(const char *story_dir)
-{
-    if (!story_dir)
-    {
-        printf("[SIMPLE_PLAYER] invalid story directory\n");
-        return false;
-    }
-    
-    printf("[SIMPLE_PLAYER] starting playback: %s\n", story_dir);
-    
-    // 如果已经在播放,先停止
-    if (g_simple_player.is_playing)
-    {
-        printf("[SIMPLE_PLAYER] stopping playback\n");
-        ln_story_player_simple_stop();
-    }
-    
-    // 初始化音频(只初始化一次)
-    if (!AudioInit())
-    {
-        printf("[SIMPLE_PLAYER] audio init failed\n");
-        return false;
-    }
-    
-    // 扫描音频文件
-    if (!ScanAudioFiles(story_dir))
-    {
-        printf("[SIMPLE_PLAYER] no audio files found\n");
-        return false;
-    }
-    
-    // 开始播放第一个文件
-    g_simple_player.current_index = 0;
-    g_simple_player.should_stop = false;
-    
-    if (!ln_story_player_simple_play_file(&g_simple_player, 0))
-    {
-        printf("[SIMPLE_PLAYER] failed to start playing\n");
-        return false;
-    }
-    
-    printf("[SIMPLE_PLAYER] playback started successfully\n");
-    return true;
-}
-
-// 停止播放
-void ln_story_player_simple_stop(void)
-{
-    printf("[SIMPLE_PLAYER] ln_story_player_simple_stop\n");
-    
-    g_simple_player.should_stop = true;
-    g_simple_player.is_playing = false;
-    g_simple_player.is_paused = false;
-    
-    if (!g_simple_player.player)
-    {
-        printf("[SIMPLE_PLAYER] player is null, nothing to stop\n");
-        return;
-    }
-    
-    // 检查播放器状态
-    int32_t player_state;
-    int32_t ret = g_simple_player.player->GetPlayerState(player_state);
-    if (ret != 0)
-    {
-        printf("[SIMPLE_PLAYER] get player state failed: %d\n", ret);
-        // 即使获取状态失败,也要尝试清理
-    }
-    else
-    {
-        printf("[SIMPLE_PLAYER] current player state: %d\n", player_state);
-    }
-    
-    // 根据播放器状态进行处理(参考PlayersModel::PlayerStop)
-    if (player_state == PLAYER_STARTED || player_state == PLAYER_PLAYBACK_COMPLETE)
-    {
-        printf("[SIMPLE_PLAYER] stopping and resetting player\n");
-        ret = g_simple_player.player->Stop();
-        if (ret != 0)
-        {
-            printf("[SIMPLE_PLAYER] stop failed: %d\n", ret);
-        }
-        
-        ret = g_simple_player.player->Reset();
-        if (ret != 0)
-        {
-            printf("[SIMPLE_PLAYER] reset failed: %d\n", ret);
-        }
-    }
-    else if (player_state == PLAYER_PAUSED)
-    {
-        printf("[SIMPLE_PLAYER] resetting paused player\n");
-        ret = g_simple_player.player->Reset();
-        if (ret != 0)
-        {
-            printf("[SIMPLE_PLAYER] reset failed: %d\n", ret);
-        }
-    }
-    else if (player_state == PLAYER_STOPPED)
-    {
-        printf("[SIMPLE_PLAYER] player already stopped\n");
-    }
-    else
-    {
-        printf("[SIMPLE_PLAYER] unknown state, forcing stop and reset\n");
-        g_simple_player.player->Stop();
-        g_simple_player.player->Reset();
-    }
-    // 清理音频中断
-    ClearActivateAudioInterrupt();
-    
-    
-    printf("[SIMPLE_PLAYER] playback stopped\n");
-}
-
-// 检查是否正在播放
-bool ln_story_player_simple_is_playing(void)
-{
-    return g_simple_player.is_playing;
-}
-
-// 获取当前播放的文件索引
-int ln_story_player_simple_get_current_index(void)
-{
-    return g_simple_player.current_index;
-}
-
-// 获取总文件数
-int ln_story_player_simple_get_file_count(void)
-{
-    return g_simple_player.file_count;
-}
-
-// 播放指定音频文件
-bool ln_story_player_simple_play_file(const char *file_path)
-{
-    if (!file_path)
-    {
-        printf("[SIMPLE_PLAYER] invalid file path\n");
-        return false;
-    }
-    
-    printf("[SIMPLE_PLAYER] playing single file: %s\n", file_path);
-    
-    // 如果已经在播放,先停止
-    if (g_simple_player.is_playing)
-    {
-        printf("[SIMPLE_PLAYER] stopping current playback\n");
-        ln_story_player_simple_stop();
-    }
-    
-    // 初始化音频(只初始化一次)
-    if (!AudioInit())
-    {
-        printf("[SIMPLE_PLAYER] audio init failed\n");
-        return false;
-    }
-    
-    // 设置单个文件播放模式
-    g_simple_player.file_count = 1;
-    g_simple_player.current_index = 0;
-    g_simple_player.should_stop = false;
-    g_simple_player.is_paused = false;
-    strncpy(g_simple_player.file_paths[0], file_path, sizeof(g_simple_player.file_paths[0]) - 1);
-    g_simple_player.file_paths[0][sizeof(g_simple_player.file_paths[0]) - 1] = '\0';
-    
-    // 播放文件
-    if (!ln_story_player_simple_play_file(&g_simple_player, 0))
-    {
-        printf("[SIMPLE_PLAYER] failed to start playing single file\n");
-        return false;
-    }
-    
-    printf("[SIMPLE_PLAYER] single file playback started successfully\n");
-    return true;
-}
-
-// 暂停播放
-bool ln_story_player_simple_pause(void)
-{
-    if (!g_simple_player.player)
-    {
-        printf("[SIMPLE_PLAYER] player not initialized\n");
-        return false;
-    }
-    
-    if (!g_simple_player.is_playing)
-    {
-        printf("[SIMPLE_PLAYER] not currently playing\n");
-        return false;
-    }
-    
-    if (g_simple_player.is_paused)
-    {
-        printf("[SIMPLE_PLAYER] already paused\n");
-        return false;
-    }
-    
-    int32_t ret = g_simple_player.player->Pause();
-    if (ret != 0)
-    {
-        printf("[SIMPLE_PLAYER] pause failed: %d\n", ret);
-        return false;
-    }
-    
-    g_simple_player.is_paused = true;
-    printf("[SIMPLE_PLAYER] playback paused\n");
-    return true;
-}
-
-// 恢复播放
-bool ln_story_player_simple_resume(void)
-{
-    if (!g_simple_player.player)
-    {
-        printf("[SIMPLE_PLAYER] player not initialized\n");
-        return false;
-    }
-    
-    if (!g_simple_player.is_paused)
-    {
-        printf("[SIMPLE_PLAYER] not currently paused\n");
-        return false;
-    }
-    
-    int32_t ret = g_simple_player.player->Play();
-    if (ret != 0)
-    {
-        printf("[SIMPLE_PLAYER] resume failed: %d\n", ret);
-        return false;
-    }
-    
-    g_simple_player.is_paused = false;
-    printf("[SIMPLE_PLAYER] playback resumed\n");
-    return true;
-}
-
-// 检查是否暂停
-bool ln_story_player_simple_is_paused(void)
-{
-    return g_simple_player.is_paused;
-}
-
-#ifdef __cplusplus
-#if __cplusplus
-}
-#endif /* __cplusplus */
-#endif /* __cplusplus */
diff --git a/code/sdk/application/wearable/n9/nativeapp/nativeui/leiniao/include/ln_story_player_simple.h b/code/sdk/application/wearable/n9/nativeapp/nativeui/leiniao/include/ln_story_player_simple.h
deleted file mode 100644 (file)
index e5ba5d8..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-#ifndef LN_STORY_PLAYER_SIMPLE_H
-#define LN_STORY_PLAYER_SIMPLE_H
-
-#ifdef __cplusplus
-#if __cplusplus
-extern "C"
-{
-#endif
-#endif
-
-#include "stdint.h"
-#include "errcode.h"
-#include <stdbool.h>
-
-/* ============================== 精简版故事播放器接口 ============================== */
-
-/**
- * @brief 开始播放指定目录下的音频文件(顺序播放)
- * @param story_dir 故事文件目录路径
- * @return true 成功,false 失败
- * 
- * 功能说明:
- * - 自动扫描目录下的音频文件(支持mp3, wav, aac, m4a格式)
- * - 按文件名顺序播放所有音频文件
- * - 播放完一个文件后自动播放下一个文件
- * - 音频系统只初始化一次,提高效率
- */
-bool ln_story_player_simple_start(const char *story_dir);
-
-/**
- * @brief 停止播放并清理所有资源
- * @return 无返回值
- * 
- * 功能说明:
- * - 立即停止当前播放
- * - 清理所有音频资源
- * - 重置播放器状态
- */
-void ln_story_player_simple_stop(void);
-
-/**
- * @brief 检查是否正在播放
- * @return true 正在播放,false 未播放
- */
-bool ln_story_player_simple_is_playing(void);
-
-/**
- * @brief 获取当前播放的文件索引
- * @return 当前播放的文件索引(从0开始),-1表示未播放
- */
-int ln_story_player_simple_get_current_index(void);
-
-/**
- * @brief 获取总文件数
- * @return 扫描到的音频文件总数
- */
-int ln_story_player_simple_get_file_count(void);
-
-/**
- * @brief 播放指定音频文件
- * @param file_path 音频文件完整路径
- * @return true 成功,false 失败
- * 
- * 功能说明:
- * - 播放指定的单个音频文件
- * - 不会自动播放下一个文件
- * - 需要手动调用停止或暂停
- */
-bool ln_story_player_simple_play_file(const char *file_path);
-
-/**
- * @brief 暂停播放
- * @return true 成功,false 失败
- * 
- * 功能说明:
- * - 暂停当前正在播放的音频
- * - 保持播放器状态,可以恢复播放
- * - 不会清理音频资源
- */
-bool ln_story_player_simple_pause(void);
-
-/**
- * @brief 恢复播放
- * @return true 成功,false 失败
- * 
- * 功能说明:
- * - 恢复之前暂停的音频播放
- * - 只能在暂停状态下调用
- * - 如果当前没有暂停的音频,返回失败
- */
-bool ln_story_player_simple_resume(void);
-
-/**
- * @brief 检查是否暂停
- * @return true 已暂停,false 未暂停
- */
-bool ln_story_player_simple_is_paused(void);
-
-/**
- * @brief 处理播放器消息队列命令(内部使用)
- * @param cmd 命令类型
- * @param data 数据指针
- * @param len 数据长度
- */
-void ln_story_player_simple_handle_message(int cmd, char *data, uint32_t len);
-
-/* ============================== 使用示例 ============================== */
-
-/*
-// 开始播放
-if (ln_story_player_simple_start("/user/leiniao/story/choose"))
-{
-    printf("播放开始成功\n");
-}
-
-// 检查播放状态
-if (ln_story_player_simple_is_playing())
-{
-    printf("正在播放第 %d 个文件,共 %d 个文件\n", 
-           ln_story_player_simple_get_current_index(),
-           ln_story_player_simple_get_file_count());
-}
-
-// 停止播放
-ln_story_player_simple_stop();
-*/
-
-#ifdef __cplusplus
-#if __cplusplus
-}
-#endif
-#endif
-#endif
diff --git a/code/sdk/application/wearable/n9/nativeapp/nativeui/leiniao/src/ln_story_player_simple.cpp b/code/sdk/application/wearable/n9/nativeapp/nativeui/leiniao/src/ln_story_player_simple.cpp
deleted file mode 100644 (file)
index 441ae6e..0000000
+++ /dev/null
@@ -1,731 +0,0 @@
-#include "leiniao/include/ln_story_player_simple.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <dirent.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <errno.h>
-#include <service/graphic_service.h>
-/* 引入播放器相关头文件 */
-#include "player.h"
-#include "source.h"
-#include "audio_manager.h"
-#include <audio_base_type.h>
-#include <audio_player_service.h>
-#include <custom_utils.h>
-#include <los_base.h>
-/* 引入消息队列相关头文件 */
-#include "ln_api.h"
-
-#ifdef __cplusplus
-#if __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-#endif /* __cplusplus */
-
-using OHOS::Media::Player;
-using OHOS::Media::Source;
-using namespace OHOS::Media;
-using namespace::Audio;
-using Audio::AudioManager;
-
-/* ============================== 精简版播放器结构体 ============================== */
-
-/* 播放器消息命令定义 */
-
-
-typedef struct
-{
-    /* 文件列表 */
-    char file_paths[100][256];  // 最多100个文件
-    int file_count;
-    int current_index;
-    
-    /* 播放器对象 */
-    std::shared_ptr<Player> player;
-    std::shared_ptr<Source> source;
-    std::map<std::string, std::string> header;
-    
-    /* 音频管理 */
-    AudioSession sessionId;
-    std::shared_ptr<AudioInterrupt> interrupt;
-    std::shared_ptr<InterruptListener> interruptListener;
-    bool audio_initialized;
-    bool is_activate_audio_interrupt;  // 音频中断激活标志
-    
-    /* 状态标志 */
-    bool is_playing;
-    bool should_stop;
-    bool is_paused;  // 暂停状态标志
-} ln_story_player_simple_t;
-
-
-static bool ln_story_player_simple_play_file(ln_story_player_simple_t *impl, int file_index);
-static bool ln_story_player_simple_player_stat(ln_story_player_simple_t *impl, int file_index);
-
-/* ============================== 播放器回调类 ============================== */
-
-class SimplePlayerCallback : public PlayerCallback
-{
-public:
-    SimplePlayerCallback(ln_story_player_simple_t *impl) : impl_(impl) {}
-
-    void OnPlaybackComplete() override
-    {
-        if (impl_ && !impl_->should_stop)
-        {
-            printf("[SIMPLE_PLAYER] playback completed, scheduling next file\n");
-            // 通过消息队列播放下一个文件,避免在回调中直接调用
-            impl_->current_index++;
-            if (impl_->current_index < impl_->file_count)
-            {
-                // 发送消息到 ln_http_server_send_task 线程
-                do_ln_http_server_send_data(LN_HTTP_SERVICE_CMD_AUDIO_PLAY_NEXT, NULL, 0);
-            }
-            else
-            {
-                printf("[SIMPLE_PLAYER] all files played, stopping(所有文件播放完成)\n");
-                do_ln_http_server_send_data(LN_HTTP_SERVICE_CMD_AUDIO_STOP, NULL, 0);
-                impl_->is_playing = false;
-            }
-        }
-    }
-
-    void OnError(int32_t errorType, int32_t errorCode) override
-    {
-        printf("[SIMPLE_PLAYER] playback error: type=%d, code=%d\n", errorType, errorCode);
-        if (impl_)
-        {
-            impl_->is_playing = false;
-        }
-    }
-
-    void OnInfo(int32_t type, int32_t extra) override {}
-    void OnRewindToComplete() override {}
-
-private:
-    ln_story_player_simple_t *impl_;
-};
-
-/* ============================== 中断监听器类 ============================== */
-
-class SimplePlayerInterruptListener : public InterruptListener
-{
-public:
-    SimplePlayerInterruptListener(ln_story_player_simple_t *impl) : impl_(impl) {}
-
-    void OnInterrupt(int32_t type, int32_t hint) override
-    {
-        if (!impl_)
-            return;
-
-        printf("[SIMPLE_PLAYER] OnInterrupt: type=%d, hint=%d\n", type, hint);
-
-        if (type == INTERRUPT_TYPE_BEGIN && hint == INTERRUPT_HINT_PAUSE)
-        {
-            if (impl_->is_playing && impl_->player)
-            {
-                impl_->player->Pause();
-            }
-        }
-        else if (type == INTERRUPT_TYPE_END && hint == INTERRUPT_HINT_RESUME)
-        {
-            if (impl_->is_playing && impl_->player)
-            {
-                impl_->player->Play();
-            }
-        }
-        else if (type == INTERRUPT_TYPE_BEGIN && hint == INTERRUPT_HINT_STOP)
-        {
-            if (impl_->is_playing)
-            {
-                impl_->player->Stop();
-                impl_->is_playing = false;
-            }
-        }
-    }
-
-private:
-    ln_story_player_simple_t *impl_;
-};
-
-/* ============================== 全局变量 ============================== */
-
-static ln_story_player_simple_t g_simple_player = {0};
-static std::shared_ptr<SimplePlayerCallback> g_player_callback = nullptr;
-static std::shared_ptr<SimplePlayerInterruptListener> g_interrupt_listener = nullptr;
-
-/* ============================== 内部函数 ============================== */
-
-// 处理播放器消息队列命令
-void ln_story_player_simple_handle_message(int cmd, char *data, uint32_t len)
-{
-    if (cmd == LN_HTTP_SERVICE_CMD_AUDIO_PLAY_NEXT)
-    {
-        printf("[SIMPLE_PLAYER] received play next command\n");
-        if (g_simple_player.is_playing && !g_simple_player.should_stop)
-        {
-            if (g_simple_player.current_index < g_simple_player.file_count)
-            {
-                ln_story_player_simple_play_file(&g_simple_player, g_simple_player.current_index);
-            }
-        }
-    }
-}
-
-// 音频初始化(只初始化一次)
-static bool AudioInit(void)
-{
-    if (g_simple_player.audio_initialized)
-    {
-        return true;
-    }
-    
-    AudioManager& amInstance = AudioManager::GetInstance();
-    if (!amInstance.Initialize())
-    {
-        printf("[SIMPLE_PLAYER] AudioManager Initialize failed\n");
-        return false;
-    }
-    
-    g_simple_player.player = std::make_shared<Player>();
-    if (!g_simple_player.player)
-    {
-        printf("[SIMPLE_PLAYER] Player create failed\n");
-        return false;
-    }
-    
-    g_player_callback = std::make_shared<SimplePlayerCallback>(&g_simple_player);
-    if (!g_player_callback)
-    {
-        printf("[SIMPLE_PLAYER] PlayerCallback create failed\n");
-        return false;
-    }
-    
-    g_simple_player.audio_initialized = true;
-    g_simple_player.is_activate_audio_interrupt = false;
-    
-    printf("[SIMPLE_PLAYER] Audio initialized successfully\n");
-    return true;
-}
-
-// 比较函数,用于文件名排序
-static int CompareFileNames(const void *a, const void *b)
-{
-    const char *file_a = (const char *)a;
-    const char *file_b = (const char *)b;
-    
-    // 提取文件名(去掉路径)
-    const char *name_a = strrchr(file_a, '/');
-    const char *name_b = strrchr(file_b, '/');
-    
-    if (name_a) name_a++;
-    else name_a = file_a;
-    if (name_b) name_b++;
-    else name_b = file_b;
-    
-    // 提取数字部分进行比较
-    int num_a = atoi(name_a);
-    int num_b = atoi(name_b);
-    
-    return num_a - num_b;
-}
-
-// 扫描目录获取音频文件
-static bool ScanAudioFiles(const char *story_dir)
-{
-    printf("[SIMPLE_PLAYER] scanning directory: %s\n", story_dir);
-    
-    // 检查目录是否存在
-    if (access(story_dir, F_OK) == -1)
-    {
-        printf("[SIMPLE_PLAYER] directory does not exist: %s\n", story_dir);
-        return false;
-    }
-    
-    DIR *dir = opendir(story_dir);
-    if (!dir)
-    {
-        printf("[SIMPLE_PLAYER] failed to open directory: %s\n", story_dir);
-        return false;
-    }
-    
-    g_simple_player.file_count = 0;
-    struct dirent *entry;
-    
-    while ((entry = readdir(dir)) != NULL && g_simple_player.file_count < 100)
-    {
-        // 跳过 . 和 .. 目录
-        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
-        {
-            continue;
-        }
-        
-        // 检查是否是音频文件
-        const char *ext = strrchr(entry->d_name, '.');
-        if (ext && (strcasecmp(ext, ".mp3") == 0 || strcasecmp(ext, ".wav") == 0 || 
-                    strcasecmp(ext, ".aac") == 0 || strcasecmp(ext, ".m4a") == 0))
-        {
-            snprintf(g_simple_player.file_paths[g_simple_player.file_count], 
-                    sizeof(g_simple_player.file_paths[g_simple_player.file_count]),
-                    "%s/%s", story_dir, entry->d_name);
-            g_simple_player.file_count++;
-            printf("[SIMPLE_PLAYER] found audio file: %s\n", entry->d_name);
-        }
-    }
-    
-    closedir(dir);
-    
-    // 对文件路径进行排序(按文件名中的数字排序)
-    if (g_simple_player.file_count > 1)
-    {
-        qsort(g_simple_player.file_paths, g_simple_player.file_count, 
-              sizeof(g_simple_player.file_paths[0]), CompareFileNames);
-        printf("[SIMPLE_PLAYER] files sorted by name\n");
-    }
-    
-    printf("[SIMPLE_PLAYER] found %d audio files\n", g_simple_player.file_count);
-    return g_simple_player.file_count > 0;
-}
-
-// 播放指定文件
-static bool ln_story_player_simple_play_file(ln_story_player_simple_t *impl, int file_index)
-{
-    if (file_index < 0 || file_index >= impl->file_count)
-    {
-        printf("[SIMPLE_PLAYER] invalid file index: %d\n", file_index);
-        return false;
-    }
-    
-    printf("[SIMPLE_PLAYER] playing file %d: %s\n", file_index, impl->file_paths[file_index]);
-    
-    // 检查播放器状态
-    int32_t player_state;
-    impl->player->GetPlayerState(player_state);
-    printf("[SIMPLE_PLAYER] current player state: %d\n", player_state);
-    
-    // 根据播放器状态进行处理
-    if (player_state == PLAYER_STARTED || player_state == PLAYER_PLAYBACK_COMPLETE)
-    {
-        printf("[SIMPLE_PLAYER] stopping and resetting player before switching\n");
-        impl->player->Stop();
-        impl->player->Reset();
-        // 然后调用PlayerStat来重新播放
-        return ln_story_player_simple_player_stat(impl, file_index);
-    }
-    else if (player_state == PLAYER_PAUSED || player_state == PLAYER_IDLE)
-    {
-        printf("[SIMPLE_PLAYER] player is ready, calling PlayerStat\n");
-        impl->player->Reset();
-        return ln_story_player_simple_player_stat(impl, file_index);
-    }
-    else
-    {
-        printf("[SIMPLE_PLAYER] unknown state, forcing reset and calling PlayerStat\n");
-        impl->player->Stop();
-        impl->player->Reset();
-        return ln_story_player_simple_player_stat(impl, file_index);
-    }
-}
-
-// 播放器状态设置和播放(类似PlayersModel::PlayerStat)
-static bool ln_story_player_simple_player_stat(ln_story_player_simple_t *impl, int file_index)
-{
-    printf("[SIMPLE_PLAYER] ln_story_player_simple_player_stat\n");
-    int32_t ret;
-
-    // 设置回调函数
-    impl->player->SetPlayerCallback(g_player_callback);
-
-    // 设置音频源
-    impl->source = std::make_shared<Source>(impl->file_paths[file_index], impl->header);
-    if (!impl->source)
-    {
-        printf("[SIMPLE_PLAYER] failed to create source\n");
-        return false;
-    }
-    
-    ret = impl->player->SetSource(*impl->source);
-    if (ret != 0)
-    {
-        printf("[SIMPLE_PLAYER] set source failed: %d\n", ret);
-        impl->player->Reset();  // 只在SetSource失败时Reset
-        return false;
-    }
-    
-    // 配置播放器
-    impl->player->SetAudioStreamType(AUDIO_STREAM_MUSIC);
-    
-    // 准备播放
-    ret = impl->player->Prepare();
-    if (ret != 0)
-    {
-        printf("[SIMPLE_PLAYER] prepare failed: %d\n", ret);
-        impl->player->Reset();  // 只在Prepare失败时Reset
-        return false;
-    }
-    
-    // 设置音频会话和中断监听(只在第一次播放时申请)
-    AudioManager &amInstance = AudioManager::GetInstance();
-    
-    if (!impl->is_activate_audio_interrupt)
-    {
-        // 创建新的会话和中断(只在第一次播放时创建)
-        impl->sessionId = amInstance.MakeSessionId();
-        if (impl->sessionId == AUDIO_SESSION_ID_NONE)
-        {
-            printf("[SIMPLE_PLAYER] failed to create session\n");
-            impl->player->Reset();
-            return false;
-        }
-        
-        impl->interruptListener = std::make_shared<SimplePlayerInterruptListener>(impl);
-        impl->interrupt = std::make_shared<AudioInterrupt>();
-        impl->interrupt->streamType = AUDIO_STREAM_MUSIC;
-        impl->interrupt->sessionID = impl->sessionId;
-        impl->interrupt->interruptListener = impl->interruptListener;
-        
-        if (amInstance.ActivateAudioInterrupt(*impl->interrupt) == INTERRUPT_FAILED)
-        {
-            printf("[SIMPLE_PLAYER] failed to activate audio interrupt\n");
-            impl->player->Reset();
-            return false;
-        }
-        
-        impl->is_activate_audio_interrupt = true;
-        printf("[SIMPLE_PLAYER] audio interrupt activated for first file\n");
-    }
-    else
-    {
-        printf("[SIMPLE_PLAYER] reusing existing audio interrupt for file %d\n", file_index);
-    }
-    
-    // 设置音频会话ID
-    ret = impl->player->SetAudioSessionId(impl->sessionId);
-    if (ret != 0)
-    {
-        printf("[SIMPLE_PLAYER] SetAudioSessionId failed: %d\n", ret);
-        impl->player->Reset();
-        // 只在第一次播放失败时才清理音频中断
-        if (impl->is_activate_audio_interrupt)
-        {
-            amInstance.DeactivateAudioInterrupt(*impl->interrupt);
-            impl->is_activate_audio_interrupt = false;
-        }
-        return false;
-    }
-    
-    // 开始播放
-    ret = impl->player->Play();
-    if (ret != 0)
-    {
-        printf("[SIMPLE_PLAYER] play failed: %d\n", ret);
-        impl->player->Stop();
-        impl->player->Reset();
-        // 只在第一次播放失败时才清理音频中断
-        if (impl->is_activate_audio_interrupt)
-        {
-            amInstance.DeactivateAudioInterrupt(*impl->interrupt);
-            impl->is_activate_audio_interrupt = false;
-        }
-        return false;
-    }
-    
-    impl->is_playing = true;
-    impl->is_paused = false;  // 重置暂停状态
-    printf("[SIMPLE_PLAYER] started playing file %d\n", file_index);
-    return true;
-}
-
-// 清理音频中断
-static void ClearActivateAudioInterrupt(void)
-{
-    if (g_simple_player.is_activate_audio_interrupt && g_simple_player.interrupt && g_simple_player.sessionId != AUDIO_SESSION_ID_NONE)
-    {
-        AudioManager &amInstance = AudioManager::GetInstance();
-        amInstance.DeactivateAudioInterrupt(*g_simple_player.interrupt);
-        g_simple_player.is_activate_audio_interrupt = false;
-        printf("[SIMPLE_PLAYER] audio interrupt cleared\n");
-    }
-}
-
-// 清理资源
-static void CleanupResources(void)
-{
-    if (g_simple_player.player)
-    {
-        g_simple_player.player->Stop();
-        g_simple_player.player->Reset();
-        g_simple_player.player->Release();
-        g_simple_player.player.reset();
-    }
-    
-    if (g_simple_player.is_activate_audio_interrupt && g_simple_player.interrupt && g_simple_player.sessionId != AUDIO_SESSION_ID_NONE)
-    {
-        AudioManager &amInstance = AudioManager::GetInstance();
-        amInstance.DeactivateAudioInterrupt(*g_simple_player.interrupt);
-        g_simple_player.is_activate_audio_interrupt = false;
-        printf("[SIMPLE_PLAYER] audio interrupt deactivated\n");
-    }
-    
-    g_simple_player.interrupt.reset();
-    g_simple_player.interruptListener.reset();
-    g_player_callback.reset();
-    
-    memset(&g_simple_player, 0, sizeof(g_simple_player));
-    printf("[SIMPLE_PLAYER] resources cleaned up\n");
-}
-
-/* ============================== 公共接口 ============================== */
-
-// 开始播放指定目录下的音频文件(顺序播放)
-bool ln_story_player_simple_start(const char *story_dir)
-{
-    if (!story_dir)
-    {
-        printf("[SIMPLE_PLAYER] invalid story directory\n");
-        return false;
-    }
-    
-    printf("[SIMPLE_PLAYER] starting playback: %s\n", story_dir);
-    
-    // 如果已经在播放,先停止
-    if (g_simple_player.is_playing)
-    {
-        printf("[SIMPLE_PLAYER] stopping playback\n");
-        ln_story_player_simple_stop();
-    }
-    
-    // 初始化音频(只初始化一次)
-    if (!AudioInit())
-    {
-        printf("[SIMPLE_PLAYER] audio init failed\n");
-        return false;
-    }
-    
-    // 扫描音频文件
-    if (!ScanAudioFiles(story_dir))
-    {
-        printf("[SIMPLE_PLAYER] no audio files found\n");
-        return false;
-    }
-    
-    // 开始播放第一个文件
-    g_simple_player.current_index = 0;
-    g_simple_player.should_stop = false;
-    
-    if (!ln_story_player_simple_play_file(&g_simple_player, 0))
-    {
-        printf("[SIMPLE_PLAYER] failed to start playing\n");
-        return false;
-    }
-    
-    printf("[SIMPLE_PLAYER] playback started successfully\n");
-    return true;
-}
-
-// 停止播放
-void ln_story_player_simple_stop(void)
-{
-    printf("[SIMPLE_PLAYER] ln_story_player_simple_stop\n");
-    
-    g_simple_player.should_stop = true;
-    g_simple_player.is_playing = false;
-    g_simple_player.is_paused = false;
-    
-    if (!g_simple_player.player)
-    {
-        printf("[SIMPLE_PLAYER] player is null, nothing to stop\n");
-        return;
-    }
-    
-    // 检查播放器状态
-    int32_t player_state;
-    int32_t ret = g_simple_player.player->GetPlayerState(player_state);
-    if (ret != 0)
-    {
-        printf("[SIMPLE_PLAYER] get player state failed: %d\n", ret);
-        // 即使获取状态失败,也要尝试清理
-    }
-    else
-    {
-        printf("[SIMPLE_PLAYER] current player state: %d\n", player_state);
-    }
-    
-    // 根据播放器状态进行处理(参考PlayersModel::PlayerStop)
-    if (player_state == PLAYER_STARTED || player_state == PLAYER_PLAYBACK_COMPLETE)
-    {
-        printf("[SIMPLE_PLAYER] stopping and resetting player\n");
-        ret = g_simple_player.player->Stop();
-        if (ret != 0)
-        {
-            printf("[SIMPLE_PLAYER] stop failed: %d\n", ret);
-        }
-        
-        ret = g_simple_player.player->Reset();
-        if (ret != 0)
-        {
-            printf("[SIMPLE_PLAYER] reset failed: %d\n", ret);
-        }
-    }
-    else if (player_state == PLAYER_PAUSED)
-    {
-        printf("[SIMPLE_PLAYER] resetting paused player\n");
-        ret = g_simple_player.player->Reset();
-        if (ret != 0)
-        {
-            printf("[SIMPLE_PLAYER] reset failed: %d\n", ret);
-        }
-    }
-    else if (player_state == PLAYER_STOPPED)
-    {
-        printf("[SIMPLE_PLAYER] player already stopped\n");
-    }
-    else
-    {
-        printf("[SIMPLE_PLAYER] unknown state, forcing stop and reset\n");
-        g_simple_player.player->Stop();
-        g_simple_player.player->Reset();
-    }
-    // 清理音频中断
-    ClearActivateAudioInterrupt();
-    
-    
-    printf("[SIMPLE_PLAYER] playback stopped\n");
-}
-
-// 检查是否正在播放
-bool ln_story_player_simple_is_playing(void)
-{
-    return g_simple_player.is_playing;
-}
-
-// 获取当前播放的文件索引
-int ln_story_player_simple_get_current_index(void)
-{
-    return g_simple_player.current_index;
-}
-
-// 获取总文件数
-int ln_story_player_simple_get_file_count(void)
-{
-    return g_simple_player.file_count;
-}
-
-// 播放指定音频文件
-bool ln_story_player_simple_play_file(const char *file_path)
-{
-    if (!file_path)
-    {
-        printf("[SIMPLE_PLAYER] invalid file path\n");
-        return false;
-    }
-    
-    printf("[SIMPLE_PLAYER] playing single file: %s\n", file_path);
-    
-    // 如果已经在播放,先停止
-    if (g_simple_player.is_playing)
-    {
-        printf("[SIMPLE_PLAYER] stopping current playback\n");
-        ln_story_player_simple_stop();
-    }
-    
-    // 初始化音频(只初始化一次)
-    if (!AudioInit())
-    {
-        printf("[SIMPLE_PLAYER] audio init failed\n");
-        return false;
-    }
-    
-    // 设置单个文件播放模式
-    g_simple_player.file_count = 1;
-    g_simple_player.current_index = 0;
-    g_simple_player.should_stop = false;
-    g_simple_player.is_paused = false;
-    strncpy(g_simple_player.file_paths[0], file_path, sizeof(g_simple_player.file_paths[0]) - 1);
-    g_simple_player.file_paths[0][sizeof(g_simple_player.file_paths[0]) - 1] = '\0';
-    
-    // 播放文件
-    if (!ln_story_player_simple_play_file(&g_simple_player, 0))
-    {
-        printf("[SIMPLE_PLAYER] failed to start playing single file\n");
-        return false;
-    }
-    
-    printf("[SIMPLE_PLAYER] single file playback started successfully\n");
-    return true;
-}
-
-// 暂停播放
-bool ln_story_player_simple_pause(void)
-{
-    if (!g_simple_player.player)
-    {
-        printf("[SIMPLE_PLAYER] player not initialized\n");
-        return false;
-    }
-    
-    if (!g_simple_player.is_playing)
-    {
-        printf("[SIMPLE_PLAYER] not currently playing\n");
-        return false;
-    }
-    
-    if (g_simple_player.is_paused)
-    {
-        printf("[SIMPLE_PLAYER] already paused\n");
-        return false;
-    }
-    
-    int32_t ret = g_simple_player.player->Pause();
-    if (ret != 0)
-    {
-        printf("[SIMPLE_PLAYER] pause failed: %d\n", ret);
-        return false;
-    }
-    
-    g_simple_player.is_paused = true;
-    printf("[SIMPLE_PLAYER] playback paused\n");
-    return true;
-}
-
-// 恢复播放
-bool ln_story_player_simple_resume(void)
-{
-    if (!g_simple_player.player)
-    {
-        printf("[SIMPLE_PLAYER] player not initialized\n");
-        return false;
-    }
-    
-    if (!g_simple_player.is_paused)
-    {
-        printf("[SIMPLE_PLAYER] not currently paused\n");
-        return false;
-    }
-    
-    int32_t ret = g_simple_player.player->Play();
-    if (ret != 0)
-    {
-        printf("[SIMPLE_PLAYER] resume failed: %d\n", ret);
-        return false;
-    }
-    
-    g_simple_player.is_paused = false;
-    printf("[SIMPLE_PLAYER] playback resumed\n");
-    return true;
-}
-
-// 检查是否暂停
-bool ln_story_player_simple_is_paused(void)
-{
-    return g_simple_player.is_paused;
-}
-
-#ifdef __cplusplus
-#if __cplusplus
-}
-#endif /* __cplusplus */
-#endif /* __cplusplus */
index e93d2a7..1777e2b 100644 (file)
 #include "stdio.h"
 #include "audio_stream_player.h"
 
-
-#ifdef BOARD_N9
-#include "leiniao/include/ln_story_player_simple.h"
-#endif
-
 // 声明播放器消息处理函数
 extern void ln_story_player_simple_handle_message(int cmd, char *data, uint32_t len);
 
@@ -60,13 +55,13 @@ char *uapi_ln_get_device_iccid(void)
 /* 获取设备model */
 char *uapi_ln_get_device_model(void)
 {
-    g_device_model = "abmybox_1";
+    g_device_model = "AB101";
     return g_device_model;
 }
 /* 获取设备固件版本version */
 char *uapi_ln_get_device_version(void)
 {
-    g_device_version = "1.0.0";
+    g_device_version = "1.3.107";
     return g_device_version;
 }
 /* 获取设备token: 优先读本地缓存,判断过期,否则刷新 */
@@ -438,6 +433,7 @@ static void handle_ota_download_msg(const OtaDownloadMsg *msg)
                     printf("[OTA_DOWNLOAD] MD5校验成功,准备重启升级\n");
                     push_ota_status(OTA_UI_STATUS_SUCCESS);
                     /* 外部可在此触发升级动作 */
+                    uaip_cmd_update_request();
                 } else if (md5_ok == 0) {
                     printf("[OTA_DOWNLOAD] MD5校验失败,建议重新下载\n");
                     push_ota_status(OTA_UI_STATUS_FAILED);
@@ -1068,78 +1064,27 @@ static void ln_http_server_send_task(void const *arg)
         else if (mail.cmd == LN_HTTP_SERVICE_CMD_AUDIO_PLAY)
         {
             printf("LN_HTTP_SERVICE_CMD_AUDIO_PLAY:播放音频\n");
-            #ifdef BOARD_N9
-            if (ln_story_player_simple_start("/user/leiniao/story/choose"))
-            {
-                printf("播放开始成功\n");
-            }
-            #endif
         }
         else if (mail.cmd == LN_HTTP_SERVICE_CMD_AUDIO_STOP)
         {
             printf("LN_HTTP_SERVICE_CMD_AUDIO_STOP:停止播放音频\n");
-            #ifdef BOARD_N9
-            ln_story_player_simple_stop();
-            #endif
         }
         else if (mail.cmd == LN_HTTP_SERVICE_CMD_AUDIO_PLAY_NEXT)
         {
             printf("LN_HTTP_SERVICE_CMD_AUDIO_PLAY_NEXT:播放下一首\n");
-            #ifdef BOARD_N9
-            ln_story_player_simple_handle_message(LN_HTTP_SERVICE_CMD_AUDIO_PLAY_NEXT, NULL, 0);
-            #endif
         }
         else if (mail.cmd == LN_HTTP_SERVICE_CMD_AUDIO_PLAY_FILE)
         {
             printf("LN_HTTP_SERVICE_CMD_AUDIO_PLAY_FILE:播放指定文件\n");
-            #ifdef BOARD_N9
-            if (mail.data != NULL)
-            {
-                char *file_path = (char*)mail.data;
-                printf("Playing file: %s\n", file_path);
-                if (ln_story_player_simple_play_file(file_path))
-                {
-                    printf("File playback started successfully\n");
-                }
-                else
-                {
-                    printf("Failed to start file playback\n");
-                }
-            }
-            else
-            {
-                printf("Error: No file path provided\n");
-            }
-            #endif
         }
         else if (mail.cmd == LN_HTTP_SERVICE_CMD_AUDIO_PAUSE)
         {
             printf("LN_HTTP_SERVICE_CMD_AUDIO_PAUSE:暂停播放\n");
-            // #ifdef BOARD_N9
-            // if (ln_story_player_simple_pause())
-            // {
-            //     printf("Playback paused successfully\n");
-            // }
-            // else
-            // {
-            //     printf("Failed to pause playback\n");
-            // }
-            // #endif
             uapi_ln_audio_download_is_cancel(1);
         }
         else if (mail.cmd == LN_HTTP_SERVICE_CMD_AUDIO_RESUME)
         {
             printf("LN_HTTP_SERVICE_CMD_AUDIO_RESUME:恢复播放\n");
-            // #ifdef BOARD_N9
-            // if (ln_story_player_simple_resume())
-            // {
-            //     printf("Playback resumed successfully\n");
-            // }
-            // else
-            // {
-            //     printf("Failed to resume playback\n");
-            // }
-            // #endif
             uapi_ln_audio_download_is_cancel(0);
         }
         if (mail.data != NULL)
diff --git a/code/sdk/zhihui/leiniao/imsl_ln/ln_api_emoji.c b/code/sdk/zhihui/leiniao/imsl_ln/ln_api_emoji.c
new file mode 100644 (file)
index 0000000..2fea535
--- /dev/null
@@ -0,0 +1,719 @@
+#include "ln_api.h"
+#include <stdio.h>
+#include <string.h>
+#include "cJSON.h"
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+/* 宏定义 */
+#define EMOJI_CACHE_BASE_PATH "/emoji_cache/" // 表情缓存根目录
+#define EMOJI_DOWNLOAD_TASK_STACK 4096        // 下载任务栈大小
+#define EMOJI_DOWNLOAD_TASK_PRIO 25           // 下载任务优先级
+#define MAX_PATH_LEN 512                      // 最大路径长度
+
+/* 表情信息结构体定义 */
+typedef struct
+{
+    char emotion[32];   // 心情类型
+    char emojiUrl[512]; // 表情文件URL
+} EmotionEmoji;
+
+/* 表情包配置结构体 */
+typedef struct
+{
+    char characterId[64]; // 角色ID
+    char eyesColor[32];   // 瞳色
+    char eyesShape[32];   // 眼型
+    EmotionEmoji *emojis; // 表情列表
+    int emojiCount;       // 表情数量
+} EmojiPackage;
+
+/* 全局变量 */
+EmojiPackage g_emoji_package = {0};
+static volatile int g_emoji_downloading = 0; // 下载状态标志
+
+/* 安全字符串复制函数 */
+static inline void ln_safe_strcpy(char *dst, size_t dst_size, const char *src)
+{
+    if (!dst || dst_size == 0)
+        return;
+    if (src == NULL)
+    {
+        dst[0] = '\0';
+        return;
+    }
+    strncpy(dst, src, dst_size - 1);
+    dst[dst_size - 1] = '\0';
+}
+
+/* 释放表情列表资源 */
+static void ln_free_emoji_list()
+{
+    if (g_emoji_package.emojis)
+    {
+        free(g_emoji_package.emojis);
+        g_emoji_package.emojis = NULL;
+    }
+    g_emoji_package.emojiCount = 0;
+}
+
+/* 工具函数:创建多级目录 */
+static int ln_mkdir_p(const char *path)
+{
+    if (!path || *path == '\0')
+        return -1;
+
+    char dir[MAX_PATH_LEN] = {0};
+    strncpy(dir, path, sizeof(dir) - 1);
+    int len = strlen(dir);
+    if (dir[len - 1] != '/')
+    {
+        strncat(dir, "/", sizeof(dir) - 1 - len);
+        len++;
+    }
+
+    char *p = dir + 1;
+    while (*p)
+    {
+        if (*p == '/')
+        {
+            *p = '\0';
+            if (mkdir(dir, 0777) != 0 && errno != EEXIST)
+            {
+                return -1;
+            }
+            *p = '/';
+        }
+        p++;
+    }
+
+    // 创建最后一级目录
+    if (mkdir(dir, 0777) != 0 && errno != EEXIST)
+    {
+        return -1;
+    }
+    return 0;
+}
+
+/* 工具函数:生成表情缓存路径 */
+static void ln_gen_emoji_cache_path(const EmojiPackage *pkg, const EmotionEmoji *emoji, char *path, size_t path_len)
+{
+    if (!pkg || !emoji || !path || path_len == 0)
+        return;
+
+    // 路径格式:BASE/characterId/eyesColor_eyesShape/emotion.ext
+    char ext[32] = {0};
+    const char *dot = strrchr(emoji->emojiUrl, '.');
+    if (dot && strlen(dot) < sizeof(ext))
+    {
+        strncpy(ext, dot, sizeof(ext) - 1);
+    }
+
+    snprintf(path, path_len,
+             "%s%s/%s_%s/%s%s",
+             EMOJI_CACHE_BASE_PATH,
+             pkg->characterId,
+             pkg->eyesColor,
+             pkg->eyesShape,
+             emoji->emotion,
+             ext);
+}
+
+/* 工具函数:检查表情是否已缓存 */
+static int ln_emoji_is_cached(const EmojiPackage *pkg, const EmotionEmoji *emoji)
+{
+    char path[MAX_PATH_LEN] = {0};
+    ln_gen_emoji_cache_path(pkg, emoji, path, sizeof(path));
+    struct stat st;
+    return (stat(path, &st) == 0 && S_ISREG(st.st_mode)) ? 1 : 0;
+}
+
+/* 文件下载函数:从URL下载到指定路径 */
+static int ln_download_file(const char *url, const char *save_path)
+{
+    if (!url || !save_path)
+        return -1;
+
+    // 创建保存目录
+    char dir[MAX_PATH_LEN] = {0};
+    strncpy(dir, save_path, sizeof(dir) - 1);
+    char *last_slash = strrchr(dir, '/');
+    if (last_slash)
+    {
+        *last_slash = '\0';
+        if (ln_mkdir_p(dir) != 0)
+        {
+            printf("[DOWNLOAD] create dir %s failed\n", dir);
+            return -1;
+        }
+    }
+
+    // 初始化HTTP客户端
+    HttpClient client = {0};
+    HttpClientData clientData = {0};
+    HTTPC_RESULT prep = ln_http_prepare_auto(&clientData, 2048, 32 * 1024); // 增大接收缓冲区
+    if (prep != HTTP_SUCCESS)
+    {
+        printf("[DOWNLOAD] prepare failed\n");
+        return -1;
+    }
+
+    // 发送GET请求
+    HTTPC_RESULT res = HttpClientGetRequest(&client, url, &clientData);
+    if (res != HTTP_SUCCESS || HttpClientGetResponseCode(&client) != 200)
+    {
+        printf("[DOWNLOAD] GET %s failed\n", url);
+        HttpClientUnprepare(&clientData);
+        return -1;
+    }
+
+    // 写入文件
+    int fd = open(save_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+    if (fd < 0)
+    {
+        printf("[DOWNLOAD] open %s failed\n", save_path);
+        HttpClientUnprepare(&clientData);
+        return -1;
+    }
+
+    int write_len = write(fd, clientData.responseBuf, clientData.responseContentLen);
+    close(fd);
+    HttpClientUnprepare(&clientData);
+
+    if (write_len != clientData.responseContentLen)
+    {
+        printf("[DOWNLOAD] write file failed\n");
+        unlink(save_path); // 删除不完整文件
+        return -1;
+    }
+
+    printf("[DOWNLOAD] %s saved to %s\n", url, save_path);
+    return 0;
+}
+
+/* 下载任务:批量下载表情并上报结果 */
+static void ln_emoji_download_task(void *arg)
+{
+    EmojiPackage *pkg = (EmojiPackage *)arg;
+    if (!pkg || pkg->emojiCount <= 0 || !pkg->emojis)
+    {
+        g_emoji_downloading = 0;
+        return;
+    }
+
+    int all_success = 1;
+
+    // 遍历下载所有表情
+    for (int i = 0; i < pkg->emojiCount; i++)
+    {
+        // 跳过已缓存的文件
+        if (ln_emoji_is_cached(pkg, &pkg->emojis[i]))
+        {
+            printf("[DOWNLOAD] emoji %s already cached\n", pkg->emojis[i].emotion);
+            continue;
+        }
+
+        // 下载并缓存
+        char save_path[MAX_PATH_LEN] = {0};
+        ln_gen_emoji_cache_path(pkg, &pkg->emojis[i], save_path, sizeof(save_path));
+        if (ln_download_file(pkg->emojis[i].emojiUrl, save_path) != 0)
+        {
+            all_success = 0;
+            printf("[DOWNLOAD] emoji %s download failed\n", pkg->emojis[i].emotion);
+        }
+    }
+
+    // 下载完成后上报状态
+    const char *status = all_success ? "success" : "failed";
+    uint32_t report_res = ln_emoji_report_status_http(
+        get_device_id(),    // 假设存在设备ID获取接口
+        get_device_token(), // 假设存在设备Token获取接口
+        pkg->characterId,
+        pkg->eyesColor,
+        pkg->eyesShape,
+        status);
+
+    printf("[DOWNLOAD] report status %s, result: %d\n", status, report_res);
+
+    g_emoji_downloading = 0;
+    LOS_TaskDelete(NULL); // 删除当前任务(根据实际系统接口调整)
+}
+
+/* 启动下载任务 */
+static void ln_start_emoji_download()
+{
+    if (g_emoji_downloading)
+    {
+        printf("[DOWNLOAD] already downloading, skip\n");
+        return;
+    }
+
+    if (g_emoji_package.emojiCount <= 0 || !g_emoji_package.emojis)
+    {
+        printf("[DOWNLOAD] no emojis to download\n");
+        return;
+    }
+
+    g_emoji_downloading = 1;
+
+    // 创建下载任务(基于LiteOS接口示例)
+    UINT32 task_id;
+    TSK_INIT_PARAM_S task_param = {
+        .pfnTaskEntry = (TSK_ENTRY_FUNC)ln_emoji_download_task,
+        .ulStackSize = EMOJI_DOWNLOAD_TASK_STACK,
+        .pcName = "emoji_download",
+        .usTaskPrio = EMOJI_DOWNLOAD_TASK_PRIO,
+        .pvArg = &g_emoji_package};
+
+    if (LOS_TaskCreate(&task_id, &task_param) != LOS_OK)
+    {
+        printf("[DOWNLOAD] create task failed\n");
+        g_emoji_downloading = 0;
+    }
+}
+
+/* 解析下载表情命令JSON */
+void ln_parse_download_emoji(const char *json_buf, int json_len)
+{
+    if (!json_buf || json_len <= 0)
+    {
+        printf("[DOWNLOAD_EMOJI] invalid json input\n");
+        return;
+    }
+
+    // 释放原有表情资源
+    ln_free_emoji_list();
+
+    // 复制并终止字符串
+    char *text = (char *)malloc((size_t)json_len + 1);
+    if (!text)
+        return;
+    memcpy(text, json_buf, (size_t)json_len);
+    text[json_len] = '\0';
+
+    // 解析JSON根对象
+    cJSON *root = cJSON_Parse(text);
+    if (!root)
+    {
+        printf("[DOWNLOAD_EMOJI] json parse failed\n");
+        free(text);
+        return;
+    }
+
+    // 检查错误码
+    cJSON *errorCode = cJSON_GetObjectItem(root, "errorCode");
+    if (errorCode && !cJSON_IsNull(errorCode))
+    {
+        printf("[DOWNLOAD_EMOJI] server error: %s\n",
+               cJSON_IsString(errorCode) ? errorCode->valuestring : "unknown");
+        cJSON_Delete(root);
+        free(text);
+        return;
+    }
+
+    // 获取data对象
+    cJSON *data = cJSON_GetObjectItem(root, "data");
+    if (!data || !cJSON_IsObject(data))
+    {
+        printf("[DOWNLOAD_EMOJI] no data object\n");
+        cJSON_Delete(root);
+        free(text);
+        return;
+    }
+
+    // 解析基础字段
+    cJSON *characterId = cJSON_GetObjectItem(data, "characterId");
+    cJSON *eyesColor = cJSON_GetObjectItem(data, "eyesColor");
+    cJSON *eyesShape = cJSON_GetObjectItem(data, "eyesShape");
+
+    ln_safe_strcpy(g_emoji_package.characterId,
+                   sizeof(g_emoji_package.characterId),
+                   (characterId && cJSON_IsString(characterId)) ? characterId->valuestring : "");
+
+    ln_safe_strcpy(g_emoji_package.eyesColor,
+                   sizeof(g_emoji_package.eyesColor),
+                   (eyesColor && cJSON_IsString(eyesColor)) ? eyesColor->valuestring : "");
+
+    ln_safe_strcpy(g_emoji_package.eyesShape,
+                   sizeof(g_emoji_package.eyesShape),
+                   (eyesShape && cJSON_IsString(eyesShape)) ? eyesShape->valuestring : "");
+
+    // 解析表情列表
+    cJSON *emotionEmojis = cJSON_GetObjectItem(data, "emotionEmojis");
+    if (emotionEmojis && cJSON_IsArray(emotionEmojis))
+    {
+        int count = cJSON_GetArraySize(emotionEmojis);
+        if (count > 0)
+        {
+            g_emoji_package.emojiCount = count;
+            g_emoji_package.emojis = (EmotionEmoji *)malloc(sizeof(EmotionEmoji) * count);
+            if (!g_emoji_package.emojis)
+            {
+                printf("[DOWNLOAD_EMOJI] malloc failed for emojis\n");
+                g_emoji_package.emojiCount = 0;
+            }
+            else
+            {
+                // 遍历解析每个表情
+                for (int i = 0; i < count; i++)
+                {
+                    cJSON *item = cJSON_GetArrayItem(emotionEmojis, i);
+                    if (item && cJSON_IsObject(item))
+                    {
+                        cJSON *emotion = cJSON_GetObjectItem(item, "emotion");
+                        cJSON *emojiUrl = cJSON_GetObjectItem(item, "emojiUrl");
+
+                        ln_safe_strcpy(g_emoji_package.emojis[i].emotion,
+                                       sizeof(g_emoji_package.emojis[i].emotion),
+                                       (emotion && cJSON_IsString(emotion)) ? emotion->valuestring : "");
+
+                        ln_safe_strcpy(g_emoji_package.emojis[i].emojiUrl,
+                                       sizeof(g_emoji_package.emojis[i].emojiUrl),
+                                       (emojiUrl && cJSON_IsString(emojiUrl)) ? emojiUrl->valuestring : "");
+                    }
+                }
+            }
+        }
+    }
+
+    // 打印解析结果
+    printf("[DOWNLOAD_EMOJI] parsed successfully:\n");
+    printf("  characterId: %s\n", g_emoji_package.characterId);
+    printf("  eyesColor: %s\n", g_emoji_package.eyesColor);
+    printf("  eyesShape: %s\n", g_emoji_package.eyesShape);
+    printf("  emojiCount: %d\n", g_emoji_package.emojiCount);
+
+    for (int i = 0; i < g_emoji_package.emojiCount; i++)
+    {
+        printf("  emoji %d: emotion=%s, url=%s\n",
+               i + 1,
+               g_emoji_package.emojis[i].emotion,
+               g_emoji_package.emojis[i].emojiUrl);
+    }
+
+    // 解析完成后启动下载任务
+    ln_start_emoji_download();
+
+    // 清理资源
+    cJSON_Delete(root);
+    free(text);
+}
+
+/* 工具函数:递归删除目录 */
+static int ln_rmdir_recursive(const char *path)
+{
+    if (!path)
+        return -1;
+
+    struct stat st;
+    if (stat(path, &st) != 0)
+        return -1;
+
+    if (S_ISREG(st.st_mode))
+    {
+        return unlink(path); // 删除文件
+    }
+    else if (S_ISDIR(st.st_mode))
+    {
+        DIR *dir = opendir(path);
+        if (!dir)
+            return -1;
+
+        struct dirent *entry;
+        while ((entry = readdir(dir)) != NULL)
+        {
+            if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
+                continue;
+
+            char subpath[MAX_PATH_LEN] = {0};
+            snprintf(subpath, sizeof(subpath), "%s/%s", path, entry->d_name);
+            if (ln_rmdir_recursive(subpath) != 0)
+            {
+                closedir(dir);
+                return -1;
+            }
+        }
+
+        closedir(dir);
+        return rmdir(path); // 删除空目录
+    }
+
+    return -1;
+}
+
+/* 解析删除表情命令JSON */
+void ln_parse_delete_emoji(const char *json_buf, int json_len)
+{
+    if (!json_buf || json_len <= 0)
+    {
+        printf("[DELETE_EMOJI] invalid json input\n");
+        return;
+    }
+
+    // 复制并终止字符串
+    char *text = (char *)malloc((size_t)json_len + 1);
+    if (!text)
+        return;
+    memcpy(text, json_buf, (size_t)json_len);
+    text[json_len] = '\0';
+
+    // 解析JSON根对象
+    cJSON *root = cJSON_Parse(text);
+    if (!root)
+    {
+        printf("[DELETE_EMOJI] json parse failed\n");
+        free(text);
+        return;
+    }
+
+    // 检查错误码
+    cJSON *errorCode = cJSON_GetObjectItem(root, "errorCode");
+    if (errorCode && !cJSON_IsNull(errorCode))
+    {
+        printf("[DELETE_EMOJI] server error: %s\n",
+               cJSON_IsString(errorCode) ? errorCode->valuestring : "unknown");
+        cJSON_Delete(root);
+        free(text);
+        return;
+    }
+
+    // 获取data对象
+    cJSON *data = cJSON_GetObjectItem(root, "data");
+    if (!data || !cJSON_IsObject(data))
+    {
+        printf("[DELETE_EMOJI] no data object\n");
+        cJSON_Delete(root);
+        free(text);
+        return;
+    }
+
+    // 解析字段
+    cJSON *characterId = cJSON_GetObjectItem(data, "characterId");
+    cJSON *eyesColor = cJSON_GetObjectItem(data, "eyesColor");
+    cJSON *eyesShape = cJSON_GetObjectItem(data, "eyesShape");
+
+    char del_characterId[64] = {0};
+    char del_eyesColor[32] = {0};
+    char del_eyesShape[32] = {0};
+
+    ln_safe_strcpy(del_characterId, sizeof(del_characterId),
+                   (characterId && cJSON_IsString(characterId)) ? characterId->valuestring : "");
+
+    ln_safe_strcpy(del_eyesColor, sizeof(del_eyesColor),
+                   (eyesColor && cJSON_IsString(eyesColor)) ? eyesColor->valuestring : "");
+
+    ln_safe_strcpy(del_eyesShape, sizeof(del_eyesShape),
+                   (eyesShape && cJSON_IsString(eyesShape)) ? eyesShape->valuestring : "");
+
+    // 打印解析结果
+    printf("[DELETE_EMOJI] parsed successfully:\n");
+    printf("  characterId: %s\n", del_characterId);
+    printf("  eyesColor: %s\n", del_eyesColor);
+    printf("  eyesShape: %s\n", del_eyesShape);
+
+    // 删除本地表情缓存
+    char del_dir[MAX_PATH_LEN] = {0};
+    snprintf(del_dir, sizeof(del_dir),
+             "%s%s/%s_%s",
+             EMOJI_CACHE_BASE_PATH,
+             del_characterId,
+             del_eyesColor,
+             del_eyesShape);
+
+    if (ln_rmdir_recursive(del_dir) == 0)
+    {
+        printf("[DELETE_EMOJI] cached files in %s deleted\n", del_dir);
+    }
+    else
+    {
+        printf("[DELETE_EMOJI] failed to delete cached files in %s\n", del_dir);
+    }
+
+    // 清理资源
+    cJSON_Delete(root);
+    free(text);
+}
+
+static inline int ln_fill_auth_header(HttpClient *client,
+                                      const char *device_id,
+                                      const char *device_token)
+{
+    if (!client || !device_id || !device_token)
+        return -1;
+    char header_buf[512];
+    int hdr = snprintf(header_buf, sizeof(header_buf),
+                       "deviceId: %s\r\n"
+                       "deviceToken: %s\r\n"
+                       "Content-Type: application/json\r\n",
+                       device_id, device_token);
+    if (hdr <= 0 || hdr >= (int)sizeof(header_buf))
+        return -1;
+    HttpClientSetCustomHeader(client, header_buf);
+    return 0;
+}
+
+/* 7.1 上报角色表情组下载状态 */
+uint32_t ln_emoji_report_status_http(const char *device_id,
+                                     const char *device_token,
+                                     const char *character_id,
+                                     const char *eyes_color,
+                                     const char *eyes_shape,
+                                     const char *status)
+{
+    if (!device_id || !device_token || !character_id || !eyes_color || !eyes_shape || !status)
+        return ERRCODE_FAIL;
+
+#ifdef SUPPORT_CAT1_SERVICE
+    cat1_api_add_cat1_vote();
+    cat1_api_wakeup_cat1(1);
+    cat1_api_keep_wakeup(1);
+    cat1_api_disable_cat1_cmd(1);
+    LOS_Msleep(200);
+#endif
+
+    HttpClient client = (HttpClient){0};
+    HttpClientData clientData = (HttpClientData){0};
+
+    if (ln_fill_auth_header(&client, device_id, device_token) != 0)
+        return ERRCODE_FAIL;
+
+    /* 组装 JSON */
+    cJSON *root = cJSON_CreateObject();
+    if (!root)
+        return ERRCODE_FAIL;
+    cJSON_AddStringToObject(root, "characterId", character_id);
+    cJSON_AddStringToObject(root, "eyesColor", eyes_color);
+    cJSON_AddStringToObject(root, "eyesShape", eyes_shape);
+    cJSON_AddStringToObject(root, "status", status);
+    char *body = cJSON_PrintUnformatted(root);
+    cJSON_Delete(root);
+    if (!body)
+        return ERRCODE_FAIL;
+
+    HTTPC_RESULT prep = ln_http_prepare_auto(&clientData, 2048, 8 * 1024);
+    if (prep != HTTP_SUCCESS)
+    {
+        free(body);
+        return ERRCODE_FAIL;
+    }
+    clientData.postBuf = body;
+    clientData.postBufLen = (int)strlen(body);
+    clientData.postContentType = (char *)"application/json";
+
+    HTTPC_RESULT res = HttpClientPostRequest(&client, LN_EMOJI_REPORT_URL, &clientData);
+    if (res != HTTP_SUCCESS)
+    {
+        free(body);
+        HttpClientUnprepare(&clientData);
+        return ERRCODE_FAIL;
+    }
+
+    int code = HttpClientGetResponseCode(&client);
+    if (clientData.responseBuf && clientData.responseBufLen > 0)
+    {
+        int real_len = clientData.responseContentLen > 0 ? clientData.responseContentLen : clientData.responseBufLen;
+        do_ln_http_server_recv_data(LN_HTTP_RECV_EMOJI_REPORT, clientData.responseBuf, (uint32_t)real_len);
+    }
+    if (code != 200)
+    {
+        free(body);
+        HttpClientUnprepare(&clientData);
+        return ERRCODE_FAIL;
+    }
+
+    free(body);
+    HttpClientUnprepare(&clientData);
+    return ERRCODE_SUCC;
+}
+
+/* 7.2 上报设备所有表情组状态 */
+uint32_t ln_emoji_report_all_http(const char *device_id,
+                                  const char *device_token,
+                                  const LnEmojiGroup *groups,
+                                  int group_count)
+{
+    if (!device_id || !device_token || (!groups && group_count > 0) || group_count < 0)
+        return ERRCODE_FAIL;
+
+#ifdef SUPPORT_CAT1_SERVICE
+    cat1_api_add_cat1_vote();
+    cat1_api_wakeup_cat1(1);
+    cat1_api_keep_wakeup(1);
+    cat1_api_disable_cat1_cmd(1);
+    LOS_Msleep(200);
+#endif
+
+    HttpClient client = (HttpClient){0};
+    HttpClientData clientData = (HttpClientData){0};
+    client.isHttp = false;
+    client.remotePort = 443;
+
+    if (ln_fill_auth_header(&client, device_id, device_token) != 0)
+        return ERRCODE_FAIL;
+
+    /* 组装 JSON 数组 */
+    cJSON *root = cJSON_CreateObject();
+    if (!root)
+        return ERRCODE_FAIL;
+    cJSON *arr = cJSON_CreateArray();
+    if (!arr)
+    {
+        cJSON_Delete(root);
+        return ERRCODE_FAIL;
+    }
+    for (int i = 0; i < group_count; ++i)
+    {
+        cJSON *item = cJSON_CreateObject();
+        if (!item)
+        {
+            continue;
+        }
+        cJSON_AddStringToObject(item, "characterId", groups[i].characterId ? groups[i].characterId : "");
+        cJSON_AddStringToObject(item, "eyesColor", groups[i].eyesColor ? groups[i].eyesColor : "");
+        cJSON_AddStringToObject(item, "eyesShape", groups[i].eyesShape ? groups[i].eyesShape : "");
+        cJSON_AddStringToObject(item, "status", groups[i].status ? groups[i].status : "");
+        cJSON_AddItemToArray(arr, item);
+    }
+    cJSON_AddItemToObject(root, "emojiGroups", arr);
+    char *body = cJSON_PrintUnformatted(root);
+    cJSON_Delete(root);
+    if (!body)
+        return ERRCODE_FAIL;
+
+    HTTPC_RESULT prep = ln_http_prepare_auto(&clientData, 2048, 8 * 1024);
+    if (prep != HTTP_SUCCESS)
+    {
+        free(body);
+        return ERRCODE_FAIL;
+    }
+    clientData.postBuf = body;
+    clientData.postBufLen = (int)strlen(body);
+    clientData.postContentType = (char *)"application/json";
+
+    HTTPC_RESULT res = HttpClientPostRequest(&client, LN_EMOJI_REPORT_ALL_URL, &clientData);
+    if (res != HTTP_SUCCESS)
+    {
+        free(body);
+        HttpClientUnprepare(&clientData);
+        return ERRCODE_FAIL;
+    }
+
+    int code = HttpClientGetResponseCode(&client);
+    if (clientData.responseBuf && clientData.responseBufLen > 0)
+    {
+        int real_len = clientData.responseContentLen > 0 ? clientData.responseContentLen : clientData.responseBufLen;
+        do_ln_http_server_recv_data(LN_HTTP_RECV_EMOJI_REPORT_ALL, clientData.responseBuf, (uint32_t)real_len);
+    }
+    if (code != 200)
+    {
+        free(body);
+        HttpClientUnprepare(&clientData);
+        return ERRCODE_FAIL;
+    }
+
+    free(body);
+    HttpClientUnprepare(&clientData);
+    return ERRCODE_SUCC;
+}
\ No newline at end of file
index 190b4d8..0301cb7 100644 (file)
@@ -31,7 +31,7 @@ uint32_t ln_ota_get_task_http(const char *device_id,
                        "deviceVersion: %s\r\n"
                        "Content-Type: application/json\r\n",
                        device_id, device_token,
-                       (uapi_ln_get_device_model() ? uapi_ln_get_device_model() : "abmybox_1"),
+                       (uapi_ln_get_device_model() ? uapi_ln_get_device_model() : "AB101"),
                        (uapi_ln_get_device_version() ? uapi_ln_get_device_version() : "1.0.0"));
     if (hdr <= 0 || hdr >= (int)sizeof(header_buf))
         return ERRCODE_FAIL;
@@ -130,7 +130,7 @@ static int ln_download_file_to_path(const char *full_url, const char *save_path,
         return -1;
     }
 
-    HTTPC_RESULT prep = ln_http_prepare_auto(&client_data, 2048, LN_CLIENT_PREPARE_SIZE * 3);
+    HTTPC_RESULT prep = ln_http_prepare_auto(&client_data, 2048, LN_CLIENT_PREPARE_SIZE * 4);
     if (prep != HTTP_SUCCESS)
     {
         printf("[OTA] range prepare failed: %d\n", prep);
@@ -263,7 +263,7 @@ uint32_t ln_ota_download_flow_http(const char *device_id,
     int dres;
     if (g_ln_last_package_size > 0)
     {
-        dres = ln_download_file_to_path(g_ln_last_package_url, save_path, g_ln_last_package_size);
+        dres = ln_download_file_to_path(g_ln_last_package_url, LN_OTA_SAVE_DIR, g_ln_last_package_size);
     }
     if (dres != 0)
     {
@@ -275,7 +275,7 @@ uint32_t ln_ota_download_flow_http(const char *device_id,
     }
 
     char done[512];
-    int m = snprintf(done, sizeof(done), "{\"status\":%d,\"filePath\":\"%s\",\"md5\":\"%s\"}", 1, save_path, g_ln_last_package_md5);
+    int m = snprintf(done, sizeof(done), "{\"status\":%d,\"filePath\":\"%s\",\"md5\":\"%s\"}", 1, LN_OTA_SAVE_DIR, g_ln_last_package_md5);
     if (m > 0)
         do_ln_http_server_recv_data(LN_HTTP_RECV_OTA_DOWNLOAD_MSG, done, (uint32_t)m);
     return ERRCODE_SUCC;
index 1c6fa8d..edec9b5 100644 (file)
@@ -265,7 +265,7 @@ uint32_t ln_get_device_token_http(const char *device_id,
                            "deviceVersion: %s\r\n"
                            "Content-Type: application/json\r\n",
                            device_id, device_iccid, timestamp, nonce, signature,
-                           (device_model && device_model[0]) ? device_model : "abmybox_1",
+                           (device_model && device_model[0]) ? device_model : "AB101",
                            (device_version && device_version[0]) ? device_version : "1.0.0");
     if (hdr_len <= 0 || hdr_len >= (int)sizeof(header_buf))
     {
index 3a0cb09..812e9b6 100644 (file)
@@ -44,7 +44,7 @@ def get_device_token() -> Optional[str]:
             "timestamp": timestamp,
             "nonce": nonce,
             "signature": signature,
-            "deviceModel": "abmybox_1",
+            "deviceModel": "AB101",
             "deviceVersion": "1.0.0",
             "Content-Type": "application/json"
         }
index 9743588..5c09874 100644 (file)
@@ -28,7 +28,7 @@ class Constants(Enum):
     TOKEN_API_URL = "https://ambybox-api.test.leiniao.com/ambybox-device-api/v1/auth/getDeviceToken"
     UPGRADE_TEST_URL = "https://ambybox-api.test.leiniao.com/ambybox-device-api/v1/upgrade/getTask"
     SIGN_SECRET = "vDdXVXgPUEUM6_piUjz5AEhMvYTSFzQdPaN-ogKnSus="
-    DEVICE_MODEL = "abmybox_1"
+    DEVICE_MODEL = "AB101"
     DEVICE_VERSION = "1.0.0"
     HEARTBEAT_INTERVAL = 30  # 心跳间隔(秒)
     HEARTBEAT_TIMEOUT = 10   # 心跳超时(秒)
index ab03e6c..f8770a2 100644 (file)
@@ -36,7 +36,7 @@ def generate_request_params():
         "timestamp": timestamp,
         "nonce": nonce,
         "signature": signature,
-        "deviceModel": "abmybox_1",
+        "deviceModel": "AB101",
         "deviceVersion": "1.0.0"
     }
 
index bde84f5..6b9b82a 100644 (file)
@@ -40,7 +40,7 @@ def get_device_token():
             "timestamp": timestamp,
             "nonce": nonce,
             "signature": signature,
-            "deviceModel": "abmybox_1",
+            "deviceModel": "AB101",
             "deviceVersion": "1.0.0",
             "Content-Type": "application/json"
         }
index 4869b28..7eafdaa 100644 (file)
@@ -31,7 +31,7 @@ class Config:
     SIGN_SECRET = "vDdXVXgPUEUM6_piUjz5AEhMvYTSFzQdPaN-ogKnSus="
     DEVICE_ID = "DEVICE_PC_TEST_001"
     DEVICE_ICCID = "86123456789012345678"
-    DEVICE_MODEL = "abmybox_1"
+    DEVICE_MODEL = "AB101"
     DEVICE_VERSION = "1.0.0"
     
     # 资源与超时配置