Android API 说明
Android 通过 TiRTC SDK 查询、回放、截图和导出云录像。
安装和初始化见 Android SDK 接入。查询、播放、下载和截图见播放录像。
包名:
import android.content.Context
import android.net.Uri
import android.view.ViewGroup
import com.tange.ai.tirtc.*同步命令返回 Int 错误码,TiStoreErrorCode.OK 表示当前调用成功。Kotlin 的一次性异步操作使用 suspend 返回具体 Result;Java 使用对应 callback。需要业务分支处理的错误通过 TiStoreErrorCode 提供公开常量;完整含义和处理建议见错误码。TiStore.errorToString(code) 只用于展示或诊断。
基础类型
data class TiStoreRecordingRange(
val startTimeMs: Long,
val endTimeMs: Long,
)
data class TiStoreRecordingDay(
val date: String,
val hasRecording: Boolean,
)
enum class TiStoreReplaySpeed { X1, X2, X4, X8 }
data class TiStoreRecordingRangesResult(
val code: Int,
val recordings: List<TiStoreRecordingRange>,
)
fun interface TiStoreRecordingsCallback {
fun onResult(result: TiStoreRecordingRangesResult)
}
data class TiStoreRecordingDaysResult(
val code: Int,
val days: List<TiStoreRecordingDay>,
)
fun interface TiStoreRecordingDaysCallback {
fun onResult(result: TiStoreRecordingDaysResult)
}
fun interface TiStoreTimeChangedListener {
fun onTimeChanged(timeMs: Long)
}
fun interface TiStoreReplayErrorListener {
fun onError(code: Int)
}
fun interface TiStoreReplayCompletedListener {
fun onCompleted()
}
fun interface TiStoreTokenExpiredListener {
fun onTokenExpired()
}TiStoreRecordingRange
一段存在云录像的可用时间。
| 字段 | 说明 |
|---|---|
startTimeMs | 开始时间,UTC Unix 毫秒 |
endTimeMs | 结束时间,UTC Unix 毫秒;必须晚于 startTimeMs |
TiStoreRecordingDay
| 字段 | 说明 |
|---|---|
date | 严格的 YYYY-MM-DD 日期 |
hasRecording | 该自然日至少有一个当前可见的录像时点时为 true |
TiStoreReplaySpeed
| 枚举值 | 说明 |
|---|---|
X1 | 1 倍速,播放音频和视频 |
X2 | 2 倍速,视频播放,音频静音 |
X4 | 4 倍速,视频播放,音频静音 |
X8 | 8 倍速,视频播放,音频静音 |
Result、Callback 与 Listener
| 类型 | 参数 | 说明 |
|---|---|---|
TiStoreRecordingRangesResult | code 与 recordings | listRecordings 的一次性结果;成功但没有录像时列表为空 |
TiStoreRecordingsCallback | result | Java 调用 listRecordings 时接收同一个一次性结果 |
TiStoreRecordingDaysResult | code 与 days | listRecordingDays 的一次性逐日结果 |
TiStoreRecordingDaysCallback | result | Java 调用 listRecordingDays 时接收同一个一次性结果 |
TiStoreTimeChangedListener | timeMs:当前播放位置,UTC Unix 毫秒 | 回放位置变化通知 |
TiStoreReplayErrorListener | code:回放错误码 | Token、权限、网络或录像读取错误通知 |
TiStoreReplayCompletedListener | 无 | 当前 play 的时间范围自然耗尽通知 |
Result 只返回一次方法调用的最终结果。Callback 是 Java 接收同一结果的入口;Listener 绑定对象,在对象生命周期内可以收到多次状态或事件通知。
最小回放示例
selectedRecording 是从 listRecordings 返回结果中选择的一段录像。回放期间保持 replay、videoOutput 和 audioOutput 有效。
val initCode = TiStore.init(applicationContext, appId)
if (initCode != TiStoreErrorCode.OK) return
val store = TiStore(token)
val replay = store.createReplay()
val videoOutput = TiStoreVideoOutput()
val audioOutput = TiStoreAudioOutput()
replay.onError = TiStoreReplayErrorListener { code ->
showReplayError(code)
}
replay.onCompleted = TiStoreReplayCompletedListener {
showReplayCompleted()
}
videoOutput.attachView(videoContainer)
videoOutput.attach(replay, videoChannelId)
audioOutput.attach(replay, audioChannelId)
replay.play(
selectedRecording.startTimeMs,
selectedRecording.endTimeMs,
)同步方法返回非 TiStoreErrorCode.OK 时,当前操作没有生效。通过两个 Output 的状态更新播放界面;Token、网络或录像读取失败时,在 Replay 的错误 listener 中处理。
页面退出时,先停止 Replay、detach 两个 Output,并调用 videoOutput.detachView()。再依次 dispose Output 和 Replay。不再访问这台设备时,dispose store。
TiStore
class TiStore(token: String) {
companion object {
@JvmStatic
@JvmOverloads
fun init(
context: Context,
appId: String,
endpoint: String = "",
consoleLogEnabled: Boolean = false,
): Int
@JvmStatic
fun errorToString(code: Int): String
}
var onTokenExpired: TiStoreTokenExpiredListener?
fun updateToken(token: String): Int
@JvmSynthetic
suspend fun listRecordingDays(
startDate: String,
endDate: String,
timeZoneId: String = "Asia/Shanghai",
): TiStoreRecordingDaysResult
fun listRecordingDays(
startDate: String,
endDate: String,
callback: TiStoreRecordingDaysCallback,
)
fun listRecordingDays(
startDate: String,
endDate: String,
timeZoneId: String,
callback: TiStoreRecordingDaysCallback,
)
@JvmSynthetic
suspend fun listRecordings(
startTimeMs: Long,
endTimeMs: Long,
): TiStoreRecordingRangesResult
fun listRecordings(
startTimeMs: Long,
endTimeMs: Long,
callback: TiStoreRecordingsCallback,
)
fun createReplay(): TiStoreReplay
fun exportRecording(
request: TiStoreExportRequest,
progressListener: TiStoreExportProgressListener?,
callback: TiStoreRecordingCallback,
): TiStoreExportTaskStartResult
fun dispose(): Int
}使用任何云存储 API 前先调用 TiStore.init。初始化后用一台设备的非空 Token 创建 TiStore 实例;构造不发起网络请求。同时访问多台设备时创建多个实例。
| API | 说明 |
|---|---|
init(context, appId, endpoint, consoleLogEnabled) | 初始化。context 传 applicationContext;appId 来自申请开通;endpoint 留空时使用默认服务地址;consoleLogEnabled 默认为 false。返回本次初始化错误码 |
errorToString(code) | 返回错误码对应的稳定名称,用于日志和诊断 |
updateToken(token) | 为同一设备更新 Token,只影响之后启动的 List、Play 和 Export |
listRecordingDays(startDate, endDate, timeZoneId) | Kotlin 查询包含式日期范围,单次最多 31 天。时区使用 IANA ID,默认 Asia/Shanghai;结果按日期升序返回范围内每一天 |
listRecordingDays(startDate, endDate, callback) | Java 使用默认时区查询,结果在主线程返回一次 |
listRecordingDays(startDate, endDate, timeZoneId, callback) | Java 使用显式 IANA 时区查询,结果在主线程返回一次 |
listRecordings(startTimeMs, endTimeMs) | Kotlin 查询当前设备在 [startTimeMs, endTimeMs) 内的录像可用时间段,挂起并返回唯一的 TiStoreRecordingRangesResult。时间使用 UTC Unix 毫秒,单次跨度最长 10 天 |
listRecordings(startTimeMs, endTimeMs, callback) | Java 互操作入口。包括参数、Token、对象状态和运行期错误在内,均由 callback 在主线程恰好返回一次,不同步返回另一份错误码 |
createReplay() | 创建属于当前设备的 Replay |
exportRecording(request, progressListener, callback) | 开始一次录像导出。进度监听器可空;同步结果包含错误码和可空 Task,接受成功后 callback 返回唯一的最终结果 |
dispose() | 释放当前设备实例;仍有查询、Replay、ExportTask 或回调正在执行时返回 in-use |
onTokenExpired 只在实例当前 Token 被云端明确判定为过期时通知,同一个 Token 至多一次。触发过期的 List、Play 或 Export 先通过自身结果或 listener 报告错误;Token 无效或权限不足不触发该 listener。当前 Token 已经确定过期时,新的 List 通过唯一 Result 返回 TOKEN_EXPIRED,新的 Play 或 Export 在启动调用中同步拒绝。updateToken 保存不同的非空 Token,之后启动的操作使用新 Token;相同 Token 不清除过期状态,已经开始的操作也不自动换证或重试。它只用于同一设备续签,访问另一台设备时创建新的 TiStore。
listRecordingDays 的起止日期都使用严格的 YYYY-MM-DD 格式并包含在结果中。成功结果包含范围内每一天,包括 hasRecording == false 的日期。时区必须是有效的 IANA ID;范围超过 31 天时返回 range-too-large。
listRecordings 结果按 startTimeMs 升序排列,并裁剪在请求的 [startTimeMs, endTimeMs) 内。重叠或首尾相接的时间段会合并;任何大于 0 的空洞都会保留为不同项。结果是设备级完整快照,不保证每个 Channel 都有媒体,也不分页。合并后最多返回 10000 项。查询跨度或结果数量超限时,整体返回 range-too-large,不返回部分结果;成功但没有录像时返回空列表。
TiStoreReplay
class TiStoreReplay private constructor() {
val speed: TiStoreReplaySpeed
val currentTimeMs: Long?
var onTimeChanged: TiStoreTimeChangedListener?
var onError: TiStoreReplayErrorListener?
var onCompleted: TiStoreReplayCompletedListener?
fun play(
startTimeMs: Long,
endTimeMs: Long,
initialTimeMs: Long? = null,
): Int
fun pause(): Int
fun resume(): Int
fun seek(timeMs: Long): Int
fun setSpeed(speed: TiStoreReplaySpeed): Int
fun startRecording(
videoChannelId: Int,
audioChannelId: Int? = null,
): TiStoreRecordingTaskStartResult
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、X2、X4 或 X8 倍速;非 X1 时 Audio Output 静音 |
startRecording(videoChannelId, audioChannelId) | 保存当前回放的一段内容。同步结果包含错误码和可空 RecordingTask |
stop() | 停止当前回放并清除 currentTimeMs;保留 Output 绑定和倍速 |
dispose() | 释放 Replay;调用后不能继续使用该实例 |
Replay 只能由 store.createReplay() 创建,并固定属于该设备实例。Replay 没有公开 state。onTimeChanged 返回当前播放时间;onError 返回当前 play 过程中发生的 Token、权限、网络或录像读取错误。错误发生时恰好调用一次;同步拒绝、主动 stop、被新 play 替换或自然完成不会触发。每个被接受的 play 仅在其时间范围自然耗尽时调用一次 onCompleted;同步拒绝、主动 stop、被新 play 替换或错误终止均不触发。开始 play 前设置 listener,晚设置不会重放此前错误或完成事件。接受 Play 时固定使用 Store 实例当前的 Token,之后更新 Token 不改变本次回放。
录像文件已被删除、缺失、损坏或无法读取时,onError 返回 TiStoreErrorCode.RECORDING_UNREADABLE。网络或服务暂时不可用时,返回 TiStoreErrorCode.STORE_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 TiStoreAudioOutputState {
IDLE,
BUFFERING,
PLAYING,
FAILED,
PAUSED,
COMPLETED,
}
enum class TiStoreVideoOutputState {
IDLE,
BUFFERING,
RENDERING,
FAILED,
PAUSED,
COMPLETED,
}
fun interface TiStoreAudioOutputStateListener {
fun onStateChanged(state: TiStoreAudioOutputState)
}
fun interface TiStoreVideoOutputStateListener {
fun onStateChanged(state: TiStoreVideoOutputState)
}
fun interface TiStoreOutputErrorListener {
fun onError(code: Int)
}
class TiStoreAudioOutput {
val state: TiStoreAudioOutputState
var onStateChanged: TiStoreAudioOutputStateListener?
var onError: TiStoreOutputErrorListener?
fun attach(replay: TiStoreReplay, channelId: Int): Int
fun setVolume(volumePercent: Int): Int
fun detach(): Int
fun dispose(): Int
}
class TiStoreVideoOutput {
val state: TiStoreVideoOutputState
var onStateChanged: TiStoreVideoOutputStateListener?
var onError: TiStoreOutputErrorListener?
fun attachView(container: ViewGroup): Int
fun detachView(): Int
fun attach(replay: TiStoreReplay, channelId: Int): Int
@JvmSynthetic
suspend fun takeSnapshot(): TiStoreSnapshotResult
fun takeSnapshot(callback: TiStoreSnapshotCallback)
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;成功结果包含 TiStoreSnapshotFile |
detach() | Audio、Video | 解除当前 Replay 绑定;对象仍可再次 attach |
dispose() | Audio、Video | 释放 Output;调用后不能继续使用该实例 |
attachView 与 Replay 的 attach 相互独立;SDK 借用 ViewGroup 到 detachView 成功为止,应用必须在销毁或复用容器前先解除绑定。Kotlin takeSnapshot() 挂起到最终结果返回,Java callback 在主线程调用一次。成功时 file.path 是 SDK 私有 cache 中的临时 JPEG。
当前绑定还没有画面时,callback 返回 no-frame。暂停或自然播放完成后,只要最后画面仍然保留,就可以继续截图;attach 新来源、新的 play 生效、detachView 或 detach 后,在新画面到达前返回 no-frame。同一个 Video Output 同时只接受一个 Snapshot;已有请求未完成时,新的 callback 返回 in-use。不同 Output 仍可能因全局资源上限返回 resource-exhausted。
Snapshot callback 返回前,dispose() 返回 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 TiStoreDeleteCallback {
fun onResult(code: Int)
}
class TiStoreRecordingFile internal constructor(
val path: String,
val durationMs: Long,
) {
@JvmSynthetic suspend fun delete(): Int
fun delete(callback: TiStoreDeleteCallback)
}
class TiStoreSnapshotFile internal constructor(val path: String) {
@JvmSynthetic suspend fun delete(): Int
fun delete(callback: TiStoreDeleteCallback)
}
data class TiStoreRecordingResult(
val code: Int,
val file: TiStoreRecordingFile?,
)
data class TiStoreSnapshotResult(
val code: Int,
val file: TiStoreSnapshotFile?,
)
fun interface TiStoreRecordingCallback {
fun onResult(result: TiStoreRecordingResult)
}
fun interface TiStoreSnapshotCallback {
fun onResult(result: TiStoreSnapshotResult)
}文件路径位于 SDK 私有 cache。Android SDK 只提供受限、幂等的 delete();需要长期保存时由应用自行复制或移动文件。系统相册便利能力只由 Flutter 与 React Native SDK 提供。
TiStoreRecordingTask
data class TiStoreRecordingTaskStartResult(
val code: Int,
val task: TiStoreRecordingTask?,
)
class TiStoreRecordingTask {
@JvmSynthetic
suspend fun stop(): TiStoreRecordingResult
fun stop(callback: TiStoreRecordingCallback)
}TiStoreReplay.startRecording(videoChannelId, audioChannelId) 同步返回 TiStoreRecordingTaskStartResult。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。
TiStoreExportTask
data class TiStoreExportRequest(
val startTimeMs: Long,
val endTimeMs: Long,
val videoChannelId: Int,
val audioChannelId: Int? = null,
)
data class TiStoreExportTaskStartResult(
val code: Int,
val task: TiStoreExportTask?,
)
fun interface TiStoreExportProgressListener {
fun onProgress(progress: Double)
}
class TiStoreExportTask {
val progress: Double
fun stop(): Int
}store.exportRecording(request, progressListener, callback) 在启动 Task 前固定实例当前的 Token,并保存两个回调。随后同步返回 TiStoreExportTaskStartResult。成功时 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 返回后自动释放底层资源,不提供 dispose。不同 Task 相互独立并生成不同 cache 文件;资源达到上限返回 RESOURCE_EXHAUSTED。
错误码
| 错误码 | 常量 | 常见含义 | 建议处理 |
|---|---|---|---|
| 0 | TiStoreErrorCode.OK | 操作成功 | 继续后续流程 |
| 6000 | TiStoreErrorCode.INVALID_ARGUMENT | 参数缺失、取值越界或时间范围无效 | 修正参数后重试 |
| 6001 | TiStoreErrorCode.NOT_INITIALIZED | 尚未初始化云存储能力,或已经关闭 | 先调用 TiStore.init |
| 6014 | TiStoreErrorCode.TOKEN_EXPIRED | Token 已过期 | 为同一设备更新 Token 后重新发起请求 |
| 6022 | TiStoreErrorCode.ALREADY_INITIALIZED | 已使用另一组配置初始化 | 保持初始化参数一致;需要更换配置时,重启应用后再初始化 |
| 6024 | TiStoreErrorCode.PERMISSION_DENIED | Token 无效,或无权访问目标设备或录像 | 检查授权并重新取得 Token |
| 6026 | TiStoreErrorCode.IN_USE | 对象仍在播放、录制或执行任务,当前操作不能执行 | 先结束活动操作,再重试 |
| 6027 | TiStoreErrorCode.NOT_STARTED | 尚未开始播放或录制 | 先启动对应操作 |
| 6029 | TiStoreErrorCode.NOT_BOUND | 尚未建立当前操作要求的绑定 | 完成对应绑定后重试 |
| 6030 | — | 缺少必要的目标或媒体通道配置 | 补充通道或目标配置后重试 |
| 6043 | TiStoreErrorCode.RESOURCE_EXHAUSTED | 当前设备没有足够资源创建或继续任务 | 结束其他任务并释放资源后重试 |
| 6046 | TiStoreErrorCode.FILE_WRITE_FAILED | 无法创建或写入输出文件 | 检查目录权限和磁盘空间 |
| 6113 | TiStoreErrorCode.UNSUPPORTED_FORMAT | 录像的音视频格式不受支持 | 提示当前录像无法播放或导出 |
| 6115 | TiStoreErrorCode.CANCELLED | List 请求被取消 | 结束对应等待 |
| 6117 | TiStoreErrorCode.RANGE_TOO_LARGE | 日期查询超过 31 天,或时间段查询超过 10 天或合并结果超过 10000 项 | 缩短查询范围后重试 |
| 6118 | TiStoreErrorCode.NO_FRAME | Video Output 尚无可用于截图的视频帧 | 等待出画后重试 |
| 6119 | TiStoreErrorCode.NO_RECORDABLE_MEDIA | 所选范围或通道没有可写入的媒体 | 重新选择录像范围或通道 |
| 6120 | TiStoreErrorCode.RECORDING_OVERRUN | 本地写入持续跟不上回放数据,保存任务已经终止 | 释放设备资源、检查存储性能后重新保存 |
| 6122 | TiStoreErrorCode.RECORDING_UNREADABLE | 录像文件缺失、损坏,或上传的格式与帧数据无法读取 | 文件缺失或损坏时停止重试;其他情况检查设备上传的格式与帧要求 |
| 6123 | TiStoreErrorCode.STORE_UNAVAILABLE | 网络、云存储服务或录像数据读取暂时不可用 | 稍后重试 |
| 6124 | TiStoreErrorCode.STOPPED | 活动 ExportTask 已被主动停止 | 结束导出进度,不使用输出文件 |
常量列为“—”的错误通常表示调用顺序或资源状态问题,记录数值用于定位即可,不需要在业务流程中逐项判断。不要根据 errorToString 返回值或日志文本判断错误类型。
线程、生命周期与 Java 互操作
- 所有 callback/listener 都进入 Android 主线程。
- SDK 不在发起 API 调用的栈内同步调用 callback。
- Kotlin
listRecordings返回到调用方 coroutine;@JvmSynthetic入口不向 Java 暴露。 - callback 参数是不可变的 Kotlin/Java 值对象。
dispose会检查对象是否仍在使用,并允许在清理后重试。Replay 仍在播放、仍有 Output 绑定或活动 RecordingTask 时返回in-use。Output 仍绑定 Replay、宿主 View 或活动 Snapshot 时也返回in-use。失败时对象及关系保持不变。dispose只有在 native destroy 真正成功后才返回OK;重复调用幂等返回OK。成功后普通方法返回not-initialized,getter 保留最后提交值,SDK 不再投递该对象的普通 listener。- MP4 Task 在最终结果 callback 返回后自动释放底层资源;Java/Kotlin 不需要额外 dispose。
TiStore和 Output 的构造器只创建对应对象,不抛 SDK 运行错误;createReplay同样只创建 Replay。第一次需要底层资源的方法返回创建错误,对象仍可在修正问题后重试。
Java 可以直接使用一次性 callback;不关心导出进度时无需实现额外接口:
TiStore store = new TiStore(token);
store.listRecordings(startTimeMs, endTimeMs, result -> {
if (result.getCode() == TiStoreErrorCode.OK) {
showRecordings(result.getRecordings());
}
});
TiStoreExportTaskStartResult exportStart = store.exportRecording(
request,
null,
result -> showExportResult(result)
);