OpusMange.c 14.9 KB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <dirent.h>  
#include <sys/stat.h>  

#include "JZsdkLib.h"
#include "OpusFile.h"

#define AUDIO_DIR "/root/sdcard/opus"
#define MAX_OPUS_FILES 100

// 沿用只有一百首的方案,由于opus格式只用记载名字,所以只设定数组


static T_JZ_opusInfo g_opusList[MAX_OPUS_FILES] = { 0 };
static int g_opusListNum = 0;

static T_JZsdkReturnCode OpusInfo_PrintAll(void);
static T_JZsdkReturnCode OpusInfo_GetFileInfo(const char* filePath, T_JZ_opusInfo* info);

//------------------------------------------------------------------------------
// 内部辅助函数:从文件路径获取opus文件信息(文件名、大小、估算时长)
//------------------------------------------------------------------------------
static T_JZsdkReturnCode OpusInfo_GetFileInfo(const char* filePath, T_JZ_opusInfo* info)
{
    if (filePath == NULL || info == NULL) {
        JZSDK_LOG_ERROR("OpusInfo_GetFileInfo: 参数为空");
        return JZ_ERROR_SYSTEM_MODULE_CODE_INVALID_PARAMETER;
    }

    memset(info, 0, sizeof(T_JZ_opusInfo));

    // 提取文件名(不含路径)
    const char* fileName = strrchr(filePath, '/');
    if (fileName == NULL) {
        fileName = filePath;   // 没有路径分隔符,直接使用
    }
    else {
        fileName++;            // 跳过 '/'
    }
    strncpy(info->name, fileName, sizeof(info->name) - 1);
    info->name[sizeof(info->name) - 1] = '\0';

    // 检查扩展名是否为.opus
    int len = strlen(info->name);
    if (JZsdk_strings_suffix_comparison_withLen((const unsigned char*)info->name, len,
        (const unsigned char*)".opus") != JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        JZSDK_LOG_ERROR("OpusInfo_GetFileInfo: 文件不是.opus格式: %s", fileName);
        return JZ_ERROR_SYSTEM_MODULE_CODE_FAILURE;
    }

    // 读取文件大小
    if (JZsdk_Fs_ReadFileSize((unsigned char*)filePath, &(info->size)) != JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        JZSDK_LOG_ERROR("OpusInfo_GetFileInfo: 获取文件大小失败: %s", filePath);

        //移除该文件
        JZsdk_Osal_delete(filePath);

        return JZ_ERROR_SYSTEM_MODULE_CODE_FAILURE;
    }

    // 估算时长(与原逻辑一致:size/2000,单位秒)
    info->duration = info->size / 2000;
    if (info->duration < 1) info->duration = 1; // 至少1秒

    return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

//------------------------------------------------------------------------------
// 添加单个opus文件(通过完整文件路径)
//------------------------------------------------------------------------------
T_JZsdkReturnCode OpusInfo_AddFile(const char* filePath)
{
    if (filePath == NULL) {
        JZSDK_LOG_ERROR("OpusInfo_AddFile: 文件路径为空");
        return JZ_ERROR_SYSTEM_MODULE_CODE_INVALID_PARAMETER;
    }

    // 检查列表是否已满
    if (g_opusListNum >= MAX_OPUS_FILES) {
        JZSDK_LOG_ERROR("OpusInfo_AddFile: 列表已满,最多支持%d个文件", MAX_OPUS_FILES);
        return JZ_ERROR_SYSTEM_MODULE_CODE_FAILURE;
    }

    // 检查文件是否存在且为.opus格式,并获取信息
    T_JZ_opusInfo newInfo;
    T_JZsdkReturnCode ret = OpusInfo_GetFileInfo(filePath, &newInfo);
    if (ret != JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        return ret;
    }

    // 检查是否已存在同名文件(防止重复添加)
    for (int i = 0; i < g_opusListNum; i++) {
        if (strcmp(g_opusList[i].name, newInfo.name) == 0) {
            JZSDK_LOG_WARN("OpusInfo_AddFile: 文件已存在于列表中: %s", newInfo.name);
            return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;  // 视为成功,不重复添加
        }
    }

    // 添加到列表尾部
    memcpy(&g_opusList[g_opusListNum], &newInfo, sizeof(T_JZ_opusInfo));
    g_opusListNum++;

    JZSDK_LOG_INFO("OpusInfo_AddFile: 成功添加文件: %s, 大小:%d, 时长:%d",
        newInfo.name, newInfo.size, newInfo.duration);
    return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

//------------------------------------------------------------------------------
// 添加单个opus文件(手动提供参数)
//------------------------------------------------------------------------------
T_JZsdkReturnCode OpusInfo_AddManual(const char* fileName, int size, int duration)
{
    if (fileName == NULL) {
        JZSDK_LOG_ERROR("OpusInfo_AddManual: 文件名为空");
        return JZ_ERROR_SYSTEM_MODULE_CODE_INVALID_PARAMETER;
    }

    if (g_opusListNum >= MAX_OPUS_FILES) {
        JZSDK_LOG_ERROR("OpusInfo_AddManual: 列表已满");
        return JZ_ERROR_SYSTEM_MODULE_CODE_FAILURE;
    }

    // 检查是否已存在
    for (int i = 0; i < g_opusListNum; i++) {
        if (strcmp(g_opusList[i].name, fileName) == 0) {
            JZSDK_LOG_WARN("OpusInfo_AddManual: 文件已存在: %s", fileName);
            return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
        }
    }

    T_JZ_opusInfo newInfo;
    memset(&newInfo, 0, sizeof(newInfo));
    strncpy(newInfo.name, fileName, sizeof(newInfo.name) - 1);
    newInfo.size = size;
    newInfo.duration = duration;

    memcpy(&g_opusList[g_opusListNum], &newInfo, sizeof(T_JZ_opusInfo));
    g_opusListNum++;

    JZSDK_LOG_INFO("OpusInfo_AddManual: 成功添加文件: %s, 大小:%d, 时长:%d", fileName, size, duration);
    return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

//------------------------------------------------------------------------------
// 按索引删除opus文件
//------------------------------------------------------------------------------
T_JZsdkReturnCode OpusInfo_DeleteByIndex(int index)
{
    if (index < 0 || index >= g_opusListNum) {
        JZSDK_LOG_ERROR("OpusInfo_DeleteByIndex: 索引无效: %d, 当前数量:%d", index, g_opusListNum);
        return JZ_ERROR_SYSTEM_MODULE_CODE_INVALID_PARAMETER;
    }

    JZSDK_LOG_INFO("OpusInfo_DeleteByIndex: 删除索引 %d: %s", index, g_opusList[index].name);

    // 将后面的元素向前移动
    for (int i = index; i < g_opusListNum - 1; i++) {
        memcpy(&g_opusList[i], &g_opusList[i + 1], sizeof(T_JZ_opusInfo));
    }
    // 清空最后一个元素
    memset(&g_opusList[g_opusListNum - 1], 0, sizeof(T_JZ_opusInfo));
    g_opusListNum--;

    JZSDK_LOG_INFO("OpusInfo_DeleteByIndex: 删除成功,剩余数量:%d", g_opusListNum);
    return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

//------------------------------------------------------------------------------
// 按文件名删除opus文件(只删除第一个匹配项)
//------------------------------------------------------------------------------
T_JZsdkReturnCode OpusInfo_DeleteByName(const char* fileName)
{
    if (fileName == NULL) {
        JZSDK_LOG_ERROR("OpusInfo_DeleteByName: 文件名为空");
        return JZ_ERROR_SYSTEM_MODULE_CODE_INVALID_PARAMETER;
    }

    for (int i = 0; i < g_opusListNum; i++) {
        if (strcmp(g_opusList[i].name, fileName) == 0) {
            return OpusInfo_DeleteByIndex(i);
        }
    }

    JZSDK_LOG_WARN("OpusInfo_DeleteByName: 未找到文件: %s", fileName);
    return JZ_ERROR_SYSTEM_MODULE_CODE_FAILURE;
}

//------------------------------------------------------------------------------
// 按文件名删除所有匹配的opus文件(删除同名文件)
//------------------------------------------------------------------------------
T_JZsdkReturnCode OpusInfo_DeleteAllByName(const char* fileName)
{
    if (fileName == NULL) {
        JZSDK_LOG_ERROR("OpusInfo_DeleteAllByName: 文件名为空");
        return JZ_ERROR_SYSTEM_MODULE_CODE_INVALID_PARAMETER;
    }

    int deleteCount = 0;
    for (int i = 0; i < g_opusListNum; ) {
        if (strcmp(g_opusList[i].name, fileName) == 0) {
            OpusInfo_DeleteByIndex(i);  // 删除后索引不变(因为元素前移)
            deleteCount++;

            char FilePath[512];
            snprintf(FilePath, 512, "/root/sdcard/opus/%s", fileName);

            //删除
            JZsdk_Osal_delete(FilePath);

            JZsdk_Sync();
        }
        else {
            i++;
        }
    }

    if (deleteCount > 0) {
        JZSDK_LOG_INFO("OpusInfo_DeleteAllByName: 共删除 %d 个文件", deleteCount);
        return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
    }
    else {
        JZSDK_LOG_WARN("OpusInfo_DeleteAllByName: 未找到文件: %s", fileName);
        return JZ_ERROR_SYSTEM_MODULE_CODE_FAILURE;
    }
}

//------------------------------------------------------------------------------
// 清空整个列表
//------------------------------------------------------------------------------
T_JZsdkReturnCode OpusInfo_ClearAll(void)
{
    if (g_opusListNum == 0) {
        JZSDK_LOG_INFO("OpusInfo_ClearAll: 列表已是空");
        return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
    }

    memset(g_opusList, 0, sizeof(g_opusList));
    g_opusListNum = 0;
    JZSDK_LOG_INFO("OpusInfo_ClearAll: 列表已清空");
    return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

//------------------------------------------------------------------------------
// 初始化函数(读取目录中的所有.opus文件)
//------------------------------------------------------------------------------
T_JZsdkReturnCode OpusInfo_Init()
{
    //检查是否存在存放的文件夹
    //检查是否存在audio文件夹,没有则创建一个
    if (JZsdk_check_directory_exists_posix(AUDIO_DIR) != JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS)
    {
        JZSDK_LOG_ERROR("不存在aopus文件夹,创建一个");
        JZsdk_Osal_Mkdir(AUDIO_DIR);
    }

    OpusInfo_FlushList();

    OpusInfo_PrintAll();
    JZSDK_LOG_INFO("OpusInfo_Init: 初始化完成,共 %d 个文件", g_opusListNum);
    return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

//------------------------------------------------------------------------------
// 打印所有opus文件信息(静态函数)
//------------------------------------------------------------------------------
static T_JZsdkReturnCode OpusInfo_PrintAll()
{
    if (g_opusListNum <= 0) {
        JZSDK_LOG_INFO("opus列表为空,没有可打印的内容");
        return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
    }

    for (int i = 0; i < g_opusListNum; i++) {
        JZSDK_LOG_INFO("[%02d] 文件名: %s 大小:%8d字节 时长:%4d秒",
            i + 1, g_opusList[i].name, g_opusList[i].size, g_opusList[i].duration);
    }
    return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

//------------------------------------------------------------------------------
// 对外接口:获取opus文件列表数量
//------------------------------------------------------------------------------
T_JZsdkReturnCode OpusInfo_GetNum(int* num)
{
    if (num == NULL) {
        JZSDK_LOG_ERROR("OpusInfo_GetNum: 参数为空");
        return JZ_ERROR_SYSTEM_MODULE_CODE_INVALID_PARAMETER;
    }
    *num = g_opusListNum;
    return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

//------------------------------------------------------------------------------
// 对外接口:根据索引获取opus文件信息
//------------------------------------------------------------------------------
T_JZsdkReturnCode OpusInfo_GetInfo(int index, T_JZ_opusInfo* info)
{
    if (info == NULL) {
        JZSDK_LOG_ERROR("OpusInfo_GetInfo: 输出参数为空");
        return JZ_ERROR_SYSTEM_MODULE_CODE_INVALID_PARAMETER;
    }
    if (index < 0 || index >= g_opusListNum) {
        JZSDK_LOG_ERROR("OpusInfo_GetInfo: 索引%d超出范围,当前数量%d", index, g_opusListNum);
        return JZ_ERROR_SYSTEM_MODULE_CODE_INVALID_PARAMETER;
    }
    memcpy(info, &g_opusList[index], sizeof(T_JZ_opusInfo));
    return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}


//------------------------------------------------------------------------------
// 获取整个opus列表的指针和数量(直接返回内部数组,只读,请勿修改)
//------------------------------------------------------------------------------
T_JZsdkReturnCode OpusInfo_GetList(T_JZ_opusInfo** list, int* count)
{
    if (list == NULL || count == NULL) {
        JZSDK_LOG_ERROR("OpusInfo_GetList: 参数为空指针");
        return JZ_ERROR_SYSTEM_MODULE_CODE_INVALID_PARAMETER;
    }

    *list = g_opusList;      // 返回内部静态数组首地址
    *count = g_opusListNum;  // 返回当前列表数量

    JZSDK_LOG_DEBUG("OpusInfo_GetList: 列表指针=%p, 数量=%d", *list, *count);
    return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

//------------------------------------------------------------------------------
// 获取前 maxCount 首歌曲,复制到用户提供的缓冲区中
//------------------------------------------------------------------------------
T_JZsdkReturnCode OpusInfo_GetListPartial(T_JZ_opusInfo* outList, int* outCount, int maxCount)
{
    if (outList == NULL || outCount == NULL) {
        JZSDK_LOG_ERROR("OpusInfo_GetListPartial: 输出缓冲区或计数指针为空");
        return JZ_ERROR_SYSTEM_MODULE_CODE_INVALID_PARAMETER;
    }
    if (maxCount <= 0) {
        JZSDK_LOG_ERROR("OpusInfo_GetListPartial: maxCount必须大于0");
        return JZ_ERROR_SYSTEM_MODULE_CODE_INVALID_PARAMETER;
    }

    // 确定实际要复制的数量(取列表长度和maxCount的较小值)
    int copyCount = (g_opusListNum < maxCount) ? g_opusListNum : maxCount;

    if (copyCount > 0) {
        memcpy(outList, g_opusList, copyCount * sizeof(T_JZ_opusInfo));
    }

    *outCount = copyCount;
    JZSDK_LOG_DEBUG("OpusInfo_GetListPartial: 请求%d, 实际复制%d", maxCount, copyCount);
    return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

//------------------------------------------------------------------------------
// 重置列表
//------------------------------------------------------------------------------
T_JZsdkReturnCode OpusInfo_FlushList()
{
    // 先清空列表
    OpusInfo_ClearAll();

    DIR* dir;
    struct dirent* entry;

    // 检查是否存在opus文件夹,没有则创建
    if (JZsdk_check_directory_exists_posix(AUDIO_DIR) != JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        JZSDK_LOG_WARN("不存在opus文件夹, 创建一个");
        if (JZsdk_Osal_Mkdir(AUDIO_DIR) != JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
            JZSDK_LOG_ERROR("创建opus文件夹失败");
            return JZ_ERROR_SYSTEM_MODULE_CODE_FAILURE;
        }
    }

    if ((dir = opendir(AUDIO_DIR)) == NULL) {
        JZSDK_LOG_ERROR("打开文件夹失败: %s", AUDIO_DIR);
        return JZ_ERROR_SYSTEM_MODULE_CODE_FAILURE;
    }

    while ((entry = readdir(dir)) != NULL) {
        const char* filename = entry->d_name;
        if (entry->d_type == DT_DIR || strcmp(filename, ".") == 0 || strcmp(filename, "..") == 0) {
            continue;
        }

        int len = strlen(filename);
        if (JZsdk_strings_suffix_comparison_withLen((const unsigned char*)filename, len,
            (const unsigned char*)".opus") != JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
            continue;
        }

        // 构建完整路径
        char filePath[256];
        snprintf(filePath, sizeof(filePath), "%s/%s", AUDIO_DIR, filename);

        // 添加到列表
        OpusInfo_AddFile(filePath);
    }

    closedir(dir);

    return JZ_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}