SparkOS人机交互平台
SparkOS人机交互平台文档导览
SparkOS产品介绍
SparkOS人机交互平台隐私协议
SparkOS人机交互平台用户协议
SparkOS Android SDK接入文档
SparkOS iOS SDK接入文档
SparkOS Harmony NEXT接入文档
本文档使用 MrDoc 发布
-
+
首页
SparkOS Android SDK接入文档
# SparkOS Android SDK接入文档 ## 1. 兼容性说明 |类别|兼容范围| |---|---| |系统|SDK支持Android 5.0(SDK API Level 21)及以上系统版本,SDK目前只支持armeabi-v7a和arm64-v8a架构| |开发语言|JAVA| ## 2. 准备工作 ### 2.1 平台配置 在集成开发SDK前,需要开发者在AIUI交互平台上创建应用及申请授权,设置好相关的配置(如个性化数据、技能、情景以及自然语言理解,即语义是使用交互大模型还是AIUI),并获取AIUI交互协议文档。 ### 2.2 授权申请 接入SDK前,请先联系项目侧开通使用交互大模型需要用到的各种云端授权,防止出现运行时的授权报错。 除云端功能授权外,若需使用多模交互、音频编解码等功能,需额外开通客户端侧的离线能力授权,可联系SDK技术支持人工协助。 ### 2.3 功能介绍 SDK内部包含多个独立子能力,通过编排协议按业务流程编排形成AIUI交互流程,预置子能力如下: |子能力|说明| |---|---| |录音器、播放器|用于音频采集和播放| |视频录像|用于采集视频/图片| |VAD/IAT/NLP/TTS|在线AIUI能力,进行人声检测/语音识别/语义理解/合成| |AudioCodec|音频编解码,用于采集音频编码、服务下发音频解码(需开通授权)| |ImageConvert|图片编码,用于采集的视频/图片编码(需开通授权)| |虚拟形象|AI虚拟人技术,将合成结果通过虚拟形象播报(需开通授权)| ## 3. SDK组成 SDK zip包解压后文件结构: ```Plain Text ├── SparkOS Android SDK接入文档.pdf // AIUI SDK能力集成指南 ├── 使用Demo // 集成前通过Demo了解调用原理 ├── ReleaseNote.txt // SDK版本日志 ├── AIKit.aar // 核心框架依赖 └── xrtcsdk-{version}.aar // 虚拟人视频拉流依赖组件 ``` ## 4. SDK工程配置 ### 4.1 导入SDK库 在项目build.gradle中引入: ```Plain Text implementation files('libs/AIKit.aar') // 虚拟人依赖 implementation files('libs/xrtcsdk-{version}.aar') implementation 'com.squareup.okhttp3:okhttp:3.10.0' ``` ### 4.2 配置权限 在AndroidManifest.xml中申请相关权限: ```XML <uses-permission android:name="android.permission.INTERNET" /> <!-- 工作目录设置在外部存储时需要该权限 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.CAMERA" /> <!-- 可选权限:用于会话中自动获取位置信息 <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> --> ``` SDK已配置可选权限,无需时可移除: ```XML <!-- 可选权限:获取设备IMEI用于精准授权,IMEI加密存储,不存明文 --> <uses-permission android:name="android.permission.READ_PHONE_STATE" tools:node="remove" /> ``` ## 5. 接口调用流程 ### 5.1 初始化 使用AIUI能力前,需获取授权应用信息(appId、apiKey、apiSecret),联系项目经理获取;SDK仅需初始化一次。 #### 初始化示例代码 ```Java final String TAG = "AIUIDemo"; // 设置鉴权回调 AuthListener authListener = (type, code) -> { initCode = code; Log.d(TAG, "onAuthStateChange, code is " + code); if (code == 0) { // code == 0 鉴权通过,鉴权通过后可以开始start会话 } }; // 设置能力响应回调,并注册到SDK(可选) private class ResponseListener implements AiResponseListener { @Override public void onResult(String ability, int handleID, List<AiResponse> responseData, Object usrContext) {} @Override public void onEvent(String ability, int handleID, int event, List<AiResponse> eventData, Object usrContext) {} @Override public void onError(String ability, int handleID, int err, String msg, Object usrContext) {} } AppHelper.getInst().registerListener(new ResponseListener()); //授权类型 BaseLibrary.AuthType authType = BaseLibrary.AuthType.DEVICE; // 设备授权 authType = BaseLibrary.AuthType.APP; //应用授权 // 设置SDK初始化参数并初始化 final AiHelper.Params params = AiHelper.Params.builder() .appId(您的APP_ID) .apiKey(您的APP_KEY) .apiSecret(您的APP_SECRET) .workDir("/sdcard/iflytek/AIUI") //SDK运行目录,需要有写权限 .authType(authType) .build(); //初始化 AppHelper.getInst().init(context.getApplicationContext(), params, authListener); ``` #### 初始化参数说明 |参数|类型|是否必填|说明| |---|---|---|---| |appID|String|是|AIUI交互平台创建应用后生成的应用ID| |apiKey|String|是|AIUI交互平台创建应用后生成的唯一应用标识| |apiSecret|String|是|AIUI交互平台创建应用后生成的唯一应用秘钥| |workDir|String|是|SDK工作目录,可自行指定,需确保有访问权限| |authType|int|否|端能力授权方式,0=设备级授权,1=应用级授权| #### 初始化返回值 0:初始化成功;非0:初始化失败,参考错误码章节查询原因。 #### 回调接口说明 - onResult:AIUI处理结果回调,通过key区分结果类型 - onEvent:会话事件信息回调 - onError:会话错误信息回调 #### AiResponse结构说明 |变量名|类型|是否必填|说明| |---|---|---|---| |key|String|是|输出数据名称| |type|enum|否|输出数据类型,0=音频;1=文本;2=图片;3=视频;4=个性化数据| |value|byte[]|否|字节数组类型输出数据| |varType|enum|否|输出数据变量类型,0=STRING;1=INT;2=DOUBLE;3=BOOL| |len|int|否|输出数据长度| #### AiResponse常见key取值 |key取值|含义|说明| |---|---|---| |iat|识别结果数据|唤醒后用户指令的语音识别结果| |nlp|语义数据|AIUI根据识别结果返回的语义数据| |tts|未解码的合成音频数据|云端合成的原始音频数据| |audio|解码后的合成音频数据|解码完成的合成音频数据| #### onEvent事件码 - 21=网络连接响应超时 - 22=网络连接实例已销毁 - 23=网络连接已经被抛弃 - 24=发送队列拥塞 - 30=VAD开始 - 31=VAD结束 - 32=VAD未检测到人声 ### 5.2 请求调用 #### 5.2.1 场景切换 通过AppHelper.start启动交互会话,AppHelper.stop结束会话,支持5大类场景: ```Java public enum AppMode { AUDIO_TO_AUDIO, // 语音输入,语音输出 AUDIO_TO_VIDEO, // 语音输入,视频输出(虚拟人) VIDEO_TO_AUDIO, // 视频输入,语音输出(多模) VIDEO_TO_VIDEO, // 视频输入,视频输出(虚拟人+多模) AUDIO_TO_AUDIO_RTC, // RTC语音交互 AUDIO_TO_VIDEO_RTC, // 后续版本添加 VIDEO_TO_AUDIO_RTC, // 后续版本添加 VIDEO_TO_VIDEO_RTC; // 后续版本添加 } /** * 启动会话 * @param mode 应用模式 * @param appParams 会话参数 * @return 错误码,0为成功 */ int start(AppMode mode, AppParams appParams); /** * 停止会话 * @return 错误码,0为成功 */ int stop(); ``` #### 5.2.2 参数配置 会话参数通过AppParams构建,常用参数:发音人、虚拟人形象、设备唯一码、云端识别场景、多模显示控件等。 ```Java public class AppParams { public static Builder builder() public static class Builder{ AppParams.Builder isDuplex(boolean isDuplex); AppParams.Builder vcn(String vcn); AppParams.Builder avatarId(String avatarId); AppParams.Builder avatarSize(int width, int height); AppParams.Builder eos(int eosDelay); AppParams.Builder uid(String uid); AppParams.Builder scene(String scene); AppParams.Builder cameraView(TextureView cameraView); AppParams.Builder imageSrcFormat(String srcFormat); AppParams.Builder imageDetectBlurry(boolean detectBlurry); AppParams.Builder imageSaveResult(boolean imageSaveResult); AppParams.Builder imageSaveResultPath(String saveResultPath); AppParams build(); } } ``` #### start传参完整示例 ```Java //构建AIUI参数 AppParams.Builder paramBuilder = AppParams.builder(); paramBuilder.uid("39769795890") //用户唯一标识 .scene("main") //网页后台配置的场景 .eos(eos_delay) //后端点 .prompt(prompt) //自定义prompt .vcn(vcn); //发音人 //虚拟人参数 paramBuilder.avatarSize(512, 512) //虚拟人尺寸 .avatarId(avatar_id); //虚拟人形象ID //图片理解参数(开启视频输入有效) paramBuilder.imageSrcFormat("raw_yuv420_888"); //原始图片格式 默认raw_yuv420_888 paramBuilder.imageDetectBlurry(true); //是否开启模糊检测 默认开启 paramBuilder.imageSaveResult(false); //是否保存转码后图片到本地(调试用) paramBuilder.imageSaveResultPath(Constants.imageSavePath); //保存路径 //如果使用默认DeviceVideoInput需要传入TextureView cameraView = findViewById(R.id.textureView); paramBuilder.cameraView(cameraView); // true全双工(默认) false半双工 paramBuilder.isDuplex(true); //应用模式 AppMode mode = AppMode.VIDEO_TO_VIDEO; //语音+虚拟人+图片理解 int ret = AppHelper.getInst().start(mode, paramBuilder.build()); ``` #### 5.2.3 自定义IO 可自行实现音频/视频输入输出接口,通过AppHelper.registerIODevice注册,需在start前调用。 ##### 核心IO接口 ```Java public interface IDeviceIO { void init(Context context); void release(); } public interface IDeviceVideoInput extends IDeviceIO { void on(IWriterWH writer); void off(); void switchTo(VideoDataSource vds); } public interface IWriterWH { void write(byte[] data, int width, int height); } public enum VideoDataSource { DEFAULT_CAMERA, FRONT_CAMERA, REAR_CAMERA; } public interface IDeviceVideoOutput extends IDeviceOutput { void on(); void ready(); void pause(); void resume(); void off(); void data(byte[] data); ViewGroup container(); VideoParams params(); } public interface IDeviceAudioOutput extends IDeviceOutput { void on(); void pause(); void resume(); void off(); void data(byte[] data); boolean isPlaying(); } public interface IDeviceAudioInput extends IDeviceIO { void on(IWriter writer); void off(); } ``` ##### 注册自定义IO示例 - 注册播放器设备 ```Java AppHelper.getInst().registerIODevice(new IDeviceAudioOutput() { @Override public void on() { PcmStreamPlayer.getInst().start(); } @Override public void pause() {} @Override public void resume() {} @Override public void off() { PcmStreamPlayer.getInst().stop(); } @Override public void data(byte[] bytes) { PcmStreamPlayer.getInst().fitBluetooth(); PcmStreamPlayer.getInst().write(bytes); } @Override public boolean isPlaying() { boolean isPlaying = false; try { isPlaying = PcmStreamPlayer.getInst().isPlaying(); } catch (IOException e) { e.printStackTrace(); } return isPlaying; } @Override public void init(Context context) { PcmStreamPlayer.getInst().init(context, null); } @Override public void release() { PcmStreamPlayer.getInst().release(); } }); ``` - 注册录音器设备 ```Java AppHelper.getInst().registerIODevice(new IDeviceAudioInput() { private WeakReference<Context> mContext = null; private WeakReference<IWriter> mWriter = null; private final RecorderListener recorderListener = new RecorderListener(){ @Override public void onBuffer(byte[] bytes, int i, int i1) { IWriter writer = mWriter.get(); if (writer != null) { writer.write(bytes); } } @Override public void onError(SpeechError speechError) {} @Override public void onStart(boolean success) {} @Override public void onRelease() {} @Override public void onDecibel(int i) {} }; @Override public void init(Context context) { mContext = new WeakReference<>(context); } @Override public void release() { RecorderHelper.getInst().stop(); mContext.clear(); } @Override public void on(final IWriter writer) { Context context = mContext.get(); if (context != null) { AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); if (audioManager != null) { audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION); audioManager.setSpeakerphoneOn(true); } this.mWriter = new WeakReference<>(writer); RecorderHelper.Params params = RecorderHelper.Params.builder() .source(MediaRecorder.AudioSource.VOICE_COMMUNICATION) .sampleRates(AppConstants.RECORDER_SAMPLE_RATES) .channel(AppConstants.RECORDER_CHANNEL) .format(AudioFormat.ENCODING_PCM_16BIT) .frameSize(AppConstants.FRAME_SIZE) .build(); RecorderHelper.getInst().init(params, recorderListener); } } @Override public void off() { RecorderHelper.getInst().stop(); } }); ``` - 注册相机设备 ```Java void registerCamera(TextureView cameraView){ IDeviceVideoInput iDeviceVideoInput = new IDeviceVideoInput() { @Override public void init(Context context) { CameraHelper.getInst().init(context, cameraView, null); } @Override public void release() { CameraHelper.getInst().release(); } @Override public void on(final IWriterWH iVideoWriter) { if (cameraView == null) { Log.e(getClass().getName(), "CameraView not set"); return; } CameraHelper.getInst().setListener(new CameraHelper.CameraHelperListener() { @Override public void onImageAvailable(byte[] bytes, int width, int height) { iVideoWriter.write(bytes, width, height); } @Override public void onCameraOpened(int width, int height) { CameraHelper.getInst().openCamera(false); } }); } @Override public void off() { if (cameraView == null) { Log.e(getClass().getName(), "CameraView not set"); return; } CameraHelper.getInst().setListener(null); CameraHelper.getInst().closeCamera(); } @Override public void switchTo(VideoDataSource vds) { CameraHelper.getInst().switchCamera(); } }; AppHelper.getInst().registerIODevice(iDeviceVideoInput); } ``` - 注册视频输出设备 ```Java AIUIHelper.getInst().registerVideoOutput(new IDeviceVideoOutput() { @Override public void on() {} @Override public void ready() { hideProgressDialog(); } @Override public void pause() {} @Override public void resume() {} @Override public void off() {} @Override public void data(byte[] bytes) {} @Override public ViewGroup container() { ViewGroup virtualContainer = findViewById(R.id.ll_vms); return virtualContainer; } @Override public VideoParams params() { VideoParams videoParams = VideoParams.builder() .fillMode(VideoFillMode.VIDEO_RENDER_MODE_FIT) .rotation(VideoRotation.VIDEO_ROTATION_0) .mirror(VideoMirrorType.VIDEO_MIRROR_TYPE_DISABLE) .stream(VideoStreamType.VIDEO_STREAM_TYPE_BIG) .volume(VolumeType.SystemVolumeTypeVOIP) .shape(VideoShape.VIDEO_SHAPE_ROUNDED) .build(); return videoParams; } @Override public void init(Context context) {} @Override public void release() {} }); ``` #### 5.2.4 交互协议 [https://yf2ljykclb.xfchat.iflytek.com/sync/Y98Ddchq6sGOfVbftySr8TuMzpb](https://yf2ljykclb.xfchat.iflytek.com/sync/Y98Ddchq6sGOfVbftySr8TuMzpb) ### 5.3 逆初始化 不再使用能力时,释放资源: ```Java AppHelper.getInst().release(); ``` ## 6. 高级功能 ### 6.1 SDK初始化高级配置 |参数名|类型|说明|是否必填| |---|---|---|---| |authInterval|int|在线授权校验间隔时长,默认300s,最短60s,单位秒|否| |authType|int|端能力授权方式,0=设备级授权,1=应用级授权|否| |iLogMaxCount|int|本地日志最大存储个数【1,300】,默认70|否| |iLogMaxSize|int|单日志文件大小(1024,10485760】,默认1024,单位字节|否| |cfgPath|String|配置文件路径,需使用配置文件时传入|否| ### 6.2 动态配置访问url ```Java AiHelper.getInst().setConfig("HostUrl", "{\"aiui_spark\":\"ws://sos-gray.cn-huabei-1.xf-yun.com/v3/sos\",\"aiui_image\":\"ws://sos-gray.cn-huabei-1.xf-yun.com/v3/sos-image\"}"); ``` ### 6.3 下发服务侧sid结果 开启后结果会携带header数据,包含sid: ```Java AiHelper.getInst().setConfig("ResultFormat", "{\"aiui_spark\":1}"); ``` header数据格式: ```JSON { "code": 0, "message": "success", "cid": "cidxxxxxxxxxxxxxxxxx", "sid": "xxx@xxxxxxxxxxxxxxxx" } ``` ### 6.4 获取会话结束标识 通过key+status判断会话状态: |key|status含义|获取方式| |---|---|---| |iat|识别结果状态,0=第一帧,1=中间,2=最后一帧|onResult中key=iat时取status| |nlp|语义结果状态,0=第一帧,1=中间,2=最后一帧|onResult中key=nlp时取status| |tts|合成音频状态,0=第一帧,1=中间,2=最后一帧|onResult中key=tts时取status| |header|会话整体状态,0=第一帧,1=中间,2=最后一帧|解析header的status字段| ### 6.5 日志配置 ```Java /** * 设置日志级别、模式、保存路径 * @param level 日志级别 * @param mode 输出模式 0:LOG_STDOUT 1:LOG_LOGCAT 2:LOG_FILE * @param path 输出为文件时的路径+文件名 * @return */ public int setLogInfo(LogLvl level, int mode, String path) AiHelper.getInst().setLogInfo(LogLvl.VERBOSE, 1, WORKDIR + "/aikit.log"); ``` #### 日志参数说明 |参数|类型|说明|是否必填| |---|---|---|---| |level|LogLvl|日志等级:VERBOSE/DEBUG/WARN/INFO/ERROR/FATAL|是| |mode|int|输出模式:0=标准输出,1=Logcat,2=文件|是| |path|String|文件输出时的路径(含文件名)|否| ## 7. 错误码 ### 7.1 SDK错误码 参见AIKit错误码描述 ### 7.2 云端错误码 参见云端错误码查询
aiuiadmin
2026年3月24日 14:43
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
分享
链接
类型
密码
更新密码