HappyOyster Android SDK 入口为单例对象 HappyOyster ,除 initialize 、 updateToken 、 attachVideo 、 sendCommand 外,业务方法均为 suspend ,失败时抛出 SDKError 。
调用方 coroutine 被取消时,SDK 会取消该调用仍在进行的 HTTP 请求(如有),原样传播 CancellationException,不会转换为 SDKError。取消不代表服务端已经受理的请求会被回滚。
接入流程、安装、最佳实践见 HappyOyster Android SDK 接入指南。
核心名词概念
名词 | 含义 |
|---|---|
token | 百炼网关 API Key:由你的 App 通过 |
ticket | 一次性体验凭证:由你的服务端调用开放平台换取并下发给客户端,仅用于一次 |
环境要求
项 | 要求 |
|---|---|
minSdk | 24(Android 7.0)及以上 |
compileSdk | 36 |
语言 | Kotlin(协程 |
ABI |
|
网络 | 需要可访问公网 |
核心概念
概念 | 说明 |
|---|---|
World | AI 世界,包含角色、场景。由你的服务端创建与管理。 |
Travel | 一次实时体验。基本生命周期: |
模式 |
|
实时视频 |
|
概览
HappyOyster 方法
方法 | 说明 |
|---|---|
| 初始化 SDK;允许在 idle 时重新初始化,Travel 正在 starting、active 或 ending 时重新初始化会以 |
| 注入/更新百炼网关 API Key(Bearer token)。 |
| 用一次性凭证开始一次体验,自动建立实时视频连接。 |
| 异步暂停体验(实时导演与角色演绎,且体验支持暂停);受理后真正暂停以 |
| 恢复已暂停的体验(实时导演与角色演绎);内部含 3× 重试退避。 |
| 回溯到指定秒数(仅实时导演、状态为 paused)。秒数取 4 的整数倍。角色演绎 不支持回溯。 |
| 发送文本指令驱动剧情(实时导演与角色演绎,running 或 paused)。 |
| 发送方向/视角/动作控制指令(世界探索模式,仅 running;主线程调用)。角色演绎不可用。 |
| 返回播放用 |
| 结束体验,自动断开实时连接并释放全部会话资源。 |
| SDK 版本字符串(SemVer),编译期常量。 |
事件
事件 | 说明 |
|---|---|
| 体验状态变化(含实时视频生命周期),值见 |
| 内部自动流程出错时回调;致命错误会同时终止本次体验。 |
关键数据类型
类型 | 说明 |
|---|---|
| SDK 初始化配置( |
| 体验状态: |
| 体验模式: |
| 世界创建模型: |
|
|
|
|
| SDK 错误,含 |
HappyOyster.initialize
初始化 SDK,应在调用其他 API 前完成(建议在 Application.onCreate)。config 为必填参数,须携带你账号的百炼 apiHost,并通过 model 指定拆分后的模型名(happyoyster-1.0-directing / happyoyster-1.0-acting / happyoyster-1.0-adventure,与所用 Open API 入口一致)。SDK 按以下规则拼接请求地址:
https://{apiHost}/api/v2/apps/{model}/openapi/v1/{endpoint}
model 没有默认值:构造 SDKConfig 时遗漏该参数会编译失败;传入空白值则 initialize 同步抛出 SDKError(100002),且不会创建或替换 runtime,也不会发起网络请求。SDK 只持有 application context,不持有 Activity。仅当上一个 runtime 为 idle 时允许重新初始化;切换模型时须在 idle 状态使用新 model 重新初始化。若 Travel 正在 starting、active 或 ending,须先等待 endTravel() 完成。
说明
地域合规提示:- 为支持适用法律法规及数据合规要求的落实,如您的目标用户包括美国用户,您必须在 SDK 初始化时为面向该等用户的服务配置美国地区 API Host。
- 开发者应确保配置正确,并依法承担因未按上述要求配置所产生的相应责任。
签名
fun initialize(context: Context, config: SDKConfig)
参数
字段 | 类型 | 是否必填 | 描述 |
|---|---|---|---|
context | Context | 是 | 建议传 |
config | SDKConfig | 是 | SDK 配置,须携带必填且无默认值的 |
返回值
无返回值。
错误
code | 说明 |
|---|---|
|
|
| Travel 正在 starting、active 或 ending,拒绝重新初始化。等待 |
HappyOyster.updateToken
注入/更新百炼网关 API Key,线程安全;在 initialize 后可随时调用。SDK 会将最新 token 用于 startTravel 及后续体验控制请求。ticket 是一次性体验凭证,不应和 Bearer token 混用。
签名
fun updateToken(token: String)
参数
字段 | 类型 | 是否必填 | 描述 |
|---|---|---|---|
token | String | 是 | 百炼网关 API Key,作为 Bearer token 使用。 |
返回值
无返回值。
错误
code | 说明 |
|---|---|
| SDK 尚未初始化。 |
HappyOyster.startTravel
用一次性 ticket 开始一次体验。成功后 SDK 自动建立实时视频连接并开始内部状态轮询,状态通过 onStatusChanged 透出。
ticket为一次性凭证,调用后即视为已消费。- 同一 App 同一时刻只允许一个并发 Travel;已有体验进行中时再次调用会抛出
SDKError(103004),SDKError.raw中仅包含当前活跃 ticket 的脱敏摘要供诊断,不包含完整 ticket。 - 可选传入
maxExperienceTimeSec限制本次体验最大时长(仅世界探索 / adventure 模式生效),详见参数。
StartTravelData.creationModel(CreationModelValue,默认 CreationModelValue.Simple):指示该世界的创建模型,即剧本内容的管理方式。simple(默认)为普通 instruct 驱动的世界,世界探索类世界也会归一化为此值。scriptlist 为结构化 ScriptList 世界——剧本内容不通过本 SDK 访问。在 ScriptList 模式(creationModel == CreationModelValue.ScriptList)下调用 sendInstruct 会被拒绝,抛出 SDKError(103002)。该字段缺省值为 simple。
StartTravelData.aspectRatio(String?):服务端为本次会话分配的播放画幅,形如 width:height。仅角色演绎(acting)非空——"9:16"(竖屏,服务端创建时的默认值)或 "16:9"(横屏);世界探索与实时导演模式、以及服务端未下发时为 null。SDK 原样保留未知取值(不收敛为 null),宿主须把不认识的值等同 null 处理并回退到自己的默认方向;SDK 自身不消费该字段。
该值随 startTravel() 的返回值交付:请在 startTravel() 返回后、调用 attachVideo() 把返回的视图挂进布局之前据此确定播放容器方向——SDK 只有在宿主挂载视图后才开始绑定渲染远端流,所以此刻定方向仍赶在首帧渲染之前(但不保证发生在 SDK 加入实时房间之前)。远端视图以裁剪填充(clip-to-fill)方式绑定,容器方向与该值不一致会裁掉画面而不是留黑边。
签名
suspend fun startTravel(ticket: String): StartTravelData
suspend fun startTravel(ticket: String, maxExperienceTimeSec: Int?): StartTravelData
参数
字段 | 类型 | 是否必填 | 描述 |
|---|---|---|---|
ticket | String | 是 | 一次性体验凭证,由你的服务端下发。 |
maxExperienceTimeSec | Int? | 否 | 本次体验的最大时长(秒),到时后世界侧自动结束会话。仅世界探索(adventure)模式生效,实时导演与角色演绎 忽略此值。合法取值由服务端配置,当前为 |
返回值
返回 StartTravelData,含体验元数据(mode、version、creationModel、aspectRatio 等)。先检视返回的元数据再决定如何互动(如 travel.mode、travel.creationModel、travel.version),角色演绎还需按 travel.aspectRatio 定播放容器方向。
错误
code | 说明 |
|---|---|
|
|
|
|
| 入参非法(如 |
| 世界状态非就绪 |
| 资源分配/服务内部失败 |
| 已有 Travel 正在 starting、active 或 ending,或并发调用 |
HappyOyster.pauseTravel / HappyOyster.resumeTravel
暂停 / 恢复体验。SDK 同时只管理一个 Travel,encryptedTravelId 由 SDK 内部自动取得,调用方无需传入。
前置条件:
pauseTravel:仅实时导演(directing)或角色演绎(acting)、且状态为running时可调用。resumeTravel:仅实时导演(directing)或角色演绎(acting)、状态为paused时可调用。
并非所有体验都支持暂停 / 恢复:体验须报告本模式要求的版本标识(StartTravelData.version,实时导演为 storyV2、角色演绎为 actingV2;比较时忽略首尾空白与大小写),否则 pauseTravel 与 resumeTravel 都返回 103002。角色演绎支持暂停 / 恢复,但 不支持 rewindTravel。
暂停是异步的(重要):pauseTravel 是一个「重」操作——调用成功(方法返回)只代表暂停已受理,此刻体验还未真正暂停。只有当 onStatusChanged 回调报告 paused 时,才算真正暂停。因此请以该回调驱动宿主状态机和调用门控:在「调用 pauseTravel」到「收到 paused 回调」之间可将本地状态标记为 pausing;收到 paused 后才允许发起 resumeTravel 或 rewindTravel。不要把 pauseTravel 的返回当作已暂停。
实时连接的处理:真正暂停后 SDK 会断开实时连接;恢复时 SDK 会用同一次 startTravel 时下发的凭证自动重新入会并恢复画面,无需宿主干预。
暂停拆房有序屏障:收到 Paused 后,服务端实时房间的拆除仍可能短暂滞后。SDK 会从暂停确认时刻起建立 3 s settle 窗口;窗口内调用 resumeTravel 或 rewindTravel 时,suspend 调用先非阻塞等待剩余时间,再发送会重新开房的 API。若收到 Paused 后已自然等待满 3 s,则不增加延迟。这样可避免迟到的 pause teardown 关闭刚重开的房间并触发 105001。
resume API 重试:resumeTravel 内部会在失败时最多重试 3 次(退避 1 s / 2 s / 3 s),以应对暂停后服务短暂不可用的情况;只有 3 次全部失败才会向上抛出错误。
说明建议宿主在 resumeTravel 返回成功后 3 s 内暂缓再次发起 pauseTravel,避免过于频繁的切换。此为宿主侧调用冷却建议,SDK 本身不强制。详见 HappyOyster Android SDK 接入指南。
签名
suspend fun pauseTravel(): TravelStateData
suspend fun resumeTravel(): TravelStateData
参数
无参数。
返回值
返回 TravelStateData(含 encryptedTravelId、status)。
错误
code | 说明 |
|---|---|
| 无活跃体验 |
| 状态不允许,或该体验不支持暂停 / 恢复 |
| 在世界探索模式下调用,仅实时导演与角色演绎 支持暂停 / 恢复 |
HappyOyster.rewindTravel
回溯到指定秒数。encryptedTravelId 由 SDK 内部自动取得。
前置条件:仅实时导演(directing)模式、且状态为 paused 时可调用(不允许在 running 状态下回溯);并非所有实时导演体验都支持回溯,不支持时返回 103002。回溯成功后体验会自动恢复,SDK 会自动重连 RTC,无需宿主干预。
角色演绎完全没有回溯能力:在角色演绎下调用会被 SDK 在本地以 103003 拒绝,不发出任何请求。宿主在角色演绎下应隐藏回溯入口,而不仅是禁用按钮。
签名
suspend fun rewindTravel(rewindToSec: Double): RewindTravelData
参数
字段 | 类型 | 是否必填 | 描述 |
|---|---|---|---|
rewindToSec | Double | 是 | 回溯到的目标秒数,应为 4 的整数倍(如 4、8、12)。非 4 的整数倍由服务端向下取整到最近的较小 4 的倍数(如传 7 取 4)。 |
返回值
返回 RewindTravelData(含 encryptedTravelId、status、resumedAtSec)。其中 resumedAtSec 为服务端实际回溯到的秒数(已按 4 的整数倍向下取整)。
错误
code | 说明 |
|---|---|
| 无活跃体验 |
| 状态不是 |
| 在世界探索或角色演绎下调用,仅实时导演模式支持回溯 |
HappyOyster.sendInstruct
发送文本指令驱动剧情,仅在实时导演(directing)或角色演绎(acting)且体验状态为 running 或 paused 时有效。encryptedTravelId 由 SDK 内部自动取得。
paused 态行为:SDK 不会在 paused 时自动 resume,instruct 直接发送。由宿主决定是否先调用 resumeTravel 再发 instruct。
签名
suspend fun sendInstruct(content: String): SendInstructData
参数
字段 | 类型 | 是否必填 | 描述 |
|---|---|---|---|
content | String | 是 | 要发送的文本指令内容。 |
返回值
返回 SendInstructData(含 encryptedTravelId、content、accepted)。
错误
code | 说明 |
|---|---|
| 无活跃体验(未调用 |
| 当前模式非实时导演或角色演绎(在世界探索模式下调用) |
| 体验状态既不是 |
| 内容安审拦截 |
| Travel 不存在 |
HappyOyster.sendCommand
发送方向/视角/动作控制指令。仅在世界探索模式、running 时有效。
- 请在主线程调用;离主线程调用会同步抛出
IllegalStateException。 - 无活跃体验报
103001。 - 在非世界探索模式(实时导演 / 角色演绎)下调用会报
103003。 - 状态不允许报
103002。 - 上行通过一路静音音频流建立(SDK 不录制、不上传真实音频);
RECORD_AUDIO并非 DataChannel 硬前置,为兼容各机型建议声明并授予(见 HappyOyster Android SDK 接入指南 § 安装 · 权限)。105004表示实时通道未就绪 / 发送失败(如 DataChannel 连接中断或实时通道异常),不由缺少权限直接触发。
内置 42 ms 节流(24fps,latest-wins):sendCommand 内部对 DataChannel 写入做了以 42 ms(约 24fps)为周期的节流。状态校验同步、立即执行并在非法调用时立即抛出;DataChannel 实际写入是异步节流的:若距上次发送已过 42 ms 则立即发出(首次立即发),否则将命令更新为最新值(latest-wins)并在当前 42 ms 周期结束时延迟发出一次。同一周期内多次调用等同于一次、以最后一次为准。这意味着宿主可以按游戏帧率高频调用 sendCommand,SDK 会稳定合并为约每 42 ms 一次上链,无需宿主手动限速。
节流期间的发送失败:节流 flush 是异步的,发送失败无法抛给调用方——错误会通过 onError 回调(非致命,105004)透出。Session 结束时 pending 的命令会被丢弃(不会在结束后发送)。
签名
fun sendCommand(command: AdventureCommand)
参数
字段 | 类型 | 是否必填 | 描述 |
|---|---|---|---|
command | AdventureCommand | 是 | 含 |
AdventureCommand 字段与取值
translation — 移动
前/左/后/右/斜向/静止。
值 | 方向 |
|---|---|
| 前 |
| 左 |
| 后 |
| 右 |
| 左前 |
| 右前 |
| 左后 |
| 右后 |
| 静止 |
rotation — 视角
上/下/左/右/斜向/无。
值 | 方向 |
|---|---|
| 上 |
| 下 |
| 左 |
| 右 |
| 左上 |
| 右上 |
| 左下 |
| 右下 |
| 无 |
interaction — 交互
跳跃/攻击/蹲下/冲刺/无。
值 | 动作 |
|---|---|
| 跳跃 |
| 攻击 |
| 蹲下 |
| 冲刺 |
| 无 |
三字段彼此独立,各自对应一组互斥指令;斜向移动/视角使用单个组合值(如同时前+左发 W_A,而非同字段并发 W 与 A)。每次调用传入当前完整状态即可。
最佳实践:单次动作 vs 持续动作
以 42 ms 周期为心智模型,区分两类用法:
单次动作(如点一下跳跃/攻击、走一步):调用一次即可。SDK 会在最近的周期把它上链,动作即生效;无需持续发送,也无需补发 None。
// 跳一下
HappyOyster.sendCommand(AdventureCommand("None", "None", "Jump"))
持续动作(如按住持续移动、持续转视角):按住期间按帧持续调用,SDK 每约 42 ms 上链一次,持续输出该指令,角色即持续动作;松手时显式发送一次带 None 的指令复位停止。SDK 不会自动代发 None——不持续调用就没有后续上链、动作会停下,但不发 None 就不会主动复位。
// 按住:每帧持续调用(宿主自行驱动帧循环)
HappyOyster.sendCommand(AdventureCommand("W", "None", "None"))
// 松手:显式复位一次
HappyOyster.sendCommand(AdventureCommand("None", "None", "None"))
返回值
无返回值(同步)。状态校验同步立即执行;DataChannel 写入异步节流。
错误
code | 说明 |
|---|---|
| 无活跃体验 |
| 状态不允许 |
| 在非世界探索模式(实时导演 / 角色演绎)下调用 |
| 节流 flush 发送失败(非致命,异步回调) |
HappyOyster.attachVideo
返回一个用于播放的 SurfaceView,由你加入布局;SDK 内部完成与远端流的渲染绑定。
- 请在主线程调用;离主线程调用会同步抛出
IllegalStateException。 - SDK 对返回的 View 仅持弱引用,体验结束时释放渲染绑定;你需自行将 View 从布局移除。
- 角色演绎体验请先按
StartTravelData.aspectRatio定好播放容器方向,再把返回的视图挂进布局:渲染以裁剪填充方式绑定,方向不符会裁掉画面(见startTravel)。
签名
fun attachVideo(): SurfaceView
参数
无参数。
返回值
返回 SurfaceView,加入布局后即可播放实时视频。
错误
code | 说明 |
|---|---|
| SDK 未初始化 |
HappyOyster.endTravel
结束体验。encryptedTravelId 由 SDK 内部自动取得。调用成功(或异常退出)后,SDK 自动断开实时连接、停止内部轮询、释放全部会话资源,本次 ticket 同时失效。
签名
suspend fun endTravel(): EndTravelData
参数
无参数。
返回值
返回 EndTravelData(含 encryptedTravelId、status、endedAt、durationSec)。
错误
code | 说明 |
|---|---|
| SDK 未初始化 |
| 无活跃体验 |
HappyOyster.VERSION
返回 SDK 版本字符串(SemVer),如 "x.y.z"。该值是编译期常量,由 VERSION_NAME Gradle 属性注入;无需先调用 initialize 即可安全读取。
签名
val VERSION: String
返回值
SDK 版本字符串,如 "x.y.z"。
Log.d("MyApp", "SDK version: ${HappyOyster.VERSION}")
事件监听
interface HappyOysterListener {
fun onStatusChanged(status: TravelStatusValue) {}
fun onError(error: SDKError) {}
}
fun addListener(listener: HappyOysterListener)
fun removeListener(listener: HappyOysterListener)
SDK 事件是对你的主动推送通道,用于回调那些非你主动调用触发的情况(如 SDK 内部自动维护的实时连接或状态轮询出现问题)。
事件 | 说明 |
|---|---|
| 体验状态变化(含实时视频生命周期),值见 |
| 内部自动流程出错时回调;致命错误会同时终止本次体验(见错误码节)。 |
说明addListener / removeListener 必须在 initialize 之后调用;在初始化前调用会抛出 SDKError(100001)。建议在 HappyOyster.initialize(...) 成功返回后立即注册监听器。
数据模型
// 配置
data class SDKConfig(
// 必填:你账号的百炼 API Host(如 llm-xxxx.ap-southeast-1.maas.aliyuncs.com),百炼控制台 API Key 页复制;
// 须与注入的 API Key 同账号/区域,否则网关返回 AccessDenied。
val apiHost: String,
// 必填且无默认值:包含版本的完整 HappyOyster 模型名称(如 happyoyster-1.0-directing);
// 可用值以百炼官方 HappyOyster 系列模型文档为准。
val model: String,
// 内置 Logcat 输出的最低等级(不影响 logHandler);默认 INFO,含重建会话时间线所需的
// 生命周期锚点(初始化、Travel 起止/状态、RTC 入会/首帧)。仅需报错可降为 WARN,排障可升到 DEBUG/VERBOSE。
val logLevel: LogLevel = LogLevel.INFO,
// RTC 入会(超时触发 105002)、首帧等待(超时触发 105003)与 SDK 网关 HTTP 信令调用(超时触发 105005)的超时;
// 两个 RTC 阶段串行,最坏等待 2×callbackTimeoutMs(60s)。
val callbackTimeoutMs: Long = SDKConfig.DEFAULT_CALLBACK_TIMEOUT_MS, // 30_000ms
// SDK 是否将自身日志写入 Android Logcat(tag HappyOysterSDK);默认 false(静默)。
val logcatEnabled: Boolean = false,
// 宿主日志回调;接收全量 SDK LogRecord,不受 logLevel 影响;默认 null。
val logHandler: HappyOysterLogHandler? = null,
) {
companion object {
/** 默认回调超时(毫秒)。公开常量,可用于对比或显示。 */
const val DEFAULT_CALLBACK_TIMEOUT_MS: Long = 30_000
}
}
enum class LogLevel { VERBOSE, DEBUG, INFO, WARN, ERROR, NONE }
// 宿主日志接收器;通过 SDKConfig.logHandler 注入;全量 firehose,不受 logLevel 影响。
fun interface HappyOysterLogHandler {
fun onLog(record: LogRecord)
}
// SDK 结构化日志记录;交付给 HappyOysterLogHandler;不含敏感值(Bearer / ticket / RTC token、
// RTC 标识与媒体 URL 均已脱敏)。travelId(encryptedTravelId)保留全值,可用于与服务端会话日志对账。
data class LogRecord(
val level: LogLevel,
val tag: String, // 固定为 "HappyOysterSDK"
val message: String, // 可读日志行(含事件名与详情)
val throwable: Throwable?,
val timestampMs: Long, // 发出时的 epoch 毫秒
)
// 状态与模式(保留未知值,便于服务扩展)
@JvmInline value class TravelStatusValue(val rawValue: String) {
companion object {
val Init = TravelStatusValue("init")
val Pending = TravelStatusValue("pending")
val Running = TravelStatusValue("running")
val Paused = TravelStatusValue("paused")
val Failed = TravelStatusValue("failed")
val Completed = TravelStatusValue("completed")
}
}
@JvmInline value class ModeValue(val rawValue: String) {
companion object {
val Adventure = ModeValue("adventure")
val Directing = ModeValue("directing")
val Acting = ModeValue("acting")
}
}
@JvmInline value class CreationModelValue(val rawValue: String) {
companion object {
val Simple = CreationModelValue("simple") // 默认;prompt/instruct 驱动,世界探索类世界归一化为此值
val ScriptList = CreationModelValue("scriptlist") // 结构化 ScriptList 世界;不支持 sendInstruct(抛 103002)
}
}
// startTravel 返回
data class StartTravelData(
val encryptedTravelId: String, // 后续控制接口的标识
val encryptedWorldId: String,
val mode: ModeValue, // adventure / directing / acting
val creationModel: CreationModelValue = CreationModelValue.Simple, // 世界创建模型;Simple(默认)为 instruct 驱动,ScriptList 不支持 sendInstruct
val playUrl: String?,
val firstFrame: String?, // 首帧图地址,可能异步产生
val bgmUrl: String?,
val version: String, // 世界版本标识;角色演绎的 version 为 actingV2
val aspectRatio: String? = null, // 仅角色演绎返回 9:16 / 16:9;其余模式 null。用于定播放器方向
val maxExperienceTimeSec: Int? = null, // 服务端回显的本次最大体验时长(秒);仅 adventure 非 null,directing / acting 为 null
)
// 控制接口参数与返回
data class AdventureCommand(
val translation: String, // 移动:前/左/后/右/斜向(W_A 等)/静止
val rotation: String, // 视角:上/下/左/右/斜向(Mouse_Up_Left 等)/无
val interaction: String, // 交互:跳跃/攻击/蹲下/冲刺/无
)
data class TravelStateData(val encryptedTravelId: String, val status: TravelStatusValue)
data class RewindTravelData(val encryptedTravelId: String, val status: TravelStatusValue, val resumedAtSec: Double)
data class EndTravelData(val encryptedTravelId: String, val status: TravelStatusValue, val endedAt: String, val durationSec: Int)
data class SendInstructData(val encryptedTravelId: String, val content: String, val accepted: Boolean)
// 错误(以 code 标识,原始信息见 raw)
// 注意:SDKError 不是 data class(无 copy()/解构),是普通 class。
class SDKError(val code: Int, val raw: Any? = null) : Exception("Happy Oyster SDK error: $code")
错误码
错误以数字 code 标识。SDK 会透传可由调用方处理的业务错误码(常见为 4xxxxx / 5xxxxx),本地 SDK 错误码为 1xxxxx。
业务错误码(常见)
code | 含义 | 建议处理 |
|---|---|---|
| 参数非法(枚举非法等) | 检查请求参数或 SDK 版本 |
|
| 让服务端重新下发凭证 |
|
| 凭证一次性,重新下发 |
| World 不存在、已删除或不属于当前开发者(含 | 重新选择有效 World |
| 世界状态非就绪 | 等世界就绪后再开始 |
| 输入内容违规(内容安审);适用于 | 修改输入内容后重试 |
| 当前规格未开通 | 不可按容量满重试;换已开通规格或联系开通 |
| 容量配置暂不可用 | 稍后重试 |
| Travel 资源不存在或 ID 不归属当前账号 | 重新开始 Travel |
| 请求与当前资源状态冲突 | 检查 Travel 状态 |
| 当前规格并发已满 | 等已有会话结束后重试(勿与 |
| 当前可用容量不足 | 稍后重试 |
| 推理资源分配/服务内部失败 | 稍后重试 |
| 系统内部错误 | 稍后重试 / 反馈 |
客户端本地错误码
说明「是否致命」专指是否触发 SDK 自动终止本次体验:
100001/100002/103xxx这类同步校验错误只会拒绝/抛出该次调用(100002直接使初始化失败),不会终止体验。- SDK 自动终止本次体验分为四类:① 内部轮询读到
failed;② 实时连接致命(105001/105002/105003);③ 无推流自动结束(105006);④ SDK 被远程禁用(108001)。
code | 含义 | 是否致命 | 建议处理 |
|---|---|---|---|
| SDK 未初始化即调用 | 调用拒绝 | 先 |
| SDK 初始化时 | 初始化失败 | 传入非空的完整模型名称及版本后重新 |
| 未注入百炼网关 API Key | 否 |
|
| 百炼网关 Bearer API Key 已过期或被拒绝。注意:这是网关 Bearer Key,不是一次性 ticket;ticket 级别的凭证错误由六位服务端 code 标识(如 | 否 | 重新获取 Bearer Key 后 |
| 当前无活跃体验 | 调用拒绝 | 先 |
| 当前状态不允许该操作(含:状态不符、 | 调用拒绝 | 检查体验状态与模式;ScriptList 模式( |
| 模式不匹配:实时导演或角色演绎 下调用了 | 调用拒绝 | 检查当前模式是否匹配接口要求 |
| 并发调用 | 调用拒绝 | 等待 |
| 实时连接失败 | 是 | 结束并重新开始 |
| 实时入会超时 | 是 | 结束并重新开始 |
| 等待视频首帧超时 | 是 | 结束并重新开始 |
| 实时通道未就绪/发送失败(如 DataChannel 连接中断或实时通道异常) | 否 | 确认实时通道已就绪, |
| SDK 网关 HTTP 信令调用在 | 否 | 建议重试,或调大 |
| 无推流自动结束:首帧从未到达,或运行中推流中断且超时未恢复。SDK 会主动结束本次体验 | 是 | 结束并重新开始 |
| 本地网络错误 | 否 | 可重试 |
| 响应解析失败 | 否 | 用户主动调用时抛给调用方;内部状态轮询时仅 |
| 上游服务返回无法识别的错误响应,SDK 已将原始信息保留在 | 否 | 可重试;若持续出现,结合 |
| SDK 被远程禁用(整体关停或版本过低);原因在 | 是(SDK 感知到禁用结果时会自动结束进行中的体验;恢复后可重新开始) | 按 |
致命 vs 非致命
致命错误:SDK 会自动终止本次体验(断开实时连接、释放资源、调用 endTravel),并通过 onError 透出;宿主应清理本次体验状态并允许重新开始。共四类:
- ① 内部状态轮询读到体验状态
failed(如500001推理失败) - ② 实时连接致命(
105001/105002/105003) - ③ 无推流自动结束(
105006:首帧从未到达,或运行中推流中断且超时未恢复,SDK 主动结束) - ④ SDK 被远程禁用(
108001)
非致命错误:不终止体验,仅通过 onError 透出;你可重新 updateToken 或等待服务 / 实时通道恢复后继续。内部状态轮询自身的单次请求失败(网络 106001、解析 106002、上游异常 106003、业务错误 5xxxxx)属于此类——轮询会在下一周期继续,只有它读到状态 failed 才会结束体验;鉴权失败 101001、sendCommand 节流 flush 的异步发送失败 105004 同样为非致命。注:SDK 不会自行向实时通道发送任何保活报文,因此空闲期不会出现 105004——该错误只可能由你主动调用 sendCommand 触发。