Skip to content

Ti 云存 HarmonyOS API 参考 ​

本文列出 OpenHarmony/HarmonyOS 中 Ti 云存与通用 Media 的公开 API、返回结果和行为约定。第一次接入时,播放录像先阅读查询与播放录像,导出本地 MP4 先阅读下载录像。

同步命令返回 number 错误码,TI_CLOUD_STORAGE_ERROR_OK 表示当前调用成功。异步方法通过 Promise 返回唯一最终结果。常见错误通过包根入口提供公开常量;没有命名常量的错误仍会返回完整整数值,含义和处理建议见错误码。TiCloudStorage.errorToString(code) 只用于展示或诊断。

基础类型 ​

typescript
export interface Resp<T> {
  readonly success: boolean;
  readonly code: number | null;
  readonly message: string | null;
  readonly data: T | null;
}

export interface TiCloudStorageRecordingRange {
  readonly startTimeMs: number;
  readonly endTimeMs: number;
}

export interface TiCloudStorageRecordingRangesResult {
  readonly code: number;
  readonly recordings: ReadonlyArray<TiCloudStorageRecordingRange>;
}

export interface TiCloudStorageRecordingDay {
  readonly date: string;
  readonly hasRecording: boolean;
}

export interface TiCloudStorageRecordingDaysResult {
  readonly code: number;
  readonly days: ReadonlyArray<TiCloudStorageRecordingDay>;
}

export enum TiCloudStorageReplaySpeed {
  x0_125 = 6,
  x0_25 = 5,
  x0_5 = 4,
  x1 = 0,
  x2 = 1,
  x4 = 2,
  x8 = 3,
}
类型或字段说明
TiCloudStorageRecordingRange.startTimeMs录像可用时间段的开始时间,UTC Unix 毫秒
TiCloudStorageRecordingRange.endTimeMs录像可用时间段的结束时间,UTC Unix 毫秒;必须晚于 startTimeMs
TiCloudStorageRecordingRangesResult.code查询最终错误码
TiCloudStorageRecordingRangesResult.recordings查询得到的录像可用时间段;成功但没有录像时为空数组
TiCloudStorageRecordingDay.date严格 YYYY-MM-DD 日期
TiCloudStorageRecordingDay.hasRecording该自然日至少有一个当前可见录像时点时为 true
TiCloudStorageRecordingDaysResult日期查询的最终错误码和完整逐日结果
倍速说明
x0_1251/8 倍速,视频慢放,音频静音
x0_251/4 倍速,视频慢放,音频静音
x0_51/2 倍速,视频慢放,音频静音
x11 倍速,播放音频和视频
x22 倍速,视频播放,音频静音
x44 倍速,视频播放,音频静音
x88 倍速,视频播放,音频静音

所有时间必须是 JavaScript 安全整数;SDK 不进行本地时区换算。

使用可用时间段开始回放 ​

selectedRecording 是从 listRecordings 返回结果中选择的一段录像。下面只展示正常调用顺序;回放期间保持 replay、videoOutput 和 audioOutput 有效。

typescript
const initCode = await TiCloudStorage.init({
  context: uiAbilityContext,
  appId,
});
if (initCode !== TI_CLOUD_STORAGE_ERROR_OK) return;

const cloudStorage = new TiCloudStorage(token);
const replay = cloudStorage.createReplay();
const videoOutput = new TiCloudStorageVideoOutput();
const audioOutput = new TiCloudStorageAudioOutput();
replay.onError = showReplayError;
replay.onCompleted = markReplaySourceCompleted;

videoOutput.attach(replay, videoChannelId);
audioOutput.attach(replay, audioChannelId);

replay.play(
  selectedRecording.startTimeMs,
  selectedRecording.endTimeMs,
);

@Builder
function CloudStoragePlaybackVideo(): void {
  TiCloudStorageVideoOutputView({
    output: videoOutput,
    fit: TiCloudStorageVideoFit.contain,
  });
}

同步方法返回非 TI_CLOUD_STORAGE_ERROR_OK 时,当前操作没有生效。通过两个 Output 的状态更新播放界面;Token、网络或录像读取失败时,在 Replay 的错误回调中处理。

页面退出时,先停止 Replay、detach 两个 Output,并从组件树中移除 TiCloudStorageVideoOutputView。随后依次 dispose Output 和 Replay。不再访问这台设备时 dispose cloudStorage;应用不再使用 Ti 云存时,最后调用 TiCloudStorage.shutdown()。

TiCloudStorage ​

typescript
import { common } from '@kit.AbilityKit';

export interface TiCloudStorageInitConfig {
  readonly context: common.UIAbilityContext;
  readonly appId: string;
  readonly endpoint?: string;
  readonly consoleLogEnabled?: boolean;
}

export class TiCloudStorage {
  constructor(token: string);

  static init(config: TiCloudStorageInitConfig): Promise<number>;
  static shutdown(): number;
  static errorToString(code: number): string;

  updateToken(token: string): number;

  listRecordingDays(
    startDate: string,
    endDate: string,
    timeZoneId?: string,
  ): Promise<TiCloudStorageRecordingDaysResult>;

  listRecordings(
    startTimeMs: number,
    endTimeMs: number,
  ): Promise<TiCloudStorageRecordingRangesResult>;

  createReplay(): TiCloudStorageReplay;

  exportRecording(
    options: TiCloudStorageExportOptions,
    onProgress?: (progress: number) => void,
    observer?: TiCloudStorageExportObserver,
  ): Resp<TiCloudStorageExportTask>;

  dispose(): number;
}

使用任何 Ti 云存 API 前先调用 TiCloudStorage.init。初始化后用一台设备的非空 Token 创建 TiCloudStorage 实例;构造不发起网络请求。同时访问多台设备时创建多个实例。释放全部 TiCloudStorage 实例、Replay、Output 和任务后调用 TiCloudStorage.shutdown()。Promise 正常 resolve 统一结果码,不以 reject 表示 SDK 运行错误;仅编程错误或 JS/ArkTS 桥异常可以 reject。

TiRTC 与 Ti 云存可以在同一进程共存,两者可以使用不同的 App ID 和 endpoint。由 common.UIAbilityContext.cacheDir/tirtc 解析出的工作根目录和 consoleLogEnabled 由两者共享,因此配置必须一致。Runtime 在该目录下管理日志、日志归档和临时媒体文件。初始化第二项服务不会重启 Runtime;共享配置不一致时返回 already-initialized,已初始化的服务不受影响。调用 TiCloudStorage.shutdown() 不会停止 TiRTC。

TiCloudStorage.shutdown() 在尚未初始化或已经关闭时幂等返回成功;仍有活动资源时返回 in-use。在对象回调中同步停止、解绑或释放当前对象及其关联资源,也会返回 in-use 且不改变状态。其他无关实例和资源不受此限制。

cloudStorage.dispose() 只有在底层资源释放成功后才使实例失效。若返回 in-use 或其他错误,实例和当前 Token 仍然有效;清理占用资源后可以重试。SDK 不负责清除调用方持有的 Token 字符串。

类型、字段或 API说明
TiCloudStorageInitConfig.context当前应用的 common.UIAbilityContext
TiCloudStorageInitConfig.appId控制台分配的 AppId,必填
TiCloudStorageInitConfig.endpoint自定义 Ti 云存服务地址;普通接入不传
TiCloudStorageInitConfig.consoleLogEnabled是否把 SDK 日志输出到控制台,默认 false
init(config)初始化 TiCloudStorage;Promise 返回初始化错误码
shutdown()关闭 Ti 云存。调用前必须释放所有 TiCloudStorage 实例、Replay、Output,并等待查询、截图和文件 Task 完成
errorToString(code)返回错误码对应的稳定名称,用于日志和诊断
updateToken(token)为同一设备更新 Token,只影响之后启动的 List、Play 和 Export
listRecordingDays(startDate, endDate, timeZoneId)查询包含式日期范围,单次最多 31 天。timeZoneId 使用 IANA ID,省略时默认 Asia/Shanghai;Promise 返回包含 true/false 日期的完整升序结果
listRecordings(startTimeMs, endTimeMs)查询当前设备指定 UTC 时间范围内的录像可用时间段;单次跨度最长 10 天。成功但没有录像时 recordings 为空数组
createReplay()创建属于当前设备的 Replay
exportRecording(options, onProgress, observer)开始一次录像导出;普通进度和详细观察器均可选,同步返回 Resp<TiCloudStorageExportTask>
dispose()释放当前设备实例;仍有查询、Replay、ExportTask 或待处理回调时返回 in-use

Token 过期由触发它的 List、Play 或 Export 直接报告 token-expired。SDK 不另发过期通知,也不自动刷新或重试。应用取得同一设备的新 Token、调用 updateToken,再显式重做失败的操作。SDK 保存不同的非空新 Token,供之后启动的操作使用;重复设置相同 Token 不会清除已经确定的过期状态。访问另一台设备时创建新的 TiCloudStorage。

List 结果按 startTimeMs 升序排列并裁剪在请求的 [startTimeMs, endTimeMs) 内;重叠或首尾相接的时间段会合并,任何大于 0 的空洞都保留为不同项。结果是设备级完整快照,不保证每个 Channel 都有媒体,也不分页。合并后最多返回 10000 项;查询跨度或结果数量超限时整体 resolve range-too-large,不返回部分结果;成功但没有录像时返回空数组。

TiCloudStorageReplay ​

typescript
export enum TiCloudStorageRecordingTrackKind {
  video = 1,
  audio = 2,
}

export interface TiCloudStorageRecordingTrack {
  readonly kind: TiCloudStorageRecordingTrackKind;
  readonly channelId: number;
}

export enum TiCloudStorageRecordingGapReason {
  unknown = 0,
  notFound = 1,
  downloadFailed = 2,
  integrityFailed = 3,
  mediaUnreadable = 4,
  noKeyFrame = 5,
  noRecording = 6,
  decryptionFailed = 7,
  unsupportedMedia = 8,
  trackUnavailable = 9,
}

export interface TiCloudStorageRecordingGap {
  readonly range: TiCloudStorageRecordingRange;
  readonly tracks: ReadonlyArray<TiCloudStorageRecordingTrack>;
  readonly reasons: ReadonlyArray<TiCloudStorageRecordingGapReason>;
}

export interface TiCloudStorageReplay {
  readonly speed: TiCloudStorageReplaySpeed;
  readonly currentTimeMs?: number;
  onTimeChanged?: (timeMs: number) => void;
  onError?: (code: number) => void;
  onCompleted?: () => void;
  onRecordingGap?: (gap: TiCloudStorageRecordingGap) => void;

  play(
    startTimeMs: number,
    endTimeMs: number,
    initialTimeMs?: number,
  ): number;
  pause(): number;
  resume(): number;
  seek(timeMs: number): number;
  setSpeed(speed: TiCloudStorageReplaySpeed): number;
  startRecording(
    options: TiCloudStorageStartRecordingOptions,
  ): Resp<TiCloudStorageRecordingTask>;
  startRawDump(options: TiCloudStorageRawDumpOptions): Promise<Resp<TiRawDump>>;
  stop(): number;
  dispose(): number;
}
成员说明
speed当前回放倍速,初始值为 x1
currentTimeMs当前回放位置,UTC Unix 毫秒;首次取得位置前和 stop 后缺省
onTimeChanged回放位置变化通知;晚设置时不会补发之前的事件
onError当前 play 的 Token、权限、网络或录像读取错误;一次回放最多通知一次
onCompleted当前 play 的时间范围自然耗尽通知;一次回放最多通知一次
onRecordingGap回放越过已确认的录像缺口时触发;包含时间范围、受影响的音视频 Channel 和原因
play(startTimeMs, endTimeMs, initialTimeMs)播放所属设备的指定 UTC 时间范围;initialTimeMs 可选,省略时从范围开头播放
pause()暂停当前回放;重复调用成功
resume()继续当前回放;重复调用成功
seek(timeMs)定位到当前回放范围内的 UTC 时间;同步返回操作是否被接受
setSpeed(speed)设置七档固定速度;非 x1 时 Audio Output 静音,慢放画面采用持帧显示
startRecording(options)保存当前回放的一段内容;同步返回 Resp<TiCloudStorageRecordingTask>
startRawDump(options)按 Channel ID 开始原始音视频诊断采集;Promise 返回错误码和可空的采集任务对象
stop()停止当前回放并清除 currentTimeMs;保留 Output 绑定和倍速
dispose()释放 Replay;调用后不能继续使用该实例

Replay 只能由 cloudStorage.createReplay() 创建,并固定属于该设备实例。Replay 不公开 state。onError 返回当前 play 过程中发生的 Token、权限、网络或录像读取错误。错误发生时恰好调用一次;同步拒绝、主动 stop、被新 play 替换或自然完成不会触发。onCompleted 是 Replay 的自然完成事件:每个被接受的 play 仅在其时间范围自然耗尽时恰好调用一次;同步拒绝、主动 stop、被新 play 替换或错误终止均不触发。开始 play 前设置回调,晚设置不会重放此前错误或完成事件。接受 Play 时固定使用 TiCloudStorage 实例当前的 Token,之后更新 Token 不改变本次回放。

onRecordingGap 只报告 SDK 已经确认并越过的来源缺口,不表示所有下载或解析错误都能跳过。无法继续读取或解析录像时,Replay 仍通过 onError 结束。

云端明确返回录像文件不存在或文件已被删除时,onError 返回 TI_CLOUD_STORAGE_ERROR_RECORDING_NOT_FOUND;SDK 未能成功下载目标录像文件时,返回 TI_CLOUD_STORAGE_ERROR_RECORDING_DOWNLOAD_FAILED;文件已经下载但 SDK 无法解密或解析出有效音视频帧时,返回 TI_CLOUD_STORAGE_ERROR_RECORDING_UNREADABLE。SDK 无法完成录像查询或取得下载信息时,返回 TI_CLOUD_STORAGE_ERROR_UNAVAILABLE。

  • currentTimeMs 在首次取得位置前和 stop 后缺省;暂停时保留最后位置,自然完成时为请求的 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 保留速度和暂停意图;连续调用时,以最后一次 Seek 的目标为准。定位生效后,currentTimeMs 和 onTimeChanged 更新为第一个不早于目标的可播放位置。目标合法但其后没有录像时,位置推进到 endTimeMs 并按自然结束触发 onCompleted。
  • stop 幂等,不触发 onCompleted,也不把 Output 标记为 completed;它会清除 currentTimeMs,并保留 Output 绑定和速度。

Audio/Video Output 扩展 ​

typescript
export enum TiCloudStorageAudioOutputState {
  idle = 0,
  buffering = 1,
  playing = 2,
  failed = 3,
  paused = 4,
  completed = 5,
}

export enum TiCloudStorageVideoOutputState {
  idle = 0,
  buffering = 1,
  rendering = 2,
  failed = 3,
  paused = 4,
  completed = 5,
}

export enum TiCloudStorageVideoFit {
  contain = 0,
  cover = 1,
}

export interface TiCloudStorageVideoOutputViewOptions {
  readonly output: TiCloudStorageVideoOutput;
  readonly fit?: TiCloudStorageVideoFit;
  readonly backgroundColor?: ResourceColor;
  readonly width?: Length;
  readonly height?: Length;
}

export class TiCloudStorageAudioOutput {
  readonly state: TiCloudStorageAudioOutputState;
  onStateChanged?: (state: TiCloudStorageAudioOutputState) => void;
  onError?: (code: number) => void;

  attach(replay: TiCloudStorageReplay, channelId: number): number;
  setVolume(volumePercent: number): number;
  detach(): number;
  dispose(): number;
}

export class TiCloudStorageVideoOutput {
  readonly state: TiCloudStorageVideoOutputState;
  onStateChanged?: (state: TiCloudStorageVideoOutputState) => void;
  onError?: (code: number) => void;

  attach(replay: TiCloudStorageReplay, channelId: number): number;
  takeSnapshot(): Promise<Resp<TiCloudStorageSnapshotFile>>;
  detach(): number;
  dispose(): number;
}

@Builder
export function TiCloudStorageVideoOutputView(
  options: TiCloudStorageVideoOutputViewOptions,
): void;

setVolume 接收 0..100 的整数;0 表示静音。它只调整当前 Audio Output,不修改系统全局音量。新一次 play 会保留该值。

Output 状态 ​

Audio 状态Video 状态说明
idleidle尚未输出媒体,或已经 detach
bufferingbuffering正在等待足够的媒体数据
playingrendering正在播放音频或渲染视频
pausedpausedReplay 已暂停
completedcompletedReplay 来源已经自然耗尽,并且该 Output 已排空
failedfailed当前 Output 无法继续输出媒体
成员适用对象说明
stateAudio、Video当前 Output 状态
onStateChangedAudio、VideoOutput 状态变化通知
onErrorAudio、Video当前 Output 的解码、播放或渲染错误
TiCloudStorageVideoOutputView(options)Video在 ArkUI 组件树中承载 Video Output;fit 默认为 contain
attach(replay, channelId)Audio、Video绑定 Replay 中指定 channelId 的媒体;Channel ID 取值为 0..255
takeSnapshot()Video把当前视频画面保存为唯一的临时 JPEG;Promise 成功时返回 TiCloudStorageSnapshotFile
detach()Audio、Video解除当前 Replay 绑定;对象仍可再次 attach
dispose()Audio、Video释放 Output;调用后不能继续使用该实例

TiCloudStorageVideoOutputView 只负责宿主渲染面,和 Replay 的 attach 相互独立;output 必填,fit 支持 contain 和 cover,其余尺寸与背景字段沿用 ArkUI 类型。组件从 ArkUI 树移除时解除渲染面,但不改变 Replay 绑定。

Snapshot 保存当前绑定和本次播放中最近一次成功呈现、且仍可读取的画面,不包含字幕、按钮等页面 UI。成功时 data.path 是 SDK 私有 cache 中的临时 JPEG。需要长期保存时由应用自行复制或移动,直接使用完成后调用 delete()。当前绑定和本次播放尚未成功出画时返回 no-frame;暂停保留当前画面,自然播放完成后只要最终画面仍在就可以截图。重新 attach、开始新一次 play、detach、移除 View 或清空画面后,必须等新画面成功呈现才能再次截图。

同一个 Video Output 同时只接受一个 Snapshot;已有请求未完成时,新 Promise resolve 为 in-use。不同 Output 仍可能因全局资源上限 resolve 为 resource-exhausted。Snapshot 完成前,dispose() 和 TiCloudStorage.shutdown() 返回 in-use,Output 及其绑定关系保持不变。

Video Output 和 Audio Output 分别使用设备配置提供的 channelId,取值范围是 0..255;两者可以相同,也可以不同。处理所有 enum 分支时,需要包含 paused 和 completed。

重复绑定同一个 Replay 的同一个 channel_id 会成功;已经绑定时传入不同 Replay 或 channel_id 返回 in-use 并保留原关系,必须先显式 detach。Replay 正在运行时新增或 detach 后重新绑定 Output,从绑定生效后的下一可独立解码位置开始,不补发此前媒体。同一个 Replay 的同一个 channel_id 只能绑定一个同类播放 Output。stop、自然完成和新 play 都保留绑定;dispose 不隐式解绑,关系仍存在时返回 in-use。某个 Output 解码、播放或渲染失败时,它的 onError 返回错误,并且只终止该 Output。Token、网络、所选范围过大或录像读取失败时,Replay 的 onError 返回一次错误,并使本次回放的全部 Output 进入 failed。

本地媒体文件 ​

typescript
export interface TiCloudStorageRecordingFile {
  readonly path: string;
  readonly durationMs: number;
  delete(): Promise<number>;
}

export interface TiCloudStorageSnapshotFile {
  readonly path: string;
  delete(): Promise<number>;
}

两个文件对象的 path 在成功返回时指向 SDK 私有 cache。OHOS SDK 只提供受限、幂等的 delete();需要长期保存时由应用自行复制或移动文件。成功返回的文件对象在对应 Task、Output、TiCloudStorage 实例或 SDK 关闭后仍可读取和删除。系统相册便利能力只由 Flutter 与 React Native SDK 提供。

TiCloudStorageRecordingTask ​

typescript
export interface TiCloudStorageStartRecordingOptions {
  readonly videoChannelId: number;
  readonly audioChannelId?: number;
}

export interface TiCloudStorageRecordingTask {
  stop(): Promise<Resp<TiCloudStorageRecordingFile>>;
}

TiCloudStorageReplay.startRecording(options) 同步返回 Resp<TiCloudStorageRecordingTask>。Replay 必须正在回放;视频 Channel 必填,音频 Channel 可空。同步失败不创建 Task。

RecordingTask 和 ExportTask 的 MP4 格式范围见确认录像可以生成 MP4。RecordingTask 期间,所选视频 Channel 的编码格式和分辨率必须保持不变;需要切换时先完成当前 Task,再用新格式创建 Task。ExportTask 遇到不兼容片段时会通过报告说明缺口,并在之后重新出现兼容、可独立解码的内容时继续处理。

stop() 停止接收新媒体,排空已接收数据并完成 MP4。第一次调用开始终结;重复调用返回同一个 Promise。Replay 自然结束时 Task 自动完成,随后调用 stop() 返回缓存结果。

Task 不公开 state、实时 duration、cancel 或 dispose。相同 Channel 可以创建多个 Task,SDK 为每个 Task 生成不同文件;两个视频 Channel 使用两个 Task。

TiCloudStorageExportTask ​

typescript
export interface TiCloudStorageExportOptions {
  readonly startTimeMs: number;
  readonly endTimeMs: number;
  readonly videoChannelId: number;
  readonly audioChannelId?: number;
}

export interface TiCloudStorageExportProgress {
  readonly fraction: number;
  readonly coveredDurationMs: number;
}

export interface TiCloudStorageExportSegment {
  readonly sourceRange: TiCloudStorageRecordingRange;
  readonly outputStartMs: number;
  readonly outputEndMs: number;
}

export enum TiCloudStorageExportTermination {
  exhausted = 0,
  interrupted = 1,
  cancelled = 2,
  failed = 3,
}

export interface TiCloudStorageExportReport {
  readonly requestedRange: TiCloudStorageRecordingRange;
  readonly coveredDurationMs: number;
  readonly segments: ReadonlyArray<TiCloudStorageExportSegment>;
  readonly gaps: ReadonlyArray<TiCloudStorageRecordingGap>;
  readonly unprocessedRanges: ReadonlyArray<TiCloudStorageRecordingRange>;
  readonly complete: boolean;
  readonly termination: TiCloudStorageExportTermination;
  readonly cause: number;
}

export interface TiCloudStorageExportResult {
  readonly file: TiCloudStorageRecordingFile;
  readonly report: TiCloudStorageExportReport;
}

export interface TiCloudStorageExportOutcome {
  readonly code: number;
  readonly file?: TiCloudStorageRecordingFile;
  readonly report?: TiCloudStorageExportReport;
}

export interface TiCloudStorageExportObserver {
  onProgressDetail?: (progress: TiCloudStorageExportProgress) => void;
  onRecordingGap?: (gap: TiCloudStorageRecordingGap) => void;
}

export interface TiCloudStorageExportTask {
  readonly progress: number;
  readonly progressDetail: TiCloudStorageExportProgress;
  readonly report?: TiCloudStorageExportReport;
  readonly result: Promise<Resp<TiCloudStorageRecordingFile>>;
  readonly detailedResult: Promise<Resp<TiCloudStorageExportResult>>;
  readonly completion: Promise<TiCloudStorageExportOutcome>;

  cancel(): number;
  stop(): Promise<Resp<TiCloudStorageRecordingFile>>;
}

TiCloudStorageExportObserver 可通过 onProgressDetail 接收扫描比例和已覆盖时长,通过 onRecordingGap 接收导出过程中确认的录像缺口。TiCloudStorageExportReport 包含请求范围、已覆盖时长、输出片段、缺口、未处理区间、完整性、结束方式和原因码。

cloudStorage.exportRecording(options, onProgress, observer) 在启动 Task 前固定实例当前的 Token,并保存可选回调,然后同步返回 Resp<TiCloudStorageExportTask>。成功只表示 Task 已经开始。

同步失败不创建 Task,也不调用回调。回调不会在 exportRecording 返回前触发。

progress 和 progressDetail.fraction 位于 0.0..1.0 且单调不回退;coveredDurationMs 表示已经写入结果文件的来源时长。进度达到 1.0 只表示请求范围扫描完成,不代表没有缺口。中间通知可以合并,属性始终返回当前快照。

result 保留原有文件结果,只需要导出可播放 MP4 时等待它即可。detailedResult 返回文件和报告,completion 无论成功失败都尽量保留可用报告;业务要求完整覆盖请求范围时,再等待详细结果并检查 report.complete == true、缺口和未处理区间。

cancel() 只发出非阻塞取消请求,最终状态仍以 completion 为准。取消胜出时不返回成功 MP4,但报告可以保留已经确认的覆盖、缺口和未处理范围。活动 Task 调用 stop() 会停止导出、清理未完成文件,并以 stopped 返回;它不会把当前内容封装成部分成功文件。自然完成或其他终局已经先发生时,cancel() / stop() 返回缓存的原结果。重复调用幂等。

Task 在最终结果返回后自动释放底层执行资源,不提供 dispose。不同 Task 相互独立并生成不同 cache 文件;资源达到上限返回 resource-exhausted。

原始音视频诊断采集 ​

ts
interface TiCloudStorageRawDumpOptions {
  readonly audioChannelIds?: ReadonlyArray<number>; // 0..255
  readonly videoChannelIds?: ReadonlyArray<number>; // 0..255
}

TiCloudStorageReplay.startRawDump(
  options: TiCloudStorageRawDumpOptions,
): Promise<Resp<TiRawDump>>

两个 Channel ID 数组至少填写一个。采集文件结构、5 分钟和 1 GiB 限制、完整性字段、单任务限制以及 SDK 缓存目录中的文件保留规则与 TiRTC 原始音视频诊断采集相同;停止采集后,下一次 TiRtcLogging.upload() 会附带已完成的采集文件。完整流程见接入客户端诊断能力。

TiRtcLogging ​

TiRtcLogging 用于上传 SDK 日志。完成 Ti 云存初始化后调用;上传成功后,把返回的 logId 提供给支持人员。开发阶段的入口设计和接入流程见接入客户端诊断能力。

ts
// 上传当前 SDK 日志;code == 0 且 logId 有值表示上传成功。
static upload(): Promise<TiRtcLoggingUploadResult>

正常日志不包含原始音视频;只有显式完成一次原始音视频诊断采集后,下一次上传才会附带采集文件。

相关类型:

ts
interface TiRtcLoggingUploadResult {
  code: number;
  logId?: string;
}

示例:

ts
import { TiRtcLogging } from 'tirtc/Index';

const result = await TiRtcLogging.upload();
if (result.code === 0 && result.logId !== undefined && result.logId.length > 0) {
  console.info(`Ti Cloud Storage logId=${result.logId}`);
}

调用前必须完成 TiCloudStorage.init,并等待 Promise 返回后再调用 TiCloudStorage.shutdown()。非 0 错误码或空 logId 表示没有取得可提交的日志编号;按问题排查保留错误码和原始日志。

错误码 ​

方法、结果对象和回调会返回完整整数错误码。常量列为“—”时没有对应的命名常量,错误码仍会原样返回。

错误码常量常见含义建议处理
0TI_CLOUD_STORAGE_ERROR_OK操作成功继续后续流程
6000TI_CLOUD_STORAGE_ERROR_INVALID_ARGUMENT参数缺失、取值越界或时间范围无效修正参数后重试
6001—尚未初始化 TiCloudStorage,或已经关闭先调用 TiCloudStorage.init
6014TI_CLOUD_STORAGE_ERROR_TOKEN_EXPIREDTi 云存 Token 已过期为同一设备更新 Token 后重新发起请求
6022—已使用另一组配置初始化保持初始化参数一致,或在全部资源释放后重新初始化
6024TI_CLOUD_STORAGE_ERROR_PERMISSION_DENIEDToken 无效,或无权访问目标设备或录像检查授权并重新取得 Token
6026TI_CLOUD_STORAGE_ERROR_IN_USE对象仍在播放、录制或执行任务,当前操作不能执行先结束活动操作,再重试
6027—尚未开始播放或录制先启动对应操作
6029—尚未建立当前操作要求的绑定完成对应绑定后重试
6030—缺少必要的目标或媒体通道配置补充通道或目标配置后重试
6043—当前设备没有足够资源创建或继续任务结束其他任务并释放资源后重试
6044—初始化时无法创建或打开 SDK 工作目录检查应用缓存目录和文件系统状态后重试
6045—删除临时媒体文件时无法读取文件状态确认文件对象来自当前 SDK 实例,并检查缓存文件系统
6046TI_CLOUD_STORAGE_ERROR_FILE_WRITE_FAILED无法创建或写入输出文件检查目录权限和磁盘空间
6113TI_CLOUD_STORAGE_ERROR_UNSUPPORTED_FORMAT当前操作遇到不支持的音视频格式;保存或导出任务内的视频编码格式或分辨率发生变化时也可能返回先确认失败的是播放、保存还是导出;保存或导出时按格式稳定的时间范围拆分任务
6114—底层 I/O 或运行时边界失败保留错误码并检查运行环境
6115TI_CLOUD_STORAGE_ERROR_CANCELLEDList 请求被取消结束对应等待
6117TI_CLOUD_STORAGE_ERROR_RANGE_TOO_LARGEList 查询跨度超过 10 天或合并结果超过 10000 项缩短查询范围后重试
6118TI_CLOUD_STORAGE_ERROR_NO_FRAMEVideo Output 尚无可用于截图的视频帧等待出画后重试
6119TI_CLOUD_STORAGE_ERROR_NO_RECORDABLE_MEDIA所选范围或通道没有可写入的媒体重新选择录像范围或通道
6120TI_CLOUD_STORAGE_ERROR_RECORDING_OVERRUN本地写入持续跟不上回放数据,保存任务已经终止释放设备资源、检查存储性能后重新保存
6122TI_CLOUD_STORAGE_ERROR_RECORDING_UNREADABLE录像文件已经下载,但 SDK 无法解密或解析出有效的音视频帧,当前任务无法继续不要持续重试同一文件;AAC 录像应确认每次写入都保留完整 ADTS 头,采样率和声道数与实际音频及 flags 一致,ADTS 声明的帧长度与本次写入字节数一致
6123TI_CLOUD_STORAGE_ERROR_UNAVAILABLESDK 无法完成录像查询或取得下载信息,通常是网络中断、Ti 云存服务暂时不可用或服务响应异常稍后重新查询;持续失败时上报日志
6124TI_CLOUD_STORAGE_ERROR_STOPPED活动 ExportTask 已被主动停止结束导出进度,不使用输出文件
6130—解码型 Output 持续收到同类媒体,但 5 秒内没有匹配绑定的 Channel ID核对设备上传与客户端绑定的 Channel ID,修正后重新播放
6134TI_CLOUD_STORAGE_ERROR_RECORDING_NOT_FOUND云端明确返回目标录像文件不存在;查询结果可能已过期,或文件已被删除刷新录像列表后重新选择,不持续重试同一文件
6135TI_CLOUD_STORAGE_ERROR_RECORDING_DOWNLOAD_FAILEDSDK 未能成功下载目标录像文件;常见原因包括请求签名失败、连接超时、HTTP 错误、响应不完整或有限重试耗尽稍后重试一次;持续失败时上报日志
6136TI_CLOUD_STORAGE_ERROR_NETWORK_UNAVAILABLE本地网络已经明确不可用等待网络恢复后重新发起操作
6137TI_CLOUD_STORAGE_ERROR_ENDPOINT_DNS_RESOLUTION_FAILED配置的服务地址域名无法解析检查 DNS、网络代理和自定义 endpoint;恢复后重试

业务分支优先使用公开常量;没有命名常量时可以直接比较返回的整数错误码。不要根据 errorToString 返回值或日志文本判断错误类型。

线程与生命周期 ​

  • 所有 callback 和 Promise completion 都进入 ArkUI 主线程。
  • Promise 不会在发起异步 API 的调用栈中同步完成。
  • dispose 是 checked 且可重试的:Replay 仍在播放、仍有 Output 绑定或活动 RecordingTask,或者 Output 仍绑定 Replay、仍被 TiCloudStorageVideoOutputView 承载或仍有活动 Snapshot 时返回 in-use。失败时对象及关系保持不变。
  • dispose 只有在 native destroy 真正成功后才返回 TI_CLOUD_STORAGE_ERROR_OK;重复调用幂等返回 TI_CLOUD_STORAGE_ERROR_OK。成功后普通方法返回 not-initialized,getter 保留最后提交值,不再触发普通状态 callback。
  • MP4 Task 在最终结果返回后自动释放底层执行资源,不需要额外 dispose。
  • Ti 云存和 Output 构造器只创建 ArkTS 对象,不申请底层资源,也不抛 SDK 运行错误;createReplay 同样只创建 Replay 对象。资源创建失败由第一次需要该资源的方法返回。

Ti 云存开发文档