iOS API 说明
iOS 与 macOS 通过 TiRTC SDK 查询、回放、截图和导出云录像。
安装和初始化见 iOS SDK 接入。查询、播放、下载和截图见播放录像。
同步方法返回 Int32 错误码,TiStoreErrorCode.ok 表示当前调用成功。Swift 的一次性异步操作使用 async,Objective-C 使用 completion;两者都只返回一个最终结果。需要业务分支处理的错误通过 TiStoreErrorCode 提供公开常量;完整含义和处理建议见错误码。TiStore.errorToString(_:) 只用于展示或诊断。
基础类型
@objcMembers public final class TiStoreRecordingRange: NSObject {
public let startTimeMs: Int64
public let endTimeMs: Int64
public init(
startTimeMs: Int64,
endTimeMs: Int64
)
}
@objcMembers public final class TiStoreRecordingRangesResult: NSObject {
public let code: Int32
public let recordings: [TiStoreRecordingRange]
}
@objcMembers public final class TiStoreRecordingDay: NSObject {
public let date: String
public let hasRecording: Bool
}
@objcMembers public final class TiStoreRecordingDaysResult: NSObject {
public let code: Int32
public let days: [TiStoreRecordingDay]
}
@objc public enum TiStoreReplaySpeed: Int {
case x1 = 0
case x2 = 1
case x4 = 2
case x8 = 3
}TiStoreRecordingRange
| 字段 | 说明 |
|---|---|
startTimeMs | 录像可用时间段的开始时间,UTC Unix 毫秒 |
endTimeMs | 录像可用时间段的结束时间,UTC Unix 毫秒;必须晚于 startTimeMs |
TiStoreRecordingRangesResult
| 字段 | 说明 |
|---|---|
code | List 的最终错误码 |
recordings | 查询得到的录像可用时间段;成功但没有录像时为空数组 |
TiStoreRecordingDay 与 TiStoreRecordingDaysResult
| 字段 | 说明 |
|---|---|
TiStoreRecordingDay.date | 严格的 YYYY-MM-DD 日期 |
TiStoreRecordingDay.hasRecording | 该自然日至少有一个当前可见的录像时点时为 true |
TiStoreRecordingDaysResult.code | 日期查询的最终错误码 |
TiStoreRecordingDaysResult.days | 查询范围内完整的逐日结果 |
TiStoreReplaySpeed
| 枚举值 | 说明 |
|---|---|
.x1 | 1 倍速,播放音频和视频 |
.x2 | 2 倍速,视频播放,音频静音 |
.x4 | 4 倍速,视频播放,音频静音 |
.x8 | 8 倍速,视频播放,音频静音 |
NSNumber? 用于向 Objective-C 表达可空整数。
最小回放示例
selectedRecording 是从 listRecordings 返回结果中选择的一段录像。回放期间保持 replay、videoOutput 和 audioOutput 有效。
guard TiStore.initialize(appId: appId)
== TiStoreErrorCode.ok else { return }
let store = TiStore(token: token)
let replay = store.createReplay()
let videoOutput = TiStoreVideoOutput()
let audioOutput = TiStoreAudioOutput()
replay.onError = showReplayError
replay.onCompleted = showReplayCompleted
videoOutput.attachView(videoView)
videoOutput.attach(replay: replay, channelId: videoChannelId)
audioOutput.attach(replay: replay, channelId: audioChannelId)
replay.play(
startTimeMs: selectedRecording.startTimeMs,
endTimeMs: selectedRecording.endTimeMs
)同步方法返回非 TiStoreErrorCode.ok 时,当前操作没有生效。通过两个 Output 的状态和 delegate 更新播放界面;Token、网络或录像读取失败时,在 Replay 的错误回调中处理。
页面退出时,先停止 Replay、detach 两个 Output,并调用 videoOutput.detachView()。再依次 dispose Output 和 Replay。不再访问这台设备时,dispose store。
TiStore
@objcMembers public final class TiStore: NSObject {
public static func initialize(appId: String) -> Int32
public static func initialize(
appId: String,
endpoint: String,
consoleLogEnabled: Bool
) -> Int32
public static func errorToString(_ code: Int32) -> String
public var onTokenExpired: (() -> Void)?
public init(token: String)
public func updateToken(_ token: String) -> Int32
@MainActor @nonobjc public func listRecordingDays(
startDate: String,
endDate: String,
timeZoneId: String = "Asia/Shanghai"
) async -> TiStoreRecordingDaysResult
@objc(listRecordingDaysWithStartDate:endDate:completion:)
@MainActor public func listRecordingDaysForObjectiveC(
startDate: String,
endDate: String,
completion: @escaping @MainActor @Sendable (TiStoreRecordingDaysResult) -> Void
)
@objc(listRecordingDaysWithStartDate:endDate:timeZoneId:completion:)
@MainActor public func listRecordingDaysForObjectiveC(
startDate: String,
endDate: String,
timeZoneId: String,
completion: @escaping @MainActor @Sendable (TiStoreRecordingDaysResult) -> Void
)
@MainActor @nonobjc public func listRecordings(
startTimeMs: Int64,
endTimeMs: Int64
) async -> TiStoreRecordingRangesResult
@objc(listRecordingsWithStartTimeMs:endTimeMs:completion:)
@MainActor public func listRecordingsForObjectiveC(
startTimeMs: Int64,
endTimeMs: Int64,
completion: @escaping @MainActor @Sendable (TiStoreRecordingRangesResult) -> Void
)
public func createReplay() -> TiStoreReplay
public func exportRecording(
_ request: TiStoreExportRequest,
progress: ((Double) -> Void)?,
completion: @escaping (TiStoreRecordingResult) -> Void
) -> TiStoreExportTaskStartResult
public func dispose() -> Int32
}使用任何云存储 API 前先调用 TiStore.initialize(appId:)。初始化后用一台设备的非空 Token 创建 TiStore 实例;构造不发起网络请求。同时访问多台设备时创建多个实例。
| API | 说明 |
|---|---|
initialize(appId:) | 使用默认服务地址初始化;appId 来自申请开通。返回初始化错误码 |
initialize(appId:endpoint:consoleLogEnabled:) | 使用完整配置初始化。endpoint 留空时使用默认服务地址;consoleLogEnabled 控制控制台日志 |
errorToString(_:) | 返回错误码对应的稳定名称,用于日志和诊断 |
updateToken(_:) | 为同一设备更新 Token,只影响之后启动的 List、Play 和 Export |
listRecordingDays(startDate:endDate:timeZoneId:) | Swift 查询包含式日期范围,单次最多 31 天。时区使用 IANA ID,默认 Asia/Shanghai;结果按日期升序返回范围内每一天 |
listRecordingDaysWithStartDate:endDate:completion: | Objective-C 使用默认时区查询,结果在主队列返回一次 |
listRecordingDaysWithStartDate:endDate:timeZoneId:completion: | Objective-C 使用显式 IANA 时区查询,结果在主队列返回一次 |
listRecordings(startTimeMs:endTimeMs:) | Swift 查询当前设备在 [startTimeMs, endTimeMs) 内的录像可用时间段,等待并返回唯一的 TiStoreRecordingRangesResult。单次跨度最长 10 天 |
listRecordingsWithStartTimeMs:endTimeMs:completion: | Objective-C 互操作入口。包括参数、Token、对象状态和运行期错误在内,均由主队列 completion 恰好返回一次,不同步返回另一份错误码 |
createReplay() | 创建属于当前设备的 Replay |
exportRecording(_:progress:completion:) | 开始一次录像导出。同步结果包含错误码和可空 Task;接受成功后,completion 返回唯一的最终结果 |
dispose() | 释放当前设备实例;仍有查询、Replay、ExportTask 或回调正在执行时返回 inUse |
onTokenExpired 只在当前 Token 被云端明确判定为过期时通知,同一个 Token 至多一次。触发过期的 List、Play 或 Export 先通过自身结果或回调报告错误;Token 无效或权限不足不触发该回调。当前 Token 已经确定过期时,新的 List 通过唯一 Result 返回 tokenExpired,新的 Play 或 Export 在启动调用中同步拒绝。updateToken 保存不同的非空 Token,之后启动的操作使用新 Token;相同 Token 不清除过期状态,已经开始的操作也不自动换证或重试。它只用于同一设备续签,访问另一台设备时创建新的 TiStore。
listRecordingDays 的起止日期都使用严格的 YYYY-MM-DD 格式并包含在结果中。成功结果包含范围内每一天,包括 hasRecording == false 的日期。时区必须是有效的 IANA ID;范围超过 31 天时返回 rangeTooLarge。
listRecordings 结果按 startTimeMs 升序排列,并裁剪在请求的 [startTimeMs, endTimeMs) 内。重叠或首尾相接的时间段会合并;任何大于 0 的空洞都会保留为不同项。结果是设备级完整快照,不保证每个 Channel 都有媒体,也不分页。合并后最多返回 10000 项。查询跨度或结果数量超限时,整体返回 rangeTooLarge,不返回部分结果;成功但没有录像时返回空数组。
TiStoreReplay
@objcMembers public final class TiStoreReplay: NSObject {
public private(set) var speed: TiStoreReplaySpeed
public private(set) var currentTimeMs: NSNumber?
public var onTimeChanged: ((Int64) -> Void)?
public var onError: ((Int32) -> Void)?
public var onCompleted: (() -> Void)?
public func play(
startTimeMs: Int64,
endTimeMs: Int64,
initialTimeMs: NSNumber? = nil
) -> Int32
public func pause() -> Int32
public func resume() -> Int32
public func seek(toTimeMs timeMs: Int64) -> Int32
public func setSpeed(_ speed: TiStoreReplaySpeed) -> Int32
public func startRecording(
videoChannelId: Int,
audioChannelId: NSNumber? = nil
) -> TiStoreRecordingTaskStartResult
public func stop() -> Int32
public func dispose() -> Int32
}属性与回调
| 成员 | 说明 |
|---|---|
speed | 当前回放倍速,初始值为 .x1 |
currentTimeMs | 当前回放位置,UTC Unix 毫秒;首次取得位置前和 stop 后为 nil |
onTimeChanged | 回放位置变化通知;晚设置时不会补发之前的事件 |
onError | 当前 play 的 Token、权限、网络或录像读取错误;一次回放最多通知一次 |
onCompleted | 当前 play 的时间范围自然耗尽通知;一次回放最多通知一次 |
方法
| API | 说明 |
|---|---|
play(startTimeMs:endTimeMs:initialTimeMs:) | 播放所属设备在 [startTimeMs, endTimeMs) 内的录像。initialTimeMs 可空,缺省时从 startTimeMs 开始;传入时从指定位置开始。返回值表示请求是否被接受 |
pause() | 暂停当前回放;重复调用成功 |
resume() | 继续当前回放;重复调用成功 |
seek(toTimeMs:) | 定位到当前回放范围内的 UTC 时间;同步返回操作是否被接受 |
setSpeed(_:) | 设置 .x1、.x2、.x4 或 .x8 倍速;非 .x1 时 Audio Output 静音 |
startRecording(videoChannelId:audioChannelId:) | 保存当前回放的一段内容。同步结果包含错误码和可空 RecordingTask |
stop() | 停止当前回放并清除 currentTimeMs;保留 Output 绑定和倍速 |
dispose() | 释放 Replay;调用后不能继续使用该实例 |
Replay 只能由 store.createReplay() 创建,并固定属于该设备实例。Replay 没有公开 state。onError 返回当前 play 过程中发生的 Token、权限、网络或录像读取错误。错误发生时恰好调用一次;同步拒绝、主动 stop、被新 play 替换或自然完成不会触发。每个被接受的 play 仅在其时间范围自然耗尽时调用一次 onCompleted;同步拒绝、主动 stop、被新 play 替换或错误终止均不触发。开始 play 前设置回调,晚设置不会重放此前错误或完成事件。接受 Play 时固定使用 Store 实例当前的 Token,之后更新 Token 不改变本次回放。
录像文件已被删除、缺失、损坏或无法读取时,onError 返回 TiStoreErrorCode.recordingUnreadable。网络或服务暂时不可用时,返回 TiStoreErrorCode.storeUnavailable。
currentTimeMs在首次取得位置前和stop后为nil;暂停时保留最后位置,自然完成时为请求的endTimeMs,回放失败时保留最后已知位置。晚设置onTimeChanged不重放旧事件,先读取属性再订阅。speed初始为.x1;非.x1时 Audio Output 静音。play前必须至少绑定一个 Output。onCompleted不取代 Output 的.completed:前者表示 Replay 来源自然耗尽,后者只表示对应 Output 已排空。自然完成会自动终结活动 RecordingTask。play要求startTimeMs < endTimeMs;非空的initialTimeMs必须位于[startTimeMs, endTimeMs)。参数校验失败同步返回invalidArgument,原回放不受影响。成功接受后从初始位置建立新回放,不会先输出范围开头的媒体;初始位置落在空洞中时从其后的第一段录像开始,其后没有录像时按自然结束处理。- 最后一个 Output 离开且没有活动 RecordingTask 时,Replay 停止读取来源,但不触发
onCompleted。 - 新
play被接受后原回放停止,但保留 Output 绑定、Audio Output 音量和速度;同步拒绝时原回放不受影响。 pause和resume分别幂等;尚未开始、已经stop、自然完成或失败时返回notStarted。- Seek 只能在当前
play仍在运行或暂停时调用,目标必须位于当前[startTimeMs, endTimeMs)。回放未活动或目标越界时,分别同步返回notStarted或invalidArgument,当前回放不受影响。自然完成后要从指定位置重新播放时,调用带initialTimeMs的play。 - Seek 保留速度和暂停意图,连续调用采用 latest-wins。定位生效后,
currentTimeMs和onTimeChanged更新为第一个不早于目标的可播放位置。目标合法但其后没有录像时,位置推进到endTimeMs并按自然结束触发onCompleted。 stop幂等,不触发onCompleted,也不把 Output 标记为.completed;它会清除currentTimeMs,并保留 Output 绑定和速度。
Audio/Video Output
@objc public enum TiStoreAudioOutputState: Int {
case idle = 0
case buffering = 1
case playing = 2
case failed = 3
case paused = 4
case completed = 5
}
@objc public enum TiStoreVideoOutputState: Int {
case idle = 0
case buffering = 1
case rendering = 2
case failed = 3
case paused = 4
case completed = 5
}
@objc public protocol TiStoreAudioOutputDelegate: NSObjectProtocol {
@objc optional func audioOutput(
_ output: TiStoreAudioOutput,
didChangeState state: TiStoreAudioOutputState
)
@objc optional func audioOutput(
_ output: TiStoreAudioOutput,
didFailWithCode code: Int32
)
}
@objcMembers public final class TiStoreAudioOutput: NSObject {
public weak var delegate: TiStoreAudioOutputDelegate?
public private(set) var state: TiStoreAudioOutputState
public override init()
public func attach(replay: TiStoreReplay, channelId: UInt8) -> Int32
public func setVolume(_ volumePercent: UInt32) -> Int32
public func detach() -> Int32
public func dispose() -> Int32
}
@objc public protocol TiStoreVideoOutputDelegate: NSObjectProtocol {
@objc optional func videoOutput(
_ output: TiStoreVideoOutput,
didChangeState state: TiStoreVideoOutputState
)
@objc optional func videoOutput(
_ output: TiStoreVideoOutput,
didFailWithCode code: Int32
)
}
@objcMembers public final class TiStoreVideoOutput: NSObject {
public weak var delegate: TiStoreVideoOutputDelegate?
public private(set) var state: TiStoreVideoOutputState
public override init()
public func attachView(_ view: TiRtcPlatformView) -> Int32
public func detachView() -> Int32
public func attach(replay: TiStoreReplay, channelId: UInt8) -> Int32
@nonobjc public func takeSnapshot() async -> TiStoreSnapshotResult
@objc(takeSnapshotWithCompletion:)
@MainActor
public func takeSnapshotForObjectiveC(
completion: @escaping @MainActor @Sendable (TiStoreSnapshotResult) -> Void
)
public func detach() -> Int32
public func dispose() -> Int32
}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 无法继续输出媒体 |
属性与 Delegate
| 成员 | 说明 |
|---|---|
state | 当前 Output 状态 |
delegate | 弱引用;接收状态变化和当前 Output 的解码、播放或渲染错误 |
audioOutput(_:didChangeState:) / videoOutput(_:didChangeState:) | output 为发生变化的实例,state 为当前状态 |
audioOutput(_:didFailWithCode:) / videoOutput(_:didFailWithCode:) | output 为失败的实例,code 为错误码 |
方法
| API | 适用对象 | 说明 |
|---|---|---|
attachView(_:) | Video | 把 Video Output 绑定到宿主提供的 TiRtcPlatformView;重复绑定同一 View 成功,换绑失败时保留原 View |
detachView() | Video | 解除宿主 View 绑定;对象和 Replay 绑定保持不变 |
attach(replay:channelId:) | Audio、Video | 绑定 Replay 中指定 channel_id 的音频或视频;channelId 取值为 0...255 |
takeSnapshot() / takeSnapshotWithCompletion: | Video | 把当前视频画面保存为唯一的临时 JPEG;成功结果包含 TiStoreSnapshotFile |
detach() | Audio、Video | 解除当前 Replay 绑定;对象仍可再次 attach |
dispose() | Audio、Video | 释放 Output;调用后不能继续使用该实例 |
两个 Output 都提供只读 state 和弱 delegate。delegate 报告状态变化和错误。
attachView 与 Replay 的 attach 相互独立;SDK 借用 TiRtcPlatformView 到 detachView 成功为止,应用必须在销毁或复用 View 前先解除绑定。Swift takeSnapshot() 等待最终结果,Objective-C completion 在主队列调用一次。成功时 file.path 是 SDK 私有 cache 中的临时 JPEG。
当前绑定还没有画面时,completion 返回 noFrame。暂停或自然播放完成后,只要最后画面仍然保留,就可以继续截图;attach 新来源、新的 play 生效、detachView 或 detach 后,在新画面到达前返回 noFrame。同一个 Video Output 同时只接受一个 Snapshot;已有请求未完成时,新的 completion 返回 inUse。不同 Output 仍可能因全局资源上限返回 resourceExhausted。
Snapshot completion 返回前,dispose() 返回 inUse,Output、View 与 Replay 关系保持不变。先等待 completion,再按正常顺序解除 View 和 Replay 绑定并释放 Output。
Video Output 和 Audio Output 分别使用设备配置提供的 channelId,取值范围是 0...255;两者可以相同,也可以不同。使用 exhaustive switch 时,需要处理 paused 和 completed。
重复绑定同一个 Replay 的同一个 channel_id 会成功;已经绑定时传入不同 Replay 或 channel_id 返回 inUse 并保留原关系,必须先显式 detach。Replay 正在运行时新增或 detach 后重新绑定 Output,从绑定生效后的下一可独立解码位置开始,不补发此前媒体。同一个 Replay 的同一个 channel_id 只能绑定一个同类播放 Output。stop、自然完成和新 play 都保留绑定;dispose 不隐式解绑,关系仍存在时返回 inUse。某个 Output 解码、播放或渲染失败时,它的 delegate 返回错误,并且只终止该 Output。Token、网络、所选范围过大或录像读取失败时,Replay 的 onError 返回一次错误,并使本次回放的全部 Output 进入 failed。
本地媒体文件
@objcMembers public final class TiStoreRecordingFile: NSObject {
public let path: String
public let durationMs: Int64
@nonobjc public func delete() async -> Int32
@objc(deleteWithCompletion:)
public func deleteForObjectiveC(
completion: @escaping @MainActor @Sendable (Int32) -> Void
)
}
@objcMembers public final class TiStoreSnapshotFile: NSObject {
public let path: String
@nonobjc public func delete() async -> Int32
@objc(deleteWithCompletion:)
public func deleteForObjectiveC(
completion: @escaping @MainActor @Sendable (Int32) -> Void
)
}
@objcMembers public final class TiStoreRecordingResult: NSObject {
public let code: Int32
public let file: TiStoreRecordingFile?
}
@objcMembers public final class TiStoreSnapshotResult: NSObject {
public let code: Int32
public let file: TiStoreSnapshotFile?
}文件路径位于应用 container cache。Apple 平台(Darwin)SDK 只提供受限、幂等的 delete();需要长期保存时由应用自行复制或移动文件。Objective-C 使用对应 delete completion 入口。系统相册便利能力只由 Flutter 与 React Native SDK 提供。
TiStoreRecordingTask
@objcMembers public final class TiStoreRecordingTaskStartResult: NSObject {
public let code: Int32
public let task: TiStoreRecordingTask?
}
@objcMembers public final class TiStoreRecordingTask: NSObject {
@nonobjc public func stop() async -> TiStoreRecordingResult
@objc(stopWithCompletion:)
public func stopForObjectiveC(
completion: @escaping @MainActor @Sendable (TiStoreRecordingResult) -> Void
)
}TiStoreReplay.startRecording(videoChannelId:audioChannelId:) 同步返回错误码和可空 Task。Replay 必须正在回放;视频 Channel 必填,音频 Channel 可空。同步失败不创建 Task。
Swift stop() 与 Objective-C stopWithCompletion: 都停止接收新媒体,排空已接收数据并完成 MP4。重复或并发调用取得同一个最终结果。Replay 自然结束时 Task 自动完成,随后调用 stop 返回缓存结果。
Task 不公开 state、实时 duration、cancel 或 dispose。相同 Channel 可以创建多个 Task,SDK 为每个 Task 生成不同文件;两个视频 Channel 使用两个 Task。
TiStoreExportTask
@objcMembers public final class TiStoreExportRequest: NSObject {
public let startTimeMs: Int64
public let endTimeMs: Int64
public let videoChannelId: Int
public let audioChannelId: NSNumber?
}
@objcMembers public final class TiStoreExportTaskStartResult: NSObject {
public let code: Int32
public let task: TiStoreExportTask?
}
@objcMembers public final class TiStoreExportTask: NSObject {
public private(set) var progress: Double
public func stop() -> Int32
}store.exportRecording(_:progress:completion:) 在启动 Task 前固定实例当前的 Token,并保存两个回调。随后同步返回 TiStoreExportTaskStartResult。成功时 Task 已经开始,进度和唯一的最终结果在主队列返回。
同步失败时 task == nil,且不调用回调。SDK 也不会在 exportRecording 返回前调用回调。
progress 位于 0.0...1.0 且单调不回退。只有 MP4 完整生成后才到达 1.0。中间通知可以合并。
活动 Task 调用 stop() 会停止导出、清理临时文件,并使原 completion 返回 .stopped 和 file == nil;不生成部分 MP4。自然完成或失败后调用 stop() 不改变缓存结果。重复调用幂等。
Task 在 completion 返回后自动释放底层资源,不提供 dispose。不同 Task 相互独立并生成不同 cache 文件;资源达到上限返回 .resourceExhausted。
错误码
| 错误码 | 常量 | 常见含义 | 建议处理 |
|---|---|---|---|
| 0 | TiStoreErrorCode.ok | 操作成功 | 继续后续流程 |
| 6000 | TiStoreErrorCode.invalidArgument | 参数缺失、取值越界或时间范围无效 | 修正参数后重试 |
| 6001 | — | 尚未初始化云存储能力,或已经关闭 | 先调用 TiStore.initialize |
| 6014 | TiStoreErrorCode.tokenExpired | Token 已过期 | 为同一设备更新 Token 后重新发起请求 |
| 6022 | — | 已使用另一组配置初始化 | 保持初始化参数一致;需要更换配置时,重启应用后再初始化 |
| 6024 | TiStoreErrorCode.permissionDenied | Token 无效,或无权访问目标设备或录像 | 检查授权并重新取得 Token |
| 6026 | — | 对象仍在播放、录制或执行任务,当前操作不能执行 | 先结束活动操作,再重试 |
| 6027 | — | 尚未开始播放或录制 | 先启动对应操作 |
| 6029 | — | 尚未建立当前操作要求的绑定 | 完成对应绑定后重试 |
| 6030 | — | 缺少必要的目标或媒体通道配置 | 补充通道或目标配置后重试 |
| 6043 | — | 当前设备没有足够资源创建或继续任务 | 结束其他任务并释放资源后重试 |
| 6046 | TiStoreErrorCode.fileWriteFailed | 无法创建或写入输出文件 | 检查目录权限和磁盘空间 |
| 6113 | TiStoreErrorCode.unsupportedFormat | 录像的音视频格式不受支持 | 提示当前录像无法播放或导出 |
| 6115 | TiStoreErrorCode.cancelled | List 请求被取消 | 结束对应等待 |
| 6117 | TiStoreErrorCode.rangeTooLarge | 日期查询超过 31 天,或时间段查询超过 10 天或合并结果超过 10000 项 | 缩短查询范围后重试 |
| 6118 | TiStoreErrorCode.noFrame | Video Output 尚无可用于截图的视频帧 | 等待出画后重试 |
| 6119 | TiStoreErrorCode.noRecordableMedia | 所选范围或通道没有可写入的媒体 | 重新选择录像范围或通道 |
| 6120 | TiStoreErrorCode.recordingOverrun | 本地写入持续跟不上回放数据,保存任务已经终止 | 释放设备资源、检查存储性能后重新保存 |
| 6122 | TiStoreErrorCode.recordingUnreadable | 录像文件缺失、损坏,或上传的格式与帧数据无法读取 | 文件缺失或损坏时停止重试;其他情况检查设备上传的格式与帧要求 |
| 6123 | TiStoreErrorCode.storeUnavailable | 网络、云存储服务或录像数据读取暂时不可用 | 稍后重试 |
| 6124 | TiStoreErrorCode.stopped | 活动 ExportTask 已被主动停止 | 结束导出进度,不使用输出文件 |
常量列为“—”的错误通常表示调用顺序或资源状态问题,记录数值用于定位即可,不需要在业务流程中逐项判断。不要根据 errorToString 返回值或日志文本判断错误类型。
队列、生命周期与互操作
listRecordings在@MainActor上返回;其他 Swiftasync方法返回到调用方所在的并发上下文。Objective-C completion、delegate 和 progress 都进入主队列,不会在发起异步 API 的调用栈中执行。dispose会检查对象是否仍在使用,并允许在清理后重试。Replay 仍在播放、仍有 Output 绑定或活动 RecordingTask 时返回inUse;Output 仍绑定 Replay、宿主 View 或活动 Snapshot 时也返回inUse。失败时对象及关系保持不变。dispose只有在没有 binding、宿主 View 或活动 Snapshot,并且 native destroy 真正成功后才返回.ok;失败时对象及关系保持不变。重复调用幂等返回.ok。成功后普通方法返回notInitialized,getter 保留最后提交值,SDK 不再调用该对象的 delegate 或状态回调。- completion block 由 SDK 保持到完成,你不需要额外持有。
- MP4 Task 在最终结果 completion 返回后自动释放底层资源,不需要额外 dispose。
- Store 和 Output 构造器只创建对应对象,不抛 SDK 运行错误;
createReplay同样只创建 Replay。底层资源创建失败由第一次需要该资源的方法返回。