1# 接口开发规范<a name="ZH-CN_TOPIC_0000001096100171"></a> 2 3- [规则:SDK需按算法调用顺序,封装client对外提供接口;对于异步插件对应的SDK,需要实现client提供的回调接口IClientCb](#section15872017171616) 4- [规则:SDK接口实现中,需要保存与client交互的相关通用数据](#section011283741612) 5- [建议:SDK实现client定义的IServiceDeadCb接口](#section1199125331613) 6- [规则:SDK与plugin需要使用编解码模块,将特定算法数据转换成AI引擎的通用数据类型](#section93139389171) 7- [规则:在SDK中,对以编解码返回的出参数据类型,需要进行内存释放,否则会出现内存泄漏](#section1698441814183) 8- [规则:plugin需要实现server定义的IPlugin接口,并使用宏PLUGIN\_INTERFACE\_IMPL对外提供插件函数指针](#section20850717196) 9- [规则:plugin需要使用AI引擎提供的统一数据通道](#section1493821732019) 10 11## 规则:SDK需按算法调用顺序,封装client对外提供接口;对于异步插件对应的SDK,需要实现client提供的回调接口IClientCb<a name="section15872017171616"></a> 12 13AI引擎的client端对外提供的接口包括AieClientInit、AieClientPrepare、AieClientSyncProcess、AieClientAsyncProcess、AieClientRelease、AieClientDestroy、AieClientSetOption、AieClientGetOption,sdk需要根据插件的北向接口按照顺序至少封装AieClientInit、AieClientPrepare、AieClientSyncProcess/AieClientAsyncProcess、AieClientRelease、AieClientDestroy五个接口,否则会出现调用问题或者内存泄漏。比如封装过程遗漏了AieClientprepare接口,则server端无法完成插件加载,故后面的接口都无法调用成功。 14 15对于异步插件,sdk需要实现IClientCb接口,用于接收来自client端的算法推理结果,并将该结果返回给三方调用者。 16 17## 规则:SDK接口实现中,需要保存与client交互的相关通用数据<a name="section011283741612"></a> 18 19AI引擎将的client端采用单例实现,对接多个SDK,因此各SDK需要保存与client交互的通用数据,用于连接server端进行任务推理、结果返回等;需保存数据包含clientInfo、algorithmInfo、configInfo三种数据类型,定义在SDK的成员变量里即可。 20 21## 建议:SDK实现client定义的IServiceDeadCb接口<a name="section1199125331613"></a> 22 23Server端是系统常驻进程,以系统能力的形式为多个client提供服务;client定义的IServiceDeadCb接口,是在server端异常死亡后,会被触发调用。这种异常场景,sdk可在死亡通知接口中,实现相关操作,比如停止调用或者再次拉起server端等。 24 25IServiceDeadCb接口实现示例: 26 27``` 28class ServiceDeadCb : public IServiceDeadCb { 29public: 30ServiceDeadCb() = default; 31~ServiceDeadCb() override = default; 32void OnServiceDead() override 33{ 34printf("[ServiceDeadCb]OnServiceDead Callback happens"); 35} 36}; 37``` 38 39如上示例,SDK可在OnServiceDead\(\)方法中实现自己的操作,比如停止所有的接口调用等等。 40 41## 规则:SDK与plugin需要使用编解码模块,将特定算法数据转换成AI引擎的通用数据类型<a name="section93139389171"></a> 42 43插件的推理数据,会由三方调用者通过client、server传递到插件中;不同的算法所需要的数据类型是不一致的,比如cv的需要图片数据、asr的需要语音数据;为了适配数据类型的差异,AI引擎对外提供了对基本数据类型的编解码能力,将不同数据类型转换为AI引擎可以使用的通用数据类型。 44 45编码后的数据类型定义: 46 47``` 48struct DataInfo { 49unsigned char *data; 50int length; 51} DataInfo; 52 53``` 54 55如上示例,DataInfo数据结构包括指向数据内存的指针和数据长度两个变量组成。 56 57框架接口使用方法: 58 591.添加依赖的头文件:"utils/encdec/include/encdec.h"。 60 612.添加build.gn中的依赖项: 62 63include\_dirs添加"//foundation/ai/engine/services/common"。 64 65deps添加"//foundation/ai/engine/services/common/utils/encdec:encdec" 。 66 673.编解码示例: 68 69``` 70// 编码调用函数示例:arg1,arg2,arg3等为需编码的变量,dataInfo为编码后的结果 71retCode = ProcessEncode(dataInfo, arg1, arg2, arg3) //可以接收任意多个参数 72// 解码调用函数示例:dataInfo为需要解码的信息,arg1,arg2,arg3等为解码后的结果 73retCode = ProcessDecode(dataInfo, arg1, arg2, arg3) //可以接收任意多个参数 74``` 75 76注意: 77 78- 编码和解码调用时的参数顺序需要保证一致。 79- 编码后dataInfo的内存需要调用者手动进行释放。 80- server端和client端的内存是分开管理和释放的。 81- 如果包含共享内存的指针,不需要额外处理。 82- 如果其他类型的指针,则需要解引用后使用ProcessEncode/ ProcessDecode。 83- 该编解码模块未适配class数据类型,不建议使用。 84 85## 规则:在SDK中,对以编解码返回的出参数据类型,需要进行内存释放,否则会出现内存泄漏<a name="section1698441814183"></a> 86 87编码得到的通用数据,本质上是将不同类型数据封装在同一块内存中,然后将这块内存的首地址与长度封装到结构体中。通过编码返回到sdk中的出参数据,在插件中申请了内存,但插件无法释放,否则sdk将无法拿到数据;因此sdk在拿到数据之后,需要对内存进行释放。 88 89内存释放示例: 90 91``` 92DataInfo outputInfo = { 93.data = nullptr, 94.length = 0, 95}; 96AieClientPrepare(clientInfo_, algorithmInfo_, inputInfo, outputInfo, nullptr); 97if (outputInfo.data != nullptr) { 98free(outputInfo.data); 99outputInfo.data = nullptr; 100outputInfo.length = 0; 101} 102``` 103 104## 规则:plugin需要实现server定义的IPlugin接口,并使用宏PLUGIN\_INTERFACE\_IMPL对外提供插件函数指针<a name="section20850717196"></a> 105 106Server端管理的插件内部接口实现逻辑各不相同,为了统一插件的加载流程,AI引擎定义了插件接口IPlugin;在运行态,插件是以动态链接库的形式被AI引擎框架通过dlopen方式加载,各插件需要使用PLUGIN\_INTERFACE\_IMPL语句对外暴露函数指针,否则插件将无法被正常加载使用。 107 108## 规则:plugin需要使用AI引擎提供的统一数据通道<a name="section1493821732019"></a> 109 110AI Engine在server与插件之间,提供了一个统一的数据通道,用来处理来自sdk的推理请求和来自插件的结果返回;plugin在推理接口中,需按数据通道完成请求数据的获取以及推理结果的封装。 111 112数据通道使用示例: 113 114``` 115int SyncProcess(IRequest *request, IResponse *&response) 116{ 117HILOGI("[IvpPlugin]Begin SyncProcess"); 118if (request == nullptr) { 119HILOGE("[IvpPlugin]SyncProcess request is nullptr"); 120return RETCODE_NULL_PARAM; 121} 122DataInfo inputInfo = request->GetMsg(); 123if (inputInfo.data == nullptr) { 124HILOGE("[IvpPlugin]InputInfo data is nullptr"); 125return RETCODE_NULL_PARAM; 126} 127 128... 129 130response = IResponse::Create(request); 131response->SetResult(outputInfo); 132return RETCODE_SUCCESS; 133} 134``` 135 136示例中request和response是数据通道的内容主体,server端会将数据封装在request中,传递到插件,插件进行算法处理之后,则需要将结果封装成response进行返回。 137 138