tirtc-react-native 2.5.0-alpha.1 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/README.md +39 -6
  2. package/TiRtcReactNative.podspec +1 -1
  3. package/android/build.gradle +1 -1
  4. package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcModule.kt +137 -14
  5. package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeCleanup.kt +54 -19
  6. package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeCloudStorageCallbacks.kt +60 -0
  7. package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeEventBinder.kt +2 -0
  8. package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeEventSink.kt +20 -0
  9. package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeMaps.kt +112 -5
  10. package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeOptions.kt +2 -7
  11. package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeRegistry.kt +3 -0
  12. package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeStorageSupport.kt +46 -22
  13. package/ios/TiRtcReactNative+Conn.mm +61 -0
  14. package/ios/TiRtcReactNative+Output.mm +1 -7
  15. package/ios/TiRtcReactNative+Private.h +1 -0
  16. package/ios/TiRtcReactNative+Storage.mm +133 -35
  17. package/ios/TiRtcReactNative.mm +137 -48
  18. package/ios/TiRtcReactNativeCloudStorageCallbacks.h +13 -0
  19. package/ios/TiRtcReactNativeCloudStorageCallbacks.mm +67 -0
  20. package/ios/TiRtcReactNativeEventBinder.h +4 -0
  21. package/ios/TiRtcReactNativeEventBinder.mm +11 -0
  22. package/ios/TiRtcReactNativeEventSink.h +5 -0
  23. package/ios/TiRtcReactNativeEventSink.mm +18 -0
  24. package/ios/TiRtcReactNativeMaps.h +6 -0
  25. package/ios/TiRtcReactNativeMaps.mm +47 -0
  26. package/ios/TiRtcReactNativeOptions.mm +2 -6
  27. package/lib/module/audio_input.js +23 -4
  28. package/lib/module/audio_input.js.map +1 -1
  29. package/lib/module/build_identity.js +1 -1
  30. package/lib/module/conn.js +19 -0
  31. package/lib/module/conn.js.map +1 -1
  32. package/lib/module/events.js +16 -9
  33. package/lib/module/events.js.map +1 -1
  34. package/lib/module/index.js +3 -2
  35. package/lib/module/index.js.map +1 -1
  36. package/lib/module/raw_dump.js +53 -0
  37. package/lib/module/raw_dump.js.map +1 -0
  38. package/lib/module/specs/NativeTiRtc.js.map +1 -1
  39. package/lib/module/storage.js +185 -33
  40. package/lib/module/storage.js.map +1 -1
  41. package/lib/module/types.js +0 -4
  42. package/lib/module/types.js.map +1 -1
  43. package/lib/module/video_input.js +16 -6
  44. package/lib/module/video_input.js.map +1 -1
  45. package/lib/typescript/conn.d.ts +2 -0
  46. package/lib/typescript/index.d.ts +5 -3
  47. package/lib/typescript/native.d.ts +1 -1
  48. package/lib/typescript/raw_dump.d.ts +35 -0
  49. package/lib/typescript/specs/NativeTiRtc.d.ts +74 -2
  50. package/lib/typescript/storage.d.ts +82 -3
  51. package/lib/typescript/types.d.ts +5 -6
  52. package/package.json +2 -2
  53. package/src/audio_input.ts +30 -11
  54. package/src/conn.ts +23 -0
  55. package/src/events.ts +14 -9
  56. package/src/index.ts +17 -1
  57. package/src/native.ts +7 -1
  58. package/src/raw_dump.ts +84 -0
  59. package/src/specs/NativeTiRtc.ts +79 -2
  60. package/src/storage.ts +256 -39
  61. package/src/types.ts +5 -8
  62. package/src/video_input.ts +22 -12
@@ -3,6 +3,7 @@ import { type ViewProps } from 'react-native';
3
3
  import { NativeTiRtc, type NativeTiRtcEvent } from './native';
4
4
  import { type NativeIdentity } from './native_object_id';
5
5
  import { type Resp, type TiRtcGalleryAsset } from './recording';
6
+ import { TiRawDump, type TiCloudStorageRawDumpOptions } from './raw_dump';
6
7
  export declare const TI_CLOUD_STORAGE_ERROR_OK: 0;
7
8
  export declare const TI_CLOUD_STORAGE_ERROR_INVALID_ARGUMENT: 6000;
8
9
  export declare const TI_CLOUD_STORAGE_ERROR_NOT_INITIALIZED: 6001;
@@ -45,6 +46,69 @@ export type TiCloudStorageRecordingDaysResult = Readonly<{
45
46
  code: number;
46
47
  days: ReadonlyArray<TiCloudStorageRecordingDay>;
47
48
  }>;
49
+ export declare const TiCloudStorageRecordingTrackKind: {
50
+ readonly video: "video";
51
+ readonly audio: "audio";
52
+ };
53
+ export type TiCloudStorageRecordingTrackKind = (typeof TiCloudStorageRecordingTrackKind)[keyof typeof TiCloudStorageRecordingTrackKind];
54
+ export type TiCloudStorageRecordingTrack = Readonly<{
55
+ kind: TiCloudStorageRecordingTrackKind;
56
+ channelId: number;
57
+ }>;
58
+ export declare const TiCloudStorageRecordingGapReason: {
59
+ readonly unknown: "unknown";
60
+ readonly notFound: "notFound";
61
+ readonly downloadFailed: "downloadFailed";
62
+ readonly integrityFailed: "integrityFailed";
63
+ readonly mediaUnreadable: "mediaUnreadable";
64
+ readonly noKeyFrame: "noKeyFrame";
65
+ readonly noRecording: "noRecording";
66
+ readonly decryptionFailed: "decryptionFailed";
67
+ readonly unsupportedMedia: "unsupportedMedia";
68
+ readonly trackUnavailable: "trackUnavailable";
69
+ };
70
+ export type TiCloudStorageRecordingGapReason = (typeof TiCloudStorageRecordingGapReason)[keyof typeof TiCloudStorageRecordingGapReason];
71
+ export type TiCloudStorageRecordingGap = Readonly<{
72
+ range: TiCloudStorageRecordingRange;
73
+ tracks: ReadonlyArray<TiCloudStorageRecordingTrack>;
74
+ reasons: ReadonlyArray<TiCloudStorageRecordingGapReason>;
75
+ }>;
76
+ export type TiCloudStorageExportProgress = Readonly<{
77
+ fraction: number;
78
+ coveredDurationMs: number;
79
+ }>;
80
+ export type TiCloudStorageExportSegment = Readonly<{
81
+ sourceRange: TiCloudStorageRecordingRange;
82
+ outputStartMs: number;
83
+ outputEndMs: number;
84
+ }>;
85
+ export declare const TiCloudStorageExportTermination: {
86
+ readonly exhausted: "exhausted";
87
+ readonly interrupted: "interrupted";
88
+ readonly cancelled: "cancelled";
89
+ readonly failed: "failed";
90
+ };
91
+ export type TiCloudStorageExportTermination = (typeof TiCloudStorageExportTermination)[keyof typeof TiCloudStorageExportTermination];
92
+ export type TiCloudStorageExportReport = Readonly<{
93
+ requestedRange: TiCloudStorageRecordingRange;
94
+ coveredDurationMs: number;
95
+ segments: ReadonlyArray<TiCloudStorageExportSegment>;
96
+ gaps: ReadonlyArray<TiCloudStorageRecordingGap>;
97
+ unprocessedRanges: ReadonlyArray<TiCloudStorageRecordingRange>;
98
+ complete: boolean;
99
+ termination: TiCloudStorageExportTermination;
100
+ cause: number;
101
+ }>;
102
+ export type TiCloudStorageExportOutcome = Readonly<{
103
+ code: number;
104
+ file: TiCloudStorageRecordingFile | null;
105
+ report: TiCloudStorageExportReport | null;
106
+ }>;
107
+ export type TiCloudStorageExportObserver = Readonly<{
108
+ onProgress?: (progress: number) => void;
109
+ onProgressDetail?: (progress: TiCloudStorageExportProgress) => void;
110
+ onRecordingGap?: (gap: TiCloudStorageRecordingGap) => void;
111
+ }>;
48
112
  export declare const TiCloudStorageReplaySpeed: {
49
113
  readonly x0_125: "x0_125";
50
114
  readonly x0_25: "x0_25";
@@ -99,6 +163,7 @@ export declare class TiCloudStorage {
99
163
  private token;
100
164
  private identity;
101
165
  private disposed;
166
+ private pendingAsyncOperations;
102
167
  constructor(token: string);
103
168
  static init(options: Readonly<{
104
169
  appId: string;
@@ -111,19 +176,22 @@ export declare class TiCloudStorage {
111
176
  listRecordings(startTimeMs: number, endTimeMs: number): Promise<TiCloudStorageRecordingRangesResult>;
112
177
  listRecordingDays(startDate: string, endDate: string, timeZoneId?: string): Promise<TiCloudStorageRecordingDaysResult>;
113
178
  createReplay(): TiCloudStorageReplay;
114
- exportRecording(options: TiCloudStorageExportOptions, onProgress?: (progress: number) => void): Resp<TiCloudStorageExportTask>;
179
+ exportRecording(options: TiCloudStorageExportOptions, observer?: ((progress: number) => void) | TiCloudStorageExportObserver): Resp<TiCloudStorageExportTask>;
115
180
  dispose(): number;
181
+ private trackAsyncOperation;
116
182
  private ensureIdentity;
117
183
  }
118
184
  export declare class TiCloudStorageReplay {
119
185
  private readonly cloudStorage;
120
186
  private identity;
121
187
  private disposed;
188
+ private inCallback;
122
189
  private currentSpeed;
123
190
  private currentTime;
124
191
  onTimeChanged: ((timeMs: number) => void) | null;
125
192
  onError: ((code: number) => void) | null;
126
193
  onCompleted: (() => void) | null;
194
+ onRecordingGap: ((gap: TiCloudStorageRecordingGap) => void) | null;
127
195
  constructor(cloudStorage: TiCloudStorage);
128
196
  get speed(): TiCloudStorageReplaySpeed;
129
197
  get currentTimeMs(): number | null;
@@ -133,6 +201,7 @@ export declare class TiCloudStorageReplay {
133
201
  seek(timeMs: number): number;
134
202
  setSpeed(speed: TiCloudStorageReplaySpeed): number;
135
203
  startRecording(options: TiCloudStorageStartRecordingOptions): Resp<TiCloudStorageRecordingTask>;
204
+ startRawDump(options: TiCloudStorageRawDumpOptions): Promise<Resp<TiRawDump>>;
136
205
  stop(): number;
137
206
  dispose(): number;
138
207
  private command;
@@ -198,11 +267,21 @@ export declare class TiCloudStorageRecordingTask {
198
267
  export declare class TiCloudStorageExportTask {
199
268
  private readonly taskId;
200
269
  private readonly owner;
201
- private readonly onProgress?;
202
270
  private resultPromise;
203
- constructor(taskId: number, owner: TiCloudStorage, onProgress?: ((progress: number) => void) | undefined);
271
+ private completionPromise;
272
+ private readonly identity;
273
+ private currentProgressDetail;
274
+ private currentReport;
275
+ private readonly observer;
276
+ private terminal;
277
+ constructor(taskId: number, generation: number, owner: TiCloudStorage, observer?: ((progress: number) => void) | TiCloudStorageExportObserver);
204
278
  get progress(): number;
279
+ get progressDetail(): TiCloudStorageExportProgress;
280
+ get report(): TiCloudStorageExportReport | null;
281
+ get completion(): Promise<TiCloudStorageExportOutcome>;
205
282
  get result(): Promise<Resp<TiCloudStorageRecordingFile>>;
283
+ cancel(): number;
206
284
  stop(): Promise<Resp<TiCloudStorageRecordingFile>>;
285
+ private handleEvent;
207
286
  }
208
287
  export {};
@@ -66,11 +66,6 @@ export declare const TiRtcVideoCodec: {
66
66
  readonly mjpeg: "mjpeg";
67
67
  };
68
68
  export type TiRtcVideoCodec = (typeof TiRtcVideoCodec)[keyof typeof TiRtcVideoCodec];
69
- export declare const TiRtcVideoEncoderCodec: {
70
- readonly h264: "h264";
71
- readonly mjpeg: "mjpeg";
72
- };
73
- export type TiRtcVideoEncoderCodec = (typeof TiRtcVideoEncoderCodec)[keyof typeof TiRtcVideoEncoderCodec];
74
69
  export declare const TiRtcVideoFrameRate: {
75
70
  readonly fps10: "fps10";
76
71
  readonly fps15: "fps15";
@@ -145,6 +140,9 @@ export type TiRtcVideoOutputViewProps = ViewProps & Readonly<{
145
140
  resizeMode?: 'contain' | 'cover' | 'stretch';
146
141
  }>;
147
142
  export type TiRtcAudioInputOptions = Readonly<{
143
+ /** Nano audio media: 1 PCM, 2 G711A, 3 AAC, 4 Opus, 5 AMR. Omitted or -1 uses codec. */
144
+ media?: number;
145
+ /** @deprecated Use media. The legacy default is g711a. */
148
146
  codec?: TiRtcAudioCodec;
149
147
  sampleRate?: TiRtcAudioSampleRate;
150
148
  channels?: TiRtcAudioChannelCount;
@@ -153,7 +151,8 @@ export type TiRtcAudioInputOptions = Readonly<{
153
151
  ansLevel?: TiRtcAudioAnsLevel;
154
152
  }>;
155
153
  export type TiRtcVideoInputOptions = Readonly<{
156
- codec?: TiRtcVideoEncoderCodec;
154
+ /** Nano video media: 66 H.264 (default) or 65 MJPEG. */
155
+ media?: number;
157
156
  width?: number;
158
157
  height?: number;
159
158
  frameRate?: TiRtcVideoFrameRate;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tirtc-react-native",
3
- "version": "2.5.0-alpha.1",
3
+ "version": "2.5.0",
4
4
  "description": "TiRTC React Native SDK",
5
5
  "homepage": "https://tange.ai/",
6
6
  "repository": {
@@ -49,7 +49,7 @@
49
49
  "build": "node scripts/clean_generated_lib.mjs && tsc -p tsconfig.build.json && node scripts/freeze_build_identity.mjs && node scripts/write_codegen_component_specs.mjs",
50
50
  "lint": "node test/source_guard.mjs",
51
51
  "preflight:npm": "node scripts/npm_preflight.mjs",
52
- "test": "node test/parity_guard.mjs && node test/package_artifact_guard.mjs && node test/lifecycle_contract_guard.mjs && node test/lifecycle_behavior_guard.mjs && node test/integration_contract_guard.mjs && node test/runner_schema_guard.mjs",
52
+ "test": "node test/parity_guard.mjs && node test/package_artifact_guard.mjs && node test/lifecycle_contract_guard.mjs && node test/lifecycle_behavior_guard.mjs && node test/integration_contract_guard.mjs && node test/runner_schema_guard.mjs && node --test test/source_fingerprint.test.mjs",
53
53
  "test:contract-red": "node test/contract_red_summary.mjs",
54
54
  "typecheck": "tsc -p tsconfig.json --noEmit",
55
55
  "codegen:check": "node test/codegen_contract_guard.mjs"
@@ -21,6 +21,7 @@ export class TiRtcAudioInput {
21
21
  private queue: Promise<unknown> = Promise.resolve();
22
22
  private currentState: TiRtcInputState = 'idle';
23
23
  private options: Required<TiRtcAudioInputOptions> = {
24
+ media: -1,
24
25
  codec: 'g711a',
25
26
  sampleRate: 'rate16k',
26
27
  channels: 'mono',
@@ -58,8 +59,20 @@ export class TiRtcAudioInput {
58
59
  if (!isPlainObject(options)) {
59
60
  return Promise.resolve(TIRTC_ERROR_INVALID_ARGUMENT);
60
61
  }
62
+ const media = options.media === undefined ? -1 : options.media;
63
+ const source = media === -1 ? (options.codec === undefined ? 'default' : 'legacy') : 'media';
64
+ const rawLegacy = options.codec === undefined ? 'omitted' :
65
+ ['g711a', 'aac', 'pcm', 'opus', 'amr'].includes(options.codec) ? options.codec : 'invalid';
66
+ const legacyCodec = options.codec ?? 'g711a';
67
+ if (!Number.isInteger(media) || ![-1, 1, 2, 3, 4, 5].includes(media) ||
68
+ (media === -1 && !['g711a', 'aac', 'pcm', 'opus', 'amr'].includes(legacyCodec))) {
69
+ logRtcOutcome('audio_input_set_options', TIRTC_ERROR_INVALID_ARGUMENT,
70
+ ` nano_media=${typeof media === 'number' ? media : typeof media} legacy_codec=${rawLegacy} source=${source}`);
71
+ return Promise.resolve(TIRTC_ERROR_INVALID_ARGUMENT);
72
+ }
61
73
  const normalized = {
62
- codec: options.codec ?? 'g711a',
74
+ media,
75
+ codec: media === -1 ? legacyCodec : 'g711a' as const,
63
76
  sampleRate: options.sampleRate ?? 'rate16k',
64
77
  channels: options.channels ?? 'mono',
65
78
  aecMode: options.aecMode ?? 'disabled',
@@ -72,6 +85,8 @@ export class TiRtcAudioInput {
72
85
  return identity;
73
86
  }
74
87
  const code = await NativeTiRtc.audioInputSetOptions(identity.objectId, normalized);
88
+ logRtcOutcome('audio_input_set_options', code,
89
+ ` nano_media=${media} legacy_codec=${rawLegacy} source=${source} sample_rate=${['rate8k', 'rate16k'].includes(normalized.sampleRate) ? normalized.sampleRate : 'invalid'} channels=${normalized.channels === 'mono' ? 'mono' : 'invalid'}`);
75
90
  if (code === TIRTC_ERROR_OK) {
76
91
  this.options = normalized;
77
92
  }
@@ -100,16 +115,20 @@ export class TiRtcAudioInput {
100
115
  }
101
116
 
102
117
  start(): Promise<number> {
103
- return this.logged(
104
- 'audio_input_start',
105
- this.enqueue(async () => {
106
- const identity = this.ensureIdentity();
107
- if (typeof identity === 'number') {
108
- return identity;
109
- }
110
- return NativeTiRtc.audioInputStart(identity.objectId);
111
- }),
112
- );
118
+ return this.enqueue(async () => {
119
+ const identity = this.ensureIdentity();
120
+ if (typeof identity === 'number') {
121
+ logRtcOutcome('audio_input_start', identity);
122
+ return identity;
123
+ }
124
+ const wasRunning = this.state === 'running';
125
+ const code = await NativeTiRtc.audioInputStart(identity.objectId);
126
+ if (code !== TIRTC_ERROR_OK || !wasRunning) {
127
+ logRtcOutcome('audio_input_start', code,
128
+ ` object_id=${identity.objectId} nano_media=${this.options.media} legacy_codec=${this.options.codec} sample_rate=${this.options.sampleRate} channels=${this.options.channels}`);
129
+ }
130
+ return code;
131
+ });
113
132
  }
114
133
 
115
134
  stop(): Promise<number> {
package/src/conn.ts CHANGED
@@ -27,6 +27,12 @@ import type {
27
27
  TiRtcOnConnStateChanged,
28
28
  TiRtcOnConnStreamMessage,
29
29
  } from './types';
30
+ import {
31
+ createRawDumpFromNative,
32
+ normalizeRawDumpIds,
33
+ TiRawDump,
34
+ type TiRtcRawDumpOptions,
35
+ } from './raw_dump';
30
36
 
31
37
  export class TiRtcConn {
32
38
  private identity: NativeIdentity | null = null;
@@ -59,6 +65,23 @@ export class TiRtcConn {
59
65
  return typeof identity === 'number' ? recordingFailure(identity) : startRecording(identity.objectId, options);
60
66
  }
61
67
 
68
+ async startRawDump(options: TiRtcRawDumpOptions): Promise<Resp<TiRawDump>> {
69
+ if (options === null || typeof options !== 'object') return recordingFailure(TIRTC_ERROR_INVALID_ARGUMENT);
70
+ const audio = normalizeRawDumpIds(options.audioStreamIds ?? [], 15);
71
+ const video = normalizeRawDumpIds(options.videoStreamIds ?? [], 15);
72
+ const uplinkAudio = normalizeRawDumpIds(options.uplinkAudioStreamIds ?? [], 15);
73
+ if (audio === null || video === null || uplinkAudio === null ||
74
+ (audio.length === 0 && video.length === 0 && uplinkAudio.length === 0)) {
75
+ return recordingFailure(TIRTC_ERROR_INVALID_ARGUMENT);
76
+ }
77
+ const identity = this.ensureIdentity();
78
+ if (typeof identity === 'number') return recordingFailure(identity);
79
+ const result = await NativeTiRtc.connStartRawDump(identity.objectId, audio, video, uplinkAudio);
80
+ return result.code === 0 && result.dumpId !== null
81
+ ? {success: true, code: null, message: null, data: createRawDumpFromNative(result.dumpId)}
82
+ : recordingFailure(result.code);
83
+ }
84
+
62
85
  get state(): TiRtcConnState {
63
86
  if (this.identity !== null && !this.disposed) {
64
87
  const result = NativeTiRtc.connGetState(this.identity.objectId);
package/src/events.ts CHANGED
@@ -16,20 +16,25 @@ function ensureSubscribed(): void {
16
16
  return;
17
17
  }
18
18
  subscription = NativeTiRtc.onTiRtcEvent((event) => {
19
- if (!isPositiveInt32(event.objectId) || !isPositiveInt32(event.generation)) {
20
- return;
21
- }
22
- const handler = handlers.get(eventKey({
23
- objectId: event.objectId,
24
- generation: event.generation,
25
- }));
26
- if (handler !== undefined) {
27
- handler(event);
19
+ if (event.type === 'tiCloudStorageCallbackReady') {
20
+ const pending = NativeTiRtc.tiCloudStorageTakeCallback();
21
+ if (pending === null) return;
22
+ try {
23
+ deliver(pending.event);
24
+ } finally {
25
+ NativeTiRtc.tiCloudStorageAcknowledgeCallback(pending.deliveryId);
26
+ }
28
27
  return;
29
28
  }
29
+ deliver(event);
30
30
  });
31
31
  }
32
32
 
33
+ function deliver(event: NativeTiRtcEvent): void {
34
+ if (!isPositiveInt32(event.objectId) || !isPositiveInt32(event.generation)) return;
35
+ handlers.get(eventKey({objectId: event.objectId, generation: event.generation}))?.(event);
36
+ }
37
+
33
38
  export function registerNativeEventHandler(identity: NativeIdentity, handler: NativeEventHandler): void {
34
39
  handlers.set(eventKey(identity), handler);
35
40
  ensureSubscribed();
package/src/index.ts CHANGED
@@ -9,7 +9,6 @@ export {
9
9
  TiRtcAudioAgcLevel,
10
10
  TiRtcAudioAnsLevel,
11
11
  TiRtcVideoCodec,
12
- TiRtcVideoEncoderCodec,
13
12
  TiRtcVideoFrameRate,
14
13
  TiRtcCameraFacing,
15
14
  TiRtcVideoDecoderPreference,
@@ -60,6 +59,13 @@ export {TiRtcAudioInput} from './audio_input';
60
59
  export {TiRtcVideoInput, TiRtcVideoInputPreview} from './video_input';
61
60
  export {TiRtcLogging} from './logging';
62
61
  export {TiRtcRecordingTask} from './recording';
62
+ export {TiRawDump} from './raw_dump';
63
+ export type {
64
+ TiRtcRawDumpOptions,
65
+ TiCloudStorageRawDumpOptions,
66
+ TiRawDumpStopReason,
67
+ TiRawDumpArchive,
68
+ } from './raw_dump';
63
69
  export type {
64
70
  Resp,
65
71
  TiRtcGalleryAsset,
@@ -95,6 +101,9 @@ export {
95
101
  TI_CLOUD_STORAGE_ERROR_NETWORK_UNAVAILABLE,
96
102
  TI_CLOUD_STORAGE_ERROR_ENDPOINT_DNS_RESOLUTION_FAILED,
97
103
  TiCloudStorageReplaySpeed,
104
+ TiCloudStorageRecordingTrackKind,
105
+ TiCloudStorageRecordingGapReason,
106
+ TiCloudStorageExportTermination,
98
107
  TiCloudStorageAudioOutputState,
99
108
  TiCloudStorageVideoOutputState,
100
109
  TiCloudStorage,
@@ -107,6 +116,13 @@ export {
107
116
  } from './storage';
108
117
  export type {
109
118
  TiCloudStorageRecordingRange,
119
+ TiCloudStorageRecordingTrack,
120
+ TiCloudStorageRecordingGap,
121
+ TiCloudStorageExportProgress,
122
+ TiCloudStorageExportSegment,
123
+ TiCloudStorageExportReport,
124
+ TiCloudStorageExportOutcome,
125
+ TiCloudStorageExportObserver,
110
126
  TiCloudStorageRecordingRangesResult,
111
127
  TiCloudStorageRecordingDay,
112
128
  TiCloudStorageRecordingDaysResult,
package/src/native.ts CHANGED
@@ -3,4 +3,10 @@ import NativeTiRtcVideoInputPreview from './specs/TiRtcVideoInputPreviewNativeCo
3
3
  import NativeTiRtcVideoOutputView from './specs/TiRtcVideoOutputViewNativeComponent';
4
4
 
5
5
  export {NativeTiRtc, NativeTiRtcVideoOutputView, NativeTiRtcVideoInputPreview};
6
- export type {NativeTiRtcEvent} from './specs/NativeTiRtc';
6
+ export type {
7
+ NativeTiRtcEvent,
8
+ NativeTiCloudStorageExportProgress,
9
+ NativeTiCloudStorageExportReport,
10
+ NativeTiCloudStorageRecordingGap,
11
+ NativeRawDumpArchive,
12
+ } from './specs/NativeTiRtc';
@@ -0,0 +1,84 @@
1
+ import {isFiniteSafeInteger, TIRTC_ERROR_INVALID_ARGUMENT} from './errors';
2
+ import {NativeTiRtc, type NativeRawDumpArchive} from './native';
3
+ import type {Resp} from './recording';
4
+
5
+ export type TiRawDumpStopReason =
6
+ | 'unknown' | 'user' | 'timeLimit' | 'byteLimit' | 'sourceClosed'
7
+ | 'resourceLimit' | 'writeFailed';
8
+
9
+ export type TiRtcRawDumpOptions = Readonly<{
10
+ /** Remote downlink audio stream IDs. */
11
+ audioStreamIds?: ReadonlyArray<number>;
12
+ /** Remote downlink video stream IDs. */
13
+ videoStreamIds?: ReadonlyArray<number>;
14
+ /** Local uplink audio stream IDs used by TiRtcAudioInput.attach. */
15
+ uplinkAudioStreamIds?: ReadonlyArray<number>;
16
+ }>;
17
+
18
+ export type TiCloudStorageRawDumpOptions = Readonly<{
19
+ audioChannelIds?: ReadonlyArray<number>;
20
+ videoChannelIds?: ReadonlyArray<number>;
21
+ }>;
22
+
23
+ export type TiRawDumpArchive = Readonly<{
24
+ captureId: string; path: string; size: number; sha256: string; capturedDurationMs: number;
25
+ captureComplete: boolean; stopReason: TiRawDumpStopReason;
26
+ unsavedPacketCount: number; unsavedByteCount: number; empty: boolean;
27
+ }>;
28
+
29
+ const reasons: ReadonlyArray<TiRawDumpStopReason> = [
30
+ 'unknown', 'user', 'timeLimit', 'byteLimit', 'sourceClosed', 'resourceLimit', 'writeFailed',
31
+ ];
32
+
33
+ function archiveFromNative(value: NativeRawDumpArchive): TiRawDumpArchive {
34
+ return {...value, stopReason: reasons[value.stopReason] ?? 'unknown'};
35
+ }
36
+
37
+ function failure<T>(code: number): Resp<T> {
38
+ return {success: false, code, message: null, data: null};
39
+ }
40
+
41
+ export function normalizeRawDumpIds(
42
+ value: unknown,
43
+ maximum: number,
44
+ ): ReadonlyArray<number> | null {
45
+ if (!Array.isArray(value)) return null;
46
+ const result = new Set<number>();
47
+ for (const item of value) {
48
+ if (!isFiniteSafeInteger(item) || item < 0 || item > maximum) return null;
49
+ result.add(item);
50
+ }
51
+ return [...result];
52
+ }
53
+
54
+ export class TiRawDump {
55
+ private stopPromise: Promise<Resp<TiRawDumpArchive>> | null = null;
56
+
57
+ private constructor(private readonly nativeId: number) {}
58
+
59
+ stop(): Promise<Resp<TiRawDumpArchive>> {
60
+ if (this.stopPromise === null) {
61
+ this.stopPromise = NativeTiRtc.rawDumpStop(this.nativeId).then((result) => {
62
+ if (result.code !== 0 || result.archive === null) {
63
+ if (!result.terminal) this.stopPromise = null;
64
+ return failure<TiRawDumpArchive>(result.code);
65
+ }
66
+ const archive = archiveFromNative(result.archive);
67
+ return {success: true, code: null, message: null, data: archive};
68
+ }).catch(() => {
69
+ this.stopPromise = null;
70
+ return failure<TiRawDumpArchive>(TIRTC_ERROR_INVALID_ARGUMENT);
71
+ });
72
+ }
73
+ return this.stopPromise!;
74
+ }
75
+
76
+ async dispose(): Promise<number> {
77
+ const result = await this.stop();
78
+ return result.success ? 0 : result.code ?? TIRTC_ERROR_INVALID_ARGUMENT;
79
+ }
80
+ }
81
+
82
+ export function createRawDumpFromNative(nativeId: number): TiRawDump {
83
+ return Reflect.construct(TiRawDump, [nativeId]) as TiRawDump;
84
+ }
@@ -36,6 +36,7 @@ export type NativeVideoOutputOptions = Readonly<{
36
36
  }>;
37
37
 
38
38
  export type NativeAudioInputOptions = Readonly<{
39
+ media: number;
39
40
  codec: 'g711a' | 'aac' | 'pcm' | 'opus' | 'amr';
40
41
  sampleRate: 'rate8k' | 'rate16k';
41
42
  channels: 'mono';
@@ -45,7 +46,7 @@ export type NativeAudioInputOptions = Readonly<{
45
46
  }>;
46
47
 
47
48
  export type NativeVideoInputOptions = Readonly<{
48
- codec: 'h264' | 'mjpeg';
49
+ media: number;
49
50
  width: number;
50
51
  height: number;
51
52
  frameRate: 'fps10' | 'fps15' | 'fps30';
@@ -102,11 +103,63 @@ export type NativeLoggingUploadResult = Readonly<{
102
103
  logId: string | null;
103
104
  }>;
104
105
 
106
+ export type NativeRawDumpStartResult = Readonly<{code: number; dumpId: NativeObjectId | null}>;
107
+ export type NativeRawDumpArchive = Readonly<{
108
+ captureId: string; path: string; size: number; sha256: string; capturedDurationMs: number;
109
+ captureComplete: boolean; stopReason: number;
110
+ unsavedPacketCount: number; unsavedByteCount: number; empty: boolean;
111
+ }>;
112
+ export type NativeRawDumpStopResult = Readonly<{
113
+ code: number; archive: NativeRawDumpArchive | null; terminal: boolean;
114
+ }>;
115
+
105
116
  export type NativeTiCloudStorageRecordingRange = Readonly<{
106
117
  startTimeMs: number;
107
118
  endTimeMs: number;
108
119
  }>;
109
120
 
121
+ export type NativeTiCloudStorageRecordingTrack = Readonly<{
122
+ kind: number;
123
+ channelId: number;
124
+ }>;
125
+
126
+ export type NativeTiCloudStorageRecordingGap = Readonly<{
127
+ range: NativeTiCloudStorageRecordingRange;
128
+ tracks: ReadonlyArray<NativeTiCloudStorageRecordingTrack>;
129
+ reasons: ReadonlyArray<number>;
130
+ }>;
131
+
132
+ export type NativeTiCloudStorageExportProgress = Readonly<{
133
+ fraction: number;
134
+ coveredDurationMs: number;
135
+ }>;
136
+
137
+ export type NativeTiCloudStorageExportSegment = Readonly<{
138
+ sourceRange: NativeTiCloudStorageRecordingRange;
139
+ outputStartMs: number;
140
+ outputEndMs: number;
141
+ }>;
142
+
143
+ export type NativeTiCloudStorageExportReport = Readonly<{
144
+ requestedRange: NativeTiCloudStorageRecordingRange;
145
+ coveredDurationMs: number;
146
+ segments: ReadonlyArray<NativeTiCloudStorageExportSegment>;
147
+ gaps: ReadonlyArray<NativeTiCloudStorageRecordingGap>;
148
+ unprocessedRanges: ReadonlyArray<NativeTiCloudStorageRecordingRange>;
149
+ complete: boolean;
150
+ termination: number;
151
+ cause: number;
152
+ }>;
153
+
154
+ export type NativeTiCloudStorageExportResult = Readonly<{
155
+ code: number;
156
+ fileId: NativeObjectId | null;
157
+ filePath: string | null;
158
+ durationMs: number | null;
159
+ report: NativeTiCloudStorageExportReport | null;
160
+ progressDetail: NativeTiCloudStorageExportProgress | null;
161
+ }>;
162
+
110
163
  export type NativeTiCloudStorageRecordingRangesResult = Readonly<{
111
164
  code: number;
112
165
  recordings: ReadonlyArray<NativeTiCloudStorageRecordingRange>;
@@ -131,6 +184,7 @@ export type NativeTiCloudStorageReplayInfo = Readonly<{
131
184
  export type NativeTiCloudStorageTaskStartResult = Readonly<{
132
185
  code: number;
133
186
  taskId: NativeObjectId | null;
187
+ generation: number;
134
188
  }>;
135
189
 
136
190
  export type NativeTiRtcEvent = Readonly<{
@@ -147,6 +201,8 @@ export type NativeTiRtcEvent = Readonly<{
147
201
  data?: NativeBytes;
148
202
  size?: NativeSize;
149
203
  fps?: number;
204
+ exportProgress?: NativeTiCloudStorageExportProgress;
205
+ recordingGap?: NativeTiCloudStorageRecordingGap;
150
206
  }>;
151
207
 
152
208
  type NativeConnMetricsResult = Readonly<{
@@ -242,6 +298,11 @@ type NativeVideoOutputDebugSnapshotResult = Readonly<{
242
298
  }> | null;
243
299
  }>;
244
300
 
301
+ type NativeTiCloudStorageCallback = Readonly<{
302
+ deliveryId: number;
303
+ event: NativeTiRtcEvent;
304
+ }>;
305
+
245
306
  interface Spec extends TurboModule {
246
307
  readonly onTiRtcEvent: CodegenTypes.EventEmitter<NativeTiRtcEvent>;
247
308
 
@@ -251,6 +312,8 @@ interface Spec extends TurboModule {
251
312
  writeLog(level: number, tag: string, message: string): number;
252
313
  uploadLogs(): Promise<NativeLoggingUploadResult>;
253
314
 
315
+ tiCloudStorageTakeCallback(): NativeTiCloudStorageCallback | null;
316
+ tiCloudStorageAcknowledgeCallback(deliveryId: number): number;
254
317
  tiCloudStorageInitialize(options: NativeInitOptions): Promise<number>;
255
318
  tiCloudStorageShutdown(): number;
256
319
  tiCloudStorageCreate(token: string): NativeCreateResult;
@@ -275,7 +338,9 @@ interface Spec extends TurboModule {
275
338
  audioChannelId: number | null,
276
339
  ): NativeTiCloudStorageTaskStartResult;
277
340
  tiCloudStorageExportProgress(id: NativeObjectId): number;
278
- tiCloudStorageExportResult(id: NativeObjectId): Promise<NativeMp4Result>;
341
+ tiCloudStorageExportProgressDetail(id: NativeObjectId): NativeTiCloudStorageExportProgress;
342
+ tiCloudStorageExportResult(id: NativeObjectId): Promise<NativeTiCloudStorageExportResult>;
343
+ tiCloudStorageExportCancel(id: NativeObjectId): number;
279
344
  tiCloudStorageExportStop(id: NativeObjectId): number;
280
345
  tiCloudStorageDispose(id: NativeObjectId): number;
281
346
 
@@ -290,6 +355,11 @@ interface Spec extends TurboModule {
290
355
  videoChannelId: number,
291
356
  audioChannelId: number | null,
292
357
  ): NativeTiCloudStorageTaskStartResult;
358
+ tiCloudStorageReplayStartRawDump(
359
+ id: NativeObjectId,
360
+ audioChannelIds: ReadonlyArray<number>,
361
+ videoChannelIds: ReadonlyArray<number>,
362
+ ): Promise<NativeRawDumpStartResult>;
293
363
  tiCloudStorageRecordingTaskStop(id: NativeObjectId): Promise<NativeMp4Result>;
294
364
  tiCloudStorageReplayStop(id: NativeObjectId): number;
295
365
  tiCloudStorageReplayDispose(id: NativeObjectId): number;
@@ -326,6 +396,13 @@ interface Spec extends TurboModule {
326
396
  id: NativeObjectId,
327
397
  options: NativeRecordingOptions,
328
398
  ): NativeRecordingStartResult;
399
+ connStartRawDump(
400
+ id: NativeObjectId,
401
+ audioStreamIds: ReadonlyArray<number>,
402
+ videoStreamIds: ReadonlyArray<number>,
403
+ uplinkAudioStreamIds: ReadonlyArray<number>,
404
+ ): Promise<NativeRawDumpStartResult>;
405
+ rawDumpStop(id: NativeObjectId): Promise<NativeRawDumpStopResult>;
329
406
  recordingTaskStop(id: NativeObjectId): Promise<NativeMp4Result>;
330
407
  mediaFileMoveToGallery(id: NativeObjectId, fileName: string | null): Promise<NativeGalleryResult>;
331
408
  mediaFileDelete(id: NativeObjectId): Promise<number>;