Android SDK 接入指南(v0.0.7)
一.准备工作
概述
本文是 XingyunAvatarAgent SDK Android 版本的接入文档,用于指导 SDK 的使用方法,默认读者已经熟悉 Android Studio 的基本使用方法,以及具有一定的 Android 编程知识基础。
XingyunAvatarAgent SDK 在具身智能体渲染能力(虚拟人 Lite SDK)的基础上,集成了 E2E 语音对话能力(麦克风采集 → ASR 识别 → LLM 大模型 → 具身智能体自动播报),对外提供统一入口类 XingyunAvatarAgent,一次初始化即可同时获得:
- 具身智能体渲染 + 播报(内部封装 XmovAvatar 全部能力)
- 语音对话(ASR 实时识别、LLM 流式回答并自动驱动具身智能体播报)
- 文本对话(ask 文本提问,LLM 流式回答并自动驱动具身智能体播报)
内部联动逻辑(无需接入方处理):
- ASR 识别到完整一句话(isFinal=true)→ 具身智能体自动进入 think 状态
- LLM 流式分片输出 → 自动流式驱动具身智能体 speak 播报
- interrupt() → 同时打断具身智能体播报与 E2E 会话
快速体验 demo
工程中的 app 模块即示例工程,使用 Android Studio 打开后:
a. 修改 app/src/main/assets/agent_config.json 中的 asrConfig、ttsConfig、brainConfig、features、avatarAppId、avatarAppSecret、avatarGatewayServer 等参数(asrConfig / ttsConfig / brainConfig / features 的值是 JSON 字符串,转义后填入;ttsConfig 默认为空)
b. 直接运行到 Android 手机上体验
开发环境搭建
(1)将开发包拷贝到工程
将 SDK 的 aar 包拷贝到自己工程的 libs 目录下,如没有该目录需新建。
在 app 文件夹下的 build.gradle 的 dependencies 中配置对应版本的 aar 依赖:
implementation files('libs/xingyun_avatar_agent-xxx.aar')
(2)添加外部第三方依赖:
implementation "com.squareup.okhttp3:okhttp:4.12.0"
implementation "com.google.code.gson:gson:2.13.1"
// Opus 音频编码(语音采集上行)
implementation "io.github.jaredmdobson:concentus:1.0.2"
implementation "javax.vecmath:vecmath:1.5.2"
implementation "org.msgpack:msgpack-core:0.9.3"
implementation "io.socket:socket.io-client:2.1.0"
// Protobuf 依赖
implementation "com.google.protobuf:protobuf-javalite:3.21.12"
// ExoPlayer dependency for WebM/Opus streaming
implementation "androidx.media3:media3-exoplayer:1.9.0"
(3)配置 AndroidManifest.xml 文件
在 manifest 标签内添加必要的权限支持:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
注意:
RECORD_AUDIO属于危险权限,调用startASR()之前必须先完成运行时权限申请,否则音频采集会失败并通过onError(domain="audio")回调。
(4)混淆规则:
-keep class com.xmov.xingyunavataragent.XingyunAvatarAgent { public *; }
-keep interface com.xmov.xingyunavataragent.XingyunAvatarAgentListener { *; }
-keep class com.xmov.xingyunavataragent.XingyunAvatarAgentConfig { public *; }
-keep class com.xmov.xingyunavataragent.XingyunAvatarAgentError { public *; }
-keep class com.xmov.xingyunavataragent.LlmUsage { public *; }
-keep class com.xmov.xingyunavataragent.SemanticJudgeResult { public *; }
-keep enum com.xmov.xingyunavataragent.XingyunAvatarAgentState { *; }
-keep public class com.xmov.metahuman.sdk.data.**{*;}
-keep public class com.xmov.metahuman.sdk.impl.data.**{*;}
-keep public class com.xmov.metahuman.sdk.impl.transport.http.**{*;}
-keep public interface com.xmov.metahuman.sdk.PreCacheListener {
public protected *;
}
-dontwarn io.github.jaredmdobson.concentus.OpusApplication
-dontwarn io.github.jaredmdobson.concentus.OpusEncoder
-dontwarn io.github.jaredmdobson.concentus.OpusSignal
-dontwarn io.github.jaredmdobson.concentus.OpusDecoder
通过上面的几个步骤,工程就配置完成了,接下来就可以在工程中使用 XingyunAvatarAgent SDK 进行开发了。
二.SDK 使用说明
1.预缓存
预缓存是提前缓存视频资源或者 charbin 文件资源,可按需调用,不是必须调用的;调用时机在初始化方法之前调用。
(1)预缓存视频
文件较多,需要几分钟时间,大屏常驻设备可提前调用缓存,按需调用。
方法原型
fun preCache(
context: Context,
appId: String,
appSecret: String,
url: String,
listener: PreCacheListener?
)
(2)预缓存 charbin
时间较快,可提前调用,缩短初始化耗时。
fun preCacheCharBin(
context: Context,
appId: String,
appSecret: String,
url: String,
listener: PreCacheListener?
)
参数描述
参数 | 类型 | 说明 |
context | Context | 一般传 Activity 或者 applicationContext 对象 |
appId | String | 星云开放平台上创建对应应用角色的 appId |
appSecret | String | 星云开放平台上创建对应应用角色的 appSecret |
url | String | 预缓存资源地址 |
listener | PreCacheListener | 回调监听 |
示例代码
val agent = XingyunAvatarAgent()
agent.preCache(this, appId, appSecret, preCacheUrl, object : PreCacheListener {
override fun onPreCacheProgress(progress: Int) {
runOnUiThread { setLoadingTitle("预缓存中 $progress%") }
}
override fun onPreCacheComplete() {
runOnUiThread { toast("预缓存完成") }
}
override fun onPreCacheFailed(errorCode: Int, errorMessage: String) {
runOnUiThread { toast("预缓存失败: $errorCode $errorMessage") }
}
})
1.进度回调 onPreCacheProgress(progress: Int),progress 范围是 0-100,缓存的进度
2.完成回调 onPreCacheComplete(),缓存完成
3.失败回调 onPreCacheFailed(errorCode: Int, errorMessage: String)
2.初始化
使用 SDK 功能前,必须先进行初始化操作。初始化会同时完成:
- 具身智能体渲染管线初始化(进房、加载资源、渲染首帧)
- 具身智能体就绪后自动建立 E2E 语音对话连接
E2E 连接建立成功后回调 onStateChanged(CONNECTED),此后即可调用 startASR / ask 等对话接口。
方法原型
fun init(
context: Context,
layout: ViewGroup,
config: XingyunAvatarAgentConfig,
listener: XingyunAvatarAgentListener
)
参数描述
参数 | 类型 | 说明 |
context | Context | 一般传 Activity 对象 |
layout | ViewGroup | 加载具身智能体所在的父布局 |
config | XingyunAvatarAgentConfig | 统一配置类(包含 E2E + 具身智能体参数) |
listener | XingyunAvatarAgentListener | 统一回调监听 |
XingyunAvatarAgentConfig 类介绍
主配置类
参数 | 类型 | 必填 | 说明 |
asrConfig | String? | 否 | ASR 配置 JSON 字符串(原样透传到服务端 asr_config),默认 null |
ttsConfig | String? | 否 | TTS 配置 JSON 字符串(原样透传到服务端 tts_config),默认 null,由服务端取默认 TTS 配置 |
brainConfig | String? | 否 | Brain/LLM 配置 JSON 字符串(原样透传到服务端 brain_config),默认 null |
features | String? | 否 | 特性开关配置 JSON 字符串(原样透传到服务端 features),默认 null |
sessionSpeakReqId | Int | 否 | 说话请求计数器,默认 1 |
avatarAppId | String | 是 | 星云具身中应用对应的 appId |
avatarAppSecret | String | 是 | 星云具身中应用对应的 appSecret |
avatarGatewayServer | String | 是 | 进入房间的地址,如 "https://nebula-agent.xingyun3d.com/user/v1/ttsa_v2/session" |
avatarInitConfigJson | String | 否 | 具身智能体初始化 JSON 配置,默认 "{}"(字段含义与虚拟人 Lite SDK 的 config 完全一致,详见 Lite SDK 接入文档"config 配置"章节) |
audioInputInitiallyOff | Boolean | 否 | 连接建立后音频输入是否保持关闭,默认 true |
debugLogEnabled | Boolean | 否 | SDK 内部调试日志开关,默认 false |
extras | String? | 否 | 预留扩展 JSON 字符串,原样透传到 startSession 请求体中(与 asr_config / features 同级) |
注意:
asrConfig/ttsConfig/brainConfig/features/extras均为 JSON 字符串,SDK 只原样透传,不解析、不校验。字段名采用下划线命名(如base_url、enable_aec),具体格式见下方"配置 JSON 示例"。已废弃:
host、userToken、sessionId三个字段已不再使用。E2E 会话的 token 和 ws_url 现在由具身智能体startSession接口在响应的data.e2e_resp中直接返回,SDK 内部自动提取,无需接入方单独配置。
配置 JSON 示例(asrConfig / brainConfig / features 的值格式)
{
"asr_config": {
"provider": "doubao",
"base_url": "wss://openspeech.bytedance.com/api/v3/sauc/bigmodel_async",
"api_key": "your-api-key",
"model": "bigmodel",
"headers": {
"access_token": "your-access-token",
"app_id": "your-app-id",
"resource_id": "volc.bigasr.sauc.duration",
"secret_key": "your-secret-key"
},
"request": {
"model_name": "bigmodel",
"model_version": "400",
"result_type": "full",
"enable_itn": true,
"enable_punc": true,
"show_utterances": true
}
},
"brain_config": {
"provider": "doubao",
"base_url": "https://ark.cn-beijing.volces.com/api/v3",
"api_key": "your-api-key",
"model": "your-model-id",
"preset": "你是一个简洁的助手。",
"history_length": 5
},
"features": {
"anti_interference": {
"semantic_judge_enabled": false
},
"speech_frontend": {
"enabled": true,
"enable_aec": true,
"enable_speech_separation": true
},
"vad_merge_mode": true,
"volume_and_repetition_text_detection": true
}
}
asrConfig 字段说明(原样透传到服务端 asr_config)
字段 | 类型 | 必填 | 说明 |
provider | string | 是 | ASR 服务商,支持 |
base_url | string | 是 | ASR WebSocket 地址 |
headers | object | 是 | ASR 鉴权字段:doubao 为 |
request | object | 否 | ASR 请求参数(如 |
brainConfig 字段说明(原样透传到服务端 brain_config)
字段 | 类型 | 必填 | 说明 |
provider | string | 是 | LLM 服务商,支持 |
base_url | string | 是 | LLM API 地址 |
api_key | string | 是 | LLM API key;缺失、为空或仅含空白字符时服务端返回 HTTP 400 |
model | string | 是 | 模型名称 / 模型 ID |
preset | string | 否 | 系统提示词;可省略或传空字符串,为空时不生成 system message |
history_length | int | 否 | 历史轮数,默认 5 |
extra_body | object | 否 | 直连模型 provider 的原生请求扩展参数,默认 |
注意:普通 Brain 由服务端按
history_length维护并发送历史;youling / coze / dify 使用各自服务端会话(E2EMPServer 不重发本地历史),系统提示词由对应平台配置管理。
features 字段说明(原样透传到服务端 features)
字段 | 类型 | 必填 | 说明 |
vad_merge_mode | bool | 否 | VAD 合并模式,默认 true |
volume_and_repetition_text_detection | bool | 否 | 音量与重复文本检测总开关,默认 true |
anti_interference.semantic_judge_enabled | bool | 否 | 语义判定开关,默认 false |
speech_frontend.enabled | bool | 否 | SF 降噪桥接开关,默认 false |
speech_frontend.enable_aec | bool | 否 | 回声消除与降噪统一开关,连接前确定,默认 false |
speech_frontend.enable_speech_separation | bool | 否 | 人声分离开关 |
auto_send_asr_to_llm | bool | 否 | 远端发送 ASR 结果给大模型,默认 true |
注意:
features为可选、可部分提供的对象,服务端按「代码默认值 → 服务端数据库dict_config→ 本次请求features」递归合并:显式传入的false/0会覆盖数据库值,省略的字段不覆盖,具体默认是否开启以服务端配置为准。speech_frontend下还支持ws_url、fixed_chunk_enabled、chunk_samples、sample_rate、ws_max_size等服务端参数;anti_interference下还支持音量阈值、重复文本相似度、次数、位置、时间窗口、相似度算法等参数(字段名以服务端数据库dict_config配置为准)。
实际接入时把对应片段转成 JSON 字符串填入 asrConfig / brainConfig / features 参数(可直接参考 demo 的 app/src/main/assets/agent_config.json)。
初始化示例代码
val agent = XingyunAvatarAgent()
agent.init(
this,
mBinding.avatarLayout,
XingyunAvatarAgentConfig(
// 以下均为 JSON 字符串,原样透传给服务端(格式参考上方"配置 JSON 示例")
asrConfig = """{"provider":"doubao","base_url":"wss://openspeech.bytedance.com/api/v3/sauc/bigmodel_async","headers":{"access_token":"your-access-token","app_id":"your-app-id","resource_id":"volc.bigasr.sauc.duration","secret_key":"your-secret-key"},"request":{"model_name":"bigmodel","model_version":"400","result_type":"full","enable_itn":true,"enable_punc":true,"show_utterances":true}}""",
brainConfig = """{"provider":"doubao","base_url":"https://ark.cn-beijing.volces.com/api/v3","api_key":"your-api-key","model":"your-model-id","preset":"你是一个简洁的助手。","history_length":5}""",
features = """{"anti_interference":{"semantic_judge_enabled":false},"speech_frontend":{"enabled":true,"enable_aec":true,"enable_speech_separation":true},"vad_merge_mode":true,"volume_and_repetition_text_detection":true}""",
avatarAppId = "your-app-id",
avatarAppSecret = "your-app-secret",
avatarGatewayServer = "https://nebula-agent.xingyun3d.com/user/v1/ttsa/session",
debugLogEnabled = true,
),
object : XingyunAvatarAgentListener {
// ===== E2E 语音对话回调 =====
override fun onStateChanged(state: XingyunAvatarAgentState) {
Log.d(TAG, "state -> $state")
// state == CONNECTED 后即可调用 startASR() / ask()
}
override fun onAsrResult(text: String, isFinal: Boolean) {
// 实时识别字幕;isFinal=true 表示一句话识别结束
tvSubtitle.text = "我:$text"
}
override fun onLlmChunk(text: String, isFirst: Boolean) {
// LLM 流式回答分片;isFirst=true 表示本轮回答的首个分片
// 具身智能体播报由 SDK 内部自动驱动,此处只需处理字幕展示
if (isFirst) llmSubtitle.clear()
llmSubtitle.append(text)
tvSubtitle.text = llmSubtitle.toString()
}
override fun onLlmDone(usage: LlmUsage) {
Log.d(TAG, "LLM done: $usage")
}
override fun onError(error: XingyunAvatarAgentError) {
Log.e(TAG, "ERROR: $error")
}
// ===== 具身智能体回调(均有默认空实现,按需重写) =====
override fun onInitEvent(code: Int, message: String?) {
Log.d(TAG, "avatar init: code=$code $message") // code=4000 成功
}
override fun onAvatarStateChange(state: String) {
Log.d(TAG, "avatar state: $state")
}
override fun onSpeakStateChange(speakState: String, clientSpeakId: String, errorMsg: String) {
Log.d(TAG, "speak: $speakState $errorMsg")
}
override fun onAvatarReconnectEvent(code: Int, message: String?) {
Log.d(TAG, "avatar reconnect: code=$code $message")
}
override fun onOfflineEvent() {
Log.d(TAG, "avatar offline")
}
override fun onSDKRuntimeError(code: Int, message: String?) {
Log.e(TAG, "avatar runtime error: code=$code $message")
}
},
)
回调线程说明:除
onAudioData外,XingyunAvatarAgentListener的其余回调统一在主线程执行,可直接操作 UI。onAudioData在 SDK 专用后台线程回调(高频音频大包,避免阻塞主线程),如需更新 UI 请自行runOnUiThread;回调积压超过阈值时 SDK 会丢弃中间帧只保最新。
3.语音对话(ASR)
3.1 开始语音识别
打开麦克风采集并开始 ASR 实时识别。识别文本通过 onAsrResult 回调;一句话识别结束(isFinal=true)后自动送入 LLM,回答通过 onLlmChunk 流式回调并自动驱动具身智能体播报。
调用前提:状态已为 CONNECTED,且已授予 RECORD_AUDIO 权限。
方法原型
fun startASR()
示例代码
if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)
!= PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(
this, arrayOf(Manifest.permission.RECORD_AUDIO), REQUEST_RECORD_AUDIO,
)
return
}
agent.startASR() // 成功后 onStateChanged(LISTENING)
3.2 停止语音识别
关闭麦克风采集,停止 ASR 识别。
方法原型
fun stopASR()
示例代码
agent.stopASR() // 成功后 onStateChanged(CONNECTED)
注意:
stopASR()为异步收尾——SDK 会在后台完成采集/编码/发送的收尾(通常几十毫秒,积压时可能几百毫秒),收尾完成后才回调onStateChanged(CONNECTED);收尾期间再次调用startASR()会被忽略,请等待回到CONNECTED后再操作。
4.文本对话(ask)
文本提问,走 LLM 大模型,回答通过 onLlmChunk 流式回调并自动驱动具身智能体播报。
调用前提:状态为 CONNECTED 或 LISTENING。
方法原型
fun ask(text: String)
参数说明
参数 | 参数类型 | 说明 |
text(必填) | String | 提问文本 |
示例代码
agent.ask("今天天气怎么样?")
5.Speak(直接驱动具身智能体播报)
不经过 LLM,直接让具身智能体播报指定文本(同时会将播报文本同步给 E2E 会话)。
SDK 提供两个重载版本:
(1)简化版本(推荐用于纯文本播报)
fun speak(text: String, isStart: Boolean, isEnd: Boolean)
参数 | 参数类型 | 说明 |
text(必填) | String | 说话内容文本 |
isStart(必填) | Boolean | 是否开始节点 |
isEnd(必填) | Boolean | 是否输入结束 |
示例:
agent.speak("你好,我是具身智能体。", isStart = true, isEnd = true)
(2)完整版本(支持 SSML / ka 动作 / 流式播报 / 缓存控制 / 自定义 speakId)
fun speak(
ssml: String?,
isStart: Boolean,
isEnd: Boolean,
enableSpeechCache: Boolean? = null,
clientSpeakId: String? = null
)
流式文本输入示例:
// 开头
agent.speak("msg 1", isStart = true, isEnd = false)
agent.speak("msg 2", isStart = false, isEnd = false)
// ...
// 结尾
agent.speak("msg n", isStart = false, isEnd = true)
注意:LLM 回答的播报由 SDK 内部自动完成流式 speak 驱动,接入方不要在
onLlmChunk中再次调用 speak,否则会重复播报。
6.打断
同时打断具身智能体当前播报与 E2E 会话中正在进行的回答。
方法原型
fun interrupt()
示例代码
agent.interrupt()
7.具身智能体状态切换
具身智能体常用的动作状态切换(ASR/LLM 流程中 think、speak 状态由 SDK 自动驱动,一般无需手动调用)。
agent.listen() // 倾听
agent.think() // 思考
agent.idle() // 待机
agent.interactiveidle() // 交互待机
8.断线重连
SDK 具备两层重连机制,自动处理网络波动场景:
8.1 具身智能体(SocketIO)重连
网络波动或断网时,具身智能体自动进入离线状态,有网络时自动重连。重连事件通过 onAvatarReconnectEvent 回调(code=4000 成功,其他为错误码)。
也支持手动切换:
agent.switchModel(true) // 手动切换到离线模式
agent.switchModel(false) // 手动重连(仅离线状态下有效)
8.2 E2E WebSocket 重连
E2E 语音会话的 WebSocket 连接异常断开时(非正常关闭 code≠1000),SDK 会自动发起重连:
- 重连策略:指数退避,初始 1s,每次翻倍,最大 16s,最多重试 5 次
- 状态回调:重连期间状态依次为
DISCONNECTED → CONNECTING → CONNECTED - 错误通知:每次断线回调
onError(domain="ws"),重连 5 次耗尽后回调onError(domain="ws", message="reconnect exhausted after 5 attempts")
8.3 两层联动
具身智能体重连时 E2E 自动同步:
- 具身智能体断线 → E2E 自动断开,等待具身智能体重连
- 具身智能体重连成功 → E2E 用新的会话凭证自动建立连接(状态:
IDLE → CONNECTING → CONNECTED) - E2E 独立断线时,使用已有凭证自行重试,不触发具身智能体重连
9.生命周期与销毁
(1)前后台切换
在 Activity 对应生命周期中调用:
override fun onResume() {
super.onResume()
agent.onResume()
}
override fun onPause() {
super.onPause()
agent.onPause()
}
(2)停止与销毁
停止 E2E 会话 + 销毁具身智能体并释放资源;退出页面时调用。stop 之后可重新调用 init 再次启动。
方法原型
fun stop()
示例代码
override fun onDestroy() {
super.onDestroy()
agent.stop()
}
10.其他常用接口
方法 | 说明 |
fun setVolume(volume: Float) | 设置具身智能体播报音量,0f~1f |
fun getVersion(): String | 获取 SDK 版本号 |
fun clearCache() | 清除本地缓存资源 |
fun getIsOffLineMode(): Boolean | 当前是否处于离线模式 |
fun getCurrentFps(): Float | 获取当前渲染帧率 |
fun showDebugInfo() / hideDebugInfo() | 打开 / 关闭调试信息展示 |
fun setLogStorageAndUploadEnabled(enabled: Boolean) | 日志存储与上传开关 |
fun changeLayout(layout: LayoutConfig) | 动态修改具身智能体布局 |
fun changeWalkConfig(walkConfig: WalkConfig) | 重新设置行走配置 |
fun notifyVoiceEnd() | 通知服务端具身智能体本轮播报已结束 |
三.状态与回调
1.E2E 会话状态
onStateChanged(state: XingyunAvatarAgentState) 回调,状态流转如下:
状态 | 说明 |
IDLE | 初始 / 已停止 |
CONNECTING | E2E 连接建立中(init 后具身智能体就绪时自动进入) |
CONNECTED | E2E 连接已建立,可调用 startASR / ask |
LISTENING | 麦克风采集与 ASR 识别中 |
DISCONNECTED | 连接异常断开,E2E 会自动重连(指数退避),重连中状态切回 CONNECTING |
状态流转图:
IDLE → CONNECTING → CONNECTED ⇄ LISTENING
↑ ↑ ↓ ↓
│ └── DISCONNECTED(异常断开后自动重连)
└── stop() 手动停止
2.回调一览
XingyunAvatarAgentListener 除 onAudioData 外全部回调在主线程执行(onAudioData 在后台线程回调,见下)。
(1)E2E 语音对话回调(必须实现)
回调 | 说明 |
onStateChanged(state) | E2E 会话状态变化 |
onAsrResult(text, isFinal) | ASR 识别结果;isFinal=true 表示一句话识别结束 |
onLlmChunk(text, isFirst) | LLM 流式输出分片;isFirst=true 表示本轮回答的首个分片 |
onLlmDone(usage) | LLM 本轮输出完成,usage 含 token 用量统计 |
onSemanticJudge(result) | 语义判定结果(服务端开启时才会回调,默认空实现) |
onError(error) | 错误事件 |
LlmUsage 实体类
字段 | 类型 | 含义 |
promptTokens | Int | 提问消耗 token 数 |
completionTokens | Int | 回答消耗 token 数 |
totalTokens | Int | 总 token 数 |
cachedTokens | Int | 命中缓存 token 数 |
SDKMessage 实体类
字段 | 类型 | 含义 |
error_code | String | 服务端返回的错误码字符串 |
session_id | String | 会话 ID |
request_id | String | 请求 ID |
speech_id | Int | 语音 ID |
client_speak_id | String | 客户端 speak ID |
(2)具身智能体回调(均有默认空实现,按需重写)
回调 | 说明 |
onInitEvent(code, message) | 具身智能体初始化结果,code=4000 成功 |
onAvatarStateChange(state) | 具身智能体状态变化(listen/think/speak/idle/interactive_idle) |
onVoiceStateChange(status, clientSpeakId) | 播报状态:"voice_start" 播报开始 / "voice_end" 播报结束 |
onSpeakStateChange(speakState, clientSpeakId, errorMsg) | speak 事件状态:speak_start / speak_end / speak_error |
onAvatarReconnectEvent(code, message) | 具身智能体重连事件,code=4000 成功 |
onWidgetEvent(widgetData) | Widget 事件数据(字幕等) |
onSdkMessage(sdkMessage) | SDK 原始消息,参数为 |
onDebugInfo(type, payload) | 调试信息 |
onNetworkInfo(connected, type) | 网络信息变化 |
onAvatarStatusChange(status) | 具身智能体内部状态 |
onStateRenderChange(state, duration) | 状态切换到首帧渲染耗时 |
onWalkStateChange(walkState) | 行走状态:speak_walk_start / speak_walk_end |
onDownloadProgressAndSpeed(progress, speedMBps) | 资源下载进度 |
onAudioData(audioData, speechId) | 具身智能体音频数据(PCM 16kHz 单声道,s16le 小端);后台线程回调,积压超限时可能丢帧 |
onOfflineEvent() | 进入离线模式 |
onSDKRuntimeError(code, message) | SDK 运行时错误,可在此做重新初始化保证长期运行 |
四.错误码
1.E2E 错误(onError 回调)
XingyunAvatarAgentError 实体类
字段 | 类型 | 含义 |
domain | ErrorDomain | 错误域枚举,见下表 |
code | Int | 错误码:HTTP 状态码 / WS 关闭码 / 服务端错误码 |
message | String | 错误信息 |
错误域说明
枚举值 | 说明 |
SESSION | E2E 会话初始化失败(startSession 返回的 e2e_resp 缺失等) |
WS | E2E WebSocket 连接错误 / 异常断开(code 为 WS 关闭码) |
ASR | 服务端 ASR 错误(code 为服务端错误码) |
AUDIO | 本地音频采集错误(如麦克风被占用、无权限) |
INTERNAL | SDK 内部调用错误(如状态不满足时调用接口) |
2.具身智能体返回码
主要用于 onInitEvent、onAvatarReconnectEvent、onSDKRuntimeError 回调。
返回码 | 返回码描述 |
4000 | 成功 |
4100 | 进入房间失败(包含服务端接口返回的报错,json 解析报错) |
4101 | 正在初始化中,请稍后再试(仅在 onInitEvent 回调中) |
4102 | 视频帧渲染超时(仅在 onSDKRuntimeError 回调中) |
4103 | socket 连接退出(仅在 onSDKRuntimeError 回调中) |
4104 | 断开 socket 连接 |
4105 | 同步时间帧发生错误 |
4106 | 加载 charbin 失败(仅在 onSDKRuntimeError 回调中) |
4107 | 服务升级 |
4108 | 暂无可用房间 |
4109 | 渲染失败(仅在 onInitEvent 回调中) |
4110 | socket 连接错误 |
4200 | 在未成功初始化时执行其他状态操作 |
4300 | sdk 未在离线状态下进行重连(仅在 onAvatarReconnectEvent 回调中) |
五.典型接入流程小结
// 1. 创建实例
val agent = XingyunAvatarAgent()
// 2.(可选)预缓存资源
agent.preCache(context, appId, appSecret, preCacheUrl, preCacheListener)
// 3. 统一初始化(具身智能体 + E2E 语音对话)
agent.init(context, avatarLayout, config, listener)
// 4. 等待 onStateChanged(CONNECTED) 后进行对话
agent.startASR() // 语音对话(需 RECORD_AUDIO 权限)
agent.stopASR()
agent.ask("你好") // 文本对话
agent.interrupt() // 打断
// 5. 直接播报(不经过 LLM)
agent.speak("欢迎光临", isStart = true, isEnd = true)
// 6. 生命周期
agent.onResume() / agent.onPause()
// 7. 退出释放
agent.stop()