扩展指南 (extending)
本文介绍如何为 XSTAR 音频框架编写自定义组件,包括 三种扩展方式的对比以及 effect / source / sink 的完整实现模板。
三种扩展方式对比
| 方式 | 适用场景 | 是否注册 | 复杂度 |
|---|---|---|---|
| 回调式 source | 快速集成外部音频数据 | 否,audio_source_alloc_custom() 即可 | ★☆☆ |
| 自定义 effect | 新的信号处理算法:滤波/特效/分析 | 是,register_audio_effect() | ★★★ |
| 自定义 source/sink | 新文件格式/新硬件接口/新分析工具 | 否,实现 xxx_pdata_t + 钩子函数 | ★★☆ |
方式一:自定义 effect 插件(最常用)
模板代码
#include <kernel/audio/effect.h>
/* 私有数据结构 */
struct myeffect_pdata_t {
float param1;
int param2;
/* 状态变量(如果需要) */
};
static void * myeffect_create(void)
{
struct myeffect_pdata_t * pdat;
pdat = xos_mem_malloc(sizeof(struct myeffect_pdata_t));
if(!pdat)
return NULL;
pdat->param1 = 1.0f;
pdat->param2 = 0;
return pdat;
}
static void myeffect_setup(void * ctx, struct json_value_t * v)
{
struct myeffect_pdata_t * pdat = (struct myeffect_pdata_t *)ctx;
if(v && (v->type == JSON_OBJECT))
{
for(int i = 0; i < v->u.object.length; i++)
{
struct json_value_t * o = v->u.object.values[i].value;
switch(shash(v->u.object.values[i].name))
{
case 0x01234567: /* "param1" — 用 shash("param1") 替换 */
if(o && (o->type == JSON_DOUBLE))
pdat->param1 = (float)o->u.dbl;
break;
/* 更多参数... */
}
}
}
}
static void myeffect_prepare(void * ctx, struct audio_frame_t * input)
{
/* 可选:根据 input->rate/channel/frames 重新分配缓冲区 */
}
static struct audio_frame_t * myeffect_process(void * ctx, struct audio_frame_t * input)
{
struct myeffect_pdata_t * pdat = (struct myeffect_pdata_t *)ctx;
float * pi = input->samples;
for(int n = 0; n < input->frames; n++)
{
for(int c = 0; c < input->channel; c++)
{
pi[c] = pi[c] * pdat->param1; /* 示例:幅度缩放 */
}
pi += input->channel;
}
return input; /* 原地处理或返回新 buffer */
}
static void myeffect_destroy(void * ctx)
{
struct myeffect_pdata_t * pdat = (struct myeffect_pdata_t *)ctx;
if(pdat)
xos_mem_free(pdat);
}
static struct audio_effect_t myeffect = {
.name = "myeffect",
.create = myeffect_create,
.setup = myeffect_setup,
.prepare = myeffect_prepare,
.process = myeffect_process,
.destroy = myeffect_destroy,
};
static void myeffect_init(void) { register_audio_effect(&myeffect); }
static void myeffect_exit(void) { unregister_audio_effect(&myeffect); }
core_initcall(myeffect_init);
core_exitcall(myeffect_exit);
5 个钩子说明
| 钩子 | 时机 | 必选 | 职责 |
|---|---|---|---|
create | 分配 filter 时 | 是 | 分配私有数据结构并初始化默认值 |
setup | 每次 JSON 配置/重配置 | 是 | 解析 JSON 更新参数(可能被多次调用) |
prepare | 每次 process 之前 | 是 | 根据入参格式预分配输出缓冲区 |
process | 每帧处理 | 是 | 核心算法:处理输入帧 → 返回输出帧 |
destroy | 释放 filter 时 | 是 | 释放私有数据 |
两个重要约定:
setup可能被外部通过audio_filter_setup()多次调用以修改参数prepare与process成对出现——prepare做资源预检/分配,process做实际计算
关于 shash 哈希值的获取
在源码目录执行以下命令获取字段名的 shash 值:
# 用现成的 shash 工具(位于 developments/shash/)
echo -n "myparam" | ../developments/shash/shash
或临时编写 C 代码:
#include <stdio.h>
#include "libx/string-hash.h"
int main(void) { printf("0x%08x\n", shash("myparam")); return 0; }