tirtc-react-native 2.4.2 → 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.
- package/README.md +39 -6
- package/TiRtcReactNative.podspec +1 -1
- package/android/build.gradle +1 -1
- package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcModule.kt +140 -17
- package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeCleanup.kt +54 -19
- package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeCloudStorageCallbacks.kt +60 -0
- package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeEventBinder.kt +2 -0
- package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeEventSink.kt +20 -0
- package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeMaps.kt +112 -5
- package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeOptions.kt +2 -7
- package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeRegistry.kt +3 -0
- package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeStorageSupport.kt +46 -22
- package/ios/TiRtcReactNative+Conn.mm +61 -0
- package/ios/TiRtcReactNative+Output.mm +1 -7
- package/ios/TiRtcReactNative+Private.h +1 -0
- package/ios/TiRtcReactNative+Storage.mm +133 -35
- package/ios/TiRtcReactNative.mm +142 -51
- package/ios/TiRtcReactNativeCloudStorageCallbacks.h +13 -0
- package/ios/TiRtcReactNativeCloudStorageCallbacks.mm +67 -0
- package/ios/TiRtcReactNativeEventBinder.h +4 -0
- package/ios/TiRtcReactNativeEventBinder.mm +11 -0
- package/ios/TiRtcReactNativeEventSink.h +5 -0
- package/ios/TiRtcReactNativeEventSink.mm +18 -0
- package/ios/TiRtcReactNativeMaps.h +6 -0
- package/ios/TiRtcReactNativeMaps.mm +47 -0
- package/ios/TiRtcReactNativeOptions.mm +2 -6
- package/lib/module/audio_input.js +23 -4
- package/lib/module/audio_input.js.map +1 -1
- package/lib/module/build_identity.js +1 -0
- package/lib/module/conn.js +19 -0
- package/lib/module/conn.js.map +1 -1
- package/lib/module/events.js +16 -9
- package/lib/module/events.js.map +1 -1
- package/lib/module/index.js +3 -2
- package/lib/module/index.js.map +1 -1
- package/lib/module/logging_internal.js +16 -0
- package/lib/module/logging_internal.js.map +1 -1
- package/lib/module/raw_dump.js +53 -0
- package/lib/module/raw_dump.js.map +1 -0
- package/lib/module/runtime.js +3 -1
- package/lib/module/runtime.js.map +1 -1
- package/lib/module/specs/NativeTiRtc.js.map +1 -1
- package/lib/module/storage.js +190 -33
- package/lib/module/storage.js.map +1 -1
- package/lib/module/types.js +0 -4
- package/lib/module/types.js.map +1 -1
- package/lib/module/video_input.js +16 -6
- package/lib/module/video_input.js.map +1 -1
- package/lib/typescript/build_identity.d.ts +6 -0
- package/lib/typescript/conn.d.ts +2 -0
- package/lib/typescript/index.d.ts +5 -3
- package/lib/typescript/logging_internal.d.ts +1 -0
- package/lib/typescript/native.d.ts +1 -1
- package/lib/typescript/raw_dump.d.ts +35 -0
- package/lib/typescript/specs/NativeTiRtc.d.ts +75 -3
- package/lib/typescript/storage.d.ts +84 -3
- package/lib/typescript/types.d.ts +5 -6
- package/package.json +3 -3
- package/src/audio_input.ts +30 -11
- package/src/build_identity.ts +6 -0
- package/src/conn.ts +23 -0
- package/src/events.ts +14 -9
- package/src/index.ts +19 -1
- package/src/logging_internal.ts +18 -0
- package/src/native.ts +7 -1
- package/src/raw_dump.ts +84 -0
- package/src/runtime.ts +2 -1
- package/src/specs/NativeTiRtc.ts +80 -3
- package/src/storage.ts +260 -39
- package/src/types.ts +5 -8
- 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;
|
|
@@ -27,6 +28,8 @@ export declare const TI_CLOUD_STORAGE_ERROR_UNAVAILABLE: 6123;
|
|
|
27
28
|
export declare const TI_CLOUD_STORAGE_ERROR_STOPPED: 6124;
|
|
28
29
|
export declare const TI_CLOUD_STORAGE_ERROR_RECORDING_NOT_FOUND: 6134;
|
|
29
30
|
export declare const TI_CLOUD_STORAGE_ERROR_RECORDING_DOWNLOAD_FAILED: 6135;
|
|
31
|
+
export declare const TI_CLOUD_STORAGE_ERROR_NETWORK_UNAVAILABLE: 6136;
|
|
32
|
+
export declare const TI_CLOUD_STORAGE_ERROR_ENDPOINT_DNS_RESOLUTION_FAILED: 6137;
|
|
30
33
|
export type TiCloudStorageRecordingRange = Readonly<{
|
|
31
34
|
startTimeMs: number;
|
|
32
35
|
endTimeMs: number;
|
|
@@ -43,6 +46,69 @@ export type TiCloudStorageRecordingDaysResult = Readonly<{
|
|
|
43
46
|
code: number;
|
|
44
47
|
days: ReadonlyArray<TiCloudStorageRecordingDay>;
|
|
45
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
|
+
}>;
|
|
46
112
|
export declare const TiCloudStorageReplaySpeed: {
|
|
47
113
|
readonly x0_125: "x0_125";
|
|
48
114
|
readonly x0_25: "x0_25";
|
|
@@ -97,6 +163,7 @@ export declare class TiCloudStorage {
|
|
|
97
163
|
private token;
|
|
98
164
|
private identity;
|
|
99
165
|
private disposed;
|
|
166
|
+
private pendingAsyncOperations;
|
|
100
167
|
constructor(token: string);
|
|
101
168
|
static init(options: Readonly<{
|
|
102
169
|
appId: string;
|
|
@@ -109,19 +176,22 @@ export declare class TiCloudStorage {
|
|
|
109
176
|
listRecordings(startTimeMs: number, endTimeMs: number): Promise<TiCloudStorageRecordingRangesResult>;
|
|
110
177
|
listRecordingDays(startDate: string, endDate: string, timeZoneId?: string): Promise<TiCloudStorageRecordingDaysResult>;
|
|
111
178
|
createReplay(): TiCloudStorageReplay;
|
|
112
|
-
exportRecording(options: TiCloudStorageExportOptions,
|
|
179
|
+
exportRecording(options: TiCloudStorageExportOptions, observer?: ((progress: number) => void) | TiCloudStorageExportObserver): Resp<TiCloudStorageExportTask>;
|
|
113
180
|
dispose(): number;
|
|
181
|
+
private trackAsyncOperation;
|
|
114
182
|
private ensureIdentity;
|
|
115
183
|
}
|
|
116
184
|
export declare class TiCloudStorageReplay {
|
|
117
185
|
private readonly cloudStorage;
|
|
118
186
|
private identity;
|
|
119
187
|
private disposed;
|
|
188
|
+
private inCallback;
|
|
120
189
|
private currentSpeed;
|
|
121
190
|
private currentTime;
|
|
122
191
|
onTimeChanged: ((timeMs: number) => void) | null;
|
|
123
192
|
onError: ((code: number) => void) | null;
|
|
124
193
|
onCompleted: (() => void) | null;
|
|
194
|
+
onRecordingGap: ((gap: TiCloudStorageRecordingGap) => void) | null;
|
|
125
195
|
constructor(cloudStorage: TiCloudStorage);
|
|
126
196
|
get speed(): TiCloudStorageReplaySpeed;
|
|
127
197
|
get currentTimeMs(): number | null;
|
|
@@ -131,6 +201,7 @@ export declare class TiCloudStorageReplay {
|
|
|
131
201
|
seek(timeMs: number): number;
|
|
132
202
|
setSpeed(speed: TiCloudStorageReplaySpeed): number;
|
|
133
203
|
startRecording(options: TiCloudStorageStartRecordingOptions): Resp<TiCloudStorageRecordingTask>;
|
|
204
|
+
startRawDump(options: TiCloudStorageRawDumpOptions): Promise<Resp<TiRawDump>>;
|
|
134
205
|
stop(): number;
|
|
135
206
|
dispose(): number;
|
|
136
207
|
private command;
|
|
@@ -196,11 +267,21 @@ export declare class TiCloudStorageRecordingTask {
|
|
|
196
267
|
export declare class TiCloudStorageExportTask {
|
|
197
268
|
private readonly taskId;
|
|
198
269
|
private readonly owner;
|
|
199
|
-
private readonly onProgress?;
|
|
200
270
|
private resultPromise;
|
|
201
|
-
|
|
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);
|
|
202
278
|
get progress(): number;
|
|
279
|
+
get progressDetail(): TiCloudStorageExportProgress;
|
|
280
|
+
get report(): TiCloudStorageExportReport | null;
|
|
281
|
+
get completion(): Promise<TiCloudStorageExportOutcome>;
|
|
203
282
|
get result(): Promise<Resp<TiCloudStorageRecordingFile>>;
|
|
283
|
+
cancel(): number;
|
|
204
284
|
stop(): Promise<Resp<TiCloudStorageRecordingFile>>;
|
|
285
|
+
private handleEvent;
|
|
205
286
|
}
|
|
206
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
|
-
|
|
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.
|
|
3
|
+
"version": "2.5.0",
|
|
4
4
|
"description": "TiRTC React Native SDK",
|
|
5
5
|
"homepage": "https://tange.ai/",
|
|
6
6
|
"repository": {
|
|
@@ -46,10 +46,10 @@
|
|
|
46
46
|
"react-native.config.js"
|
|
47
47
|
],
|
|
48
48
|
"scripts": {
|
|
49
|
-
"build": "node scripts/clean_generated_lib.mjs && tsc -p tsconfig.build.json && node scripts/write_codegen_component_specs.mjs",
|
|
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"
|
package/src/audio_input.ts
CHANGED
|
@@ -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
|
-
|
|
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.
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
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 (
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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,
|
|
@@ -92,7 +98,12 @@ export {
|
|
|
92
98
|
TI_CLOUD_STORAGE_ERROR_STOPPED,
|
|
93
99
|
TI_CLOUD_STORAGE_ERROR_RECORDING_NOT_FOUND,
|
|
94
100
|
TI_CLOUD_STORAGE_ERROR_RECORDING_DOWNLOAD_FAILED,
|
|
101
|
+
TI_CLOUD_STORAGE_ERROR_NETWORK_UNAVAILABLE,
|
|
102
|
+
TI_CLOUD_STORAGE_ERROR_ENDPOINT_DNS_RESOLUTION_FAILED,
|
|
95
103
|
TiCloudStorageReplaySpeed,
|
|
104
|
+
TiCloudStorageRecordingTrackKind,
|
|
105
|
+
TiCloudStorageRecordingGapReason,
|
|
106
|
+
TiCloudStorageExportTermination,
|
|
96
107
|
TiCloudStorageAudioOutputState,
|
|
97
108
|
TiCloudStorageVideoOutputState,
|
|
98
109
|
TiCloudStorage,
|
|
@@ -105,6 +116,13 @@ export {
|
|
|
105
116
|
} from './storage';
|
|
106
117
|
export type {
|
|
107
118
|
TiCloudStorageRecordingRange,
|
|
119
|
+
TiCloudStorageRecordingTrack,
|
|
120
|
+
TiCloudStorageRecordingGap,
|
|
121
|
+
TiCloudStorageExportProgress,
|
|
122
|
+
TiCloudStorageExportSegment,
|
|
123
|
+
TiCloudStorageExportReport,
|
|
124
|
+
TiCloudStorageExportOutcome,
|
|
125
|
+
TiCloudStorageExportObserver,
|
|
108
126
|
TiCloudStorageRecordingRangesResult,
|
|
109
127
|
TiCloudStorageRecordingDay,
|
|
110
128
|
TiCloudStorageRecordingDaysResult,
|
package/src/logging_internal.ts
CHANGED
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
import {TiRtcLogging} from './logging';
|
|
2
|
+
import {NativeTiRtc} from './native';
|
|
3
|
+
import {buildIdentity} from './build_identity';
|
|
2
4
|
|
|
3
5
|
const rtcLogTag = 'TIRTC_REACT_NATIVE';
|
|
6
|
+
const loggedIdentityProducts = new Set<string>();
|
|
7
|
+
|
|
8
|
+
export function logBuildIdentity(product: 'rtc' | 'cloud_storage'): void {
|
|
9
|
+
if (loggedIdentityProducts.has(product)) return;
|
|
10
|
+
try {
|
|
11
|
+
const code = NativeTiRtc.writeLog(
|
|
12
|
+
1,
|
|
13
|
+
rtcLogTag,
|
|
14
|
+
'[build_identity] summary: component build identity; component=react_native ' +
|
|
15
|
+
`product=${product} release_version=${buildIdentity.releaseVersion} ` +
|
|
16
|
+
`build_time_utc=${buildIdentity.buildTimeUtc} source_revision=${buildIdentity.sourceRevision} ` +
|
|
17
|
+
`source_dirty=${buildIdentity.sourceDirty}`,
|
|
18
|
+
);
|
|
19
|
+
if (code === 0) loggedIdentityProducts.add(product);
|
|
20
|
+
} catch {}
|
|
21
|
+
}
|
|
4
22
|
|
|
5
23
|
export function logRtcOutcome(operation: string, code: number, details = ''): void {
|
|
6
24
|
const message = `[${operation}] completed code=${code}${details}`;
|
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 {
|
|
6
|
+
export type {
|
|
7
|
+
NativeTiRtcEvent,
|
|
8
|
+
NativeTiCloudStorageExportProgress,
|
|
9
|
+
NativeTiCloudStorageExportReport,
|
|
10
|
+
NativeTiCloudStorageRecordingGap,
|
|
11
|
+
NativeRawDumpArchive,
|
|
12
|
+
} from './specs/NativeTiRtc';
|
package/src/raw_dump.ts
ADDED
|
@@ -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
|
+
}
|
package/src/runtime.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {isPlainObject, TIRTC_ERROR_INVALID_ARGUMENT} from './errors';
|
|
2
2
|
import {NativeTiRtc} from './native';
|
|
3
|
-
import {logRtcOutcome} from './logging_internal';
|
|
3
|
+
import {logBuildIdentity, logRtcOutcome} from './logging_internal';
|
|
4
4
|
import type {TiRtcInitOptions} from './types';
|
|
5
5
|
|
|
6
6
|
export class TiRtc {
|
|
@@ -15,6 +15,7 @@ export class TiRtc {
|
|
|
15
15
|
endpoint: typeof config.endpoint === 'string' ? config.endpoint : '',
|
|
16
16
|
consoleLogEnabled: typeof config.consoleLogEnabled === 'boolean' ? config.consoleLogEnabled : false,
|
|
17
17
|
}).then((code) => {
|
|
18
|
+
if (code === 0) logBuildIdentity('rtc');
|
|
18
19
|
logRtcOutcome('runtime_initialize', code);
|
|
19
20
|
return code;
|
|
20
21
|
});
|