PLAYER_HANDLE lisa_player_create(const char *name, int id);
接口说明:该接口用于创建播放器
返回值:播放器句柄
参数名 | 类型 | 说明 |
---|---|---|
name | char * | 播放器名称 |
id | int | 播放器id |
void lisa_player_set_loglev(int level);
日志等级 | 输出日志类型 |
---|---|
0 | LOG |
1 | ERROR LOG |
2 | WARNING LOG |
3 | INFO LOG |
4 | DEBUG LOG |
5 | VERBOSE LOG |
参数名 | 类型 | 说明 |
---|---|---|
level | int | 播放器日志等级(0-5) |
void lisa_player_destory(PLAYER_HANDLE h);
接口说明:该接口用于销毁播放器
返回值:无
参数名 | 类型 | 说明 |
---|---|---|
h | PLAYER_HANDLE | 创建播放器时的句柄 |
PlayerErr lisa_player_set_callback(PLAYER_HANDLE h, player_callback cb);
接口说明:该接口用于设置播放器事件回调
返回值:PlayerErr
,详见通用错误码定义
参数名 | 类型 | 说明 |
---|---|---|
h | PLAYER_HANDLE | 创建播放器时的句柄 |
cb | player_callback | 接收事件回调的函数指针 |
typedef int (*player_callback)(PlayerEvt evt, int arg1, int arg2, int id);
参数名 | 类型 | 说明 |
---|---|---|
evt | PlayerEvt | 播放器回调事件,详见下方关于 PlayerEvt 定义 |
arg1 | int | 参数1,出错时为错误码,详见通用错误码定义 |
arg2 | int | 参数2,应用层一般不需要关心 |
id | int | 创建时传入的播放器id |
PlayerEvt:
枚举值 | 说明 |
---|---|
PLAYER_EVT_ERROR | 播放错误 |
PLAYER_EVT_PREPARED | 缓冲完成,需要调用 lisa_player_play 才会去播放 |
PLAYER_EVT_PLAYING | 播放中 |
PLAYER_EVT_PAUSED | 已暂停 |
PLAYER_EVT_STOPED | 已停止 |
PLAYER_EVT_NEARLY_COMPLETE | 即将播放完成 |
PLAYER_EVT_PLAYBACK_COMPLETE | 播放完成 |
PLAYER_EVT_SEEKING | Seek中 |
PLAYER_EVT_SEEK_COMPLETE | Seek完成 |
PLAYER_EVT_INIT | 初始化状态 |
PlayerErr lisa_player_seturl(PLAYER_HANDLE h, const char *url);
接口说明:该接口用于设置播放器播放的 url,可以是本地资源路径或网络资源路径
返回值:PlayerErr
,详见通用错误码定义
参数名 | 类型 | 说明 |
---|---|---|
h | PLAYER_HANDLE | 创建播放器时的句柄 |
url | char * | url 地址 |
播放本地提示音的时候,AP侧和ASR侧传入的url是有差别的;
AP侧:通过提示音获取接口app_tone_get_url
获取url;
ASR侧:url格式为mem://id=1
,1是需要播放提示音的id;
提示音获取参考文档本地提示音部分;
播放示例参考文档播放器使用示例部分;
PlayerErr lisa_player_start_pcm_mode(PLAYER_HANDLE h, AudioFormat format);
接口说明:该接口用于播放 pcm 开始时调用
返回值:PlayerErr
,详见通用错误码定义
参数名 | 类型 | 说明 |
---|---|---|
h | PLAYER_HANDLE | 创建播放器时的句柄 |
format | AudioFormat | 音频格式,详见下方关于 AudioFormat 定义 |
AudioFormat:
参数名 | 类型 | 说明 |
---|---|---|
channel | uint8_t | 音频的通道数 |
bits | uint8_t | 音频的采样精度 |
samplerate | uint32_t | 音频的采样率 |
PlayerErr lisa_player_write_pcm_data(PLAYER_HANDLE h, uint8_t *data, uint32_t size);
接口说明:该接口用于写入 pcm 数据并播放
返回值:PlayerErr
,详见通用错误码定义
参数名 | 类型 | 说明 |
---|---|---|
h | PLAYER_HANDLE | 创建播放器时的句柄 |
data | uint8_t * | 音频数据指针 |
size | uint32_t | 音频数据大小 |
PlayerErr lisa_player_write_pcm_data_eos(PLAYER_HANDLE h, uint8_t *data, uint32_t size);
接口说明:该接口用于写入最后一次 pcm 数据
返回值:PlayerErr
,详见通用错误码定义
参数名 | 类型 | 说明 |
---|---|---|
h | PLAYER_HANDLE | 创建播放器时的句柄 |
data | uint8_t * | 音频数据指针 |
size | uint32_t | 音频数据大小 |
PlayerErr lisa_player_play(PLAYER_HANDLE h);
接口说明:该接口用于播放器开始播放,在收到播放器 PLAYER_EVT_PREPARED 事件时调用
返回值:PlayerErr
,详见通用错误码定义
参数名 | 类型 | 说明 |
---|---|---|
h | PLAYER_HANDLE | 创建播放器时的句柄 |
PlayerErr lisa_player_pause(PLAYER_HANDLE h);
接口说明:该接口用于播放器暂停播放
返回值:PlayerErr
,详见通用错误码定义
参数名 | 类型 | 说明 |
---|---|---|
h | PLAYER_HANDLE | 创建播放器时的句柄 |
PlayerErr lisa_player_resume(PLAYER_HANDLE h); //异步接口
PlayerErr lisa_player_resume_sync(PLAYER_HANDLE h); //同步接口
接口说明:该接口用于播放器恢复播放
返回值:PlayerErr
,详见通用错误码定义
参数名 | 类型 | 说明 |
---|---|---|
h | PLAYER_HANDLE | 创建播放器时的句柄 |
PlayerErr lisa_player_stop(PLAYER_HANDLE h); //异步接口
PlayerErr lisa_player_stop_sync(PLAYER_HANDLE h); //同步接口
接口说明:该接口用于播放器停止播放
返回值:PlayerErr
,详见通用错误码定义
参数名 | 类型 | 说明 |
---|---|---|
h | PLAYER_HANDLE | 创建播放器时的句柄 |
PlayerErr lisa_player_reset(PLAYER_HANDLE h);
接口说明:该接口用于播放器重置,一般在播放新的 url 之前调用
返回值:PlayerErr
,详见通用错误码定义
参数名 | 类型 | 说明 |
---|---|---|
h | PLAYER_HANDLE | 创建播放器时的句柄 |
PlayerErr lisa_player_seek(PLAYER_HANDLE h, int seek_ms); //异步接口
PlayerErr lisa_player_seek_sync(PLAYER_HANDLE h, int seek_ms); //同步接口
接口说明:该接口用于播放器 seek
返回值:PlayerErr
,详见通用错误码定义
参数名 | 类型 | 说明 |
---|---|---|
h | PLAYER_HANDLE | 创建播放器时的句柄 |
seek_ms | int | 需要seek的时间点,单位ms |
PlayerState lisa_player_get_state(PLAYER_HANDLE h);
接口说明:该接口用于获取播放器状态
返回值:播放器状态,详见下方 PlayerState
定义
参数名 | 类型 | 说明 |
---|---|---|
h | PLAYER_HANDLE | 创建播放器时的句柄 |
PlayerState:
枚举值 | 说明 |
---|---|
PLAYER_ST_ERROR | 错误状态 |
PLAYER_ST_NONE | 初始化状态 |
PLAYER_ST_READY_TO_PLAY | 准备去播放状态 |
PLAYER_ST_PREPARED | 缓冲完成状态 |
PLAYER_ST_PLAYING | 播放中 |
PLAYER_ST_PAUSED | 已暂停 |
PLAYER_ST_STOPED | 已停止 |
PLAYER_ST_PLAYBACK_COMPLETE | 播放完成 |
int32_t lisa_player_get_duration(PLAYER_HANDLE h);
接口说明:该接口用于当前播放资源的总时长
返回值:资源总时长,单位 ms
参数名 | 类型 | 说明 |
---|---|---|
h | PLAYER_HANDLE | 创建播放器时的句柄 |
int32_t lisa_player_get_pos(PLAYER_HANDLE h);
接口说明:该接口用于当前播放资源的进度
返回值:资源播放进度,单位 ms
参数名 | 类型 | 说明 |
---|---|---|
h | PLAYER_HANDLE | 创建播放器时的句柄 |
PlayerErr lisa_player_set_vol(PLAYER_HANDLE h, int vol);
接口说明:该接口用于设置播放器的音量,范围[0, 100]
返回值:PlayerErr
,详见通用错误码定义
参数名 | 类型 | 说明 |
---|---|---|
h | PLAYER_HANDLE | 创建播放器时的句柄 |
vol | int | 音量,范围[0, 100] |
PlayerErr lisa_player_throw_begin_data(PLAYER_HANDLE h, int throw_time_ms);
接口说明:该接口用于丢弃开头指定时长的数据,在 lisa_player_seturl
之前调用;(由于部分音频前面存在静音数据,需要丢弃静音数据的时候调用该接口)
返回值:PlayerErr
,详见通用错误码定义
参数名 | 类型 | 说明 |
---|---|---|
h | PLAYER_HANDLE | 创建播放器时的句柄 |
throw_time_ms | int | 丢弃多长时间的数据,单位ms |
枚举值 | 说明 |
---|---|
PLAYER_OK | 正常 |
PLAYER_ERR | 通用错误 |
PLAYER_OP_FAIL | 操作失败 |
PLAYER_NO_MEMORY | 内存不足 |
PLAYER_INVALID_HANDLE | 无效的句柄 |
PLAYER_INVALID_STATE | 无效的状态 |
PLAYER_INVALID_CTX | 无效的context |
PLAYER_INVALID_PARAM | 无效的参数 |
PLAYER_INVALID_FMT | 无效的格式 |
PLAYER_DEMUX_ERR | demux失败 |
PLAYER_DEMUX_ERR_SEEK | seek失败 |
PLAYER_DEMUX_ERR_FORMAT | 格式解析失败 |
PLAYER_DEMUX_ERR_READ | 读取失败 |
PLAYER_DEMUX_SEEK_UNSUPPORT | 不支持seek |
PLAYER_DEMUX_SEEK_ERRORTIME | seek时间不正确 |
PLAYER_DECODE_ERR | 解码失败 |
PLAYER_DECODE_INIT_ERR | 解码初始化失败 |
PLAYER_DECODE_FORMAT_ERR | 解码对应音频格式失败 |
PLAYER_DECODE_INIT_RESAMPLE_ERR | 重采样失败 |
PLAYER_DECODE_UNSUPPORT_CHL_ERR | 不支持的通道配置 |
PLAYER_PLAY_ERR | 播放出错 |
PLAYER_PLAY_TRACK_INIT_ERR | 声卡初始化失败 |
PLAYER_PLAY_WRITE_ERR | 往声卡写出错 |
PLAYER_PROBE_FORMAT_ERROR | 音频格式解析失败 |
PLAYER_PROBE_FORMAT_UNKNOW | 音频格式未知 |
//以下展示部分代码
/ ****************************************
* 本地、在线音频播放参考示例
* 在线音频播放前需要连接网络
******************************************/
static PLAYER_HANDLE lisa_player = NULL;
/* 播放器事件回调函数 */
static int _play_callback(PlayerEvt evt, int arg1, int arg2, int id)
{
printk("_play_callback player evt = %d\n", evt);
switch (evt) {
case PLAYER_EVT_PREPARED:
lisa_player_play(lisa_player);
return 0;
case PLAYER_EVT_PLAYING:
break;
case PLAYER_EVT_PAUSED:
break;
case PLAYER_EVT_STOPED:
break;
case PLAYER_EVT_PLAYBACK_COMPLETE:
break;
case PLAYER_EVT_ERROR:
break;
default:
break;
}
return 0;
}
void audio_player_play(void)
{
if (!lisa_player) {
/* 创建播放器 */
lisa_player = lisa_player_create("test_player", 0);
if (lisa_player) {
/* 设置播放播放器音量 */
lisa_player_set_vol(lisa_player, 100);
/* 设置播放播放器回调接口 */
lisa_player_set_callback(lisa_player, _play_callback);
} else {
printk("player create failed\n");
return 0;
}
}
/* 播放在线资源 */
lisa_player_seturl(lisa_player, "http://listenai-firmware-delivery.oss-cn-beijing.aliyuncs.com/mt8512/music/128k.mp3");
/* AP侧播放本地资源 */
// 例如播放提示音id是1的本地提示音
// char *tone_url = app_tone_get_url(1);
// lisa_player_seturl(lisa_player, tone_url);
/* ASR侧播放本地资源 */
// 例如播放提示音id是1的本地提示音
// lisa_player_seturl(lisa_player, "mem://id=1");
//以下展示部分代码
/ ****************************************
* 播放 PCM 数据参考示例
*
******************************************/
#define STREAM_FRAME_SAPMS (160)
#define STREAM_FRAME_CHANNELS (1)
#define STREAM_FRAME_SIZE (STREAM_FRAME_SAPMS * STREAM_FRAME_CHANNELS * sizeof(short))
unsigned char array_pcm[] = {
/*此处为音频的 PCM 数据*/
};
static PLAYER_HANDLE lisa_player = NULL;
/* 播放器事件回调函数 */
static int _play_callback(PlayerEvt evt, int arg1, int arg2, int id)
{
printk("_play_callback player evt = %d\n", evt);
switch (evt) {
case PLAYER_EVT_PREPARED:
lisa_player_play(lisa_player);
return 0;
case PLAYER_EVT_PLAYING:
break;
case PLAYER_EVT_PAUSED:
break;
case PLAYER_EVT_STOPED:
break;
case PLAYER_EVT_PLAYBACK_COMPLETE:
break;
case PLAYER_EVT_ERROR:
break;
default:
break;
}
return 0;
}
void audio_player_pcm(void)
{
if (!lisa_player) {
/* 创建播放器 */
lisa_player = lisa_player_create("pcm_test_player", 0);
if (lisa_player) {
/* 设置播放播放器音量 */
lisa_player_set_vol(lisa_player, 100);
/* 设置播放播放器回调接口 */
lisa_player_set_callback(lisa_player, _play_callback);
} else {
printk("player create failed");
return 0;
}
}
/* 播放pcm */
AudioFormat format;
format.bits = 16;
format.channel = 1;
format.samplerate = 16000;
lisa_player_start_pcm_mode(lisa_player, format);
int rc;
int playsize = STREAM_FRAME_SIZE;
bool is_eos = false;
uint32_t fileLen = sizeof(array_pcm);
for (int i = 0; i < fileLen; i += playsize) {
int nPlaySize = playsize;
if ((i + playsize) >= fileLen) {
nPlaySize = fileLen - i;
is_eos = true;
}
if (is_eos) {
rc = lisa_player_write_pcm_data_eos(lisa_player, array_pcm + i, nPlaySize);
if (rc != 0) {
break;
}
} else {
rc = lisa_player_write_pcm_data(lisa_player, array_pcm + i, nPlaySize);
if (rc != 0) {
break;
}
}
}
}
CSK6 播放器默认不支持 AAC 解码,也就是说 CSK6 播放器默认不支持播放 m4a、aac 等用 AAC 编码的音频文件,播放时会报错;如果开发者想支持 AAC 解码,则需要按照以下步骤自行操作:
下载地址:https://github.com/knik0/faad2/releases
build.sh
内容如下所示,其中工具链地址需要根据实际情况修改
#!/bin/bash
export PATH=~/code/csk6/gcc-arm-none-eabi-10.3-2021.10/bin:$PATH
rm -rf out
make clean
mkdir ./out
make all
Makefile 内容如下所示
TOPDIR = .
TAG := CSK6001
CROSS_COMPILE := arm-none-eabi-
CC = $(CROSS_COMPILE)gcc
C++ = $(CROSS_COMPILE)g++
LD = $(CROSS_COMPILE)ld
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump
AR = $(CROSS_COMPILE)ar #gcc-ar
AS = $(CROSS_COMPILE)as
NM = $(CROSS_COMPILE)nm #gcc-nm
READELF = $(CROSS_COMPILE)readelf
STRIP = $(CROSS_COMPILE)strip
SIZE = $(CROSS_COMPILE)size
RM = -rm -rf
MV = mv
CP = cp
MAKE = make
#lib or target you want to build: eg. LIB=libmisc.a or TARGET=wlan
LIB = libFAAD2.a
TARGET =
LDS =
#libraries depend: eg. LIBS = -lbsp -ldrv -lrtos
LIBS =
#exclude subdirs
EXDIRS =
#files want to build: eg. CSRCS=x.c SSRCS=x.S
CSRCS = $(wildcard libfaad/*.c)
SSRCS =
# OPTIM = -Os
#includings and flags
CFLAGS += -Dmalloc=lisa_mem_sram_alloc
CFLAGS += -Dcalloc=lisa_mem_sram_calloc
CFLAGS += -Drealloc=lisa_mem_sram_realloc
CFLAGS += -Dfree=lisa_mem_sram_free
CFLAGS += -DHAVE_STDINT_H=1 -DEXPORT= -DPACKAGE_VERSION=\"2.10.1\"
CFLAGS += -DHAVE_MEMCPY=1 -DLC_ONLY_DECODER
CFLAGS += -Os -w -Wunused-function -funwind-tables -fcommon
CFLAGS += -I./include/
CFLAGS += -I./libfaad/
CFLAGS += -I./libfaad/codebook
#defines
PLATFORM_DEF = -DPLATFORM_AP -DARMCM33_DSP_FP -DCONFIG_ARM \
-DCONFIG_ARMV7_M_ARMV8_M_MAINLINE -DCONFIG_CPU_CORTEX_M \
-DCONFIG_CPU_CORTEX_M33 -DCONFIG_PREEMPT_ENABLED
OS_DEF = -DFREERTOS_USED
OPTIM = -O3 -g # -flto -ffat-lto-objects
COREFLAGS := -mcpu=cortex-m33 -mfpu=fpv5-sp-d16 -mfloat-abi=hard
AFLAGS += -mthumb -gdwarf-2 -mthumb-interwork
CFLAGS += $(PLATFORM_DEF) $(OS_DEF) $(COREFLAGS) -DIC_BOARD=$(IC_BOARD) $(OPTIM) \
-w -Wno-format -Wno-unused -Wno-comment -MMD -ffunction-sections -fdata-sections \
-mthumb -gdwarf-2 -mapcs-frame -mthumb-interwork -DCONFIG_PRINTK
LDFLAGS += $(COREFLAGS) -mthumb -gdwarf-2 -mapcs-frame -mthumb-interwork \
-static -Wl,-gc-sections -T $(LDSCRIPT) --specs=nosys.specs # -flto -fuse-linker-plugin
LIBSGROUP := -Wl,--start-group $(LIBS) -lm -ldbg -Wl,--end-group -L$(TOPDIR)/lib
SUBDIRS := $(filter-out $(EXDIRS), $(shell find * -maxdepth 0 -type d))
TGTOUT = $(TOPDIR)/out
LIBOUT = $(TOPDIR)/out
LDOUT = $(notdir $(LDSCRIPT))
COBJS = $(CSRCS:.c=.o)
CPPOBJS = $(CPPSRCS:.cc=.o)
SOBJS = $(SSRCS:.S=.o)
DEPS = $(CSRCS:.c=.d) $(CPPSRCS:.cc=.d) $(SSRCS:.S=.d)
OBJS = $(COBJS) $(CPPOBJS) $(SOBJS)
DEP_LIBS = $(filter $(wildcard $(LIBOUT)/*.a), $(patsubst -l%, $(LIBOUT)/lib%.a, $(LIBS)))
.PHONY : all clean ld libs apps subdirs_l subdirs_t subdirs_c pre ext strip show_lib_ver burn remove
all : libs apps
libs : pre $(LIBOUT)/$(LIB) ext subdirs_l
$(LIBOUT)/$(LIB): $(COBJS) $(CPPOBJS) $(SOBJS)
@if [ "$(LIB)" != "" ]; then \
echo "archiving: $@ ..."; \
$(AR) rs $@ $^; \
fi
subdirs_l:
@for dir in $(SUBDIRS); do \
if [ -f "$$dir/Makefile" ]; then \
$(MAKE) -C $$dir libs||exit 1; \
fi; \
done
subdirs_t:
@for dir in $(SUBDIRS); do \
if [ -f "$$dir/Makefile" ]; then \
$(MAKE) -C $$dir apps||exit 1; \
fi; \
done
$(SOBJS): %.o: %.S
@echo compliling: $< ...
@$(CC) -c $(CFLAGS) $(AFLAGS) $< -o $@
$(COBJS): %.o: %.c
@echo compliling: $< ...
@$(CC) -c $(CFLAGS) -std=gnu11 $< -o $@
$(CPPOBJS): %.o: %.cc
@echo compliling: $< ...
@$(C++) -c $(CFLAGS) -std=gnu++17 $< -o $@
subdirs_c :
@for dir in $(SUBDIRS); do \
if [ -f "$$dir/Makefile" ]; then \
$(MAKE) -C $$dir clean||exit 1; \
fi; \
done
clean: subdirs_c
@if [ -n "$(LIB)" ]; then \
echo removing: $(LIB) ...; \
rm -rf $(LIBOUT)/$(LIB) $(OBJS) $(DEPS) *.o *.d *.m; \
fi
remove:
@$(shell find -type f -name "*.[odm]" -exec rm -rf {} \;)
strip:
for liba in $(shell find $(LIBOUT) -name "*.a" -type f); do \
$(STRIP) --strip-debug $$liba; \
done
屏蔽 libfaad/common.h
头文件中如下的宏定义
// #define SBR_DEC
// #define SBR_LOW_POWER
// #define PS_DEC
执行 build.sh
编译,生成的 FAAD2 库在 out 目录下面,文件名为 libFAAD2.a
a. 将上一步生成的 libFAAD2.a
库拷贝到 AP 源码的 lib 目录下面
b. 在 src/Makefile
文件中加上如下配置
LDFLAGS += -Wl,--whole-archive -lFAAD2 -Wl,--no-whole-archive