MUSIC 模式相关应用
📎 原始文档:https://www.kdocs.cn/l/ckoROeH2VL48 MUSIC 模式相关应用
一. 设备类
- 设备剩余空间获取(LZK)
int fet_free_space(const char *path, u32 *space); 函数返回值单位为KB
例子:
//sd0
u32 free_space = 0;
fget_free_space("storage/sd0/C/",&free_space);
printf("free_space %d\n",free_space);
//sd1
u32 free_space = 0;
fget_free_space("storage/sd1/C/",&free_space);
printf("free_space %d\n",free_space);
//USB
u32 free_space = 0;
fget_free_space("storage/udisk0/C/",&free_space);
printf("free_space %d\n",free_space);
打印信息如下
printf("free_space %d KB - %d MB\n",free_space,free_space/1024);
PS:1、AC692系列 —— 修改看:AC692X软件问题整理 122点
2、AC696 补丁如下:
2. 获取设备总容量(LZK)
struct vfs_partition *fget_partition(const char *path);//获得分区part
信息在以下返回结构体中:
例子
//sd0
struct vfs_partition *part;
part = fget_partition("storage/sd0/C/");
printf("total_size %dKB - %d MB,clust size %d\n",part->total_size,part->total_size/1024,part->clust_size);
//sd1
struct vfs_partition *part;
part = fget_partition("storage/sd1/C/");
printf("total_size %dKB - %d MB,clust size %d\n",part->total_size,part->total_size/1024,part->clust_size);
//USB
struct vfs_partition *part;
part = fget_partition("storage/udisk0/C/");
printf("total_size %dKB - %d MB,clust size %d\n",part->total_size,part->total_size/1024,part->clust_size);
打印信息如下
printf("free_space %d KB - %d MB\n",free_space,free_space/1024);


相关补丁
- AC695N_soundbox_sdk_release_3.1.0 【金山文档】 获取设备总容量_AC695N_soundbox_sdk_release_3.1.0
3.设备支持
支持文件夹个数:2^32个
支持文件个数:2^32 个
支持文件深度:9层
支持最大容量:128PB
支持系统:支持fat12\16\32\exfat
二. 文件系统基础接口
- 文件操作接口 SDK自带的文档:《文件系统接口设计说明文档》有说明
fopen 创建或打开文件
可设置不同读写属性。
FILE * fopen(const char * path,const char * mode);
-- path: 文件路径,如:"storage/sd0/C/test.txt"
-- mode: 文件打开方式,例如:
"r" 以只读方式打开文件,该文件必须存在。
"r+" 以可读写方式打开文件,该文件必须存在。。
"w" 打开只写文件,若文件存在则文件长度清为0,即该文件内容会消失。若文件不存在则建立该文件。
"w+" 打开可读写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件。
"a" 以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。(EOF符保留)
"a+" 以附加方式打开可读写的文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾后,即文件原先的内容会被保留。(原来的EOF符不保留)
"wb" 只写打开或新建一个二进制文件,只允许写数据。
"wb+" 读写打开或建立一个二进制文件,允许读和写。
"ab" 追加打开一个二进制文件,并在文件末尾写数据。
"ab+"读写打开一个二进制文件,允许读,或在文件末追加数据。
--返回值: 如果文件打开失败则返回 NULL
fopen播放文件参考
static FILE *open_file = NULL;//加到函数前,如下:
static void open_file_play_evt_handler(void *priv, int argc, int *argv)
{
u8 event = (u8)argv[0];
if (event ==
_DEC_EVENT_END) {
open_file_close();
}
}
int ret = 0;
char path[64] = {0};
sprintf(path,"%s","storage/fat_nor/C/JL_REC/AC69****.***");//*:通配符
file_dec_close();
open_file = NULL;
open_file = fopen(path, "r");
if(open_file){
ret = file_dec_create(NULL, open_file_play_evt_handler);
if(!ret){
file_dec_open(open_file, NULL);
}
}
f_close 关闭打开的文件
int (fclose)(FILE *);
f_read 读取文件
case KEY_FREAD_FILE:
printf("KEY_FREAD_FILE\n");
char user_file_path[48] = "storage/udisk0/C/1.mp3"; //路径
FILE *fd = fopen(user_file_path, "r"); //检查文件是否存在
if (!fd) {
r_printf("open %s file err!!!\n",user_file_path);
break;
}
u8 buf[512]={0};
int len;
fseek(fd,128,SEEK_CUR); //偏移128个字节
len = fread(fd, buf, sizeof(buf)); //读取内容
r_printf("read file len %d",len);
put_buf(buf,sizeof(buf)); //打印每一个字节
//r_printf("read file data %s",buf); //不建议用这个方式去打印buf
fclose(fd); //关闭
break;
fdelete删除文件
char user_file_path[48] = "storage/udisk0/C/1.mp3"; //路径
FILE *fd = fopen(user_file_path, "r"); //检查文件是否存在
if (!fd) {
r_printf("open %s file err!!!\n",user_file_path);
break;
}
fdelete(fd);//删除文件
file_manager_delete_dir删除文件夹
/* --------------------------------------------------------------------------*/
/**
* @brief 文件删除统一处理
*
* @param path 扫描路径名
* @param param 配置参数
* @param dir_flag 是否删除文件夹标志
* @note 加速处理:(删除文件的时候使用)从前往后依次删除. 文件夹必须从后往前删。
*
* @return 0成功, 其他失败
*/
/* ----------------------------------------------------------------------------*/
int file_manager_delete_deal(char *path, char *param, u8 dir_flag)
{
u16 folder_total_file = 0;
struct vfscan *fsn = NULL;
FILE *d_f = NULL;
fsn = fscan(path, param, 9);
if (fsn == NULL) {
r_printf(">>>[test]:err!!!!!! fsacn fsn fail\n");
return 1;
}
folder_total_file = fsn->file_number;
y_printf(">>>[test]:total = %d\n", folder_total_file);
for (int i = folder_total_file; i >= 1; i--) {
if (!dir_flag) {
d_f = fselect(fsn, FSEL_BY_NUMBER, folder_total_file - i + 1); //加速处理,不用找到最后一个文件。
} else {
d_f = fselect(fsn, FSEL_BY_NUMBER, i);
}
if (d_f == NULL) {
r_printf(">>>[test]:err!! select file err\n");
return 1;
}
putchar('D');
int d_err = fdelete(d_f);
if (d_err) {
r_printf(">>>[test]:err!! delete file err\n");
return 1;
}
d_f = NULL;
}
return 0;
}
/*----------------------------------------------------------------------------*/
/** @brief:文件夹删除处理
@param:dev_logo :设备logo folder:文件夹路径(短名) folder_len:文件夹路径长度
@return:
@author:phewlee
@note:
@date: 2021-05-21,10:16
*/
/*----------------------------------------------------------------------------*/
int file_manager_delete_dir(char *dev_logo, char *folder, u16 folder_len)
{
int err = 0;
struct __dev *dev;
char path[128] = {0};
static const u8 delete_file_param[] = "-t"
"ALL"
" -sn -r";
static const u8 delete_folder_param[] = "-t"
"ALL"
" -sn -d -r";
dev = dev_manager_find_spec(dev_logo, 0);
if (dev == NULL) {
r_printf(">>>[test]:errr!!!!!!!!! not find dev\n");
return 1;
}
char *root_path = dev_manager_get_root_path(dev);
memcpy(path, root_path, strlen(root_path));
memcpy(path + strlen(root_path), folder, folder_len);
r_printf(">>>[test]:path = %s\n", path);
err = file_manager_delete_deal(path, (char *)delete_file_param, 0);
if (err) {
r_printf(">>>[test]:errr!!!!!!!!! delete file deal fail\n");
return 1;
}
err = file_manager_delete_deal(path, (char *)delete_folder_param, 1);
if (err) {
r_printf(">>>[test]:errr!!!!!!!!! delete folder deal fail\n");
return 1;
}
FILE *folder_f = fopen(path, "r");
if (folder_f == NULL) {
r_printf(">>>[test]:err open folder\n");
return 1;
}
err = fdelete(folder_f);
return err;
}
f_write 写文件
f_seek 移动当前文件操作指针到指定位置
f_seek加速:改善f_seek函数在偏移量大的情况下,执行时间偏长问题
换库:
【金山文档】 system_AC695N_soundbox_310_2022.8.25_添加seek和上下曲加速
https://kdocs.cn/l/cr5vNaSpMSvd
修改:
const int FILT_0SIZE_ENABLE = 1;


#define FILE_DEC_SAVE_FAT_TABLE_SIZE 1024
//......
if(dec->fat_table == NULL){
dec->fat_table = zalloc(FILE_DEC_SAVE_FAT_TABLE_SIZE);
}
else{
printf("warn\n");
}
fsave_fat_table(dec->file,FILE_DEC_SAVE_FAT_TABLE_SIZE,dec->fat_table);
fpos - 获取当前文件指针。
flen - 获取文件大小。
int fsize = flen(d_f);
frename - 重命名文件
int frename(FILE *file, const char *path);
//demo
char open_path[32] = "storage/sd0/C/3.txt";
char rename_path[16] = "4.txt";
FILE *file;
file = fopen(open_path, "r"); //只能用 r 打开
//重命名
if(file){
printf("open file ok\n");
extern int frename(FILE *file, const char *path);
frename(file,rename_path);
}
fclose(file);
fscan 扫描文件夹
void *dev = dev_manager_find_active(1);
if (!dev) {
//printf("No active device found");
return;
}
struct vfscan *root_fsn = fscan(dev_manager_get_root_path(dev), MUSIC_SCAN_PARAM, 1);
fscan的长文件夹名的路径要求为 (USB路径/ “\U”002Language/“\U”006Section/)
对应十六进制字符串为:
73 74 6F 72 61 67 65 2F 75 64 69 73 6B 30 2F 43
5C 55 30 00 30 00 32 00 4C 00 61 00 6E 00 67 00
75 00 61 00 67 00 65 00 2F 00
5C 55 30 00 30 00 36 00 53 00 65 00 63 00 74 00
69 00 6F 00 6E 00 2F 00
1. 完整解码结果
第一部分:ASCII/UTF-8 路径
原始数据:
73 74 6F 72 61 67 65 2F 75 64 69 73 6B 30 2F 43
转换结果:
storage/udisk0/C
分析:
标准Unix风格路径,指向存储设备的C分区或目录。
第二部分:UTF-16LE 字符串
原始数据:
5C 55 30 00 30 00 32 00 4C 00 61 00 6E 00 67 00 75 00 61 00 67 00 65 00 2F 00
转换结果:
\U002Language/
关键点:
\U002:可能是资源标识符(类似Windows资源格式)。
Language:表示语言分类目录。
末尾/:路径分隔符。
第三部分:UTF-16LE 字符串
原始数据:
5C 55 30 00 30 00 36 00 53 00 65 00 63 00 74 00 69 00 6F 00 6E 00 2F 00
转换结果:
\U006Section/
关键点:
\U006:资源编号(第6条)。
Section:表示章节或区块分类。
设置文件创建时间/修改录音创建的文件的时间
//! 创建文件前先传好
void fat_set_datetime_info(u16 year,u8 month,u8 day,u8 hour,u8 minute,u8 second);
补丁:
AC695N&AC696N&AC608N音箱问题整理.otl
AC695N_音箱3.0.4SDK_EXFAT文件系统使用修复:【金山文档】 system_AC695N_304_2023_2_25_支持exfat创建时间 https://kdocs.cn/l/cicOGoy1yhzy
【金山文档】 system_AC695N_310_2023_4_13_支持exfat创建时间 https://kdocs.cn/l/cgX7ThkllKJS
- 设置卷标 不能超过11字节(标准文件系统固定最长是11字节)。
int fset_vol(const char *path, const char *name);//设置卷标
部分SDK还需要打开下面这个写fats的开关

#define FLAG_NAME "JL123456789"//长度不能超过11个
#define STRL_EN "\0"
#define FLAG_NAME_LEN 11
const char name[] =FLAG_NAME STRL_EN;//不加结束符 编译器有概率不补/0
// const char *name = FLAG_NAME STRL_EN;//不加结束符 编译器有概率不补/0
// const char name[FLAG_NAME_LEN+1] = FLAG_NAME;
r_printf("dev_manager_add name len %s %d\n",name, strlen(name));
ASSERT(strlen(name) <= FLAG_NAME_LEN){
r_printf("name too long\n");
}
r_printf("dev_manager_add %s %s %s %s\n", p->logo, p->storage_path, p->fs_type,name);
int ret = fset_vol(p->root_path, name);
r_printf("fset_vol %s RET %d\n", p->root_path, ret);
if(ret){
r_printf("fset_vol err\n");
}
701 142 需要换库不然exfat文件系统更改不了卷标名资料传送门
文件/文件夹名
//AC695 长文件名 demo
u8 path_buf[256] = {0};
int len = fget_path(music_player_get_file_hdl(),path_buf,sizeof(path_buf),1);
if ((path_buf[0] == '\\') && (path_buf[1] == 'U')) {
unicode = 1;
len -= 2;
printf("cur path = %s, len = %d, unicode = %d\n", path_buf + 2, music_file_name_len, unicode);
} else {
printf("cur path = %s, len = %d, unicode = %d\n", path_buf, music_file_name_len, unicode);
}
//文件夹名 demo
char path_buf[512] = {0};
int len_1 = fget_path(music_player_get_file_hdl(),path_buf,sizeof(path_buf),1);
put_buf(path_buf,sizeof(path_buf));
//是否过滤隐藏 和 .开头名名的字文件 1:过滤 0不过滤
hidden_file(0);
长文件名测试程序
///////////////////长文件名创建和重命名接口测试/////////////////////////////////////////////
/*----------------------------------------------------------------------------*/
/** @brief:文件创建及重命名接口测试
@param: 测试fopen, frename.
@return:
@author: phew lee .fy
@note:
@date: 2021-1-26,14:54
*/
/*----------------------------------------------------------------------------*/
#ifdef LONG_FOPEN_RENAME_TEST
void long_fopen_rename_test()
{
#if 0
static void *file;
u8 buf[256] = {0};
for (int i = 0; i < 256; i++) {
buf[i] = (i & 0xff);
}
int len = 0;
static void *file_d;
char path_d[64] = "storage/virfat_flash/C/delete.txt";
y_printf(">>>[test]:open create 1111\n");
file_d = fopen(path_d, "w+");
y_printf(">>>[test]:dwrite\n");
len = fwrite(file_d, buf, 256);
fclose(file_d);
file_d = fopen(path_d, "r");
memset(buf, 0, 256);
r_printf(">>>[test]:read......\n");
for (int i = 0; i < 2; i++) {
len = fread_fast(file_d, buf, 256);
if (len == 256) {
put_buf(buf, 256);
} else {
r_printf(">>>[test]:len = %d\n", len);
}
}
fclose(file_d);
#endif
#if 1
#define N 64
char path[256] = "storage/sd0/C";
/* char file_path[128] = {'/','M', 'U', 'S', 'I', 'C', 'h', '/', '\\', 'U', 0x61, 0x0, 0x62, 0x0, 0x63, 0x0, 0x64, 0x0, 0x65, 0x0, 0x66, 0x0, 0X67, 0x0, 0x68, 0x0, 0x69, 0, '/', 0, 't', 'e', 's', 't', '.', 'm', 'p' , '3', 0}; */
/* char file_path[128] = {'/','M', 'U', 'S', 'I', 'C', '/', '\\', 'U', 0x31, 0x0, 0x32, 0x0, 0x33, 0x0, 0x34, 0x0, 0x35, 0x0, 0x36, 0x0, 0X37, 0x0, 0x38, 0x0, 0x39, 0, '/', 0, '\\', 'U', 0x31, 0x0, 0x32, 0x0, 0x33, 0x0, 0x34, 0x0, 0x35, 0x0, 0x36, 0x0, 0X37, 0x0, 0x38, 0x0, 0x39, 0x0, 0x31, 0, 0x32, 0, 0x33, 0, 0x2E, 0x0, 0x6D, 0x0, 0x70, 0x0, 0x33, 0}; */
/* char file_path[56] = { '\\', 'U', 0x4B, 0x6D, 0xD5, 0x8B, 0x1B, 0x52, 0xFA, 0x5E, 0x7F, 0x95, 0x87, 0x65, 0XF6, 0x4E, 0x0D, 0x54, 0x2E, 0, 0x6D, 0, 0x70, 0, 0x33, 0, '&', '&', 0xB2, 0xE2, 0xCA, 0xD4, 0xB4, 0xB4, 0xBD, 0xA8, 0xB3, 0xA4, 0xCE, 0xC4, 0xBC, 0xFE, 0xC3, 0xFB, 0, 0}; // 测试创建长文件名.mp3 + '&'+ '&' + GBK */
/* char file_path[56] = { '\\', 'U', 0x4B, 0x6D, 0xD5, 0x8B, 0x1B, 0x52, 0xFA, 0x5E, 0x7F, 0x95, 0x87, 0x65, 0XF6, 0x4E, 0x0D, 0x54, 0x2E, 0, 0x74, 0, 0x78, 0, 0x74, 0, '&', '&', 0xB2, 0xE2, 0xCA, 0xD4, 0xB4, 0xB4, 0xBD, 0xA8, 0xB3, 0xA4, 0xCE, 0xC4, 0xBC, 0xFE, 0xC3, 0xFB, 0, 0}; // 测试创建长文件名.txt + '&'+ '&' + GBK */
/* char file_path[56] = { '\\', 'U', 0x4B, 0x6D, 0xD5, 0x8B, 0x1B, 0x52, 0xFA, 0x5E, 0x7F, 0x95, 0x87, 0x65, 0XF6, 0x4E, 0x0D, 0x54, 0x2E, 0, 0x74, 0, 0x78, 0, 0x74, 0}; // 测试创建长文件名.txt */
/* char file_path[56] = { '\\', 'U', 0x60, 0x4F, 0x7D, 0x59, 0x40, 0x54, 0x2E, 0, 0x6D, 0, 0x70, 0, 0x33, 0}; //你好呀.mp3 */
/* char file_path[56] = {0xB1, 0xA6, 0xB1, 0xA6, 0xBF, 0xDE, 0xC1, 0xCB, 0x2E, 0x74, 0x78, 0x74, 0}; // 测试创建长文件名.txt */
/* char file_path[] = {'/','\\', 'U', 0xD9, 0x8F, 0x2A, 0x4E, 0x8e, 0x7f, 0x7d,0x59,0x84,0x76,0x1f,0x75,0x3b,0x6d,0x2D,0x00,0x81,0x68,0xE5,0x5D,0x2E, 0x0, 0x6D, 0x0, 0x70, 0x0, 0x33, 0}; // 这个美好的生活-梁工.mp3 */
char file_path[128] = {'/', '\\', 'U', 0xD9, 0x8F, 0x16, 0x4E, 0x4C, 0x75, 0x1F, 0x77, 0x27, 0x59, 0x2D, 0x00, 0x81, 0x68, 0xE5, 0x5D, 0x2E, 0x0, 0x6D, 0x0, 0x70, 0x0, 0x33, 0}; // 123.mp3
/* char file_path[128] = {'\\', 'U', 0x31, 0x0, 0x32, 0x0, 0x33, 0x0, 0x34, 0x0, 0x35, 0x0, 0x36, 0x0, 0X37, 0x0, 0x38, 0x0, 0x39, 0x0, 0x31, 0, 0x32, 0, 0x33, 0, 0x2E, 0x0, 0x6D, 0x0, 0x70, 0x0, 0x33, 0}; */
memcpy(path + strlen(path), file_path, sizeof(file_path));
#if 0
FILE *file = fopen("storage/sd0/C/music2.txt", "w+");
char *buf = malloc(N);
memset(buf, 0, N);
for (int i = 0; i < N; i++) {
buf[i] = (i & 0xff);
}
int wlen = fwrite(file, buf, N);
r_printf(">>>[test]:wlen = %d\n", wlen);
if (wlen != N) {
r_printf(">>>[test]:err write\n");
}
memset(buf, 0, N);
fseek(file, 0, SEEK_SET);
int rlen = fread(file, buf, N);
y_printf(">>>[test]:rlen = %d\n", rlen);
if (rlen != N) {
r_printf(">>>[test]:err read\n");
}
for (int i = 0; i < N; i++) {
if (buf[i] != (i & 0xff)) {
r_printf(">>>[test]:errr buf[%d] = %d\n", i, buf[i]);
/* return; */
}
}
free(buf);
buf = NULL;
fclose(file);
file = NULL;
return;
#endif
#if 0
/////////////////////////////////////////////
FILE *file = fopen("storage/sd0/C/music123.txt", "w+");
/* FILE *file = fopen(path, "r"); */
if (file == NULL) {
r_printf(">>>[test]:open errrr!!!!!\n");
}
fclose(file);
file = NULL;
file = fopen("storage/sd0/C/music123.txt", "r");
/* int err = frename(file, file_path); */
int err = frename(file, "3444.txt");
if (err == 0) {
y_printf(">>>[test]:okk!!!!!!!!!!!\n");
} else {
y_printf(">>>[test]:error!!!!!!!!!!!\n");
}
fclose(file);
file = NULL;
#else
FILE *file = fopen(path, "w+");
/* FILE *file = fopen("storage/udisk0/C/test.txt", "w+"); */
if (file) {
fclose(file);
file = NULL;
} else {
y_printf(">>>[test]:errror open long name\n");
}
#endif
#endif
}
#endif
void fatfs_test_open(void)
{
#if 1
char path[256] = {"storage/udisk0/C/999999/"};
int path_len = strlen(path);
char dir[64] = {"升级plus再次"};
u8 utf8_flag = utf8_check(dir, sizeof(dir));
if (!utf8_flag) {
y_printf("\n >>>[test]:func = %s,line= %d\n",__FUNCTION__, __LINE__);
return;
}
u16 dir_unicode[64] = {0};
int len = UTF82Unicode(dir, dir_unicode + 1, sizeof(dir));
y_printf(">>>[test]:len = %d\n", len);
dir_unicode[0] = 'U\\';
dir_unicode[len + 1] = '/';
put_buf(dir_unicode, (len + 2) * 2);
memcpy(path + path_len, dir_unicode, (len + 2) * 2);
memcpy(path + path_len + (len + 2) * 2, "ABC.mp3", strlen("ABC.mp3"));
FILE *file = fopen(path, "w+");
if (file) {
r_printf(">>>[test]:open OK\n");
} else {
r_printf(">>>[test]:open err\n");
}
return;
#else
/* for (int i = 0; i < 20; i++) */
{
FILE *file = fopen("storage/udisk0/C/JL_REC/AC69****.mp3", "w+");
/* FILE *file = fopen("storage/udisk0/C/AAAA/BBBB/CCCC/AS11.txt", "r"); */
if (!file) {
y_printf(">>>[test]:errr open !!!!!!!!!!\n");
while(1);
}
fclose(file);
}
#endif
}
695创建打开长文件名
【金山文档 | WPS云文档】 system_695v310_创建长文件夹名称乱码修复_20241225
https://kdocs.cn/l/coL5vP8v3GFY
696创建打开长文件名
换库文件
【金山文档 | WPS云文档】 system_696v170_创建长文件夹名称乱码修复_20241225
https://kdocs.cn/l/cgjRcKP0MrLc
【金山文档】 system_AC696N_170_2023_7_14_添加支持多级长文件名创建
https://kdocs.cn/l/cr5sfKIUVlBv
编译不过在lib_system_config.c添加以下定义
const int FATFS_WRITE = 0; // 控制fatfs写功能开关。
const int FILT_0SIZE_ENABLE = 1; //是否过滤0大小文件
const int FATFS_LONG_NAME_ENABLE = 1;
const int FATFS_RENAME_ENABLE = 0; // 是否使能文件重命名功能
const int FATFS_FGET_PATH_ENABLE = 0;
const int FATFS_SAVE_FAT_TABLE_ENABLE = 1;
//demo程序
char path[384] = "storage/udisk0/C";
char file_name[128] = {'/','\\','U',0x4B,0x6D,0xD5,0x8B,0x7F,0x95,0x87,0x65,0xF6,0x4E,0x39,0x59,0x0D,0x54,0x4B,0x6D,0xD5,0x8B,'/',0x00,'\\','U',0x4B,0x6D,0xD5,0x8B,0x1B,0x52,0xFA,0x5E,0x7F,0x95,0x87,0x65,0xF6,0x4E,0x0D,0x54,0x4B,0x6D,0xD5,0x8B,0x2E,0x00,0x74,0x00,0x78,0x00,0x74,0x00};
memcpy(path + strlen(path), file_name, sizeof(file_name));
printf("name == %s\n",path);
FILE *file = fopen(path, "w");//r
printf("name == %s\n",path);
if (file) {
printf("open_file_ok\n");
fclose(file);
file = NULL;
} else {
printf("open_file_not_ok\n");
y_printf(">>>[test]:errror open long name\n");
}
//注意长文件名是Unicode码
网址:http://zhanzhang.cnzzla.com/tool/unicode.php
通过获取文件夹名称组成路径,对该文件夹进行单独扫盘
参考以下demo,该方法即通过fget_name获取文件夹名,组成扫盘路径,单独对该文件夹扫盘,获取该文件夹扫盘句柄
AC695N
该demo程序中替换了以下库文件:
【金山文档】 system_AC695N_310_2023_8_15_修复兼容fat32_exfat长短名文件夹和带点短名文件夹扫盘https://kdocs.cn/l/caucpvgqGavA
【金山文档】 AC695N_soundbox_sdk_release_3.1.0-支持对fat32和exfat系统下长短名文件夹扫盘处理【该demo程序中已替换上面的system.a文件】
AC695N_soundbox_sdk_release_3.1.0-支持对fat32和exfat系统下长短名文件夹扫盘处理.zip
AC696N
【金山文档】 ac696n_soundbox_sdk_v1.7.0-支持对长短名文件夹扫盘
ac696n_soundbox_sdk_v1.7.0-支持对长短名文件夹扫盘.zip
- 文件解码接口 SDK\apps\common\music\music_player.c
//music_player获取当前播放歌曲总时间
int music_player_get_dec_total_time(void)
//music_player获取当前播放循环模式
music_player_get_repeat_mode(void)
//music_player获取当前播放对应的music设备
char *music_player_get_cur_music_dev(void)
//music_player获取当前播放状态
int music_player_get_play_status(void)
音频文件获取信息
//*----------------------------------------------------------------------------*/
/**@brief music 解码成功回调
@param priv:私有参数, parm:暂时未用
@return
@note 此处可以做一些用户操作, 如断点保存, 显示, 获取播放信息等
*/
/*----------------------------------------------------------------------------*/
static void music_player_play_success(void *priv, int parm)
{
char *logo = music_player_get_dev_cur();
log_i("\n\n----------------music_player_play_success----------------------\n");
log_i("cur dev = %s\n", logo);
log_i("total dev = %d\n", dev_manager_get_total(1));
log_i("cur filenum = %d\n", music_player_get_file_cur());
log_i("totol filenum = %d\n", music_player_get_file_total());
log_i("totol time = %d\n", music_player_get_dec_total_time());
log_i("sclust = %d\n", music_player_get_file_sclust());
log_i("fsize = %d\n", music_player_get_file_fsize());
log_i("dir_cur = %d\n", music_player_get_dir_cur());
log_i("dir_total = %d\n", music_player_get_dir_total());
log_i("file indir = %d\n", music_player_get_fileindir_number());
music_file_name_len = fget_name(music_player_get_file_hdl(), music_file_name, sizeof(music_file_name));
int unicode = fget_name_type(music_file_name, music_file_name_len);
log_i("cur file = %s\n", music_file_name);
log_i("\n");
///save breakpoint, 只保存文件信息
if (music_player_get_playing_breakpoint(breakpoint, 0) == true) {
breakpoint_vm_write(breakpoint, logo);
}
int analaz = music_player_lrc_analy_start();
///show ui
UI_SHOW_MENU(MENU_FILENUM, 1000, music_player_get_file_cur(), NULL);
UI_MSG_POST("music_start:show_lyric=%4:dev=%4:filenum=%4:total_filenum=%4", !analaz, logo, music_player_get_file_cur(), music_player_get_file_total());
///smartbox info update
SMARTBOX_UPDATE(MUSIC_FUNCTION_MASK,
BIT(MUSIC_INFO_ATTR_STATUS) | BIT(MUSIC_INFO_ATTR_FILE_NAME) | BIT(MUSIC_INFO_ATTR_FILE_PLAY_MODE));
}
//*----------------------------------------------------------------------------*/
/**@brief music_player获取文件大小
@param
@return 文件大小, 单位:字节,-1:无效
@note
*/
/*----------------------------------------------------------------------------*/
u32 music_player_get_file_fsize(void)
{
if (__this && __this->file) {
struct vfs_attr tmp_attr = {0};
fget_attrs(__this->file, &tmp_attr);
return tmp_attr.fsize;
}
return (u32) - 1;
}
三.解码基础接口
解码器接口函数基本在 music_player.h 文件找到说明,详细可以看注释
关键字:文件名后缀 文件格式
struct file_dec_hdl *dec = get_file_dec_hdl();
if (dec) {
if (dec->file_dec.decoder.dec_ops->coding_type == AUDIO_CODING_APE
|| dec->file_dec.decoder.dec_ops->coding_type == AUDIO_CODING_FLAC
|| dec->file_dec.decoder.dec_ops->coding_type == AUDIO_CODING_DTS
|| dec->file_dec.decoder.dec_ops->coding_type == AUDIO_CODING_WAV) {
}
}
四. 性能测试数据
1. 文件播放速度测试数据
| AC696 U盘(2k多文件夹)--2021-7-7(单位:秒) | AC696 U盘(1w单文件夹)-2021-7-7(单位:秒) | |||||||
|---|---|---|---|---|---|---|---|---|
| 测试次数 | 第一次 | 第二次 | 第三次 | 测试次数 | 第一次 | 第二次 | 第三次 | |
| 首次上电读取 | 4.48 | 4.5 | 首次上电读取 | 6.25 | 6.25 | 6.25 | ||
| 第―首歌曲断点拔插 | 4.47 | 4.31 | 4.38 | 第―首歌曲断点拔插 | 6.26 | 6.25 | ||
| 最后―首歌曲断点拔插 | 4.47 | 4.47 | 4.41 | 最后―首歌曲断点拔插 | 6.25 | 6.25 | ||
| 第―首歌上―曲 | 0.36 | 0.36 | 0.36 | 第―首歌上―曲 | 0.43 | 0.43 | 0.43 | |
| 第―首歌下―曲 | 0.16 | 0.16 | 0.16 | 第―首歌下―曲 | 0.16 | 0.16 | 0.16 | |
| 第五首连续上一曲 | 0.4 | 0.4 | 0.4 | 第五首连续上一曲 | 0.36 | 0.38 | 0.36 |
2. 支持的音频格式
AC696、AC695
| 格式 | 码率(单位kbps) | 采样率(单位Hz) | 位宽 | 声道 |
|---|---|---|---|---|
| aac/m5a | 8~576 | 8k/11025/12k/16k/22050/24k/32k/44100/48k | 16bit 【解码出来的位宽】 | 单/双声道 |
| amr | 4.75/5.15/5.9/6.7/7.4/7.95/102/12.2 | 8k | 16bit 【解码出来的位宽】 | 单声道 |
| dts | 32~3840 | 8k/11025/12k/16k/22050/24k/32k/44100/48k | 16bit 【解码出来的位宽】 | 5.1声道 |
| alac | 1、无损格式一般压缩比为50%左右,编码好的文件都是vbr的, 要完成编码后才知道具体码率,各种码率解码器都可以支持, 速度瓶颈在读数据(设备读速度) 2、ape解码支持可支持Fast/Normal/High这3种,有的SDK速 度不够,可能会限制不支持High模式,使用Monkey's Audio 压缩工具编码High文件可测试。 | 8k/11025/12k/16k/22050/24k/32k/44100/48k | 16bit | 单/双声道 |
| ape | 8k/11025/12k/16k/22050/24k/32k/44100/48k | 16bit | 单/双声道 | |
| flac | 8k/11025/12k/16k/22050/24k/32k/44100/48k | 16bit | 单/双声道 | |
| mp3 | 全码率,支持layer1,layer2,layer3 | 8k/11025/12k/16k/22050/24k/32k/44100/48k | 16bit 【解码出来的位宽】 | 单/双声道 |
| wav | 码率有留个上限const变量WAV_MAX_BITRATEV给外部配置, 超过上限码率的返回不支持。例如 12bit2ch48k的pcm, 码率较高 【不支持3bit ima,alaw,ulaw等】 | 8k/11025/12k/16k/22050/24k/32k/44100/48k | wav支持8/16/24/32bit的pcm, 4bit的ima跟4bit ms adpcm | 单/双声道 |
| wma | 支持Windows Media Audio中非加密的格式 【不支持Windows Media Audio Professional, Windows Media Audio Lossless,Windows Media Audio Voice,或者 加密的文件】 | 8k/11025/12k/16k/22050/24k/32k/44100/48k | 16bit 【解码出来的位宽】 | 单/双声道 |
| g726 | 8k,16k | 支持4bit的解码,解码出来的位宽为16bit | 单声道 | |
| midi | 8k/11025/12k/16k/22050/24k/32k/44100/48k | 16bit 【解码出来的位宽】 | 双声道 |
五. 功能
- 启动解码后但不马上开始播放
u8 file_dec_start_pause = 0; // 启动解码后但不马上开始播放
- 无缝播放
2.1 无缝播放内置提示音
- AC696/AC695 音箱SDK修改方法
- 在文件SDK\cpu\br25\audio_dec\audio_dec_tone.c 添加以下函数
/*----------------------------------------------------------------------------*/
/**@brief 内置提示音循环播放回调接口
@param *priv: 私有参数
@return 0:循环播放
@return 非0:结束循环
@note
*/
/*----------------------------------------------------------------------------*/
static int tone_dec_repeat_cb(void *priv)
{
struct tone_dec_handle *dec = priv;
printf("file_dec_repeat_cb\\n");
if (dec->repeat_num) {
dec->repeat_num--;
} else {
y_printf("file_dec_repeat_cb end\\n");
return -1;
}
return 0;
}
/*----------------------------------------------------------------------------*/
/**@brief 内置提示音设置循环播放次数
@param repeat_num: 循环次数
@return true:成功
@return false:失败
@note
*/
/*----------------------------------------------------------------------------*/
int tone_dec_repeat_set(struct audio_dec_file_app_hdl * file_dec,u8 repeat_num)
{
struct tone_dec_handle *dec = file_dec->priv;
switch (file_dec->dec->decoder.dec_ops->coding_type) {
case AUDIO_CODING_WAV:
case AUDIO_CODING_MP3:
{
dec->repeat_num = repeat_num;
struct audio_repeat_mode_param rep = {0};
rep.flag = 1; //使能
rep.headcut_frame = 2; //依据需求砍掉前面几帧,仅mp3格式有效
rep.tailcut_frame = 2; //依据需求砍掉后面几帧,仅mp3格式有效
rep.repeat_callback = tone_dec_repeat_cb;
rep.callback_priv = dec;
rep.repair_buf = &dec->repair_buf;
audio_decoder_ioctrl(&(file_dec->dec->decoder), AUDIO_IOCTRL_CMD_REPEAT_PLAY, &rep);
}
return true;
}
return false;
}
- SDK\cpu\br25\audio_dec\audio_dec_tone.h 添加以下结构体参数
/*
* 提示音解码结构体
* 可以实现多个tone_dec_list_handle播放,通过结构体中的链表连接
* 当解码中有正弦波数组播放时,必须要实现*get_sine接口
*/
struct tone_dec_handle {
struct list_head head; // 链表头
struct audio_dec_sine_app_hdl *dec_sin; // 文件播放句柄
struct audio_dec_file_app_hdl *dec_file; // sine播放句柄
struct tone_dec_list_handle *cur_list; // 当前播放list
struct sin_param *(*get_sine)(u8 id, u8 *num); // 按序列号获取sine数组
OS_MUTEX mutex; // 互斥
u8 repeat_num; // 无缝循环次数
struct fixphase_repair_obj repair_buf; // 无缝循环句柄
};
- 添加以下内容 SDK\cpu\br25\audio_dec\audio_dec_tone.c 的 tone_dec_file_app_evt_cb 函数
case AUDIO_DEC_APP_EVENT_START_INIT_OK:
log_i("tone_file start init ok\\n");
if (dec->cur_list->stream_handler) {
// 删除原有的数据流,需要在回调中重新设置
if (file_dec->dec->stream) {
audio_stream_del_entry(&file_dec->dec->mix_ch.entry);
audio_stream_del_entry(&file_dec->dec->decoder.entry);
audio_stream_close(file_dec->dec->stream);
file_dec->dec->stream = NULL;
}
dec->cur_list->stream_handler(dec->cur_list->stream_priv, event, file_dec->dec);
}
clock_add_set(DEC_TONE_CLK);
audio_dec_file_app_init_ok(file_dec);
tone_dec_repeat_set(file_dec,3);//这次传重复次数,如果需要一直循环,需回调函数一直返回0
break;
- 测试函数
case KEY_TONE_REPLAY_TEST:
{
extern int tone_play_repeat(const char *name, u8 preemption);
tone_play_by_path(tone_table[IDEX_TONE_BLE_DS], 1);
}
break;
- 注意点: 无缝播放只支持 MP3、WAV格式
- 按文件号播放 我们文件号取决于文件放进文件系统中的时间,从早到晚依次排序
//*----------------------------------------------------------------------------*/
/**@brief music_player序号播放指定设备
@param
logo:逻辑盘符,如:sd0/sd1/udisk0
number:指定播放序号
@return 播放错误码
@note
*/
/*----------------------------------------------------------------------------*/
int music_player_play_by_number(char *logo, u32 number)
- 按路径播放
短文件名/文件夹播放(不支持长文件名:超过8个字节文件名一般为长文件名,长文件夹名字也不支持)
长文件名(只支持完整路径播放)
中文路径 程序识别中文是使用ANSI编码格式,
要使用中文路径,需知中文路径名字在ANSI编码的16进制
方法:使用记事本设置编码格式:
然后使用WINHEX打开,16进制为:
字符串:char zhongwen[6] = {0xD6,0xD0,0xCE,0xC4};
使用方法:
比如:storage/udisk0/C/中文.txt 这个路径
char zhongwen[6] = {0xD6,0xD0,0xCE,0xC4};
char path[80] = {0}
sprintf(path, "%s%s%s", "storage/udisk0/C/", zhongwen,".txt");
printf("name == %s\n",path); //path == ”storage/udisk0/C/中文.txt”
- 指定文件夹播放
- 实现原理:重新指定一个扫描路径去获取到指定路径的,然后根据文件号进行播放
- 步骤:
- apps\common\dev_manager\dev_manager.c 添加以下函数
//*----------------------------------------------------------------------------*/
/**@brief 设备扫盘
@param
dev:设备节点
path:指定扫描目录
parm:扫描参数,包括文件后缀等
cycle_mode:播放循环模式
callback:扫描打断回调
@return 成功返回扫描控制句柄,失败返回NULL
@note
*/
/*----------------------------------------------------------------------------*/
struct vfscan *dev_manager_scan_disk_by_user(struct __dev *dev, const char *path, const char *parm, u8 cycle_mode, struct __scan_callback *callback)
{
if (dev_manager_check(dev) == NULL) {
return NULL;
}
#if TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0
#if (TCFG_DM_MULTIPLEX_WITH_SD_PORT == 0) //0:sd0 1:sd1 //dm 参与复用的sd配置
if(!memcmp(dev->parm->logo ,"sd0",strlen("sd0"))){
#else
if(!memcmp(dev->parm->logo ,"sd1",strlen("sd1"))){
#endif
dev_usb_change_sd();
}
if(!memcmp(dev->parm->logo ,"udisk",strlen("udisk")))
dev_sd_change_usb();
if (dev_manager_online_check(dev, 1) == NULL) {
printf("mult remount fail !!!\n");
return NULL;
}
#endif
char *fsn_path = NULL;
char *tmp_path = NULL;
if (path) {
if (*path == '/') {
path++;
}
tmp_path = zalloc(strlen(dev->parm->root_path) + strlen(path) + 1);
if (tmp_path == NULL) {
return NULL;
}
sprintf(tmp_path, "%s%s", dev->parm->root_path, path);
fsn_path = tmp_path;
} else {
fsn_path = dev->parm->root_path;
}
printf("fsn_path = %s, scan parm = %s\n", fsn_path, parm);
struct vfscan *fsn;
/* clock_add_set(SCAN_DISK_CLK); */
if(callback && callback->enter){
callback->enter(dev);//扫描前处理, 可以在注册的回调里提高系统时钟等处理
}
fsn = fscan_interrupt(
(const char *)fsn_path,
parm,
DEV_MANAGER_SCAN_DISK_MAX_DEEPTH,
((callback) ? callback->scan_break : NULL));
/* clock_remove_set(SCAN_DISK_CLK); */
if(callback && callback->exit){
callback->exit(dev);//扫描后处理, 可以在注册的回调里还原到enter前的状态
}
y_printf("fsn->file_number %d\n",fsn->file_number);
if (fsn) {
if (fsn->file_number == 0) {
printf("dev nofile\n");
#if (TCFG_DEV_UPDATE_IF_NOFILE_ENABLE)
///没有文件找升级文件
dev_update_check(dev->parm->logo);
#endif/*TCFG_DEV_UPDATE_IF_NOFILE_ENABLE*/
///没有文件,释放fsn, 减少外面流程的处理
dev_manager_scan_disk_release(fsn);
fsn = NULL;
} else {
fsn->cycle_mode = cycle_mode;
}
}
if (tmp_path) {
free(tmp_path);
}
return fsn;
}
- apps\common\music\music_player.c 添加 int music_player_play_by_path_index(char *logo, const char *path,int index)
//*----------------------------------------------------------------------------*/
/**@brief music_player路径播放指定设备
@param
logo:逻辑盘符,如:sd0/sd1/udisk0, 设置为NULL,为默认当前播放设备
path:指定播放文件夹路径(例如:/dir2)
index:文件夹内的序号(1~N)
@return 播放错误码
@note
*/
/*----------------------------------------------------------------------------*/
int music_player_play_by_path_index(char *logo, const char *path,int index)
{
static struct vfscan *fsn;//设备扫描句柄
if (path == NULL) {
return MUSIC_PLAYER_ERR_POINT;
}
if (logo == NULL) {
music_player_stop(0);
if (dev_manager_online_check(__this->dev, 1) == 0) {
return MUSIC_PLAYER_ERR_DEV_OFFLINE;
}
///没有指定设备不需要找设备, 不需要扫描
} else {
music_player_stop(0);
__this->dev = dev_manager_find_spec(logo, 1);
if (__this->dev == NULL) {
return MUSIC_PLAYER_ERR_DEV_NOFOUND;
}
fsn = dev_manager_scan_disk_by_user(__this->dev, path, scan_parm, app_var.cycle_mode, __this->parm.scan_cb);
}
if (fsn == NULL) {
return MUSIC_PLAYER_ERR_FSCAN;
}
y_printf("index %d\n",index);
///get file
__this->file = file_manager_select(__this->dev, fsn, FSEL_BY_NUMBER, index, __this->parm.scan_cb);//根据簇号查找文件
if (__this->file == NULL) {
return MUSIC_PLAYER_ERR_FILE_NOFOUND;
}
// //释放fsn, 减少外面流程的处理
dev_manager_scan_disk_release(fsn);
///start decoder
int err = music_player_decode_start(__this->file, 0);
if (err == MUSIC_PLAYER_SUCC) {
///选定新设备播放成功后,需要激活当前设备
dev_manager_set_active(__this->dev);
log_i("[%s %d] ok\n", __FUNCTION__, __LINE__);
}
return err;
}
- 使用方法:
music_player_play_by_path_index((char *)"udisk0", "/dir2",1);///this is a demo
- 文件浏览 可以参考 SDK\apps\common\file_operate\file_bs_deal.c 中的void file_bs_test(void
void file_bs_test(void)
- IR按键实现选择第X首歌曲播放

/*********************************************************************************************************//**
* @brief IR数字按键播放音乐
* @retval
***********************************************************************************************************/
static u16 auto_time_id = 0;
void user_music_play_finle_number(void *priv){
int *filenum = (int *)priv;
auto_time_id = 0;
y_f_printf(">>>number %d %d\n",*filenum);
if(*filenum)
{
music_player_play_by_number(music_player_get_dev_cur(),*filenum);
// music_play_msg_post(3, MPLY_MSG_FILE_BY_DEV_FILENUM, (int)music_play_get_cur_dev(), *filenum);
}
*filenum = 0;
y_f_printf(">>>>%d\n",*filenum);
}
//设置MUSIC音量
void user_music_set_file_number(int number)
{
#if USER_IR_PLAY_FILE_NUMBER
static int filenum = 0;
s32 tp = filenum*10+number;
y_f_printf(">>>>>music_play_get_file_total_file %d\n",music_player_get_file_total());
if(auto_time_id){
sys_timeout_del(auto_time_id);
}
if((tp>music_player_get_file_total()) || tp/10000){
filenum = 0;
UI_SHOW_MENU(MENU_SET_ERR, 3000, 0, NULL);
return;
}
else{
filenum = tp;
}
y_f_printf(">>>>> filenum %d\n",filenum);
UI_SHOW_MENU(MENU_FILENUM, 4000, filenum, NULL);
if(filenum>1000){
user_music_play_finle_number(&filenum);
filenum = 0;
}
else{
auto_time_id = sys_timeout_add(&filenum,user_music_play_finle_number,3000);
}
#endif
}
FAQ
- AC695X 3.1.0SDKmusic下切设备顺序以及是否播放设备提示音------------SQ 修改文件包
- 程序msuic.c修改
- 添加宏定义、变量
/***添加宏定义、变量 start***/
#define USER_DEV_USB "udisk0"
#define USER_DEV_SD0 "sd0"
#define USER_DEV_SD1 "sd1"
u8 dev_order=1;//0:默认sdk 1:usb优先 2:sd卡优先
u8 dev_tone=0;//0:不播放设备提示音 1:播放设备提示音
u8 u_dev_mount_flag=0;//设备上标志 1 usb 2 sd
/***添加宏定义、变量 end***/
- 设备提示音使能
///设备提示音使能
#define MUSIC_DEVICE_TONE_EN 1
- 提示音名称使其与外部工具配置一致
const struct __dev_tone device_tone[] = {
{"udisk0", "udisk0", TONE_RES_ROOT_PATH"tone/usb.*"/**名称与外部配置工具保持一致**/, DEVICE_INDEX_UDISK},
{"udisk0_rec", "udisk0", TONE_RES_ROOT_PATH"tone/usb.*"/**名称与外部配置工具保持一致**/, DEVICE_INDEX_UDISK_REC},
{"sd0", "sd0", TONE_RES_ROOT_PATH"tone/sd.*"/**名称与外部配置工具保持一致**/, DEVICE_INDEX_SD0},
{"sd0_rec", "sd0", TONE_RES_ROOT_PATH"tone/sd.*"/**名称与外部配置工具保持一致**/, DEVICE_INDEX_SD0_REC},
{"sd1", "sd1", TONE_RES_ROOT_PATH"tone/sd.*"/**名称与外部配置工具保持一致**/, DEVICE_INDEX_SD1},
{"sd1_rec", "sd1", TONE_RES_ROOT_PATH"tone/sd.*"/**名称与外部配置工具保持一致**/, DEVICE_INDEX_SD1_REC},
};
- 嵌入控制设备提示音播放变量
if (strcmp(device_tone[i].logo, logo) == 0) {
log_i("[%s, %d]device_tone play \n", logo, __LINE__);
memset(__this->device_tone_dev, 0, sizeof(__this->device_tone_dev));
memcpy(__this->device_tone_dev, device_tone[i].phy_logo, strlen(device_tone[i].phy_logo));
/***嵌入控制设备提示音播放变量 start**/
if(dev_tone){
tone_play_with_callback_by_name(device_tone[i].tone_path, 1, music_tone_play_end_callback, (void *)device_tone[i].index);
}else{
music_tone_play_end_callback((void *)device_tone[i].index,0);
}
/***嵌入控制设备提示音播放变量 end**/
return true;
}
- KEY_MUSIC_PLAYER_START消息处理修改
#if (MUSIC_DEVICE_TONE_EN)
if (/*start*/dev_tone &&/*end*/ (music_device_tone_play(logo) == true)) {
UI_SHOW_MENU(MENU_MUSIC_SEITCH_DEV, 0, 0, NULL);
break;
}
#endif
- 添加KEY_CHANGE_MODE消息处理
case KEY_CHANGE_MODE:
r_printf("KEY_CHANGE_MODE");
if((dev_manager_get_total(1)>1)){
char *active_by_logo=NULL;
if(dev_order){
if(1==dev_order){
active_by_logo=USER_DEV_USB;
}else if(2==dev_order){
#if TCFG_SD0_ENABLE
active_by_logo=USER_DEV_SD0;
#elif TCFG_SD1_ENABLE
active_by_logo=USER_DEV_SD1;
#endif
}
if(active_by_logo && (music_player_get_dev_cur()==active_by_logo)){
app_task_put_key_msg(KEY_MUSIC_AUTO_NEXT_DEV,0);
break;
}
}
}
ret = false;
break;
- 进music模式添加播放逻辑处理
void app_music_task()
{
int res;
int msg[32];
music_task_start();
/***多设备在线判断 start***/
if((dev_manager_get_total(1)>1)){
char *active_by_logo=NULL;
if(dev_order){
if(1==dev_order){
if(2==u_dev_mount_flag){
#if TCFG_SD0_ENABLE
active_by_logo=USER_DEV_SD0;
#elif TCFG_SD1_ENABLE
active_by_logo=USER_DEV_SD1;
#endif
}else{
active_by_logo=USER_DEV_USB;
}
}else if(2==dev_order){
if(1==u_dev_mount_flag){
active_by_logo=USER_DEV_USB;
}else{
#if TCFG_SD0_ENABLE
active_by_logo=USER_DEV_SD0;
#elif TCFG_SD1_ENABLE
active_by_logo=USER_DEV_SD1;
#endif
}
}
dev_manager_set_active_by_logo(active_by_logo);
}
}
/***多设备在线判断 end***/
#if (MUSIC_DEVICE_TONE_EN)
/***是否播放设备提示音 start***/
if (dev_tone){
music_player_play_start();
}else{
tone_play_with_callback_by_name(tone_table[IDEX_TONE_MUSIC], 1, music_tone_play_end_callback, (void *)IDEX_TONE_MUSIC);
}
/***是否播放设备提示音 end***/
#else
.....
.....
- app_common.c修改内容
- 设备上线标记
case DRIVER_EVENT_FROM_SD0:
case DRIVER_EVENT_FROM_SD1:
case DRIVER_EVENT_FROM_SD2:
#if TCFG_APP_MUSIC_EN
ret = dev_status_event_filter(event);///解码设备上下线, 设备挂载等处理
if (ret == true) {
if (event->u.dev.event == DEVICE_EVENT_IN) {
///设备上线, 非解码模式切换到解码模式播放
if (app_get_curr_task() != APP_MUSIC_TASK) {
app = APP_MUSIC_TASK;
/*设备上线标记 satrt*/
extern u8 u_dev_mount_flag;//1 usb 2 sd
if(((u32)event->arg)==DRIVER_EVENT_FROM_SD0 || ((u32)event->arg)==DRIVER_EVENT_FROM_SD2){
u_dev_mount_flag=2;
}else{
u_dev_mount_flag=1;
}
/*设备上线标记 end*/
}
}
}
#endif
- 播放设备提示音的地方需要主要提示音名称一定要在工具里面有

- 如果不需要分开播放设备提示音就把提示音改为一样,同样需要满足第3点

5.播放隐藏文件

- 696 170 删除设备中的文件夹 内部git
ac696x_soundbox_sdk-1.7.0-删除设备中的文件夹.7z