Ti 云存 Android API 参考
本文列出 Android 中 Ti 云存与通用 Media 的公开 API、返回结果和行为约定。第一次接入时,建议先阅读 Ti 云存 API 总览。
包名:
import android.content.Context
import android.net.Uri
import android.view.ViewGroup
import com.tange.ai.tirtc.*同步命令返回 Int 错误码,TiCloudStorageErrorCode.OK 表示当前调用成功。Kotlin 的一次性异步操作使用 suspend 返回具体 Result;Java 使用对应 callback。需要业务分支处理的错误通过 TiCloudStorageErrorCode 提供公开常量;完整含义和处理建议见错误码。TiCloudStorage.errorToString(code) 只用于展示或诊断。
基础类型
data class TiCloudStorageRecordingRange(
val startTimeMs: Long,
val endTimeMs: Long,
)
enum class TiCloudStorageReplaySpeed { X0_125, X0_25, X0_5, X1, X2, X4, X8 }
data class TiCloudStorageRecordingRangesResult(
val code: Int,
val recordings: List<TiCloudStorageRecordingRange>,
)
fun interface TiCloudStorageRecordingsCallback {
fun onResult(result: TiCloudStorageRecordingRangesResult)
}
fun interface TiCloudStorageTimeChangedListener {
fun onTimeChanged(timeMs: Long)
}
fun interface TiCloudStorageReplayErrorListener {
fun onError(code: Int)
}
fun interface TiCloudStorageReplayCompletedListener {
fun onCompleted()
}TiCloudStorageRecordingRange
一段存在云录像的可用时间。
| 字段 | 说明 |
|---|---|
startTimeMs | 开始时间,UTC Unix 毫秒 |
endTimeMs | 结束时间,UTC Unix 毫秒;必须晚于 startTimeMs |
TiCloudStorageRecordingDay
| 字段 | 说明 |
|---|---|
date | 严格 YYYY-MM-DD 日期 |
hasRecording | 该自然日至少有一个当前可见录像时点时为 true |
TiCloudStorageReplaySpeed
| 枚举值 | 说明 |
|---|---|
X0_125 | 1/8 倍速,视频慢放,音频静音 |
X0_25 | 1/4 倍速,视频慢放,音频静音 |
X0_5 | 1/2 倍速,视频慢放,音频静音 |
X1 | 1 倍速,播放音频和视频 |
X2 | 2 倍速,视频播放,音频静音 |
X4 | 4 倍速,视频播放,音频静音 |
X8 | 8 倍速,视频播放,音频静音 |
Result、Callback 与 Listener
| 类型 | 参数 | 说明 |
|---|---|---|
TiCloudStorageRecordingRangesResult | code 与 recordings | listRecordings 的一次性结果;成功但没有录像时列表为空 |
TiCloudStorageRecordingsCallback | result | Java 调用 listRecordings 时接收同一个一次性结果 |
TiCloudStorageRecordingDaysResult | code 与 days | listRecordingDays 的一次性结果 |
TiCloudStorageRecordingDaysCallback | result | Java 调用 listRecordingDays 时接收同一个一次性结果 |
TiCloudStorageTimeChangedListener | timeMs:当前播放位置,UTC Unix 毫秒 | 回放位置变化通知 |
TiCloudStorageReplayErrorListener | code:回放错误码 | Token、权限、网络或录像读取错误通知 |
TiCloudStorageReplayCompletedListener | 无 | 当前 play 的时间范围自然耗尽通知 |
Result 只承接一次方法调用的唯一终局。Callback 是 Java 对同一结果的互操作入口;Listener 绑定对象,在对象生命周期内可以收到多次状态或事件通知。
使用可用时间段开始回放
selectedRecording 是从 listRecordings 返回结果中选择的一段录像。下面只展示正常调用顺序;回放期间保持 replay、videoOutput 和 audioOutput 有效。
val initCode = TiCloudStorage.init(applicationContext, appId)
if (initCode != TiCloudStorageErrorCode.OK) return
val cloudStorage = TiCloudStorage(token)
val replay = cloudStorage.createReplay()
val videoOutput = TiCloudStorageVideoOutput()
val audioOutput = TiCloudStorageAudioOutput()
replay.onError = TiCloudStorageReplayErrorListener { code ->
showReplayError(code)
}
replay.onCompleted = TiCloudStorageReplayCompletedListener {
showReplayCompleted()
}
videoOutput.attachView(videoContainer)
videoOutput.attach(replay, videoChannelId)
audioOutput.attach(replay, audioChannelId)
replay.play(
selectedRecording.startTimeMs,
selectedRecording.endTimeMs,
)同步方法返回非 TiCloudStorageErrorCode.OK 时,当前操作没有生效。通过两个 Output 的状态更新播放界面;Token、网络或录像读取失败时,在 Replay 的错误 listener 中处理。
页面退出时,先停止 Replay,detach 两个 Output,并调用 videoOutput.detachView()。随后依次 dispose Output 和 Replay。不再访问这台设备时 dispose cloudStorage;应用不再使用 Ti 云存时,最后调用 TiCloudStorage.shutdown()。
TiCloudStorage
class TiCloudStorage(token: String) {
companion object {
@JvmStatic
@JvmOverloads
fun init(
context: Context,
appId: String,
endpoint: String = "",
consoleLogEnabled: Boolean = false,
): Int
@JvmStatic
fun shutdown(): Int
@JvmStatic
fun errorToString(code: Int): String
}
fun updateToken(token: String): Int
@JvmSynthetic
suspend fun listRecordingDays(
startDate: String,
endDate: String,
timeZoneId: String = "Asia/Shanghai",
): TiCloudStorageRecordingDaysResult
fun listRecordingDays(
startDate: String,
endDate: String,
callback: TiCloudStorageRecordingDaysCallback,
)
fun listRecordingDays(
startDate: String,
endDate: String,
timeZoneId: String,
callback: TiCloudStorageRecordingDaysCallback,
)
@JvmSynthetic
suspend fun listRecordings(
startTimeMs: Long,
endTimeMs: Long,
): TiCloudStorageRecordingRangesResult
fun listRecordings(
startTimeMs: Long,
endTimeMs: Long,
callback: TiCloudStorageRecordingsCallback,
)
fun createReplay(): TiCloudStorageReplay
fun exportRecording(
request: TiCloudStorageExportRequest,
progressListener: TiCloudStorageExportProgressListener?,
callback: TiCloudStorageRecordingCallback,
): TiCloudStorageExportTaskStartResult
fun dispose(): Int
}使用任何 Ti 云存 API 前先调用 TiCloudStorage.init。初始化后用一台设备的非空 Token 创建 TiCloudStorage 实例;构造不发起网络请求。同时访问多台设备时创建多个实例。释放全部 TiCloudStorage 实例、Replay、Output 和任务后调用 TiCloudStorage.shutdown()。
TiRTC 与 Ti 云存可以在同一进程共存,两者可以使用不同的 App ID 和 endpoint。由 Context.cacheDir/tirtc 解析出的工作根目录和 consoleLogEnabled 由两者共享,因此配置必须一致。Runtime 在该目录下管理日志、日志归档和临时媒体文件。初始化第二项服务不会重启 Runtime;共享配置不一致时返回 already-initialized,已初始化的服务不受影响。调用 TiCloudStorage.shutdown() 不会停止 TiRTC。
TiCloudStorage.shutdown() 在尚未初始化或已经关闭时幂等返回成功;仍有活动资源时返回 in-use。在对象回调中同步停止、解绑或释放当前对象及其关联资源,也会返回 in-use 且不改变状态。其他无关实例和资源不受此限制。
cloudStorage.dispose() 只有在底层资源释放成功后才使实例失效。若返回 in-use 或其他错误,实例和当前 Token 仍然有效;清理占用资源后可以重试。SDK 不负责清除调用方持有的 Token 字符串。
| API | 说明 |
|---|---|
init(context, appId, endpoint, consoleLogEnabled) | 初始化 Ti 云存。context 传 applicationContext;appId 必填;endpoint 留空时使用默认服务地址;consoleLogEnabled 默认为 false。返回本次初始化错误码 |
shutdown() | 关闭 Ti 云存。调用前必须释放所有 TiCloudStorage 实例、Replay、Output,并等待查询、截图和文件 Task 完成;仍有活动资源时返回错误码 |
errorToString(code) | 返回错误码对应的稳定名称,用于日志和诊断 |
updateToken(token) | 为同一设备更新 Token,只影响之后启动的 List、Play 和 Export |
listRecordingDays(startDate, endDate, timeZoneId) | Kotlin 查询包含式日期范围,单次最多 31 天。timeZoneId 使用 IANA ID,默认 Asia/Shanghai;结果完整包含 true/false 日期并按日期升序排列 |
listRecordingDays(startDate, endDate, callback) | Java 使用默认时区的互操作入口 |
listRecordingDays(startDate, endDate, timeZoneId, callback) | Java 使用显式 IANA 时区的互操作入口;结果在主线程恰好返回一次 |
listRecordings(startTimeMs, endTimeMs) | Kotlin 查询当前设备在 [startTimeMs, endTimeMs) 内的录像可用时间段,挂起并返回唯一的 TiCloudStorageRecordingRangesResult。时间使用 UTC Unix 毫秒,单次跨度最长 10 天 |
listRecordings(startTimeMs, endTimeMs, callback) | Java 互操作入口。包括参数、Token、对象状态和运行期错误在内,均由 callback 在主线程恰好返回一次,不同步返回另一份错误码 |
createReplay() | 创建属于当前设备的 Replay |
exportRecording(request, progressListener, callback) | 开始一次录像导出。进度监听器可空;同步结果包含错误码和可空 Task,接受成功后 callback 返回唯一终局 |
dispose() | 释放当前设备实例;仍有查询、Replay、ExportTask 或 callback barrier 时返回 in-use |
Token 过期由触发它的 List、Play 或 Export 直接报告 TOKEN_EXPIRED。SDK 不另发过期通知,也不自动刷新或重试。应用取得同一设备的新 Token、调用 updateToken,再显式重做失败的操作。不同非空 Token 建立新的授权代际,只影响之后启动的操作;相同 Token 不清除已确定的过期状态。访问另一台设备时创建新的 TiCloudStorage。
List 结果按 startTimeMs 升序排列并裁剪在请求的 [startTimeMs, endTimeMs) 内;重叠或首尾相接的时间段会合并,任何大于 0 的空洞都保留为不同项。结果是设备级完整快照,不保证每个 Channel 都有媒体,也不分页。合并后最多返回 10000 项;查询跨度或结果数量超限时整体返回 range-too-large,不返回部分结果;成功但没有录像时返回空列表。
TiCloudStorageReplay
class TiCloudStorageReplay private constructor() {
val speed: TiCloudStorageReplaySpeed
val currentTimeMs: Long?
var onTimeChanged: TiCloudStorageTimeChangedListener?
var onError: TiCloudStorageReplayErrorListener?
var onCompleted: TiCloudStorageReplayCompletedListener?
fun play(
startTimeMs: Long,
endTimeMs: Long,
initialTimeMs: Long? = null,
): Int
fun pause(): Int
fun resume(): Int
fun seek(timeMs: Long): Int
fun setSpeed(speed: TiCloudStorageReplaySpeed): Int
fun startRecording(
videoChannelId: Int,
audioChannelId: Int? = null,
): TiCloudStorageRecordingTaskStartResult
fun stop(): Int
fun dispose(): Int
}属性与 Listener
| 成员 | 说明 |
|---|---|
speed | 当前回放倍速,初始值为 X1 |
currentTimeMs | 当前回放位置,UTC Unix 毫秒;首次取得位置前和 stop 后为 null |
onTimeChanged | 回放位置变化通知;晚设置时不会补发之前的事件 |
onError | 当前 play 的 Token、权限、网络或录像读取错误;一次回放最多通知一次 |
onCompleted | 当前 play 的时间范围自然耗尽通知;一次回放最多通知一次 |
方法
| API | 说明 |
|---|---|
play(startTimeMs, endTimeMs, initialTimeMs) | 播放所属设备在 [startTimeMs, endTimeMs) 内的录像。initialTimeMs 可空,缺省时从 startTimeMs 开始;传入时从指定位置开始。返回值表示请求是否被接受 |
pause() | 暂停当前回放;重复调用成功 |
resume() | 继续当前回放;重复调用成功 |
seek(timeMs) | 定位到当前回放范围内的 UTC 时间;同步返回操作是否被接受 |
setSpeed(speed) | 设置七档固定速度;非 X1 时 Audio Output 静音,慢放画面采用持帧显示 |
startRecording(videoChannelId, audioChannelId) | 保存当前回放的一段内容。同步结果包含错误码和可空 RecordingTask |
stop() | 停止当前回放并清除 currentTimeMs;保留 Output 绑定和倍速 |
dispose() | 释放 Replay;调用后不能继续使用该实例 |
Replay 只能由 cloudStorage.createReplay() 创建,并固定属于该设备实例。Replay 没有公开 state。onTimeChanged 返回当前播放时间;onError 返回当前 play 过程中发生的 Token、权限、网络或录像读取错误。错误发生时恰好调用一次;同步拒绝、主动 stop、被新 play 替换或自然完成不会触发。onCompleted 是 Replay 级自然终局:每个被接受的 play 仅在其时间范围自然耗尽时恰好调用一次;同步拒绝、主动 stop、被新 play 替换或错误终止均不触发。开始 play 前设置 listener,晚设置不会重放此前错误或完成事件。接受 Play 时固定使用 TiCloudStorage 实例当前的 Token,之后更新 Token 不改变本次回放。
录像文件已被删除、缺失、损坏或无法读取时,onError 返回 TiCloudStorageErrorCode.RECORDING_UNREADABLE。网络或服务暂时不可用时,返回 TiCloudStorageErrorCode.CLOUD_STORAGE_UNAVAILABLE。
currentTimeMs在首次取得位置前和stop后为null;暂停时保留最后位置,自然完成时为请求的endTimeMs,回放失败时保留最后已知位置。晚设置onTimeChanged不重放旧事件,先读取属性再订阅。speed初始为X1;非X1时 Audio Output 静音。play前必须至少绑定一个 Output。onCompleted不取代 Output 的COMPLETED:前者表示 Replay 来源自然耗尽,后者只表示对应 Output 已排空。自然完成会自动终结活动 RecordingTask。play要求startTimeMs < endTimeMs;非空的initialTimeMs必须位于[startTimeMs, endTimeMs)。参数校验失败同步返回invalid-argument,原回放不受影响。成功接受后从初始位置建立新回放,不会先输出范围开头的媒体;初始位置落在空洞中时从其后的第一段录像开始,其后没有录像时按自然结束处理。- 最后一个 Output 离开且没有活动 RecordingTask 时,Replay 停止读取来源,但不触发
onCompleted。 - 新
play被接受后原回放停止,但保留 Output 绑定、Audio Output 音量和速度;同步拒绝时原回放不受影响。 pause和resume分别幂等;尚未开始、已经stop、自然完成或失败时返回not-started。- Seek 只能在当前
play仍在运行或暂停时调用,目标必须位于当前[startTimeMs, endTimeMs)。回放未活动或目标越界时,分别同步返回not-started或invalid-argument,当前回放不受影响。自然完成后要从指定位置重新播放时,调用带initialTimeMs的play。 - Seek 保留速度和暂停意图,连续调用采用 latest-wins。定位生效后,
currentTimeMs和onTimeChanged更新为第一个不早于目标的可播放位置。目标合法但其后没有录像时,位置推进到endTimeMs并按自然结束触发onCompleted。 stop幂等,不触发onCompleted,也不把 Output 标记为COMPLETED;它会清除currentTimeMs,并保留 Output 绑定和速度。
Audio/Video Output 扩展
enum class TiCloudStorageAudioOutputState {
IDLE,
BUFFERING,
PLAYING,
FAILED,
PAUSED,
COMPLETED,
}
enum class TiCloudStorageVideoOutputState {
IDLE,
BUFFERING,
RENDERING,
FAILED,
PAUSED,
COMPLETED,
}
fun interface TiCloudStorageAudioOutputStateListener {
fun onStateChanged(state: TiCloudStorageAudioOutputState)
}
fun interface TiCloudStorageVideoOutputStateListener {
fun onStateChanged(state: TiCloudStorageVideoOutputState)
}
fun interface TiCloudStorageOutputErrorListener {
fun onError(code: Int)
}
class TiCloudStorageAudioOutput {
val state: TiCloudStorageAudioOutputState
var onStateChanged: TiCloudStorageAudioOutputStateListener?
var onError: TiCloudStorageOutputErrorListener?
fun attach(replay: TiCloudStorageReplay, channelId: Int): Int
fun setVolume(volumePercent: Int): Int
fun detach(): Int
fun dispose(): Int
}
class TiCloudStorageVideoOutput {
val state: TiCloudStorageVideoOutputState
var onStateChanged: TiCloudStorageVideoOutputStateListener?
var onError: TiCloudStorageOutputErrorListener?
fun attachView(container: ViewGroup): Int
fun detachView(): Int
fun attach(replay: TiCloudStorageReplay, channelId: Int): Int
@JvmSynthetic
suspend fun takeSnapshot(): TiCloudStorageSnapshotResult
fun takeSnapshot(callback: TiCloudStorageSnapshotCallback)
fun detach(): Int
fun dispose(): Int
}setVolume 接收 0..100;0 表示静音。它只调整当前 Audio Output,不修改系统全局音量。新一次 play 会保留该值。
Output 状态
| Audio 状态 | Video 状态 | 说明 |
|---|---|---|
IDLE | IDLE | 尚未输出媒体,或已经 detach |
BUFFERING | BUFFERING | 正在等待足够的媒体数据 |
PLAYING | RENDERING | 正在播放音频或渲染视频 |
PAUSED | PAUSED | Replay 已暂停 |
COMPLETED | COMPLETED | Replay 来源已经自然耗尽,并且该 Output 已排空 |
FAILED | FAILED | 当前 Output 无法继续输出媒体 |
属性与 Listener
| 成员 | 说明 |
|---|---|
state | 当前 Output 状态 |
onStateChanged | Output 状态变化通知;参数 state 为当前 Output 状态 |
onError | 当前 Output 的解码、播放或渲染错误;参数 code 为错误码,不会报告 Token、网络或录像读取错误 |
方法
| API | 适用对象 | 说明 |
|---|---|---|
attachView(container) | Video | 把 Video Output 绑定到宿主提供的 ViewGroup;重复绑定同一容器成功,换绑失败时保留原容器 |
detachView() | Video | 解除宿主 View 绑定;对象和 Replay 绑定保持不变 |
attach(replay, channelId) | Audio、Video | 绑定 Replay 中指定 channel_id 的音频或视频;channelId 取值为 0..255 |
takeSnapshot() / takeSnapshot(callback) | Video | 把当前视频画面保存为唯一的临时 JPEG;成功结果包含 TiCloudStorageSnapshotFile |
detach() | Audio、Video | 解除当前 Replay 绑定;对象仍可再次 attach |
dispose() | Audio、Video | 释放 Output;调用后不能继续使用该实例 |
attachView 与 Replay 的 attach 相互独立;SDK 借用 ViewGroup 到 detachView 成功为止,应用必须在销毁或复用容器前先解除绑定。Kotlin takeSnapshot() 挂起到唯一终局,Java callback 在主线程完成一次。成功时 file.path 是 SDK 私有 cache 中的临时 JPEG。
当前 binding generation 尚未出画时,callback 返回 no-frame。暂停或自然播放完成后,只要最后画面仍然保留,就可以继续截图;attach 新来源、新的 play 生效、detachView 或 detach 后,在新画面到达前返回 no-frame。同一个 Video Output 同时只接受一个 Snapshot;已有请求未完成时,新的 callback 返回 in-use。不同 Output 仍可能因全局资源上限返回 resource-exhausted。
Snapshot callback 返回前,dispose() 和 TiCloudStorage.shutdown() 返回 in-use,Output、View 与 Replay 关系保持不变。先等待 callback,再按正常顺序解除 View 和 Replay 绑定并释放 Output。
Video Output 和 Audio Output 分别使用设备配置提供的 channelId,取值范围是 0..255;两者可以相同,也可以不同。使用 exhaustive when 时,需要处理 PAUSED 和 COMPLETED。
重复绑定同一个 Replay 的同一个 channel_id 会成功;已经绑定时传入不同 Replay 或 channel_id 返回 in-use 并保留原关系,必须先显式 detach。Replay 正在运行时新增或 detach 后重新绑定 Output,从绑定生效后的下一可独立解码位置开始,不补发此前媒体。同一个 Replay 的同一个 channel_id 只能绑定一个同类播放 Output。stop、自然完成和新 play 都保留绑定;dispose 不隐式解绑,关系仍存在时返回 in-use。某个 Output 解码、播放或渲染失败时,它的错误 listener 返回错误,并且只终止该 Output。Token、网络、所选范围过大或录像读取失败时,Replay 的错误 listener 返回一次错误,并使本次回放的全部 Output 进入 FAILED。
本地媒体文件
fun interface TiCloudStorageDeleteCallback {
fun onResult(code: Int)
}
class TiCloudStorageRecordingFile internal constructor(
val path: String,
val durationMs: Long,
) {
@JvmSynthetic suspend fun delete(): Int
fun delete(callback: TiCloudStorageDeleteCallback)
}
class TiCloudStorageSnapshotFile internal constructor(val path: String) {
@JvmSynthetic suspend fun delete(): Int
fun delete(callback: TiCloudStorageDeleteCallback)
}
data class TiCloudStorageRecordingResult(
val code: Int,
val file: TiCloudStorageRecordingFile?,
)
data class TiCloudStorageSnapshotResult(
val code: Int,
val file: TiCloudStorageSnapshotFile?,
)
fun interface TiCloudStorageRecordingCallback {
fun onResult(result: TiCloudStorageRecordingResult)
}
fun interface TiCloudStorageSnapshotCallback {
fun onResult(result: TiCloudStorageSnapshotResult)
}文件路径位于 SDK 私有 cache。Android SDK 只提供受限、幂等的 delete();需要长期保存时由应用自行复制或移动文件。系统相册便利能力只由 Flutter 与 React Native SDK 提供。
TiCloudStorageRecordingTask
data class TiCloudStorageRecordingTaskStartResult(
val code: Int,
val task: TiCloudStorageRecordingTask?,
)
class TiCloudStorageRecordingTask {
@JvmSynthetic
suspend fun stop(): TiCloudStorageRecordingResult
fun stop(callback: TiCloudStorageRecordingCallback)
}TiCloudStorageReplay.startRecording(videoChannelId, audioChannelId) 同步返回 TiCloudStorageRecordingTaskStartResult。Replay 必须正在回放;视频 Channel 必填,音频 Channel 可空。成功时 code == OK 且 task 非空;同步失败时不创建 Task。
Kotlin stop() 与 Java stop(callback) 都停止接收新媒体,排空已经接收的数据并完成 MP4。重复或并发调用取得同一个终局。Replay 自然结束时 Task 自动完成,之后调用 stop 返回缓存结果。
Task 不公开 state、实时 duration、cancel 或 dispose。停止一个 Task 不影响 Replay 或其他 Task。相同 Channel 可以创建多个 Task,SDK 为每个 Task 生成不同文件;两个视频 Channel 使用两个 Task。
TiCloudStorageExportTask
data class TiCloudStorageExportRequest(
val startTimeMs: Long,
val endTimeMs: Long,
val videoChannelId: Int,
val audioChannelId: Int? = null,
)
data class TiCloudStorageExportTaskStartResult(
val code: Int,
val task: TiCloudStorageExportTask?,
)
fun interface TiCloudStorageExportProgressListener {
fun onProgress(progress: Double)
}
class TiCloudStorageExportTask {
val progress: Double
fun stop(): Int
}cloudStorage.exportRecording(request, progressListener, callback) 在启动 Task 前固定实例当前的 Token,并保存两个回调,然后同步返回 TiCloudStorageExportTaskStartResult。成功时 Task 已经开始,进度与最终结果在主线程返回。
同步失败时 task == null,且不调用回调。SDK 也不会在 exportRecording 返回前调用回调。
progress 位于 0.0..1.0 且单调不回退。只有 MP4 完整生成后才到达 1.0。中间通知可以合并,progress 始终返回当前快照。
活动 Task 调用 stop() 会停止导出、清理临时文件,并使同一个终局 callback 返回 STOPPED 和 file == null;它不生成部分 MP4。已经自然完成或失败时,stop() 返回 OK 且不改变缓存终局。重复调用幂等。
Task 在终局 callback 返回后自动释放 Native 执行资源,不提供 dispose。不同 Task 相互独立并生成不同 cache 文件;资源达到上限返回 RESOURCE_EXHAUSTED。
错误码
| 错误码 | 常量 | 常见含义 | 建议处理 |
|---|---|---|---|
| 0 | TiCloudStorageErrorCode.OK | 操作成功 | 继续后续流程 |
| 6000 | TiCloudStorageErrorCode.INVALID_ARGUMENT | 参数缺失、取值越界或时间范围无效 | 修正参数后重试 |
| 6001 | TiCloudStorageErrorCode.NOT_INITIALIZED | 尚未初始化 TiCloudStorage,或已经关闭 | 先调用 TiCloudStorage.init |
| 6014 | TiCloudStorageErrorCode.TOKEN_EXPIRED | Ti 云存 Token 已过期 | 为同一设备更新 Token 后重新发起请求 |
| 6022 | TiCloudStorageErrorCode.ALREADY_INITIALIZED | 已使用另一组配置初始化 | 保持初始化参数一致,或在全部资源释放后重新初始化 |
| 6024 | TiCloudStorageErrorCode.PERMISSION_DENIED | Token 无效,或无权访问目标设备或录像 | 检查授权并重新取得 Token |
| 6026 | TiCloudStorageErrorCode.IN_USE | 对象仍在播放、录制或执行任务,当前操作不能执行 | 先结束活动操作,再重试 |
| 6027 | TiCloudStorageErrorCode.NOT_STARTED | 尚未开始播放或录制 | 先启动对应操作 |
| 6029 | TiCloudStorageErrorCode.NOT_BOUND | 尚未建立当前操作要求的绑定 | 完成对应绑定后重试 |
| 6030 | — | 缺少必要的目标或媒体通道配置 | 补充通道或目标配置后重试 |
| 6043 | TiCloudStorageErrorCode.RESOURCE_EXHAUSTED | 当前设备没有足够资源创建或继续任务 | 结束其他任务并释放资源后重试 |
| 6046 | TiCloudStorageErrorCode.FILE_WRITE_FAILED | 无法创建或写入输出文件 | 检查目录权限和磁盘空间 |
| 6113 | TiCloudStorageErrorCode.UNSUPPORTED_FORMAT | 录像的音视频格式不受支持 | 提示当前录像无法播放或导出 |
| 6115 | TiCloudStorageErrorCode.CANCELLED | List 请求被取消 | 结束对应等待 |
| 6117 | TiCloudStorageErrorCode.RANGE_TOO_LARGE | List 查询跨度超过 10 天或合并结果超过 10000 项 | 缩短查询范围后重试 |
| 6118 | TiCloudStorageErrorCode.NO_FRAME | Video Output 尚无可用于截图的视频帧 | 等待出画后重试 |
| 6119 | TiCloudStorageErrorCode.NO_RECORDABLE_MEDIA | 所选范围或通道没有可写入的媒体 | 重新选择录像范围或通道 |
| 6120 | TiCloudStorageErrorCode.RECORDING_OVERRUN | 本地写入持续跟不上回放数据,保存任务已经终止 | 释放设备资源、检查存储性能后重新保存 |
| 6122 | TiCloudStorageErrorCode.RECORDING_UNREADABLE | 录像文件缺失、损坏或无法读取 | 提示当前录像不可用,不要持续重试同一请求 |
| 6123 | TiCloudStorageErrorCode.CLOUD_STORAGE_UNAVAILABLE | 网络、Ti 云存服务或录像数据读取暂时不可用 | 稍后重试 |
| 6124 | TiCloudStorageErrorCode.STOPPED | 活动 ExportTask 已被主动停止 | 结束导出进度,不使用输出文件 |
常量列为“—”的错误通常表示调用顺序或资源状态问题,记录数值用于定位即可,不需要在业务流程中逐项判断。不要根据 errorToString 返回值或日志文本判断错误类型。
线程、生命周期与 Java 互操作
- 所有 callback/listener 都进入 Android 主线程。
- SDK 不在发起 API 调用的栈内同步调用 callback。
- Kotlin
listRecordings返回到调用方 coroutine;@JvmSynthetic入口不向 Java 暴露。 - callback 参数是不可变的 Kotlin/Java 值对象。
dispose是 checked 且可重试的:Replay 仍在播放、仍有 Output 绑定或活动 RecordingTask,或者 Output 仍绑定 Replay、宿主 View 或活动 Snapshot 时返回in-use。失败时对象及关系保持不变。dispose只有在 native destroy 真正成功后才返回OK;重复调用幂等返回OK。成功后普通方法返回not-initialized,getter 保留最后提交值,SDK 不再投递该对象的普通 listener。- MP4 Task 在终局 callback 返回后自动释放 Native 执行资源;Java/Kotlin 不需要额外 dispose。
TiCloudStorage和 Output 的构造器只创建 Kotlin wrapper,不抛 SDK 运行错误;createReplay同样只建立 Replay wrapper。第一次需要 Native 资源的方法返回创建错误,wrapper 保持可重试。
Java 可以直接使用一次性 callback;不关心导出进度时无需实现额外接口:
TiCloudStorage cloudStorage = new TiCloudStorage(token);
cloudStorage.listRecordings(startTimeMs, endTimeMs, result -> {
if (result.getCode() == TiCloudStorageErrorCode.OK) {
showRecordings(result.getRecordings());
}
});
TiCloudStorageExportTaskStartResult exportStart = cloudStorage.exportRecording(
request,
null,
result -> showExportResult(result)
);