tirtc-react-native 2.3.0 → 2.4.0-alpha.3
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 +23 -7
- package/TiRtcReactNative.podspec +1 -1
- package/android/build.gradle +1 -1
- package/android/src/main/AndroidManifest.xml +2 -1
- package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcModule.kt +585 -28
- package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeCleanup.kt +115 -0
- package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeEventBinder.kt +35 -8
- 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 +62 -0
- package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeModuleSupport.kt +6 -6
- package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeRegistry.kt +27 -0
- package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcReactNativeStoreSupport.kt +64 -0
- package/android/src/main/java/com/tange/ai/tirtc/reactnative/TiRtcVideoOutputViewManager.kt +17 -2
- package/ios/TiRtcReactNative+Conn.mm +173 -2
- package/ios/TiRtcReactNative+Input.mm +18 -4
- package/ios/TiRtcReactNative+Output.mm +41 -4
- package/ios/TiRtcReactNative+Private.h +4 -0
- package/ios/TiRtcReactNative+Store.mm +496 -0
- package/ios/TiRtcReactNative.h +2 -1
- package/ios/TiRtcReactNative.mm +109 -1
- package/ios/TiRtcReactNativeEventBinder.h +8 -0
- package/ios/TiRtcReactNativeEventBinder.mm +104 -0
- package/ios/TiRtcReactNativeEventSink.h +4 -0
- package/ios/TiRtcReactNativeEventSink.mm +20 -0
- package/ios/TiRtcReactNativeRegistry.h +5 -0
- package/ios/TiRtcReactNativeRegistry.mm +43 -0
- package/ios/TiRtcVideoOutputView.mm +11 -0
- package/lib/module/audio_input.js +33 -17
- package/lib/module/audio_input.js.map +1 -1
- package/lib/module/audio_output.js +27 -10
- package/lib/module/audio_output.js.map +1 -1
- package/lib/module/conn.js +31 -7
- package/lib/module/conn.js.map +1 -1
- package/lib/module/errors.js +4 -3
- package/lib/module/errors.js.map +1 -1
- package/lib/module/index.js +2 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/logging.js +9 -1
- package/lib/module/logging.js.map +1 -1
- package/lib/module/logging_internal.js +27 -0
- package/lib/module/logging_internal.js.map +1 -0
- package/lib/module/recording.js +210 -0
- package/lib/module/recording.js.map +1 -0
- package/lib/module/runtime.js +13 -5
- package/lib/module/runtime.js.map +1 -1
- package/lib/module/specs/NativeTiRtc.js.map +1 -1
- package/lib/module/store.js +698 -0
- package/lib/module/store.js.map +1 -0
- package/lib/module/video_input.js +40 -22
- package/lib/module/video_input.js.map +1 -1
- package/lib/module/video_output.js +51 -10
- package/lib/module/video_output.js.map +1 -1
- package/lib/typescript/audio_input.d.ts +1 -0
- package/lib/typescript/conn.d.ts +2 -0
- package/lib/typescript/errors.d.ts +3 -2
- package/lib/typescript/index.d.ts +4 -0
- package/lib/typescript/logging_internal.d.ts +2 -0
- package/lib/typescript/recording.d.ts +53 -0
- package/lib/typescript/runtime.d.ts +2 -0
- package/lib/typescript/specs/NativeTiRtc.d.ts +88 -0
- package/lib/typescript/store.d.ts +202 -0
- package/lib/typescript/video_input.d.ts +1 -0
- package/lib/typescript/video_output.d.ts +3 -0
- package/package.json +1 -1
- package/src/audio_input.ts +85 -59
- package/src/audio_output.ts +30 -17
- package/src/conn.ts +46 -28
- package/src/errors.ts +4 -3
- package/src/index.ts +54 -0
- package/src/logging.ts +7 -1
- package/src/logging_internal.ts +23 -0
- package/src/recording.ts +271 -0
- package/src/runtime.ts +14 -5
- package/src/specs/NativeTiRtc.ts +123 -0
- package/src/store.ts +760 -0
- package/src/video_input.ts +97 -62
- package/src/video_output.ts +54 -16
|
@@ -0,0 +1,698 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { View } from 'react-native';
|
|
3
|
+
import { isFiniteSafeInteger, isPlainObject, isUInt8, normalizeCreateResult, } from './errors';
|
|
4
|
+
import { registerNativeEventHandler, unregisterNativeEventHandler } from './events';
|
|
5
|
+
import { TiRtcLogging } from './logging';
|
|
6
|
+
import { NativeTiRtc, NativeTiRtcVideoOutputView } from './native';
|
|
7
|
+
import { clearNativeIdentity, readNativeIdentity, setNativeIdentity, subscribeNativeIdentity, } from './native_object_id';
|
|
8
|
+
import { NativeMediaFileBase, recordingFailure } from './recording';
|
|
9
|
+
export const TISTORE_ERROR_OK = 0;
|
|
10
|
+
export const TISTORE_ERROR_INVALID_ARGUMENT = 6000;
|
|
11
|
+
export const TISTORE_ERROR_NOT_INITIALIZED = 6001;
|
|
12
|
+
export const TISTORE_ERROR_TOKEN_EXPIRED = 6014;
|
|
13
|
+
export const TISTORE_ERROR_ALREADY_INITIALIZED = 6022;
|
|
14
|
+
export const TISTORE_ERROR_PERMISSION_DENIED = 6024;
|
|
15
|
+
export const TISTORE_ERROR_IN_USE = 6026;
|
|
16
|
+
export const TISTORE_ERROR_NOT_STARTED = 6027;
|
|
17
|
+
export const TISTORE_ERROR_NOT_BOUND = 6029;
|
|
18
|
+
export const TISTORE_ERROR_NOT_CONFIGURED = 6030;
|
|
19
|
+
export const TISTORE_ERROR_RESOURCE_EXHAUSTED = 6043;
|
|
20
|
+
export const TISTORE_ERROR_FILE_WRITE_FAILED = 6046;
|
|
21
|
+
export const TISTORE_ERROR_UNSUPPORTED_FORMAT = 6113;
|
|
22
|
+
export const TISTORE_ERROR_IO_FAILED = 6114;
|
|
23
|
+
export const TISTORE_ERROR_CANCELLED = 6115;
|
|
24
|
+
export const TISTORE_ERROR_RANGE_TOO_LARGE = 6117;
|
|
25
|
+
export const TISTORE_ERROR_NO_FRAME = 6118;
|
|
26
|
+
export const TISTORE_ERROR_NO_RECORDABLE_MEDIA = 6119;
|
|
27
|
+
export const TISTORE_ERROR_RECORDING_OVERRUN = 6120;
|
|
28
|
+
export const TISTORE_ERROR_RECORDING_UNREADABLE = 6122;
|
|
29
|
+
export const TISTORE_ERROR_STORE_UNAVAILABLE = 6123;
|
|
30
|
+
export const TISTORE_ERROR_STOPPED = 6124;
|
|
31
|
+
export const TiStoreReplaySpeed = {
|
|
32
|
+
x1: 'x1',
|
|
33
|
+
x2: 'x2',
|
|
34
|
+
x4: 'x4',
|
|
35
|
+
x8: 'x8',
|
|
36
|
+
};
|
|
37
|
+
const storeLogTag = 'TIRTC_REACT_NATIVE_STORE';
|
|
38
|
+
function logStoreOutcome(operation, code, details = '') {
|
|
39
|
+
const message = `[${operation}] outcome=${code === TISTORE_ERROR_OK ? 'ok' : 'failed'} error_code=${code}${details}`;
|
|
40
|
+
if (code === TISTORE_ERROR_OK)
|
|
41
|
+
TiRtcLogging.i(storeLogTag, message);
|
|
42
|
+
else
|
|
43
|
+
TiRtcLogging.e(storeLogTag, message);
|
|
44
|
+
}
|
|
45
|
+
export const TiStoreAudioOutputState = {
|
|
46
|
+
idle: 'idle',
|
|
47
|
+
buffering: 'buffering',
|
|
48
|
+
playing: 'playing',
|
|
49
|
+
failed: 'failed',
|
|
50
|
+
paused: 'paused',
|
|
51
|
+
completed: 'completed',
|
|
52
|
+
};
|
|
53
|
+
export const TiStoreVideoOutputState = {
|
|
54
|
+
idle: 'idle',
|
|
55
|
+
buffering: 'buffering',
|
|
56
|
+
rendering: 'rendering',
|
|
57
|
+
failed: 'failed',
|
|
58
|
+
paused: 'paused',
|
|
59
|
+
completed: 'completed',
|
|
60
|
+
};
|
|
61
|
+
class RecordingFile extends NativeMediaFileBase {
|
|
62
|
+
constructor(path, durationMs, id) {
|
|
63
|
+
super(path, id, 'video');
|
|
64
|
+
this.durationMs = durationMs;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
class SnapshotFile extends NativeMediaFileBase {
|
|
68
|
+
constructor(path, id) {
|
|
69
|
+
super(path, id, 'image');
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function success(data) {
|
|
73
|
+
return { success: true, code: null, message: null, data };
|
|
74
|
+
}
|
|
75
|
+
function validTime(value) {
|
|
76
|
+
return isFiniteSafeInteger(value) && value >= 0;
|
|
77
|
+
}
|
|
78
|
+
function speedToNative(speed) {
|
|
79
|
+
switch (speed) {
|
|
80
|
+
case TiStoreReplaySpeed.x1:
|
|
81
|
+
return 0;
|
|
82
|
+
case TiStoreReplaySpeed.x2:
|
|
83
|
+
return 1;
|
|
84
|
+
case TiStoreReplaySpeed.x4:
|
|
85
|
+
return 2;
|
|
86
|
+
case TiStoreReplaySpeed.x8:
|
|
87
|
+
return 3;
|
|
88
|
+
default:
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function speedFromNative(speed) {
|
|
93
|
+
switch (speed) {
|
|
94
|
+
case 0:
|
|
95
|
+
return TiStoreReplaySpeed.x1;
|
|
96
|
+
case 1:
|
|
97
|
+
return TiStoreReplaySpeed.x2;
|
|
98
|
+
case 2:
|
|
99
|
+
return TiStoreReplaySpeed.x4;
|
|
100
|
+
case 3:
|
|
101
|
+
return TiStoreReplaySpeed.x8;
|
|
102
|
+
default:
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function audioStateFromNative(state) {
|
|
107
|
+
switch (state) {
|
|
108
|
+
case TiStoreAudioOutputState.idle:
|
|
109
|
+
case TiStoreAudioOutputState.buffering:
|
|
110
|
+
case TiStoreAudioOutputState.playing:
|
|
111
|
+
case TiStoreAudioOutputState.failed:
|
|
112
|
+
case TiStoreAudioOutputState.paused:
|
|
113
|
+
case TiStoreAudioOutputState.completed:
|
|
114
|
+
return state;
|
|
115
|
+
default:
|
|
116
|
+
return TiStoreAudioOutputState.failed;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function videoStateFromNative(state) {
|
|
120
|
+
switch (state) {
|
|
121
|
+
case TiStoreVideoOutputState.idle:
|
|
122
|
+
case TiStoreVideoOutputState.buffering:
|
|
123
|
+
case TiStoreVideoOutputState.rendering:
|
|
124
|
+
case TiStoreVideoOutputState.failed:
|
|
125
|
+
case TiStoreVideoOutputState.paused:
|
|
126
|
+
case TiStoreVideoOutputState.completed:
|
|
127
|
+
return state;
|
|
128
|
+
default:
|
|
129
|
+
return TiStoreVideoOutputState.failed;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
export class TiStore {
|
|
133
|
+
constructor(token) {
|
|
134
|
+
this.token = token;
|
|
135
|
+
this.identity = null;
|
|
136
|
+
this.disposed = false;
|
|
137
|
+
this.onTokenExpired = null;
|
|
138
|
+
}
|
|
139
|
+
static init(options) {
|
|
140
|
+
if (!isPlainObject(options) || typeof options.appId !== 'string' || options.appId.length === 0) {
|
|
141
|
+
logStoreOutcome('store_initialize', TISTORE_ERROR_INVALID_ARGUMENT);
|
|
142
|
+
return Promise.resolve(TISTORE_ERROR_INVALID_ARGUMENT);
|
|
143
|
+
}
|
|
144
|
+
return NativeTiRtc.storeInitialize({
|
|
145
|
+
appId: options.appId,
|
|
146
|
+
endpoint: options.endpoint ?? '',
|
|
147
|
+
consoleLogEnabled: options.consoleLogEnabled ?? false,
|
|
148
|
+
}).then((code) => {
|
|
149
|
+
logStoreOutcome('store_initialize', code);
|
|
150
|
+
return code;
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
static shutdown() {
|
|
154
|
+
const nativeCode = NativeTiRtc.storeShutdown();
|
|
155
|
+
const code = nativeCode === TISTORE_ERROR_NOT_INITIALIZED ? TISTORE_ERROR_OK : nativeCode;
|
|
156
|
+
logStoreOutcome('store_shutdown', code);
|
|
157
|
+
return code;
|
|
158
|
+
}
|
|
159
|
+
static errorToString(code) {
|
|
160
|
+
return NativeTiRtc.errorToString(code);
|
|
161
|
+
}
|
|
162
|
+
updateToken(token) {
|
|
163
|
+
if (token.length === 0)
|
|
164
|
+
return TISTORE_ERROR_INVALID_ARGUMENT;
|
|
165
|
+
const identity = this.ensureIdentity();
|
|
166
|
+
if (typeof identity === 'number')
|
|
167
|
+
return identity;
|
|
168
|
+
const code = NativeTiRtc.storeUpdateToken(identity.objectId, token);
|
|
169
|
+
if (code === 0)
|
|
170
|
+
this.token = token;
|
|
171
|
+
logStoreOutcome('store_update_token', code);
|
|
172
|
+
return code;
|
|
173
|
+
}
|
|
174
|
+
listRecordings(startTimeMs, endTimeMs) {
|
|
175
|
+
if (!validTime(startTimeMs) || !validTime(endTimeMs) || endTimeMs <= startTimeMs) {
|
|
176
|
+
return Promise.resolve({
|
|
177
|
+
code: TISTORE_ERROR_INVALID_ARGUMENT,
|
|
178
|
+
recordings: [],
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
const identity = this.ensureIdentity();
|
|
182
|
+
if (typeof identity === 'number') {
|
|
183
|
+
logStoreOutcome('recording_list', identity);
|
|
184
|
+
return Promise.resolve({ code: identity, recordings: [] });
|
|
185
|
+
}
|
|
186
|
+
TiRtcLogging.i(storeLogTag, `[recording_list] outcome=started range_duration_ms=${endTimeMs - startTimeMs}`);
|
|
187
|
+
return NativeTiRtc.storeListRecordings(identity.objectId, startTimeMs, endTimeMs).then((result) => {
|
|
188
|
+
logStoreOutcome('recording_list', result.code, ` recording_count=${result.recordings.length}`);
|
|
189
|
+
return result;
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
listRecordingDays(startDate, endDate, timeZoneId = 'Asia/Shanghai') {
|
|
193
|
+
if (typeof startDate !== 'string' ||
|
|
194
|
+
typeof endDate !== 'string' ||
|
|
195
|
+
typeof timeZoneId !== 'string' ||
|
|
196
|
+
timeZoneId.length === 0) {
|
|
197
|
+
return Promise.resolve({ code: TISTORE_ERROR_INVALID_ARGUMENT, days: [] });
|
|
198
|
+
}
|
|
199
|
+
const identity = this.ensureIdentity();
|
|
200
|
+
if (typeof identity === 'number') {
|
|
201
|
+
logStoreOutcome('recording_days_list', identity);
|
|
202
|
+
return Promise.resolve({ code: identity, days: [] });
|
|
203
|
+
}
|
|
204
|
+
TiRtcLogging.i(storeLogTag, '[recording_days_list] outcome=started');
|
|
205
|
+
return NativeTiRtc.storeListRecordingDays(identity.objectId, startDate, endDate, timeZoneId).then((result) => {
|
|
206
|
+
logStoreOutcome('recording_days_list', result.code, ` day_count=${result.days.length}`);
|
|
207
|
+
return result;
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
createReplay() {
|
|
211
|
+
return new TiStoreReplay(this);
|
|
212
|
+
}
|
|
213
|
+
exportRecording(options, onProgress) {
|
|
214
|
+
if (!validTime(options.startTimeMs) ||
|
|
215
|
+
!validTime(options.endTimeMs) ||
|
|
216
|
+
options.endTimeMs <= options.startTimeMs ||
|
|
217
|
+
!isUInt8(options.videoChannelId) ||
|
|
218
|
+
(options.audioChannelId !== undefined && !isUInt8(options.audioChannelId))) {
|
|
219
|
+
return recordingFailure(TISTORE_ERROR_INVALID_ARGUMENT);
|
|
220
|
+
}
|
|
221
|
+
const identity = this.ensureIdentity();
|
|
222
|
+
if (typeof identity === 'number')
|
|
223
|
+
return recordingFailure(identity);
|
|
224
|
+
const result = NativeTiRtc.storeExportRecording(identity.objectId, options.startTimeMs, options.endTimeMs, options.videoChannelId, options.audioChannelId ?? null);
|
|
225
|
+
logStoreOutcome('export_start', result.code, ` range_duration_ms=${options.endTimeMs - options.startTimeMs}`);
|
|
226
|
+
return result.code === 0 && result.taskId !== null
|
|
227
|
+
? success(new TiStoreExportTask(result.taskId, this, onProgress))
|
|
228
|
+
: recordingFailure(result.code);
|
|
229
|
+
}
|
|
230
|
+
dispose() {
|
|
231
|
+
if (this.disposed)
|
|
232
|
+
return 0;
|
|
233
|
+
if (this.identity === null) {
|
|
234
|
+
this.disposed = true;
|
|
235
|
+
this.token = '';
|
|
236
|
+
this.onTokenExpired = null;
|
|
237
|
+
return 0;
|
|
238
|
+
}
|
|
239
|
+
const identity = this.identity;
|
|
240
|
+
const code = NativeTiRtc.storeDispose(identity.objectId);
|
|
241
|
+
if (code === 0) {
|
|
242
|
+
unregisterNativeEventHandler(identity);
|
|
243
|
+
clearNativeIdentity(this);
|
|
244
|
+
this.identity = null;
|
|
245
|
+
this.disposed = true;
|
|
246
|
+
this.token = '';
|
|
247
|
+
this.onTokenExpired = null;
|
|
248
|
+
}
|
|
249
|
+
return code;
|
|
250
|
+
}
|
|
251
|
+
ensureIdentity() {
|
|
252
|
+
if (this.disposed)
|
|
253
|
+
return TISTORE_ERROR_NOT_INITIALIZED;
|
|
254
|
+
if (this.identity !== null)
|
|
255
|
+
return this.identity;
|
|
256
|
+
if (this.token.length === 0)
|
|
257
|
+
return TISTORE_ERROR_INVALID_ARGUMENT;
|
|
258
|
+
const result = normalizeCreateResult(NativeTiRtc.storeCreate(this.token));
|
|
259
|
+
if (result.code !== 0)
|
|
260
|
+
return result.code;
|
|
261
|
+
this.identity = {
|
|
262
|
+
objectId: result.objectId,
|
|
263
|
+
generation: result.generation,
|
|
264
|
+
};
|
|
265
|
+
setNativeIdentity(this, this.identity);
|
|
266
|
+
registerNativeEventHandler(this.identity, (event) => {
|
|
267
|
+
if (event.type === 'storeTokenExpired')
|
|
268
|
+
this.onTokenExpired?.();
|
|
269
|
+
});
|
|
270
|
+
return this.identity;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
function nativeStoreIdentity(store) {
|
|
274
|
+
return store.ensureIdentity();
|
|
275
|
+
}
|
|
276
|
+
export class TiStoreReplay {
|
|
277
|
+
constructor(store) {
|
|
278
|
+
this.store = store;
|
|
279
|
+
this.identity = null;
|
|
280
|
+
this.disposed = false;
|
|
281
|
+
this.currentSpeed = 'x1';
|
|
282
|
+
this.currentTime = null;
|
|
283
|
+
this.onTimeChanged = null;
|
|
284
|
+
this.onError = null;
|
|
285
|
+
this.onCompleted = null;
|
|
286
|
+
}
|
|
287
|
+
get speed() {
|
|
288
|
+
if (this.identity !== null) {
|
|
289
|
+
const info = NativeTiRtc.storeReplayGetInfo(this.identity.objectId);
|
|
290
|
+
if (info.code === 0)
|
|
291
|
+
this.currentSpeed = speedFromNative(info.speed) ?? this.currentSpeed;
|
|
292
|
+
}
|
|
293
|
+
return this.currentSpeed;
|
|
294
|
+
}
|
|
295
|
+
get currentTimeMs() {
|
|
296
|
+
if (this.identity !== null) {
|
|
297
|
+
const info = NativeTiRtc.storeReplayGetInfo(this.identity.objectId);
|
|
298
|
+
if (info.code === 0)
|
|
299
|
+
this.currentTime = info.currentTimeMs;
|
|
300
|
+
}
|
|
301
|
+
return this.currentTime;
|
|
302
|
+
}
|
|
303
|
+
play(startTimeMs, endTimeMs, initialTimeMs) {
|
|
304
|
+
if (!validTime(startTimeMs) ||
|
|
305
|
+
!validTime(endTimeMs) ||
|
|
306
|
+
endTimeMs <= startTimeMs ||
|
|
307
|
+
(initialTimeMs !== undefined &&
|
|
308
|
+
(!validTime(initialTimeMs) || initialTimeMs < startTimeMs || initialTimeMs >= endTimeMs)))
|
|
309
|
+
return TISTORE_ERROR_INVALID_ARGUMENT;
|
|
310
|
+
const identity = this.ensureIdentity();
|
|
311
|
+
const code = typeof identity === 'number'
|
|
312
|
+
? identity
|
|
313
|
+
: NativeTiRtc.storeReplayPlay(identity.objectId, startTimeMs, endTimeMs, initialTimeMs ?? null);
|
|
314
|
+
logStoreOutcome('replay_play', code, ` range_duration_ms=${endTimeMs - startTimeMs}`);
|
|
315
|
+
return code;
|
|
316
|
+
}
|
|
317
|
+
pause() {
|
|
318
|
+
const code = this.command(NativeTiRtc.storeReplayPause);
|
|
319
|
+
logStoreOutcome('replay_pause', code);
|
|
320
|
+
return code;
|
|
321
|
+
}
|
|
322
|
+
resume() {
|
|
323
|
+
const code = this.command(NativeTiRtc.storeReplayResume);
|
|
324
|
+
logStoreOutcome('replay_resume', code);
|
|
325
|
+
return code;
|
|
326
|
+
}
|
|
327
|
+
seek(timeMs) {
|
|
328
|
+
if (!validTime(timeMs))
|
|
329
|
+
return TISTORE_ERROR_INVALID_ARGUMENT;
|
|
330
|
+
const identity = this.ensureIdentity();
|
|
331
|
+
const code = typeof identity === 'number' ? identity : NativeTiRtc.storeReplaySeek(identity.objectId, timeMs);
|
|
332
|
+
logStoreOutcome('replay_seek', code);
|
|
333
|
+
return code;
|
|
334
|
+
}
|
|
335
|
+
setSpeed(speed) {
|
|
336
|
+
const index = speedToNative(speed);
|
|
337
|
+
if (index === null)
|
|
338
|
+
return TISTORE_ERROR_INVALID_ARGUMENT;
|
|
339
|
+
const identity = this.ensureIdentity();
|
|
340
|
+
if (typeof identity === 'number')
|
|
341
|
+
return identity;
|
|
342
|
+
const code = NativeTiRtc.storeReplaySetSpeed(identity.objectId, index);
|
|
343
|
+
if (code === 0)
|
|
344
|
+
this.currentSpeed = speed;
|
|
345
|
+
logStoreOutcome('replay_speed', code, ` speed=${speed}`);
|
|
346
|
+
return code;
|
|
347
|
+
}
|
|
348
|
+
startRecording(options) {
|
|
349
|
+
if (!isUInt8(options.videoChannelId) ||
|
|
350
|
+
(options.audioChannelId !== undefined && !isUInt8(options.audioChannelId))) {
|
|
351
|
+
return recordingFailure(TISTORE_ERROR_INVALID_ARGUMENT);
|
|
352
|
+
}
|
|
353
|
+
const identity = this.ensureIdentity();
|
|
354
|
+
if (typeof identity === 'number')
|
|
355
|
+
return recordingFailure(identity);
|
|
356
|
+
const result = NativeTiRtc.storeReplayStartRecording(identity.objectId, options.videoChannelId, options.audioChannelId ?? null);
|
|
357
|
+
logStoreOutcome('replay_recording_start', result.code);
|
|
358
|
+
return result.code === 0 && result.taskId !== null
|
|
359
|
+
? success(new TiStoreRecordingTask(result.taskId, this))
|
|
360
|
+
: recordingFailure(result.code);
|
|
361
|
+
}
|
|
362
|
+
stop() {
|
|
363
|
+
const code = this.command(NativeTiRtc.storeReplayStop);
|
|
364
|
+
if (code === 0)
|
|
365
|
+
this.currentTime = null;
|
|
366
|
+
logStoreOutcome('replay_stop', code);
|
|
367
|
+
return code;
|
|
368
|
+
}
|
|
369
|
+
dispose() {
|
|
370
|
+
if (this.disposed)
|
|
371
|
+
return 0;
|
|
372
|
+
if (this.identity === null) {
|
|
373
|
+
this.disposed = true;
|
|
374
|
+
this.onTimeChanged = null;
|
|
375
|
+
this.onError = null;
|
|
376
|
+
this.onCompleted = null;
|
|
377
|
+
return 0;
|
|
378
|
+
}
|
|
379
|
+
const identity = this.identity;
|
|
380
|
+
const code = NativeTiRtc.storeReplayDispose(identity.objectId);
|
|
381
|
+
if (code === 0) {
|
|
382
|
+
unregisterNativeEventHandler(identity);
|
|
383
|
+
clearNativeIdentity(this);
|
|
384
|
+
this.identity = null;
|
|
385
|
+
this.disposed = true;
|
|
386
|
+
this.onTimeChanged = null;
|
|
387
|
+
this.onError = null;
|
|
388
|
+
this.onCompleted = null;
|
|
389
|
+
}
|
|
390
|
+
logStoreOutcome('replay_dispose', code);
|
|
391
|
+
return code;
|
|
392
|
+
}
|
|
393
|
+
command(operation) {
|
|
394
|
+
const identity = this.ensureIdentity();
|
|
395
|
+
return typeof identity === 'number' ? identity : operation(identity.objectId);
|
|
396
|
+
}
|
|
397
|
+
ensureIdentity() {
|
|
398
|
+
if (this.disposed)
|
|
399
|
+
return TISTORE_ERROR_NOT_INITIALIZED;
|
|
400
|
+
if (this.identity !== null)
|
|
401
|
+
return this.identity;
|
|
402
|
+
const store = nativeStoreIdentity(this.store);
|
|
403
|
+
if (typeof store === 'number')
|
|
404
|
+
return store;
|
|
405
|
+
const result = normalizeCreateResult(NativeTiRtc.storeCreateReplay(store.objectId));
|
|
406
|
+
if (result.code !== 0)
|
|
407
|
+
return result.code;
|
|
408
|
+
this.identity = {
|
|
409
|
+
objectId: result.objectId,
|
|
410
|
+
generation: result.generation,
|
|
411
|
+
};
|
|
412
|
+
setNativeIdentity(this, this.identity);
|
|
413
|
+
registerNativeEventHandler(this.identity, (event) => this.handleEvent(event));
|
|
414
|
+
return this.identity;
|
|
415
|
+
}
|
|
416
|
+
handleEvent(event) {
|
|
417
|
+
if (event.type === 'storeReplayTimeChanged' && event.timestampMs !== undefined) {
|
|
418
|
+
this.currentTime = event.timestampMs;
|
|
419
|
+
this.onTimeChanged?.(event.timestampMs);
|
|
420
|
+
}
|
|
421
|
+
else if (event.type === 'storeReplayCompleted')
|
|
422
|
+
this.onCompleted?.();
|
|
423
|
+
else if (event.type === 'storeReplayError')
|
|
424
|
+
this.onError?.(event.code ?? TISTORE_ERROR_STORE_UNAVAILABLE);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
function nativeReplayIdentity(replay) {
|
|
428
|
+
return replay.ensureIdentity();
|
|
429
|
+
}
|
|
430
|
+
class StoreOutputBase {
|
|
431
|
+
constructor() {
|
|
432
|
+
this.identity = null;
|
|
433
|
+
this.disposed = false;
|
|
434
|
+
this.bound = false;
|
|
435
|
+
}
|
|
436
|
+
ensureIdentity() {
|
|
437
|
+
if (this.disposed)
|
|
438
|
+
return TISTORE_ERROR_NOT_INITIALIZED;
|
|
439
|
+
if (this.identity !== null)
|
|
440
|
+
return this.identity;
|
|
441
|
+
const result = normalizeCreateResult(this.create());
|
|
442
|
+
if (result.code !== 0)
|
|
443
|
+
return result.code;
|
|
444
|
+
this.identity = {
|
|
445
|
+
objectId: result.objectId,
|
|
446
|
+
generation: result.generation,
|
|
447
|
+
};
|
|
448
|
+
setNativeIdentity(this, this.identity);
|
|
449
|
+
registerNativeEventHandler(this.identity, (event) => this.handleEvent(event));
|
|
450
|
+
return this.identity;
|
|
451
|
+
}
|
|
452
|
+
releaseIdentity() {
|
|
453
|
+
if (this.identity !== null) {
|
|
454
|
+
unregisterNativeEventHandler(this.identity);
|
|
455
|
+
clearNativeIdentity(this);
|
|
456
|
+
}
|
|
457
|
+
this.identity = null;
|
|
458
|
+
this.disposed = true;
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
export class TiStoreAudioOutput extends StoreOutputBase {
|
|
462
|
+
constructor() {
|
|
463
|
+
super(...arguments);
|
|
464
|
+
this.currentState = 'idle';
|
|
465
|
+
this.onStateChanged = null;
|
|
466
|
+
this.onError = null;
|
|
467
|
+
}
|
|
468
|
+
create() {
|
|
469
|
+
return NativeTiRtc.storeCreateAudioOutput();
|
|
470
|
+
}
|
|
471
|
+
get state() {
|
|
472
|
+
if (this.identity !== null)
|
|
473
|
+
this.currentState = audioStateFromNative(NativeTiRtc.storeAudioOutputGetState(this.identity.objectId).state ?? this.currentState);
|
|
474
|
+
return this.currentState;
|
|
475
|
+
}
|
|
476
|
+
attach(replay, channelId) {
|
|
477
|
+
if (!isUInt8(channelId))
|
|
478
|
+
return TISTORE_ERROR_INVALID_ARGUMENT;
|
|
479
|
+
const output = this.ensureIdentity();
|
|
480
|
+
const replayId = nativeReplayIdentity(replay);
|
|
481
|
+
if (typeof output === 'number')
|
|
482
|
+
return output;
|
|
483
|
+
if (typeof replayId === 'number')
|
|
484
|
+
return replayId;
|
|
485
|
+
const code = NativeTiRtc.storeAudioOutputAttach(output.objectId, replayId.objectId, channelId);
|
|
486
|
+
if (code === 0)
|
|
487
|
+
this.bound = true;
|
|
488
|
+
logStoreOutcome('audio_output_attach', code);
|
|
489
|
+
return code;
|
|
490
|
+
}
|
|
491
|
+
setVolume(volumePercent) {
|
|
492
|
+
if (!isFiniteSafeInteger(volumePercent) || volumePercent < 0 || volumePercent > 100)
|
|
493
|
+
return TISTORE_ERROR_INVALID_ARGUMENT;
|
|
494
|
+
const output = this.ensureIdentity();
|
|
495
|
+
return typeof output === 'number' ? output : NativeTiRtc.storeAudioOutputSetVolume(output.objectId, volumePercent);
|
|
496
|
+
}
|
|
497
|
+
detach() {
|
|
498
|
+
if (this.identity === null)
|
|
499
|
+
return 0;
|
|
500
|
+
const code = NativeTiRtc.storeAudioOutputDetach(this.identity.objectId);
|
|
501
|
+
if (code === 0) {
|
|
502
|
+
this.bound = false;
|
|
503
|
+
this.currentState = TiStoreAudioOutputState.idle;
|
|
504
|
+
}
|
|
505
|
+
logStoreOutcome('audio_output_detach', code);
|
|
506
|
+
return code;
|
|
507
|
+
}
|
|
508
|
+
dispose() {
|
|
509
|
+
if (this.disposed)
|
|
510
|
+
return 0;
|
|
511
|
+
if (this.bound)
|
|
512
|
+
return TISTORE_ERROR_IN_USE;
|
|
513
|
+
if (this.identity === null) {
|
|
514
|
+
this.disposed = true;
|
|
515
|
+
this.currentState = TiStoreAudioOutputState.idle;
|
|
516
|
+
this.onStateChanged = null;
|
|
517
|
+
this.onError = null;
|
|
518
|
+
return 0;
|
|
519
|
+
}
|
|
520
|
+
const code = NativeTiRtc.storeAudioOutputDispose(this.identity.objectId);
|
|
521
|
+
if (code === 0) {
|
|
522
|
+
this.releaseIdentity();
|
|
523
|
+
this.currentState = TiStoreAudioOutputState.idle;
|
|
524
|
+
this.onStateChanged = null;
|
|
525
|
+
this.onError = null;
|
|
526
|
+
}
|
|
527
|
+
logStoreOutcome('audio_output_dispose', code);
|
|
528
|
+
return code;
|
|
529
|
+
}
|
|
530
|
+
handleEvent(event) {
|
|
531
|
+
if (event.type === 'audioOutputStateChanged' && event.state !== undefined) {
|
|
532
|
+
this.currentState = audioStateFromNative(event.state);
|
|
533
|
+
this.onStateChanged?.(this.currentState);
|
|
534
|
+
}
|
|
535
|
+
else if (event.type === 'audioOutputError')
|
|
536
|
+
this.onError?.(event.code ?? TISTORE_ERROR_IO_FAILED);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
export class TiStoreVideoOutput extends StoreOutputBase {
|
|
540
|
+
constructor() {
|
|
541
|
+
super(...arguments);
|
|
542
|
+
this.currentState = 'idle';
|
|
543
|
+
this.onStateChanged = null;
|
|
544
|
+
this.onError = null;
|
|
545
|
+
}
|
|
546
|
+
create() {
|
|
547
|
+
return NativeTiRtc.storeCreateVideoOutput();
|
|
548
|
+
}
|
|
549
|
+
get state() {
|
|
550
|
+
if (this.identity !== null)
|
|
551
|
+
this.currentState = videoStateFromNative(NativeTiRtc.storeVideoOutputGetState(this.identity.objectId).state ?? this.currentState);
|
|
552
|
+
return this.currentState;
|
|
553
|
+
}
|
|
554
|
+
view(props = {}) {
|
|
555
|
+
this.ensureIdentity();
|
|
556
|
+
return React.createElement(TiStoreVideoOutputView, {
|
|
557
|
+
...props,
|
|
558
|
+
output: this,
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
attach(replay, channelId) {
|
|
562
|
+
if (!isUInt8(channelId))
|
|
563
|
+
return TISTORE_ERROR_INVALID_ARGUMENT;
|
|
564
|
+
const output = this.ensureIdentity();
|
|
565
|
+
const replayId = nativeReplayIdentity(replay);
|
|
566
|
+
if (typeof output === 'number')
|
|
567
|
+
return output;
|
|
568
|
+
if (typeof replayId === 'number')
|
|
569
|
+
return replayId;
|
|
570
|
+
const code = NativeTiRtc.storeVideoOutputAttach(output.objectId, replayId.objectId, channelId);
|
|
571
|
+
if (code === 0)
|
|
572
|
+
this.bound = true;
|
|
573
|
+
logStoreOutcome('video_output_attach', code);
|
|
574
|
+
return code;
|
|
575
|
+
}
|
|
576
|
+
async takeSnapshot() {
|
|
577
|
+
const output = this.ensureIdentity();
|
|
578
|
+
if (typeof output === 'number')
|
|
579
|
+
return recordingFailure(output);
|
|
580
|
+
const result = await NativeTiRtc.storeVideoOutputTakeSnapshot(output.objectId);
|
|
581
|
+
logStoreOutcome('snapshot', result.code);
|
|
582
|
+
return result.code === 0 && result.fileId !== null && result.filePath !== null
|
|
583
|
+
? success(new SnapshotFile(result.filePath, result.fileId))
|
|
584
|
+
: recordingFailure(result.code);
|
|
585
|
+
}
|
|
586
|
+
detach() {
|
|
587
|
+
if (this.identity === null)
|
|
588
|
+
return 0;
|
|
589
|
+
const code = NativeTiRtc.storeVideoOutputDetach(this.identity.objectId);
|
|
590
|
+
if (code === 0) {
|
|
591
|
+
this.bound = false;
|
|
592
|
+
this.currentState = TiStoreVideoOutputState.idle;
|
|
593
|
+
}
|
|
594
|
+
logStoreOutcome('video_output_detach', code);
|
|
595
|
+
return code;
|
|
596
|
+
}
|
|
597
|
+
dispose() {
|
|
598
|
+
if (this.disposed)
|
|
599
|
+
return 0;
|
|
600
|
+
if (this.bound)
|
|
601
|
+
return TISTORE_ERROR_IN_USE;
|
|
602
|
+
if (this.identity === null) {
|
|
603
|
+
this.disposed = true;
|
|
604
|
+
this.currentState = TiStoreVideoOutputState.idle;
|
|
605
|
+
this.onStateChanged = null;
|
|
606
|
+
this.onError = null;
|
|
607
|
+
return 0;
|
|
608
|
+
}
|
|
609
|
+
const code = NativeTiRtc.storeVideoOutputDispose(this.identity.objectId);
|
|
610
|
+
if (code === 0) {
|
|
611
|
+
this.releaseIdentity();
|
|
612
|
+
this.currentState = TiStoreVideoOutputState.idle;
|
|
613
|
+
this.onStateChanged = null;
|
|
614
|
+
this.onError = null;
|
|
615
|
+
}
|
|
616
|
+
logStoreOutcome('video_output_dispose', code);
|
|
617
|
+
return code;
|
|
618
|
+
}
|
|
619
|
+
handleEvent(event) {
|
|
620
|
+
if (event.type === 'videoOutputStateChanged' && event.state !== undefined) {
|
|
621
|
+
this.currentState = videoStateFromNative(event.state);
|
|
622
|
+
this.onStateChanged?.(this.currentState);
|
|
623
|
+
}
|
|
624
|
+
else if (event.type === 'videoOutputError')
|
|
625
|
+
this.onError?.(event.code ?? TISTORE_ERROR_IO_FAILED);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
export function TiStoreVideoOutputView(props) {
|
|
629
|
+
const { output, resizeMode = 'contain', ...viewProps } = props;
|
|
630
|
+
const identity = useOwnerIdentity(output);
|
|
631
|
+
return identity === null
|
|
632
|
+
? React.createElement(View, viewProps)
|
|
633
|
+
: React.createElement(NativeTiRtcVideoOutputView, {
|
|
634
|
+
...viewProps,
|
|
635
|
+
nativeObjectId: identity.objectId,
|
|
636
|
+
generation: identity.generation,
|
|
637
|
+
resizeMode,
|
|
638
|
+
});
|
|
639
|
+
}
|
|
640
|
+
function useOwnerIdentity(owner) {
|
|
641
|
+
const [, update] = React.useReducer((value) => value + 1, 0);
|
|
642
|
+
React.useEffect(() => subscribeNativeIdentity(owner, update), [owner]);
|
|
643
|
+
return readNativeIdentity(owner);
|
|
644
|
+
}
|
|
645
|
+
export class TiStoreRecordingTask {
|
|
646
|
+
constructor(taskId, owner) {
|
|
647
|
+
this.taskId = taskId;
|
|
648
|
+
this.owner = owner;
|
|
649
|
+
this.stopPromise = null;
|
|
650
|
+
}
|
|
651
|
+
stop() {
|
|
652
|
+
void this.owner;
|
|
653
|
+
return (this.stopPromise ?? (this.stopPromise = NativeTiRtc.storeRecordingTaskStop(this.taskId).then((result) => {
|
|
654
|
+
logStoreOutcome('replay_recording_stop', result.code, ` duration_ms=${result.durationMs ?? 0}`);
|
|
655
|
+
return result.code === 0 && result.fileId !== null && result.filePath !== null && result.durationMs !== null
|
|
656
|
+
? success(new RecordingFile(result.filePath, result.durationMs, result.fileId))
|
|
657
|
+
: recordingFailure(result.code);
|
|
658
|
+
})));
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
export class TiStoreExportTask {
|
|
662
|
+
constructor(taskId, owner, onProgress) {
|
|
663
|
+
this.taskId = taskId;
|
|
664
|
+
this.owner = owner;
|
|
665
|
+
this.onProgress = onProgress;
|
|
666
|
+
this.resultPromise = NativeTiRtc.storeExportResult(taskId).then((result) => {
|
|
667
|
+
logStoreOutcome('export_terminal', result.code, ` duration_ms=${result.durationMs ?? 0}`);
|
|
668
|
+
return result.code === 0 && result.fileId !== null && result.filePath !== null && result.durationMs !== null
|
|
669
|
+
? success(new RecordingFile(result.filePath, result.durationMs, result.fileId))
|
|
670
|
+
: recordingFailure(result.code);
|
|
671
|
+
});
|
|
672
|
+
if (onProgress !== undefined) {
|
|
673
|
+
let lastProgress = -1;
|
|
674
|
+
const timer = setInterval(() => {
|
|
675
|
+
const progress = NativeTiRtc.storeExportProgress(taskId);
|
|
676
|
+
if (progress !== lastProgress) {
|
|
677
|
+
lastProgress = progress;
|
|
678
|
+
onProgress(progress);
|
|
679
|
+
}
|
|
680
|
+
}, 100);
|
|
681
|
+
const clear = () => clearInterval(timer);
|
|
682
|
+
void this.resultPromise.then(clear, clear);
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
get progress() {
|
|
686
|
+
void this.owner;
|
|
687
|
+
return NativeTiRtc.storeExportProgress(this.taskId);
|
|
688
|
+
}
|
|
689
|
+
get result() {
|
|
690
|
+
return this.resultPromise;
|
|
691
|
+
}
|
|
692
|
+
stop() {
|
|
693
|
+
const code = NativeTiRtc.storeExportStop(this.taskId);
|
|
694
|
+
logStoreOutcome('export_stop', code);
|
|
695
|
+
return this.resultPromise;
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
//# sourceMappingURL=store.js.map
|