Android SDK 接入指南(v0.0.6)
一.准备工作
概述
本文是Lite_SDK_Android版本的接入文档,用于指导SDK的使用方法,默认读者已经熟悉 IDE(Eclipse 或者 Android Studio)的基本使用方法,以及具有一定的 Android 编程知识基础。
快速体验demo
- Android压缩包附带的apk文件中是虚拟人demo的安装包,可以直接安装到Android手机上。并快速体验在您的手机上的表现。
- Android压缩包附带的demo文件夹中是虚拟人的示例工程,使用Android studio打开示例工程,完成以下步骤配置,然后直接运行起来测试。
a. 替换SettingActivity中的appid和appSecret
b.demo_configs.json中的config按需配置
c.MockAudioInputsData.json是支持自行输入音频数据的示例格式
开发环境搭建
(1)将开发包拷贝到工程
将SDK中libs目录下的aar包拷贝到自己工程的libs目录下,如没有该目录需新建。
在app文件夹下的build.gradle的dependencies中配置对应版本的aar依赖详细代码如下:
implementation files('libs/xmovdigitalhuman-xxx.aar')
(2)添加外部第三方依赖 详细代码如下:
implementation "javax.vecmath:vecmath:1.5.2"
implementation "com.google.code.gson:gson:2.13.1"
implementation "com.squareup.okhttp3:okhttp:5.1.0"
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"
根 build.gradle.kts文件中增加protobuf相关配置
alias(libs.plugins.protobuf) apply false这一内容。该图片与文档中“根build.gradle.kts文件中增加protobuf相关配置”的要求对应,清晰呈现了protobuf插件依赖的配置代码,是SDK接入准备工作里根Gradle文件配置环节的直观演示。" width="inherit" height="inherit" id="88">

(3)配置AndroidManifest.xml文件
在manifest标签内添加必要的权限支持
<uses-permission android:name="android.permission.INTERNET"/>
(3) 混淆规则:
-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.IXmovAvatar {*;}
-keep class com.xmov.metahuman.sdk.IXmovAvatar$Companion { *;}
-keep public interface com.xmov.metahuman.sdk.IAvatarListener {
public protected *;
}
-keep public interface com.xmov.metahuman.sdk.PreCacheListener {
public protected *;
}
通过上面的几个步骤,工程就配置完成了,接下来就可以在工程中使用虚拟人SDK进行开发了。
二.SDK使用说明
1.预缓存
预缓存是提前缓存视频资源或者charbin文件资源,可按需调用,不是必须调用的;调用时机在初始化方法之前调用
(1)预缓存视频
文件较多,需要几分钟时间,大屏常驻设备可提前调用缓存,按需调用
方法原型
fun preCache(
context: Context,
appId: String,
appSecret: String,
url: String,
listener: PreCacheListener?
)
参数描述
参数 | 类型 | 说明 |
|---|---|---|
context | Context | 一般传Activity或者applicationContext对象 |
appId | String | 星云开放平台上创建对应应用角色的appid |
appSecret | String | 星云开放平台上创建对应应用角色的appSecret |
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 |
listener | PreCacheListener | 回调监听 |
示例代码
//预缓存视频资源
IXmovAvatar.get().preCache(this,AppConfig.appId,AppConfig.appSecret, DemoConfig.gatewayServerCache
,object :
PreCacheListener {
override fun onPreCacheComplete() {
runOnUiThread {
LogUtil.i("onPreCacheComplete")
dismissLoading()
TipsToast.showTips("预缓存完成")
MainActivity.start(this@SplashActivity)
finish()
}
}
override fun onPreCacheProgress(progress: Int) {
runOnUiThread {
LogUtil.i("onPreCacheProgress: $progress")
setLoadingTitle("预缓存中 $progress%")
}
}
})
//预缓存charbin
IXmovAvatar.get().preCacheCharBin(this,AppConfig.appId,AppConfig.appSecret, DemoConfig.gatewayServerCache
,object :
PreCacheListener {
override fun onPreCacheComplete() {
runOnUiThread {
LogUtil.i("onPreCacheComplete")
dismissLoading()
TipsToast.showTips("预缓存完成")
MainActivity.start(this@SplashActivity)
finish()
}
}
override fun onPreCacheProgress(progress: Int) {
runOnUiThread {
LogUtil.i("onPreCacheProgress: $progress")
setLoadingTitle("预缓存中 $progress%")
}
}
})
1.进度回调onPreCacheProgress(progress: Int) progress 范围是0-100,缓存的进度
2.完成回调 onPreCacheComplete() 缓存完成
3.失败回调 onPreCacheFailed(errorCode: Int, errorMessage: String)
2.初始化
使用SDK功能前,必须先进行初始化操作。
方法原型
fun init(
context: Context,
layout: ViewGroup,
initConfig: InitConfig,
listener: IAvatarListener?
)
参数描述
参数 | 类型 | 说明 |
|---|---|---|
context | Context | 一般传Activity对象 |
layout | ViewGroup | 加载虚拟人所在的父布局 |
initConfig | InitConfig | 初始化配置类 |
listener | IAvatarListener | 回调监听 |
InitConfig 类介绍
参数 | 类型 | 说明 |
|---|---|---|
appId | String | 星云具身中应用对应的appId |
appSecret | String | 星云具身中应用对应的appSecret |
gatewayServer | String | 进入房间的地址:"https://nebula-agent.xingyun3d.com/user/v1/ttsa/session" |
config | String | json string 设置一些配置项 |
初始化示例代码
IXmovAvatar.get().init(this, mBinding.avatarLayout, initConfig.appId, initConfig.appSecret,initConfig.gatewayServer,object : IAvatarListener {
override fun onInitEvent(code: Int, message: String?) {
LogUtil.d("onInitEvent code:$code,message:$message")
}
override fun onWidgetEvent(widgetData: IRawEventFrameData?) {
LogUtil.d("onWidgetEvent widgetData:$widgetData")
}
override fun onNetworkInfo(sdkNetworkInfo: SDKNetworkInfo?) {
LogUtil.d("onNetworkInfo $sdkNetworkInfo")
}
override fun onMessage(sdkMessage: SDKMessage?) {
LogUtil.d("onMessage $sdkMessage")
}
override fun onStateChange(state: String?) {
LogUtil.d("onStateChange $state")
}
override fun onStatusChange(status: SDKStatus?) {
LogUtil.d("onStatusChange $status")
}
override fun onStateRenderChange(state: String?, duration: Long) {
LogUtil.d("onStateRenderChange state:$state,duration:$duration")
}
override fun onVoiceStateChange(status: String?,clientSpeakId: String?) {
LogUtil.d("onVoiceStateChange state:$status")
runOnUiThread {
if ("voice_end" == status) {
} else if ("voice_start" == status) {
}
}
}
override fun onDebugInfo(debugInfo: JSONObject) {
// LogUtil.d("onDebugInfo debugInfo:$debugInfo")
}
override fun onReconnectEvent(code: Int, message: String?) {
toast("重连:code=$code message=$message")
}
override fun onOfflineEvent() {
toast("进入离线状态")
}
override fun onSDKRuntimeError(code: Int, message: String?) {
Log.d(TAG, "onSDKRuntimeError code:$code,message:$message")
toast("onSDKRuntimeError code:$code,message:$message")
}
override fun onSpeakStateChange(
speakState: String?,
clientSpeakId: String?,
errorMsg: String?
) {
Log.d(TAG, "onSpeakStateChange :speakState=$speakState clientSpeakId=$clientSpeakId errorMsg=$errorMsg")
toast("onSpeakStateChange :speakState=$speakState clientSpeakId=$clientSpeakId errorMsg=$errorMsg")
}
override fun onWalkStateChange(walkState: String?) {
Log.d(TAG, "onWalkStateChange $walkState")
toast("onWalkStateChange $walkState")
}
})
1.初始化回调
onInitEvent(code: Int, message: String?)方法返回参数分为外层code和result,含义如下:
字段 | 类型 | 含义 |
|---|---|---|
code | Int | code为0:成功;其他:失败 |
message | String | 返回信息 |
2.事件回调(字幕回调)
onWidgetEvent(widgetData: IRawEventFrameData?)
IRawEventFrameData实体类
字段 | 类型 | 含义 |
|---|---|---|
startFrame | Int | 开始帧 |
event | JSONArray | type: "subtitle_on" 字幕类型,text 字幕文案 |
3.声音播报回调
onVoiceStateChange(status: String?,clientSpeakId: String?)
字段 | 类型 | 含义 |
|---|---|---|
status | String | "voice_start" 播报开始"voice_end" 播报结束 |
clientSpeakId | String | speakid,可在调用speak时传入,不传内部自动生成一个id |
4.重连在线模式回调
onReconnectEvent(code: Int, message: String?)
字段 | 类型 | 含义 |
|---|---|---|
code | Int | code为0:成功;其他:失败 |
message | String | 返回信息 |
5.SDK在运行过程中的错误回调
可在该回调中,进行重新初始化逻辑,保证设备长期运行
onSDKRuntimeError(code: Int, message: String?)
字段 | 类型 | 含义 |
|---|---|---|
code | Int | 错误code码 |
message | String | 错误信息 |
6.speak事件回调
返回speak事件的开始,结束,错误状态
onSpeakStateChange(speakState: String?,clientSpeakId: String?,errorMsg: String?)
字段 | 类型 | 含义 |
|---|---|---|
speakState | String | speak事件状态 speak_start speak_end speak_error |
clientSpeakId | String | speakid,可在调用speak时传入,不传内部自动生成一个id |
errorMsg | String | 错误信息 仅在speakState为speak_error下返回 |
7.walk事件回调
onWalkStateChange(String walkState)
字段 | 类型 | 含义 |
|---|---|---|
walkState | String | walk事件状态 speak_walk_start speak_walk_end |
3.config配置
在进行初始化时,initConfig中的config是一个json 字符串,可以定制化做一些配置
config字段名介绍
字段名 | 数据类型 | 说明 | 默认值 | 示例值 |
|---|---|---|---|---|
input_audio | boolean | 是否开启自己的音频输入true为开启,false为关闭(sdk内部的音频输入) | FALSE | FALSE |
output_audio | boolean | 是否开启SDK内音频输出true为使用sdk内部音频输出false不使用sdk内部音频输出 | TRUE | TRUE |
input_audio_sample_rate | Int | 输入音频的采样率(仅在使用输入音频时使用) | 24000 | 16000 |
enable_client_interrupt | boolean | 开启enableClientInterrupt,播报状态切换其他状态时会立即关闭数字人口型渲染及音频字幕。 | FALSE | TRUE |
max_reconnect_count | Int | 最大重连次数(默认5次)断网情况下会切换到离线模式,当sdk检测到有网会进行重连 | 5 | 5 |
init_time_out | Int | 初始化渲染第一帧超时阈值(默认30s) | 30 | 30 |
render_time_out | Int | 视频渲染超时阈值(默认15秒) | 15 | 15 |
resolution | JSONObject | 分辨率配置对象,用于定义画面的宽高参数(跟随角色分辨率保持一致) | {"height": 1920, "width": 1080} | {"height": 1920, "width": 1080} |
resolution.height | number | 画面高度,单位为像素(px) | 1920 | 1920 |
resolution.width | number | 画面宽度,单位为像素(px) | 1080 | 1080 |
layout | LayoutConfig | 数字人布局配置结构化对象 | ||
walk_config | WalkConfig | 数字人行走配置结构化对象 |
LayoutConfig介绍
(1)container(容器配置)
字段名 | 数据类型 | 说明 | 默认值 | 示例值 |
|---|---|---|---|---|
size | Int[] | 容器尺寸,数组第一位为宽度,第二位为高度 | [1080, 1920] |
(2)avatar(数字人布局配置)注意:align需要容器为约束布局ConstraintLayout 类型生效
字段名 | 数据类型 | 取值范围 | 说明 | 默认值 | 示例值 |
|---|---|---|---|---|---|
v_align | string | "top" / "middle" / "bottom" | 数字人在容器内的垂直对齐方式(vertical align),控制数字人在容器垂直方向的位置(容器为约束布局ConstraintLayout 类型生效) | "middle" | "middle" |
h_align | string | "left" "center" "right" | 数字人在容器内的水平对齐方式(horizontal align),控制数字人在容器水平方向的位置(容器为约束布局ConstraintLayout 类型生效) | "center" | "center" |
scale | Float | string | >0 或者 40vh | 数字人缩放比例,1 为原始尺寸,0.5 为缩小至 50%,大于 1 为放大 // 设置0.4 是基于分辨率的0.4,例如:10801920的数字人。设置0.4之后大小为432768 // 设置40vh 非数字,且包含vh时,根据vh计算scale 计算公式是 vh值 / 100 * 容器高度 / 分辨率高度 = scale 例如0.4vh,实际scale =(40/100* 810)/1920=0.16875,此时数字人的大小为182.25*324 | 1 | 0.5 |
offset_x | number | 任意数值 | 数字人在水平对齐基础上的偏移量(正数向右,负数向左) | 0 | 20 |
offset_y | number | 任意数值 | 数字人在垂直对齐基础上的偏移量(正数向下,负数向上) | 0 | 20 |
WalkConfig介绍
配置项 | 类型 | 取值约束 | 说明 | 示例 |
|---|---|---|---|---|
walk_points | object | 1. 键:自定义点位名称(字符串,如 A/B/C/D、start/center/end 等); | ||
init_point | string | walk_points中的键名 | 设置数字人的当前点位 |
配置示例
{
"max_reconnect_count": 5,
"render_time_out": 12,
"input_audio": false,
"output_audio": true,
"enable_client_interrupt": true,
"resolution": {
"width": 1080,
"height": 1920
},
"layout": {
"container": {
"size": [
2712,
1220
]
},
"avatar": {
"h_align": "center",
"v_align": "middle",
"scale": 1,
"offset_x": 0,
"offset_y": 0
}
},
"walk_config": {
"walk_points": {
"A": -500,
"B": -400,
"C": -300,
"D": -200,
"E": -100,
"F": 0,
"G": 100,
"H": 200,
"I": 300,
"J": 400,
"K": 500,
"O": 600,
"P": 700,
"Q": 800,
"L": 900,
"M": 1000
},
"init_point": 0
}
}
4.Speak
4.1 SDK内部音频播报
方法原型
fun speak(
ssml: String?,
isStart: Boolean,
isEnd: Boolean,
enableSpeechCache: Boolean? = null,
clientSpeakId: String? = null
)
参数说明
参数 | 参数类型 | 说明 |
|---|---|---|
ssml(必填) | String | 传入说话内容的文本信息(支持ka动作) |
isStart(必填) | boolean | 是否开始节点 |
isEnd(必填) | boolean | 是否输入结束 |
enableSpeechCache(可选) | boolean? | 是否启用缓存(默认null) |
clientSpeakId(可选) | String? | 当前会话的speak id (默认null) |
支持全文本和流式文本输入
(1)全文本输入时代码示例:
IXmovAvatar.get().speak("welcomeMessage", true, true, false,null)
(2) 流式文本输入时代码示例
//开头
IXmovAvatar.get().speak("msg 1", true, false, false,null)
IXmovAvatar.get().speak("msg 2", false, false, false,null)
...
//结尾
IXmovAvatar.get().speak("msg 2", false, true, false,null)
4.2 SDK外部音频播报
使用该方法时必须要设置config必须要配置"input_audio": true, "output_audio": true
方法原型
fun speak(
ssml: String?,
isStart: Boolean,
isEnd: Boolean,
ttsData: JSONObject,
enableSpeechCache: Boolean? = null,
clientSpeakId: String? = null
)
参数说明
参数 | 参数类型 | 说明 |
|---|---|---|
ssml(必填) | String | 传入说话内容的文本信息(支持ka动作) |
isStart(必填) | boolean | 是否开始节点 |
isEnd(必填) | boolean | 是否输入结束 |
ttsData(必填) | JSONObject | 音频数据(格式参考demo中的MockAudioInputsData.json文件) |
enableSpeechCache(可选) | boolean? | 是否启用缓存(默认null) |
clientSpeakId(可选) | String? | 当前会话的speak id (默认null) |
5.断线重连
本sdk支持,当网络波动或者无网情况下,自动进入离线状态,当有网络时会自动重连。
也支持客户手动切换到离线状态,然后再重连(注意 重连只能是离线状态下进行重连,其他状态进行重连会报错)
方法原型
fun switchModel(isOffline: Boolean)
参数说明
参数 | 参数类型 | 说明 |
|---|---|---|
isOffline(必填) | Boolean | true:切换到离线模式false:进行重连到在线模式 |
示例代码
IXmovAvatar.get().switchModel(true)
6.销毁
销毁sdk实例,断开连接 进行资源释放。虚拟人退出时调用
方法原型
fun destroy()
示例代码
IXmovAvatar.get().destroy()
7.设置行走配置
在初始化成功后重新设置初始点位
方法原型
fun changeWalkConfig(walkConfig: WalkConfig)
示例代码
val walkConfig = WalkConfig().apply {
initPoint = -1000f
walkPoints.apply {
put("A", -1000.0f)
put("B", -800.0f)
put("C", -600.0f)
put("D", -400.0f)
put("E", -200.0f)
put("F", 0.0f)
put("G", 200.0f)
put("H", 400.0f)
put("I", 600.0f)
put("J", 800.0f)
put("K", 1000.0f)
}
}
IXmovAvatar.newInstance().changeWalkConfig(walkConfig)
8.获取数字人X偏移量
在行走过程中可以用来获取当前数字人的X偏移量,单位px
方法原型
fun getGlViewOffsetX(): Float
9.日志开关
在调试阶段可以打开日志,方便分析问题,应用发布时可关闭日志,提升性能,默认是打开日志的
关闭日志方法原型
fun hideDebugInfo()
示例代码
IXmovAvatar.get().hideDebugInfo()
打开日志方法原型
fun showDebugInfo()
示例代码
IXmovAvatar.get().showDebugInfo()
三.虚拟人状态
虚拟人常用的一下动作状态切换
1.倾听
代码示例
IXmovAvatar.get().listen()
2.思考
代码示例
IXmovAvatar.get().think()
3.打断
代码示例
IXmovAvatar.get().interrupt()
四.返回码
该返回码为虚拟人SDK自身的返回码,具体错误在碰到之后查阅
主要用于onInitEvent、onReconnectEvent、onSDKRuntimeError回调
返回码 | 返回码描述 |
|---|---|
0 | 成功 |
1000 | 进入房间失败(包含服务端接口返回的报错,json解析报错) |
1001 | 正在初始化中,请稍后再试(仅在onInitEvent回调中) |
1002 | 视频帧渲染超时(仅在onSDKRuntimeError回调中) |
1003 | socket连接退出 (仅在onSDKRuntimeError回调中) |
1004 | 断开socket连接 |
1005 | 同步时间帧发生错误 |
1006 | 加载charbin失败 (仅在onSDKRuntimeError回调中) |
1007 | 服务升级 |
1008 | 暂无可用房间 |
1009 | 渲染失败(仅在onInitEvent回调中) |
2000 | 在未成功初始化时执行其他状态操作 (仅在onMessage回调中) |
3000 | sdk 未在离线状态下进行重连 (仅在onReconnectEvent回调中) |